beremiz

Parents b73d6668eba3
Children 09aa8a10026c
C++ runtime: WIP: untested PLCObject implementation. Still missing tracing.
--- a/.gitignore Fri Apr 26 09:45:02 2024 +0200
+++ b/.gitignore Sat May 11 19:27:28 2024 +0200
@@ -7,3 +7,11 @@
**/my_*.der
**/my_*.pem
tests/tools/Docker/requirements.txt
+**/management.json
+**/.secret
+
+doc/_build/**
+doc/locale/**
+
+C_runtime/**/*.d
+C_runtime/**/*.o
\ No newline at end of file
--- a/C_runtime/Makefile Fri Apr 26 09:45:02 2024 +0200
+++ b/C_runtime/Makefile Sat May 11 19:27:28 2024 +0200
@@ -7,13 +7,17 @@
RUNTIME_ROOT = $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
ERPC_ROOT ?= $(abspath $(RUNTIME_ROOT)/../../erpc)
ERPC_C_ROOT = $(ERPC_ROOT)/erpc_c
+BEREMIZ_ROOT = $(abspath $(RUNTIME_ROOT)/..)
+MATIEC_ROOT ?= $(abspath $(RUNTIME_ROOT)/../../matiec)
INCLUDES += $(ERPC_C_ROOT)/infra \
$(ERPC_C_ROOT)/port \
$(ERPC_C_ROOT)/setup \
$(ERPC_C_ROOT)/transports \
$(ERPC_ROOT)/test/common/config \
- $(ERPC_ROOT)/erpcgen/src
+ $(ERPC_ROOT)/erpcgen/src \
+ $(BEREMIZ_ROOT)/targets \
+ $(MATIEC_ROOT)/lib/C
INCLUDES := $(foreach includes, $(INCLUDES), -I $(includes))
@@ -42,6 +46,8 @@
$(RUNTIME_ROOT)/erpc_PLCObject_client.cpp \
$(RUNTIME_ROOT)/erpc_PLCObject_interface.cpp \
$(RUNTIME_ROOT)/erpc_PLCObject_server.cpp \
+ $(RUNTIME_ROOT)/md5.cpp \
+ $(RUNTIME_ROOT)/blob.cpp \
$(RUNTIME_ROOT)/posix_main.cpp \
$(RUNTIME_ROOT)/PLCObject.cpp
--- a/C_runtime/PLCObject.cpp Fri Apr 26 09:45:02 2024 +0200
+++ b/C_runtime/PLCObject.cpp Sat May 11 19:27:28 2024 +0200
@@ -1,80 +1,341 @@
-#include <stdlib.h>
+#include <string.h>
+#include <filesystem>
+#include <dlfcn.h>
+#include <fstream>
+#include <iostream>
#include "Logging.hpp"
#include "PLCObject.hpp"
+#include "beremiz.h"
+
+
+// File name of the last transferred PLC md5 hex digest
+// with typo in the name, for compatibility with Python runtime
+#define LastTransferredPLC "lasttransferedPLC.md5"
+
+// File name of the extra files list
+#define ExtraFilesList "extra_files.txt"
+
+
+
+PLCObject::PLCObject(void)
+{
+}
+
PLCObject::~PLCObject(void)
{
}
-uint32_t PLCObject::AppendChunkToBlob(const binary_t * data, const binary_t * blobID, binary_t * newBlobID)
+uint32_t PLCObject::AppendChunkToBlob(
+ const binary_t *data, const binary_t *blobID, binary_t *newBlobID)
{
+ // Append data to blob with given blobID
+ // Output new blob's md5 into newBlobID
+ // Return 0 if success
+
+ auto nh = m_mapBlobIDToBlob.extract(std::vector<uint8_t>(
+ blobID->data, blobID->data + blobID->dataLength));
+ if (nh.empty())
+ {
+ return ENOENT;
+ }
+
+ Blob *blob = nh.mapped();
+
+ uint32_t res = blob->appendChunk(data->data, data->dataLength);
+ if (res != 0)
+ {
+ return res;
+ }
+
+ MD5::digest_t digest = blob->digest();
+
+ nh.key() = std::vector<uint8_t>(
+ (uint8_t)*digest.data, (uint8_t)*digest.data + MD5::digestsize);
+
+ m_mapBlobIDToBlob.insert(std::move(nh));
+
return 0;
}
-uint32_t PLCObject::GetLogMessage(uint8_t level, uint32_t msgID, log_message * message)
+#define LOG_READ_BUFFER_SIZE 1 << 10 // 1KB
+
+uint32_t PLCObject::GetLogMessage(
+ uint8_t level, uint32_t msgID, log_message *message)
{
+ char buf[LOG_READ_BUFFER_SIZE];
+ uint32_t tick;
+ uint32_t tv_sec;
+ uint32_t tv_nsec;
+
+ uint32_t resultLen = m_PLCSyms.GetLogMessage(
+ level, msgID, buf, LOG_READ_BUFFER_SIZE - 1,
+ &tick, &tv_sec, &tv_nsec);
+
+ if (resultLen == 0)
+ {
+ return ENOENT;
+ }
+
+ // Get log message with given msgID
+ message->msg = (char *)malloc(resultLen);
+ if (message->msg == NULL)
+ {
+ return ENOMEM;
+ }
+ // Copy the log message into eRPC message
+ memcpy(message->msg, buf, resultLen);
+ message->msg[resultLen + 1] = '\0';
+
+ message->tick = tick;
+ message->sec = tv_sec;
+ message->nsec = tv_nsec;
+
return 0;
}
-uint32_t PLCObject::GetPLCID(PSKID * plcID)
+uint32_t PLCObject::GetPLCID(PSKID *plcID)
+{
+ // Get PLC ID
+ *plcID = m_plcID;
+ return 0;
+}
+
+uint32_t PLCObject::GetPLCstatus(PLCstatus *status)
{
+ // Get PLC status
+ *status = m_status;
+ return 0;
+}
+
+uint32_t PLCObject::GetTraceVariables(
+ uint32_t debugToken, TraceVariables *traces)
+{
+ // XXX TODO
+ return 0;
+}
+
+uint32_t PLCObject::MatchMD5(const char *MD5, bool *match)
+{
+ // Load the last transferred PLC md5 hex digest
+ std::string md5sum;
+ std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+
+ // Compare the given MD5 with the last transferred PLC md5
+ *match = (md5sum == MD5);
+
return 0;
}
-uint32_t PLCObject::GetPLCstatus(PLCstatus * status)
+#if defined(_WIN32) || defined(_WIN64)
+// For Windows platform
+#define SHARED_OBJECT_EXT ".dll"
+#elif defined(__APPLE__) || defined(__MACH__)
+// For MacOS platform
+#define SHARED_OBJECT_EXT ".dylib"
+#else
+// For Linux/Unix platform
+#define SHARED_OBJECT_EXT ".so"
+#endif
+
+uint32_t PLCObject::BlobAsFile(
+ const binary_t *BlobID, std::filesystem::path filename)
{
+ // Extract the blob from the map
+ auto nh = m_mapBlobIDToBlob.extract(
+ std::vector<uint8_t>(BlobID->data, BlobID->data + BlobID->dataLength));
+ if (nh.empty())
+ {
+ return ENOENT;
+ }
+ Blob *blob = nh.mapped();
+
+ // Realize the blob into a file
+ uint32_t res = blob->asFile(filename);
+
+ delete blob;
+
+ if (res != 0)
+ {
+ return res;
+ }
return 0;
}
-uint32_t PLCObject::GetTraceVariables(uint32_t debugToken, TraceVariables * traces)
+uint32_t PLCObject::NewPLC(
+ const char *md5sum, const binary_t *plcObjectBlobID,
+ const list_extra_file_1_t *extrafiles, bool *success)
{
+ // Concatenate md5sum and shared object extension to obtain filename
+ std::filesystem::path filename =
+ std::filesystem::path(md5sum) += SHARED_OBJECT_EXT;
+
+ // Create the PLC object shared object file
+ BlobAsFile(plcObjectBlobID, filename);
+
+ // create "lasttransferedPLC.md5" file and Save md5sum in it
+ std::ofstream(std::string(LastTransferredPLC), std::ios::binary) << md5sum;
+
+ // create "extra_files.txt" file
+ std::ofstream extra_files_log(std::string(ExtraFilesList), std::ios::binary);
+
+ // Create extra files
+ for (int i = 0; i < extrafiles->elementsCount; i++)
+ {
+ extra_file *extrafile = extrafiles->elements + i;
+
+ BlobAsFile(plcObjectBlobID, extrafile->fname);
+
+ // Save the extra file name in "extra_files.txt"
+ extra_files_log << extrafile->fname << std::endl;
+ }
+
return 0;
}
-uint32_t PLCObject::MatchMD5(const char * MD5, bool * match)
+#define DLSYM(sym) \
+ do \
+ { \
+ m_PLCSyms.sym = (decltype(m_PLCSyms.sym))dlsym(m_handle, #sym); \
+ if (m_PLCSyms.sym == NULL) \
+ { \
+ return errno; \
+ } \
+ } while (0);
+
+uint32_t PLCObject::LoadPLC(void)
{
+ // Load the last transferred PLC md5 hex digest
+ std::string md5sum;
+ std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum;
+
+ // Concatenate md5sum and shared object extension to obtain filename
+ std::filesystem::path filename = std::filesystem::path(md5sum) += SHARED_OBJECT_EXT;
+
+ // Load the shared object file
+ m_handle = dlopen(filename.c_str(), RTLD_NOW);
+ if (m_handle == NULL)
+ {
+ return errno;
+ }
+
+ // Resolve shared object symbols
+ FOR_EACH_PLC_SYMBOLS_DO(DLSYM);
+
return 0;
}
-uint32_t PLCObject::NewPLC(const char * md5sum, const binary_t * plcObjectBlobID, const list_extra_file_1_t * extrafiles, bool * success)
+#define ULSYM(sym) \
+ do \
+ { \
+ m_PLCSyms.sym = NULL; \
+ } while (0);
+
+uint32_t PLCObject::UnLoadPLC(void)
{
+ // Unload the shared object file
+ FOR_EACH_PLC_SYMBOLS_DO(ULSYM);
+ dlclose(m_handle);
+
return 0;
}
uint32_t PLCObject::PurgeBlobs(void)
{
+ // Purge all blobs
+
+ for (auto &blob : m_mapBlobIDToBlob)
+ {
+ delete blob.second;
+ }
+ m_mapBlobIDToBlob.clear();
+
return 0;
}
uint32_t PLCObject::RepairPLC(void)
{
+ // XXX TODO
+ LogMessage(LOG_WARNING, "RepairPLC not implemented");
return 0;
}
uint32_t PLCObject::ResetLogCount(void)
{
+ m_PLCSyms.ResetLogCount();
return 0;
}
-uint32_t PLCObject::SeedBlob(const binary_t * seed, binary_t * blobID)
+uint32_t PLCObject::SeedBlob(const binary_t *seed, binary_t *blobID)
{
+ // Create a blob with given seed
+ // Output new blob's md5 into blobID
+ // Return 0 if success
+
+ Blob *blob = NULL;
+ try
+ {
+ blob = new Blob(seed->data, seed->dataLength);
+ }
+ catch (int e)
+ {
+ return e;
+ }
+
+ MD5::digest_t digest = blob->digest();
+
+ m_mapBlobIDToBlob[std::vector<uint8_t>((uint8_t)*digest.data, (uint8_t)*digest.data + MD5::digestsize)] = blob;
+
+ blobID->data = (uint8_t *)malloc(MD5::digestsize);
+ if (blobID->data == NULL)
+ {
+ return ENOMEM;
+ }
+ memcpy(blobID->data, digest.data, MD5::digestsize);
+ blobID->dataLength = MD5::digestsize;
+
return 0;
}
-uint32_t PLCObject::SetTraceVariablesList(const list_trace_order_1_t * orders, uint32_t * debugtoken)
+uint32_t PLCObject::SetTraceVariablesList(
+ const list_trace_order_1_t *orders, uint32_t *debugtoken)
{
+ // XXX TODO
+ LogMessage(LOG_WARNING, "SetTraceVariablesList not implemented");
return 0;
}
uint32_t PLCObject::StartPLC(void)
{
+ LogMessage(LOG_INFO, "Starting PLC");
+ uint32_t res = m_PLCSyms.startPLC(m_argc, m_argv);
+ if(res != 0)
+ {
+ m_status.PLCstatus = Broken;
+ return res;
+ }
+ m_status.PLCstatus = Started;
return 0;
}
-uint32_t PLCObject::StopPLC(bool * success)
+uint32_t PLCObject::StopPLC(bool *success)
{
+ LogMessage(LOG_INFO, "Stopping PLC");
+ uint32_t res = m_PLCSyms.stopPLC();
+ if(res != 0)
+ {
+ m_status.PLCstatus = Broken;
+ return res;
+ }
+ m_status.PLCstatus = Stopped;
return 0;
}
+
+uint32_t PLCObject::LogMessage(uint8_t level, std::string message)
+{
+ // Log std::string message with given level
+ return m_PLCSyms.LogMessage(level, (char *)message.c_str(), message.size());
+}
--- a/C_runtime/PLCObject.hpp Fri Apr 26 09:45:02 2024 +0200
+++ b/C_runtime/PLCObject.hpp Sat May 11 19:27:28 2024 +0200
@@ -6,30 +6,100 @@
#if !defined(_PLCObject_hpp_)
#define _PLCObject_hpp_
+#include <map>
+#include <vector>
+#include "blob.hpp"
+
#include "erpc_PLCObject_interface.hpp"
using namespace erpcShim;
+#define FOR_EACH_PLC_SYMBOLS_DO(ACTION) \
+ ACTION(PLC_ID)\
+ ACTION(startPLC)\
+ ACTION(stopPLC)\
+ ACTION(ResetDebugVariables)\
+ ACTION(RegisterDebugVariable)\
+ ACTION(FreeDebugData)\
+ ACTION(GetDebugData)\
+ ACTION(suspendDebug)\
+ ACTION(ResumeDebug)\
+ ACTION(ResetLogCount)\
+ ACTION(GetLogCount)\
+ ACTION(LogMessage)\
+ ACTION(GetLogMessage)
+
+typedef struct s_PLCSyms{
+ uint8_t *PLC_ID;
+ int (*startPLC)(int argc,char **argv);
+ int (*stopPLC)(void);
+ void (*ResetDebugVariables)(void);
+ int (*RegisterDebugVariable)(unsigned int idx, void* force, size_t force_size);
+ void (*FreeDebugData)(void);
+ int (*GetDebugData)(unsigned long *tick, unsigned long *size, void **buffer);
+ int (*suspendDebug)(int disable);
+ void (*ResumeDebug)(void);
+ void (*ResetLogCount)(void);
+ uint32_t (*GetLogCount)(uint8_t level);
+ int (*LogMessage)(uint8_t level, char* buf, uint32_t size);
+ uint32_t (*GetLogMessage)(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec);
+} PLCSyms;
+
class PLCObject : public BeremizPLCObjectService_interface
{
public:
+ PLCObject(void);
~PLCObject(void);
- virtual uint32_t AppendChunkToBlob(const binary_t * data, const binary_t * blobID, binary_t * newBlobID);
- virtual uint32_t GetLogMessage(uint8_t level, uint32_t msgID, log_message * message);
- virtual uint32_t GetPLCID(PSKID * plcID);
- virtual uint32_t GetPLCstatus(PLCstatus * status);
- virtual uint32_t GetTraceVariables(uint32_t debugToken, TraceVariables * traces);
- virtual uint32_t MatchMD5(const char * MD5, bool * match);
- virtual uint32_t NewPLC(const char * md5sum, const binary_t * plcObjectBlobID, const list_extra_file_1_t * extrafiles, bool * success);
- virtual uint32_t PurgeBlobs(void);
- virtual uint32_t RepairPLC(void);
- virtual uint32_t ResetLogCount(void);
- virtual uint32_t SeedBlob(const binary_t * seed, binary_t * blobID);
- virtual uint32_t SetTraceVariablesList(const list_trace_order_1_t * orders, uint32_t * debugtoken);
- virtual uint32_t StartPLC(void);
- virtual uint32_t StopPLC(bool * success);
+ // ERPC interface
+ uint32_t AppendChunkToBlob(const binary_t * data, const binary_t * blobID, binary_t * newBlobID);
+ uint32_t GetLogMessage(uint8_t level, uint32_t msgID, log_message * message);
+ uint32_t GetPLCID(PSKID * plcID);
+ uint32_t GetPLCstatus(PLCstatus * status);
+ uint32_t GetTraceVariables(uint32_t debugToken, TraceVariables * traces);
+ uint32_t MatchMD5(const char * MD5, bool * match);
+ uint32_t NewPLC(const char * md5sum, const binary_t * plcObjectBlobID, const list_extra_file_1_t * extrafiles, bool * success);
+ uint32_t PurgeBlobs(void);
+ uint32_t RepairPLC(void);
+ uint32_t ResetLogCount(void);
+ uint32_t SeedBlob(const binary_t * seed, binary_t * blobID);
+ uint32_t SetTraceVariablesList(const list_trace_order_1_t * orders, uint32_t * debugtoken);
+ uint32_t StartPLC(void);
+ uint32_t StopPLC(bool * success);
+
+ //
+
+ private:
+ // A map of all the blobs
+ std::map<std::vector<uint8_t>, Blob*> m_mapBlobIDToBlob;
+
+ // PLC object library handle
+ void * m_handle;
+
+ // Symbols resolved from the PLC object
+ PLCSyms m_PLCSyms;
+
+ // argc and argv for the PLC object
+ int m_argc;
+ char ** m_argv;
+
+ // PLC status
+ PLCstatus m_status;
+
+ // PLC ID
+ PSKID m_plcID;
+
+ uint32_t BlobAsFile(const binary_t * BlobID, std::filesystem::path filename);
+ uint32_t LoadPLC(void);
+ uint32_t UnLoadPLC(void);
+ uint32_t LogMessage(uint8_t level, std::string message);
+
+
+
+
+
+
};
#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/C_runtime/README.md Sat May 11 19:27:28 2024 +0200
@@ -0,0 +1,11 @@
+# Beremiz C++ runtime
+
+This project is licensed under the [LPGLv2](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html) license.
+
+## Warning: Work in Progress
+
+**Please note that this project is currently a work in progress.**
+
+## Description
+
+Beremiz C++ runtime. Loads shared object produced by Beremiz but doesn't use python.
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/C_runtime/blob.cpp Sat May 11 19:27:28 2024 +0200
@@ -0,0 +1,82 @@
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "blob.hpp"
+#include <unistd.h>
+
+Blob::Blob(uint8_t *seedData, size_t seedLength)
+{
+ // Create a temporary file to store blob data
+ // not using tmpfile() because we need to know the filename
+ // for later renaming and avoid deletion on close
+
+ // Assume that a tmp directory exists in the current directory
+ uint8_t template_name[] = "tmp/blobXXXXXX";
+ int fd = mkstemp((char *)template_name);
+ if (fd == -1) {
+ throw errno;
+ }
+
+ // Open file for stdlib I/O
+ m_file = fdopen(fd, "w+");
+ if (m_file == NULL) {
+ throw errno;
+ }
+
+ // Save a copy of the filename
+ m_filename = (char *)template_name;
+
+ // Seed the MD5 hash with the seed data
+ md5.update(seedData, seedLength);
+}
+
+Blob::~Blob() {
+ if (m_file != NULL) {
+ std::fclose(m_file);
+ std::remove(m_filename.c_str());
+ }
+}
+
+MD5::digest_t Blob::digest() {
+ return md5.digest();
+}
+
+uint32_t Blob::appendChunk(uint8_t *data, size_t length) {
+ // Write data to file
+ if (std::fwrite(data, 1, length, m_file) != length) {
+ return errno;
+ }
+
+ // Update MD5 hash
+ md5.update(data, length);
+
+ return 0;
+}
+
+uint32_t Blob::asFile(std::filesystem::path &filename)
+{
+ // Flush file
+ if (std::fflush(m_file) != 0) {
+ return errno;
+ }
+
+ // Sync file to disk
+ if (fsync(fileno(m_file)) != 0) {
+ return errno;
+ }
+
+ // Close file
+ if (std::fclose(m_file) != 0) {
+ return errno;
+ }
+
+ m_file = NULL;
+
+ // Rename temp file to final file
+ if (std::rename(m_filename.c_str(), filename.c_str()) != 0) {
+ return errno;
+ }
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/C_runtime/blob.hpp Sat May 11 19:27:28 2024 +0200
@@ -0,0 +1,24 @@
+#ifndef BLOB_HPP
+#define BLOB_HPP
+
+#include <string>
+#include <filesystem>
+
+#include "md5.hpp"
+
+class Blob
+{
+public:
+ Blob(uint8_t *seedData, size_t seedLength);
+ ~Blob();
+ MD5::digest_t digest();
+ uint32_t appendChunk(uint8_t *data, size_t length);
+ uint32_t asFile(std::filesystem::path &filename);
+
+private:
+ MD5 md5;
+ std::FILE * m_file;
+ std::filesystem::path m_filename;
+};
+
+#endif // BLOB_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/C_runtime/md5.cpp Sat May 11 19:27:28 2024 +0200
@@ -0,0 +1,325 @@
+/* MD5
+ converted to C++ class by Frank Thilo (thilo@unix-ag.org)
+ for bzflag (http://www.bzflag.org)
+
+ based on:
+
+ md5.h and md5.c
+ reference implemantion of RFC 1321
+
+ Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+/* interface header */
+#include "md5.hpp"
+
+// Constants for MD5Transform routine.
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+///////////////////////////////////////////////
+
+// F, G, H and I are basic MD5 functions.
+inline uint32_t MD5::F(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x & y | ~x & z;
+}
+
+inline uint32_t MD5::G(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x & z | y & ~z;
+}
+
+inline uint32_t MD5::H(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x ^ y ^ z;
+}
+
+inline uint32_t MD5::I(uint32_t x, uint32_t y, uint32_t z)
+{
+ return y ^ (x | ~z);
+}
+
+// rotate_left rotates x left n bits.
+inline uint32_t MD5::rotate_left(uint32_t x, int n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+// Rotation is separate from addition to prevent recomputation.
+inline void MD5::FF(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
+{
+ a = rotate_left(a + F(b, c, d) + x + ac, s) + b;
+}
+
+inline void MD5::GG(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
+{
+ a = rotate_left(a + G(b, c, d) + x + ac, s) + b;
+}
+
+inline void MD5::HH(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
+{
+ a = rotate_left(a + H(b, c, d) + x + ac, s) + b;
+}
+
+inline void MD5::II(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
+{
+ a = rotate_left(a + I(b, c, d) + x + ac, s) + b;
+}
+
+//////////////////////////////////////////////
+
+// default ctor, just initailize
+MD5::MD5()
+{
+ init();
+}
+
+//////////////////////////////
+
+void MD5::init()
+{
+ count[0] = 0;
+ count[1] = 0;
+
+ // load magic initialization constants.
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+}
+
+//////////////////////////////
+
+// decodes input (unsigned char) into output (uint32_t). Assumes len is a multiple of 4.
+void MD5::decode(uint32_t output[], const uint8_t input[], size_type len)
+{
+ for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j + 1]) << 8) |
+ (((uint32_t)input[j + 2]) << 16) | (((uint32_t)input[j + 3]) << 24);
+}
+
+//////////////////////////////
+
+// encodes input (uint32_t) into output (unsigned char). Assumes len is
+// a multiple of 4.
+void MD5::encode(uint8_t output[], const uint32_t input[], size_type len)
+{
+ for (size_type i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output[j] = input[i] & 0xff;
+ output[j + 1] = (input[i] >> 8) & 0xff;
+ output[j + 2] = (input[i] >> 16) & 0xff;
+ output[j + 3] = (input[i] >> 24) & 0xff;
+ }
+}
+
+//////////////////////////////
+
+// apply MD5 algo on a block
+void MD5::transform(const uint8_t block[blocksize])
+{
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+ decode(x, block, blocksize);
+
+ /* Round 1 */
+ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ // Zeroize sensitive information.
+ memset(x, 0, sizeof x);
+}
+
+//////////////////////////////
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block
+void MD5::update(const unsigned char input[], size_type length)
+{
+ // compute number of bytes mod 64
+ size_type index = count[0] / 8 % blocksize;
+
+ // Update number of bits
+ if ((count[0] += (length << 3)) < (length << 3))
+ count[1]++;
+ count[1] += (length >> 29);
+
+ // number of bytes we need to fill in buffer
+ size_type firstpart = 64 - index;
+
+ size_type i;
+
+ // transform as many times as possible.
+ if (length >= firstpart)
+ {
+ // fill buffer first, transform
+ memcpy(&buffer[index], input, firstpart);
+ transform(buffer);
+
+ // transform chunks of blocksize (64 bytes)
+ for (i = firstpart; i + blocksize <= length; i += blocksize)
+ transform(&input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ // buffer remaining input
+ memcpy(&buffer[index], &input[i], length - i);
+}
+
+//////////////////////////////
+
+
+MD5::digest_t MD5::digest()
+{
+ static const unsigned char 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};
+
+ // Copies of hash state
+ uint8_t _buffer[blocksize];
+ uint32_t _count[2];
+ uint32_t _state[4];
+
+ // Backup hash state at previous block boundary
+ memcpy(_buffer, buffer, blocksize);
+ memcpy(_count, count, 8);
+ memcpy(_state, state, 16);
+
+ // Save number of bits
+ unsigned char bits[8];
+ encode(bits, count, 8);
+
+ // pad out to 56 mod 64.
+ size_type index = count[0] / 8 % 64;
+ size_type padLen = (index < 56) ? (56 - index) : (120 - index);
+ update(padding, padLen);
+
+ // Append length (before padding)
+ update(bits, 8);
+
+ // Store state in digest
+ digest_t result;
+ encode(result.data, state, 16);
+
+ // revert hash state to previous hash boundary
+ memcpy(buffer, _buffer, blocksize);
+ memcpy(count, _count, 8);
+ memcpy(state, _state, 16);
+
+ return result;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/C_runtime/md5.hpp Sat May 11 19:27:28 2024 +0200
@@ -0,0 +1,88 @@
+/* MD5
+
+ Modified in 2024 for use in Beremiz by Edouard Tisserant
+
+ converted to C++ class by Frank Thilo (thilo@unix-ag.org)
+ for bzflag (http://www.bzflag.org)
+
+ based on:
+
+ md5.h and md5.c
+ reference implementation of RFC 1321
+
+ Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+#ifndef BZF_MD5_H
+#define BZF_MD5_H
+
+#include <cstdint>
+
+// a small class for calculating MD5 hashes of strings or byte arrays
+// it is not meant to be fast or secure
+//
+// usage: 1) feed it blocks of uchars with update()
+// 2) get digest() data
+//
+// assumes that char is 8 bit and int is 32 bit
+class MD5
+{
+public:
+ typedef unsigned int size_type; // must be 32bit
+
+ MD5();
+ void update(const unsigned char *buf, size_type length);
+ typedef struct {
+ uint8_t data[16];
+ } digest_t;
+ digest_t digest();
+ enum
+ {
+ blocksize = 64,
+ digestsize = 16
+ };
+
+private:
+ void init();
+
+ void transform(const uint8_t block[blocksize]);
+ static void decode(uint32_t output[], const uint8_t input[], size_type len);
+ static void encode(uint8_t output[], const uint32_t input[], size_type len);
+
+ uint8_t buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
+ uint32_t count[2]; // 64bit counter for number of bits (lo, hi)
+ uint32_t state[4]; // digest so far
+
+ // low level logic operations
+ static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z);
+ static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z);
+ static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z);
+ static inline uint32_t I(uint32_t x, uint32_t y, uint32_t z);
+ static inline uint32_t rotate_left(uint32_t x, int n);
+ static inline void FF(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+ static inline void GG(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+ static inline void HH(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+ static inline void II(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+};
+
+#endif
\ No newline at end of file
--- a/C_runtime/posix_main.cpp Fri Apr 26 09:45:02 2024 +0200
+++ b/C_runtime/posix_main.cpp Sat May 11 19:27:28 2024 +0200
@@ -1,3 +1,14 @@
+/*
+ * Beremiz C++ runtime
+ *
+ * This file implements Beremiz C++ runtime Command Line Interface for POSIX
+ *
+ * Based on erpcsniffer.cpp, BSD-3-Clause, Copyright 2017 NXP
+ *
+ * Copyright 2024 Beremiz SAS
+ *
+ * See COPYING for licensing details
+ */
#include <stdlib.h>
#include <vector>
@@ -294,8 +305,18 @@
m_workingDir = std::filesystem::current_path().c_str();
} else {
m_workingDir = m_positionalArgs[0].c_str();
+ std::filesystem::current_path(m_workingDir);
}
+ // remove temporary directory if it already exists
+ if (std::filesystem::exists("tmp"))
+ {
+ std::filesystem::remove_all("tmp");
+ }
+
+ // Create temporary directory in working directory
+ std::filesystem::create_directory("tmp");
+
Transport *_transport;
switch (m_transport)
{