# HG changeset patch # User Edouard Tisserant # Date 1715448448 -7200 # Node ID 934bd46a7500c9c9ee56283a9cf43dbe04939ec0 # Parent b73d6668eba31ed637cce53bc77fc71ad69ac8e1 C++ runtime: WIP: untested PLCObject implementation. Still missing tracing. diff -r b73d6668eba3 -r 934bd46a7500 .gitignore --- 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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/Makefile --- 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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/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 +#include +#include +#include +#include +#include #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) -{ - return 0; -} - -uint32_t PLCObject::GetLogMessage(uint8_t level, uint32_t msgID, log_message * message) -{ - return 0; -} - -uint32_t PLCObject::GetPLCID(PSKID * plcID) -{ - return 0; -} - -uint32_t PLCObject::GetPLCstatus(PLCstatus * status) -{ - return 0; -} - -uint32_t PLCObject::GetTraceVariables(uint32_t debugToken, TraceVariables * traces) -{ - return 0; -} - -uint32_t PLCObject::MatchMD5(const char * MD5, bool * match) -{ - return 0; -} - -uint32_t PLCObject::NewPLC(const char * md5sum, const binary_t * plcObjectBlobID, const list_extra_file_1_t * extrafiles, bool * success) -{ +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( + 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)*digest.data, (uint8_t)*digest.data + MD5::digestsize); + + m_mapBlobIDToBlob.insert(std::move(nh)); + + return 0; +} + +#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) +{ + // 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; +} + +#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(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::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; +} + +#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; +} + +#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) { - return 0; -} - -uint32_t PLCObject::SeedBlob(const binary_t * seed, binary_t * blobID) -{ - return 0; -} - -uint32_t PLCObject::SetTraceVariablesList(const list_trace_order_1_t * orders, uint32_t * debugtoken) -{ + m_PLCSyms.ResetLogCount(); + return 0; +} + +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)*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) +{ + // XXX TODO + LogMessage(LOG_WARNING, "SetTraceVariablesList not implemented"); return 0; } uint32_t PLCObject::StartPLC(void) { - return 0; -} - -uint32_t PLCObject::StopPLC(bool * success) -{ - return 0; -} + 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) +{ + 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()); +} diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/PLCObject.hpp --- 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 +#include +#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, 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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/README.md --- /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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/blob.cpp --- /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 +#include + +#include "blob.hpp" +#include + +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; +} diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/blob.hpp --- /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 +#include + +#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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/md5.cpp --- /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 +#include + +/* 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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/md5.hpp --- /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 + +// 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 diff -r b73d6668eba3 -r 934bd46a7500 C_runtime/posix_main.cpp --- 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 #include @@ -294,7 +305,17 @@ 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)