edouard@3937: edouard@3940: #include edouard@3940: #include edouard@3940: #include edouard@3940: #include edouard@3940: #include edouard@3937: edouard@3937: #include "Logging.hpp" edouard@3937: edouard@3937: #include "PLCObject.hpp" edouard@3937: edouard@3940: #include "beremiz.h" edouard@3940: edouard@3940: edouard@3940: // File name of the last transferred PLC md5 hex digest edouard@3940: // with typo in the name, for compatibility with Python runtime edouard@3940: #define LastTransferredPLC "lasttransferedPLC.md5" edouard@3940: edouard@3940: // File name of the extra files list edouard@3940: #define ExtraFilesList "extra_files.txt" edouard@3940: edouard@3940: edouard@3940: edouard@3940: PLCObject::PLCObject(void) edouard@3940: { edouard@3940: } edouard@3940: edouard@3937: PLCObject::~PLCObject(void) edouard@3937: { edouard@3937: } edouard@3937: edouard@3940: uint32_t PLCObject::AppendChunkToBlob( edouard@3940: const binary_t *data, const binary_t *blobID, binary_t *newBlobID) edouard@3940: { edouard@3940: // Append data to blob with given blobID edouard@3940: // Output new blob's md5 into newBlobID edouard@3940: // Return 0 if success edouard@3940: edouard@3940: auto nh = m_mapBlobIDToBlob.extract(std::vector( edouard@3940: blobID->data, blobID->data + blobID->dataLength)); edouard@3940: if (nh.empty()) edouard@3940: { edouard@3940: return ENOENT; edouard@3940: } edouard@3940: edouard@3940: Blob *blob = nh.mapped(); edouard@3940: edouard@3940: uint32_t res = blob->appendChunk(data->data, data->dataLength); edouard@3940: if (res != 0) edouard@3940: { edouard@3940: return res; edouard@3940: } edouard@3940: edouard@3940: MD5::digest_t digest = blob->digest(); edouard@3940: edouard@3940: nh.key() = std::vector( edouard@3940: (uint8_t)*digest.data, (uint8_t)*digest.data + MD5::digestsize); edouard@3940: edouard@3940: m_mapBlobIDToBlob.insert(std::move(nh)); edouard@3940: edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: #define LOG_READ_BUFFER_SIZE 1 << 10 // 1KB edouard@3940: edouard@3940: uint32_t PLCObject::GetLogMessage( edouard@3940: uint8_t level, uint32_t msgID, log_message *message) edouard@3940: { edouard@3940: char buf[LOG_READ_BUFFER_SIZE]; edouard@3940: uint32_t tick; edouard@3940: uint32_t tv_sec; edouard@3940: uint32_t tv_nsec; edouard@3940: edouard@3940: uint32_t resultLen = m_PLCSyms.GetLogMessage( edouard@3940: level, msgID, buf, LOG_READ_BUFFER_SIZE - 1, edouard@3940: &tick, &tv_sec, &tv_nsec); edouard@3940: edouard@3940: if (resultLen == 0) edouard@3940: { edouard@3940: return ENOENT; edouard@3940: } edouard@3940: edouard@3940: // Get log message with given msgID edouard@3940: message->msg = (char *)malloc(resultLen); edouard@3940: if (message->msg == NULL) edouard@3940: { edouard@3940: return ENOMEM; edouard@3940: } edouard@3940: // Copy the log message into eRPC message edouard@3940: memcpy(message->msg, buf, resultLen); edouard@3940: message->msg[resultLen + 1] = '\0'; edouard@3940: edouard@3940: message->tick = tick; edouard@3940: message->sec = tv_sec; edouard@3940: message->nsec = tv_nsec; edouard@3940: edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::GetPLCID(PSKID *plcID) edouard@3940: { edouard@3940: // Get PLC ID edouard@3940: *plcID = m_plcID; edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::GetPLCstatus(PLCstatus *status) edouard@3940: { edouard@3940: // Get PLC status edouard@3940: *status = m_status; edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::GetTraceVariables( edouard@3940: uint32_t debugToken, TraceVariables *traces) edouard@3940: { edouard@3940: // XXX TODO edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::MatchMD5(const char *MD5, bool *match) edouard@3940: { edouard@3940: // Load the last transferred PLC md5 hex digest edouard@3940: std::string md5sum; edouard@3940: std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum; edouard@3940: edouard@3940: // Compare the given MD5 with the last transferred PLC md5 edouard@3940: *match = (md5sum == MD5); edouard@3940: edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: #if defined(_WIN32) || defined(_WIN64) edouard@3940: // For Windows platform edouard@3940: #define SHARED_OBJECT_EXT ".dll" edouard@3940: #elif defined(__APPLE__) || defined(__MACH__) edouard@3940: // For MacOS platform edouard@3940: #define SHARED_OBJECT_EXT ".dylib" edouard@3940: #else edouard@3940: // For Linux/Unix platform edouard@3940: #define SHARED_OBJECT_EXT ".so" edouard@3940: #endif edouard@3940: edouard@3940: uint32_t PLCObject::BlobAsFile( edouard@3940: const binary_t *BlobID, std::filesystem::path filename) edouard@3940: { edouard@3940: // Extract the blob from the map edouard@3940: auto nh = m_mapBlobIDToBlob.extract( edouard@3940: std::vector(BlobID->data, BlobID->data + BlobID->dataLength)); edouard@3940: if (nh.empty()) edouard@3940: { edouard@3940: return ENOENT; edouard@3940: } edouard@3940: Blob *blob = nh.mapped(); edouard@3940: edouard@3940: // Realize the blob into a file edouard@3940: uint32_t res = blob->asFile(filename); edouard@3940: edouard@3940: delete blob; edouard@3940: edouard@3940: if (res != 0) edouard@3940: { edouard@3940: return res; edouard@3940: } edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::NewPLC( edouard@3940: const char *md5sum, const binary_t *plcObjectBlobID, edouard@3940: const list_extra_file_1_t *extrafiles, bool *success) edouard@3940: { edouard@3940: // Concatenate md5sum and shared object extension to obtain filename edouard@3940: std::filesystem::path filename = edouard@3940: std::filesystem::path(md5sum) += SHARED_OBJECT_EXT; edouard@3940: edouard@3940: // Create the PLC object shared object file edouard@3940: BlobAsFile(plcObjectBlobID, filename); edouard@3940: edouard@3940: // create "lasttransferedPLC.md5" file and Save md5sum in it edouard@3940: std::ofstream(std::string(LastTransferredPLC), std::ios::binary) << md5sum; edouard@3940: edouard@3940: // create "extra_files.txt" file edouard@3940: std::ofstream extra_files_log(std::string(ExtraFilesList), std::ios::binary); edouard@3940: edouard@3940: // Create extra files edouard@3940: for (int i = 0; i < extrafiles->elementsCount; i++) edouard@3940: { edouard@3940: extra_file *extrafile = extrafiles->elements + i; edouard@3940: edouard@3940: BlobAsFile(plcObjectBlobID, extrafile->fname); edouard@3940: edouard@3940: // Save the extra file name in "extra_files.txt" edouard@3940: extra_files_log << extrafile->fname << std::endl; edouard@3940: } edouard@3940: edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: #define DLSYM(sym) \ edouard@3940: do \ edouard@3940: { \ edouard@3940: m_PLCSyms.sym = (decltype(m_PLCSyms.sym))dlsym(m_handle, #sym); \ edouard@3940: if (m_PLCSyms.sym == NULL) \ edouard@3940: { \ edouard@3940: return errno; \ edouard@3940: } \ edouard@3940: } while (0); edouard@3940: edouard@3940: uint32_t PLCObject::LoadPLC(void) edouard@3940: { edouard@3940: // Load the last transferred PLC md5 hex digest edouard@3940: std::string md5sum; edouard@3940: std::ifstream(std::string(LastTransferredPLC), std::ios::binary) >> md5sum; edouard@3940: edouard@3940: // Concatenate md5sum and shared object extension to obtain filename edouard@3940: std::filesystem::path filename = std::filesystem::path(md5sum) += SHARED_OBJECT_EXT; edouard@3940: edouard@3940: // Load the shared object file edouard@3940: m_handle = dlopen(filename.c_str(), RTLD_NOW); edouard@3940: if (m_handle == NULL) edouard@3940: { edouard@3940: return errno; edouard@3940: } edouard@3940: edouard@3940: // Resolve shared object symbols edouard@3940: FOR_EACH_PLC_SYMBOLS_DO(DLSYM); edouard@3940: edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: #define ULSYM(sym) \ edouard@3940: do \ edouard@3940: { \ edouard@3940: m_PLCSyms.sym = NULL; \ edouard@3940: } while (0); edouard@3940: edouard@3940: uint32_t PLCObject::UnLoadPLC(void) edouard@3940: { edouard@3940: // Unload the shared object file edouard@3940: FOR_EACH_PLC_SYMBOLS_DO(ULSYM); edouard@3940: dlclose(m_handle); edouard@3940: edouard@3937: return 0; edouard@3937: } edouard@3937: edouard@3937: uint32_t PLCObject::PurgeBlobs(void) edouard@3937: { edouard@3940: // Purge all blobs edouard@3940: edouard@3940: for (auto &blob : m_mapBlobIDToBlob) edouard@3940: { edouard@3940: delete blob.second; edouard@3940: } edouard@3940: m_mapBlobIDToBlob.clear(); edouard@3940: edouard@3937: return 0; edouard@3937: } edouard@3937: edouard@3937: uint32_t PLCObject::RepairPLC(void) edouard@3937: { edouard@3940: // XXX TODO edouard@3940: LogMessage(LOG_WARNING, "RepairPLC not implemented"); edouard@3937: return 0; edouard@3937: } edouard@3937: edouard@3937: uint32_t PLCObject::ResetLogCount(void) edouard@3937: { edouard@3940: m_PLCSyms.ResetLogCount(); edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::SeedBlob(const binary_t *seed, binary_t *blobID) edouard@3940: { edouard@3940: // Create a blob with given seed edouard@3940: // Output new blob's md5 into blobID edouard@3940: // Return 0 if success edouard@3940: edouard@3940: Blob *blob = NULL; edouard@3940: try edouard@3940: { edouard@3940: blob = new Blob(seed->data, seed->dataLength); edouard@3940: } edouard@3940: catch (int e) edouard@3940: { edouard@3940: return e; edouard@3940: } edouard@3940: edouard@3940: MD5::digest_t digest = blob->digest(); edouard@3940: edouard@3940: m_mapBlobIDToBlob[std::vector((uint8_t)*digest.data, (uint8_t)*digest.data + MD5::digestsize)] = blob; edouard@3940: edouard@3940: blobID->data = (uint8_t *)malloc(MD5::digestsize); edouard@3940: if (blobID->data == NULL) edouard@3940: { edouard@3940: return ENOMEM; edouard@3940: } edouard@3940: memcpy(blobID->data, digest.data, MD5::digestsize); edouard@3940: blobID->dataLength = MD5::digestsize; edouard@3940: edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::SetTraceVariablesList( edouard@3940: const list_trace_order_1_t *orders, uint32_t *debugtoken) edouard@3940: { edouard@3940: // XXX TODO edouard@3940: LogMessage(LOG_WARNING, "SetTraceVariablesList not implemented"); edouard@3937: return 0; edouard@3937: } edouard@3937: edouard@3937: uint32_t PLCObject::StartPLC(void) edouard@3937: { edouard@3940: LogMessage(LOG_INFO, "Starting PLC"); edouard@3940: uint32_t res = m_PLCSyms.startPLC(m_argc, m_argv); edouard@3940: if(res != 0) edouard@3940: { edouard@3940: m_status.PLCstatus = Broken; edouard@3940: return res; edouard@3940: } edouard@3940: m_status.PLCstatus = Started; edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::StopPLC(bool *success) edouard@3940: { edouard@3940: LogMessage(LOG_INFO, "Stopping PLC"); edouard@3940: uint32_t res = m_PLCSyms.stopPLC(); edouard@3940: if(res != 0) edouard@3940: { edouard@3940: m_status.PLCstatus = Broken; edouard@3940: return res; edouard@3940: } edouard@3940: m_status.PLCstatus = Stopped; edouard@3940: return 0; edouard@3940: } edouard@3940: edouard@3940: uint32_t PLCObject::LogMessage(uint8_t level, std::string message) edouard@3940: { edouard@3940: // Log std::string message with given level edouard@3940: return m_PLCSyms.LogMessage(level, (char *)message.c_str(), message.size()); edouard@3940: }