Refactor project structure
This commit is contained in:
670
integrations/ANNHUB/ANSANNHUB.cpp
Normal file
670
integrations/ANNHUB/ANSANNHUB.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
69
integrations/ANNHUB/ANSANNHUB.h
Normal file
69
integrations/ANNHUB/ANSANNHUB.h
Normal 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
|
||||
23
integrations/ANNHUB/CMakeLists.txt
Normal file
23
integrations/ANNHUB/CMakeLists.txt
Normal 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)
|
||||
19
integrations/ANNHUB/dllmain.cpp
Normal file
19
integrations/ANNHUB/dllmain.cpp
Normal 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;
|
||||
}
|
||||
|
||||
7
integrations/ANNHUB/framework.h
Normal file
7
integrations/ANNHUB/framework.h
Normal 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>
|
||||
5
integrations/ANNHUB/pch.cpp
Normal file
5
integrations/ANNHUB/pch.cpp
Normal 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
18
integrations/ANNHUB/pch.h
Normal 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
|
||||
46
integrations/ANSIO/CMakeLists.txt
Normal file
46
integrations/ANSIO/CMakeLists.txt
Normal 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)
|
||||
3143
integrations/ANSIO/IOBox/cJSON.c
Normal file
3143
integrations/ANSIO/IOBox/cJSON.c
Normal file
File diff suppressed because it is too large
Load Diff
300
integrations/ANSIO/IOBox/cJSON.h
Normal file
300
integrations/ANSIO/IOBox/cJSON.h
Normal 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
|
||||
1481
integrations/ANSIO/IOBox/cJSON_Utils.c
Normal file
1481
integrations/ANSIO/IOBox/cJSON_Utils.c
Normal file
File diff suppressed because it is too large
Load Diff
88
integrations/ANSIO/IOBox/cJSON_Utils.h
Normal file
88
integrations/ANSIO/IOBox/cJSON_Utils.h
Normal 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
|
||||
3354
integrations/ANSIO/IOBox/iobox_api.cpp
Normal file
3354
integrations/ANSIO/IOBox/iobox_api.cpp
Normal file
File diff suppressed because it is too large
Load Diff
215
integrations/ANSIO/IOBox/iobox_api.h
Normal file
215
integrations/ANSIO/IOBox/iobox_api.h
Normal 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
|
||||
|
||||
|
||||
111
integrations/ANSIO/IOBox/main.cpp
Normal file
111
integrations/ANSIO/IOBox/main.cpp
Normal 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;
|
||||
}
|
||||
1490
integrations/ANSIO/IOBox/mbedtls/aes.c
Normal file
1490
integrations/ANSIO/IOBox/mbedtls/aes.c
Normal file
File diff suppressed because it is too large
Load Diff
297
integrations/ANSIO/IOBox/mbedtls/aes.h
Normal file
297
integrations/ANSIO/IOBox/mbedtls/aes.h
Normal 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 */
|
||||
289
integrations/ANSIO/IOBox/mbedtls/base64.c
Normal file
289
integrations/ANSIO/IOBox/mbedtls/base64.c
Normal 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 */
|
||||
88
integrations/ANSIO/IOBox/mbedtls/base64.h
Normal file
88
integrations/ANSIO/IOBox/mbedtls/base64.h
Normal 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 */
|
||||
540
integrations/ANSIO/IOBox/mbedtls/check_config.h
Normal file
540
integrations/ANSIO/IOBox/mbedtls/check_config.h
Normal 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 */
|
||||
2511
integrations/ANSIO/IOBox/mbedtls/config.h
Normal file
2511
integrations/ANSIO/IOBox/mbedtls/config.h
Normal file
File diff suppressed because it is too large
Load Diff
214
integrations/ANSIO/IOBox/mbedtls/platform.h
Normal file
214
integrations/ANSIO/IOBox/mbedtls/platform.h
Normal 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 */
|
||||
445
integrations/ANSIO/IOBox/mbedtls/sha256.c
Normal file
445
integrations/ANSIO/IOBox/mbedtls/sha256.c
Normal 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 */
|
||||
141
integrations/ANSIO/IOBox/mbedtls/sha256.h
Normal file
141
integrations/ANSIO/IOBox/mbedtls/sha256.h
Normal 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 */
|
||||
1141
integrations/ANSIO/dllmain.cpp
Normal file
1141
integrations/ANSIO/dllmain.cpp
Normal file
File diff suppressed because it is too large
Load Diff
7
integrations/ANSIO/framework.h
Normal file
7
integrations/ANSIO/framework.h
Normal 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>
|
||||
5
integrations/ANSIO/pch.cpp
Normal file
5
integrations/ANSIO/pch.cpp
Normal 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
22
integrations/ANSIO/pch.h
Normal 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
|
||||
960
integrations/ANSONVIF/ANSONVIF.cpp
Normal file
960
integrations/ANSONVIF/ANSONVIF.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
93
integrations/ANSONVIF/ANSONVIF.h
Normal file
93
integrations/ANSONVIF/ANSONVIF.h
Normal 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
|
||||
31
integrations/ANSONVIF/CMakeLists.txt
Normal file
31
integrations/ANSONVIF/CMakeLists.txt
Normal 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)
|
||||
19
integrations/ANSONVIF/dllmain.cpp
Normal file
19
integrations/ANSONVIF/dllmain.cpp
Normal 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;
|
||||
}
|
||||
|
||||
5
integrations/ANSONVIF/framework.h
Normal file
5
integrations/ANSONVIF/framework.h
Normal 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>
|
||||
5
integrations/ANSONVIF/pch.cpp
Normal file
5
integrations/ANSONVIF/pch.cpp
Normal 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.
|
||||
13
integrations/ANSONVIF/pch.h
Normal file
13
integrations/ANSONVIF/pch.h
Normal 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
|
||||
300
integrations/ANSPulsar/ANSPulsar.cpp
Normal file
300
integrations/ANSPulsar/ANSPulsar.cpp
Normal 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
|
||||
|
||||
81
integrations/ANSPulsar/ANSPulsar.h
Normal file
81
integrations/ANSPulsar/ANSPulsar.h
Normal 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
|
||||
30
integrations/ANSPulsar/CMakeLists.txt
Normal file
30
integrations/ANSPulsar/CMakeLists.txt
Normal 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)
|
||||
419
integrations/ANSPulsar/dllmain.cpp
Normal file
419
integrations/ANSPulsar/dllmain.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
7
integrations/ANSPulsar/framework.h
Normal file
7
integrations/ANSPulsar/framework.h
Normal 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>
|
||||
5
integrations/ANSPulsar/pch.cpp
Normal file
5
integrations/ANSPulsar/pch.cpp
Normal 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.
|
||||
13
integrations/ANSPulsar/pch.h
Normal file
13
integrations/ANSPulsar/pch.h
Normal 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
|
||||
807
integrations/ANSRabbitMQ/ANSRabbitMQ.cpp
Normal file
807
integrations/ANSRabbitMQ/ANSRabbitMQ.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
124
integrations/ANSRabbitMQ/ANSRabbitMQ.h
Normal file
124
integrations/ANSRabbitMQ/ANSRabbitMQ.h
Normal 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
|
||||
30
integrations/ANSRabbitMQ/CMakeLists.txt
Normal file
30
integrations/ANSRabbitMQ/CMakeLists.txt
Normal 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)
|
||||
558
integrations/ANSRabbitMQ/dllmain.cpp
Normal file
558
integrations/ANSRabbitMQ/dllmain.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
7
integrations/ANSRabbitMQ/framework.h
Normal file
7
integrations/ANSRabbitMQ/framework.h
Normal 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>
|
||||
5
integrations/ANSRabbitMQ/pch.cpp
Normal file
5
integrations/ANSRabbitMQ/pch.cpp
Normal 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.
|
||||
13
integrations/ANSRabbitMQ/pch.h
Normal file
13
integrations/ANSRabbitMQ/pch.h
Normal 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
|
||||
Reference in New Issue
Block a user