commit 1776a2bf0d76e0b2111420275fb04890c5a812bf Author: lnk Date: Thu Jan 16 16:17:01 2025 +0800 lnk commit front code diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..de2c28a --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,10 @@ +{ + "ExpandedNodes": [ + "", + "\\include", + "\\json", + "\\mms" + ], + "SelectedNode": "\\mms\\main.c", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/pt61850netd_pqfe/FileContentIndex/b26e7c6e-ba2e-44cb-b930-f4408fe18097.vsidx b/.vs/pt61850netd_pqfe/FileContentIndex/b26e7c6e-ba2e-44cb-b930-f4408fe18097.vsidx new file mode 100644 index 0000000..5bce07a Binary files /dev/null and b/.vs/pt61850netd_pqfe/FileContentIndex/b26e7c6e-ba2e-44cb-b930-f4408fe18097.vsidx differ diff --git a/.vs/pt61850netd_pqfe/v17/.wsuo b/.vs/pt61850netd_pqfe/v17/.wsuo new file mode 100644 index 0000000..720f51d Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/.wsuo differ diff --git a/.vs/pt61850netd_pqfe/v17/Browse.VC.db b/.vs/pt61850netd_pqfe/v17/Browse.VC.db new file mode 100644 index 0000000..9367188 Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/Browse.VC.db differ diff --git a/.vs/pt61850netd_pqfe/v17/DocumentLayout.json b/.vs/pt61850netd_pqfe/v17/DocumentLayout.json new file mode 100644 index 0000000..da06296 --- /dev/null +++ b/.vs/pt61850netd_pqfe/v17/DocumentLayout.json @@ -0,0 +1,54 @@ +{ + "Version": 1, + "WorkspaceRootPath": "D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\", + "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\mms\\main.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}", + "RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:mms\\main.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}" + }, + { + "AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\json\\create_json.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}", + "RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:json\\create_json.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}" + } + ], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedWidth": 200, + "SelectedChildIndex": 1, + "Children": [ + { + "$type": "Document", + "DocumentIndex": 1, + "Title": "create_json.cpp", + "DocumentMoniker": "D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\json\\create_json.cpp", + "RelativeDocumentMoniker": "json\\create_json.cpp", + "ToolTip": "D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\json\\create_json.cpp", + "RelativeToolTip": "json\\create_json.cpp", + "ViewState": "AgIAAD8CAAAAAAAAAAAQwDMEAAAEAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|", + "WhenOpened": "2024-11-15T06:54:01.719Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 0, + "Title": "main.c", + "DocumentMoniker": "D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\mms\\main.c", + "RelativeDocumentMoniker": "mms\\main.c", + "ToolTip": "D:\\canneng\\pms3.0_czy_2024-10-9\\pt61850netd_pqfe\\mms\\main.c", + "RelativeToolTip": "mms\\main.c", + "ViewState": "AgIAAAcBAAAAAAAAAAAowBUBAAASAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000423|", + "WhenOpened": "2024-11-15T06:46:56.891Z", + "EditorCaption": "" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/24ff2127f6df48e5/MMSCLI_LOG.ipch b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/24ff2127f6df48e5/MMSCLI_LOG.ipch new file mode 100644 index 0000000..ea6f721 Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/24ff2127f6df48e5/MMSCLI_LOG.ipch differ diff --git a/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/3dc132dc77509067/CREATE_JSON.ipch b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/3dc132dc77509067/CREATE_JSON.ipch new file mode 100644 index 0000000..16749c3 Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/3dc132dc77509067/CREATE_JSON.ipch differ diff --git a/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/7d785466d3c72295/MMSCLI_RPT.ipch b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/7d785466d3c72295/MMSCLI_RPT.ipch new file mode 100644 index 0000000..3b231ac Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/7d785466d3c72295/MMSCLI_RPT.ipch differ diff --git a/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/92a79bbe7bc3f92f/MMSCLIENT.ipch b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/92a79bbe7bc3f92f/MMSCLIENT.ipch new file mode 100644 index 0000000..ca8fe43 Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/92a79bbe7bc3f92f/MMSCLIENT.ipch differ diff --git a/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/c7f586a7cca8b352/MAIN.ipch b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/c7f586a7cca8b352/MAIN.ipch new file mode 100644 index 0000000..bb3d88a Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/ipch/AutoPCH/c7f586a7cca8b352/MAIN.ipch differ diff --git a/.vs/pt61850netd_pqfe/v17/workspaceFileList.bin b/.vs/pt61850netd_pqfe/v17/workspaceFileList.bin new file mode 100644 index 0000000..f026613 Binary files /dev/null and b/.vs/pt61850netd_pqfe/v17/workspaceFileList.bin differ diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..8809651 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..bfa1cc6 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "C:/Users/lnk/Downloads/mingw32/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..fbed8ec --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "d:/canneng/pms3.0_czy_2024-10-9/pt61850netd_pqfe/mms", + "program": "d:/canneng/pms3.0_czy_2024-10-9/pt61850netd_pqfe/mms/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d3be971 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,141 @@ +{ + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false, + "files.associations": { + "array": "cpp", + "string": "cpp", + "string_view": "cpp", + "span": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "format": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "text_encoding": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "chrono": "cpp", + "db_interface.h": "c", + "rdb_client.h": "c", + "bitset": "cpp", + "regex": "cpp", + "unordered_set": "cpp", + "stdlib.h": "c", + "apr_time.h": "c", + "queue": "cpp", + "xmltools.h": "c", + "simpleproducer.h": "c", + "stdbool.h": "c", + "node.h": "c", + "save2json.h": "c" + } +} \ No newline at end of file diff --git a/build-ubuntu.sh b/build-ubuntu.sh new file mode 100644 index 0000000..ee94ebc --- /dev/null +++ b/build-ubuntu.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +DEBUG='-f Makefile.Debug' +RELEASE='-f Makefile.Release' + +make_function() +{ + qmake pt61850netd_pqfe.pro + make $1 distclean + qmake pt61850netd_pqfe.pro + make $1 clean + make $1 -j 2 + make $1 install +} + +echo Usage: "build-xxx.sh release/debug/all/clean/\"\" " +echo " release|\"\" : Make version release " +echo " debug : Make version debug " +echo " all : Make version debug and release" +echo " clean : Make clean " + +if [ "$1" = "" ]; then + make_function "$RELEASE" +fi +if [ "$1" = "release" ]; then + make_function "$RELEASE" +fi +if [ "$1" = "debug" ]; then + make_function "$DEBUG" +fi +if [ "$1" = "all" ]; then + make_function "$RELEASE" + make_function "$DEBUG" +fi +if [ "$1" = "clean" ]; then + qmake + make distclean +fi + diff --git a/cfg_parse/CVS/Entries b/cfg_parse/CVS/Entries new file mode 100644 index 0000000..462159e --- /dev/null +++ b/cfg_parse/CVS/Entries @@ -0,0 +1,2 @@ +/cfg_parser.cpp/1.20/Tue Jan 22 07:41:32 2019// +D diff --git a/cfg_parse/CVS/Entries.Extra b/cfg_parse/CVS/Entries.Extra new file mode 100644 index 0000000..376c5b8 --- /dev/null +++ b/cfg_parse/CVS/Entries.Extra @@ -0,0 +1 @@ +/cfg_parser.cpp////*//// diff --git a/cfg_parse/CVS/Entries.Extra.Old b/cfg_parse/CVS/Entries.Extra.Old new file mode 100644 index 0000000..376c5b8 --- /dev/null +++ b/cfg_parse/CVS/Entries.Extra.Old @@ -0,0 +1 @@ +/cfg_parser.cpp////*//// diff --git a/cfg_parse/CVS/Entries.Old b/cfg_parse/CVS/Entries.Old new file mode 100644 index 0000000..edbcdbe --- /dev/null +++ b/cfg_parse/CVS/Entries.Old @@ -0,0 +1,2 @@ +/cfg_parser.cpp/1.19/Fri Jan 18 02:42:35 2019// +D diff --git a/cfg_parse/CVS/Repository b/cfg_parse/CVS/Repository new file mode 100644 index 0000000..498d964 --- /dev/null +++ b/cfg_parse/CVS/Repository @@ -0,0 +1 @@ +jspqfe/src/pt61850netd_pqfe/source/cfg_parse diff --git a/cfg_parse/CVS/Root b/cfg_parse/CVS/Root new file mode 100644 index 0000000..0536776 --- /dev/null +++ b/cfg_parse/CVS/Root @@ -0,0 +1 @@ +:ext:lizhongming@10.0.0.2:/JoyProject diff --git a/cfg_parse/CVS/Template b/cfg_parse/CVS/Template new file mode 100644 index 0000000..e69de29 diff --git a/cfg_parse/SimpleProducer.cpp b/cfg_parse/SimpleProducer.cpp new file mode 100644 index 0000000..86aba7b --- /dev/null +++ b/cfg_parse/SimpleProducer.cpp @@ -0,0 +1,866 @@ +/* +* Description: Simple Producer demo +*/ +#include // 用于 std::ifstream +#include // 用于 std::stringstream +#include +#include +#include +#include +#include "../mms/db_interface.h" +#include "../include/rocketmq/CProducer.h" +#include "../include/rocketmq/CMessage.h" +#include "../include/rocketmq/CSendResult.h" + +#include "../include/rocketmq/SimpleProducer.h" + +//测试300数据用lnk20241202 +#include +#include +//测试300数据用 +//lnk20241209添加队列选择 +#include "../include/rocketmq/MQSelector.h" +#include "../include/rocketmq/MQMessageQueue.h" +//#include +#include +#include +//lnk20241209添加队列选择 +#include + +// 引入提供的消费者接口头文件 +#include "../include/rocketmq/CPushConsumer.h" +#include "../include/rocketmq/CCommon.h" +#include "../include/rocketmq/CMessageExt.h" +#include +#include // 用于互斥锁(在 C++98 中没有 std::mutex) +#include // for std::pair + +using namespace std; + +extern std::string G_ROCKETMQ_PRODUCER;//rocketmq producer +extern std::string G_ROCKETMQ_IPPORT;//rocketmq ip+port +extern std::string G_ROCKETMQ_TOPIC;//topie +extern std::string G_ROCKETMQ_TAG;//tag +extern std::string G_ROCKETMQ_KEY;//key + +#ifdef __cplusplus +extern "C" { +#endif + +extern std::string G_MQCONSUMER_TOPIC_SET; // C++ 中的全局变量声明 + +#ifdef __cplusplus +} +#endif + +extern int QUEUENUM; + +extern int g_front_seg_index; +extern char subdir[128]; +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//消费者连接秘钥 +extern std::string G_MQCONSUMER_ACCESSKEY; +extern std::string G_MQCONSUMER_SECRETKEY; +extern std::string G_MQCONSUMER_CHANNEL; + +// 前向声明 RocketMQConsumer 类 +class RocketMQConsumer; + +// 全局映射:CPushConsumer* -> RocketMQConsumer* +std::map g_consumerMap;// +pthread_mutex_t g_consumerMapMutex = PTHREAD_MUTEX_INITIALIZER; + +class RocketMQConsumer { +public: + // 构造函数:初始化消费者并启动 + RocketMQConsumer(const std::string& consumerName, const std::string& nameServer, const std::string& groupId); + + // 禁用拷贝和赋值 + RocketMQConsumer(const RocketMQConsumer&) {} + RocketMQConsumer& operator=(const RocketMQConsumer&) { return *this; } + + // 订阅主题和标签,并注册回调 + void subscribe(const std::string& topic, const std::string& tag, MessageCallBack callback); + + // 启动消费者 + void start(); + + //修改消费模式 + void setConsumerMessageModel(const std::string& topic); + + // 析构函数:关闭并销毁消费者 + ~RocketMQConsumer(); + +private: + CPushConsumer* consumer_; // C 接口消费者指针 + //MessageCallBack messageCallback_; // 函数指针用于回调 + std::map, MessageCallBack> callbacks_; // 订阅到回调的映射 + + // 静态消息处理回调 + static int messageHandler(CPushConsumer* consumer, CMessageExt* msg); + + // 实例消息处理函数 + int handleMessage(CMessageExt* msg); +}; + +// 构造函数实现 +RocketMQConsumer::RocketMQConsumer(const std::string& consumerName, const std::string& nameServer, const std::string& groupId) + : consumer_(NULL)//, messageCallback_(NULL) +{ + // 创建消费者 + consumer_ = CreatePushConsumer(consumerName.c_str()); + if (consumer_ == NULL) { + std::cout << "error CreatePushConsumer"<< std::endl; + throw std::runtime_error("Failed to create push consumer."); + } + + SetPushConsumerSessionCredentials(consumer_,G_MQCONSUMER_ACCESSKEY.c_str(),G_MQCONSUMER_SECRETKEY.c_str(),G_MQCONSUMER_CHANNEL.c_str()); + + // 设置 NameServer 地址 + if (SetPushConsumerNameServerAddress(consumer_, nameServer.c_str()) != 0) { + DestroyPushConsumer(consumer_); + std::cout << "error setting nameServer"<< std::endl; + throw std::runtime_error("Failed to set NameServer address."); + } + + // 设置消费者组ID + if (SetPushConsumerGroupID(consumer_, groupId.c_str()) != 0) { + DestroyPushConsumer(consumer_); + std::cout << "error setting groupId"<< std::endl; + throw std::runtime_error("Failed to set Consumer Group ID."); + } + + // 设置消费模式为广播模式 + if (SetPushConsumerMessageModel(consumer_, BROADCASTING) != 0) { + DestroyPushConsumer(consumer_); + std::cout << "error setting messagemodel"<< std::endl; + } + + //调试用 + std::string consumerlog = "./mqconsumer/" + consumerName +".log"; + if ( (SetPushConsumerLogPath(consumer_,consumerlog.c_str()) || SetPushConsumerLogFileNumAndSize(consumer_,10,100) || SetPushConsumerLogLevel(consumer_,E_LOG_LEVEL_DEBUG) ) != 0) {//记录消费日志 + DestroyPushConsumer(consumer_); + std::cout << "error setting logpath"<< std::endl; + } + std::cout << "logpath:" << consumerlog << std::endl; + + // 注册消息回调 + if (RegisterMessageCallback(consumer_, RocketMQConsumer::messageHandler) != 0) { + DestroyPushConsumer(consumer_); + std::cout << "error setting Callback"<< std::endl; + throw std::runtime_error("Failed to register message callback."); + } + + // 将消费者实例添加到全局映射 + pthread_mutex_lock(&g_consumerMapMutex); + g_consumerMap[consumer_] = this; + pthread_mutex_unlock(&g_consumerMapMutex); + + std::cout << "RocketMQ Consumer initialized and started." << std::endl; +} + +// 启动消费者 +void RocketMQConsumer::start() +{ + if (StartPushConsumer(consumer_) != 0) { + pthread_mutex_lock(&g_consumerMapMutex); + g_consumerMap.erase(consumer_); + pthread_mutex_unlock(&g_consumerMapMutex); + DestroyPushConsumer(consumer_); + throw std::runtime_error("Failed to start push consumer."); + } + else{ + std::cout << "RocketMQ Consumer started." << std::endl; + } +} + +void RocketMQConsumer::subscribe(const std::string& topic, const std::string& tag, MessageCallBack callback) +{ + if (Subscribe(consumer_, topic.c_str(), tag.c_str()) != 0) { + throw std::runtime_error("Failed to subscribe to topic/tag."); + } + std::cout << "Subscribed to topic: " << topic << ", tag: " << tag << std::endl; + + // 使用 std::pair 作为键 + std::pair key(topic, tag); + callbacks_[key] = callback; +} + +// 静态消息处理回调实现 +int RocketMQConsumer::messageHandler(CPushConsumer* consumer, CMessageExt* msg) +{ + RocketMQConsumer* instance = NULL; + + //调试用 + std::cout << "messagehandler" << std::endl; + + // 查找对应的消费者实例 + pthread_mutex_lock(&g_consumerMapMutex); + std::map::iterator it = g_consumerMap.find(consumer); + if (it != g_consumerMap.end()) { + instance = it->second; + } + pthread_mutex_unlock(&g_consumerMapMutex); + + if (instance) { + return instance->handleMessage(msg); + } else { + std::cerr << "Consumer instance not found for callback." << std::endl; + return E_RECONSUME_LATER; // 默认返回重试状态 + } +} + +int RocketMQConsumer::handleMessage(CMessageExt* msg) +{ + // 检查 msg 和 consumer_ 是否为 NULL + if (!msg || !consumer_) { + std::cerr << "Received null message or consumer." << std::endl; + return E_RECONSUME_LATER; + } + + // 获取消息的主题和标签 + std::string topic = GetMessageTopic(msg); // 假设存在此函数 + std::string tag = GetMessageTags(msg); // 假设存在此函数 + + // 打印调试信息 + std::cout << "Handling message for topic: " << topic << ", tag: " << tag << std::endl; + + // 使用 std::pair 作为键 + std::pair key(topic, tag); + + // 查找对应的回调函数 + std::map, MessageCallBack>::iterator it = callbacks_.find(key); + if (it != callbacks_.end()) { + // 调用对应的回调函数 + + //调试 + std::cout << "callback Handling message " <second(consumer_, msg); + + } else { + + //调试 + std::cout << "there is no callback " <& subscriptions) // 接收多个订阅 +{ + if (g_consumer == NULL) { + std::cout << "create new consumer!" << std::endl; + try { + g_consumer = new RocketMQConsumer(consumerName, nameServer,consumerName);//用消费名作为消费组,不同进程(不同的消费者)同时消费topic的同一条消息 + + for (size_t i = 0; i < subscriptions.size(); ++i) { + g_consumer->setConsumerMessageModel(subscriptions[i].topic);//初始化时根据topic设置消费模式 + g_consumer->subscribe(subscriptions[i].topic, subscriptions[i].tag, subscriptions[i].callback); + } + + g_consumer->start(); + + } + catch (const std::exception& e) { + std::cerr << "Failed to initialize consumer: " << e.what() << std::endl; + throw; // 重新抛出异常 + } + } +} + +// 关闭并销毁消费者函数 +void ShutdownAndDestroyConsumer() +{ + if (g_consumer != NULL) { + delete g_consumer; + g_consumer = NULL; + } +} + +// 消费消息的接口函数 +void rocketmq_consumer_receive( + const std::string& consumerName, + const std::string& nameServer, + const std::vector& subscriptions) // 接收多个订阅 +{ + if (g_consumer == NULL) { + try { + //InitializeConsumer(consumerName, nameServer, topic, tag, callback);//初始化后,mq库内部来完成消息的获取 + InitializeConsumer(consumerName, nameServer, subscriptions); // 初始化后,MQ库内部开始获取消息 + } + catch (...) { + std::cerr << "Cannot consume message because consumer initialization failed." << std::endl; + return; + } + } + + // 消费逻辑已通过回调处理,无需额外操作 +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +//封装生产者类 +#if 1 +// 全局或静态变量,用于维护当前队列索引 +static int currentQueueId = 0; + +// 队列选择器回调函数:轮询选择队列 ID +int RoundRobinSelector(int queueNum, CMessage* msg, void* arg) { + if (queueNum == 0) { + throw std::runtime_error("No available queues"); + } + int queueId = currentQueueId % queueNum; + currentQueueId++; + if (currentQueueId >= 1024 - queueNum) { + currentQueueId = 0; + } + return queueId; +} + +// 封装生产者的类 +class RocketMQProducer { +public: + RocketMQProducer(const std::string& producerName, const std::string& nameServer) + : producer_(NULL) + { + // 创建生产者 + producer_ = CreateProducer(producerName.c_str()); + if (producer_ == NULL) { + throw std::runtime_error("Failed to create producer."); + } + + // 设置 nameserver 地址 + SetProducerNameServerAddress(producer_, nameServer.c_str()); + + // 启动生产者 + StartProducer(producer_); + + std::cout << "rocketmq_Producer initialized and started." << std::endl; + } + + // 禁用拷贝和赋值 + RocketMQProducer(const RocketMQProducer&) = delete; + RocketMQProducer& operator=(const RocketMQProducer&) = delete; + + // 发送消息 + void sendMessage(const char* strbody, const char* topic, const std::string& tags, const std::string& keys) { + CSendResult result; + CMessage* msg = NULL; + + try { + // 创建消息并设置属性 + msg = CreateMessage(topic); + if (msg == NULL) { + throw std::runtime_error("Failed to create message."); + } + + SetMessageTags(msg, tags.c_str()); + SetMessageKeys(msg, keys.c_str()); + SetMessageBody(msg, strbody); + + // 假设队列数量和 Broker 名称是固定的 + int queueNum = QUEUENUM; // 配置的队列数量,例如5 + + // 发送消息 + int sendResult = SendMessageOnewayOrderly( + producer_, + msg, + RoundRobinSelector, // 队列选择器回调函数 + &queueNum // 传递给选择器的额外参数(队列数量) + ); + + if (sendResult == 0) { // 假设返回 0 表示成功 + std::cout << "Message sent successfully." << std::endl; + } else { + std::cout << "Failed to send message." << std::endl; + } + + // 销毁消息 + DestroyMessage(msg); + msg = NULL; // 防止重复销毁 + } + catch (const std::runtime_error& e) { + std::cerr << "Runtime error during message sending: " << e.what() << std::endl; + // 如果消息已经创建,确保销毁它 + if (msg != NULL) { + DestroyMessage(msg); + } + // 可以在这里添加更多的错误处理逻辑,比如重试、记录日志等 + } + catch (const std::exception& e) { + std::cerr << "Exception during message sending: " << e.what() << std::endl; + if (msg != NULL) { + DestroyMessage(msg); + } + } + catch (...) { + std::cerr << "Unknown error during message sending." << std::endl; + if (msg != NULL) { + DestroyMessage(msg); + } + } + } + + + // 析构函数中关闭并销毁生产者 + ~RocketMQProducer() { + if (producer_) { + ShutdownProducer(producer_); + DestroyProducer(producer_); + std::cout << "rocketmq_Producer shutdown and destroyed." << std::endl; + } + } + +private: + CProducer* producer_; +}; + +// 全局生产者实例 +RocketMQProducer* g_producer = NULL; + +// 初始化生产者(在程序启动时调用一次) +void InitializeProducer() +{ + if (g_producer == NULL) { + try { + g_producer = new RocketMQProducer(G_ROCKETMQ_PRODUCER, G_ROCKETMQ_IPPORT); + } + catch (const std::exception& e) { + std::cerr << "Failed to initialize producer: " << e.what() << std::endl; + // 根据需求决定是否终止程序或采取其他措施 + throw; // 重新抛出异常 + } + } +} + +// 关闭并销毁生产者(在程序结束时调用一次) +void ShutdownAndDestroyProducer() +{ + if (g_producer != NULL) { + delete g_producer; + g_producer = NULL; + } +} + +// 发送消息的接口函数 +void rocketmq_producer_send(const char* strbody, const char* topic) +{ + if (g_producer == NULL) { + try { + InitializeProducer(); + } + catch (...) { + std::cerr << "Cannot send message because producer initialization failed." << std::endl; + return; + } + } + + // 假设 tags 和 keys 是固定的,可以根据需要修改 + std::string tags = G_ROCKETMQ_TAG; + std::string keys = G_ROCKETMQ_KEY; + + try { + g_producer->sendMessage(strbody, topic, tags, keys); + } + catch (const std::exception& e) { + std::cerr << "Failed to send message: " << e.what() << std::endl; + // 处理发送失败的情况,例如记录日志或重试 + } +} +#endif + +//lnk20241209队列轮询 +#if 0 +// 全局或静态变量,用于维护当前队列索引 +static int currentQueueId = 0; + +// 队列选择器回调函数:轮询选择队列 ID +int RoundRobinSelector(int queueNum, CMessage* msg, void* arg) { + if (queueNum == 0) { + throw std::runtime_error("No available queues"); + } + // 选择当前队列 ID,并更新索引 + int queueId = currentQueueId % queueNum; + currentQueueId++; + // 防止溢出,重置索引 + if (currentQueueId >= 1024 - queueNum) { + currentQueueId = 0; + } + return queueId; +} +void StartSendMessage_queue(CProducer* producer, const char* strbody, const char* topic) +{ + CSendResult result; + + // 创建消息并设置一些属性 + CMessage* msg = CreateMessage(topic); + SetMessageTags(msg, G_ROCKETMQ_TAG.c_str()); + SetMessageKeys(msg, G_ROCKETMQ_KEY.c_str()); + SetMessageBody(msg, strbody); + + // 动态获取队列数量和 Broker 名称 + int queueNum = QUEUENUM; // 假设这个是配置的队列数量,比如5 + + // 使用 SendMessageOnewayOrderly 发送消息,传递回调函数 + int sendResult = SendMessageOnewayOrderly( + producer, + msg, + RoundRobinSelector, // 传递符合 QueueSelectorCallback 签名的函数 + &queueNum // 传递给选择器的额外参数(队列数量) + ); + + if (sendResult == 0) { // 假设返回 0 表示成功 + std::cout << "Message sent successfully: " << std::endl; + } else { + std::cout << "Failed to send message: " << std::endl; + } + + // 销毁消息 + DestroyMessage(msg); +} +#endif +////////////////////////////////////////////////////////////////////////////////////////////////////////// +// producer_send0测试用 +void StartSendMessage(CProducer* producer) +{ + CSendResult result; + + // create message and set some values for it + CMessage* msg = CreateMessage(G_ROCKETMQ_TOPIC.c_str()); + SetMessageTags(msg, G_ROCKETMQ_TAG.c_str()); + SetMessageKeys(msg, G_ROCKETMQ_KEY.c_str()); + + for (int i = 0; i < 10; i++) + { + // construct different body + string strMessageBody = "this is body number"; + + SetMessageBody(msg, strMessageBody.c_str()); + // send message + SendMessageSync(producer, msg, &result); + + cout << "send message[" << i << "], result status:" << result.sendStatus << ", msgBody:" << strMessageBody << endl; + usleep(1000); + } + + // destroy message + DestroyMessage(msg); +} +//producer_send 测试用 +void StartSendMessage(CProducer* producer,const char* strbody) +{ + CSendResult result; + + // create message and set some values for it + CMessage* msg = CreateMessage(G_ROCKETMQ_TOPIC.c_str()); + SetMessageTags(msg, G_ROCKETMQ_TAG.c_str()); + SetMessageKeys(msg, G_ROCKETMQ_KEY.c_str()); + + SetMessageBody(msg, strbody); + // send message + SendMessageSync(producer, msg, &result); + + cout << "result status:" << result.sendStatus << ", msgBody:" << strbody << endl; + + // destroy message + DestroyMessage(msg); +} + +//测试用 固定消息体 +void producer_send0() +{ + cout << "Producer Initializing....." << endl; + + // create producer and set some values for it + CProducer* producer = CreateProducer(G_ROCKETMQ_PRODUCER.c_str()); + SetProducerNameServerAddress(producer, G_ROCKETMQ_IPPORT.c_str()); + // start producer + StartProducer(producer); + cout << "Producer start....." << endl; + // send message + StartSendMessage(producer); + // shutdown producer + ShutdownProducer(producer); + // destroy producer + DestroyProducer(producer); + cout << "Producer Shutdown!" << endl; +} +//测试用 可控制消息体 +void producer_send(const char* strbody) +{ + cout << "Producer Initializing....." << endl; + + // create producer and set some values for it + CProducer* producer = CreateProducer(G_ROCKETMQ_PRODUCER.c_str()); + SetProducerNameServerAddress(producer, G_ROCKETMQ_IPPORT.c_str()); + // start producer + StartProducer(producer); + cout << "Producer start....." << endl; + // send message + StartSendMessage(producer, strbody); + // shutdown producer + ShutdownProducer(producer); + // destroy producer + DestroyProducer(producer); + cout << "Producer Shutdown!" << endl; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if 0 +void rocketmq_StartSendMessage(CProducer* producer,const char* strbody,const char* topic) +{ + CSendResult result; + + // create message and set some values for it + CMessage* msg = CreateMessage(topic); + + //多前置区分消息tag,一个进程 + + SetMessageTags(msg, G_ROCKETMQ_TAG.c_str()); + SetMessageKeys(msg, G_ROCKETMQ_KEY.c_str()); + + SetMessageBody(msg, strbody); + // send message + SendMessageSync(producer, msg, &result); + + //cout << "rocketmq_result status:" << result.sendStatus << ", msgBody:" << strbody << endl; + + // destroy message + DestroyMessage(msg); +} + +void rocketmq_producer_send(const char* strbody,const char* topic) +{ + cout << "rocketmq_Producer Initializing....." << endl; + + // create producer and set some values for it + CProducer* producer = CreateProducer(G_ROCKETMQ_PRODUCER.c_str()); + if (producer == NULL) { + std::cerr << "Failed to create producer." << std::endl; + return; + } + + // nameserver + SetProducerNameServerAddress(producer, G_ROCKETMQ_IPPORT.c_str()); + + // start producer + StartProducer(producer); + + cout << "rocketmq_Producer start....." << endl; + // send message + //rocketmq_StartSendMessage(producer,strbody,topic); + //根据队列发消息 + StartSendMessage_queue(producer,strbody,topic); + // shutdown producer + ShutdownProducer(producer); + // destroy producer + DestroyProducer(producer); + cout << "rocketmq_Producer Shutdown!" << endl; +} +#endif + +extern "C" { +extern std::string G_MQCONSUMER_TOPIC_RT; +void rocketmq_test_rt() +{ + Ckafka_data_t data; + data.monitor_id = 123123; + data.strTopic = QString::fromStdString(G_MQCONSUMER_TOPIC_RT); + std::ifstream file("rt.txt"); // 文件中存储长字符串 + std::stringstream buffer; + buffer << file.rdbuf(); // 读取整个文件内容 + + data.strText = QString::fromStdString(buffer.str()); + data.mp_id = 123123; + my_rocketmq_send(data); +} +extern std::string G_MQCONSUMER_TOPIC_UD; +void rocketmq_test_ud()//用来测试台账更新 +{ + Ckafka_data_t data; + data.monitor_id = 123123; + data.strTopic = QString::fromStdString(G_MQCONSUMER_TOPIC_UD); + std::ifstream file("ud.txt"); // 文件中存储长字符串 + std::stringstream buffer; + buffer << file.rdbuf(); // 读取整个文件内容 + + data.strText = QString::fromStdString(buffer.str()); + data.mp_id = 123123; + my_rocketmq_send(data); +} + +void rocketmq_test_set()//用来测试进程控制脚本 +{ + Ckafka_data_t data; + data.monitor_id = 123123; + data.strTopic = QString::fromStdString(G_MQCONSUMER_TOPIC_SET); + std::ifstream file("set.txt"); // 文件中存储长字符串 + std::stringstream buffer; + buffer << file.rdbuf(); // 读取整个文件内容 + + data.strText = QString::fromStdString(buffer.str()); + data.mp_id = 123123; + my_rocketmq_send(data); +} +extern std::string G_MQCONSUMER_TOPIC_RC; +void rocketmq_test_rc() +{ + Ckafka_data_t data; + data.monitor_id = 123123; + data.strTopic = QString::fromStdString(G_MQCONSUMER_TOPIC_RC); + std::ifstream file("rc.txt"); // 文件中存储长字符串 + std::stringstream buffer; + buffer << file.rdbuf(); // 读取整个文件内容 + + data.strText = QString::fromStdString(buffer.str()); + data.mp_id = 123123; + my_rocketmq_send(data); +} +} + +std::string to_string(long long value) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +void rocketmq_test_300(int mpnum,int front_index) { + Ckafka_data_t data; + data.strTopic = QString::fromStdString(G_ROCKETMQ_TOPIC); + data.mp_id = "0"; + + // 读取文件内容 + std::ifstream file("long_string.txt"); // 文件中存储长字符串 + std::stringstream buffer; + buffer << file.rdbuf(); + std::string file_contents = buffer.str(); // 获取文件内容 + std::string base_strText = file_contents; + + // 获取当前时间作为开始时间 + std::time_t t = std::time(NULL);//获取当前的系统时间(自 1970 年 1 月 1 日以来的秒数,通常称为 UNIX 时间戳) + std::tm* time_info = std::localtime(&t);//将 std::time_t(表示当前的 UNIX 时间戳)转换为本地时间(std::tm 结构) + time_info->tm_sec = 0; // 清零秒位 + //time_info->tm_msec = 0; // 清零毫秒位(如果需要更精确,使用高精度时间) + + // 获取当前的时间戳(秒) + std::time_t base_time_t = std::mktime(time_info);//将 std::tm 结构(本地时间)转换回 std::time_t(时间戳) + + // 计算每条消息的时间戳,精确到分钟,毫秒和秒清零 + long long current_time_ms = static_cast(base_time_t) * 1000; // 每分钟递增,单位毫秒 + + // 设定总的消息数量 + int total_messages = mpnum; + + // 循环发送 300 条消息 + for (int i = 0; i < total_messages; ++i) { + // 修改 Monitor 值 + data.monitor_id = front_index *10000 + 1 + i; + + data.mp_id = QString::number(data.monitor_id); + + std::string modified_time = to_string(current_time_ms); // 时间转换为整数类型(Unix时间戳) + + // 替换消息中的 Monitor 和 TIME 字段(只匹配字段名,不匹配具体数值) + std::string modified_strText = base_strText; + + // 替换 Monitor 字段 + size_t monitor_pos = modified_strText.find("\"Monitor\""); + if (monitor_pos != std::string::npos) { + size_t colon_pos = modified_strText.find(":", monitor_pos); + size_t quote_pos = modified_strText.find("\"", colon_pos); + size_t end_quote_pos = modified_strText.find("\"", quote_pos + 1); + if (colon_pos != std::string::npos && quote_pos != std::string::npos && end_quote_pos != std::string::npos) { + modified_strText.replace(quote_pos + 1, end_quote_pos - quote_pos - 1, to_string(data.monitor_id)); + } + } + + // 替换 TIME 字段 + size_t time_pos = modified_strText.find("\"TIME\""); + if (time_pos != std::string::npos) { + size_t colon_pos = modified_strText.find(":", time_pos); + size_t quote_pos = colon_pos; + size_t end_quote_pos = modified_strText.find(",", quote_pos + 1); + if (colon_pos != std::string::npos && quote_pos != std::string::npos && end_quote_pos != std::string::npos) { + modified_strText.replace(quote_pos + 1, end_quote_pos - quote_pos - 1, modified_time); + } + } + + // 更新数据 + data.strText = QString::fromStdString(modified_strText); + + // 发送数据 + my_rocketmq_send(data); + + // 输出调试信息 + std::cout << "Sent message " << (i + 1) << " with Monitor " << data.monitor_id << " and TIME " << modified_time << std::endl; + + // 等待下一条消息的发送(固定为1分钟) + //QThread::sleep(60); // 每次发送间隔1分钟 + } + + std::cout << "Finished sending " << total_messages << " messages." << std::endl; +} diff --git a/cfg_parse/base64.cpp b/cfg_parse/base64.cpp new file mode 100644 index 0000000..c06ed5c --- /dev/null +++ b/cfg_parse/base64.cpp @@ -0,0 +1,189 @@ +/** +* @file: $RCSfile: base64.cpp,v $ +* @brief: base64 include +* +* @version: $Revision: 1.00 $ +* @date: $Date: 2024/09/24 18:34:00 $ +* @author: $Author: caizhouyu $ +* @state: $State: Exp $ +* +* @latest: $Id: base64.cpp,v 1.00 2023/10/24 18:34:00 caizhouyu Exp $ +* +*/ + +using namespace std; + +#include + +#include +#include + +#include "../mms/db_interface.h" +#include "../json/cjson.h"//WW 2023-08-27json +#include "../include/curl/curl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + // Base64 + const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + //base64 + static const unsigned char base64_decode_table[] = { + //ÿ16 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //1 - 16 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //17 - 32 + 0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63, //33 - 48 + 52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0, //49 - 64 + 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, //65 - 80 + 15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0, //81 - 96 + 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, //97 - 112 + 41,42,43,44,45,46,47,48,49,50,51,0,0,0,0,0 //113 - 128 + }; + + /** + * @brief base64_decode base64 + * @param indata + * @param inlen ݴС + * @param outdata + * @param outlen ݴС + * @return int 0ɹ -1Ч + * ע⣺ݵĴС44ı + */ + int base64_decode(const char* indata, int inlen, char* outdata, long* outlen) + { + if (indata == NULL || inlen <= 0 || (outdata == NULL && outlen == NULL)) { + return -1; + } + if (inlen < 4 || inlen % 4 != 0) { //ҪݳȲ4ı //inlen < 4 || + return -1; + } + + int i, j; + + //ַ + int len = inlen / 4 * 3; + if (indata[inlen - 1] == '=') { + len--; + } + if (indata[inlen - 2] == '=') { + len--; + } + + if (outdata != NULL) { + for (i = 0, j = 0; i < inlen; i += 4, j += 3) { + outdata[j] = (base64_decode_table[(unsigned char)indata[i]] << 2) | (base64_decode_table[(unsigned char)indata[i + 1]] >> 4); + outdata[j + 1] = (base64_decode_table[(unsigned char)indata[i + 1]] << 4) | (base64_decode_table[(unsigned char)indata[i + 2]] >> 2); + outdata[j + 2] = (base64_decode_table[(unsigned char)indata[i + 2]] << 6) | (base64_decode_table[(unsigned char)indata[i + 3]]); + } + } + if (outlen != NULL) { + *outlen = len; + } + return 0; + } + + // Base64 뺯 + char* base64_encode_char(const unsigned char* data, size_t input_length, size_t* output_length) { + *output_length = 4 * ((input_length + 2) / 3); // ȼ + char* encoded_data = (char*)malloc(*output_length + 1); // ڴ棬+1 Ϊ '\0' + if (encoded_data == NULL) return NULL; + + for (int i = 0, j = 0; i < input_length;) { + uint32_t octet_a = i < input_length ? data[i++] : 0; + uint32_t octet_b = i < input_length ? data[i++] : 0; + uint32_t octet_c = i < input_length ? data[i++] : 0; + + uint32_t triple = (octet_a << 16) | (octet_b << 8) | octet_c; + + encoded_data[j++] = base64_chars[(triple >> 18) & 0x3F]; + encoded_data[j++] = base64_chars[(triple >> 12) & 0x3F]; + encoded_data[j++] = (i * 2 / 3) < *output_length ? base64_chars[(triple >> 6) & 0x3F] : '='; + encoded_data[j++] = (i * 2 + 1 / 3) < *output_length ? base64_chars[triple & 0x3F] : '='; + } + + encoded_data[*output_length] = '\0'; // ַ + return encoded_data; + } + + + + /// + /// жַǷΪpower{}ʽ + /// + /// ȡַ + /// ֶ + /// ֶγ + /// ȡݳ + /// + bool extract_if_power(const char* str, char* output, size_t output_size, size_t* extracted_length) { + const char* prefix = "power{"; + size_t prefix_length = strlen(prefix); + + // ǰ׺ + if (strncmp(str, prefix, prefix_length) != 0) { + return false; // ǰ׺ƥ + } + + // ұպϵĻ + const char* close_brace = strchr(str + prefix_length, '}'); + if (close_brace == NULL) { + return false; // ûҵպϵĻ + } + + // Ҫȡݳ + size_t content_length = close_brace - (str + prefix_length); + if (content_length >= output_size) { + return false; // ̫޷ + } + + // ݵ + strncpy(output, str + prefix_length, content_length); + output[content_length] = '\0'; // ӿֹ + printf("text: %s,length:%d\n", output, content_length); // ע⣺Ҫȷınullַֹ + // ȡݳ + *extracted_length = content_length; + + return true; // ȡɹ + } + + //int testbase64(char ** decoded_text) { + // unsigned char text[] = "power{SGVsbG8sIFdvcmxkIWV3ZA==}"; + // size_t encoded_length, decoded_length; + + // char encoded_text[100]; + + // if (extract_if_power((char*)text, encoded_text, sizeof(encoded_text), &encoded_length)) { + // // ַ + // long decodedLen = strlen(encoded_text) * 3 / 4; + // * decoded_text = (char*)malloc(decodedLen + 1); + // // Base64 + // int success = base64_decode(encoded_text, strlen(encoded_text), *decoded_text, &decodedLen); + // if (decoded_text) { + // printf("Decoded: %s\n", (char*)decoded_text); // ע⣺Ҫȷınullַֹ + // free(decoded_text); // ע⣺ʵϲӦʹdecoded_textΪַӡΪunsigned char* + // // ʵӦУҪתΪchar*nullֹ + // } + // } + // else { + // printf(" no Decoded: %s\n", text); // ע⣺Ҫȷınullַֹ + // } + // + + + // // ע⣺decoded_textӡDz׼ȷģΪdecoded_textunsigned char*ҿܲnullַֹ + // // ȷǽdecoded_textתΪַıݣʽ + + // return 0; + //} + + + +#ifdef __cplusplus +} +#endif diff --git a/cfg_parse/cfg_parser.cpp b/cfg_parse/cfg_parser.cpp new file mode 100644 index 0000000..da05606 --- /dev/null +++ b/cfg_parse/cfg_parser.cpp @@ -0,0 +1,14282 @@ + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define OTL_ODBC_ODBC +#define OTL_ODBC_UNIX +#include + +#include "otlv4.h" +#include + +#include //lnk 2024-10-16 +#include //дȥص豸 +#include //ϴļ + +#include "../mms/db_interface.h" +#include "../json/save2json.h" +#include "../json/mms_json_inter.h" + +#include "../mms/rdb_client.h" +#include "../mms/interface.h" +#include "../json/cjson.h"//WW 2023-08-27json +#include "../include/curl/curl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + extern pt61850app_t* g_pt61850app; + extern node_t* g_node; + extern apr_pool_t* g_cfg_pool; + extern apr_pool_t* g_init_pool; + extern apr_pool_t* g_temp_dev_pool; + extern char subdir[128]; + extern int g_front_seg_index; + + extern unsigned int g_no_auth; + extern char g_onlyIP[255]; //ֱijIPΪ + + int g_DevFlag = 0; + +#ifdef __cplusplus +} +#endif +//ZW 2023-10-10 нṹ +class RecallInfo +{ +public: + long long starttime; + long long endtime; +}; + +//CZY 2023-09-17 +class ProgramParam // +{ +public: + QList terminal_list;//նidб + QString file_name;//װãװossеλ + +}; + +//CZY 2023-09-17 +class RecallParam // +{ +public: + QString mp_id;//id + QString start;//ʼʱ + QString end;//ݽʱ + int voltage;//̬ݱ־ + int stat;//̬ݱ־ +}; + +//CZY 2023-10-12 װʶԿ +class terminal_ext // +{ +public: + char terminal_identify_code[100];//նʶ + char terminal_key[100];//նԿ +}; + +class CJournalRecall //־нṹ +{ +public: + QString MonitorID; //· + QString StartTime; //ݲʼʱ + QString EndTime; //ݲнʱ + QString STEADY; //ʷͳݱʶ 0-У1- + QString VOLTAGE; //̬¼ʶ 0-У1- +}; + +/*lnk 2024-10-15 */ +class ledger_monitor //̨ +{ +public: + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + char timestamp[64]; + char status[255]; + char count_cfg[64]; //̨˵һ֣¼ݿҵ̨̨ +}; + +class terminal_dev //ն̨ +{ +public: + char terminal_id[64]; + char terminal_code[64]; + char org_name[64]; + char maint_name[64]; + char station_name[64]; + char tmnl_factory[64]; + char tmnl_status[64]; + char dev_type[64]; + char dev_key[255]; + char dev_series[255]; + char addr_str[64]; + char port[64]; + char timestamp[64]; + + ledger_monitor line[10]; + + char count_cfg[64]; //̨˵һ֣¼ݿҵ̨̨ +}; + +class icd_model //icdģ +{ +public: + char model_id[64]; + char tmnl_type[64]; + char tmnl_type_id[64]; //ʹ + char tmnl_factory[64]; //ʹ + char file_name[128]; + char file_path[128]; + char timestamp[64]; +}; + +class front_list//ǰñ +{ +public: + char front_ip[64]; + char front_port[64]; + char front_inst[64]; + char front_type[64]; + char front_status[64]; + char front_version[64]; + char mp_num[64]; +}; + +class intact_list//ǰñ +{ +public: + char monitor_id[64]; + char statistical_date[64]; + char exp_num[64]; + char act_num[64]; + std::vector value_time; //ʱ伯 + char last_value_time[64]; +}; +/*lnk 2024-10-15 */ + +list g_StatisticLackList; //־нṹ + +QMutex g_StatisticLackList_list_mutex; //recall + +QString DEVIE_CONFIG_FN = QString("Device_Config.xml");// +QString LINE_CONFIG_FN = QString("Line_Config.xml");// +QString JSON_CONFIG_FN_old = QString("JiangSu_Config.xml");//Ĭӳļ +QString THREE_SECS_CONFIG_FN = QString("Trigger3S.xml");//ʵʱ +QString RECALL_CONFIG_FN = QString("Recall.xml");// + +//lnk20241220һ̨˸µļ֤¸̨ +std::string LEDGER_UPDATE_FN = "LedgerUpdate.xml"; + +const int MAX_CPUNO = 10; + +//WW 2-23-08-20 add start +otl_connect db; //OTLݿӶ WW 2023-08-20 +int g_iOTLFlag = 0; //SqlǷִб־(0-ִУ1-ִ) //lnk202410-22滻webӿںر +std::string g_strOTLType = "PostgreSQL"; //OTLݿ +//std::string g_strOTLConnect = "pqsadmin/dnzladmin_001@pgsql"; //OTLݿӲ +//std::string g_strOTLConnect = "postgres/postgres@pgsql"; //OTLݿӲ +std::string g_strOTLConnect = "postgres/bmdev@123@pgsql"; //OTLݿӲ + +//////CZY 2023-09-06 config +//ǰflag:1Ϊ,0Ϊر +int MULTIPLE_NODE_FLAG = 1; +extern const char* PROGRAM_VERSION; + +extern int FRONT_MP_NUM; + +int ACCOUNT_UPDATE_INTERVAL; +char* ACCOUNT_UPDATE_LAST_TIME; + +int MULIT_NODE_INTERVAL; + +int COMMUNICATION_LOG_STATUS_TIME; +int COMMUNICATION_LOG_ABNORMAL_TIME; + +char* POSTGRES_DATABASE;//ݿ +char* POSTGRES_USERNAME;//ݿû +char* POSTGRES_PASSWORD;//ݿ +char* POSTGRES_SCHEMA;//ݿģʽ +char* POSTGRES_DNSNAME;//ȡpostgres/guass +char* POSTGRES_TABLEPREFIX;//ǰ׺ + +char* CLIENT_ID;//̨CLIENT_ID +char* CLIENT_SECRET;//̨CLIENT_SECRET +char* TOKEN_URL;//̨ȡtokenӿ +char* DEVICE_URL;//̨ȡն˽ӿ +char* GRANT_TYPE;//̨GRANT_TYPE + +char* UDS_UPLOAD_URL; +char* UDS_DOWNLOAD_URL; +char* UDS_DELETE_URL; + +//char * OSS_ENDPOINT; +//char * ACCESS_KEY_ID; +//char * ACCESS_KEY_SECRET; +//char * BUCKET_NAME; + +int FILE_FLAG; +int SEND_FLAG; +int FRONT_INST; +char* FRONT_IP; +int CITY_FLAG; + +int recall_len; +int recall_sta; +int recall_daily; + +char* BROKER_LIST; +char* TOPIC_STAT; +char* TOPIC_PST; +char* TOPIC_PLT; +char* TOPIC_EVENT; +char* TOPIC_ALARM; +char* TOPIC_SNG; + +//lnk20241220 +char* TOPIC_RTDATA; + +char* PROTOCOL; +char* MECHANISMS; +char* KEYTAB_FILE; +char* SERVICE_NAME; +char* PRINCIPAL; +char* DOMAIN_NAME; + +extern int g_front_seg_index; +extern int g_front_seg_num; + +/*ֲñlnk10-9*/ +// +std::string G_ROCKETMQ_PRODUCER = "";//rocketmq producer +std::string G_ROCKETMQ_IPPORT = "";//rocketmq ip+port +std::string G_ROCKETMQ_TOPIC = "";//topie +std::string G_ROCKETMQ_TAG = "";//tag +std::string G_ROCKETMQ_KEY = "";//key +int QUEUENUM = 0; +std::string BROKERNAME = ""; +// +std::string G_ROCKETMQ_CONSUMER = "";//rocketmq consumer +std::string G_MQCONSUMER_IPPORT = "";//consumer ip+port +std::string G_MQCONSUMER_TOPIC_RT = "";//consumer topie +std::string G_MQCONSUMER_TAG_RT = "";//consumer tag +std::string G_MQCONSUMER_KEY_RT = "";//consumer key +std::string G_MQCONSUMER_ACCESSKEY = ""; +std::string G_MQCONSUMER_SECRETKEY = ""; +std::string G_MQCONSUMER_CHANNEL = ""; +std::string G_MQCONSUMER_TOPIC_UD = "";//consumer topie +std::string G_MQCONSUMER_TAG_UD = "";//consumer tag +std::string G_MQCONSUMER_KEY_UD = "";//consumer key +std::string G_MQCONSUMER_TOPIC_RC = "";//consumer topie +std::string G_MQCONSUMER_TAG_RC = "";//consumer tag +std::string G_MQCONSUMER_KEY_RC = "";//consumer key +std::string G_MQCONSUMER_TOPIC_SET = "";//consumer topie +std::string G_MQCONSUMER_TAG_SET = "";//consumer tag +std::string G_MQCONSUMER_KEY_SET = "";//consumer key + +int G_TEST_FLAG = 0; +int G_TEST_NUM = 0; + +int TEST_PORT = 11000;//ڵǰ̵¼shellĶ˿ + +//ն˺ͼ״̬ɸѡ +std::string TERMINAL_STATUS = ""; +std::string MONITOR_STATUS = ""; +std::string ICD_FLAG = ""; + +//socketÿ +int SOCKET_PORT = 13000; +int SOCKETENABLE = 0; + +//httpų́lnk20241031 +int HTTPENABLE = 0; +std::string HTTP_IP = ""; +int HTTP_PORT = 12000; + +/*webӿlnk202411-6*/ +std::string WEB_DEVICE = ""; +std::string WEB_ICD = ""; +std::string WEB_INTEGRITY = ""; //ݲʹ +std::string WEB_COMFLAG = ""; +std::string WEB_EVENT = ""; +std::string WEB_FILEUPLOAD = ""; +std::string WEB_FILEDOWNLOAD = ""; + +//lnk20250115̨ +extern pthread_mutex_t mtx; + +/*lnk 2024-10-21 */ +int OTL_Select_DecideRecall_web(char* time, char* id);//жǷҪ +void OTL_Select_recall_web(char* time, char* id); //Բж +bool CheckPG_To_Recall_web(long long start, long long end, char* Monitorid); +////////////////////////////////////////////////////////////////////////// + +std::string g_strUID = ""; //OTLݿû +int g_iOTLConnectLimit = 3; //OTLݿⳬʱӴ עݿӴݿӼ3Σִݿ̣߳ +//ݿSql--------------------------------------- +extern QList Sql_data_list; //Sqlִ +extern QMutex Sql_data_list_mutex; //Sqlִ +extern int server_socket; //Web Socketʵ +extern unsigned int g_node_id; //ǰó(100-500) +//WW 2023-08-20 end +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parse_log_switch_ini(unsigned int* error, unsigned int* warn, unsigned int* info) +{ + QString pt61850netd_pqfe_IniFilename = QString("../etc/pt61850netd_pqfe.ini"); + QSettings settings(pt61850netd_pqfe_IniFilename, QSettings::IniFormat); + + settings.beginGroup("Log"); + *error = settings.value("error", 0).toUInt(); + *warn = settings.value("warn", 0).toUInt(); + *info = settings.value("info", 0).toUInt(); + + g_no_auth = settings.value("no_auth", 0).toUInt(); + + g_DevFlag = settings.value("DevFlag", 0).toUInt(); + + settings.endGroup(); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +//lnk20250114ʹõĴ +#if 0 +/* xml ʾ 豸ն + + +6 + +1268918860 +PQS-882A +127.0.0.1 +102 +IXFhekB3c3gzZWRjNHJmdg== +UHFzJmNuODcwMjk5 +0 + + + +*/ +int parse_device_cfg() +{ + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + unsigned int count_cfg = 0; + unsigned int count_real = 0; + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/"); + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(cfg_dir + DEVIE_CONFIG_FN); + if (!file.open(QIODevice::ReadOnly)) + return APR_EBADPATH; //ֻʽ + if (!doc.setContent(&file)) { + file.close(); + return APR_EBADF; + } + //ļݶdoc + QDomElement docElem = doc.documentElement(); //ظԪ + QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ + while (!n.isNull()) + { //ڵ㲻Ϊ + if (n.isElement()) //ڵԪ + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); + if (strTag == "DevAccountList") { + QDomNodeList list = e.childNodes(); //Ԫeӽڵб + for (int i = 0; i < list.count(); i++) //б + { + QDomNode node = list.at(i); + if (node.isElement()) { + QString strTag2 = node.toElement().tagName(); + if (strTag2 == "Count") { + count_cfg = node.toElement().text().toUInt(); + g_node->n_clients = count_cfg; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (unsigned int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + } + else if (strTag2 == "DevAccount") { + ied = g_node->clients[count_real++]; + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + + QDomNodeList list2 = node.childNodes(); //Ԫnodeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) { //б + QDomNode node2 = list2.at(i2); + if (node2.isElement()) { + QString devPropTag = node2.toElement().tagName(); + QString devPropVal = node2.toElement().text(); + if (devPropTag == "DEV_Index") { + ied_usr->dev_idx = devPropVal.toInt(); + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", devPropVal.toAscii().data()); + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_code), "%s", devPropVal.toAscii().data()); + } + else if (devPropTag == "DEV_Type") { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", devPropVal.toAscii().data()); + cout << "dev_type" << ied_usr->dev_type << endl; + } + else if (devPropTag == "DEV_Code") { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", devPropVal.toAscii().data()); + cout << "dev_code" << ied_usr->terminal_code << endl; + } + else if (devPropTag == "DEV_Key") { + QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii()); + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ba.data()); + } + else if (devPropTag == "DEV_Series") { + QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii()); + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ba.data()); + } + else if (devPropTag == "DEV_DevFlag") + ied_usr->dev_flag = devPropVal.toInt(); + else if (devPropTag == "DEV_IP") { + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4; + ied->channel[0].addr = ntohl(inet_addr(devPropVal.toAscii().data())); + strncpy(ied->channel[0].addr_str, devPropVal.toAscii().data(), LONGNAME - 1); + ied->channel[0].addr_str[LONGNAME - 1] = 0; + } + else if (devPropTag == "DEV_PortID") + ied->channel[0].port = devPropVal.toUInt(); + } + }// for(int i2=0; i2channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + } //else if ( strTag2 == "DevAccount" ) + } + } + } + } + n = n.nextSibling(); //һֵܽڵ + } + if (count_real < count_cfg) + g_node->n_clients = count_real; + if (count_cfg != count_real) + return APR_EBADF; + return APR_SUCCESS; +} + +int parse_line_cfg() +{ + ied_t* ied; + ied_usr_t* ied_usr; + int count_cfg = 0; + int count_real = 0; + LD_info_t line_info; + int dev_idx_in_line = 0; + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/"); + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(cfg_dir + LINE_CONFIG_FN); + if (!file.open(QIODevice::ReadOnly)) + return APR_EBADPATH; //ֻʽ + if (!doc.setContent(&file)) { + file.close(); + return APR_EBADF; + } + //ļݶdoc + QDomElement docElem = doc.documentElement(); //ظԪ + QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ + while (!n.isNull()) + { //ڵ㲻Ϊ + if (n.isElement()) //ڵԪ + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); + if (strTag == "MonitorAccountList") { + QDomNodeList list = e.childNodes(); //Ԫeӽڵб + for (int i = 0; i < list.count(); i++) //б + { + QDomNode node = list.at(i); + if (node.isElement()) { + QString strTag2 = node.toElement().tagName(); + if (strTag2 == "Count") { + count_cfg = node.toElement().text().toInt(); + } + else if (strTag2 == "MonitorAccount") { + count_real++; + dev_idx_in_line = -1; + memset(&line_info, 0, sizeof(line_info)); + QDomNodeList list2 = node.childNodes(); //Ԫnodeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) { //б + QDomNode node2 = list2.at(i2); + if (node2.isElement()) { + QString devPropTag = node2.toElement().tagName(); + QString devPropVal = node2.toElement().text(); + if (devPropTag == "LINE_Index") { + line_info.line_id = devPropVal.toInt(); + strcpy(line_info.mp_id, devPropVal.toAscii().data()); + } + else if (devPropTag == "DEV_Index") { + strcpy(line_info.terminal_code, devPropVal.toAscii().data()); + dev_idx_in_line = devPropVal.toInt(); + } + else if (devPropTag == "CPUNO") + line_info.cpuno = devPropVal.toInt(); + else if (devPropTag == "Name") + apr_snprintf(line_info.name, sizeof(line_info.name), "%s", devPropVal.toAscii().data()); + //strcpy(line_info.mp_id, "not def"); + //strcpy(line_info.terminal_code, "tmpcode1"); + strcpy(line_info.voltage_level, "14"); + line_info.read_flag = 1; + } + }// for(int i2=0; i2usr_ext && line_info.cpuno) { + char str[256]; + byte_t cpuno = line_info.cpuno; + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + if (cpuno > ied->cpucount) + ied->cpucount = cpuno; + } + } //else if ( strTag2 == "DevAccount" ) + } + } + } + } + n = n.nextSibling(); //һֵܽڵ + } + + if (count_cfg != count_real) + return APR_EBADF; + return APR_SUCCESS; +} +#endif +//////////////////////////////////////////////////////////CZY + +void update_odbc(char* newServicename, char* newPort) { + const char* filename = "/etc/odbc.ini"; + const char* searchip = "Servername="; // ҪҵеĿͷ + const char* searchport = "Port="; // ҪҵеĿͷ + const char* tempFilename = "/tmp/odbc.ini.XXXXXX"; // ʱļ + + FILE* file = fopen(filename, "r"); + if (file == NULL) { + printf("Error opening file\n"); + return; + } + + // ʱļ + char tempFilenameBuffer[256]; + strcpy(tempFilenameBuffer, tempFilename); + int tempfd = mkstemp(tempFilenameBuffer); + FILE* tempfile = fdopen(tempfd, "w"); + + // жȡļ + char line[256]; + while (fgets(line, sizeof(line), file)) { + if (strncmp(line, searchip, strlen(searchip)) == 0) { + // ҵҪ޸ĵУдµֵ + fprintf(tempfile, "Servername=%s\n", newServicename); + } + else if (strncmp(line, searchport, strlen(searchport)) == 0) { + // ҵҪ޸ĵУдµֵ + fprintf(tempfile, "Port=%s\n", newPort); + } + else { + // ԭʼдʱļ + fputs(line, tempfile); + } + } + + // رļ + fclose(file); + fclose(tempfile); + + // 滻ԭʼļ + remove(filename); + rename(tempFilenameBuffer, filename); +} + +//CZY 2023-09-06 config +void init_config() { + QByteArray ba; + QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir) + QSettings settings(MyKafkaIniFilename, QSettings::IniFormat); + + ACCOUNT_UPDATE_INTERVAL = settings.value("AccountUpdate/Interval", 0).toInt(); + qDebug() << "Read ACCOUNT_UPDATE_INTERVAL:" << ACCOUNT_UPDATE_INTERVAL << endl; + ba = settings.value("AccountUpdate/LastUpdateTime", "").toString().toLatin1(); + ACCOUNT_UPDATE_LAST_TIME = strdup(ba.data()); + qDebug() << "Read ACCOUNT_UPDATE_LAST_TIME:" << ACCOUNT_UPDATE_LAST_TIME << endl; + + MULIT_NODE_INTERVAL = settings.value("MultiNode/Interval", 0).toInt(); + qDebug() << "Read MULIT_NODE_INTERVAL:" << MULIT_NODE_INTERVAL << endl; + + SEND_FLAG = settings.value("Flag/SendFlag", 0).toInt(); + qDebug() << "Read SEND_FLAG:" << SEND_FLAG << endl; + FILE_FLAG = settings.value("Flag/FileFlag", 0).toInt(); + qDebug() << "Read FILE_FLAG:" << FILE_FLAG << endl; + FRONT_INST = settings.value("Flag/FrontInst", 0).toInt(); + qDebug() << "Read FRONT_INST:" << FRONT_INST << endl; + ba = settings.value("Flag/FrontIP", "").toString().toLatin1(); + FRONT_IP = strdup(ba.data()); + qDebug() << "Read FRONT_IP:" << FRONT_IP << endl; + CITY_FLAG = settings.value("Flag/CityFlag", 0).toInt(); + qDebug() << "Read CITY_FLAG:" << CITY_FLAG << endl; + +//̨lnk20241031////////////////////////////////////////////////////////////// + TERMINAL_STATUS = settings.value("Ledger/TerminalStatus", 0).toString().toStdString(); + std::cout << "Read TERMINAL_STATUS:" << TERMINAL_STATUS << std::endl; + MONITOR_STATUS = settings.value("Ledger/MonitorStatus", 0).toString().toStdString(); + std::cout << "Read MONITOR_STATUS:" << MONITOR_STATUS << std::endl; + ICD_FLAG = settings.value("Ledger/IcdFlag", 0).toString().toStdString(); + std::cout << "Read ICD_FLAG:" << ICD_FLAG << std::endl; + +//////////////////////////////////////////////////socket/////////////////// + SOCKETENABLE = settings.value("Socket/SocketEnable", 0).toInt(); + SOCKET_PORT = settings.value("Socket/SocketPort", 0).toInt(); +//////http////////////////////////////////////////////////////////////////// + HTTPENABLE = settings.value("Http/HttpEnable", 0).toInt(); + ba = settings.value("Http/HttpIp", "").toString().toLatin1(); + HTTP_IP = strdup(ba.data()); + std::cout << "Read HTTP_IP:" << HTTP_IP << std::endl; + HTTP_PORT = settings.value("Http/HttpPort", 0).toInt(); + std::cout << "Read HTTP_PORT:" << HTTP_PORT << std::endl; + + ba = settings.value("Http/WebDevice", "").toString().toLatin1(); + WEB_DEVICE = strdup(ba.data()); + std::cout << "Read WEB_DEVICE:" << WEB_DEVICE << std::endl; + ba = settings.value("Http/WebIcd", "").toString().toLatin1(); + WEB_ICD = strdup(ba.data()); + std::cout << "Read WEB_ICD:" << WEB_ICD << std::endl; + ba = settings.value("Http/WebIntegrity", "").toString().toLatin1(); + WEB_INTEGRITY = strdup(ba.data()); + std::cout << "Read WEB_INTEGRITY:" << WEB_INTEGRITY << std::endl; + ba = settings.value("Http/WebComflag", "").toString().toLatin1(); + WEB_COMFLAG = strdup(ba.data()); + std::cout << "Read WEB_COMFLAG:" << WEB_COMFLAG << std::endl; + ba = settings.value("Http/WebEvent", "").toString().toLatin1(); + WEB_EVENT = strdup(ba.data()); + std::cout << "Read WEB_EVENT:" << WEB_EVENT << std::endl; + ba = settings.value("Http/WebFileupload", "").toString().toLatin1(); + WEB_FILEUPLOAD = strdup(ba.data()); + std::cout << "Read WEB_FILEUPLOAD:" << WEB_FILEUPLOAD << std::endl; + ba = settings.value("Http/WebFiledownload", "").toString().toLatin1(); + WEB_FILEDOWNLOAD = strdup(ba.data()); + std::cout << "Read WEB_FILEDOWNLOAD:" << WEB_FILEDOWNLOAD << std::endl; + +/////////////////////////////////////////////////////////////////////////////////////////////////////// + recall_len = settings.value("Recall/recall_lenth", 0).toInt(); + qDebug() << "Read recall_lenth:" << recall_len << endl; + recall_sta = settings.value("Recall/recall_start", 0).toInt(); + qDebug() << "Read recall_start:" << recall_sta << endl; + recall_daily = settings.value("Recall/recall_dailytime", 0).toInt(); + qDebug() << "Read recall_dailytime:" << recall_daily << endl; + + COMMUNICATION_LOG_STATUS_TIME = settings.value("CommunicationLog/StatusRecordDuration", 0).toInt(); + qDebug() << "Read COMMUNICATION_LOG_STATUS_TIME:" << COMMUNICATION_LOG_STATUS_TIME << endl; + COMMUNICATION_LOG_ABNORMAL_TIME = settings.value("CommunicationLog/AbnormalRecordDuration", 0).toInt(); + qDebug() << "Read COMMUNICATION_LOG_ABNORMAL_TIME:" << COMMUNICATION_LOG_ABNORMAL_TIME << endl; + + + ba = settings.value("Postgres/Database", "").toString().toLatin1(); + POSTGRES_DATABASE = strdup(ba.data()); + ba = settings.value("Postgres/Username", "").toString().toLatin1(); + POSTGRES_USERNAME = strdup(ba.data()); + + /*QString postgres_password = settings.value("Postgres/Password", "").toString(); + ba = QByteArray::fromBase64(postgres_password.toAscii());*/ + ba = settings.value("Postgres/Password", "").toString().toLatin1(); + POSTGRES_PASSWORD = strdup(ba.data()); + + ba = settings.value("Postgres/Schema", "").toString().toLatin1(); + POSTGRES_SCHEMA = strdup(ba.data()); + ba = settings.value("Postgres/Dnsname", "").toString().toLatin1(); + POSTGRES_DNSNAME = strdup(ba.data()); + ba = settings.value("Postgres/TablePrefix", "").toString().toLatin1(); + POSTGRES_TABLEPREFIX = strdup(ba.data()); + + + qDebug() << "Read POSTGRES_DATABASE:" << POSTGRES_DATABASE << endl; + qDebug() << "Read POSTGRES_USERNAME:" << POSTGRES_USERNAME << endl; + qDebug() << "Read POSTGRES_PASSWORD:" << POSTGRES_PASSWORD << endl; + qDebug() << "Read POSTGRES_SCHEMA:" << POSTGRES_SCHEMA << endl; + qDebug() << "Read POSTGRES_DNSNAME:" << POSTGRES_DNSNAME << endl; + qDebug() << "Read POSTGRES_TABLEPREFIX:" << POSTGRES_TABLEPREFIX << endl; + + + ba = settings.value("Oss/OssEndpoint", "").toString().toLatin1(); + OSS_ENDPOINT = strdup(ba.data()); + ba = settings.value("Oss/AccessKeyID", "").toString().toLatin1(); + ACCESS_KEY_ID = strdup(ba.data()); + ba = settings.value("Oss/AccessKeySecret", "").toString().toLatin1(); + ACCESS_KEY_SECRET = strdup(ba.data()); + ba = settings.value("Oss/BucketName", "").toString().toLatin1(); + BUCKET_NAME = strdup(ba.data()); + + qDebug() << "Read OSS_ENDPOINT:" << OSS_ENDPOINT << endl; + qDebug() << "Read ACCESS_KEY_ID:" << ACCESS_KEY_ID << endl; + qDebug() << "Read ACCESS_KEY_SECRET:" << ACCESS_KEY_SECRET << endl; + qDebug() << "Read BUCKET_NAME:" << BUCKET_NAME << endl; + + ba = settings.value("Kafka/brokerlist", "").toString().toLatin1(); + BROKER_LIST = strdup(ba.data()); + ba = settings.value("Kafka/HisTopic", "").toString().toLatin1(); + TOPIC_STAT = strdup(ba.data()); + ba = settings.value("Kafka/PSTTopic", "").toString().toLatin1(); + TOPIC_PST = strdup(ba.data()); + ba = settings.value("Kafka/PLTTopic", "").toString().toLatin1(); + TOPIC_PLT = strdup(ba.data()); + + ba = settings.value("Kafka/EventTopic", "").toString().toLatin1(); + TOPIC_EVENT = strdup(ba.data()); + + ba = settings.value("Kafka/AlmTopic", "").toString().toLatin1(); + TOPIC_ALARM = strdup(ba.data()); + ba = settings.value("Kafka/SngTopic", "").toString().toLatin1(); + TOPIC_SNG = strdup(ba.data()); + + ba = settings.value("Kafka/RTDataTopic", "").toString().toLatin1(); + TOPIC_RTDATA = strdup(ba.data()); + + qDebug() << "Read BROKER_LIST:" << BROKER_LIST << endl; + qDebug() << "Read TOPIC_STAT:" << TOPIC_STAT << endl; + qDebug() << "Read TOPIC_PST:" << TOPIC_PST << endl; + qDebug() << "Read TOPIC_PLT:" << TOPIC_PLT << endl; + qDebug() << "Read TOPIC_EVENT:" << TOPIC_EVENT << endl; + qDebug() << "Read TOPIC_ALARM:" << TOPIC_ALARM << endl; + qDebug() << "Read TOPIC_SNG:" << TOPIC_SNG << endl; + qDebug() << "Read TOPIC_RTDATA:" << TOPIC_RTDATA << endl; + + + ba = settings.value("Kafka/Protocol", "").toString().toLatin1(); + PROTOCOL = strdup(ba.data()); + ba = settings.value("Kafka/Mechanisms", "").toString().toLatin1(); + MECHANISMS = strdup(ba.data()); + ba = settings.value("Kafka/KeytabFile", "").toString().toLatin1(); + KEYTAB_FILE = strdup(ba.data()); + ba = settings.value("Kafka/ServiceName", "").toString().toLatin1(); + SERVICE_NAME = strdup(ba.data()); + ba = settings.value("Kafka/Principal", "").toString().toLatin1(); + PRINCIPAL = strdup(ba.data()); + ba = settings.value("Kafka/DomainName", "").toString().toLatin1(); + DOMAIN_NAME = strdup(ba.data()); + + qDebug() << "Read PROTOCOL:" << PROTOCOL << endl; + qDebug() << "Read MECHANISMS:" << MECHANISMS << endl; + qDebug() << "Read KEYTAB_FILE:" << KEYTAB_FILE << endl; + qDebug() << "Read SERVICE_NAME:" << SERVICE_NAME << endl; + qDebug() << "Read PRINCIPAL:" << PRINCIPAL << endl; + qDebug() << "Read DOMAIN_NAME:" << DOMAIN_NAME << endl; + + ba = settings.value("Web/ClientId", "").toString().toLatin1(); + CLIENT_ID = strdup(ba.data()); + ba = settings.value("Web/ClientSecret", "").toString().toLatin1(); + CLIENT_SECRET = strdup(ba.data()); + ba = settings.value("Web/TokenUrl", "").toString().toLatin1(); + TOKEN_URL = strdup(ba.data()); + ba = settings.value("Web/DeviceUrl", "").toString().toLatin1(); + DEVICE_URL = strdup(ba.data()); + ba = settings.value("Web/GrantType", "").toString().toLatin1(); + GRANT_TYPE = strdup(ba.data()); + + qDebug() << "Read CLIENT_ID:" << CLIENT_ID << endl; + qDebug() << "Read CLIENT_SECRET:" << CLIENT_SECRET << endl; + qDebug() << "Read TOKEN_URL:" << TOKEN_URL << endl; + qDebug() << "Read DEVICE_URL:" << DEVICE_URL << endl; + qDebug() << "Read GRANT_TYPE:" << GRANT_TYPE << endl; + + ba = settings.value("Uds/UdsUploadUrl", "").toString().toLatin1(); + UDS_UPLOAD_URL = strdup(ba.data()); + ba = settings.value("Uds/UdsDownloadUrl", "").toString().toLatin1(); + UDS_DOWNLOAD_URL = strdup(ba.data()); + + qDebug() << "Read UDS_UPLOAD_URL:" << UDS_UPLOAD_URL << endl; + qDebug() << "Read UDS_DOWNLOAD_URL:" << UDS_DOWNLOAD_URL << endl; + +/*rocketmqĽ10-9 *///////////////////////////////////////////////////////////////// +// + ba = settings.value("RocketMq/producer", "").toString().toLatin1(); + G_ROCKETMQ_PRODUCER = strdup(ba.data()); + ba = settings.value("RocketMq/Ipport", "").toString().toLatin1(); + G_ROCKETMQ_IPPORT = strdup(ba.data()); + ba = settings.value("RocketMq/Topic", "").toString().toLatin1(); + G_ROCKETMQ_TOPIC = strdup(ba.data()); + ba = settings.value("RocketMq/Tag", "").toString().toLatin1(); + G_ROCKETMQ_TAG = strdup(ba.data()); + ba = settings.value("RocketMq/Key", "").toString().toLatin1(); + G_ROCKETMQ_KEY = strdup(ba.data()); + QUEUENUM = settings.value("RocketMq/Queuenum", 0).toInt(); +// + ba = settings.value("RocketMq/consumer", "").toString().toLatin1(); + G_ROCKETMQ_CONSUMER = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerIpport", "").toString().toLatin1(); + G_MQCONSUMER_IPPORT = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTopicRT", "").toString().toLatin1(); + G_MQCONSUMER_TOPIC_RT = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTagRT", "").toString().toLatin1(); + G_MQCONSUMER_TAG_RT = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerKeyRT", "").toString().toLatin1(); + G_MQCONSUMER_KEY_RT = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerAccessKey", "").toString().toLatin1(); + G_MQCONSUMER_ACCESSKEY = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerSecretKey", "").toString().toLatin1(); + G_MQCONSUMER_SECRETKEY = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerChannel", "").toString().toLatin1(); + G_MQCONSUMER_CHANNEL = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTopicUD", "").toString().toLatin1(); + G_MQCONSUMER_TOPIC_UD = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTagUD", "").toString().toLatin1(); + G_MQCONSUMER_TAG_UD = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerKeyUD", "").toString().toLatin1(); + G_MQCONSUMER_KEY_UD = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTopicRC", "").toString().toLatin1(); + G_MQCONSUMER_TOPIC_RC = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTagRC", "").toString().toLatin1(); + G_MQCONSUMER_TAG_RC = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerKeyRC", "").toString().toLatin1(); + G_MQCONSUMER_KEY_RC = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTopicSET", "").toString().toLatin1(); + G_MQCONSUMER_TOPIC_SET = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerTagSET", "").toString().toLatin1(); + G_MQCONSUMER_TAG_SET = strdup(ba.data()); + ba = settings.value("RocketMq/ConsumerKeySET", "").toString().toLatin1(); + G_MQCONSUMER_KEY_SET = strdup(ba.data()); +//MQ + G_TEST_FLAG = settings.value("RocketMq/Testflag", 0).toInt(); + G_TEST_NUM = settings.value("RocketMq/Testnum", 0).toInt(); +//shell + TEST_PORT = settings.value("RocketMq/TestPort", 0).toInt(); + +//شӡ + std::cout << "Read G_ROCKETMQ_PRODUCER:" << G_ROCKETMQ_PRODUCER << std::endl; + std::cout << "Read G_ROCKETMQ_IPPORT:" << G_ROCKETMQ_IPPORT << std::endl; + std::cout << "Read G_ROCKETMQ_TOPIC:" << G_ROCKETMQ_TOPIC << std::endl; + std::cout << "Read G_ROCKETMQ_TAG:" << G_ROCKETMQ_TAG << std::endl; + std::cout << "Read G_ROCKETMQ_KEY:" << G_ROCKETMQ_KEY << std::endl; + std::cout << "Read QUEUENUM:" << QUEUENUM << std::endl; +//شӡ + std::cout << "Read G_ROCKETMQ_CONSUMER:" << G_ROCKETMQ_CONSUMER << std::endl; + std::cout << "Read G_MQCONSUMER_IPPORT:" << G_MQCONSUMER_IPPORT << std::endl; + std::cout << "Read G_MQCONSUMER_TOPIC_RT:" << G_MQCONSUMER_TOPIC_RT << std::endl; + std::cout << "Read G_MQCONSUMER_TAG_RT:" << G_MQCONSUMER_TAG_RT << std::endl; + std::cout << "Read G_MQCONSUMER_KEY_RT:" << G_MQCONSUMER_KEY_RT << std::endl; + std::cout << "Read G_MQCONSUMER_ACCESSKEY:" << G_MQCONSUMER_ACCESSKEY << std::endl; + std::cout << "Read G_MQCONSUMER_SECRETKEY:" << G_MQCONSUMER_SECRETKEY << std::endl; + std::cout << "Read G_MQCONSUMER_CHANNEL:" << G_MQCONSUMER_CHANNEL << std::endl; + std::cout << "Read G_MQCONSUMER_TOPIC_UD:" << G_MQCONSUMER_TOPIC_UD << std::endl; + std::cout << "Read G_MQCONSUMER_TAG_UD:" << G_MQCONSUMER_TAG_UD << std::endl; + std::cout << "Read G_MQCONSUMER_KEY_UD:" << G_MQCONSUMER_KEY_UD << std::endl; + std::cout << "Read G_MQCONSUMER_TOPIC_RC:" << G_MQCONSUMER_TOPIC_RC << std::endl; + std::cout << "Read G_MQCONSUMER_TAG_RC:" << G_MQCONSUMER_TAG_RC << std::endl; + std::cout << "Read G_MQCONSUMER_KEY_RC:" << G_MQCONSUMER_KEY_RC << std::endl; + std::cout << "Read G_MQCONSUMER_TOPIC_SET:" << G_MQCONSUMER_TOPIC_SET << std::endl; + std::cout << "Read G_MQCONSUMER_TAG_SET:" << G_MQCONSUMER_TAG_SET << std::endl; + std::cout << "Read G_MQCONSUMER_KEY_SET:" << G_MQCONSUMER_KEY_SET << std::endl; +//Mqشӡ + std::cout << "Read G_TEST_FLAG:" << G_TEST_FLAG << std::endl; + std::cout << "Read G_TEST_NUM:" << G_TEST_NUM << std::endl; + +///////////////////////////////////////////////////////////////////////////////////////// + /*Nacos_GetParam(POSTGRES_USERNAME, POSTGRES_PASSWORD, CLIENT_ID, CLIENT_SECRET); + qDebug() << "Read CLIENT_ID:" << CLIENT_ID << endl; + qDebug() << "Read CLIENT_SECRET:" << CLIENT_SECRET << endl; + qDebug() << "Read POSTGRES_USERNAME:" << POSTGRES_USERNAME << endl; + qDebug() << "Read POSTGRES_PASSWORD:" << POSTGRES_PASSWORD << endl;*/ + +/*lnk10-12 ݲʹNacos*/ +/* + char* database_ip = NULL; + char* database_port = NULL; + sleep(3); + Read_Nacos_Param_Postgres(&database_ip, &database_port, &POSTGRES_DATABASE, &POSTGRES_USERNAME, &POSTGRES_PASSWORD, &POSTGRES_SCHEMA, &POSTGRES_DNSNAME, &POSTGRES_TABLEPREFIX); + qDebug() << "Read database_ip:" << database_ip << endl; + qDebug() << "Read database_port:" << database_port << endl; + update_odbc(database_ip, database_port); + qDebug() << "Read POSTGRES_DATABASE:" << POSTGRES_DATABASE << endl; + qDebug() << "Read POSTGRES_USERNAME:" << POSTGRES_USERNAME << endl; + qDebug() << "Read POSTGRES_PASSWORD:" << POSTGRES_PASSWORD << endl; + qDebug() << "Read POSTGRES_SCHEMA:" << POSTGRES_SCHEMA << endl; + qDebug() << "Read POSTGRES_DNSNAME:" << POSTGRES_DNSNAME << endl; + qDebug() << "Read POSTGRES_TABLEPREFIX:" << POSTGRES_TABLEPREFIX << endl; + sleep(3); + Read_Nacos_Param_Kafka(&BROKER_LIST, &TOPIC_STAT, &TOPIC_PST, &TOPIC_PLT, &TOPIC_EVENT, &TOPIC_ALARM, &TOPIC_SNG, &PROTOCOL, &MECHANISMS, &SERVICE_NAME, &PRINCIPAL, &DOMAIN_NAME); + qDebug() << "Read BROKER_LIST:" << BROKER_LIST << endl; + qDebug() << "Read TOPIC_STAT:" << TOPIC_STAT << endl; + qDebug() << "Read TOPIC_PLT:" << TOPIC_PLT << endl; + qDebug() << "Read TOPIC_EVENT:" << TOPIC_EVENT << endl; + qDebug() << "Read TOPIC_ALARM:" << TOPIC_ALARM << endl; + qDebug() << "Read TOPIC_SNG:" << TOPIC_SNG << endl; + qDebug() << "Read PROTOCOL:" << PROTOCOL << endl; + qDebug() << "Read PRINCIPAL:" << PRINCIPAL << endl; + sleep(3); + Read_Nacos_Param_Web(&CLIENT_ID, &CLIENT_SECRET, &TOKEN_URL, &DEVICE_URL, &GRANT_TYPE); + qDebug() << "Read CLIENT_ID:" << CLIENT_ID << endl; + qDebug() << "Read CLIENT_SECRET:" << CLIENT_SECRET << endl; + qDebug() << "Read TOKEN_URL:" << TOKEN_URL << endl; + qDebug() << "Read DEVICE_URL:" << DEVICE_URL << endl; + qDebug() << "Read GRANT_TYPE:" << GRANT_TYPE << endl; + sleep(3); + Read_Nacos_Param_Flag(&FILE_FLAG, &SEND_FLAG, &FRONT_INST, &FRONT_IP); + sleep(3); + Read_Nacos_Param_Recall(&recall_len, &recall_sta, &recall_daily); + qDebug() << "Read SEND_FLAG:" << SEND_FLAG << endl; + qDebug() << "Read FILE_FLAG:" << FILE_FLAG << endl; + qDebug() << "Read FRONT_INST:" << FRONT_INST << endl; + qDebug() << "Read FRONT_IP:" << FRONT_IP << endl; + + qDebug() << "Read recall_lenth:" << recall_len << endl; + qDebug() << "Read recall_start:" << recall_sta << endl; + qDebug() << "Read recall_dailytime:" << recall_daily << endl; + sleep(3); + Read_Nacos_Param_Uds(&UDS_UPLOAD_URL, &UDS_DOWNLOAD_URL, &UDS_DELETE_URL); + qDebug() << "Read UDS_UPLOAD_URL:" << UDS_UPLOAD_URL << endl; + qDebug() << "Read UDS_DOWNLOAD_URL:" << UDS_DOWNLOAD_URL << endl; + qDebug() << "Read UDS_DELETE_URL:" << UDS_DELETE_URL << endl; +*/ +//2024-10-25lnk Ҫǰãǰipļȡݿ +/* + if (g_front_seg_index != 0 && g_front_seg_num != 0) { + FRONT_INST = g_front_seg_index; + if (FRONT_IP != nullptr) { + free(FRONT_IP); // ͨmalloc + } + FRONT_IP = (char*)malloc(64); // ڴ + // ʹsprintfintֵΪַ + sprintf(FRONT_IP, "%d", g_front_seg_index); + } + qDebug() << "Read FRONT_INST:" << FRONT_INST << endl; + qDebug() << "Read FRONT_IP:" << FRONT_IP << endl; + + g_strOTLConnect = POSTGRES_USERNAME; + g_strOTLConnect.append("/"); + g_strOTLConnect.append(POSTGRES_PASSWORD); + g_strOTLConnect.append("@"); + g_strOTLConnect.append(POSTGRES_DNSNAME); + + cout << "Read g_strOTLConnect:" << g_strOTLConnect << endl;*/ +//20241212lnkӶǰ + if (g_front_seg_index != 0 && g_front_seg_num != 0) { + MULTIPLE_NODE_FLAG = 1; + std::cout << "ǰǶ:" << g_front_seg_index << std::endl; + } + else{ + MULTIPLE_NODE_FLAG = 0; + std::cout << "ǰǵ:" << std::endl; + } +//20250109lnkӽ̲Դӡ˿ + if (g_node_id == STAT_DATA_BASE_NODE_ID)//ͳƲɼ + TEST_PORT = TEST_PORT + STAT_DATA_BASE_NODE_ID + g_front_seg_index; + else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {// + TEST_PORT = TEST_PORT + RECALL_HIS_DATA_BASE_NODE_ID + g_front_seg_index; + } + else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3ɼ + TEST_PORT = TEST_PORT + THREE_SECS_DATA_BASE_NODE_ID + g_front_seg_index; + } + else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//̬¼ + TEST_PORT = TEST_PORT + SOE_COMTRADE_BASE_NODE_ID + g_front_seg_index; + } + +} + +// CZY ping IP +// ִȡ +std::string executeCommand(const std::string& command) { + std::string result = ""; + FILE* pipe = popen(command.c_str(), "r"); + if (!pipe) { + std::cerr << "Error executing command." << std::endl; + return result; + } + + char buffer[128]; + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) + result += buffer; + } + + pclose(pipe); + return result; +} + +bool telnet_port_socket(const char* ip, int port) { + struct sockaddr_in server_addr; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + inet_pton(AF_INET, ip, &server_addr.sin_addr); + + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("socket"); + return false; + } + + // ӳʱʱΪ5 + struct timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + close(sockfd); + return false; + } + if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + close(sockfd); + return false; + } + + if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { + if (errno == EINPROGRESS) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(sockfd, &fds); + + int ret = select(sockfd + 1, NULL, &fds, NULL, &timeout); + if (ret == -1) { + perror("select"); + close(sockfd); + return false; + } + else if (ret == 0) { + // ӳʱ + close(sockfd); + return false; + } + else { + int error; + socklen_t len = sizeof(error); + getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len); + if (error == 0) { + // ӳɹ + close(sockfd); + return true; + } + else { + // ʧ + close(sockfd); + return false; + } + } + } + else { + // ʧ + close(sockfd); + return false; + } + } + + // ӳɹ + close(sockfd); + return true; +} + +// ping IP +bool ping_ip(const std::string& ip) { + std::string command = "ping -c 1 -w 2.5 " + ip; + std::string result = executeCommand(command); + + // жǷ "1 packets transmitted, 1 received" ַ + if (result.find("1 packets transmitted, 1 received") != std::string::npos) { + return true; + } + else { + return false; + } +} + +int init_ping_telnet(int& ip_count, int& telnet_count) { + cout << "start test ping telnet" << endl; + ied_t* ied = NULL; + int iedno; + LD_info_t* LD_info = NULL; + int count = 0; + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + if (ied) { + //ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + if (g_onlyIP[0] != 0 && (strcmp(g_onlyIP, ied->channel[0].addr_str) != 0)) { + continue; + } + ied->channel[0].addr_str;//DEV_IP + ied->channel[0].port;//DEV_PortID + bool pingResult = ping_ip(ied->channel[0].addr_str); + //bool pingResult = test_ping(ied->channel[0].addr_str); + + //bool telnetResult = telnetIPPort(ied->channel[0].addr_str, ied->channel[0].port); + bool telnetResult = telnet_port_socket(ied->channel[0].addr_str, ied->channel[0].port); + std::string strlog = ""; + strlog.append("Ping to IP "); + strlog.append(ied->channel[0].addr_str); + + if (pingResult) { + ip_count++; + std::cout << "Ping to IP " << ied->channel[0].addr_str << " is successful." << std::endl; + strlog.append(" is successful."); + } + else { + std::cout << "Ping to IP " << ied->channel[0].addr_str << " is unsuccessful." << std::endl; + strlog.append(" is unsuccessful."); + + } + add_comm_log(const_cast(strlog.c_str())); + strlog = ""; + std::string str = QString::number(ied->channel[0].port).toStdString(); + strlog.append("Telnet port "); + strlog.append(str); + if (telnetResult) { + telnet_count++; + std::cout << "Telnet port " << ied->channel[0].port << " is open on IP " << ied->channel[0].addr_str << std::endl; + strlog.append(" is open on IP "); + } + else { + std::cout << "Telnet port " << ied->channel[0].port << " is closed on IP " << ied->channel[0].addr_str << std::endl; + strlog.append(" is closed on IP "); + + } + strlog.append(ied->channel[0].addr_str); + add_comm_log(const_cast(strlog.c_str())); + + cout << "iedno:" << iedno << " ip_count:" << ip_count << " telnet_count:" << telnet_count << endl; + QString MyKafkaIniFilename = QString("../etc/") + QString("testping.ini"); //+QString::fromAscii(subdir) + QSettings settings(MyKafkaIniFilename, QSettings::IniFormat); + settings.setValue("test/IpCount", ip_count); + settings.setValue("test/TelnetCount", telnet_count); + settings.setValue("test/IedCount", iedno); + } + } + cout << "end test ping telnet" << endl; + + return 1; +} + +//CZY 2023-08-30 read device account from web api +long long charToLongLong(const char* time_str) { + string str_time = "2022-01-01 10:00:00"; + struct tm tm_time = {}; + strptime(str_time.c_str(), "%Y-%m-%d %H:%M:%S", &tm_time); + time_t time_stamp = mktime(&tm_time); + //cout << "ʱΪ" << time_stamp << endl; + return time_stamp; +} + +//CZY 2023-08-30 chat* null or emptry +bool isCharPtrEmpty(const char* str) { + return str == nullptr || str[0] == '\0' || str == ""; +} + +// CZY 2024-07-24 ַǷȫΪ +int isAllDigits(const char* str) { + while (*str) { + if (!isdigit((unsigned char)*str)) { + return 0; // ַַ + } + str++; + } + return 1; // ַ +} + +// CZY 2024-07-24ַתΪintܣ +int stringToInt(const char* str, int* result) { + if (isAllDigits(str)) { + *result = atoi(str); // ʹatoiתעatoi + return 1; // תɹ + } + return 0; // תʧ +} + +//lnk20241206ʹõĴ +#if 0 +void GetWebApiJson(int perpage, int page, int flag); +//CZY 2023-10-12 +int read_terminal_ext_pg(QMap* terminal_ext_map) { + cout << "start read terminal_ext" << endl; + terminal_ext* ext; + //ȡ + try { + OTLConnect(); + //int rtState = OTLState(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select \"terminal_code\",\"terminal_identify_code\",\"terminal_key\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_terminal_ext"); + str1.append("\";"); + //cout << "pg sql1 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + + while (!i.eof()) { //while not end-of-data + char terminal_code[100]; + char terminal_identify_code[100]; + char terminal_key[100]; + i >> terminal_code >> terminal_identify_code >> terminal_key; + //qDebug() << "terminal_ext1:" << terminal_code << "," <contains(terminal_code)) { + ext = new terminal_ext(); + terminal_ext_map->insert(terminal_code, ext); + apr_snprintf(ext->terminal_identify_code, sizeof(ext->terminal_identify_code), "%s", terminal_identify_code);//terminal_code + apr_snprintf(ext->terminal_key, sizeof(ext->terminal_key), "%s", terminal_key);//terminal_code + //qDebug() << "terminal_ext2:" << terminal_code << "," << ext->terminal_identify_code << "," << ext->terminal_key << endl; + } + else + { + qDebug() << terminal_code << endl; + } + } + OTLDisconnect(); + cout << "end read terminal_ext" << endl; + + return 1; + } + catch (otl_exception& e) + { + printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + +} +static QString strDevCJson; +static QString strToken; +//CZY 2023-09-10 web device +//flag +int parse_device_cfg_json() +{ + qDebug() << "parse_device_cfg_json" << endl; + if (FRONT_INST == 0 || FRONT_IP[0] == '\0') { + MULTIPLE_NODE_FLAG = 0; + cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl; + + } + char front_type[2]; + int mp_num; + + if (MULTIPLE_NODE_FLAG) { + //std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(POSTGRES_SCHEMA); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("meas_pq_front_list_tr"); + str1.append("\" where \"front_ip\" = '"); + str1.append(FRONT_IP); + str1.append("' and \"front_inst\" = "); + std::string str3 = QString::number(FRONT_INST).toStdString(); + str1.append(str3); + str1.append(";"); + try { + OTLConnect(); + otl_stream i1(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + + int front_count; + while (!i1.eof()) { //while not end-of-data + i1 >> front_count; + //cout << "count=" << f2 << endl; + } + cout << "count=" << front_count << endl; + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + QString selectFrontSql; + selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0")); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + OTLConnect(); + otl_stream i2(1, // buffer size + selectFrontSql.toStdString().c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + + while (!i2.eof()) { //while not end-of-data + i2 >> front_type >> mp_num; + break; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + QString addFrontSql; + addFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + addFrontSql.append(QString("values('%1',10000,%2,'%3','01','%4',200) ").arg(FRONT_IP).arg(FRONT_INST).arg(front_type).arg(PROGRAM_VERSION)); + addFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + addFrontSql.append(QString("\"front_type\"= '%1',\"front_version\"='%2'").arg(front_type).arg(PROGRAM_VERSION)); + cout << addFrontSql.toStdString().c_str() << endl; + + OTLConnect(); + int rt = write_to_db(addFrontSql.toStdString().c_str()); + OTLDisconnect(); + + } + cout << "mp_num:" << mp_num << " FRONT_INST:" << FRONT_INST << endl; + + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + int count_cfg = 0; + int count_real = 0; + //豸ѭ,̨ȡ̨ն + int array_size = 0; + //ȡ + //string* json_buf; + cJSON* json = NULL; + cJSON* json_value = NULL; + + cJSON* json_records = NULL; + cJSON* json_node = NULL; + + int dev_num = 0; + QMap terminal_ext_map; + read_terminal_ext_pg(&terminal_ext_map); + try { + int effective_flag = 1; + //ȡ̨ʧܴ 5 + int dev_read_count = 0; + int total; + while (effective_flag == 1 && dev_read_count <= 5) { + effective_flag = 0; + dev_read_count++; + + GetWebApiJson(1, 1, CITY_FLAG); + if (strDevCJson == "") { + cout << "json select total error" << endl; + return APR_EBADF; + } + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}"; + /* char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00002128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}"; + json = cJSON_Parse(json_buf);*/ + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.227\",\"equipCode\":\"22M00000299758903\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"20102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.237\",\"equipCode\":\"22M00000299800679\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"10022\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}"; + //json = cJSON_Parse(json_buf); + + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}"; + + json = cJSON_Parse(strDevCJson.toUtf8().constData()); //jsonʽл + //cout << cJSON_Print(json) << endl; + if (NULL == json) + { + printf("cJSON_Parse error:%s\n", cJSON_GetErrorPtr()); + return APR_EBADF; + } + json_records = cJSON_GetObjectItem(json, "result"); //ȡresult + json_records = cJSON_GetObjectItem(json_records, "0751002"); //ȡ0751002 + json_value = cJSON_GetObjectItem(json_records, "total"); //ȡ total + if (json_value != NULL) { + total = json_value->valueint; + } + + cJSON_Delete(json); + + if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) { + GetWebApiJson(mp_num, FRONT_INST, CITY_FLAG); + } + else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) { + int front_num = (total / g_front_seg_num) + 1; + GetWebApiJson(front_num, FRONT_INST, CITY_FLAG); + + } + else { + /* cout << "dev total:" << total << endl; + if (total > 300) { + total = 300; + cout << "update dev total:" << total << endl; + + }*/ + GetWebApiJson(total, 1, CITY_FLAG); + } + + + if (strDevCJson == "") { + cout << "select dev json error" << endl; + return APR_EBADF; + } + json = cJSON_Parse(strDevCJson.toUtf8().constData()); //jsonʽл + + //json = cJSON_Parse(json_buf); + + json_records = cJSON_GetObjectItem(json, "result"); //ȡresult + json_records = cJSON_GetObjectItem(json_records, "0751002"); //ȡ0751002 + json_value = cJSON_GetObjectItem(json_records, "size"); //ȡ size + + + json_records = cJSON_GetObjectItem(json_records, "records"); //ȡrecords + array_size = cJSON_GetArraySize(json_records); //ȡС + if (array_size <= 1) { + effective_flag = 1; + if (dev_read_count <= 5) { + cJSON_Delete(json); + } + } + + } + + + count_cfg = array_size; + cout << "count_cfg" << "--" << count_cfg << endl; + g_node->n_clients = count_cfg; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + + + printf("array_size=%d\n", array_size); + + for (int i = 0; i < array_size; i++) + { + json_node = cJSON_GetArrayItem(json_records, i);//array + json_node = cJSON_GetObjectItem(json_node, "resource"); //ȡresource + ied = g_node->clients[count_real++]; + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + for (int num = 0; num < MAX_CPUNO; num++) { + ied_usr->LD_info[num].read_flag = 0; + } + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + + json_value = cJSON_GetObjectItem(json_node, "astId"); //ȡ astId + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", json_value->valuestring);//terminal_id + cout << "terminal_id:" << json_value->valuestring << "--" << ied_usr->terminal_id << endl; + } + else { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", "");//terminal_id + cout << "default terminal_id:" << ied_usr->terminal_id << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "equipCode"); //ȡ equipCode + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", json_value->valuestring);//terminal_code + cout << "terminal_code:" << json_value->valuestring << "--" << ied_usr->terminal_code << endl; + } + else { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", "");//terminal_code + cout << "default terminal_code:" << ied_usr->terminal_code << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "city#Name"); //ȡ city#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", json_value->valuestring);//org_name + cout << "org_name:" << json_value->valuestring << "--" << ied_usr->org_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "maintOrg#Name"); //ȡ maintOrg#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", json_value->valuestring);//maint_name + cout << "maint_name:" << json_value->valuestring << "--" << ied_usr->maint_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "station#Name"); //ȡ station#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", json_value->valuestring);//station_name + cout << "station_name:" << json_value->valuestring << "--" << ied_usr->station_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "manufacturer#Name"); //ȡ manufacturer#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", json_value->valuestring);//tmnl_factory + cout << "tmnl_factory:" << json_value->valuestring << "--" << ied_usr->tmnl_factory << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "deployState"); //ȡ deployState + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", json_value->valuestring);//tmnl_status + cout << "tmnl_status:" << json_value->valuestring << "--" << ied_usr->tmnl_status << endl; + } + else { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", "10");//tmnl_status + cout << "default tmnl_status:" << ied_usr->tmnl_status << endl; + + } + + + //json_value = cJSON_GetObjectItem(json_node, "lastUpdateTime"); //ȡ lastUpdateTime + json_value = cJSON_GetObjectItem(json_node, "ctime"); //ȡ ctime + if (json_value != NULL && json_value->string != NULL) { + //ied_usr->time = strtoll(json_value->valuestring, NULL, 10);//time + ied_usr->time = charToLongLong(json_value->valuestring);//time + cout << "time:" << ied_usr->time << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "model"); //ȡ model + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", json_value->valuestring);//DEV_Type + cout << "dev_type:" << json_value->valuestring << "--" << ied_usr->dev_type << endl; + } + else { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", "no-type");//DEV_Type + cout << "default dev_type:" << ied_usr->dev_type << endl; + } + + int t = 0; + if (t) { + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "!qaz@wsx3edc4rfv");//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "Pqs&cn870299");//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else { + cout << "code:" << ied_usr->terminal_code << endl; + if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) { + //terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code); + terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code)); + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else + { + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + } + + ied_usr->dev_flag = 0;//DEV_DevFlag + + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + cout << "channel_type:" << ied->channel[0].channel_type << endl; + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + + json_value = cJSON_GetObjectItem(json_node, "ipAddress"); //ȡ ipAddress + if (json_value != NULL && json_value->string != NULL) { + if (t && i == 0) { + ied->channel[0].addr = ntohl(inet_addr("172.40.251.35"));//DEV_IP + strncpy(ied->channel[0].addr_str, "172.40.251.35", LONGNAME - 1);//DEV_IP + } + else { + ied->channel[0].addr = ntohl(inet_addr(json_value->valuestring));//DEV_IP + strncpy(ied->channel[0].addr_str, json_value->valuestring, LONGNAME - 1);//DEV_IP + } + cout << "addr:" << json_value->valuestring << "--" << ied->channel[0].addr << "--" << ied->channel[0].addr_str << endl; + + } + else { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.1"));//DEV_IP + strncpy(ied->channel[0].addr_str, "0.0.0.1", LONGNAME - 1);//DEV_IP + //} + cout << "default addr:" << ied->channel[0].addr_str << endl; + + } + + + json_value = cJSON_GetObjectItem(json_node, "portNum"); //ȡ portNum + if (json_value != NULL && json_value->string != NULL) { + ied->channel[0].port = atoi(json_value->valuestring);//DEV_PortID + if (t) { + ied->channel[0].port = atoi("102");//DEV_PortID + } + cout << "port:" << "--" << atoi(json_value->valuestring) << "--" << ied->channel[0].port << endl; + } + else { + ied->channel[0].port = 0;//DEV_PortID + if (t) { + ied->channel[0].port = atoi("102");//DEV_PortID + } + cout << "default port:" << ied->channel[0].port << endl; + + } + + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + } + cJSON_Delete(json); + //listѭ + + + + + if (MULTIPLE_NODE_FLAG) { + QString updateFrontSql;//װpgsql + updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("set \"mp_num\"= %1 ").arg(count_real)); + updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2").arg(FRONT_IP).arg(FRONT_INST)); + OTLConnect(); + int rt = write_to_db(updateFrontSql.toStdString().c_str()); + OTLDisconnect(); + + } + + if (count_real < count_cfg) + g_node->n_clients = count_real; + if (count_cfg != count_real) + return APR_EBADF; + cout << "dev init create count:" << count_real; + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } + +} +//CZY 2023-09-15 pg device +int parse_device_cfg_pg() +{ + qDebug() << "parse_device_cfg_pg" << endl; + + if (FRONT_INST == 0 || FRONT_IP[0] == '\0') { + MULTIPLE_NODE_FLAG = 0; + cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl; + + } + char front_type[2]; + int mp_num; + + if (MULTIPLE_NODE_FLAG) { + QString selectFrontSql; + selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0")); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + OTLConnect(); + otl_stream i2(1, // buffer size + selectFrontSql.toStdString().c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + + while (!i2.eof()) { //while not end-of-data + i2 >> front_type >> mp_num; + break; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + QString addFrontSql; + addFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + addFrontSql.append(QString("values('%1',10000,%2,'%3','01','%4',200) ").arg(FRONT_IP).arg(FRONT_INST).arg(front_type).arg(PROGRAM_VERSION)); + addFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + addFrontSql.append(QString("\"front_type\"= '%1',\"front_version\"='%2'").arg(front_type).arg(PROGRAM_VERSION)); + cout << addFrontSql.toStdString().c_str() << endl; + + OTLConnect(); + int rt = write_to_db(addFrontSql.toStdString().c_str()); + OTLDisconnect(); + + } + cout << "mp_num:" << mp_num << " FRONT_INST:" << FRONT_INST << endl; + + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + int count_cfg = 0; + int count_real = 0; + + QMap terminal_ext_map; + read_terminal_ext_pg(&terminal_ext_map); + + //ȡ + try { + OTLConnect(); + //int rtState = OTLState(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("meas_pq_dev_tr"); + str1.append("\" where tmnl_status='20';"); + cout << "pg sql1 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + int f2; + while (!i.eof()) { //while not end-of-data + i >> f2; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + count_cfg = f2;;//ݿ + cout << "dev_count=" << count_cfg << endl; + + + } + catch (otl_exception& e) + { + printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + std::string strSchame = POSTGRES_SCHEMA;//schame analy + std::string strDevSQL = "select \"terminal_id\",\"terminal_code\",\"org_name\",\"maint_name\",\"station_name\",\"tmnl_ip\",\"tmnl_port\",\"tmnl_factory\",\"tmnl_type\",\"tmnl_status\",\"update_time\" from \""; + strDevSQL.append(strSchame); + strDevSQL.append("\".\""); + strDevSQL.append(POSTGRES_TABLEPREFIX); + strDevSQL.append("meas_pq_dev_tr"); + strDevSQL.append("\" where tmnl_status='20'"); + if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) { + strDevSQL.append(" ORDER BY terminal_id OFFSET "); + strDevSQL.append(QString::number((FRONT_INST - 1) * mp_num).toStdString()); + strDevSQL.append(" LIMIT "); + strDevSQL.append(QString::number(mp_num).toStdString()); + if (mp_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * mp_num; + } + else + { + count_cfg = mp_num; + } + } + else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) { + int front_num = (count_cfg / g_front_seg_num) + 1; + strDevSQL.append(" ORDER BY terminal_code OFFSET "); + strDevSQL.append(QString::number((FRONT_INST - 1) * front_num).toStdString()); + strDevSQL.append(" LIMIT "); + strDevSQL.append(QString::number(front_num).toStdString()); + if (front_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * front_num; + } + else + { + count_cfg = front_num; + } + } + + cout << strDevSQL << endl; + + g_node->n_clients = count_cfg; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + + + // + try { + cout << "read dev information." << endl; + OTLConnect(); + + //cout << "pg sql2 is:" << str1 << endl; + //int rtState = OTLState(); + // ִгselect + otl_stream i(1, // buffer size + strDevSQL.c_str(), + //SELECT statement + db //connect object + ); + + //create select stream + + char terminal_id[64]; + char terminal_code[64]; + char org_name[64]; + char maint_name[64]; + char station_name[64]; + char tmnl_factory[64]; + char tmnl_status[64]; + char dev_type[64]; + char dev_key[64]; + char dev_series[64]; + char addr_str[64]; + char port_char[64]; + otl_datetime timestamp; + + while (!i.eof()) { //while not end-of-data + i >> terminal_id >> terminal_code >> org_name >> maint_name >> station_name >> addr_str >> port_char >> tmnl_factory >> dev_type >> tmnl_status >> timestamp; + //cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq; + //cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect; + //cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl; + + ied = g_node->clients[count_real++]; + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + ied_usr->dev_flag = g_DevFlag; + + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + + ied->cpucount = 0; + + if (strlen(terminal_id) != 0) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id + cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl; + } + if (terminal_code != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code + cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl; + + } + if (org_name != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name + cout << "ied_usr->org_name:" << ied_usr->org_name << endl; + + } + if (maint_name != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name + cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl; + + } + if (station_name != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name + cout << "ied_usr->station_name:" << ied_usr->station_name << endl; + + } + if (tmnl_factory != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory + cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl; + + } + if (tmnl_status != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status + cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl; + + } + if (dev_type != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type + cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl; + + } + + cout << "code" << ied_usr->terminal_code << endl; + if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) { + //terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code); + terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code)); + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else + { + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + if (addr_str != NULL) { + ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + + } + else + { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + } + + if (port_char != NULL) { + int port = 102; + if (stringToInt(port_char, &port)) { + // תɹportStrȫΪ֣ѾתΪint͵port + ied->channel[0].port = port;//DEV_PortID + cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID + } + else { + ied->channel[0].port = 102;//DEV_PortID + cout << "ied_usr->port:" << port_char << ",ǺϷ˿.ʹĬ϶˿:" << ied->channel[0].port << endl;//DEV_PortID + } + + + } + if (timestamp.year != 0) { + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + ied_usr->time = static_cast(time); + cout << "ied_usr->time:" << ied_usr->time << endl; + + + } + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + + } + + OTLDisconnect(); + //listѭ + if (count_real < count_cfg) + g_node->n_clients = count_real; + if (count_cfg != count_real) + return APR_EBADF; + cout << "dev init create count:" << count_real; + return APR_SUCCESS; + } + catch (otl_exception& e) + { + printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + +} +//CZY 2023-08-30 read line account from web api +int parse_line_cfg_pg() +{ + ied_t* ied; + ied_usr_t* ied_usr; + int count_cfg = 0; + int count_real = 0; + LD_info_t line_info; + + try { + //int rtState = OTLState(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor"); + str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in ("); + //str1.append("\".\"MEAS_PQ_FRONT_LIST_TR\""); + int dev_no = 0; + cout << "n_clients:" << g_node->n_clients << endl; + if (g_node->n_clients <= 0) { + cout << "no terminal exist " << endl; + return APR_EBADF; + } + for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) { + str1.append("'"); + str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code); + str1.append("'"); + if (dev_no < g_node->n_clients - 1) { + str1 += ","; + } + } + str1.append(")"); + cout << "pg sql1 is:" << str1 << endl; + //int rtState = OTLState(); + OTLConnect(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + int f2; + while (!i.eof()) { //while not end-of-data + i >> f2; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + count_cfg = f2;;//ݿ + cout << "line_count=" << count_cfg << endl; + + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + + + // + try { + OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor"); + str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in ("); + int dev_no = 0; + + for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) { + str1.append("'"); + str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code); + str1.append("'"); + if (dev_no < g_node->n_clients - 1) { + str1 += ","; + } + } + str1.append(")"); + cout << "pg sql2 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp; + cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq; + cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect; + cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl; + + count_real++; + memset(&line_info, 0, sizeof(line_info)); + line_info.line_id = count_real; + //cout << "line_id:" << line_info.line_id << endl; + + strcpy(line_info.mp_id, monitor_id); + //cout << "mp_id:" << line_info.mp_id << endl; + strcpy(line_info.terminal_code, terminal_code); + //cout << "terminal_code:" << line_info.terminal_code << endl; + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; + //cout << "logical_device_seq:is null~"<< line_info.cpuno << endl; + } + else { + line_info.cpuno = std::atoi(logical_device_seq); + //cout << "logical_device_seq:"<< logical_device_seq << endl; + } + //cout << "cpuno:" << line_info.cpuno << endl; + strcpy(line_info.voltage_level, voltage_level); + //cout << "voltage_level:" << line_info.voltage_level << endl; + strcpy(line_info.v_wiring_type, terminal_connect); + //cout << "v_wiring_type:" << line_info.v_wiring_type << endl; + + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + line_info.time = static_cast(time); + //cout << "time:" << line_info.time << endl; + + strcpy(line_info.name, monitor_name); + //cout << "name:" << line_info.name << endl; + line_info.read_flag = 1; + ied = find_ied_from_dev_code(line_info.terminal_code); + + if (ied && ied->usr_ext && line_info.cpuno && line_info.cpuno < 10) { + char str[256]; + byte_t cpuno = line_info.cpuno; + //cout << "cpuno:" << line_info.cpuno << endl; + //cout << "byte_t cpuno:" << cpuno-1 << endl; + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + //cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl; + + if (cpuno > ied->cpucount) { + //int c = cpuno; + //cout << "cpucount(linecount old):" << (int)(ied->cpucount) << "new:" << c << endl; + + ied->cpucount = cpuno; + //cout << "byte_t cpucount:" << ied->cpucount+1 << endl; + } + } + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + if (count_cfg != count_real) + return APR_EBADF; + return APR_SUCCESS; +} +int parse_device_cfg_json_test() +{ + + qDebug() << "parse_device_cfg_json_test" << endl; + + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + int count_cfg = 0; + int count_real = 0; + + //ȡ + //string* json_buf; + cJSON* json = NULL; + cJSON* json_value = NULL; + + cJSON* json_records = NULL; + cJSON* json_node = NULL; + + int dev_num = 0; + QMap terminal_ext_map; + read_terminal_ext_pg(&terminal_ext_map); + try { + //GetWebApiJson(1); + /* if (strDevCJson == "") { + cout << "json select total error" << endl; + return APR_EBADF; + }*/ + char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"testcode\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}"; + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"testcode\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00002128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}"; + json = cJSON_Parse(json_buf); + + //json = cJSON_Parse(strDevCJson.toUtf8().constData()); //jsonʽл + //cout << cJSON_Print(json) << endl; + int total; + if (NULL == json) + { + printf("cJSON_Parse error:%s\n", cJSON_GetErrorPtr()); + return APR_EBADF; + } + json_records = cJSON_GetObjectItem(json, "result"); //ȡresult + json_records = cJSON_GetObjectItem(json_records, "0751002"); //ȡ0751002 + json_value = cJSON_GetObjectItem(json_records, "total"); //ȡ total + if (json_value != NULL && json_value != NULL) { + total = json_value->valueint; + } + + cout << "dev total:" << total << endl; + cJSON_Delete(json); + //GetWebApiJson(1); + /*if (strDevCJson == "") { + cout << "select dev json error" << endl; + return APR_EBADF; + }*/ + //json = cJSON_Parse(strDevCJson.toUtf8().constData()); //jsonʽл + json = cJSON_Parse(json_buf); + + json_records = cJSON_GetObjectItem(json, "result"); //ȡresult + json_records = cJSON_GetObjectItem(json_records, "0751002"); //ȡ0751002 + json_value = cJSON_GetObjectItem(json_records, "size"); //ȡ size + if (json_value != NULL && json_value != NULL) { + count_cfg = json_value->valueint; + cout << "count_cfg" << "--" << json_value->valueint << "--" << count_cfg << endl; + } + g_node->n_clients = count_cfg; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + + + //豸ѭ + int array_size = 0; + json_records = cJSON_GetObjectItem(json_records, "records"); //ȡrecords + array_size = cJSON_GetArraySize(json_records); //ȡС + + printf("array_size=%d\n", array_size); + + for (int i = 0; i < array_size; i++) + { + json_node = cJSON_GetArrayItem(json_records, i);//array + json_node = cJSON_GetObjectItem(json_node, "resource"); //ȡresource + ied = g_node->clients[count_real++]; + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, 500 * sizeof(LD_info_t)); + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + + json_value = cJSON_GetObjectItem(json_node, "astId"); //ȡ astId + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", json_value->valuestring);//terminal_id + cout << "terminal_id" << json_value->valuestring << "--" << ied_usr->terminal_id << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "equipCode"); //ȡ equipCode + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", "testcode");//terminal_code + cout << "terminal_code" << json_value->valuestring << "--" << ied_usr->terminal_code << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "city#Name"); //ȡ city#Name + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", json_value->valuestring);//org_name + cout << "org_name" << json_value->valuestring << "--" << ied_usr->org_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "maintOrg#Name"); //ȡ maintOrg#Name + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", json_value->valuestring);//maint_name + cout << "maint_name" << json_value->valuestring << "--" << ied_usr->maint_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "station#Name"); //ȡ station#Name + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", json_value->valuestring);//station_name + cout << "station_name" << json_value->valuestring << "--" << ied_usr->station_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "manufacturer#Name"); //ȡ manufacturer#Name + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", json_value->valuestring);//tmnl_factory + cout << "tmnl_factory" << json_value->valuestring << "--" << ied_usr->tmnl_factory << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "deployState"); //ȡ deployState + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", json_value->valuestring);//tmnl_status + cout << "tmnl_status" << json_value->valuestring << "--" << ied_usr->tmnl_status << endl; + } + + + //json_value = cJSON_GetObjectItem(json_node, "lastUpdateTime"); //ȡ lastUpdateTime + json_value = cJSON_GetObjectItem(json_node, "ctime"); //ȡ ctime + if (json_value != NULL && json_value != NULL) { + //ied_usr->time = strtoll(json_value->valuestring, NULL, 10);//time + ied_usr->time = charToLongLong(json_value->valuestring);//time + cout << "time" << json_value->valuestring << "--" << ied_usr->time << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "model"); //ȡ model + if (json_value != NULL && json_value != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", json_value->valuestring);//DEV_Type + cout << "dev_type:" << json_value->valuestring << "--" << ied_usr->dev_type << endl; + } + + int t = 1; + if (t) { + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "!qaz@wsx3edc4rfv");//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "Pqs&cn870299");//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else { + cout << "code" << ied_usr->terminal_code << endl; + if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) { + //terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code); + terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code)); + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_identify_code);//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_key);//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else + { + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + } + + ied_usr->dev_flag = 0;//DEV_DevFlag + + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + cout << "channel_type:" << ied->channel[0].channel_type << endl; + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + + json_value = cJSON_GetObjectItem(json_node, "ipAddress"); //ȡ ipAddress + if (json_value != NULL && json_value != NULL) { + if (i == 0) { + ied->channel[0].addr = ntohl(inet_addr("192.168.1.212"));//DEV_IP + strncpy(ied->channel[0].addr_str, "192.168.1.212", LONGNAME - 1);//DEV_IP + } + else { + ied->channel[0].addr = ntohl(inet_addr(json_value->valuestring));//DEV_IP + strncpy(ied->channel[0].addr_str, json_value->valuestring, LONGNAME - 1);//DEV_IP + } + cout << "addr:" << json_value->valuestring << "--" << ied->channel[0].addr << "--" << ied->channel[0].addr_str << endl; + + } + + + json_value = cJSON_GetObjectItem(json_node, "portNum"); //ȡ portNum + if (json_value != NULL && json_value != NULL) { + //ied->channel[0].port = atoi(json_value->valuestring);//DEV_PortID + ied->channel[0].port = atoi("102");//DEV_PortID + cout << "port:" << "--" << atoi(json_value->valuestring) << "--" << ied->channel[0].port << endl; + } + + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + } + cJSON_Delete(json); + //listѭ + if (count_real < count_cfg) + g_node->n_clients = count_real; + if (count_cfg != count_real) + return APR_EBADF; + cout << "dev init create count:" << count_real; + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } + +} +int parse_line_cfg_pg_test() +{ + ied_t* ied; + ied_usr_t* ied_usr; + int count_cfg = 0; + int count_real = 0; + LD_info_t line_info; + + try { + OTLConnect(); + //int rtState = OTLState(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor\""); + cout << "pg sq1 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + db //connect object + ); + //create select stream + + int f2; + while (!i.eof()) { //while not end-of-data + i >> f2; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + count_cfg = f2;;//ݿ + cout << "line_count=" << count_cfg << endl; + + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + + + + // + try { + OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor\""); + //cout << "pg sql2 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + otl_datetime timestamp; + int cpuno_count = 1; + while (!i.eof()) { //while not end-of-data + i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp; + //cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq; + //cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect; + //cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl; + + count_real++; + memset(&line_info, 0, sizeof(line_info)); + line_info.line_id = count_real; + //cout << "line_id:" << line_info.line_id << endl; + + strcpy(line_info.mp_id, monitor_id); + //cout << "mp_id:" << line_info.mp_id << endl; + strcpy(line_info.terminal_code, "testcode"); + //cout << "terminal_code:" << line_info.terminal_code << endl; + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; + //cout << "logical_device_seq:is null~"<< line_info.cpuno << endl; + } + else { + line_info.cpuno = std::atoi(logical_device_seq); + //cout << "logical_device_seq:"<< logical_device_seq << endl; + } + //cout << "cpuno:" << line_info.cpuno << endl; + strcpy(line_info.voltage_level, voltage_level); + //cout << "voltage_level:" << line_info.voltage_level << endl; + strcpy(line_info.v_wiring_type, terminal_connect); + //cout << "v_wiring_type:" << line_info.v_wiring_type << endl; + + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + line_info.time = static_cast(time); + //cout << "time:" << line_info.time << endl; + + strcpy(line_info.name, monitor_name); + //cout << "name:" << line_info.name << endl; + + ied = find_ied_from_dev_code("testcode"); + + if (ied && ied->usr_ext && line_info.cpuno) { + char str[256]; + byte_t cpuno = cpuno_count; + //cout << "cpuno:" << line_info.cpuno << endl; + //cout << "byte_t cpuno:" << cpuno-1 << endl; + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + //cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl; + + if (cpuno > ied->cpucount) { + int c = cpuno; + + ied->cpucount = cpuno; + cout << "byte_t cpucount:" << ied->cpucount + 1 << endl; + } + + } + cpuno_count++; + if (cpuno_count > 150) { + break; + } + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + + if (count_cfg != count_real) + return APR_EBADF; + return APR_SUCCESS; +} +void dev_account_add() { + +} +void dev_account_delete() { + +} +void dev_account_update() { + +} +void line_account_add() { + +} +void line_account_delete(int update_flag) { + +} +void line_account_update(int update_flag) { + +} +int create_temp_device_cfg_json(QMap& dev_map) +{ + qDebug() << "parse_device_cfg_json" << endl; + if (FRONT_INST == 0 || FRONT_IP[0] == '\0') { + MULTIPLE_NODE_FLAG = 0; + cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl; + + } + char front_type[2]; + int mp_num; + + if (MULTIPLE_NODE_FLAG) { + //std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(POSTGRES_SCHEMA); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("meas_pq_front_list_tr"); + str1.append("\" where \"front_ip\" = '"); + str1.append(FRONT_IP); + str1.append("' and \"front_inst\" = "); + std::string str3 = QString::number(FRONT_INST).toStdString(); + str1.append(str3); + str1.append(";"); + try { + OTLConnect(); + otl_stream i1(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + + int front_count; + while (!i1.eof()) { //while not end-of-data + i1 >> front_count; + //cout << "count=" << f2 << endl; + } + cout << "count=" << front_count << endl; + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + QString selectFrontSql; + selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0")); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + OTLConnect(); + otl_stream i2(1, // buffer size + selectFrontSql.toStdString().c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + + while (!i2.eof()) { //while not end-of-data + i2 >> front_type >> mp_num; + break; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + } + cout << "mp_num:" << mp_num << " FRONT_INST:" << FRONT_INST << endl; + + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + int count_cfg = 0; + int count_real = 0; + + //ȡ + //string* json_buf; + cJSON* json = NULL; + cJSON* json_value = NULL; + + cJSON* json_records = NULL; + cJSON* json_node = NULL; + + int dev_num = 0; + QMap terminal_ext_map; + read_terminal_ext_pg(&terminal_ext_map); + try { + int total; + GetWebApiJson(1, 1, CITY_FLAG); + if (strDevCJson == "") { + cout << "json select total error" << endl; + return APR_EBADF; + } + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}"; + /* char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00000128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"PQS-883\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.232.245.101\",\"equipCode\":\"16M00002128569231\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}"; + json = cJSON_Parse(json_buf);*/ + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.227\",\"equipCode\":\"22M00000299758903\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"20102\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}},{\"assets\":[],\"distribution\":1,\"id\":\"af8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"signalInputForm\":\"02\",\"source#Name\":\"豸-\",\"source\":\"01\",\"currsigInputChanqutity\":\"1\",\"astOrg#Name\":\"ʡ˾\",\"astOrg\":\"02DC9D994CE579E4E053661EDF0AFC25\",\"cabinetType\":\"05\",\"ctime\":\"2022-02-19 00:00:00\",\"model\":\"E8300\",\"station#Name\":\"110kVվ\",\"equipmentOwner\":\"E94A0732B2FB5AA1E0430901E80A21E9\",\"manufactureNum\":\"202596\",\"ipAddress\":\"10.161.208.237\",\"equipCode\":\"22M00000299800679\",\"subnetMask\":\"255.255.255.224\",\"astId\":\"af8080817efe6c21017f1064ab7c0c7e\",\"macAddress\":\"00B78D00DC23\",\"astNum\":\"200102118916\",\"signalInputForm#Name\":\"ź\",\"maintOrg#Name\":\"żҽ繩繫˾޹˾\",\"name\":\"110kV 䱦504װ\",\"deviceLevel\":\"01\",\"projectNum\":\"GGXM20220219BT\",\"projectName\":\"װ\",\"operateDate\":\"2021-11-19 00:00:00\",\"deployState\":\"20\",\"hardDiskCapacity\":\"64\",\"city\":\"02DC9D994EED79E4E053661EDF0AFC25\",\"timeSynchronization\":\"02\",\"astNature\":\"03\",\"manufacturer\":\"041696\",\"astOrgName\":\"ʡ˾\",\"voltsigInputChanqutity\":\"1\",\"cabinetType#Name\":\"ͽʽ\",\"runDevName\":\"504\",\"devPowerVoltage\":\"220\",\"station\":\"531b04dd7c8a5f84214ff783280150531a67987189\",\"manufactureDate\":\"2020-12-19 00:00:00\",\"astNature#Name\":\"ʡֱϽС˾\",\"portNum\":\"10022\",\"maintGroup#Name\":\"ά\",\"maintGroup\":\"02DC9D994F3A79E4E053661EDF0AFC25\",\"manufacturer#Name\":\"ϾܵԶɷ޹˾\",\"detectDate\":\"2021-02-19 00:00:00\",\"city#Name\":\"żҽ繩繫˾\",\"deployState#Name\":\"\",\"equipmentOwner#Name\":\"\",\"deviceLevel#Name\":\"A\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"100.232.245.97\"}}],\"searchCount\":true,\"size\":2,\"total\":391}},\"status\":\"000000\"}"; + //json = cJSON_Parse(json_buf); + + //char json_buf[] = "{\"errors\":\"ɹ\",\"message\":\"ɹ\",\"result\":{\"0751002\":{\"current\":1,\"orders\":[],\"pages\":391,\"records\":[{\"assets\":[],\"distribution\":1,\"id\":\"ff8080817efe6c21017f1064ab7c0c7e\",\"modelId\":\"0751002Z\",\"resource\":{\"deviceKind\":\"0751002\",\"maintOrg\":\"02DC9D994F2879E4E053661EDF0AFC25\",\"cabinet\":\"4dcc03dbc58a5f84225130303b01514dcba0cd1be5\",\"gateway\":\"10.232.245.97\"}}],\"searchCount\":true,\"size\":1,\"total\":391}},\"status\":\"000000\"}"; + + json = cJSON_Parse(strDevCJson.toUtf8().constData()); //jsonʽл + //cout << cJSON_Print(json) << endl; + if (NULL == json) + { + printf("cJSON_Parse error:%s\n", cJSON_GetErrorPtr()); + return APR_EBADF; + } + json_records = cJSON_GetObjectItem(json, "result"); //ȡresult + json_records = cJSON_GetObjectItem(json_records, "0751002"); //ȡ0751002 + json_value = cJSON_GetObjectItem(json_records, "total"); //ȡ total + if (json_value != NULL) { + total = json_value->valueint; + } + + cJSON_Delete(json); + if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) { + if (strcmp(front_type, "01") == 0) { + GetWebApiJson(mp_num, FRONT_INST, CITY_FLAG); + } + else + { + GetWebApiJson(mp_num, FRONT_INST, CITY_FLAG); + } + } + else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) { + int front_num = (total / g_front_seg_num) + 1; + GetWebApiJson(front_num, FRONT_INST, CITY_FLAG); + + } + else { + /* cout << "dev total:" << total << endl; + if (total > 300) { + total = 300; + cout << "update dev total:" << total << endl; + + }*/ + GetWebApiJson(total, 1, CITY_FLAG); + } + + + if (strDevCJson == "") { + cout << "select dev json error" << endl; + return APR_EBADF; + } + json = cJSON_Parse(strDevCJson.toUtf8().constData()); //jsonʽл + + //json = cJSON_Parse(json_buf); + + json_records = cJSON_GetObjectItem(json, "result"); //ȡresult + json_records = cJSON_GetObjectItem(json_records, "0751002"); //ȡ0751002 + json_value = cJSON_GetObjectItem(json_records, "size"); //ȡ size + + //豸ѭ + int array_size = 0; + json_records = cJSON_GetObjectItem(json_records, "records"); //ȡrecords + array_size = cJSON_GetArraySize(json_records); //ȡС + + /*count_cfg = array_size; + cout << "count_cfg" << "--" << count_cfg << endl; + g_node->n_clients = count_cfg; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));*/ + + + printf("array_size=%d\n", array_size); + + for (int i = 0; i < array_size; i++) + { + json_node = cJSON_GetArrayItem(json_records, i);//array + json_node = cJSON_GetObjectItem(json_node, "resource"); //ȡresource + ied = (ied_t*)apr_pcalloc(g_temp_dev_pool, sizeof(ied_t)); + count_real++; + ied_usr = (ied_usr_t*)apr_pcalloc(g_temp_dev_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_temp_dev_pool, MAX_CPUNO * sizeof(LD_info_t)); + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_temp_dev_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + + json_value = cJSON_GetObjectItem(json_node, "astId"); //ȡ astId + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", json_value->valuestring);//terminal_id + cout << "terminal_id:" << json_value->valuestring << "--" << ied_usr->terminal_id << endl; + } + else { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", "");//terminal_id + cout << "default terminal_id:" << ied_usr->terminal_id << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "equipCode"); //ȡ equipCode + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", json_value->valuestring);//terminal_code + cout << "terminal_code:" << json_value->valuestring << "--" << ied_usr->terminal_code << endl; + } + else { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", "");//terminal_code + cout << "default terminal_code:" << ied_usr->terminal_code << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "city#Name"); //ȡ city#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", json_value->valuestring);//org_name + cout << "org_name:" << json_value->valuestring << "--" << ied_usr->org_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "maintOrg#Name"); //ȡ maintOrg#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", json_value->valuestring);//maint_name + cout << "maint_name:" << json_value->valuestring << "--" << ied_usr->maint_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "station#Name"); //ȡ station#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", json_value->valuestring);//station_name + cout << "station_name:" << json_value->valuestring << "--" << ied_usr->station_name << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "manufacturer#Name"); //ȡ manufacturer#Name + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", json_value->valuestring);//tmnl_factory + cout << "tmnl_factory:" << json_value->valuestring << "--" << ied_usr->tmnl_factory << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "deployState"); //ȡ deployState + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", json_value->valuestring);//tmnl_status + cout << "tmnl_status:" << json_value->valuestring << "--" << ied_usr->tmnl_status << endl; + } + else { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", "10");//tmnl_status + cout << "default tmnl_status:" << ied_usr->tmnl_status << endl; + + } + + + //json_value = cJSON_GetObjectItem(json_node, "lastUpdateTime"); //ȡ lastUpdateTime + json_value = cJSON_GetObjectItem(json_node, "ctime"); //ȡ ctime + if (json_value != NULL && json_value->string != NULL) { + //ied_usr->time = strtoll(json_value->valuestring, NULL, 10);//time + ied_usr->time = charToLongLong(json_value->valuestring);//time + cout << "time:" << ied_usr->time << endl; + } + + + json_value = cJSON_GetObjectItem(json_node, "model"); //ȡ model + if (json_value != NULL && json_value->string != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", json_value->valuestring);//DEV_Type + cout << "dev_type:" << json_value->valuestring << "--" << ied_usr->dev_type << endl; + } + else { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", "no-type");//DEV_Type + cout << "default dev_type:" << ied_usr->dev_type << endl; + } + + int t = 1; + if (t) { + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "!qaz@wsx3edc4rfv");//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "Pqs&cn870299");//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else { + cout << "code:" << ied_usr->terminal_code << endl; + if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) { + //terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code); + terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code)); + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else + { + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + } + + ied_usr->dev_flag = 0;//DEV_DevFlag + + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + cout << "channel_type:" << ied->channel[0].channel_type << endl; + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + + json_value = cJSON_GetObjectItem(json_node, "ipAddress"); //ȡ ipAddress + if (json_value != NULL && json_value->string != NULL) { + if (t && i == 0) { + ied->channel[0].addr = ntohl(inet_addr("172.40.251.35"));//DEV_IP + strncpy(ied->channel[0].addr_str, "172.40.251.35", LONGNAME - 1);//DEV_IP + } + else { + ied->channel[0].addr = ntohl(inet_addr(json_value->valuestring));//DEV_IP + strncpy(ied->channel[0].addr_str, json_value->valuestring, LONGNAME - 1);//DEV_IP + } + cout << "addr:" << json_value->valuestring << "--" << ied->channel[0].addr << "--" << ied->channel[0].addr_str << endl; + + } + else { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.1"));//DEV_IP + strncpy(ied->channel[0].addr_str, "0.0.0.1", LONGNAME - 1);//DEV_IP + //} + cout << "default addr:" << ied->channel[0].addr_str << endl; + + } + + + json_value = cJSON_GetObjectItem(json_node, "portNum"); //ȡ portNum + if (json_value != NULL && json_value->string != NULL) { + ied->channel[0].port = atoi(json_value->valuestring);//DEV_PortID + if (t) { + ied->channel[0].port = atoi("102");//DEV_PortID + } + cout << "port:" << "--" << atoi(json_value->valuestring) << "--" << ied->channel[0].port << endl; + } + else { + ied->channel[0].port = 0;//DEV_PortID + if (t) { + ied->channel[0].port = atoi("102");//DEV_PortID + } + cout << "default port:" << ied->channel[0].port << endl; + + } + dev_map.insert(QString::fromUtf8(ied_usr->terminal_code), ied); + + } + cJSON_Delete(json); + //listѭ + + + cout << "temp dev qmap init create count:" << count_real; + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } + +} +int create_temp_line_cfg_pg(QMap& dev_map) +{ + + ied_t* ied; + ied_usr_t* ied_usr; + int count_cfg = 0; + int count_real = 0; + LD_info_t line_info; + + try { + //int rtState = OTLState(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor"); + str1.append("\" where \"terminal_code\" in ("); + //str1.append("\".\"MEAS_PQ_FRONT_LIST_TR\""); + + QMap::const_iterator cit; + for (cit = dev_map.constBegin(); cit != dev_map.constEnd();) { + QString key = cit.key(); + str1.append("'"); + str1.append(key.toStdString()); + str1.append("'"); + if (++cit != dev_map.constEnd()) { + str1 += ","; + } + } + + str1.append(")"); + cout << "dev line pg sql1 is:" << str1 << endl; + //int rtState = OTLState(); + OTLConnect(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + int f2; + while (!i.eof()) { //while not end-of-data + i >> f2; + //cout << "count=" << f2 << endl; + } + OTLDisconnect(); + count_cfg = f2;;//ݿ + cout << "line_count=" << count_cfg << endl; + + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + + + // + try { + OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor"); + str1.append("\" where \"terminal_code\" in ("); + + QMap::const_iterator cit; + for (cit = dev_map.constBegin(); cit != dev_map.constEnd();) { + QString key = cit.key(); + str1.append("'"); + str1.append(key.toStdString()); + str1.append("'"); + if (++cit != dev_map.constEnd()) { + str1 += ","; + } + } + + str1.append(")"); + cout << "qmap line pg sql2 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp; + //cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq; + //cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect; + //cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl; + + count_real++; + memset(&line_info, 0, sizeof(line_info)); + line_info.line_id = count_real; + //cout << "line_id:" << line_info.line_id << endl; + + strcpy(line_info.mp_id, monitor_id); + //cout << "mp_id:" << line_info.mp_id << endl; + strcpy(line_info.terminal_code, terminal_code); + //cout << "terminal_code:" << line_info.terminal_code << endl; + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; + //cout << "logical_device_seq:is null~"<< line_info.cpuno << endl; + } + else { + line_info.cpuno = std::atoi(logical_device_seq); + //cout << "logical_device_seq:"<< logical_device_seq << endl; + } + //cout << "cpuno:" << line_info.cpuno << endl; + strcpy(line_info.voltage_level, voltage_level); + //cout << "voltage_level:" << line_info.voltage_level << endl; + strcpy(line_info.v_wiring_type, terminal_connect); + //cout << "v_wiring_type:" << line_info.v_wiring_type << endl; + + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + line_info.time = static_cast(time); + //cout << "time:" << line_info.time << endl; + + strcpy(line_info.name, monitor_name); + //cout << "name:" << line_info.name << endl; + + ied = dev_map.value(QString::fromUtf8(line_info.terminal_code)); + //ied = find_ied_from_dev_code(line_info.terminal_code); + + if (ied && ied->usr_ext && line_info.cpuno && line_info.cpuno < 10) { + char str[256]; + byte_t cpuno = line_info.cpuno; + //cout << "cpuno:" << line_info.cpuno << endl; + //cout << "byte_t cpuno:" << cpuno-1 << endl; + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_temp_dev_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_temp_dev_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_temp_dev_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + //cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl; + + if (cpuno > ied->cpucount) { + //int c = cpuno; + //cout << "cpucount(linecount old):" << (int)(ied->cpucount) << "new:" << c << endl; + + ied->cpucount = cpuno; + //cout << "byte_t cpucount:" << ied->cpucount+1 << endl; + } + } + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + if (count_cfg != count_real) + return APR_EBADF; + return APR_SUCCESS; + + +} +void g_node_add_dev() { + int count_cfg = g_node->n_clients; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); +} +//CZY 2023-08-25 +int compare_line_account(ied_usr_t* run_ied_usr, ied_usr_t* temp_ied_usrs, int run_cpucount, int temp_cpucount) { + int run_cpuno, temp_cpuno; + for (run_cpuno = 0; run_cpuno < run_cpucount; run_cpuno++) { + + int delete_flag = 1; + for (temp_cpuno = 0; temp_cpuno < temp_cpucount; temp_cpuno++) { + if (run_ied_usr->LD_info[run_cpuno].mp_id == temp_ied_usrs->LD_info[temp_cpuno].mp_id) {//exist same mp_id(update,keep) + if (run_ied_usr->LD_info[run_cpuno].time < temp_ied_usrs->LD_info[temp_cpuno].time) {//line_update + run_ied_usr->LD_info[run_cpuno].update_flag = 4; + temp_ied_usrs->LD_info[temp_cpuno].update_flag = 4; + + } + else {//line_keep + run_ied_usr->LD_info[run_cpuno].update_flag = 0; + temp_ied_usrs->LD_info[temp_cpuno].update_flag = 0; + } + delete_flag = 0; + break; + } + } + if (delete_flag == 1) {//line_delete + run_ied_usr->LD_info[run_cpuno].update_flag = 2; + + } + } + for (temp_cpuno = 0; temp_cpuno < temp_cpucount; temp_cpuno++) { + int add_flag = 1; + for (run_cpuno = 0; run_cpuno < run_cpucount; run_cpuno++) { + if (run_ied_usr->LD_info[run_cpuno].mp_id == temp_ied_usrs->LD_info[temp_cpuno].mp_id) {//exist same mp_id + + add_flag = 0; + break; + } + } + if (add_flag == 1) {//line_add + temp_ied_usrs->LD_info[temp_cpuno].update_flag = 8; + } + } + return 0; +} +//CZY 2023-08-22 compare account +int compare_node_account(node_t* run_g_node, node_t* temp_g_node, int* add_count) +{ + + if (run_g_node == NULL) { + return 1; + } + if (temp_g_node == NULL) { + return 2; + } + int i, j; + for (i = 0; i < run_g_node->n_clients; i++) { + ied_usr_t* run_ied_usr = (ied_usr_t*)run_g_node->clients[i]->usr_ext; + run_ied_usr->update_flag = 0; + int delete_flag = 1; + for (j = 0; j < temp_g_node->n_clients; j++) { + ied_usr_t* temp_ied_usr = (ied_usr_t*)temp_g_node->clients[j]->usr_ext; + if (run_ied_usr->terminal_id == temp_ied_usr->terminal_id) {//exist same terminal_id(update,delete,keep) + + if (temp_ied_usr->time > run_ied_usr->time)//dev_update or delete + { + if (strcmp(temp_ied_usr->tmnl_status, "20") != 0 && strcmp(run_ied_usr->tmnl_status, "20") == 0) {//dev_delete + temp_ied_usr->update_flag = 2; + run_ied_usr->update_flag = 2; + + int cpuno; + for (cpuno = 0; cpuno < run_g_node->clients[i]->cpucount; cpuno++) {//line_delete + run_ied_usr->LD_info[cpuno].update_flag = 2; + } + } + else {//dev_update + run_ied_usr->update_flag = 4; + temp_ied_usr->update_flag = 4; + int cpuno; + //for (cpuno = 0; cpuno < temp_g_node->clients[j]->cpucount; cpuno++) {//line_update + // temp_ied_usr->LD_info[cpuno].update_flag = 8; + //} + int f = compare_line_account(run_ied_usr, temp_ied_usr, run_g_node->clients[i]->cpucount, temp_g_node->clients[j]->cpucount);//line_compare + } + + } + else {//dev_keep + int f = compare_line_account(run_ied_usr, temp_ied_usr, run_g_node->clients[i]->cpucount, temp_g_node->clients[j]->cpucount);//line_compare + + } + delete_flag = 0; + break; + } + } + if (delete_flag == 1) {//dev_delete + run_ied_usr->update_flag = 2; + + } + } + for (i = 0; i < temp_g_node->n_clients; i++) { + ied_usr_t* temp_ied_usr = (ied_usr_t*)temp_g_node->clients[i]->usr_ext; + if (temp_ied_usr->update_flag == 2) { + continue; + } + int add_flag = 1; + for (j = 0; j < run_g_node->n_clients; j++) { + ied_usr_t* run_ied_usr = (ied_usr_t*)run_g_node->clients[j]->usr_ext; + if (temp_ied_usr->terminal_id == run_ied_usr->terminal_id) { + add_flag = 0; + break; + } + } + if (add_flag == 1) {//dev_add + temp_ied_usr->update_flag = 8; + int cpuno; + for (cpuno = 0; cpuno < temp_g_node->clients[i]->cpucount; cpuno++) {//line_add + temp_ied_usr->LD_info[cpuno].update_flag = 8; + *add_count += 1; + } + } + } + return 0; + +} +// +void handle_line_account(ied_usr_t* run_ied_usr, ied_usr_t* temp_ied_usrs, int run_cpucount, int temp_cpucount) { + int run_cpuno, temp_cpuno; + for (run_cpuno = 0; run_cpuno < run_cpucount; run_cpuno++) { + if (run_ied_usr->LD_info[run_cpuno].update_flag = 0) { + + } + else if (run_ied_usr->LD_info[run_cpuno].update_flag = 2) { + line_account_delete(run_ied_usr->update_flag); + } + else if (run_ied_usr->LD_info[run_cpuno].update_flag = 4) { + line_account_update(run_ied_usr->update_flag); + } + } + for (temp_cpuno = 0; temp_cpuno < temp_cpucount; temp_cpuno++) { + if (temp_ied_usrs->LD_info[run_cpuno].update_flag = 8) { + line_account_add(); + } + } +} +// CZY 2023-09-12 handle account +void handle_node_account(node_t* run_g_node, node_t* temp_g_node, int dev_count) { + int i; + for (i = 0; i < run_g_node->n_clients; i++) { + ied_usr_t* run_ied_usr = (ied_usr_t*)run_g_node->clients[i]->usr_ext; + if (run_ied_usr->update_flag == 0) { + + } + else if (run_ied_usr->update_flag == 2) { + dev_account_delete(); + } + else if (run_ied_usr->update_flag == 4) { + dev_account_update(); + } + + } + //dev + for (i = 0; i < temp_g_node->n_clients; i++) { + ied_usr_t* temp_ied_usr = (ied_usr_t*)temp_g_node->clients[i]->usr_ext; + if (temp_ied_usr->update_flag == 8) { + dev_account_add(); + } + } +} +//CZY 2023-08-25 +void create_temp_g_node(node_t* temp_g_node) { + /*create_temp_device_cfg_json(temp_g_node); + create_temp_line_cfg_pg(temp_g_node); + int* add_count = 0; + compare_node_account(g_node, temp_g_node, add_count);*/ + + +} +void dev_update() { + QMap dev_map; + //create_temp_device_cfg_json(dev_map); +} +#endif + +int GetServerIndexFromDB() //ȡǰ÷ +{ + + register int fd, interface; + const int MAXINTERFACES = 100; + struct ifreq buf[MAXINTERFACES]; + struct arpreq arp; + struct ifconf ifc; + char mac[32] = ""; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + ifc.ifc_len = sizeof buf; + ifc.ifc_buf = (caddr_t)buf; + if (!ioctl(fd, SIOCGIFCONF, (char*)&ifc)) { + interface = ifc.ifc_len / sizeof(struct ifreq); + printf("\ninterface num is interface= %d\n", interface); + + while (interface-- > 0) { + printf("net device %s\n", buf[interface].ifr_name); + + /*ȷǷֻ֧ģʽ Jugde whether the net card status is promisc */ + if (!(ioctl(fd, SIOCGIFFLAGS, (char*)&buf[interface]))) { + if (buf[interface].ifr_flags & IFF_PROMISC) { + printf("the interface is PROMISC \n"); + } + } + else { + char str[256] = ""; + sprintf(str, "cpm: ioctl device %s", buf[interface].ifr_name); + perror(str); + } + + /*ж״̬Ƿ Judge whether the net card status is up */ + if (buf[interface].ifr_flags & IFF_UP) { + printf("the interface status is UP\n"); + } + else { + printf("the interface status is DOWN\n"); + } + + /*ȡIPַ Get IP of the net card */ + if (!(ioctl(fd, SIOCGIFADDR, (char*)&buf[interface]))) { + printf("IP address is: %s\n", inet_ntoa(((struct sockaddr_in*)(&buf[interface].ifr_addr))->sin_addr)); + + } + else { + char str[256] = ""; + sprintf(str, "cpm: ioctl device %s", buf[interface].ifr_name); + perror(str); + } + + /*ȡHWַ Get HW ADDRESS of the net card */ + if (!(ioctl(fd, SIOCGIFHWADDR, (char*)&buf[interface]))) { + printf("HW address is: "); + sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", + (unsigned char)buf[interface].ifr_hwaddr.sa_data[0], + (unsigned char)buf[interface].ifr_hwaddr.sa_data[1], + (unsigned char)buf[interface].ifr_hwaddr.sa_data[2], + (unsigned char)buf[interface].ifr_hwaddr.sa_data[3], + (unsigned char)buf[interface].ifr_hwaddr.sa_data[4], + (unsigned char)buf[interface].ifr_hwaddr.sa_data[5]); + printf("%s\n\n", mac); + } + else { + char str[256]; + sprintf(str, "cpm: ioctl device %s", buf[interface].ifr_name); + perror(str); + } + } + } + else + perror("cpm: ioctl"); + } + else + perror("cpm: socket"); + + close(fd); + return 0; +} +/////////////////////////////////////////////////////////CZY + +void parse_one_rpt_log_ini(int idx, QStringList* rpt_cfg_strlist, QStringList* log_cfg_strlist, char* type) +{ + char* tmp; + tmp = Get_xmlpath(type); + if (tmp == NULL) { + //zw޸ 2023 - 8 - 15 ĽXML ԭRptLogCfg.iniȡ + if (strcmp(subdir, "cfg_stat_data") == 0) + { + QString devtype; + devtype.append(type); + QString devtype2; + devtype2.append("HL-6810"); + + qDebug() << "cfg_stat_data"; + QString xml_dir = QString("../") + QString("etc/"); //Linuxµ· + + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(xml_dir + QString("JiangSu_Config.xml")); + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + { + qDebug() << "Read RPT Error1"; + return; + } + if (!doc.setContent(&file)) //ļݶdoc + { + qDebug() << "Read RPT Error2"; + file.close(); + return; + } + file.close(); + QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //ظڵԪ + QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" + while (!n.isNull()) //Topicڵ㲻Ϊ + { + if (n.isElement()) + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); // + if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + { + qDebug() << "ReportStat"; + QDomNodeList list = e.childNodes(); //Ԫصӽڵб + for (int i = 0; i < list.count(); i++) // DataTypeб + { + QDomNode node = list.at(i); //node1 + if (node.isElement()) + { + QString strTag2 = node.toElement().tagName(); //DataTypeڵ + if ("ReportStat" == strTag2) + { + QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + { + QDomNode node2 = list2.at(i2); //node2 + if (node2.isElement()) + { + rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl")); + qDebug() << "devtype:" << devtype << node2.toElement().attribute("ReportControl").toAscii().data(); + } + } + } + } + + } + } + } + n = n.nextSibling(); + } + + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + log_cfg_strlist->append(log_cfg_str); + } + if (strcmp(subdir, "cfg_soe_comtrade") == 0) + { + qDebug() << "cfg_soe_comtrade"; + QString xml_dir = QString("../") + QString("etc/"); //Linuxµ· + + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(xml_dir + QString("JiangSu_Config.xml")); + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + { + qDebug() << "Read RPT Error1"; + return; + } + if (!doc.setContent(&file)) //ļݶdoc + { + qDebug() << "Read RPT Error2"; + file.close(); + return; + } + file.close(); + QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //ظڵԪ + QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" + while (!n.isNull()) //Topicڵ㲻Ϊ + { + if (n.isElement()) + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); // + if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + { + qDebug() << "ReportEvent"; + QDomNodeList list = e.childNodes(); //Ԫصӽڵб + for (int i = 0; i < list.count(); i++) // DataTypeб + { + QDomNode node = list.at(i); //node1 + if (node.isElement()) + { + QString strTag2 = node.toElement().tagName(); //DataTypeڵ + if ("ReportEvent" == strTag2) + { + QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + { + QDomNode node2 = list2.at(i2); //node2 + if (node2.isElement()) + { + rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl")); + qDebug() << node2.toElement().attribute("ReportControl").toAscii().data(); + } + } + } + } + + } + } + } + n = n.nextSibling(); + } + + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + log_cfg_strlist->append(log_cfg_str); + } + if (strcmp(subdir, "cfg_his_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0 || strcmp(subdir, "cfg_recallhis_data") == 0 || strcmp(subdir, "cfg_recallall_data") == 0) + { + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + log_cfg_strlist->append(log_cfg_str); + } + } + else + { + QString tmppath; + tmppath.append("/FeProject/dat/").append(tmp).append(".xml"); + qDebug() << tmppath; + + //lnk20241126 + std::cout << "rptcfgfile:" << tmppath.toStdString() << std::endl; + + //zw޸ 2023 - 8 - 15 ĽXML ԭRptLogCfg.iniȡ + if (strcmp(subdir, "cfg_stat_data") == 0) + { + qDebug() << "cfg_stat_data"; + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(tmppath); + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + { + qDebug() << "Read RPT Error1"; + + //lnk20241126 + std::cout << "Read RPT Error1" << std::endl; + + return; + } + if (!doc.setContent(&file)) //ļݶdoc + { + qDebug() << "Read RPT Error2"; + + //lnk20241126 + std::cout << "Read RPT Error2" << std::endl; + + file.close(); + return; + } + file.close(); + QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //ظڵԪ + QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" + while (!n.isNull()) //Topicڵ㲻Ϊ + { + if (n.isElement()) + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); // + if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + { + qDebug() << "ReportStat"; + QDomNodeList list = e.childNodes(); //Ԫصӽڵб + for (int i = 0; i < list.count(); i++) // DataTypeб + { + QDomNode node = list.at(i); //node1 + if (node.isElement()) + { + QString strTag2 = node.toElement().tagName(); //DataTypeڵ + if ("ReportStat" == strTag2) + { + QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + { + QDomNode node2 = list2.at(i2); //node2 + if (node2.isElement()) + { + rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl")); + qDebug() << node2.toElement().attribute("ReportControl").toAscii().data(); + } + } + } + } + + } + } + } + n = n.nextSibling(); + } + + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + log_cfg_strlist->append(log_cfg_str); + } + + //lnkʵʱ20241125 + if (strcmp(subdir, "cfg_3s_data") == 0) + { + qDebug() << "cfg_3s_data"; + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(tmppath); + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + { + qDebug() << "Read RPT Error1"; + return; + } + if (!doc.setContent(&file)) //ļݶdoc + { + qDebug() << "Read RPT Error2"; + file.close(); + return; + } + file.close(); + QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //ظڵԪ + QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" + while (!n.isNull()) //Topicڵ㲻Ϊ + { + if (n.isElement()) + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); // + if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + { + qDebug() << "ReportReal"; + QDomNodeList list = e.childNodes(); //Ԫصӽڵб + for (int i = 0; i < list.count(); i++) // DataTypeб + { + QDomNode node = list.at(i); //node1 + if (node.isElement()) + { + QString strTag2 = node.toElement().tagName(); //DataTypeڵ + if ("ReportReal" == strTag2) + { + QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + { + QDomNode node2 = list2.at(i2); //node2 + if (node2.isElement()) + { + rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl")); + qDebug() << node2.toElement().attribute("ReportControl").toAscii().data(); + } + } + } + } + + } + } + } + n = n.nextSibling(); + } + + //QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + //log_cfg_strlist->append(log_cfg_str); + } + + if (strcmp(subdir, "cfg_soe_comtrade") == 0) + { + qDebug() << "cfg_soe_comtrade"; + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(tmppath); + if (!file.open(QIODevice::ReadOnly | QFile::Text)) //ֻʽxml + { + qDebug() << "Read RPT Error1"; + return; + } + if (!doc.setContent(&file)) //ļݶdoc + { + qDebug() << "Read RPT Error2"; + file.close(); + return; + } + file.close(); + QDomNode firstNode = doc.firstChild(); //ڵ"JSConfigTemplate" + QDomElement docElem = doc.documentElement(); //ظڵԪ + QDomNode n = docElem.firstChild(); //docĵһڵ㣬"Topic" + while (!n.isNull()) //Topicڵ㲻Ϊ + { + if (n.isElement()) + { + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); // + if ("ReportMap" == strTag)//zw޸ 2023 - 8 - 15 ж ĽXML ԭRptLogCfg.iniȡ + { + qDebug() << "ReportEvent"; + QDomNodeList list = e.childNodes(); //Ԫصӽڵб + for (int i = 0; i < list.count(); i++) // DataTypeб + { + QDomNode node = list.at(i); //node1 + if (node.isElement()) + { + QString strTag2 = node.toElement().tagName(); //DataTypeڵ + if ("ReportEvent" == strTag2) + { + QDomNodeList list2 = node.childNodes(); //ԪDataTypeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) // Monitorб + { + QDomNode node2 = list2.at(i2); //node2 + if (node2.isElement()) + { + rpt_cfg_strlist->append(node2.toElement().attribute("ReportControl")); + qDebug() << node2.toElement().attribute("ReportControl").toAscii().data(); + } + } + } + } + + } + } + } + n = n.nextSibling(); + } + + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + log_cfg_strlist->append(log_cfg_str); + } + if (strcmp(subdir, "cfg_his_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0 || strcmp(subdir, "cfg_recallhis_data") == 0 || strcmp(subdir, "cfg_recallall_data") == 0) + { + QString log_cfg_str = "LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0"; + log_cfg_strlist->append(log_cfg_str); + } + delete[] tmp; + } +} + +int parse_rpt_log_ini() +{ + const int MAX_DEV_FLAG = 10; + bool not_loaded[MAX_DEV_FLAG]; + //QStringList rpt_cfg_strlists[MAX_DEV_FLAG]; + //QStringList log_cfg_strlists[MAX_DEV_FLAG]; + QMap rpt_cfg_strlists; + QMap log_cfg_strlists; + + int iedno, cpuno; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + char buf[256]; + + /*for (int i = 0; i < MAX_DEV_FLAG; ++i) + not_loaded[i] = true;*/ + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = GET_IEDEXT_ADDR(ied); + QString type; + type.append(ied_usr->dev_type); + if (!rpt_cfg_strlists.contains(type)) + { + QStringList* rpt_temp = new QStringList(); + QStringList* log_temp = new QStringList(); + rpt_cfg_strlists.insert(type, rpt_temp); + log_cfg_strlists.insert(type, log_temp); + parse_one_rpt_log_ini(ied_usr->dev_flag, rpt_cfg_strlists[type], log_cfg_strlists[type], ied_usr->dev_type); + + } + /*if (not_loaded[ied_usr->dev_flag]) { + parse_one_rpt_log_ini(ied_usr->dev_flag, rpt_cfg_strlists[ied_usr->dev_flag], log_cfg_strlists[ied_usr->dev_flag], ied_usr->dev_type); + not_loaded[ied_usr->dev_flag] = false; + }*/ + + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + char str[256]; + char* tmp = Get_IED(ied_usr->dev_type); + qDebug() << tmp << endl; + + apr_snprintf(str, sizeof(str), tmp, cpuno + 1); + + ied_usr->LD_info[cpuno].LD_name = apr_pstrdup(g_init_pool, str);//domin + + delete[] tmp; + + init_rptctrl_by_count(LD_info, rpt_cfg_strlists[type]->size()); + + for (int i = 0; i < rpt_cfg_strlists[type]->size(); ++i) { + + apr_snprintf(buf, sizeof(buf), "%s", rpt_cfg_strlists[type]->at(i).toAscii().constData()); + + fill_rptctrl_by_cfg(LD_info, i, buf); + + } + + init_logctrl_by_count(LD_info, log_cfg_strlists[type]->size()); + for (int i = 0; i < log_cfg_strlists[type]->size(); ++i) { + apr_snprintf(buf, sizeof(buf), "%s", log_cfg_strlists[type]->at(i).toAscii().constData()); + char* tmp = Get_LDevice(ied_usr->dev_type); + fill_logctrl_by_cfg(LD_info, i, buf, tmp); + delete[] tmp; + } + + } + } + + //ƿ־ƿ鴦 + for (QMap::iterator it1 = log_cfg_strlists.begin(); it1 != log_cfg_strlists.end(); ++it1) + { + delete it1.value(); + } + for (QMap::iterator it2 = rpt_cfg_strlists.begin(); it2 != rpt_cfg_strlists.end(); ++it2) + { + delete it2.value(); + } + rpt_cfg_strlists.clear(); + log_cfg_strlists.clear(); + + return APR_SUCCESS; +} + +int parse_json_cfg() +{ + QString cfg_dir = QString("../") + QString("etc/"); + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(cfg_dir + JSON_CONFIG_FN_old); + if (!file.open(QIODevice::ReadOnly)) + return APR_EBADPATH; //ֻʽ + if (!doc.setContent(&file)) { + file.close(); + return APR_EBADF; + } + //ļݶdoc + QDomElement docElem = doc.documentElement(); //ظԪ + QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ + while (!n.isNull()) { //ڵ㲻Ϊ + if (n.isElement()) { //ڵԪ + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); + QString topic = e.attribute("name"); + if (strTag == "Topic" && (topic == "HISDATA" || topic == "RTDATA")) { + QDomNodeList list = e.childNodes(); //Ԫeӽڵб e + for (int i = 0; i < list.count(); i++) { //б + QDomNode node = list.at(i); + if (node.isElement()) { + QString strTag2 = node.toElement().tagName(); + QString data_type = node.toElement().attribute("value"); + if (strTag2 == "DataType") { //node + QDomNodeList list2 = node.childNodes(); //Ԫnodeӽڵб + for (int i2 = 0; i2 < list2.count(); i2++) { //б + QDomNode node2 = list2.at(i2); ////node2 + if (node2.isElement()) { + QString strTag3 = node2.toElement().tagName(); + /////////////////////////// + if (strTag3 == "Monitor") { + QDomNodeList list3 = node2.childNodes(); //Ԫnodeӽڵб + for (int i3 = 0; i3 < list3.count(); i3++) { //б + QDomNode node3 = list3.at(i3); //node3 + if (node3.isElement()) { + QString strTag4 = node3.toElement().tagName(); + //**////**////**////**////**////**////**////**////**////**////**// + if (strTag4 == "Item") { + QString item = node3.toElement().attribute("name"); + QDomNodeList list4 = node3.childNodes(); //Ԫnodeӽڵб + for (int i4 = 0; i4 < list4.count(); i4++) { //б + QDomNode node4 = list4.at(i4); //node4 + if (node4.isElement()) { + QString strTag5 = node4.toElement().tagName(); + //////////*********************//////////////////// + if (strTag5 == "Sequence") { + uint sequence = node4.toElement().attribute("value").toUInt(); + QDomNodeList list5 = node4.childNodes(); //Ԫnodeӽڵб + for (int i5 = 0; i5 < list5.count(); i5++) { //б + QDomNode node5 = list5.at(i5); //node5 + if (node5.isElement()) { + QDomElement e_Value = node5.toElement(); //תΪԪ + QString strTag6 = e_Value.tagName(); + // + if (strTag6 == "Value") { + QString name_str = e_Value.attribute("name"); + QString DO_str = e_Value.attribute("DO"); + QString DA_str = e_Value.attribute("DA"); + uint mask = 1; + for (int j = 0; j <= 3; j++) { + if (mask & sequence) + qDebug() << topic << " " << data_type << " " << item << " Phs=" << j << " " << name_str << " " << DO_str << DA_str; + mask *= 2; + } + //todo ,to read the attribute of Value + } + } + } + } + //////////*********************//////////////////// + } + } + } + //**////**////**////**////**////**////**////**////**////**////**// + } + } + } + //////////////////////////////// + } + }// for(int i2=0; i2 find_xml_belong_to_this_process() +{ + char prefix[20]; // Ҫ20ַʵҪ + sprintf(prefix, "%d_%d", g_node_id, g_front_seg_index); // g_node_idg_front_seg_indexʽΪַ + + DIR *dir = opendir(LEDGER_UPDATE_DIR.c_str()); // Ŀ¼ + struct dirent *entry; + std::list found_files; // ڴ洢ҵƥļ + + if (dir == NULL) { + std::cout << "Failed to open directory: " << LEDGER_UPDATE_DIR << std::endl; + return found_files; // ؿյlist + } + + //std::cout << "we should find file with prefix:" << prefix << std::endl; + + // Ŀ¼еļ + while ((entry = readdir(dir)) != NULL) { + std::string filename = entry->d_name; + + // ų "." ".." Ŀ¼ + if (filename == "." || filename == "..") { + continue; + } + + std::cout << "find" << filename << "in" << LEDGER_UPDATE_DIR << std::endl; + + //std::cout << "filename.find(prefix):" << filename.find(prefix) << std::endl; + + //std::cout << "filename.substr(filename.find_last_of('.') + 1)" << filename.substr(filename.find_last_of('.') + 1) << std::endl; + + // жļǷ prefix ͷչ .xml + if (filename.find(prefix) == 0 && filename.substr(filename.find_last_of('.') + 1) == "xml") { + std::string full_path = LEDGER_UPDATE_DIR + filename; + found_files.push_back(full_path); // · + } + } + + closedir(dir); // رĿ¼ + + return found_files; // ҵļ +} + +// ȡǩеֵͨú +std::string extract_value(const std::string& data, const std::string& tag) { + size_t start_pos = data.find("<" + tag + ">"); + if (start_pos == std::string::npos) return ""; + size_t end_pos = data.find("", start_pos); + if (end_pos == std::string::npos) return ""; + + return data.substr(start_pos + tag.length() + 2, end_pos - start_pos - tag.length() - 2); +} + +// str_tag terminal ӵӦ +void add_terminal_to_trigger_update(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const terminal& work_terminal) { + if (str_tag == "add") { + std::cout << "new ledger!!!!"<new_update_num < MAX_UPDATEA_NUM) { + trigger_update_xml->new_updates[trigger_update_xml->new_update_num] = work_terminal; + trigger_update_xml->new_update_num++; // ն˵ + } else { + std::cerr << "Exceeded MAX_UPDATEA_NUM limit for new updates!" << std::endl; + } + } + else if (str_tag == "modify") { + std::cout << "modify ledger!!!"<modify_update_num < MAX_UPDATEA_NUM) { + trigger_update_xml->modify_updates[trigger_update_xml->modify_update_num] = work_terminal; + trigger_update_xml->modify_update_num++; // ޸ն˵ + } else { + std::cerr << "Exceeded MAX_UPDATEA_NUM limit for modify updates!" << std::endl; + } + } + else { + std::cerr << "Unknown tag: " << str_tag << std::endl; + } +} + +// XML ݲȡ terminal Ϣ +void parse_terminal_from_data(trigger_update_xml_t* trigger_update_xml, const std::string& str_tag, const std::string& data) { + terminal work_terminal = {}; // µ terminal + + // ȡֶ + strcpy(work_terminal.terminal_id, extract_value(data, "id").c_str()); + strcpy(work_terminal.terminal_code, extract_value(data, "terminalCode").c_str()); + strcpy(work_terminal.org_name, extract_value(data, "orgName").c_str()); + strcpy(work_terminal.maint_name, extract_value(data, "maintName").c_str()); + strcpy(work_terminal.station_name, extract_value(data, "stationName").c_str()); + strcpy(work_terminal.tmnl_factory, extract_value(data, "manufacturer").c_str()); + strcpy(work_terminal.tmnl_status, extract_value(data, "status").c_str()); + strcpy(work_terminal.dev_type, extract_value(data, "devType").c_str()); + strcpy(work_terminal.dev_key, extract_value(data, "devKey").c_str()); + strcpy(work_terminal.dev_series, extract_value(data, "series").c_str()); + strcpy(work_terminal.addr_str, extract_value(data, "ip").c_str()); + strcpy(work_terminal.port, extract_value(data, "port").c_str()); + strcpy(work_terminal.timestamp, extract_value(data, "updateTime").c_str()); + + size_t monitor_pos = 0; + size_t monitor_count = 0; + + // ÿ monitorDataദ 10 + while ((monitor_pos = data.find(" λ + } + + + // str_tag terminal ӵӦ + add_terminal_to_trigger_update(trigger_update_xml, str_tag, work_terminal); +} + +void parse_ledger_update(trigger_update_xml_t* trigger_update_xml, const std::string& strTag, const std::string& data) +{ + std::cout << "record one xml.."<delete_update_num < MAX_UPDATEA_NUM) { + trigger_update_xml->delete_updates[trigger_update_xml->delete_update_num] = delete_terminal; + trigger_update_xml->delete_update_num++; // Ӽ + } + } + + } else { + std::cerr << "Unsupported strTag: " << strTag << std::endl; + } +} + + +int load_ledger_update_from_xml(trigger_update_xml_t* trigger_update_xml, const std::string& xml_fn) +{ + std::cout << "start to load one xml.."< ǩ + size_t ledger_pos = content.find(""); + if (ledger_pos == std::string::npos) { + std::cerr << "ledger_update tag not found!" << std::endl; + return -1; + } + + // , , ǩ + size_t add_pos = content.find("", ledger_pos); + size_t delete_pos = content.find("", ledger_pos); + size_t modify_pos = content.find("", ledger_pos); + + // ȷĸǩڣȡӦλ + size_t target_pos = std::string::npos; + std::string target_tag; + + if (add_pos != std::string::npos) { + target_pos = add_pos; + target_tag = "add"; + } else if (delete_pos != std::string::npos) { + target_pos = delete_pos; + target_tag = "delete"; + } else if (modify_pos != std::string::npos) { + target_pos = modify_pos; + target_tag = "modify"; + } + + //ûҵȷıǩ˳ + if (target_pos == std::string::npos) { + std::cerr << "No , , or tag found!" << std::endl; + return -1; + } + + // ĿǩĽλ + size_t end_pos = content.find("", target_pos); + if (end_pos == std::string::npos) { + std::cerr << "Closing tag not found!" << std::endl; + return -1; + } + + // ȡĿǩ + std::string target_content = content.substr(target_pos + target_tag.length() + 2, end_pos - (target_pos + target_tag.length() + 2)); + + // е + size_t data_pos = 0; + while ((data_pos = target_content.find("", data_pos)) != std::string::npos) { + size_t data_end_pos = target_content.find("", data_pos); + if (data_end_pos == std::string::npos) { + std::cerr << "Closing tag not found!" << std::endl; + return -1; + } + + std::string data_content = target_content.substr(data_pos + 14, data_end_pos - (data_pos + 14)); + + std::cout << "ledger data_content is " << data_content <ǩĿǰÿļֻһ̨ + data_pos = data_end_pos + 15; + } + + std::cout << "load one xml finish"< result = find_xml_belong_to_this_process(); + + if (!result.empty()) { + std::cout << "Found XML files:" << std::endl; + for (std::list::iterator it = result.begin(); it != result.end(); ++it) { + const std::string& filename = *it; + std::cout << filename << std::endl; + //ÿļȡնˣжնǷ + apr_sleep(apr_time_from_sec(1) / 10); + //һļݵݽṹ + if (!load_ledger_update_from_xml(trigger_update_xml, filename)) { + std::cout << "read /etc/ledgerupdate/" << filename << " success..." << std::endl; + } + //ļɾ + + if (std::remove(filename.c_str()) != 0) { + std::cerr << "Failed to remove file: " << filename << " Error: " << strerror(errno) << std::endl; + return APR_EGENERAL; + } + else{ + std::cout << "remove file: " << filename << " success..." << std::endl; + } + } + } + else { + //std::cout << "No matching XML files found." << std::endl; + return APR_EGENERAL; + } + + //ݷسɹд + //printf("Modify Update Count: %d\n", trigger_update_xml->modify_update_num); + //printf("Delete Update Count: %d\n", trigger_update_xml->delete_update_num); + //printf("New Update Count: %d\n", trigger_update_xml->new_update_num); + if(trigger_update_xml->modify_update_num || trigger_update_xml->delete_update_num || trigger_update_xml->new_update_num){ + printf("ledger update xml have data...\n"); + return APR_SUCCESS; + } + else{//ݷʧܣ + printf("ledger update xml no data...\n"); + return APR_EGENERAL; + } + +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//ʵʱ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +QString THREE_SECS_WEBSERVICE_DIR = QString("../etc/trigger3s/"); + +QString get_3s_trig_fn() +{ + QDir directory(THREE_SECS_WEBSERVICE_DIR); + QStringList filters = QStringList() << "*.xml"; + QStringList fileNames = directory.entryList(filters, QDir::Files, QDir::Time/*|QDir::Reversed*/); + if (fileNames.size() > 0) + return fileNames.at(0); + else + return ""; +} +/////////////////////////////////////////////////////////////// +int getValueFromElemAttrStr(QString str) +{ + if (str == "true") + return 1; + else if (str == "false") + return 0; + else + return -1; +} + +//lnk20241125Ӵӡ///////////////////////////////////////////////////////////////////////////////////////////////// +// ӡ trigger_t ṹĺ +void print_trigger(const trigger_t& trigger) { + printf(" dev_idx: %d, line_id: %d, real_data: %d, soe_data: %d, limit: %d, count: %d\n", + trigger.dev_idx, trigger.line_id, trigger.real_data, trigger.soe_data, trigger.limit, trigger.count); +} +// ӡ trigger_3s_xml_t ṹĺ +void print_trigger_3s_xml(const trigger_3s_xml_t& trigger_3s_xml) { + printf("Work Trigger Count: %d\n", trigger_3s_xml.work_trigger_num); + for (int i = 0; i < trigger_3s_xml.work_trigger_num; ++i) { + printf(" Work Trigger [%d]:\n", i + 1); + print_trigger(trigger_3s_xml.work_triggers[i]); + } + + printf("New Trigger Count: %d\n", trigger_3s_xml.new_trigger_num); + for (int i = 0; i < trigger_3s_xml.new_trigger_num; ++i) { + printf(" New Trigger [%d]:\n", i + 1); + print_trigger(trigger_3s_xml.new_triggers[i]); + } + + printf("Delete Trigger Count: %d\n", trigger_3s_xml.delete_trigger_num); + for (int i = 0; i < trigger_3s_xml.delete_trigger_num; ++i) { + printf(" Delete Trigger [%d]:\n", i + 1); + print_trigger(trigger_3s_xml.delete_triggers[i]); + } + + printf("Modify Trigger Count: %d\n", trigger_3s_xml.modify_trigger_num); + for (int i = 0; i < trigger_3s_xml.modify_trigger_num; ++i) { + printf(" Modify Trigger [%d]:\n", i + 1); + print_trigger(trigger_3s_xml.modify_triggers[i]); + } +} + +//ʵʱļ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void parse_3s_trigger(trigger_3s_xml_t* trigger_3s_xml, QString parentTag, QDomElement& trigger_e) +{ + QString e_atr(""); + trigger_t trigger; + + trigger.dev_idx = trigger_e.attribute("DevSeries").toInt(); + trigger.line_id = trigger_e.attribute("Line").toInt(); + + e_atr = trigger_e.attribute("RealData").toLower(); + trigger.real_data = getValueFromElemAttrStr(e_atr); + + e_atr = trigger_e.attribute("SOEData").toLower(); + trigger.soe_data = getValueFromElemAttrStr(e_atr); + + trigger.limit = trigger_e.attribute("Limit").toInt(); + trigger.count = trigger_e.attribute("Count").toInt(); + //qDebug()< " << dev_idx<<" "<work_triggers[trigger_3s_xml->work_trigger_num++] = trigger; + } + else if (parentTag == "New") { + trigger_3s_xml->new_triggers[trigger_3s_xml->new_trigger_num++] = trigger; + } + else if (parentTag == "Delete") { + trigger_3s_xml->delete_triggers[trigger_3s_xml->delete_trigger_num++] = trigger; + } + else if (parentTag == "Modify") { + trigger_3s_xml->modify_triggers[trigger_3s_xml->modify_trigger_num++] = trigger; + } + //lnk20241125 + print_trigger_3s_xml(*trigger_3s_xml); + +} + +int load_3s_data_from_xml(trigger_3s_xml_t* trigger_3s_xml, QString xml_fn) +{ + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(xml_fn); + if (!file.open(QIODevice::ReadOnly)) + return APR_EBADPATH; //ֻʽ + bool ret = doc.setContent(&file); + file.close(); + if (!ret) + return APR_EBADF; + + //ļݶdoc + QDomElement docElem = doc.documentElement(); //ظԪ + QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ + while (!n.isNull()) { //ڵ㲻Ϊ + if (n.isElement()) { //ڵԪ + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); + if (strTag == "Work" || strTag == "New" || strTag == "Delete" || strTag == "Modify") { + QDomNodeList list = e.childNodes(); //Ԫeӽڵб + for (int i = 0; i < list.count(); i++) { //б + QDomNode node = list.at(i); + if (node.isElement()) { + QDomElement trigger_e = node.toElement(); + QString strTag2 = trigger_e.tagName(); + if (strTag2 == "Trigger") { + parse_3s_trigger(trigger_3s_xml, strTag, trigger_e); + } //else if ( strTag == "Trigger" ) + } + } + } + } + n = n.nextSibling(); //һֵܽڵ + } + + return APR_SUCCESS; +} + +QString BAK_WEBSERVICE_3S_TRIG_COMMAND_XML_FN = THREE_SECS_WEBSERVICE_DIR + "bak_3s_trig_command.txt"; +int parse_3s_xml(trigger_3s_xml_t* trigger_3s_xml) +{ + printf("begin 3s xml...\n"); + memset(trigger_3s_xml, 0, sizeof(trigger_3s_xml_t)); + + //ļ¼ڽеʵʱ + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/"); + load_3s_data_from_xml(trigger_3s_xml, (cfg_dir + THREE_SECS_CONFIG_FN)); ///Feproject/etc/Trigger3S.xml + + QString the_webservice_xml_fn = get_3s_trig_fn();// ../etc/trigger3s/Ŀ¼µµxmlļļʵʱĿ + + printf("the_webservice_xml_fn.size():%d\n",the_webservice_xml_fn.size()); + + if (the_webservice_xml_fn.size() > 4) {//ļ4˵ҵļ + apr_sleep(apr_time_from_sec(1) / 10); + the_webservice_xml_fn = THREE_SECS_WEBSERVICE_DIR + the_webservice_xml_fn; + load_3s_data_from_xml(trigger_3s_xml, the_webservice_xml_fn); + QFile::remove(BAK_WEBSERVICE_3S_TRIG_COMMAND_XML_FN); + QFile::rename(the_webservice_xml_fn, BAK_WEBSERVICE_3S_TRIG_COMMAND_XML_FN); + + printf("/etc/trigger3s/*.xml success...\n"); + return APR_SUCCESS; + } + + printf("3s xml fail...\n"); + return APR_EGENERAL; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//3s¼дļ +void append_triggers(QDomDocument& doc, QDomElement& root, QString parentTag, trigger_t* trigger, int trigger_num) +{ + QString str; + QDomElement funcItem = doc.createElement(parentTag); + root.appendChild(funcItem); + for (int i = 0; i < trigger_num; i++) { + if (trigger[i].dev_idx == INVALID_DEV_IDX) + continue; + if (trigger[i].real_data == 0 && trigger[i].soe_data == 0) + continue; + QDomElement triggerItem = doc.createElement("Trigger"); + triggerItem.setAttribute("DevSeries", trigger[i].dev_idx); + triggerItem.setAttribute("Line", trigger[i].line_id); + str = trigger[i].real_data ? "true" : "false"; + triggerItem.setAttribute("RealData", str); + str = trigger[i].soe_data ? "true" : "false"; + triggerItem.setAttribute("SOEData", str); + triggerItem.setAttribute("Limit", trigger[i].limit); + triggerItem.setAttribute("Count", trigger[i].count); + funcItem.appendChild(triggerItem); + } +} + +int create_3s_xml(trigger_3s_xml_t* trigger_3s_xml) +{ + + QDomDocument doc; + doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"gb2312\"")); + + QDomElement root = doc.createElement("Trigger3S"); + doc.appendChild(root); + + append_triggers(doc, root, "Work", trigger_3s_xml->work_triggers, trigger_3s_xml->work_trigger_num); + append_triggers(doc, root, "New", trigger_3s_xml->new_triggers, 0); + append_triggers(doc, root, "Delete", trigger_3s_xml->delete_triggers, 0); + append_triggers(doc, root, "Modify", trigger_3s_xml->modify_triggers, 0); + + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/"); + QFile file(cfg_dir + THREE_SECS_CONFIG_FN /*+".bak.xml"*/); + if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) { + return -1; + } + QTextStream out(&file); + out.setCodec("gb2312"); + doc.save(out, 4); + file.close(); + + return APR_SUCCESS; +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ܣָ .cfg ļȡʼʱʹʱ䣬תΪ뼶ʱ +// +// - comtrade_fnļΪοڶλӦ .cfg ļ +// +// - start_tmصʼʱλ룩 +// - trig_tmصĴʱλ룩 +// ֵ +// - APR_SUCCESS ʾɹ APR_EBADF ʾļ +int extract_timestamp_from_cfg_file(char* comtrade_fn, long long* start_tm, long long* trig_tm) +{ + // ȡļϢ·ļȡ + QFileInfo fi(QString::fromAscii(comtrade_fn)); + QString fn = fi.fileName(); + QString cfgFileName_temp = QString("../comtrade/") + fn; // ƴ.cfgļ· + + // ļǷ ".cfg" ".CFG" β + if (!cfgFileName_temp.endsWith(".cfg", Qt::CaseInsensitive) && !cfgFileName_temp.endsWith(".CFG", Qt::CaseInsensitive)) + return APR_EBADF; // ļҪ󣬷ļ + + // ļ + QFile cfgFile_temp(cfgFileName_temp); + if (!cfgFile_temp.exists()) { // ļ + qDebug() << QString("Cannot find corresponding .cfg file: %1").arg(cfgFileName_temp); + cfgFile_temp.close(); + return APR_EBADF; + } + else if (!cfgFile_temp.open(QFile::ReadOnly | QFile::Text)) { // ļ޷ + qDebug() << QString("Cannot open file %1:\n%2.").arg(cfgFileName_temp).arg(cfgFile_temp.errorString()); + return APR_EBADF; + } + else { + QStringList datContentList_temp; + QTextStream in_temp(&cfgFile_temp); // ıȡļ + // GBK صĴ루ע͵ˣ + + QString start_time_str(""); // ڴ洢ʼʱַ + QString trigger_time_str(""); // ڴ洢ʱַ + + // жȡļ + while (!in_temp.atEnd()) { + QString line_temp = in_temp.readLine().trimmed(); // ȡȥհַ + QString upper_line_temp = line_temp.toUpper(); // תΪдַ + + // ȡ "ASCII" "BINARY" ַֹͣ + if ((upper_line_temp == QString("ASCII")) || (upper_line_temp == QString("BINARY"))) + break; + else { + // ûУʼʱʹʱ + start_time_str = trigger_time_str; + trigger_time_str = line_temp; + } + } + + // ȡ start_time_str ȴ3ȥ3ַͨǺ벿֣ + if (start_time_str.size() > 3) + start_time_str = start_time_str.left(start_time_str.size() - 3); + + // start_time_str תΪ QDateTime 󣬲תΪԼԪĺ + QDateTime start_time_dt = QDateTime::fromString(start_time_str, "dd/MM/yyyy,hh:mm:ss.zzz"); + *start_tm = start_time_dt.toMSecsSinceEpoch(); // תΪʱֵ start_tm + + // ͬʱ䣨ȥ3ַתΪʱ + if (trigger_time_str.size() > 3) + trigger_time_str = trigger_time_str.left(trigger_time_str.size() - 3); + + QDateTime trigger_time_dt = QDateTime::fromString(trigger_time_str, "dd/MM/yyyy,hh:mm:ss.zzz"); + *trig_tm = trigger_time_dt.toMSecsSinceEpoch(); // תΪʱֵ trig_tm + + cfgFile_temp.close(); // رļ + } + + return APR_SUCCESS; // ɹ +} +#if 0 +int extract_timestamp_from_cfg_file(char* comtrade_fn, long long* start_tm, long long* trig_tm) +{ + QFileInfo fi(QString::fromAscii(comtrade_fn)); + QString fn = fi.fileName(); + QString cfgFileName_temp = QString("../comtrade/") + fn; + if (!cfgFileName_temp.endsWith(".cfg", Qt::CaseInsensitive) && !cfgFileName_temp.endsWith(".CFG", Qt::CaseInsensitive))//fn_str.endsWith(".cfg", Qt::CaseInsensitive) || fn_str.endsWith(".CFG", Qt::CaseInsensitive) + return APR_EBADF; + + QFile cfgFile_temp(cfgFileName_temp); + if (!cfgFile_temp.exists()) { + qDebug() << QString("Cannot find corresponding .cfg file: %1").arg(cfgFileName_temp); + cfgFile_temp.close(); + return APR_EBADF; + } + else if (!cfgFile_temp.open(QFile::ReadOnly | QFile::Text)) { + qDebug() << QString("Cannot open file %1:\n%2.").arg(cfgFileName_temp).arg(cfgFile_temp.errorString()); + return APR_EBADF; + } + else { + QStringList datContentList_temp; + QTextStream in_temp(&cfgFile_temp); + /*QTextCodec *codec_temp=QTextCodec::codecForName("gbk"); + in_temp.setCodec(codec_temp);*/ + QString start_time_str(""); + QString trigger_time_str(""); + while (!in_temp.atEnd()) { + QString line_temp = in_temp.readLine().trimmed(); + QString upper_line_temp = line_temp.toUpper(); + if ((upper_line_temp == QString("ASCII")) || (upper_line_temp == QString("BINARY"))) + break; + else { + start_time_str = trigger_time_str; + trigger_time_str = line_temp; + } + } + //11/05/2018,15:28:53.343000 + if (start_time_str.size() > 3) + start_time_str = start_time_str.left(start_time_str.size() - 3); + QDateTime start_time_dt = QDateTime::fromString(start_time_str, "dd/MM/yyyy,hh:mm:ss.zzz"); + *start_tm = start_time_dt.toMSecsSinceEpoch(); + + if (trigger_time_str.size() > 3) + trigger_time_str = trigger_time_str.left(trigger_time_str.size() - 3); + QDateTime trigger_time_dt = QDateTime::fromString(trigger_time_str, "dd/MM/yyyy,hh:mm:ss.zzz"); + *trig_tm = trigger_time_dt.toMSecsSinceEpoch(); + + cfgFile_temp.close(); + } + return APR_SUCCESS; +} +#endif +//¼/////////////////////////////////////////////////////////////////////////////// +//WW 2023-11-01 ¼κŲintƥ +int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm) +{ + int j; + printf(">>>>>>>>>>>>>>>>>>pares_file_names file list match fltnum=%d", fltnum); + + *cfg_idx = -1; + *dat_idx = -1; + for (j = 0; j < filenum; ++j) { + + char fileNameTemp[64]; + strcpy(fileNameTemp, filenames[j]); //ʱ װ¼ļ + printf(" %s ", fileNameTemp); + if (strstr(fileNameTemp, domname) == NULL) //:"PQMonitor_PQM1" װ¼ļ:"PQMonitor_PQM1_000001_20191121_154534_689.CFG/.DAT/.HDR"Ӵ + continue; + char* p = strtok(fileNameTemp, "_"); //PQMonitor + p = strtok(NULL, "_"); //PQM1 + p = strtok(NULL, "_"); //000001 + int nFltNum = atoi(p); //ַת + + if (nFltNum == fltnum) { + + QString fn_str = QString::fromAscii(filenames[j]); + if (fn_str.endsWith(".cfg", Qt::CaseInsensitive) || fn_str.endsWith(".CFG", Qt::CaseInsensitive)) { + //PQMonitor_PQM4_000349_20180531_113701_618.CFG + *cfg_idx = j; + + QFileInfo fi(fn_str); + QString fn = fi.baseName(); + strcpy(file_base_name, fn.toAscii().data()); + + QString remain_str = fn_str.split(QString::fromAscii(p)).at(1); + QString yyyymm_str = remain_str.mid(1, 6); + strcpy(file_yyyymm, yyyymm_str.toAscii().data()); + } + else if (fn_str.endsWith(".dat", Qt::CaseInsensitive) || fn_str.endsWith(".DAT", Qt::CaseInsensitive)) + *dat_idx = j; + + } + if (*cfg_idx != -1 && *dat_idx != -1)//ļѾҵ + break; + } + + printf("\n<<<<<<<<<<<<<<<<<<<<= 0 && (*dat_idx) >= 0) + return APR_SUCCESS; + else + return APR_EBADF; +} +//WW2023-11-01 end +int parse_file_names(char* file_match_str, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm) +{ + int j; + + *cfg_idx = -1; + *dat_idx = -1; + for (j = 0; j < filenum; ++j) { + if (strstr(filenames[j], file_match_str) != NULL) { + QString fn_str = QString::fromAscii(filenames[j]); + if (fn_str.endsWith(".cfg", Qt::CaseInsensitive)) { + //PQMonitor_PQM4_000349_20180531_113701_618.CFG + *cfg_idx = j; + + QFileInfo fi(fn_str); + QString fn = fi.baseName(); + strcpy(file_base_name, fn.toAscii().data()); + + QString remain_str = fn_str.split(QString::fromAscii(file_match_str)).at(1); + QString yyyymm_str = remain_str.mid(1, 6); + strcpy(file_yyyymm, yyyymm_str.toAscii().data()); + } + else if (fn_str.endsWith(".dat", Qt::CaseInsensitive)) + *dat_idx = j; + } + } + + if ((*cfg_idx) >= 0 && (*dat_idx) >= 0) + return APR_SUCCESS; + else + return APR_EBADF; +} + +//в//////////////////////////////////////////////////////////////////////////////// + +void parse_recall(recall_xml_t* recall_xml, QString parentTag, QDomElement& recall_e, char* id) +{ + recall_t recall; + + /*QString ied; + ied.append(recall_e.attribute("MonitorID")); + QByteArray byteArray = ied.toLocal8Bit(); + char* charArray = new char[byteArray.size()]; + memcpy(charArray, byteArray.data(), byteArray.size()); + charArray[byteArray.size()] = '\0';*/ + + recall.line_id = id; + + QDateTime start_dt = QDateTime::fromString(recall_e.attribute("StartTime"), "yyyy-MM-dd hh:mm:ss"); + recall.start_time = start_dt.toMSecsSinceEpoch() / 1000; + QDateTime end_dt = QDateTime::fromString(recall_e.attribute("EndTime"), "yyyy-MM-dd hh:mm:ss"); + recall.end_time = end_dt.toMSecsSinceEpoch() / 1000; + + recall.need_steady = recall_e.attribute("STEADY").toInt(); + recall.need_voltage = recall_e.attribute("VOLTAGE").toInt(); + + qDebug() << parentTag << "-> " << " " << recall.line_id << " " << recall.need_steady << " " << recall.need_voltage + << " " << recall.start_time << " " << recall.end_time; + + if (parentTag == "Work") { + recall_xml->work_recalls[recall_xml->work_recall_num++] = recall; + } + else if (parentTag == "New") { + recall_xml->new_recalls[recall_xml->new_recall_num++] = recall; + } +} + +int delete_recall_xml(char* id) +{ + // ied_t *ied; + // ied_usr_t *ied_usr; + // LD_info_t line_info; + // int dev_idx_in_line = 0; + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall"); + QString file_name = QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + QString(id) + QString("_") + QString("*") + QString("_Recall.xml"); + + //ָļ + QDir dir(cfg_dir); + if (!dir.exists()) { + qDebug() << "folder does not exist!"; + return false; + } + //ָļ׺ָ + //qDebug() << qstrRecallPath; + QStringList filter(file_name); + //ָͺ򣬰µ޸ʱȡ + QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time); + for (int i = 0; i < files.size(); i++) {//նȡļ + QString qstrRecallPath = cfg_dir + QString("/") + files[i]; + QFile::remove(qstrRecallPath); + } + return APR_SUCCESS; +} + +int parse_recall_xml(recall_xml_t* recall_xml, char* id) +{ + // ied_t *ied; + // ied_usr_t *ied_usr; + // LD_info_t line_info; + // int dev_idx_in_line = 0; + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall"); + QString file_name = QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + QString(id) + QString("_") + QString("*") + QString("_Recall.xml"); + //lnk20241225ļ + //ָļ + QDir dir(cfg_dir); + if (!dir.exists()) { + qDebug() << "folder does not exist!"; + return false; + } + //ָļ׺ָ + //qDebug() << qstrRecallPath; + QStringList filter(file_name); + //ָͺ򣬰µ޸ʱȡ + QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time); + for (int i = 0; i < files.size(); i++) { + QString qstrRecallPath = cfg_dir + QString("/") + files[i]; + qDebug() << qstrRecallPath; + + QDomDocument doc; //½QDomDocumentһXMLĵ + QFile file(qstrRecallPath); + if (!file.open(QIODevice::ReadOnly)) + { + qDebug() << "file.open error"; + continue; //ֻʽ + } + bool ret = doc.setContent(&file); + file.close(); + if (!ret) + { + qDebug() << "doc.setContent error"; + continue; + } + //ļݶdoc + QDomElement docElem = doc.documentElement(); //ظԪ + QDomNode n = docElem.firstChild(); //ظڵĵһӽڵ + while (!n.isNull()) { //ڵ㲻Ϊ + if (n.isElement()) { //ڵԪ + QDomElement e = n.toElement(); //תΪԪ + QString strTag = e.tagName(); + if (strTag == "Work" || strTag == "New") { + QDomNodeList list = e.childNodes(); //Ԫeӽڵб + for (int i = 0; i < list.count(); i++) { //б + QDomNode node = list.at(i); + if (node.isElement()) { + QDomElement recall_e = node.toElement(); + QString strTag2 = recall_e.tagName(); + if (strTag2 == "Recall") { + parse_recall(recall_xml, strTag, recall_e, id); + } //else if ( strTag == "Trigger" ) + } + } + } + } + n = n.nextSibling(); //һֵܽڵ + } + } + + //for (int i = 0; i < files.size(); i++) {//նȡļ + // QString qstrRecallPath = cfg_dir + QString("/") + files[i]; + // QFile::remove(qstrRecallPath); + //} + return APR_SUCCESS; +} + +void process_recall_config(recall_xml_t* recall_xml) +{ + int i, j; + recall_t* recall; + recall_t* recall_work; + int recall_num; + int need_write_file; + QList recallinfo_list_hour; //ж-СʱΪ + + need_write_file = FALSE; + recall = recall_xml->new_recalls; + recall_num = recall_xml->new_recall_num; + for (i = 0; i < recall_num; i++) { + recall_xml->work_recalls[recall_xml->work_recall_num++] = recall[i]; + need_write_file = TRUE; + } + + recall = recall_xml->work_recalls; + recall_num = recall_xml->work_recall_num; + + if (recall_num > 0) { + LD_info_t* LD_info = find_LD_info_only_from_mp_id(recall[0].line_id); + printf("\n recall[0].line_id == %s \n", recall[0].line_id); + printf("\n recall[0].start_time == %d \n", recall[0].start_time); + if (LD_info == NULL || LD_info->read_flag == 0) { + printf("\n recall[0].line_id == NULL \n"); + printf("\n Find LD_info == null \n"); + } + else { + printf("\n Find LD_info != null \n"); + if (LD_info->autorecallflag != 0 || LD_info->autorecallcount == 0) { + if (LD_info->autorecallcount != 0) { + for (int j = 0; j < LD_info->autorecallcount; j++) { + delete LD_info->autorecall[j]; + } + delete LD_info->autorecall; + LD_info->autorecallcount = 0; + } + LD_info->autorecallcount = recall_num; + LD_info->autorecall = new autorecall_t * [recall_num]; + for (int j = 0; j < recall_num; j++) { + printf("\n %d ===== %d\n", recall[j].start_time, recall[j].end_time); + LD_info->autorecall[j] = new autorecall_t[1]; + LD_info->autorecall[j]->start = recall[j].start_time; + + LD_info->autorecall[j]->end = recall[j].end_time; + + //lnk20241030䲹̬̬־ÿļкܶʱ¼ + LD_info->autorecall[j]->need_steady = recall[j].need_steady; + LD_info->autorecall[j]->need_steady = recall[j].need_voltage; + + } + LD_info->autorecallflag = 0; + + + } + } + } + +} + +int remove_recall_xml() +{ + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/"); + QString filename(cfg_dir + RECALL_CONFIG_FN); + + return QFile::remove(filename); +} +////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////WW 20230819 ݿӺ +int OTLConnect() //OTLOracleݿ +{ + try { + otl_connect::otl_initialize(); //ʼOTLӿĻľ̬ + //db.rlogon(g_strOTLConnect.c_str()); //ݿOracle(û/) + //db.rlogon("postgres", "dnzl@#001", "pgsql", 0); + //db.rlogon("postgres", "1234567", "pgsql", 0); + //db.rlogon("postgres", "bmdev@123", "pgsql", 0); + db.rlogon(POSTGRES_USERNAME, POSTGRES_PASSWORD, POSTGRES_DNSNAME, 0); + printf("\nPostgreSL\"%s\"connect succ\n", g_strOTLConnect.c_str()); + } + catch (otl_exception& e) + { + //printf("\nPostgreSL\"%s\"failed,ERROR code= %d, msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + if (e.code != 32031) + printf("\nPostgreSL\"%s\"failed,ERROR code= %d, msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + return 0; +} +int OTLDisconnect() //OTLϿOracleݿ +{ + try { + db.logoff(); + printf("\nPostgreSL\"%s\"disconnect\n\n", g_strOTLConnect.c_str()); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"disconnect failed,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + return 0; +} +int OTLTestSelect() //OTLOracleݿ +{ + try { + OTLConnect(); + //int rtState = OTLState(); + otl_stream i(1, // buffer size + "select \"MODEL_ID\" from \"gaussdb\".\"MEAS_PQ_ICD_MODEL_TR\"", + //SELECT statement + db //connect object + ); + //create select stream + + char f2[64]; + while (!i.eof()) { //while not end-of-data + i >> f2; + qDebug() << " MODEL_ID =" << f2 << endl; + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + return 0; + +} + +int OTLState() //OTLOracleݿ״̬ +{ + try { + otl_datetime tm; + std::string strSql = "select sysdate from dual"; + //std::string strSql = "select * from pgsql_test_gy"; + + otl_stream i(1, strSql.c_str(), db); + if (!i.eof()) { + i >> tm; + QString qstrYear = QString("%1").arg(tm.year, 4, 10, QLatin1Char('0')); + QString qstrMonth = QString("%1").arg(tm.month, 2, 10, QLatin1Char('0')); + int iYear = qstrYear.toInt(); + int iMonth = qstrMonth.toInt(); + QString qCurrentYear = QDateTime::currentDateTime().toString("yyyy"); + QString qCurrentMonth = QDateTime::currentDateTime().toString("MM"); + if (!qstrYear.isEmpty() && !qstrMonth.isEmpty()) { + if ((iYear >= 1970) || (iMonth >= 1)) + return 0; + else { + printf("qstrYear= %siYear= %dqCurrentYear= %sqstrMonth= %siMonth= %dqCurrentMonth= %sȣݿOTLӣ\n", qstrYear.toAscii().data(), iYear, qCurrentYear.toAscii().data(), qstrMonth.toAscii().data(), iMonth, qCurrentMonth.toAscii().data()); + return -1; + } + } + else { + printf("SqlѯϵͳqstrYear= %sqstrMonth= %sΪգݿOTLӣ\n", qstrYear.toAscii().data(), qstrMonth.toAscii().data()); + return -1; + } + + printf(">>>SqlѯϵͳqstrYear= %sqCurrentYear= %sqstrMonth= %sqCurrentMonth= %s \n", qstrYear.toAscii().data(), qCurrentYear.toAscii().data(), qstrMonth.toAscii().data(), qCurrentMonth.toAscii().data()); + } + } + catch (otl_exception& e) + { + printf("SqlѯϵͳʱʧܣERROR code= %d, msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + return 0; +} + +int OTLDbconnected() { + cout << "db.connect is :" << db.connected << endl; + return db.connected; +} +////////////////////////////////////////////////////////////////////////////////ݿⲿ +int write_to_db(const char* sqlstm) //дݿ +{ + try { + apr_sleep(apr_time_from_sec(1) / 1000); + otl_stream i(1, sqlstm, db); + i.flush(); + i.close(); + db.commit(); + + printf(">>>ǰдݿSql= %s\n", sqlstm); + } + catch (otl_exception& e) + { + if (e.code != 1) + { + printf("дݿʧܣcode= %dmsg= %sSql= %s\n", e.code, e.msg, sqlstm); + OTLConnect(); + } + return e.code; + } + return 0; +} + +void WebSocketThread::run() +{ + //if (g_node_id != THREE_SECS_DATA_BASE_NODE_ID) + // return; + + printf("WebSocketThread::run() is called ...... \n"); + struct sockaddr_in client_sockaddr; + memset(&client_sockaddr, 0, sizeof(client_sockaddr)); + socklen_t address_len = 0; + while (1) { + address_len = sizeof(struct sockaddr_in); + int client_socket = accept(server_socket, (struct sockaddr*)&client_sockaddr, &address_len); + if (client_socket == -1) + { + printf("accept client %s:%d failed,error msg=%s\n\a", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), strerror(errno)); + continue; + } + printf("\naccept client %s:%d succesaddress_len= %dclient_socket= %d\n", inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port), address_len, client_socket); + + char buffer[256]; + int iRet = 0; + while (1) { + memset(buffer, 0, sizeof(buffer)); + int recvLength = recv(client_socket, buffer, sizeof(buffer), 0); + if (recvLength > 0) + { + iRet = HandleReceiveMessage(client_socket, buffer); + + //if (0 != iRet) + // iRet = SendMessageToWeb(client_socket, iRet); + break; + } + else + { + if (errno == EINTR) + continue; + printf("end socket client %d(%s:%d) msg,disconnetc Socket client\n", client_socket, inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port)); + break; + } + } + + close(client_socket); + printf("close socket client %d(%s:%d) \n", client_socket, inet_ntoa(client_sockaddr.sin_addr), htons(client_sockaddr.sin_port)); + msleep(1); + } + + close(server_socket); + return; +} + +string MatchErrorMessage(int errorCode) //ݴƥϢ +{ + string strErrorMessage = ""; + switch (errorCode) + { + case 0: + strErrorMessage = "success"; //"ɹ" + break; + default: + strErrorMessage = "error"; //""; + break; + //case 10002: + // strErrorMessage = "Incorrect message length structure"; //"ijȽṹ"; + // break; + //case 10003: + // strErrorMessage = "JSON string parsing error"; //"JSONַ"; + // break; + //case 10004: + // strErrorMessage = "Socket handling error"; //"socket쳣"; + // break; + //case 10005: + // strErrorMessage = "The device corresponding to ID was not found"; //"IDӦװδҵ"; + // break; + //case 10006: + // strErrorMessage = "The monitoring point corresponding to ID has not been found"; //"IDӦļδҵ"; + // break; + //case 10007: + // strErrorMessage = "Wrong parameter passed in"; //"IJ쳣"; + // break; + //case 10008: + // strErrorMessage = "The same type of operation is being performed"; //"ͬһ͵IJִ"; + // break; + //case 10009: + // strErrorMessage = "The device turned off the corresponding function"; //"װùر˶Ӧ"; + // break; + //case 10010: + // strErrorMessage = "The TYPE parameter passed in is exceptional"; //"TYPE쳣"; + // break; + //default: + // strErrorMessage = "An unknown error"; //"δ֪"; + // break; + } + + return strErrorMessage; +} + +int SendMessageToWeb(int socketClient, int iErrorCode) //Web Socketͻ˷Ϣ +{ + string strSendJson = ""; + char cTemp[8]; + string strErrorCode = ""; + sprintf(cTemp, "%06d", iErrorCode); + strErrorCode = cTemp; + char sendBuffer[256]; + int sendLength = 0; + + string strErrorMessage = MatchErrorMessage(iErrorCode); + //if (2 == Log_Enable) + // printf("룺%dƥ䵽Ϣ%s\n", iErrorCode, strErrorMessage.c_str()); + + strSendJson = "{\"errors\":\"" + strErrorMessage + "\",\"status\":\"" + strErrorCode + "\"}"; + strcpy(sendBuffer, strSendJson.c_str()); + sendLength = send(socketClient, strSendJson.c_str(), strSendJson.length() + 1, 0); + if (-1 == sendLength) + { + printf("ͻ%d[%d]Ϣ󣬴Ϣ%s\n", socketClient, iErrorCode, strSendJson.c_str()); + return -1; + } + + //if (1 == Log_Enable) + // printf("ͻ%d[%d]Ϣ%s\n", socketClient, iErrorCode, sendBuffer); + + return sendLength; +} + +int ExecuteWebCommand(LD_info_t* LD_info, int iType) //ִWeb SocketϢ +{ + try + { + //if (1 == Log_Enable) + // printf(">>>·%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); + + if (0 == iType || 1 == iType) + { + LD_info->count = 0; + if (0 == iType) + { + LD_info->real_data = 1; + LD_info->soe_data = 1; + //if (1 == Log_Enable) + // printf(">>>%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); + } + else + { + //LD_info->heart_beat = 1; + //if (1 == Log_Enable) + // printf(">>>%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); + } + } + + if (2 == iType) + { + LD_info->real_data = 0; + LD_info->soe_data = 0; + //if (1 == Log_Enable) + // printf(">>>ֹͣ%d\"%s\"iType= %dreal_data= %ssoe_data= %slimit= %dcount= %d\n", LD_info->line_id, LD_info->name, + // iType, 0 == LD_info->real_data ? "False" : "True", 0 == LD_info->soe_data ? "False" : "True", 20, LD_info->count); + } + } + catch (exception& e) + { + printf("/ֹͣ·%d\"%s\"ʧܣԭ%s\n", LD_info->line_id, LD_info->name, e.what()); + return 10004; + } + + return 10000; +} + +void Get_Recall_Time_Char(char* start_time, char* end_time, QList& recallinfo_list_hour) //Բж +{ + + QDateTime start_dt = QDateTime::fromString(start_time, "yyyy-MM-dd HH:mm:ss"); + QDateTime end_dt = QDateTime::fromString(end_time, "yyyy-MM-dd HH:mm:ss"); + + long long starttime = start_dt.toMSecsSinceEpoch() / 1000; //ʼʱ + long long endtime = end_dt.toMSecsSinceEpoch() / 1000; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + //QList recallinfo_list_hour; //ж-СʱΪ + + + RecallInfo info; + info.starttime = starttime; + info.endtime = endtime; + recallinfo_list.append(info); + + for (int i = 0; i < recallinfo_list.size(); i++) + { + //printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime); + long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime; + long long max_interval = 3600; + for (long long j = 0; j <= duration; j += max_interval) + { + if (j + max_interval > duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start; + info.endtime = end; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start; + info.endtime = end - 1; + recallinfo_list_hour.append(info); + } + } + } + +} + +int HandleReceiveMessage(int socketClient, char buffer[256]) //ղWeb Socketͻ˷Ϣ +{ + int iErrorCode = 000000; + + try + { + QString qstrBuffer = QString(QLatin1String(buffer)); + printf("ffeͻ%dϢqstrBur= %s\n", socketClient, qstrBuffer.toAscii().data()); + cJSON* json_root = cJSON_Parse(qstrBuffer.toUtf8().constData()); //jsonʽл + if (json_root == NULL) { + return 10000; + } + QString qstrCode = NULL;//¼ָ + cJSON* json_code = NULL; + cJSON* json_param = NULL; + cJSON* json_program_param = NULL; + cJSON* json_recall_param = NULL; + cJSON* json_wave_param = NULL; + cJSON* json_update_time = NULL; + cJSON* json_node = NULL; + + QString update_time; + QList wave_param; + ProgramParam program_param; + + json_code = cJSON_GetObjectItem(json_root, "code"); //ȡcode + if (json_code != NULL) { + qstrCode = json_code->valuestring; + } + else { + return 10000; + } + json_param = cJSON_GetObjectItem(json_root, "param"); //ȡparam + if (json_param == NULL) { + return 10000; + } + if (qstrCode == "dev_update" || qstrCode == "model_update" || qstrCode == "program_update") { + //豸¼¼ʱ + json_update_time = cJSON_GetObjectItem(json_param, "update_time"); //ȡupdate_time + if (json_update_time != NULL) { + update_time = json_update_time->valuestring; + } + } + else if (qstrCode == "manual_wave") { + //ֶ¼δ + json_wave_param = cJSON_GetObjectItem(json_param, "wave_param"); //ȡwave_param + int array_size = cJSON_GetArraySize(json_wave_param); //ȡС + int i; + + for (i = 0; i < array_size; i++) + { + json_node = cJSON_GetArrayItem(json_wave_param, i);//array + if (json_node != NULL) { + wave_param.append(json_node->valuestring); + } + } + + } + else if (qstrCode == "model_update") { + //նбͳļ + json_program_param = cJSON_GetObjectItem(json_param, "program_param"); //ȡprogram_param + cJSON* json_temp = NULL; + json_temp = cJSON_GetObjectItem(json_program_param, "terminal_list"); //ȡ + int array_size = cJSON_GetArraySize(json_temp); //ȡС + int i; + + for (i = 0; i < array_size; i++) + { + json_node = cJSON_GetArrayItem(json_temp, i);//array + if (json_node != NULL) { + program_param.terminal_list.append(json_node->valuestring); + } + } + json_node = cJSON_GetObjectItem(json_program_param, "file_name"); //ȡfile_name + if (json_node != NULL) { + program_param.file_name = json_node->valuestring; + } + } + else if (qstrCode == "manual_recall") {//ֶеָ + //в + json_recall_param = cJSON_GetObjectItem(json_param, "recall_param"); //ȡrecall_param + cJSON* json_temp = NULL; + int array_size = cJSON_GetArraySize(json_recall_param); //ȡС + int i; + QList recallinfo_list_hour; + char start_time[64]; + char end_time[64]; + QString mp_id; + for (i = 0; i < array_size; i++) + { + json_temp = cJSON_GetArrayItem(json_recall_param, i);//array + if (json_temp != NULL) { + json_node = cJSON_GetObjectItem(json_temp, "mp_id"); //ȡmp_id + if (json_node != NULL) { + mp_id = QString::fromUtf8(json_node->valuestring); + } + if (i == 0) { + json_node = cJSON_GetObjectItem(json_temp, "start"); //ȡstart + if (json_node != NULL) { + apr_snprintf(start_time, sizeof(start_time), "%s", json_node->valuestring);//start_time + } + json_node = cJSON_GetObjectItem(json_temp, "end"); //ȡend + if (json_node != NULL) { + apr_snprintf(end_time, sizeof(end_time), "%s", json_node->valuestring);//end_time + } + Get_Recall_Time_Char(start_time, end_time, recallinfo_list_hour); + } + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = mp_id; + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10);//Ĭ϶11ʮת + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + } + cJSON_Delete(json_root); + SendMessageToWeb(socketClient, 000000);//Ӧweb + } + catch (exception& e) + { + printf("ͻˣ%d͵Ϣԭ%s\n", socketClient, e.what()); + return 10004; + } + return 000000; +} +//// жʱǷ񳬹ʮ +//bool IsTimeDifferenceGreaterThanTenMinutes(apr_time_t time1, apr_time_t time2) { +// // ʱ +// apr_int64_t timeDiff = apr_time_diff(time1, time2); +// +// // תΪ +// apr_int64_t minutes = apr_time_sec(timeDiff) / 60; +// +// // жʱǷʮ +// return (minutes > 10); +//} +void Get_Recall_Time(char* time, QList& recallinfo_list_hour); + +void Cout_account_information() { + ied_t* ied = NULL; + int iedno; + LD_info_t* LD_info = NULL; + + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + if (ied) { + LD_info_t* LD_info = NULL; + ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); + int cpuno; + QString text;//װpgsql + text.append(QString("terminal_code: \"%1\" ,ip:\"%2\" ,port:\"%3\" ,cpucount:\"%4\" ").arg(ied_usr->terminal_code).arg(ied->channel[0].addr_str).arg(ied->channel[0].port).arg(ied->cpucount)); + add_comm_log(const_cast(text.toLocal8Bit().constData())); + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + QString text2;//װpgsql + text2.append(QString("mp_id: \"%1\" terminal_code:\"%2\" ").arg(LD_info->mp_id).arg(LD_info->terminal_code)); + add_comm_log(const_cast(text2.toLocal8Bit().constData())); + } + } + } +} + +//ʱתqstring +QString timestampToYYYYMMDD(long long timestamp) { + // long longʱתΪQDateTime + QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(timestamp * 1000); + + // ȡڲ֣ʽΪYYYYMMDD + // ʽQDateTimeΪQStringȷСʱ + QString formattedDateTime = dateTime.toString("yyyyMMddHH"); + + return formattedDateTime; +} + +bool containsDash(const char* str, size_t len) { + for (size_t i = 0; i < len; ++i) { + if (str[i] == '-') { + return true; // ҵ'-'ַtrue + } + } + return false; // ûҵ'-'ַfalse +} + +bool CheckPG_To_Recall(long long start, long long end, char* Monitorid) +{ + QDateTime deltime_Qtime = QDateTime::fromTime_t(start); + QDateTime deltime_Qtime_end = QDateTime::fromTime_t(end); + QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); //ǰ + QString start_chr1 = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); //ǰ + QString end_chr1 = deltime_Qtime_end.toString("yyyy-MM-dd hh:mm:ss"); //ǰ + + int timespan = 3;//Ĭʱ + + try { + int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + //printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "select \"exp_num\",\"act_num\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(tmp_chr1.toAscii().data()); + str1.append("' AND \"monitor_id\" = '"); + str1.append(Monitorid); + str1.append("'"); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + double exp_num; + double act_num; + while (!i.eof()) { //while not end-of-data + i >> exp_num >> act_num; + timespan = 1440 / exp_num; + printf("\n %f %f %d \n", exp_num, act_num, timespan); + } + //OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + + try { + long long starttime = start; //ʼʱ + long long endtime = starttime + 3599; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + QList recallinfo_list_hour; //ж-СʱΪ + + int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + /*OTLConnect();*/ + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(tmp_chr1.toAscii().data()); + str1.append("' AND \"monitor_id\" = '"); + str1.append(Monitorid); + str1.append("' ORDER BY timestamp_value"); + + std::string str4 = "select b1.timestamp_value from ("; + str4.append(str1); + str4.append(") b1 where b1.timestamp_value >= '"); + str4.append(start_chr1.toAscii().data()); + str4.append("' and b1.timestamp_value <= '"); + str4.append(end_chr1.toAscii().data()); + str4.append("'"); + otl_stream i(1, // buffer size + str4.c_str(), + //SELECT statement + db //connect object + ); + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> timestamp; + + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t timestamp = std::mktime(&timeinfo); + long long stamp = static_cast(timestamp); + timestamp_list.append(stamp); + } + //OTLDisconnect(); + + if (timestamp_list.size() <= (60 / timespan) * 0.97) //ݱ + { + printf("\n return ture %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97); + return true; + } + else + { + printf("\n return false %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97); + return false; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + printf("\n>>>error quit!!\n"); + return true; +} + +//2024-10-21 lnkʱ滻webӿ +#if 0 +void OnTimerThread::run() +{ + msleep(10000); + printf("OnTimerThread::run() is called ...... \n"); + static int delectflag = 1;//ʱ־ + bool account_update = true; + bool asd = true; + + apr_time_t previousTime = apr_time_now();// + apr_time_exp_t localTime; + apr_time_exp_gmt(&localTime, previousTime); + cout << "Local Time: " + << localTime.tm_year + 1900 << "-" << localTime.tm_mon + 1 << "-" << localTime.tm_mday << " " + << localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec + << endl; + + QMap dic_task_block; + + // QMapӼֵ + dic_task_block.insert("account", false); + dic_task_block.insert("recruit ", false); + dic_task_block.insert("log", false); + dic_task_block.insert("multi_node", false); + + int ip_count = 0; + int telnet_count = 0; + // Ҽֵ + if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) { + init_ping_telnet(ip_count, telnet_count); + Cout_account_information(); + } + + if (g_onlyIP[0] != 0) + { + printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP); + add_comm_log(const_cast("g_onlyIP[0]=!0,g_onlyIP is --%s--", g_onlyIP)); + } + else { + printf("g_onlyIP[0] == 0!"); + + } + + int pgflag = 0; + int pgmin = 0; + int mp_num_hour = 0; + int recall_flag1 = 1; + + //char recalllllll[256] = "0923000982"; + //CheckPG_To_Recall(1705168800, 1705168800 + 3599, recalllllll); + while (1) + { + /*cout << "ip_count:" << ip_count << " telnet_count:" << telnet_count << endl; + msleep(1000);*/ + + //߳ʱ + previousTime = apr_time_now(); + apr_time_exp_gmt(&localTime, previousTime); + //apr_time_t elapsedTime = currentTime - previousTime; + //apr_time_as_msec(elapsedTime); + //cout << "front num:" << FRONT_MP_NUM << endl; + if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//̨˸,ڵ,ͨѶ + //ȡϴ̨˸ʱ + + //жϼִ + if (false) { + //ִ̨; + + } + //¼ʱ + // + //жִдʱǷ 񱻶 + if (MULTIPLE_NODE_FLAG && pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + QString updateFrontSql;//װpgsql + updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("set \"mp_num\"= %1,front_version='%2' ").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2;").arg(FRONT_IP).arg(FRONT_INST)); + + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); // + + } + pgflag = 0; + } + else if (MULTIPLE_NODE_FLAG && pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + if (mp_num_hour != localTime.tm_hour) { + std::string mp_num_str = ""; + mp_num_str.append("connected device count:"); + mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString()); + mp_num_str.append(",g_node clients:"); + mp_num_str.append(QString::number(g_node->n_clients).toStdString()); + + add_comm_log(const_cast(mp_num_str.c_str())); + mp_num_hour = localTime.tm_hour; + } + + + //2023-10-17 zw obs osssqlݿ¼ɾ + if (delectflag == 1 && localTime.tm_hour == 16) + { + delectflag = 0; + //time_t timestamp = apr_time_as_time_t(previousTime); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + if (FILE_FLAG == 1) // oss ļɾ + { + //PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/9D3AAA2BDCE430BA7E3E1302F132B880.xml"); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + + long long deltime = stamp - (60 * 60 * 24 * 30);//ȥ30 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd"); + QString Oss_Del_Path = NULL; + Oss_Del_Path.append("comtrade/"); + Oss_Del_Path.append(LD_info->mp_id).append("/"); + Oss_Del_Path.append(tmp_chr1).append("/"); + //cout << Oss_Del_Path.toAscii().data() << endl; + DelOSS(Oss_Del_Path.toAscii().data()); + cpuno++; + } + i++; + } + //PutOSS("comtrade/not def/20231111/temp.log","/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml"); + //PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml"); + //PutOSS("comtrade/not def/20231111/temp3.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml"); + //DelOSS("comtrade/not def/20231111/temp3.log"); + } + else if (FILE_FLAG == 2)//Ϊ obs ļɾ + { + //OBSFile("/FeProject/dat/67BC249C13B5EC819CF4DF0307DB71C5.xml", "comtrade/not def/20231111/temp3.log", "putObject"); + //OBSFile_del("comtrade/not def/20231111/temp3.log", "deleteObject"); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + + long long deltime = stamp - (60 * 60 * 24 * 30);//ȥ30 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd"); + QString Oss_Del_Path = NULL; + Oss_Del_Path.append("comtrade/"); + Oss_Del_Path.append(LD_info->mp_id).append("/"); + Oss_Del_Path.append(tmp_chr1).append("/"); + //cout << Oss_Del_Path.toAscii().data() << endl; + OBSFile_del(Oss_Del_Path.toAscii().data(), "deleteObject"); + cpuno++; + } + i++; + } + + + } + + //pgsqlɾ¼ + long long deltime = stamp - (60 * 60 * 24 * 30);//ȥ30 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); + QString pgsql0; + pgsql0.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_status_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql1; + pgsql1.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_error_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql2; + pgsql2.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_rationality_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql3; + pgsql3.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_intact_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql4; + pgsql4.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_match_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + + Sql_data_list_mutex.lock(); // + Sql_data_list.append(pgsql0); + Sql_data_list.append(pgsql1); + Sql_data_list.append(pgsql2); + Sql_data_list.append(pgsql3); + Sql_data_list.append(pgsql4); + Sql_data_list_mutex.unlock(); // + } + if (delectflag == 0 && localTime.tm_hour != 16) + { + delectflag = 1; + } + //2023-10-17 zw obs osssqlݿ¼ɾ end + + } + if (strcmp(subdir, "cfg_newhis_data") == 0) {//Ϻʱװ־ + static int hour_time = 0; + if (localTime.tm_hour != hour_time) { + hour_time = localTime.tm_hour; + + printf(">>>cfg_newhis_data is run!!!\n"); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + long long start = stamp - (stamp % 3600) - 3600 - 3600;//ʼʱ ǰֵǰСʱ + long long end = start + 3599;//ʱ + + QList recallinfo_list_hour; + RecallInfo info; + info.starttime = start - 10; + info.endtime = end; + recallinfo_list_hour.append(info); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + + i++; + } + } + } + if (strcmp(subdir, "cfg_recallall_data") == 0) + { + static int recall_xml_time = 0; + if (localTime.tm_min != recall_xml_time) + { + recall_xml_time = localTime.tm_min; + //пʼֹʱ + static long long recall_start_time = 0; + static long long recall_end_time = 0; + static int flag = 0; + if (recall_start_time == 0 && recall_end_time == 0) {//޻ + //ѯһ -1״̬()ļ¼ + char front_ip[42]; + cout << "start select:" << endl; + + QString selectFrontSql; + selectFrontSql.append(QString("select \"front_ip\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where front_inst=%1 and \"front_status\" = '-1' LIMIT 1;").arg(g_front_seg_index)); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + otl_stream i(1, // buffer size + selectFrontSql.toStdString().c_str(), + db //connect object + ); + //create select stream + while (!i.eof()) { //while not end-of-data + i >> front_ip; + break; + //cout << "count=" << f2 << endl; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + continue; + } + if (containsDash(front_ip, 21)) { + //¼¼ + QString insertFrontSql; + insertFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + insertFrontSql.append(QString("values('%1',10000,%2,'03','-1','%3',200) ").arg(front_ip).arg(g_front_seg_index).arg(PROGRAM_VERSION)); + insertFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + insertFrontSql.append(QString("\"front_status\"= '%1'").arg("-2")); + cout << insertFrontSql.toStdString().c_str() << endl; + Sql_data_list_mutex.lock(); // + Sql_data_list.append(insertFrontSql); + Sql_data_list_mutex.unlock(); // + // + cout << "front_ip=" << front_ip << endl; + QString startDate, endDate; + // ַָ + startDate = QString::fromAscii(front_ip).left(10); // ȡǰ10ַΪʼ + qDebug() << "startDate=" << startDate << endl; + endDate = QString::fromAscii(front_ip + 11).left(10); // ӵ10ַʼȡ8ַΪ + qDebug() << "endDate=" << endDate << endl; + + QDateTime start_dt = QDateTime::fromString(startDate, "yyyyMMddHH"); + qDebug() << "start_dt=" << start_dt << endl; + recall_start_time = start_dt.toMSecsSinceEpoch() / 1000; + qDebug() << "recall_start_time=" << recall_start_time << endl; + QDateTime end_dt = QDateTime::fromString(endDate, "yyyyMMddHH"); + qDebug() << "end_dt=" << end_dt << endl; + recall_end_time = end_dt.toMSecsSinceEpoch() / 1000; + qDebug() << "recall_end_time=" << recall_end_time << endl; + } + flag = 0; + + } + else if (recall_start_time != 0 && recall_end_time != 0) {//л + // ʱתΪYYYYMMDDʽ + QString date1 = timestampToYYYYMMDD(recall_start_time); + QString date2 = timestampToYYYYMMDD(recall_end_time); + // ƴڣ'-'ָ + QString dateRange = date1 + "-" + date2; + qDebug() << "dateRange=" << dateRange << endl; + char front_status[4]; + QString selectFrontSql; + selectFrontSql.append(QString("select front_status from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where front_inst=%1 and \"front_ip\" = '%2'").arg(g_front_seg_index).arg(dateRange)); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + otl_stream i(1, // buffer size + selectFrontSql.toStdString().c_str(), + db //connect object + ); + //create select stream + while (!i.eof()) { //while not end-of-data + i >> front_status; + break; + //cout << "count=" << f2 << endl; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + continue; + } + qDebug() << "front_status=" << front_status << endl; + //ٴжǷΪִ״̬ + if (strcmp(front_status, "-1") == 0) { + //״̬Ϊ-1 ²¼¼ + QString updateFrontSql; + updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("values('%1',10000,%2,'03','-1','%3',200) ").arg(dateRange).arg(g_front_seg_index).arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + updateFrontSql.append(QString("\"front_status\"= '%1'").arg("-2")); + cout << updateFrontSql.toStdString().c_str() << endl; + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); // + flag = 0; + } + else if (strcmp(front_status, "-2") == 0) + {//״̬Ϊ-2 + + flag = 1; + } + else { + flag = 0; + recall_end_time = 0; + recall_start_time = 0; + } + + } + + if (recall_start_time != 0 && recall_end_time != 0 && flag == 1) + { + qDebug() << "start recall time=" << recall_start_time << endl; + qDebug() << "end recall time=" << recall_end_time << endl; + + long long starttime = recall_start_time; //ʼʱ + long long endtime = recall_end_time; //нʱ + + flag = 0; + recall_start_time = 0; + recall_end_time = 0; + + QList recallinfo_list; //ж + QList recallinfo_list_hour; //ж-СʱΪ + + + RecallInfo info; + info.starttime = starttime; + info.endtime = endtime; + recallinfo_list.append(info); + + for (int i = 0; i < recallinfo_list.size(); i++) + { + //printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime); + long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime; + long long max_interval = 3600; + for (long long j = 0; j <= duration; j += max_interval) + { + if (j + max_interval > duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start; + info.endtime = end; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start; + info.endtime = end - 1; + recallinfo_list_hour.append(info); + } + } + } + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + printf("/home/pq mpid=%s %d\n", LD_info->mp_id, LD_info->read_flag); + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) { + continue; + } + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + g_StatisticLackList_list_mutex.lock(); + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + +//滻webӿ 2024-10-21 lnk + // if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + // printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + + continue; + } + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList.push_back(jr); + + } + g_StatisticLackList_list_mutex.unlock(); + } + } + + i++; + } + } + } + + } + if (strcmp(subdir, "cfg_his_data") == 0) + { + if (pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + QString updateFrontSql; + updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("values('his',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION)); + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); // + + } + pgflag = 0; + } + else if (pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + static int cfg_his_data_hour_time = 0; + if (localTime.tm_hour != cfg_his_data_hour_time) { + cfg_his_data_hour_time = localTime.tm_hour; + + printf(">>>cfg_his_data is run!!!\n"); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + long long start = stamp - (stamp % 3600) - 3600 - 3600;//ʼʱ ǰֵǰСʱ + long long end = start + 3599;//ʱ + + QList recallinfo_list_hour; + RecallInfo info; + info.starttime = start - 10; + info.endtime = end; + recallinfo_list_hour.append(info); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + +//滻webӿ 2024-10-21 lnk + //if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + //printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + + continue; + } + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + + i++; + } + } + + } + if (strcmp(subdir, "cfg_recallhis_data") == 0) + { + if (pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + QString updateFrontSql; + updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("values('recallhis',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION)); + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); // + + } + pgflag = 0; + } + else if (pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + } + + //g_node_id == HIS_DATA_BASE_NODE_ID && + //printf("/home/pq hour=%d\n", localTime.tm_hour); + if (0 && g_node_id == HIS_DATA_BASE_NODE_ID && (localTime.tm_hour <= 12 || localTime.tm_hour >= 20) && recall_flag1 == 1) { + recall_flag1 = 0; + QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir) + QSettings settings(MyKafkaIniFilename, QSettings::IniFormat); + + QString dateString = settings.value("Recall/select_day").toString(); + + QList recallinfo_list_hour; + QByteArray byteArray = dateString.toUtf8(); // ʹ UTF-8 + char* charArray = byteArray.data(); + Get_Recall_Time(charArray, recallinfo_list_hour); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info->logcount <= 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + if (recallinfo_list_hour.size() != 0) { + if (LD_info->autorecallcount != 0) { + for (int j = 0; j < LD_info->autorecallcount; j++) { + delete LD_info->autorecall[j]; + } + delete LD_info->autorecall; + LD_info->autorecallcount = 0; + } + LD_info->autorecallflag = 0; + LD_info->autorecallcount = recallinfo_list_hour.size(); + LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()]; + printf("/home/pq recall mpid=%s\n", LD_info->mp_id); + + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime); + LD_info->autorecall[j] = new autorecall_t[1]; + LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime; + + LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime; + } + } + + + cpuno++; + } + i++; + } + + QDate date = QDate::fromString(dateString, "yyyy-MM-dd"); + + date.addDays(-1); // һ + settings.setValue("Recall/select_day", date.toString("yyyy-MM-dd")); // дַ + + + } + if (localTime.tm_hour > 12 && localTime.tm_hour < 20 && recall_flag1 == 0) { + recall_flag1 = 1; + } + + msleep(1000); + } + + printf(">>>OnTimerThread::run() is end!!!\n"); +} +#endif + +//ʹõĴlnk20241206 +#if 0 +/////////////////////////////////////////CZY 2023-09-04 + +/// +/// ƴjson +/// +/// +/// +/// +/// +/// +/// +/// Ƿɾѡֵ +void AppendCJson(cJSON* json_roots, cJSON* json_root, cJSON* json_params, cJSON* json_filters, int perpage, int page, int flag) { + //[] + //cJSON_AddItemToArray(json_roots, json_root); + //һ + cJSON_AddItemToObject(json_root, "distribution", cJSON_CreateString("1")); + cJSON_AddItemToObject(json_root, "id", cJSON_CreateString("")); + cJSON_AddItemToObject(json_root, "modelId", cJSON_CreateString("")); + cJSON_AddItemToObject(json_root, "params", json_params); + cJSON_AddItemToObject(json_root, "psrType", cJSON_CreateString("0751002")); + //params + cJSON_AddItemToObject(json_params, "current", cJSON_CreateNumber(1)); + cJSON_AddItemToObject(json_params, "fields", cJSON_CreateString("astId")); + cJSON_AddItemToObject(json_params, "filters", json_filters); + cJSON_AddItemToObject(json_params, "orderBy", cJSON_CreateString("astId desc")); + cJSON_AddItemToObject(json_params, "page", cJSON_CreateNumber(page)); + cJSON_AddItemToObject(json_params, "perpage", cJSON_CreateNumber(perpage)); + cJSON_AddItemToObject(json_params, "size", cJSON_CreateNumber(1)); + //filters + cJSON* json_filter = cJSON_CreateObject(); + cJSON_AddItemToArray(json_filters, json_filter); + //filter + cJSON_AddItemToObject(json_filter, "compare", cJSON_CreateString("=")); + cJSON_AddItemToObject(json_filter, "fieldName", cJSON_CreateString("deployState")); + cJSON_AddItemToObject(json_filter, "fieldValue", cJSON_CreateString("20")); + + if (g_onlyIP[0] != 0) {// + + //filters + cJSON* json_filter_ip = cJSON_CreateObject(); + cJSON_AddItemToArray(json_filters, json_filter_ip); + //json_filter_ip + cJSON_AddItemToObject(json_filter_ip, "compare", cJSON_CreateString("=")); + cJSON_AddItemToObject(json_filter_ip, "fieldName", cJSON_CreateString("ipAddress")); + cJSON_AddItemToObject(json_filter_ip, "fieldValue", cJSON_CreateString(g_onlyIP)); + } + + if (flag == 1) + { + //filters + cJSON* json_filter_city = cJSON_CreateObject(); + cJSON_AddItemToArray(json_filters, json_filter_city); + //json_filter_city + cJSON_AddItemToObject(json_filter_city, "compare", cJSON_CreateString("=")); + cJSON_AddItemToObject(json_filter_city, "fieldName", cJSON_CreateString("city")); + cJSON_AddItemToObject(json_filter_city, "fieldValue", cJSON_CreateString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFSP09")); + } + else if (flag == 2) { + //json_filter_city + cJSON* json_filter_city = cJSON_CreateObject(); + cJSON_AddItemToArray(json_filters, json_filter_city); + //json_filter_city + cJSON_AddItemToObject(json_filter_city, "compare", cJSON_CreateString("!=")); + cJSON_AddItemToObject(json_filter_city, "fieldName", cJSON_CreateString("city")); + cJSON_AddItemToObject(json_filter_city, "fieldValue", cJSON_CreateString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFSP09")); + } +} + +void GetCJson(const char* ptr) { + //cout << ">>>GetDevice in reply" << (char*)ptr; + strDevCJson = ""; + cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json_node; + if (json == NULL) { + printf("cJSON pares error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || json_node->valuestring == NULL || json_node->valuestring == "/0" || json_node->valuestring == "" || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error %s\n", cJSON_GetErrorPtr()); + } + else { + cout << ">>>create strDevCJson success"; + strDevCJson = QString::fromUtf8((char*)ptr); + } + } + cJSON_Delete(json); +} + +////////////////////////////////// + +////////////////////////////////////////////WW 2023-08-19 end +////////////////////////////////////////// +//WW 2023-08-26 webap ȻȡtokenȻtokenAPI +//http://172.40.237.145:30010/psr-auth/oauth/accessToken +//ȨϢ +//client_id : 2a78ecf0074111ed806c7a5cabbedfb4 +// client_secret : 58nOklQlP0SGEuXbrd0wgcVO7HX7IODAgvzHiCm + mAgWSadcX0we2wffjyTUYGsK +// grant_type : credentials +//getpostӦ +size_t req_reply(void* ptr, size_t size, size_t nmemb, void* stream) +{ + //ע͵ԴӡcookieϢ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + return size * nmemb; +} +//getpostӦ +void req_reply_token(const char* ptr) +{ + //ע͵ԴӡcookieϢ + printf(">>>GetToken in reply %s\n", ptr); + + cJSON* msg = cJSON_Parse(ptr); + if (msg == NULL) + { + printf("cJSON pares error %s\n", cJSON_GetErrorPtr()); + } + else + { + cJSON* json_status = cJSON_GetObjectItem(msg, "status"); + cJSON* json_error = cJSON_GetObjectItem(msg, "error"); + if (json_error == NULL) + { + cJSON* json_result = cJSON_GetObjectItem(msg, "result"); + cJSON* json_accesstoken = cJSON_GetObjectItem(msg, "access_token"); + + strToken = QString::fromAscii(json_accesstoken->valuestring); + } + cJSON_Delete(msg); + } +} + +void GetToken(const string strUrl, const string strclientid, const string strclientsecret)//ȡToken +{ + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + + if (curl) + { + // set params + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/x-www-form-urlencoded;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + //curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + printf("token_url2: %s\n", strUrl.c_str()); + + //postIJ + + char* pszEncodeAuth = curl_easy_escape(curl, strclientid.c_str(), strclientid.length()); + char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + string strTempBody; + strTempBody.append("client_id="); + strTempBody.append(pszEncodeAuth); + strTempBody.append("&"); + strTempBody.append("client_secret="); + strTempBody.append(pszEncodeSecret); + + strTempBody.append("&grant_type="); + strTempBody.append(GRANT_TYPE); + + printf(">>>TestTokenPost in curl %s \n", strTempBody.c_str()); + curl_free(pszEncodeAuth); + curl_free(pszEncodeSecret); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strTempBody.c_str()); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + //curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)strBody.toAscii().data()); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>Token Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + cout << "token curl_easy_perform() failed res code: " << res << endl; + } + else { + cout << ">>>token curl post success res code:" << res << endl; + req_reply_token(resPost0.c_str()); + } + curl_slist_free_all(header_list); + + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} +void GetDevice(const QString strUrl, const QString strxToken, int perpage, int page, int flag) +{ + + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //QDateTime askTime = QDateTime::currentDateTime(); + //long lTim = askTime.toMSecsSinceEpoch(); + //printf(">>>TestDevicePost in curl %ld\n", lTim); + //QString xTime; + + //xTime.append(QString("x-date:%l").arg(lTim)); + printf(">>>token %s \n", strxToken.toAscii().data()); + // set params + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + header_list = curl_slist_append(header_list, strxToken.toAscii().data()); + //header_list = curl_slist_append(header_list, xTime.toAscii().data()); + //header_list = curl_slist_append(header_list, "x-signature:1234"); + + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.toAscii().data()); + //postIJ + cJSON* json_roots = cJSON_CreateArray(); + cJSON* json_root = cJSON_CreateObject(); + cJSON* json_params = cJSON_CreateObject(); + cJSON* json_filters = cJSON_CreateArray(); + + AppendCJson(json_roots, json_root, json_params, json_filters, perpage, page, flag); + + char* szjson = cJSON_Print(json_root); + printf(">>>json %s\n", szjson); + //string strjson = szjson; + //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>Device Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + cout << "device curl_easy_perform() failed res code: " << res << endl; + } + else { + cout << ">>>dev curl post success res code:" << res << endl; + GetCJson(resPost0.c_str()); + } + + + free(szjson); + curl_slist_free_all(header_list); + cJSON_Delete(json_roots); + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} + +void TestToken()//ȡԴҵ̨ظ +{ + string client_id = "2a78ecf0074111ed806c7a5cabbedfb4";//client_id= + string client_secret = "58nOklQlP0SGEuXbrd0wgcVO7HX7IODAgvzHiCm+mAgWSadcX0we2wffjyTUYGsK";//client_secret= + string token_url = "http://172.40.237.145:30010/psr-auth/oauth/accessToken"; + QString device_url = QString("http://172.40.237.145:30010/assetCenter/astQueryServices/listDeviceByFilters"); + + GetToken(token_url, client_id, client_secret);//ȡtoken + QString xtoken = QString("x-token:") + strToken; + GetDevice(device_url, xtoken, 1, 1, 0);//ȡ̨ +} + +void GetWebApiJson(int perpage, int page, int flag)//ȡԴҵ̨ظ +{ + //string client_id = "2a78ecf0074111ed806c7a5cabbedfb4";//client_id= + //string client_secret = "58nOklQlP0SGEuXbrd0wgcVO7HX7IODAgvzHiCm+mAgWSadcX0we2wffjyTUYGsK";//client_secret= + //string token_url = "http://172.40.237.145:30010/psr-auth/oauth/accessToken"; + //QString device_url = QString("http://172.40.237.145:30010/assetCenter/astQueryServices/listDeviceByFilters"); + + string client_id = CLIENT_ID;//client_id= + string client_secret = CLIENT_SECRET;//client_secret= + string token_url = TOKEN_URL; + QString device_url = QString(DEVICE_URL); + /*cout << "client_id1: " << client_id << ",client_secret1: " << client_secret<<",token_url1: "<< token_url.c_str()<>>>>cJSON pares 1 %s \n", strJson.c_str()); + cJSON* msg = cJSON_Parse(strJson.c_str()); + if (msg == NULL) + { + printf("cJSON pares error %s\n", cJSON_GetErrorPtr()); + } + else + { + printf(">>>>>cJSON pares 3"); + cJSON* json_status = cJSON_GetObjectItem(msg, "status"); + cJSON* json_error = cJSON_GetObjectItem(msg, "error"); + if (json_error == NULL) + { + printf(">>>>>cJSON pares 4"); + cJSON* json_result = cJSON_GetObjectItem(msg, "result"); + cJSON* json_accesstoken = cJSON_GetObjectItem(msg, "access_token"); + + printf(">>>>>cJSON pares 5"); + QString strToken1 = QString::fromAscii(json_accesstoken->valuestring); + cJSON_Delete(msg); + printf(">>>>>cJSON pares 6 %s\n ", strToken1.toAscii().data()); + } + } + +} +#endif +#if 0//WW 2023-08-29Դs +//getpostӦ +size_t req_reply_test(void* ptr, size_t size, size_t nmemb, void* stream) +{ + //ע͵ԴӡcookieϢ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + return size * nmemb; +} +//http POST +CURLcode curl_post_req(const string& url, const string& postParams, string& response) +{ + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + printf(">>>TestSMSPost in curl \n"); + // set params + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json; charset=UTF-8"); + header_list = curl_slist_append(header_list, "Authorization:Basic bmpjbnRlc3Q6bmpjbnBxcw=="); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + //postIJ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str()); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&response); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6); + + printf(">>>TestSMSPost in curl post\n"); + // post + res = curl_easy_perform(curl); + curl_slist_free_all(header_list); + } + //ͷcurl + curl_easy_cleanup(curl); + printf(">>>TestSMSPost in curl end\n"); + return res; +} +void TestSMSPost()//WW qt post +{ + printf(">>>TestSMSPost Start \n"); + + string url_post0 = "http://192.168.1.13:10214/oauth/token"; + string paramsLogin0 = "grant_type=sms_code&phone=13914774158&smsCode=123456"; + string resPost0; + CURLcode res3 = curl_post_req(url_post0, paramsLogin0, resPost0); + + printf(">>>TestSMSPost End %s\n", resPost0.c_str()); +} + +CURLcode curl_post_body_req(const string& url, string& response) +{ + + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + printf(">>>TestBodyPost in curl \n"); + // set params + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + + //һ + cJSON_AddItemToObject(json_root, "sname", cJSON_CreateString("hongawen")); + cJSON_AddItemToObject(json_root, "value", cJSON_CreateNumber(12.5)); + char* szjson = cJSON_Print(json_root); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1); + + printf(">>>TestBodyPost in curl post\n"); + // post + res = curl_easy_perform(curl); + + free(szjson); + cJSON_Delete(json_root); + curl_slist_free_all(header_list); + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} + +void TestBodyPost()//WW qt post +{ + printf(">>>TestBodyPost Start \n"); + + string url_post0 = "http://192.168.1.111:8090/enhance/testBody"; + string resPost0; + CURLcode res3 = curl_post_body_req(url_post0, resPost0); + + printf(">>>TestBodyPost End %s\n", resPost0.c_str()); +} +#endif +//WW 2023-08-26 webap end +////////////////////////////////////////// +///////zw޸ 2023-8-30 xmlģݿȡ +int OTL_Select_xmlModel() //xmlģݿȡ +{ + try { + OTLConnect(); + //printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "select \"model_id\",\"tmnl_type\",\"tmnl_factory\",\"file_name\",\"update_time\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_icd_model_tr\" "); + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + char MODEL_ID[64]; + char TMNL_TYPE[64]; + char TMNL_FACTORY[64]; + char FILE_NAME[128]; + otl_datetime UPDATE_TIME; + //printf("\nPostgreSL 2\n"); + //create select stream + while (!i.eof()) { //while not end-of-data + //printf("\nPostgreSL 3\n"); + i >> MODEL_ID >> TMNL_TYPE >> TMNL_FACTORY >> FILE_NAME >> UPDATE_TIME; + //QString tempdate = QString("%1-%2-%3 %4:%5:%6").arg(UPDATE_TIME.year, 4, 10, QLatin1Char('0')).arg(UPDATE_TIME.month, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.day, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.hour, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.minute, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.second, 2, 10, QLatin1Char('0')); + //QDateTime dt = QDateTime::fromString(tempdate, "yyyy-MM-dd hh:mm:ss"); + Set_xml_databaseinfo(MODEL_ID, TMNL_TYPE, TMNL_FACTORY, FILE_NAME, UPDATE_TIME.year, UPDATE_TIME.month, UPDATE_TIME.day, UPDATE_TIME.hour, UPDATE_TIME.minute, UPDATE_TIME.second); + //cout << "FRONT_IP=" << f2 << endl; + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + return 0; + +} + +int OTL_Select_DecideRecall(char* time, char* id)//жǷҪ +{ + int flag = 1; + try { + int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + //printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "select \"exp_num\",\"act_num\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(time); + str1.append("' AND \"monitor_id\" = '"); + str1.append(id); + str1.append("'"); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + double exp_num; + double act_num; + while (!i.eof()) { //while not end-of-data + i >> exp_num >> act_num; + if (exp_num * 0.8 <= act_num) { + flag = 0; + } + //printf("\n %f %f %f \n", exp_num, act_num, exp_num * 0.8); + } + //OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + flag = 0; + } + return flag; +} + +void OTL_Select_recall(char* time, char* id) //Բж +{ + try { + QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd"); + long long starttime = dt.toMSecsSinceEpoch() / 1000; //ʼʱ + long long endtime = starttime + 86399; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + QList recallinfo_list_hour; //ж-СʱΪ + + int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + /*OTLConnect();*/ + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(time); + str1.append("' AND \"monitor_id\" = '"); + str1.append(id); + str1.append("' ORDER BY timestamp_value"); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> timestamp; + + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t timestamp = std::mktime(&timeinfo); + long long stamp = static_cast(timestamp); + timestamp_list.append(stamp); + + /*QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd"); + long long timestamp2 = dt.toMSecsSinceEpoch() / 1000; + printf("\n %lld \n", timestamp2);*/ + /*QString tempdate = QString("%1-%2-%3 %4:%5:%6").arg(UPDATE_TIME.year, 4, 10, QLatin1Char('0')).arg(UPDATE_TIME.month, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.day, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.hour, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.minute, 2, 10, QLatin1Char('0')).arg(UPDATE_TIME.second, 2, 10, QLatin1Char('0')); + printf("\n %s \n", tempdate.toAscii().data());*/ + //QDateTime dt = QDateTime::fromString(tempdate, "yyyy-MM-dd hh:mm:ss"); + } + //OTLDisconnect(); + + if (timestamp_list.size() == 0) //ݱ + { + RecallInfo info; + info.starttime = starttime; + info.endtime = endtime; + recallinfo_list.append(info); + } + else if (timestamp_list.size() == 1)//1 + { + long long temptime = timestamp_list[0]; + if (temptime != starttime && temptime != endtime) + { + RecallInfo info1; + info1.starttime = starttime; + info1.endtime = temptime - 1; + + RecallInfo info2; + info2.starttime = temptime + 1; + info2.endtime = endtime; + + recallinfo_list.append(info1); + recallinfo_list.append(info2); + } + else + { + RecallInfo info; + info.starttime = starttime + 1; + info.endtime = endtime - 1; + recallinfo_list.append(info); + } + } + else //ڶ + { + for (int i = 1; i < timestamp_list.size(); i++) + { + if (i == 1) + { + timestamp_list[0];//ͷ + timestamp_list[timestamp_list.size() - 1];//β + + if (timestamp_list[0] - starttime > 600) + { + RecallInfo info; + info.starttime = starttime + 1; + info.endtime = timestamp_list[0] - 1; + recallinfo_list.append(info); + } + if (endtime - timestamp_list[timestamp_list.size() - 1] > 600) + { + RecallInfo info; + info.starttime = timestamp_list[timestamp_list.size() - 1] + 1; + info.endtime = endtime - 1; + recallinfo_list.append(info); + } + } + + long long temptime1 = timestamp_list[i - 1]; + long long temptime2 = timestamp_list[i]; + if (temptime2 - temptime1 > 600) + { + RecallInfo info; + info.starttime = temptime1 + 1; + info.endtime = temptime2 - 1; + recallinfo_list.append(info); + } + } + } + + for (int i = 0; i < recallinfo_list.size(); i++) + { + //printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime); + long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime; + long long max_interval = 3600; + for (long long j = 0; j <= duration; j += max_interval) + { + if (j + max_interval > duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start - 10; + info.endtime = end - 10; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start - 10; + info.endtime = end - 10; + recallinfo_list_hour.append(info); + } + } + } + + LD_info_t* LD_info = find_LD_info_only_from_mp_id(id); + if (LD_info == NULL || LD_info->read_flag == 0) { + printf("\n Find LD_info == null \n"); + } + else { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + //if (recallinfo_list_hour.size() != 0) { + // if (LD_info->autorecallcount != 0) { + // for (int j = 0; j < LD_info->autorecallcount; j++) { + // delete LD_info->autorecall[j]; + // } + // delete LD_info->autorecall; + // LD_info->autorecallcount = 0; + // } + // LD_info->autorecallflag = 0; + // LD_info->autorecallcount = recallinfo_list_hour.size(); + // LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()]; + // for (int j = 0; j < recallinfo_list_hour.size(); j++) { + // //printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime); + // LD_info->autorecall[j] = new autorecall_t[1]; + // LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime; + + // LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime; + // } + //} + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + } +} + +//CZY +void Get_Recall_Time(char* time, QList& recallinfo_list_hour) //Բж +{ + + QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd"); + // QDateTime תΪַ + QString dateTimeString = dt.toString("yyyy-MM-dd"); + + printf("\nQDateTime dt is\"%s\" \n", dateTimeString.toStdString().c_str()); + long long starttime = dt.toMSecsSinceEpoch() / 1000; //ʼʱ + long long endtime = starttime + 86399; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + //QList recallinfo_list_hour; //ж-СʱΪ + + + RecallInfo info; + info.starttime = starttime; + info.endtime = endtime; + recallinfo_list.append(info); + + for (int i = 0; i < recallinfo_list.size(); i++) + { + //printf("\n %lld ----- %11d\n", recallinfo_list[i].starttime, recallinfo_list[i].endtime); + long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime; + long long max_interval = 3600; + for (long long j = 0; j <= duration; j += max_interval) + { + if (j + max_interval > duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start; + info.endtime = end; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start; + info.endtime = end; + recallinfo_list_hour.append(info); + } + } + } + +} + +char* getoneday(int num) +{ + apr_time_t previousTime = apr_time_now(); + long long stamp = static_cast(previousTime) / 1000000; + long long deltime = stamp - (60 * 60 * 24 * num);//ȥ1 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); + QByteArray byteArray = tmp_chr1.toLocal8Bit(); + char* charArray = new char[byteArray.size()]; + memcpy(charArray, byteArray.data(), byteArray.size()); + charArray[byteArray.size()] = '\0'; + return charArray; +} +void deletechar(char* day) +{ + delete[] day; +} + +/// +/// ɾڵxml +/// +void DeletcRecallXml() { + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall"); + QString file_name = QString(subdir) + QString("_") + QString("*") + QString("_Recall.xml"); + + //ָļ + QDir dir(cfg_dir); + if (!dir.exists()) { + qDebug() << "folder does not exist!"; + return; + } + QStringList filter(file_name); + //ָͺ򣬰µ޸ʱȡ + QStringList files = dir.entryList(filter, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::Name | QDir::Time); + + // 趨˵ںʱ + QDateTime saveDaysAgo = QDateTime::currentDateTime().addDays(-2); + + for (int i = 0; i < files.size(); i++) {//նȡļ + QFileInfo fileInfo(dir.filePath(files[i])); + if (fileInfo.lastModified() < saveDaysAgo) { + QFile::remove(fileInfo.absoluteFilePath()); + + } + } + +} + +void CreateRecallXml() +{ + apr_time_t previousTime = apr_time_now(); + long long stamp = static_cast(previousTime) / 1000000; + QDateTime deltime_Qtime = QDateTime::fromTime_t(stamp); + + /*CJournalRecall jr; + jr.MonitorID = QString::number(1100, 10); + jr.StartTime = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + for (int i = 0;i < 10;i++) { + g_StatisticLackList.push_back(jr); + }*/ + + g_StatisticLackList_list_mutex.lock(); + if (g_StatisticLackList.size() > 0) + { + printf("insert ID_CJournalRecall_Map\n"); + QMap > ID_CJournalRecall_Map; + + list::iterator sl = g_StatisticLackList.begin(); + while (sl != g_StatisticLackList.end()) + { + CJournalRecall jr = *sl++; + if (ID_CJournalRecall_Map.contains(jr.MonitorID)) + { + ID_CJournalRecall_Map[jr.MonitorID].append(jr); + } + else + { + QList TempList; + TempList.append(jr); + ID_CJournalRecall_Map.insert(jr.MonitorID, TempList); + } + } + + for (QMap >::iterator it2 = ID_CJournalRecall_Map.begin(); it2 != ID_CJournalRecall_Map.end(); ++it2) + { + QString key2 = it2.key(); + QList value2 = it2.value(); + + QString cfg_dir = QString("../")/*+QString::fromAscii(subdir)*/ + QString("etc/recall/"); + QString qstrRecallPath = cfg_dir + QString(subdir) + QString("_") + QString(QString::number(g_front_seg_index, 10)) + QString("_") + key2 + QString("_") + QString(deltime_Qtime.toString("yyyyMMddhhmmss")) + QString("_Recall.xml"); + + std::string strRecallPath = qstrRecallPath.toStdString(); + QFile file(strRecallPath.c_str()); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + printf("вѯ,%sʧ,޷д·ã\n", qstrRecallPath.toAscii().data()); + QMap >().swap(ID_CJournalRecall_Map); + return; + } + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + writer.writeStartElement("RecallList"); + writer.writeStartElement("Work"); + writer.writeEndElement(); + + writer.writeStartElement("New"); + + while (!value2.isEmpty()) + { + CJournalRecall jr = value2.takeFirst(); + writer.writeStartElement("Recall"); + writer.writeAttribute("MonitorID", jr.MonitorID); + writer.writeAttribute("StartTime", jr.StartTime); + writer.writeAttribute("EndTime", jr.EndTime); + writer.writeAttribute("STEADY", jr.STEADY); + writer.writeAttribute("VOLTAGE", jr.VOLTAGE); + writer.writeEndElement(); + } + writer.writeEndElement(); + writer.writeEndElement(); + writer.writeEndDocument(); + file.close(); + } + + QMap >().swap(ID_CJournalRecall_Map); + } + g_StatisticLackList.clear(); + g_StatisticLackList_list_mutex.unlock(); +} +///////zw޸ 2023-8-30 end + +/*/////////////////////////////////////////////////////////lnk2024-10-11ƳsqlIJԴ/////////////////////////////////////////////////////////////*/ +std::string intToString(int number) { + if (number == 0) return "0"; + std::string str; + bool isNegative = number < 0; + if (isNegative) number = -number; + + while (number > 0) { + str.insert(str.begin(), '0' + (number % 10)); + number /= 10; + } + + if (isNegative) str.insert(str.begin(), '-'); + return str; +} + +otl_datetime parseTimestamp(const std::string timestampStr) { + otl_datetime timestamp; + + // ꡢ¡աʱ֡ + int year, month, day, hour, minute, second; + + // ʹַн + std::istringstream ss(timestampStr); + char discard; // ڶָ + + // ַ + ss >> year >> discard >> month >> discard >> day >> hour >> discard >> minute >> discard >> second; + + // ֵ otl_datetime + timestamp.year = year; + timestamp.month = month; + timestamp.day = day; + timestamp.hour = hour; + timestamp.minute = minute; + timestamp.second = second; + + return timestamp; +} + +size_t req_reply_web(void* ptr, size_t size, size_t nmemb, void* stream) +{ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + return size * nmemb; +} + +void SendWebAPI_web(const string strUrl, const char* code, char** ptr) +{ + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + char url[100]; + sprintf(url, "%s?%s", strUrl.c_str(), code); + printf(">>>json %s\n", url); + // URL + curl_easy_setopt(curl, CURLOPT_URL, url); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); + + //ݽ + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + //header + curl_slist* headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + // post + res = curl_easy_perform(curl); + + // Ƿɹ + if (res != CURLE_OK) { + printf("web failed res code: "); + } + else { + printf(">>> web return str:%s \n", resPost0.c_str()); + + *ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 㹻ڴռ + if (*ptr != NULL) { + strcpy(*ptr, resPost0.c_str()); + } + else { + printf("Memory allocation failed!\n"); + } + } + } + else + { + printf(">>> web curl init failed"); + } + curl_easy_cleanup(curl); +} + +//20241206ʹõĴlnk +#if 0 +//նʶԿwebӿ +int parse_device_web_test_ext(QMap* terminal_ext_map,const std::vector& codes) +{ + std::cout << "parse_device_web_test_ext" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "info"){ + code = std::string("code1=pg_ext&code2=read&code3=info"); + } + + char* terminal_code=NULL; + char* terminal_identify_code=NULL; + char* terminal_key=NULL; + + char* ptr=NULL; + + terminal_ext* ext; + + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (terminal_code != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_code); + } + terminal_code = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_code, json_value->valuestring); + std::cout << "terminal_code:" << terminal_code <type == cJSON_String) { + if (terminal_identify_code != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_identify_code); + } + terminal_identify_code = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_identify_code, json_value->valuestring); + std::cout << "terminal_identify_code:" << terminal_identify_code <type == cJSON_String) { + if (terminal_key != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_key); + } + terminal_key = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_key, json_value->valuestring); + std::cout << "terminal_key:" << terminal_key <contains(terminal_code)) { + ext = new terminal_ext(); + terminal_ext_map->insert(terminal_code, ext); + apr_snprintf(ext->terminal_identify_code, sizeof(ext->terminal_identify_code), "%s", terminal_identify_code);//terminal_code + apr_snprintf(ext->terminal_key, sizeof(ext->terminal_key), "%s", terminal_key);//terminal_code + } + else + { + qDebug() << terminal_code << endl; + } + } + } + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } +} +//ģwebӿ +int parse_model_web_test(QMap* icd_model_map,const std::vector& codes) +{ + std::cout << "parse_model_web_test" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "info"){ + code = std::string("code1=model&code2=read&code3=info"); + } + + char* model_id=NULL; + char* tmnl_type=NULL; + char* tmnl_factory=NULL; + char* file_name=NULL; + char* timestamp=NULL; + + char* ptr=NULL; + + icd_model* model; + + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (model_id != NULL) { + // Ѿڴ棬ͷڴ + free(model_id); + } + model_id = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(model_id, json_value->valuestring); + std::cout << "model_id:" << model_id <type == cJSON_String) { + if (tmnl_type != NULL) { + // Ѿڴ棬ͷڴ + free(tmnl_type); + } + tmnl_type = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(tmnl_type, json_value->valuestring); + std::cout << "tmnl_type:" << tmnl_type <type == cJSON_String) { + if (tmnl_factory != NULL) { + // Ѿڴ棬ͷڴ + free(tmnl_factory); + } + tmnl_factory = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(tmnl_factory, json_value->valuestring); + std::cout << "tmnl_factory:" << tmnl_factory <type == cJSON_String) { + if (file_name != NULL) { + // Ѿڴ棬ͷڴ + free(file_name); + } + file_name = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(file_name, json_value->valuestring); + std::cout << "file_name:" << file_name <type == cJSON_String) { + if (timestamp != NULL) { + // Ѿڴ棬ͷڴ + free(timestamp); + } + timestamp = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(timestamp, json_value->valuestring); + std::cout << "timestamp:" << timestamp <contains(model_id)) { + model = new icd_model(); + icd_model_map->insert(model_id, model); + apr_snprintf(model->model_id, sizeof(model->model_id), "%s", model_id);//org_name + apr_snprintf(model->tmnl_type, sizeof(model->tmnl_type), "%s", tmnl_type);//maint_name + apr_snprintf(model->tmnl_factory, sizeof(model->tmnl_factory), "%s", tmnl_factory);//station_name + apr_snprintf(model->file_name, sizeof(model->file_name), "%s", file_name);//addr_str + apr_snprintf(model->timestamp, sizeof(model->timestamp), "%s", timestamp);//timestamp + } + else + { + qDebug() << model_id << endl; + } + } + } + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } +} +//̨webӿ +int parse_line_web_test(QMap* ledger_monitor_map,const std::vector& codes) +{ + std::cout << "parse_line_web_test" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "info"){ + code = std::string("code1=line&code2=read&code3=info"); + } + else if(function == "count_cfg"){ + //code = std::string("code1=line&code2=read&code3=count_cfg"); //ȡ̨˱ļ¼ + } + + char* ptr=NULL; + + char* monitor_id=NULL; + char* terminal_code=NULL; + char* monitor_name=NULL; + char* logical_device_seq=NULL; + char* voltage_level=NULL; + char* terminal_connect=NULL; + char* timestamp=NULL; + char* count=NULL; + + ledger_monitor* line; + + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + if (json != NULL) { + + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (monitor_id != NULL) { + // Ѿڴ棬ͷڴ + free(monitor_id); + } + monitor_id = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(monitor_id, json_value->valuestring); + std::cout << "monitor_id:" << monitor_id <type == cJSON_String) { + if (terminal_code != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_code); + } + terminal_code = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_code, json_value->valuestring); + std::cout << "terminal_code:" << terminal_code <type == cJSON_String) { + if (monitor_name != NULL) { + // Ѿڴ棬ͷڴ + free(monitor_name); + } + monitor_name = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(monitor_name, json_value->valuestring); + std::cout << "monitor_name:" << monitor_name <type == cJSON_String) { + if (logical_device_seq != NULL) { + // Ѿڴ棬ͷڴ + free(logical_device_seq); + } + logical_device_seq = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(logical_device_seq, json_value->valuestring); + std::cout << "logical_device_seq:" << logical_device_seq <type == cJSON_String) { + if (voltage_level != NULL) { + // Ѿڴ棬ͷڴ + free(voltage_level); + } + voltage_level = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(voltage_level, json_value->valuestring); + std::cout << "voltage_level:" << voltage_level <type == cJSON_String) { + if (terminal_connect != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_connect); + } + terminal_connect = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_connect, json_value->valuestring); + std::cout << "terminal_connect:" << terminal_connect <type == cJSON_String) { + if (timestamp != NULL) { + // Ѿڴ棬ͷڴ + free(timestamp); + } + timestamp = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(timestamp, json_value->valuestring); + std::cout << "timestamp:" << timestamp <type == cJSON_String) { + if (count != NULL) { + // Ѿڴ棬ͷڴ + free(count); + } + count = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(count, json_value->valuestring); + std::cout << "count:" << count <contains(monitor_id)) { + line = new ledger_monitor(); + + if(function == "info"){ + ledger_monitor_map->insert(monitor_id, line); + apr_snprintf(line->monitor_id, sizeof(line->monitor_id), "%s", monitor_id);//terminal_id + apr_snprintf(line->terminal_code, sizeof(line->terminal_code), "%s", terminal_code);//terminal_code + apr_snprintf(line->monitor_name, sizeof(line->monitor_name), "%s", monitor_name);//org_name + apr_snprintf(line->logical_device_seq, sizeof(line->logical_device_seq), "%s", logical_device_seq);//maint_name + apr_snprintf(line->voltage_level, sizeof(line->voltage_level), "%s", voltage_level);//station_name + apr_snprintf(line->terminal_connect, sizeof(line->terminal_connect), "%s", terminal_connect);//addr_str + apr_snprintf(line->timestamp, sizeof(line->timestamp), "%s", timestamp);//timestamp + } + else if(function == "count_cfg"){ + ledger_monitor_map->insert("count_cfg", line); + apr_snprintf(line->count_cfg, sizeof(line->count_cfg), "%s", count);//count + } + } + else + { + qDebug() << monitor_id << endl; + } + } + } + + /* ǰеն˺ɸѡ */ + /* ledger_monitor_map ɾ g_node->n_clients е terminal_code */ + QMap::iterator it; + it = ledger_monitor_map->begin(); + while (it != ledger_monitor_map->end()) { + // value һṹ壬 terminal_code + ledger_monitor* data = it.value(); // ȡ monitor_id Ӧ + std::string terminal_code_line = data->terminal_code; // ȡ terminal_code + + // ־Ƿҵƥն˺ + bool found = false; + + // g_node->n_clients terminal_code Ƿ + for (int dev_no = 0; dev_no < g_node->n_clients; dev_no++) { + ied_usr_t* user_ext = (ied_usr_t*)(g_node->clients[dev_no]->usr_ext); + std::string client_terminal_code = user_ext->terminal_code; + + // ҵƥն˺ţ found Ϊ true ֹͣѭ + if (client_terminal_code == terminal_code_line) { + + found = true; + break; + } + } + + // ûҵƥ terminal_codeɾü¼ + if (!found) { + + it = ledger_monitor_map->erase(it); // ɾǰ¼erase ᷵һ + std::cout << "Removed monitor_id: " << it.key().toStdString() << " with terminal_code: " << terminal_code << std::endl; // + } else { + ++it; // һ¼ + } + } + + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } +} +//ն̨webӿ +int parse_device_web_test_dev(QMap* terminal_dev_map,const std::vector& codes) +{ + std::cout << "parse_device_web_test_dev" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "info"){ + + /*γʼ */ + std::string front_inst = ""; + std::string mp_number = ""; + std::string cnt_cfg = ""; + std::string mult_flag = ""; + std::string front_num = ""; + + // + + front_inst = codes[1]; + mp_number = codes[2]; + cnt_cfg = codes[3]; + mult_flag = codes[4]; ///ǰ + front_num = codes[5]; + + std::cout << "param:" << front_inst << mp_number << cnt_cfg << mult_flag << front_num << std::endl; + + + code = std::string("code1=pg_dev&code2=read&code3=info") + "&code4=" + front_inst + "&code5=" + mp_number + "&code6=" + cnt_cfg + "&code7=" + mult_flag + "&code8=" + front_num; + + } + else if(function == "count_cfg"){ + + code = std::string("code1=pg_dev&code2=read&code3=count_cfg"); //ȡ̨˱ļ¼ + } + + char* ptr=NULL; + + char* terminal_id=NULL; + char* terminal_code=NULL; + char* org_name=NULL; + char* maint_name=NULL; + char* station_name=NULL; + char* addr_str=NULL; + char* port=NULL; + char* tmnl_factory=NULL; + char* dev_type=NULL; + char* tmnl_status=NULL; + char* timestamp=NULL; + char* count=NULL; + + terminal_dev* dev; + + try{ + //pg_devȡն̨ˣIJֱΪFRONT_INST ǰʵ;mp_num ǰöӦ;count_cfg ǰñȡļ;MULTIPLE_NODE_FLAG ǰñ־;g_front_seg_num ǰǰ; + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + if (json != NULL) { + + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (terminal_id != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_id); + } + terminal_id = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_id, json_value->valuestring); + std::cout << "terminal_id:" << terminal_id <type == cJSON_String) { + if (terminal_code != NULL) { + // Ѿڴ棬ͷڴ + free(terminal_code); + } + terminal_code = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(terminal_code, json_value->valuestring); + std::cout << "terminal_code:" << terminal_code <type == cJSON_String) { + if (org_name != NULL) { + // Ѿڴ棬ͷڴ + free(org_name); + } + org_name = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(org_name, json_value->valuestring); + std::cout << "org_name:" << org_name <type == cJSON_String) { + if (maint_name != NULL) { + // Ѿڴ棬ͷڴ + free(maint_name); + } + maint_name = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(maint_name, json_value->valuestring); + std::cout << "maint_name:" << maint_name <type == cJSON_String) { + if (station_name != NULL) { + // Ѿڴ棬ͷڴ + free(station_name); + } + station_name = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(station_name, json_value->valuestring); + std::cout << "station_name:" << station_name <type == cJSON_String) { + if (addr_str != NULL) { + // Ѿڴ棬ͷڴ + free(addr_str); + } + addr_str = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(addr_str, json_value->valuestring); + std::cout << "addr_str:" << addr_str <type == cJSON_String) { + if (port != NULL) { + // Ѿڴ棬ͷڴ + free(port); + } + port = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(port, json_value->valuestring); + std::cout << "port:" << port <type == cJSON_String) { + if (tmnl_factory != NULL) { + // Ѿڴ棬ͷڴ + free(tmnl_factory); + } + tmnl_factory = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(tmnl_factory, json_value->valuestring); + std::cout << "tmnl_factory:" << tmnl_factory <type == cJSON_String) { + if (dev_type != NULL) { + // Ѿڴ棬ͷڴ + free(dev_type); + } + dev_type = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(dev_type, json_value->valuestring); + std::cout << "dev_type:" << dev_type <type == cJSON_String) { + if (tmnl_status != NULL) { + // Ѿڴ棬ͷڴ + free(tmnl_status); + } + tmnl_status = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(tmnl_status, json_value->valuestring); + std::cout << "tmnl_status:" << tmnl_status <type == cJSON_String) { + if (timestamp != NULL) { + // Ѿڴ棬ͷڴ + free(timestamp); + } + timestamp = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(timestamp, json_value->valuestring); + std::cout << "timestamp:" << timestamp <type == cJSON_String) { + if (count != NULL) { + // Ѿڴ棬ͷڴ + free(count); + } + count = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(count, json_value->valuestring); + std::cout << "count:" << count <contains(terminal_code)) { + dev = new terminal_dev(); + + if(function == "info"){ + terminal_dev_map->insert(terminal_code, dev); + apr_snprintf(dev->terminal_id, sizeof(dev->terminal_id), "%s", terminal_id);//terminal_id + apr_snprintf(dev->terminal_code, sizeof(dev->terminal_code), "%s", terminal_code);//terminal_code + apr_snprintf(dev->org_name, sizeof(dev->org_name), "%s", org_name);//org_name + apr_snprintf(dev->maint_name, sizeof(dev->maint_name), "%s", maint_name);//maint_name + apr_snprintf(dev->station_name, sizeof(dev->station_name), "%s", station_name);//station_name + apr_snprintf(dev->addr_str, sizeof(dev->addr_str), "%s", addr_str);//addr_str + apr_snprintf(dev->port, sizeof(dev->port), "%s", port);//port_int + apr_snprintf(dev->tmnl_factory, sizeof(dev->tmnl_factory), "%s", tmnl_factory);//tmnl_factory + apr_snprintf(dev->dev_type, sizeof(dev->dev_type), "%s", dev_type);//dev_type + apr_snprintf(dev->tmnl_status, sizeof(dev->tmnl_status), "%s", tmnl_status);//tmnl_status + apr_snprintf(dev->timestamp, sizeof(dev->timestamp), "%s", timestamp);//timestamp + } + else if(function == "count_cfg"){ + terminal_dev_map->insert("count_cfg", dev); + apr_snprintf(dev->count_cfg, sizeof(dev->count_cfg), "%s", count);//count + } + } + else + { + qDebug() << terminal_code << endl; + } + } + } + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } +} +//ǰñwebӿ-д +int parse_device_web_test_front_write(const std::vector& codes) +{ + std::cout << "parse_device_web_test_front_write" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + char* ret=NULL; + + char* ptr=NULL; + + if(function == "insertfront"){ + + /*γʼ */ + std::string front_ip = ""; + std::string front_inst = ""; + std::string front_type = ""; + std::string program_version = ""; + std::string front_status = ""; + // + front_ip = codes[1]; + front_inst = codes[2]; + front_type = codes[3]; + program_version = codes[4]; + front_status = codes[5]; + std::cout << "insert param:" << front_ip << front_inst << front_type << program_version << front_status <3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <* front_map,const std::vector& codes) +{ + std::cout << "parse_device_web_test_front" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "info"){ + code = std::string("code1=pg_front&code2=read&code3=info"); + } + else if(function == "frontip"){ + std::string front_index = ""; + std::string front_status = ""; + front_index = codes[1]; + front_status = codes[2]; + code = std::string("code1=pg_front&code2=read&code3=frontip") + "&code4=" + front_index + "&code5=" + front_status; + } + else if(function == "frontstatus"){ + std::string front_ip = ""; + std::string front_index = ""; + front_ip = codes[1]; + front_index = codes[2]; + code = std::string("code1=pg_front&code2=read&code3=frontstatus") + "&code4=" + front_ip + "&code5=" + front_index; + } + + char* front_type=NULL; + char* mp_num=NULL; + + char* front_ip=NULL; + + char* front_status=NULL; + + char* ptr=NULL; + + //QMap front_map; + front_list* front; + + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (front_type != NULL) { + // Ѿڴ棬ͷڴ + free(front_type); + } + front_type = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(front_type, json_value->valuestring); + std::cout << "front_type:" << front_type <type == cJSON_String) { + if (mp_num != NULL) { + // Ѿڴ棬ͷڴ + free(mp_num); + } + mp_num = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(mp_num, json_value->valuestring); + std::cout << "mp_num:" << mp_num <type == cJSON_String) { + if (front_ip != NULL) { + // Ѿڴ棬ͷڴ + free(front_ip); + } + front_ip = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(front_ip, json_value->valuestring); + std::cout << "front_ip:" << front_ip <type == cJSON_String) { + if (front_status != NULL) { + // Ѿڴ棬ͷڴ + free(front_status); + } + front_status = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(front_status, json_value->valuestring); + std::cout << "front_status:" << front_status <contains("0.0.0.0")) { + front = new front_list(); + front_map->insert("0.0.0.0", front); + apr_snprintf(front->front_inst, sizeof(front->front_inst), "%s", "0");//front_inst + apr_snprintf(front->front_type, sizeof(front->front_type), "%s", front_type);//front_type + apr_snprintf(front->mp_num, sizeof(front->mp_num), "%s", mp_num);//mp_num + } + else + { + qDebug() << "0.0.0.0 : front_type = " << front_type << "mp_num = " << mp_num << endl; + } + } + else if(function == "frontip"){ + if (!front_map->contains("frontip")) { //"frontip"Ϊkey + front = new front_list(); + front_map->insert("frontip", front); + apr_snprintf(front->front_ip, sizeof(front->front_ip), "%s", front_ip);//front_type + } + else + { + qDebug() << "front_ip = " << front_ip << endl; + } + } + else if(function == "frontstatus"){ + if (!front_map->contains("frontstatus")) { //"frontstatus"Ϊkey + front = new front_list(); + front_map->insert("frontstatus", front); + apr_snprintf(front->front_status, sizeof(front->front_status), "%s", front_status);//front_type + } + else + { + qDebug() << "frontstatus = " << front_status << endl; + } + } + } + } + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } +} +//webӿ- +int parse_intact_web_test_read(QMap* intact_list_map,const std::vector& codes) +{ + std::cout << "parse_intact_web_test" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "deciderecall"){ + + /*γʼ */ + std::string time = ""; + std::string id = ""; + + // + + time = codes[1]; + id = codes[2]; + + std::cout << "param:" << time << id << std::endl; + + code = std::string("code1=intact&code2=read&code3=deciderecall") + "&code4=" + time + "&code5=" + id; + } + else if(function == "autorecall"){ + + /*γʼ */ + std::string time = ""; + std::string id = ""; + + // + + time = codes[1]; + id = codes[2]; + + std::cout << "param:" << time << id << std::endl; + + code = std::string("code1=intact&code2=read&code3=autorecall") + "&code4=" + time + "&code5=" + id; + } + else if(function == "handlerecall"){ + + /*γʼ */ + std::string tmp_time = ""; + std::string Monitorid = ""; + std::string start_time = ""; + std::string end_time = ""; + + // + tmp_time = codes[1]; + Monitorid = codes[2]; + start_time = codes[3]; + end_time = codes[4]; + + std::cout << "param:" << tmp_time << Monitorid << start_time << end_time << std::endl; + + code = std::string("code1=intact&code2=read&code3=handlerecall") + "&code4=" + tmp_time + "&code5=" + Monitorid + "&code4=" + start_time + "&code5=" + end_time; + } + + char* exp_num=NULL; + char* act_num=NULL; + + char* valuetime=NULL; + + char* ptr=NULL; + + intact_list* intact; + + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (exp_num != NULL) { + // Ѿڴ棬ͷڴ + free(exp_num); + } + exp_num = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(exp_num, json_value->valuestring); + std::cout << "exp_num:" << exp_num <type == cJSON_String) { + if (act_num != NULL) { + // Ѿڴ棬ͷڴ + free(act_num); + } + act_num = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(act_num, json_value->valuestring); + std::cout << "act_num:" << act_num <type == cJSON_String) { + if (valuetime != NULL) { + // Ѿڴ棬ͷڴ + free(valuetime); + } + valuetime = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(valuetime, json_value->valuestring); + std::cout << "valuetime:" << valuetime <contains(id)) { + intact = new intact_list(); + intact_list_map->insert(id, intact); //ʱݻѭΣidظ + if(function == "deciderecall"){ + apr_snprintf(intact->exp_num, sizeof(intact->exp_num), "%s", exp_num); + apr_snprintf(intact->act_num, sizeof(intact->act_num), "%s", act_num); + } + else if(function == "autorecall" || function == "handlerecall"){ + intact->value_time.push_back(valuetime); + } + } + else + { + intact = intact_list_map->value(id); //ҵidӦ + if(function == "deciderecall"){ + qDebug() << "exp_num = " << intact->exp_num << "act_num = " << intact->act_num << endl; + } + else if(function == "autorecall" || function == "handlerecall"){ + intact->value_time.push_back(valuetime);//¼Ӧid + } + } + } + } + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + + return APR_SUCCESS; + } + catch (const std::exception& e) { + cout << "Exception caught: " << e.what() << endl; + // 쳣߼ + } +} + +//־ݿӿ +int parse_rationality_write(const std::vector& codes) +{ + std::cout << "parse_rationality_write" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + char* ret=NULL; + + char* ptr=NULL; + + if(function == "log"){ + + /*γʼ */ + std::string id = ""; + std::string time = ""; + std::string count = ""; + std::string filename = ""; + + // + id = codes[1]; + time = codes[2]; + count = codes[3]; + filename = codes[4]; + + std::cout << "insert param:" << id << time << count << filename << std::endl; + + // + code = std::string("code1=rationality&code2=write&code3=log") + "&code4=" + id + "&code5=" + time + "&code6=" + count + "&code7=" + filename; + } + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <& codes) +{ + std::cout << "parse_dataintegrity_write" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + char* ret=NULL; + + char* ptr=NULL; + + if(function == "log"){ + + /*γʼ */ + std::string time = ""; + std::string datatime = ""; + std::string monitorId = ""; + std::string recallflag = ""; + std::string msspan = ""; + + // + time = codes[1]; + datatime = codes[2]; + monitorId = codes[3]; + recallflag = codes[4]; + msspan = codes[5]; + + std::cout << "insert param:" << time << datatime << monitorId << recallflag << msspan <3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <& codes) +{ + std::cout << "parse_match_write" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + char* ret=NULL; + + char* ptr=NULL; + + if(function == "log"){ + + /*γʼ */ + std::string id = ""; + std::string time = ""; + std::string BASE_MAT_NUM = ""; + std::string ADV_MAT_NUM = ""; + std::string BASE_ACT_NUM = ""; + std::string ADV_ACT_NUM = ""; + std::string filename = ""; + + // + id = codes[1]; + time = codes[2]; + BASE_MAT_NUM = codes[3]; + ADV_MAT_NUM = codes[4]; + BASE_ACT_NUM = codes[5]; + ADV_ACT_NUM = codes[6]; + filename = codes[7]; + + std::cout << "insert param:" << id << time << BASE_MAT_NUM<< ADV_MAT_NUM<< BASE_ACT_NUM<< ADV_ACT_NUM<3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <& codes) +{ + std::cout << "parse_commstatus_write" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + char* ret=NULL; + + char* ptr=NULL; + + if(function == "log"){ + + /*γʼ */ + std::string id = ""; + std::string currenttime = ""; + + // + id = codes[1]; + currenttime = codes[2]; + + std::cout << "insert param:" << id << currenttime <3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <& codes) +{ + std::cout << "parse_commerror_write" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + char* ret=NULL; + + char* ptr=NULL; + + if(function == "log"){ + + /*γʼ */ + std::string id = ""; + std::string time = ""; + std::string filename = ""; + + // + id = codes[1]; + time = codes[2]; + filename = codes[3]; + + std::cout << "insert param:" << id << time << filename <3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <& codes) +{ + std::cout << "parse_device_web_test_front" << std::endl; + + std::string code = ""; + + /*綨 */ + std::string function = codes[0]; + std::cout << "function:" << function << std::endl; + + if(function == "ontime"){ + /*γʼ */ + std::string time = ""; + + // + time = codes[1]; + + std::cout << "param:" << time << std::endl; + + code = std::string("code1=ontime&code2=delete&code3=deletetime") + "&code4=" + time; + } + + char* ret=NULL; + char* tablename=NULL; + + char* ptr=NULL; + + try{ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + + // + printf("ptr:%s\n",ptr); + + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node = NULL;; + cJSON* json_records = NULL;; + cJSON* json_value = NULL; + + int array_size = 0; + + int i = 0; + + if (json == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + //ط + while(json == NULL){ + SendWebAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", code.c_str(), &ptr); + json = cJSON_Parse(ptr); + i++;if(i>3)break; + } + } + else { + json_node = cJSON_GetObjectItem(json, "result"); //ȡresultڵ + + json_records = cJSON_GetObjectItem(json_node, "records"); //ȡ¼ڵ + + array_size = cJSON_GetArraySize(json_records); //ȡ¼С + + for(i = 0;itype == cJSON_String) { + if (ret != NULL) { + // Ѿڴ棬ͷڴ + free(ret); + } + ret = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(ret, json_value->valuestring); + std::cout << "ret:" << ret <type == cJSON_String) { + if (tablename != NULL) { + // Ѿڴ棬ͷڴ + free(tablename); + } + tablename = (char*)malloc(strlen(json_value->valuestring) + 1); // ڴ + strcpy(tablename, json_value->valuestring); + std::cout << "tablename:" << tablename <> exp_num >> act_num;*/ + std::vector codes;//μ + QMap intact_list_map; + codes.push_back("deciderecall"); + codes.push_back(std::string(time)); + codes.push_back(std::string(id)); + + parse_intact_web_test_read(&intact_list_map,codes); + + codes.clear(); + + try { + //char exp_num[64]; + //char act_num[64]; + double exp_num; + double act_num; + + // ն̨ + QMap::iterator it; + for (it = intact_list_map.begin(); it != intact_list_map.end(); ++it) { + intact_list* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + //strncpy(exp_num, value->exp_num.c_str(), sizeof(exp_num) - 1); + //strncpy(act_num, value->act_num.c_str(), sizeof(act_num) - 1); + + exp_num = atof(value->exp_num); + act_num = atof(value->exp_num); + + std::cout << exp_num << " " << act_num << std::endl; + + if (exp_num * 0.8 <= act_num) { + flag = 0; + } + } + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + flag = 0; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + flag = 0; + } + + return flag; +} + +void OTL_Select_recall_web(char* time, char* id) //Բж +{ + try { + QDateTime dt = QDateTime::fromString(time, "yyyy-MM-dd"); + long long starttime = dt.toMSecsSinceEpoch() / 1000; //ʼʱ + long long endtime = starttime + 86399; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + QList recallinfo_list_hour; //ж-СʱΪ + +/* int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + //OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(time); + str1.append("' AND \"monitor_id\" = '"); + str1.append(id); + str1.append("' ORDER BY timestamp_value"); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> timestamp;*/ + + std::vector codes;//μ + QMap intact_list_map; + codes.push_back("autorecall"); + codes.push_back(std::string(time)); + codes.push_back(std::string(id)); + + parse_intact_web_test_read(&intact_list_map,codes); + + codes.clear(); + + try { + otl_datetime timestamp; + + // ն̨ + if (intact_list_map.contains(id)) { + intact_list* value = intact_list_map.value(id); // ҵֵΪ "id" Ķ + + if (value != nullptr) { + // value_time ʱַ + for (std::vector::const_iterator it = value->value_time.begin(); it != value->value_time.end(); ++it) { + const std::string& time = *it; + + std::cout << "Time: " << time << std::endl; + + timestamp = parseTimestamp(time); + + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t timestamp = std::mktime(&timeinfo); + long long stamp = static_cast(timestamp); + timestamp_list.append(stamp); + + } + } + } + else { + std::cout << "No entry found for id: " << id << std::endl; + } + + +/* struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t timestamp = std::mktime(&timeinfo); + long long stamp = static_cast(timestamp); + timestamp_list.append(stamp);*/ + + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + + } + + if (timestamp_list.size() == 0) //ݱ + { + RecallInfo info; + info.starttime = starttime; + info.endtime = endtime; + recallinfo_list.append(info); + } + else if (timestamp_list.size() == 1)//1 + { + long long temptime = timestamp_list[0]; + if (temptime != starttime && temptime != endtime) + { + RecallInfo info1; + info1.starttime = starttime; + info1.endtime = temptime - 1; + + RecallInfo info2; + info2.starttime = temptime + 1; + info2.endtime = endtime; + + recallinfo_list.append(info1); + recallinfo_list.append(info2); + } + else + { + RecallInfo info; + info.starttime = starttime + 1; + info.endtime = endtime - 1; + recallinfo_list.append(info); + } + } + else //ڶ + { + for (int i = 1; i < timestamp_list.size(); i++) + { + if (i == 1) + { + timestamp_list[0];//ͷ + timestamp_list[timestamp_list.size() - 1];//β + + if (timestamp_list[0] - starttime > 600) + { + RecallInfo info; + info.starttime = starttime + 1; + info.endtime = timestamp_list[0] - 1; + recallinfo_list.append(info); + } + if (endtime - timestamp_list[timestamp_list.size() - 1] > 600) + { + RecallInfo info; + info.starttime = timestamp_list[timestamp_list.size() - 1] + 1; + info.endtime = endtime - 1; + recallinfo_list.append(info); + } + } + + long long temptime1 = timestamp_list[i - 1]; + long long temptime2 = timestamp_list[i]; + if (temptime2 - temptime1 > 600) + { + RecallInfo info; + info.starttime = temptime1 + 1; + info.endtime = temptime2 - 1; + recallinfo_list.append(info); + } + } + } + + for (int i = 0; i < recallinfo_list.size(); i++) + { + long long duration = recallinfo_list[i].endtime - recallinfo_list[i].starttime; + long long max_interval = 3600; + for (long long j = 0; j <= duration; j += max_interval) + { + if (j + max_interval > duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start - 10; + info.endtime = end - 10; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start - 10; + info.endtime = end - 10; + recallinfo_list_hour.append(info); + } + } + } + + LD_info_t* LD_info = find_LD_info_only_from_mp_id(id); + if (LD_info == NULL || LD_info->read_flag == 0) { + printf("\n Find LD_info == null \n"); + } + else { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + } +} + +bool CheckPG_To_Recall_web_test(long long start, long long end, char* Monitorid) +{ + QDateTime deltime_Qtime = QDateTime::fromTime_t(start); + QDateTime deltime_Qtime_end = QDateTime::fromTime_t(end); + QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); //ǰ + QString start_chr1 = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); //ǰ + QString end_chr1 = deltime_Qtime_end.toString("yyyy-MM-dd hh:mm:ss"); //ǰ + + int timespan = 3;//Ĭʱ + + try { + /*int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + //printf("\nPostgreSL 1 %s \n", POSTGRES_SCHEMA); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "select \"exp_num\",\"act_num\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(tmp_chr1.toAscii().data()); + str1.append("' AND \"monitor_id\" = '"); + str1.append(Monitorid); + str1.append("'"); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + double exp_num; + double act_num; + while (!i.eof()) { //while not end-of-data + i >> exp_num >> act_num;*/ + + std::vector codes;//μ + QMap intact_list_map; + + codes.push_back("deciderecall"); + codes.push_back(tmp_chr1.toStdString()); + codes.push_back(std::string(Monitorid)); + + parse_intact_web_test_read(&intact_list_map,codes); + + codes.clear(); + + try { + //char exp_num[64]; + //char act_num[64]; + double exp_num; + double act_num; + + // ն̨ + QMap::iterator it; + for (it = intact_list_map.begin(); it != intact_list_map.end(); ++it) { + intact_list* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + //strncpy(exp_num, value->exp_num.c_str(), sizeof(exp_num) - 1); + //strncpy(act_num, value->act_num.c_str(), sizeof(act_num) - 1); + + exp_num = atof(value->exp_num); + act_num = atof(value->act_num); + + std::cout << exp_num << " " << act_num << std::endl; + + timespan = 1440 / exp_num; + printf("\n %f %f %d \n", exp_num, act_num, timespan); + } + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + //OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + + try { + long long starttime = start; //ʼʱ + long long endtime = starttime + 3599; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + QList recallinfo_list_hour; //ж-СʱΪ + +/* int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0) { + int ret = OTLConnect(); + } + //OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str3 = POSTGRES_TABLEPREFIX;//schame analy + std::string str1 = "SELECT unnest(value_time) AS timestamp_value FROM \""; + str1.append(str2); + str1.append("\".\""); + str1.append(str3); + str1.append("meas_pq_measpoint_intact_tr\" "); + str1.append("WHERE \"statistical_date\" = '"); + str1.append(tmp_chr1.toAscii().data()); + str1.append("' AND \"monitor_id\" = '"); + str1.append(Monitorid); + str1.append("' ORDER BY timestamp_value"); + + std::string str4 = "select b1.timestamp_value from ("; + str4.append(str1); + str4.append(") b1 where b1.timestamp_value >= '"); + str4.append(start_chr1.toAscii().data()); + str4.append("' and b1.timestamp_value <= '"); + str4.append(end_chr1.toAscii().data()); + str4.append("'"); + otl_stream i(1, // buffer size + str4.c_str(), + //SELECT statement + db //connect object + ); + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> timestamp;*/ + + std::vector codes;//μ + QMap intact_list_map; + codes.push_back("handlerecall"); + codes.push_back(tmp_chr1.toStdString()); + codes.push_back(std::string(Monitorid)); + codes.push_back(start_chr1.toStdString()); + codes.push_back(end_chr1.toStdString()); + + parse_intact_web_test_read(&intact_list_map,codes); + + codes.clear(); + + try { + otl_datetime timestamp; + + // ն̨ + if (intact_list_map.contains(Monitorid)) { + intact_list* value = intact_list_map.value(Monitorid); // ҵֵΪ "id" Ķ + + if (value != nullptr) { + // value_time ʱַ + for (std::vector::const_iterator it = value->value_time.begin(); it != value->value_time.end(); ++it) { + const std::string& time = *it; + + std::cout << "Time: " << time << std::endl; + + timestamp = parseTimestamp(time); + + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t timestamp = std::mktime(&timeinfo); + long long stamp = static_cast(timestamp); + timestamp_list.append(stamp); + } + } + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + //OTLDisconnect(); + + if (timestamp_list.size() <= (60 / timespan) * 0.97) //ݱ + { + printf("\n return ture %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97); + return true; + } + else + { + printf("\n return false %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97); + return false; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + printf("\n>>>error quit!!\n"); + return true; +} + +//ʼwebԽӿ +int parse_device_cfg_web_test() +{ + qDebug() << "parse_device_cfg_web" << endl; + + std::vector codes; + +//ǰж + if (FRONT_INST == 0 || FRONT_IP[0] == '\0') { + MULTIPLE_NODE_FLAG = 0; + cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl; + } + + char front_type[2] = {""}; + int mp_num = 0; + +//webӿ滻ǰñĶдӿнӽӿֱȡлȡҪֵдʱֱӴΣ + if (MULTIPLE_NODE_FLAG) { +//ǰñȡ滻 + /*QString selectFrontSql; + selectFrontSql.append(QString("select \"front_type\",\"mp_num\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where \"front_ip\" = '0.0.0.0' and \"front_inst\"=0")); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + OTLConnect(); + otl_stream i2(1, // buffer size + selectFrontSql.toStdString().c_str(), + db //connect object + ); + while (!i2.eof()) { //while not end-of-data + i2 >> front_type >> mp_num; + break; + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + }*/ + QMap front_map; + codes.push_back("info"); + parse_device_web_test_front_read(&front_map,codes); + codes.clear(); + // QMap + QMap::iterator it; + for (it = front_map.begin(); it != front_map.end(); ++it) { + front_list* value = it.value(); + // ȷ value Ϊ + if (it.key() == "0.0.0.0" && value != nullptr) { + // value жȡ front_typeǰַ + strncpy(front_type, value->front_type, 2); + front_type[2] = '\0'; // ȷԿַβ + // mp_num ַתΪ + mp_num = std::atoi(value->mp_num); + } + } +//ǰñȡ +//ǰñд벿 + /*QString addFrontSql; + addFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + addFrontSql.append(QString("values('%1',10000,%2,'%3','01','%4',200) ").arg(FRONT_IP).arg(FRONT_INST).arg(front_type).arg(PROGRAM_VERSION)); + addFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + addFrontSql.append(QString("\"front_type\"= '%1',\"front_version\"='%2'").arg(front_type).arg(PROGRAM_VERSION)); + cout << addFrontSql.toStdString().c_str() << endl; + OTLConnect(); + int rt = write_to_db(addFrontSql.toStdString().c_str()); + OTLDisconnect();*/ + + codes.push_back("insertfront"); + + codes.push_back(std::string(FRONT_IP)); + codes.push_back(intToString(FRONT_INST)); + codes.push_back(std::string(front_type)); + codes.push_back(std::string(PROGRAM_VERSION)); + + codes.push_back("01"); //״ֵ̬ + + parse_device_web_test_front_write(codes); + + codes.clear(); + +//ǰñд벿 + } + + cout << "mp_num:" << mp_num << " front_type:" << front_type << endl; + + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + int count_cfg = 0; + int count_real = 0; + +//ȡնext滻Ϊwebӿ + QMap terminal_ext_map; + //read_terminal_ext_pg(&terminal_ext_map); + codes.push_back("info"); + parse_device_web_test_ext(&terminal_ext_map,codes); + codes.clear(); +//ȡնext滻Ϊwebӿ + +//ȡն̨˱滻Ϊwebӿ + /*try { + OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("meas_pq_dev_tr"); + str1.append("\" where tmnl_status='20';"); + cout << "pg sql1 is:" << str1 << endl; + otl_stream i(1, // buffer size + str1.c_str(), + db //connect object + ); + int f2; + while (!i.eof()) { //while not end-of-data + i >> f2; + } + OTLDisconnect(); + count_cfg = f2;;//ݿ + cout << "dev_count=" << count_cfg << endl; + } + catch (otl_exception& e) + { + printf("\ndev PostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + }*/ + + QMap terminal_dev_map; + + codes.push_back("count_cfg"); + + parse_device_web_test_dev(&terminal_dev_map,codes); + + // QMap + QMap::iterator it; + for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) { + terminal_dev* value = it.value(); + // ȷ value Ϊ + if (it.key() == "count_cfg" && value != nullptr) { + // count ַתΪ + count_cfg = std::atoi(value->count_cfg); + } + // + cout << "count_cfg:" << count_cfg << " value->count_cfg:" << value->count_cfg << endl; + } + + codes.clear(); + + //ȡcountcfgҪ0Ӱȡ̨߼ + terminal_dev_map.clear(); + +//ȡն̨˱滻Ϊwebӿ + +//ȡն̨˱滻Ϊwebӿ + + codes.push_back("info"); + codes.push_back(intToString(FRONT_INST)); + codes.push_back(intToString(mp_num)); + codes.push_back(intToString(count_cfg)); + codes.push_back(intToString(MULTIPLE_NODE_FLAG)); + codes.push_back(intToString(g_front_seg_num)); + + parse_device_web_test_dev(&terminal_dev_map,codes); + + codes.clear(); + + if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) { + if (mp_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * mp_num; + } + else + { + count_cfg = mp_num; + } + } + else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) { + int front_num = (count_cfg / g_front_seg_num) + 1; + if (front_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * front_num; + } + else + { + count_cfg = front_num; + } + } + g_node->n_clients = count_cfg; //ͻ + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); +/* std::string strSchame = POSTGRES_SCHEMA;//schame analy + std::string strDevSQL = "select \"terminal_id\",\"terminal_code\",\"org_name\",\"maint_name\",\"station_name\",\"tmnl_ip\",\"tmnl_port\",\"tmnl_factory\",\"tmnl_type\",\"tmnl_status\",\"update_time\" from \""; + strDevSQL.append(strSchame); + strDevSQL.append("\".\""); + strDevSQL.append(POSTGRES_TABLEPREFIX); + strDevSQL.append("meas_pq_dev_tr"); + strDevSQL.append("\" where tmnl_status='20'"); + if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) { + strDevSQL.append(" ORDER BY terminal_id OFFSET "); + strDevSQL.append(QString::number((FRONT_INST - 1) * mp_num).toStdString()); + strDevSQL.append(" LIMIT "); + strDevSQL.append(QString::number(mp_num).toStdString()); + if (mp_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * mp_num; + } + else + { + count_cfg = mp_num; + } + } + else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) { + int front_num = (count_cfg / g_front_seg_num) + 1; + strDevSQL.append(" ORDER BY terminal_code OFFSET "); + strDevSQL.append(QString::number((FRONT_INST - 1) * front_num).toStdString()); + strDevSQL.append(" LIMIT "); + strDevSQL.append(QString::number(front_num).toStdString()); + if (front_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * front_num; + } + else + { + count_cfg = front_num; + } + } + + cout << strDevSQL << endl; + + g_node->n_clients = count_cfg; + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + + + // + try { + cout << "read dev information." << endl; + OTLConnect(); + + //cout << "pg sql2 is:" << str1 << endl; + //int rtState = OTLState(); + // ִгselect + otl_stream i(1, // buffer size + strDevSQL.c_str(), + //SELECT statement + db //connect object + ); + + //create select stream + + char terminal_id[64]; + char terminal_code[64]; + char org_name[64]; + char maint_name[64]; + char station_name[64]; + char tmnl_factory[64]; + char tmnl_status[64]; + char dev_type[64]; + char dev_key[64]; + char dev_series[64]; + char addr_str[64]; + char port_char[64]; + otl_datetime timestamp; + + while (!i.eof()) { //while not end-of-data + i >> terminal_id >> terminal_code >> org_name >> maint_name >> station_name >> addr_str >> port_char >> tmnl_factory >> dev_type >> tmnl_status >> timestamp; +*/ +//ȡն̨˱滻Ϊwebӿ +////////////////////////////////////////////////////////////////////////////////////////////////// + // + try { + + char terminal_id[64]; + char terminal_code[64]; + char org_name[64]; + char maint_name[64]; + char station_name[64]; + char tmnl_factory[64]; + char tmnl_status[64]; + char dev_type[64]; + char dev_key[64]; + char dev_series[64]; + char addr_str[64]; + char port_char[64]; + //char timestamp[64]; + otl_datetime timestamp; + + // ն̨ + QMap::iterator it; + for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) { + terminal_dev* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + strncpy(terminal_id, value->terminal_id, sizeof(terminal_id) - 1); + strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1); + strncpy(org_name, value->org_name, sizeof(org_name) - 1); + strncpy(maint_name, value->maint_name, sizeof(maint_name) - 1); + strncpy(station_name, value->station_name, sizeof(station_name) - 1); + strncpy(tmnl_factory, value->tmnl_factory, sizeof(tmnl_factory) - 1); + strncpy(tmnl_status, value->tmnl_status, sizeof(tmnl_status) - 1); + strncpy(dev_type, value->dev_type, sizeof(dev_type) - 1); + //strncpy(dev_key, value->dev_key, sizeof(dev_key) - 1); + //strncpy(dev_series, value->dev_series, sizeof(dev_series) - 1); + strncpy(addr_str, value->addr_str, sizeof(addr_str) - 1); + strncpy(port_char, value->port, sizeof(port_char) - 1); + //strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1); + + timestamp = parseTimestamp(value->timestamp); + + } + +///////////////////////////////////////////////////////////////////////////////// + + ied = g_node->clients[count_real++]; + + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + + ied->usr_ext = ied_usr; + + if (ied_usr == NULL) + return APR_ENOMEM; + + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + ied->cpucount = 0; + + if (strlen(terminal_id) != 0) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id + cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl; + } + + if (terminal_code != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code + cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl; + + } + + if (org_name != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name + cout << "ied_usr->org_name:" << ied_usr->org_name << endl; + + } + + if (maint_name != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name + cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl; + + } + + if (station_name != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name + cout << "ied_usr->station_name:" << ied_usr->station_name << endl; + + } + + if (tmnl_factory != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory + cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl; + + } + + if (tmnl_status != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status + cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl; + + } + + if (dev_type != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type + cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl; + + } + + cout << "code" << ied_usr->terminal_code << endl; + + if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) { + //terminal_ext* ext = terminal_ext_map.value(ied_usr->terminal_code); + terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code)); + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else + { + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Key + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + + //QByteArray ba = QByteArray::fromBase64(devPropVal.toAscii());//DEV_Series + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + + if (addr_str != NULL) { + ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + + } + else + { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + } + + if (port_char != NULL) { + int port = 102; + if (stringToInt(port_char, &port)) { + // תɹportStrȫΪ֣ѾתΪint͵port + ied->channel[0].port = port;//DEV_PortID + cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID + } + else { + ied->channel[0].port = 102;//DEV_PortID + cout << "ied_usr->port:" << port_char << ",ǺϷ˿.ʹĬ϶˿:" << ied->channel[0].port << endl;//DEV_PortID + } + } + + if (timestamp.year != 0) { + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + ied_usr->time = static_cast(time); + cout << "ied_usr->time:" << ied_usr->time << endl; + } +//////////////////////////////// + /*// ꡢ¡աʱ֡ + int year, month, day, hour, minute, second; + // ʹַн + std::istringstream ss(timestamp); + char discard; // ڶָ + + // ַ + ss >> year >> discard >> month >> discard >> day >> hour >> discard >> minute >> discard >> second; + + std::cout << "" << year << "" << month<< "" << day<< "" << hour<< "" << minute<< "" << second<time = static_cast(time); + cout << "ied_usr->time:" << ied_usr->time << endl; + }*/ +///////////////////////////////////// + + + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + + // + std::cout << "value:" << terminal_id <<" "<n_clients = count_real; + if (count_cfg != count_real) + return APR_EBADF; + cout << "dev init create count:" << count_real; + return APR_SUCCESS; + } + catch (otl_exception& e) + { + printf("\ndev tr\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + +} + +int parse_line_cfg_web_test() +{ + ied_t* ied; + ied_usr_t* ied_usr; + int count_cfg = 0; + int count_real = 0; + LD_info_t line_info; + + std::vector codes;//μ + +// + /*try { + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select count(*) from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor"); + str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in ("); + + int dev_no = 0; + cout << "n_clients:" << g_node->n_clients << endl; + if (g_node->n_clients <= 0) { + cout << "no terminal exist " << endl; + return APR_EBADF; + } + for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) { + str1.append("'"); + str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code); + str1.append("'"); + if (dev_no < g_node->n_clients - 1) { + str1 += ","; + } + } + str1.append(")"); + cout << "pg sql1 is:" << str1 << endl; + OTLConnect(); + otl_stream i(1,str1.c_str(),db); + int f2; + while (!i.eof()) { + i >> f2; + } + OTLDisconnect(); + count_cfg = f2;;//ݿ + cout << "line_count=" << count_cfg << endl; + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + }*/ + +//ǰöӦļݼϢеն˺ŽͳƣֱӴݿȡ +// +// + QMap ledger_monitor_map; + codes.push_back("info"); + + parse_line_web_test(&ledger_monitor_map,codes); + + codes.clear(); + + /*ն˺ͼ*/ + std::cout << "n_clients:" << g_node->n_clients << std::endl; + if (g_node->n_clients <= 0) { + std::cout << "no terminal exist " << std::endl; + return APR_EBADF; + } + /*δ + for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) { + if(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code); + }*/ + + // + /*try { + OTLConnect(); + std::string str2 = POSTGRES_SCHEMA;//schame analy + std::string str1 = "select \"monitor_id\",\"terminal_code\",\"monitor_name\",\"logical_device_seq\",\"voltage_level\",\"terminal_connect\",\"update_time\" from \""; + str1.append(str2); + str1.append("\".\""); + str1.append(POSTGRES_TABLEPREFIX); + str1.append("pq_ledger_monitor"); + str1.append("\" where status<>'04' and status<>'05' and \"terminal_code\" in ("); + int dev_no = 0; + + for (dev_no = 0; dev_no < g_node->n_clients; dev_no++) { + str1.append("'"); + str1.append(((ied_usr_t*)(g_node->clients[dev_no]->usr_ext))->terminal_code); + str1.append("'"); + if (dev_no < g_node->n_clients - 1) { + str1 += ","; + } + } + str1.append(")"); + cout << "pg sql2 is:" << str1 << endl; + //int rtState = OTLState(); + otl_stream i(1, // buffer size + str1.c_str(), + //SELECT statement + db //connect object + ); + //create select stream + + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + otl_datetime timestamp; + while (!i.eof()) { //while not end-of-data + i >> monitor_id >> terminal_code >> monitor_name >> logical_device_seq >> voltage_level >> terminal_connect >> timestamp; + cout << "monitor_id=" << monitor_id << " terminal_code=" << terminal_code << " monitor_name=" << monitor_name << " logical_device_seq=" << logical_device_seq; + cout << " voltage_level=" << voltage_level << " terminal_connect=" << terminal_connect; + cout << " timestamp: " << timestamp.year << "-" << timestamp.month << "-" << timestamp.day << " " << timestamp.hour << ":" << timestamp.minute << ":" << timestamp.second << endl;*/ + // + try { + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + //char timestamp[64]; + otl_datetime timestamp; + + // ն̨ + QMap::iterator it; + for (it = ledger_monitor_map.begin(); it != ledger_monitor_map.end(); ++it) { + ledger_monitor* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + strncpy(monitor_id, value->monitor_id, sizeof(monitor_id) - 1); + strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1); + strncpy(monitor_name, value->monitor_name, sizeof(monitor_name) - 1); + strncpy(logical_device_seq, value->logical_device_seq, sizeof(logical_device_seq) - 1); + strncpy(voltage_level, value->voltage_level, sizeof(voltage_level) - 1); + strncpy(terminal_connect, value->terminal_connect, sizeof(terminal_connect) - 1); + //strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1); + + timestamp = parseTimestamp(value->timestamp); + } + + count_cfg = ledger_monitor_map.size();//ȡ + +// + + count_real++; + memset(&line_info, 0, sizeof(line_info)); + line_info.line_id = count_real; + //cout << "line_id:" << line_info.line_id << endl; + + strcpy(line_info.mp_id, monitor_id); + //cout << "mp_id:" << line_info.mp_id << endl; + strcpy(line_info.terminal_code, terminal_code); + //cout << "terminal_code:" << line_info.terminal_code << endl; + + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; + //cout << "logical_device_seq:is null~"<< line_info.cpuno << endl; + } + else { + line_info.cpuno = std::atoi(logical_device_seq); + //cout << "logical_device_seq:"<< logical_device_seq << endl; + } + + //cout << "cpuno:" << line_info.cpuno << endl; + strcpy(line_info.voltage_level, voltage_level); + //cout << "voltage_level:" << line_info.voltage_level << endl; + strcpy(line_info.v_wiring_type, terminal_connect); + //cout << "v_wiring_type:" << line_info.v_wiring_type << endl; + + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + line_info.time = static_cast(time); + //cout << "time:" << line_info.time << endl; + + strcpy(line_info.name, monitor_name); + //cout << "name:" << line_info.name << endl; + line_info.read_flag = 1; + ied = find_ied_from_dev_code(line_info.terminal_code); + + if (ied && ied->usr_ext && line_info.cpuno && line_info.cpuno < 10) { + char str[256]; + byte_t cpuno = line_info.cpuno; + //cout << "cpuno:" << line_info.cpuno << endl; + //cout << "byte_t cpuno:" << cpuno-1 << endl; + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + //cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl; + + if (cpuno > ied->cpucount) { + //int c = cpuno; + //cout << "cpucount(linecount old):" << (int)(ied->cpucount) << "new:" << c << endl; + + ied->cpucount = cpuno; + //cout << "byte_t cpucount:" << ied->cpucount+1 << endl; + } + } + + } + OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nledger monitor\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } + + if (count_cfg != count_real) + return APR_EBADF; + return APR_SUCCESS; +} + +int parse_model_cfg_web_test() +{ + std::vector codes;//μ + QMap icd_model_map; + codes.push_back("info"); + + parse_model_web_test(&icd_model_map,codes); + + codes.clear(); + + try { + char model_id[64]; + char tmnl_type[64]; + char tmnl_factory[64]; + char file_name[128]; + //char timestamp[64]; + otl_datetime timestamp; + + // ն̨ + QMap::iterator it; + for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) { + icd_model* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + strncpy(model_id, value->model_id, sizeof(model_id) - 1); + strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1); + strncpy(tmnl_factory, value->tmnl_factory, sizeof(tmnl_factory) - 1); + strncpy(file_name, value->file_name, sizeof(file_name) - 1); + //strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1); + + timestamp = parseTimestamp(value->timestamp); + + Set_xml_databaseinfo(model_id, tmnl_type, tmnl_factory, file_name, timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second); + } + } + } + catch (otl_exception& e) + { + printf("\nicd model\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } +} +#if 0 +//ʱsql޸Ϊweb +void OnTimerThread::run() +{ + msleep(10000); + printf("OnTimerThread::run() is called ...... \n"); + static int delectflag = 1;//ʱ־ + bool account_update = true; + bool asd = true; + + apr_time_t previousTime = apr_time_now();// + apr_time_exp_t localTime; + apr_time_exp_gmt(&localTime, previousTime); + cout << "Local Time: " + << localTime.tm_year + 1900 << "-" << localTime.tm_mon + 1 << "-" << localTime.tm_mday << " " + << localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec + << endl; + + QMap dic_task_block; + + // QMapӼֵ + dic_task_block.insert("account", false); + dic_task_block.insert("recruit ", false); + dic_task_block.insert("log", false); + dic_task_block.insert("multi_node", false); + + int ip_count = 0; + int telnet_count = 0; + // Ҽֵ + if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) { + init_ping_telnet(ip_count, telnet_count); + Cout_account_information(); + } + + if (g_onlyIP[0] != 0) + { + printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP); + add_comm_log(const_cast("g_onlyIP[0]=!0,g_onlyIP is --%s--", g_onlyIP)); + } + else { + printf("g_onlyIP[0] == 0!"); + + } + + int pgflag = 0; + int pgmin = 0; + int mp_num_hour = 0; + int recall_flag1 = 1; + + // + std::vector codes; + + //char recalllllll[256] = "0923000982"; + //CheckPG_To_Recall(1705168800, 1705168800 + 3599, recalllllll); + while (1) + { + /*cout << "ip_count:" << ip_count << " telnet_count:" << telnet_count << endl; + msleep(1000);*/ + + //߳ʱ + previousTime = apr_time_now(); + apr_time_exp_gmt(&localTime, previousTime); + //apr_time_t elapsedTime = currentTime - previousTime; + //apr_time_as_msec(elapsedTime); + //cout << "front num:" << FRONT_MP_NUM << endl; + if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//̨˸,ڵ,ͨѶ + //ȡϴ̨˸ʱ + + //жϼִ + if (false) { + //ִ̨; + + } + //¼ʱ + // + //жִдʱǷ 񱻶 + if (MULTIPLE_NODE_FLAG && pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + +//޸Ϊwebӿڸǰñ + /*QString updateFrontSql;//װpgsql + updateFrontSql.append(QString("update \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("set \"mp_num\"= %1,front_version='%2' ").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("where \"front_ip\" = '%1' and \"front_inst\"=%2;").arg(FRONT_IP).arg(FRONT_INST)); + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); //*/ + + codes.push_back("updatefront"); + codes.push_back(std::string(FRONT_IP)); + codes.push_back(intToString(FRONT_INST)); + codes.push_back(intToString(FRONT_MP_NUM)); + codes.push_back(std::string(PROGRAM_VERSION)); + parse_device_web_test_front_write(codes); + codes.clear(); + + } + pgflag = 0; + } + else if (MULTIPLE_NODE_FLAG && pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + if (mp_num_hour != localTime.tm_hour) { + std::string mp_num_str = ""; + mp_num_str.append("connected device count:"); + mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString()); + mp_num_str.append(",g_node clients:"); + mp_num_str.append(QString::number(g_node->n_clients).toStdString()); + + add_comm_log(const_cast(mp_num_str.c_str())); + mp_num_hour = localTime.tm_hour; + } + + + //2023-10-17 zw obs osssqlݿ¼ɾ + if (delectflag == 1 && localTime.tm_hour == 16) + { + delectflag = 0; + //time_t timestamp = apr_time_as_time_t(previousTime); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + if (FILE_FLAG == 1) // oss ļɾ + { + //PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/9D3AAA2BDCE430BA7E3E1302F132B880.xml"); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + + long long deltime = stamp - (60 * 60 * 24 * 30);//ȥ30 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd"); + QString Oss_Del_Path = NULL; + Oss_Del_Path.append("comtrade/"); + Oss_Del_Path.append(LD_info->mp_id).append("/"); + Oss_Del_Path.append(tmp_chr1).append("/"); + //cout << Oss_Del_Path.toAscii().data() << endl; + DelOSS(Oss_Del_Path.toAscii().data()); + cpuno++; + } + i++; + } + //PutOSS("comtrade/not def/20231111/temp.log","/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml"); + //PutOSS("comtrade/not def/20231111/temp2.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml"); + //PutOSS("comtrade/not def/20231111/temp3.log", "/FeProject/dat/6A5C8A2A7BBC1A61D9EC3F1AE2A25A03.xml"); + //DelOSS("comtrade/not def/20231111/temp3.log"); + } + else if (FILE_FLAG == 2)//Ϊ obs ļɾ + { + //OBSFile("/FeProject/dat/67BC249C13B5EC819CF4DF0307DB71C5.xml", "comtrade/not def/20231111/temp3.log", "putObject"); + //OBSFile_del("comtrade/not def/20231111/temp3.log", "deleteObject"); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + + long long deltime = stamp - (60 * 60 * 24 * 30);//ȥ30 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyyMMdd"); + QString Oss_Del_Path = NULL; + Oss_Del_Path.append("comtrade/"); + Oss_Del_Path.append(LD_info->mp_id).append("/"); + Oss_Del_Path.append(tmp_chr1).append("/"); + //cout << Oss_Del_Path.toAscii().data() << endl; + OBSFile_del(Oss_Del_Path.toAscii().data(), "deleteObject"); + cpuno++; + } + i++; + } + + + } + + //pgsqlɾ¼ + long long deltime = stamp - (60 * 60 * 24 * 30);//ȥ30 + QDateTime deltime_Qtime = QDateTime::fromTime_t(deltime); + QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); +//滻webӿ + /*QString pgsql0; + pgsql0.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_status_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql1; + pgsql1.append(QString("DELETE FROM \"%1\".\"%2meas_pq_comm_error_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql2; + pgsql2.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_rationality_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql3; + pgsql3.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_intact_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + QString pgsql4; + pgsql4.append(QString("DELETE FROM \"%1\".\"%2meas_pq_measpoint_match_tr\ WHERE \"statistical_data\" < '%3';").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX).arg(tmp_chr1)); + Sql_data_list_mutex.lock(); // + Sql_data_list.append(pgsql0); + Sql_data_list.append(pgsql1); + Sql_data_list.append(pgsql2); + Sql_data_list.append(pgsql3); + Sql_data_list.append(pgsql4); + Sql_data_list_mutex.unlock(); //*/ + codes.push_back("delete"); + codes.push_back(tmp_chr1.toStdString()); + parse_database_delete(codes); + codes.clear(); + + } + if (delectflag == 0 && localTime.tm_hour != 16) + { + delectflag = 1; + } + //2023-10-17 zw obs osssqlݿ¼ɾ end + + } + if (strcmp(subdir, "cfg_newhis_data") == 0) {//Ϻʱװ־ + static int hour_time = 0; + if (localTime.tm_hour != hour_time) { + hour_time = localTime.tm_hour; + + printf(">>>cfg_newhis_data is run!!!\n"); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + long long start = stamp - (stamp % 3600) - 3600 - 3600;//ʼʱ ǰֵǰСʱ + long long end = start + 3599;//ʱ + + QList recallinfo_list_hour; + RecallInfo info; + info.starttime = start - 10; + info.endtime = end; + recallinfo_list_hour.append(info); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + + i++; + } + } + } + if (strcmp(subdir, "cfg_recallall_data") == 0) + { + static int recall_xml_time = 0; + if (localTime.tm_min != recall_xml_time) + { + recall_xml_time = localTime.tm_min; + //пʼֹʱ + static long long recall_start_time = 0; + static long long recall_end_time = 0; + static int flag = 0; + if (recall_start_time == 0 && recall_end_time == 0) {//޻ + //ѯһ -1״̬()ļ¼ + char front_ip[42]; + cout << "start select:" << endl; +//滻Ϊwebӿ + /*QString selectFrontSql; + selectFrontSql.append(QString("select \"front_ip\" from \"%1\".\"%2meas_pq_front_list_tr\" ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + selectFrontSql.append(QString("where front_inst=%1 and \"front_status\" = '-1' LIMIT 1;").arg(g_front_seg_index)); + cout << selectFrontSql.toStdString().c_str() << endl; + try { + otl_stream i(1, // buffer size + selectFrontSql.toStdString().c_str(), + db //connect object + ); + //create select stream + while (!i.eof()) { //while not end-of-data + i >> front_ip; + break; + //cout << "count=" << f2 << endl; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + continue; + }*/ + QMap front_map; + codes.push_back("frontip"); + codes.push_back("g_front_seg_index"); + codes.push_back("-1"); + parse_device_web_test_front_read(&front_map,codes); + codes.clear(); + // QMap + QMap::iterator it; + for (it = front_map.begin(); it != front_map.end(); ++it) { + front_list* value = it.value(); + // ȷ value Ϊ + if (value != nullptr) { + // value жȡ front_ip + strncpy(front_ip, value->front_ip, sizeof(front_ip) - 1); + //Ӧֻһ¼ + std::cout << "front_ip:" <> front_status; + break; + //cout << "count=" << f2 << endl; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + continue; + }*/ + QMap front_map; + codes.push_back("frontstatus"); + codes.push_back(dateRange.toStdString()); //ip + codes.push_back("g_front_seg_index"); //inst + parse_device_web_test_front_read(&front_map,codes); + codes.clear(); + // QMap + QMap::iterator it; + for (it = front_map.begin(); it != front_map.end(); ++it) { + front_list* value = it.value(); + // ȷ value Ϊ + if (value != nullptr) { + // value жȡ front_ip + strncpy(front_status, value->front_status, sizeof(front_status) - 1); + //Ӧֻһ¼ + std::cout << "front_status:" < duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start; + info.endtime = end; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start; + info.endtime = end - 1; + recallinfo_list_hour.append(info); + } + } + } + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + printf("/home/pq mpid=%s %d\n", LD_info->mp_id, LD_info->read_flag); + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) { + continue; + } + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + g_StatisticLackList_list_mutex.lock(); + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + +//滻webӿ 2024-10-21 lnk + // if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + // printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + + continue; + } + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList.push_back(jr); + + } + g_StatisticLackList_list_mutex.unlock(); + } + } + + i++; + } + } + } + + } + if (strcmp(subdir, "cfg_his_data") == 0) + { + if (pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + +//滻Ϊwebӿ + /*QString updateFrontSql; + updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("values('his',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION)); + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); // */ + codes.push_back("his"); + codes.push_back("his"); //ip + codes.push_back(std::string(PROGRAM_VERSION)); + codes.push_back(intToString(FRONT_MP_NUM)); // + parse_device_web_test_front_write(codes); + codes.clear(); + + } + pgflag = 0; + } + else if (pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + static int cfg_his_data_hour_time = 0; + if (localTime.tm_hour != cfg_his_data_hour_time) { + cfg_his_data_hour_time = localTime.tm_hour; + + printf(">>>cfg_his_data is run!!!\n"); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + long long start = stamp - (stamp % 3600) - 3600 - 3600;//ʼʱ ǰֵǰСʱ + long long end = start + 3599;//ʱ + + QList recallinfo_list_hour; + RecallInfo info; + info.starttime = start - 10; + info.endtime = end; + recallinfo_list_hour.append(info); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + +//滻webӿ 2024-10-21 lnk + //if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + //printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + + continue; + } + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + + i++; + } + } + + } + if (strcmp(subdir, "cfg_recallhis_data") == 0) + { + if (pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { +//滻Ϊwebӿ + /*QString updateFrontSql; + updateFrontSql.append(QString("insert into \"%1\".\"%2meas_pq_front_list_tr\"(\"front_ip\",\"front_port\",\"front_inst\",\"front_type\",\"front_status\",\"front_version\",\"mp_num\") ").arg(POSTGRES_SCHEMA).arg(POSTGRES_TABLEPREFIX)); + updateFrontSql.append(QString("values('recallhis',10000,1,'02','01','%1',200) ").arg(PROGRAM_VERSION)); + updateFrontSql.append(QString("on conflict(\"front_ip\",\"front_inst\") do update set ")); + updateFrontSql.append(QString("\"mp_num\"= '%1',front_version='%2'").arg(FRONT_MP_NUM).arg(PROGRAM_VERSION)); + Sql_data_list_mutex.lock(); // + Sql_data_list.append(updateFrontSql); + Sql_data_list_mutex.unlock(); // */ + codes.push_back("his"); + codes.push_back("recallhis"); //ip + codes.push_back(std::string(PROGRAM_VERSION)); + codes.push_back(intToString(FRONT_MP_NUM)); // + parse_device_web_test_front_write(codes); + codes.clear(); + + } + pgflag = 0; + } + else if (pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + } + + //g_node_id == HIS_DATA_BASE_NODE_ID && + //printf("/home/pq hour=%d\n", localTime.tm_hour); + if (0 && g_node_id == HIS_DATA_BASE_NODE_ID && (localTime.tm_hour <= 12 || localTime.tm_hour >= 20) && recall_flag1 == 1) { + recall_flag1 = 0; + QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir) + QSettings settings(MyKafkaIniFilename, QSettings::IniFormat); + + QString dateString = settings.value("Recall/select_day").toString(); + + QList recallinfo_list_hour; + QByteArray byteArray = dateString.toUtf8(); // ʹ UTF-8 + char* charArray = byteArray.data(); + Get_Recall_Time(charArray, recallinfo_list_hour); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info->logcount <= 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + if (recallinfo_list_hour.size() != 0) { + if (LD_info->autorecallcount != 0) { + for (int j = 0; j < LD_info->autorecallcount; j++) { + delete LD_info->autorecall[j]; + } + delete LD_info->autorecall; + LD_info->autorecallcount = 0; + } + LD_info->autorecallflag = 0; + LD_info->autorecallcount = recallinfo_list_hour.size(); + LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()]; + printf("/home/pq recall mpid=%s\n", LD_info->mp_id); + + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime); + LD_info->autorecall[j] = new autorecall_t[1]; + LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime; + + LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime; + } + } + + + cpuno++; + } + i++; + } + + QDate date = QDate::fromString(dateString, "yyyy-MM-dd"); + + date.addDays(-1); // һ + settings.setValue("Recall/select_day", date.toString("yyyy-MM-dd")); // дַ + + + } + if (localTime.tm_hour > 12 && localTime.tm_hour < 20 && recall_flag1 == 0) { + recall_flag1 = 1; + } + + msleep(1000); + } + + printf(">>>OnTimerThread::run() is end!!!\n"); +} +#endif +#endif +/*/////////////////////////////////////////////////////////lnk10-11ƳpgsqlIJԴ/////////////////////////////////////////////////////////////*/ + +/*/////////////////////////////////////////////////////////lnk10-24webӿ޸/////////////////////////////////////////////////////////////*/ +//jsonַ +// صֱ׷ӵ *ptr +size_t req_reply_http(void* contents, size_t size, size_t nmemb, void* userp) { + size_t realsize = size * nmemb; + char** ptr = (char**)userp; + + // ̬չ *ptr ڴ + char* temp = (char*)realloc(*ptr, strlen(*ptr) + realsize + 1); + if (temp == NULL) { + printf("Memory allocation failed!\n"); + return 0; // 0 ֪ͨ curl ֹͣݽ + } + *ptr = temp; + + // ׷ݵ *ptr + strncat(*ptr, (char*)contents, realsize); + return realsize; +} + +void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr) { + CURL* curl = curl_easy_init(); + CURLcode res; + + // ʼ *ptr ַ + *ptr = (char*)malloc(1); + if (*ptr == NULL) { + printf("Memory allocation failed!\n"); + return; + } + (*ptr)[0] = '\0'; // ΪַԱ strncat + + if (curl) { + char url[256]; + snprintf(url, sizeof(url), "%s?%s", strUrl.c_str(), code); + printf(">>>json %s\n", url); + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_http); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + if (!json.empty()) { + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str()); + } + + struct curl_slist* headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + res = curl_easy_perform(curl); + + if (res != CURLE_OK) { + printf("web failed res code: %s\n", curl_easy_strerror(res)); + } else { + //printf(">>> web return str: %s \n", *ptr); + } + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + } else { + printf(">>> web curl init failed\n"); + } +} +/*void SendJsonAPI_web(const std::string& strUrl, const char* code, const std::string& json, char** ptr) { + // curl ʼ + CURL* curl = curl_easy_init(); + CURLcode res; + + if (curl) { + char url[100]; + sprintf(url, "%s?%s", strUrl.c_str(), code); + printf(">>>json %s\n", url); + + // URL + curl_easy_setopt(curl, CURLOPT_URL, url); + + // ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); + + // ݽ + std::string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + // óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + if(json != ""){ + // HTTP Ϊ POST + curl_easy_setopt(curl, CURLOPT_POST, 1L); + + // JSON ʽ body + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str()); + } + + // ͷ + struct curl_slist* headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + // ִ + res = curl_easy_perform(curl); + + // Ƿɹ + if (res != CURLE_OK) { + printf("web failed res code: %s\n", curl_easy_strerror(res)); + } else { + printf(">>> web return str: %s \n", resPost0.c_str()); + + // ڴ沢Ʒؽ + *ptr = (char*)malloc(resPost0.size() + 1); // 㹻ڴռ + if (*ptr != NULL) { + strcpy(*ptr, resPost0.c_str()); + } else { + printf("Memory allocation failed!\n"); + } + } + + // ͷ + curl_slist_free_all(headers); + } else { + printf(">>> web curl init failed"); + } + curl_easy_cleanup(curl); +}*/ + +// ӡ terminal_dev_map ݵĺ +void printTerminalDevMap(const QMap& terminal_dev_map) { + QMap::const_iterator it; + for (it = terminal_dev_map.constBegin(); it != terminal_dev_map.constEnd(); ++it) { + QString key = it.key(); + terminal_dev* dev = it.value(); + + if (dev) { + qDebug() << "Key:" << key + << ", Terminal ID:" << QString(dev->terminal_id) + << ", Terminal Code:" << QString(dev->terminal_code) + << ", Organization Name:" << QString(dev->org_name) + << ", Maintenance Name:" << QString(dev->maint_name) + << ", Station Name:" << QString(dev->station_name) + << ", Factory:" << QString(dev->tmnl_factory) + << ", Status:" << QString(dev->tmnl_status) + << ", Device Type:" << QString(dev->dev_type) + << ", Device Key:" << QString(dev->dev_key) + << ", Device Series:" << QString(dev->dev_series) + << ", Address:" << QString(dev->addr_str) + << ", Port:" << QString(dev->port) + << ", Timestamp:" << QString(dev->timestamp); + + // ӡϢ + for (int i = 0; i < 10; ++i) { + qDebug() << " Monitor ID:" << QString(dev->line[i].monitor_id) + << ", Terminal Code:" << QString(dev->line[i].terminal_code) + << ", Monitor Name:" << QString(dev->line[i].monitor_name) + << ", Logical Device Seq:" << QString(dev->line[i].logical_device_seq) + << ", Voltage Level:" << QString(dev->line[i].voltage_level) + << ", Terminal Connect:" << QString(dev->line[i].terminal_connect) + << ", Timestamp:" << QString(dev->line[i].timestamp) + << ", Status:" << QString(dev->line[i].status); + } + } else { + qDebug() << "Key:" << key << ", Value is nullptr"; + } + } +} + +//ӡǰ̵̨////////////////////////////////////////////////////////////////////////// +// ӡṹϢĵݹ麯 +void printLedger(const ied_usr_t& ied_usr) { + std::cout << "------------------------------------" << std::endl; + std::cout << "|-- terminal_id: " << ied_usr.terminal_id << std::endl; + std::cout << "|-- dev_index: " << ied_usr.dev_idx << std::endl; + std::cout << "|-- dev_type: " << ied_usr.dev_type << std::endl; + std::cout << "|-- dev_key: " << ied_usr.dev_key << std::endl; + std::cout << "|-- dev_series: " << ied_usr.dev_series << std::endl; + std::cout << "|-- dev_flag: " << ied_usr.dev_flag << std::endl; + + std::cout << "|-- last_call_wavelist_time: " << ied_usr.last_call_wavelist_time << std::endl; + + std::cout << "|-- org_name: " << ied_usr.org_name << std::endl; + std::cout << "|-- maint_name: " << ied_usr.maint_name << std::endl; + std::cout << "|-- station_name: " << ied_usr.station_name << std::endl; + std::cout << "|-- tmnl_factory: " << ied_usr.tmnl_factory << std::endl; + std::cout << "|-- time: " << ied_usr.time << std::endl; + std::cout << "|-- tmnl_status: " << ied_usr.tmnl_status << std::endl; + std::cout << "|-- terminal_code: " << ied_usr.terminal_code << std::endl; + std::cout << "|-- update_flag: " << ied_usr.update_flag << std::endl; + + // ӡÿLD_info + for (int i = 0; i < 10; ++i) { + if (strcmp(ied_usr.LD_info[i].mp_id, "") != 0) { + std::cout << "|-- LD_info[" << i << "]:" << std::endl; +//name + std::cout << " |-- name: " << ied_usr.LD_info[i].name << std::endl; + std::cout << " |-- LD_name: " + << (strlen(ied_usr.LD_info[i].LD_name) == 0 ? "NA" : ied_usr.LD_info[i].LD_name) + << std::endl; + std::cout << " |-- read_flag: " << ied_usr.LD_info[i].read_flag << std::endl; +//index + std::cout << " |-- line_id: " << ied_usr.LD_info[i].line_id << std::endl; +//monitorledger + std::cout << " |-- mp_id: " << ied_usr.LD_info[i].mp_id << std::endl; + std::cout << " |-- terminal_code: " << ied_usr.LD_info[i].terminal_code << std::endl; + std::cout << " |-- voltage_level: " << ied_usr.LD_info[i].voltage_level << std::endl; + std::cout << " |-- v_wiring_type: " << ied_usr.LD_info[i].v_wiring_type << std::endl; + std::cout << " |-- time: " << ied_usr.LD_info[i].time << std::endl; + std::cout << " |-- update_flag: " << ied_usr.LD_info[i].update_flag << std::endl; + std::cout << " |-- monitor_status: " << ied_usr.LD_info[i].monitor_status << std::endl; +//countݲӡ + std::cout << " |-- rptcount: " << ied_usr.LD_info[i].rptcount << std::endl; + std::cout << " |-- logcount: " << ied_usr.LD_info[i].logcount << std::endl; +//rpt + std::cout << " |-- rptRecvFlag: " << ied_usr.LD_info[i].rptRecvFlag << std::endl; + std::cout << " |-- rptRecvCheckFlag: " << ied_usr.LD_info[i].rptRecvCheckFlag << std::endl; + std::cout << " |-- rptPstRecvFlag: " << ied_usr.LD_info[i].rptPstRecvFlag << std::endl; + std::cout << " |-- rptPstRecvCheckFlag: " << ied_usr.LD_info[i].rptPstRecvCheckFlag << std::endl; +//rtdata + std::cout << " |-- real_data: " << ied_usr.LD_info[i].real_data << std::endl; + std::cout << " |-- soe_data: " << ied_usr.LD_info[i].soe_data << std::endl; + std::cout << " |-- limit: " << ied_usr.LD_info[i].limit << std::endl; + std::cout << " |-- count: " << ied_usr.LD_info[i].count << std::endl; +//RDRE + std::cout << " |-- RDRE_FltNum: " << ied_usr.LD_info[i].RDRE_FltNum << std::endl; + for (int j = 0; j < 256; ++j) { + if (ied_usr.LD_info[i].FltNum[j] != 0) { + std::cout << " |-- FltNum[" << j << "]:" << ied_usr.LD_info[i].FltNum[j] << std::endl; + } + } +//QVVR + std::cout << " |-- qvvr_idx: " << ied_usr.LD_info[i].qvvr_idx << std::endl; + std::cout << " |-- QVVRs:" << std::endl; + for (int j = 0; j < 256; ++j) { + if (ied_usr.LD_info[i].qvvr[j].used_status != 0) { + std::cout << " |-- QVVR[" << j << "]:" << std::endl; + std::cout << " |-- used_status: " << ied_usr.LD_info[i].qvvr[j].used_status << std::endl; + std::cout << " |-- QVVR_start: " << ied_usr.LD_info[i].qvvr[j].QVVR_start << std::endl; + std::cout << " |-- QVVR_type: " << ied_usr.LD_info[i].qvvr[j].QVVR_type << std::endl; + std::cout << " |-- QVVR_time: " << ied_usr.LD_info[i].qvvr[j].QVVR_time << std::endl; + std::cout << " |-- QVVR_PerTime: " << ied_usr.LD_info[i].qvvr[j].QVVR_PerTime << std::endl; + std::cout << " |-- QVVR_Amg: " << ied_usr.LD_info[i].qvvr[j].QVVR_Amg << std::endl; + std::cout << " |-- QVVR_Rptname: " << ied_usr.LD_info[i].qvvr[j].QVVR_Rptname << std::endl; + std::cout << " |-- timestamp: " << ied_usr.LD_info[i].qvvr[j].timestamp << std::endl; + } + } + } + } + std::cout << "------------------------------------" << std::endl; +} +void printLedgerinshell(const ied_usr_t& ied_usr, QIODevice* outputDevice) { + outputDevice->write("------------------------------------\n"); + outputDevice->write("|-- terminal_id: " + QByteArray(ied_usr.terminal_id) + "\n"); + outputDevice->write("|-- dev_index: " + QByteArray::number(ied_usr.dev_idx) + "\n"); + outputDevice->write("|-- dev_type: " + QByteArray(ied_usr.dev_type) + "\n"); + outputDevice->write("|-- dev_key: " + QByteArray(ied_usr.dev_key) + "\n"); + outputDevice->write("|-- dev_series: " + QByteArray(ied_usr.dev_series) + "\n"); + outputDevice->write("|-- dev_flag: " + QByteArray::number(ied_usr.dev_flag) + "\n"); + + outputDevice->write("|-- last_call_wavelist_time: " + QByteArray::number(ied_usr.last_call_wavelist_time) + "\n"); + + outputDevice->write("|-- org_name: " + QByteArray(ied_usr.org_name) + "\n"); + outputDevice->write("|-- maint_name: " + QByteArray(ied_usr.maint_name) + "\n"); + outputDevice->write("|-- station_name: " + QByteArray(ied_usr.station_name) + "\n"); + outputDevice->write("|-- tmnl_factory: " + QByteArray(ied_usr.tmnl_factory) + "\n"); + outputDevice->write("|-- time: " + QByteArray::number(ied_usr.time) + "\n"); + outputDevice->write("|-- tmnl_status: " + QByteArray(ied_usr.tmnl_status) + "\n"); + outputDevice->write("|-- terminal_code: " + QByteArray(ied_usr.terminal_code) + "\n"); + outputDevice->write("|-- update_flag: " + QByteArray::number(ied_usr.update_flag) + "\n"); + + // ӡÿLD_info + for (int i = 0; i < 10; ++i) { + if (strcmp(ied_usr.LD_info[i].mp_id, "") != 0) { + outputDevice->write("|-- LD_info[" + QByteArray::number(i) + "]:\n"); + + // name + outputDevice->write(" |-- name: " + QByteArray(ied_usr.LD_info[i].name) + "\n"); + outputDevice->write(" |-- LD_name: " + + (strlen(ied_usr.LD_info[i].LD_name) == 0 ? QByteArray("NA") : QByteArray(ied_usr.LD_info[i].LD_name)) + + "\n"); + outputDevice->write(" |-- read_flag: " + QByteArray::number(ied_usr.LD_info[i].read_flag) + "\n"); + + // index + outputDevice->write(" |-- line_id: " + QByteArray::number(ied_usr.LD_info[i].line_id) + "\n"); + + // monitorledger + outputDevice->write(" |-- mp_id: " + QByteArray(ied_usr.LD_info[i].mp_id) + "\n"); + outputDevice->write(" |-- terminal_code: " + QByteArray(ied_usr.LD_info[i].terminal_code) + "\n"); + outputDevice->write(" |-- voltage_level: " + QByteArray(ied_usr.LD_info[i].voltage_level) + "\n"); + outputDevice->write(" |-- v_wiring_type: " + QByteArray(ied_usr.LD_info[i].v_wiring_type) + "\n"); + outputDevice->write(" |-- time: " + QByteArray::number(ied_usr.LD_info[i].time) + "\n"); + outputDevice->write(" |-- update_flag: " + QByteArray::number(ied_usr.LD_info[i].update_flag) + "\n"); + outputDevice->write(" |-- monitor_status: " + QByteArray(ied_usr.LD_info[i].monitor_status) + "\n"); + + // countݲӡ + outputDevice->write(" |-- rptcount: " + QByteArray::number(ied_usr.LD_info[i].rptcount) + "\n"); + outputDevice->write(" |-- logcount: " + QByteArray::number(ied_usr.LD_info[i].logcount) + "\n"); + + // rpt + outputDevice->write(" |-- rptRecvFlag: " + QByteArray::number(ied_usr.LD_info[i].rptRecvFlag) + "\n"); + outputDevice->write(" |-- rptRecvCheckFlag: " + QByteArray::number(ied_usr.LD_info[i].rptRecvCheckFlag) + "\n"); + outputDevice->write(" |-- rptPstRecvFlag: " + QByteArray::number(ied_usr.LD_info[i].rptPstRecvFlag) + "\n"); + outputDevice->write(" |-- rptPstRecvCheckFlag: " + QByteArray::number(ied_usr.LD_info[i].rptPstRecvCheckFlag) + "\n"); + + // rtdata + outputDevice->write(" |-- real_data: " + QByteArray::number(ied_usr.LD_info[i].real_data) + "\n"); + outputDevice->write(" |-- soe_data: " + QByteArray::number(ied_usr.LD_info[i].soe_data) + "\n"); + outputDevice->write(" |-- limit: " + QByteArray::number(ied_usr.LD_info[i].limit) + "\n"); + outputDevice->write(" |-- count: " + QByteArray::number(ied_usr.LD_info[i].count) + "\n"); + + // RDRE + outputDevice->write(" |-- RDRE_FltNum: " + QByteArray::number(ied_usr.LD_info[i].RDRE_FltNum) + "\n"); + for (int j = 0; j < 256; ++j) { + if (ied_usr.LD_info[i].FltNum[j] != 0) { + outputDevice->write(" |-- FltNum[" + QByteArray::number(j) + "]: " + + QByteArray::number(ied_usr.LD_info[i].FltNum[j]) + "\n"); + } + } + + // QVVR + outputDevice->write(" |-- qvvr_idx: " + QByteArray::number(ied_usr.LD_info[i].qvvr_idx) + "\n"); + outputDevice->write(" |-- QVVRs:\n"); + for (int j = 0; j < 256; ++j) { + if (ied_usr.LD_info[i].qvvr[j].used_status != 0) { + outputDevice->write(" |-- QVVR[" + QByteArray::number(j) + "]:\n"); + outputDevice->write(" |-- used_status: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].used_status) + "\n"); + outputDevice->write(" |-- QVVR_start: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_start) + "\n"); + outputDevice->write(" |-- QVVR_type: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_type) + "\n"); + outputDevice->write(" |-- QVVR_time: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_time) + "\n"); + outputDevice->write(" |-- QVVR_PerTime: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_PerTime) + "\n"); + outputDevice->write(" |-- QVVR_Amg: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].QVVR_Amg) + "\n"); + outputDevice->write(" |-- QVVR_Rptname: " + QByteArray(ied_usr.LD_info[i].qvvr[j].QVVR_Rptname) + "\n"); + outputDevice->write(" |-- timestamp: " + QByteArray::number(ied_usr.LD_info[i].qvvr[j].timestamp) + "\n"); + } + } + } + } + outputDevice->write("------------------------------------\n"); +} + +// ӡ豸ϢضնϢ +void ledger(const char* terminal_id, QIODevice* outputDevice) { + pthread_mutex_lock(&mtx); + bool found = false; + ied_t* ied; + ied_usr_t* ied_usr; + for (int t = 0; t < g_node->n_clients; t++) { + ied = (ied_t*)g_node->clients[t]; + if(ied != NULL){ + ied_usr = (ied_usr_t*)ied->usr_ext; + if (ied_usr != NULL && (terminal_id == NULL || strcmp(ied_usr->terminal_id, terminal_id) == 0)) { + printLedgerinshell(*ied_usr, outputDevice); // ʹ QIODevice + std::cout << "!!! print to log !!!"<< std::endl; + printLedger(*ied_usr); + found = true; + } + } + + } + if (!found || terminal_id == NULL) { + std::cout << "ն˲: " << terminal_id << std::endl; + QByteArray msg = "ն˲: " + QByteArray(terminal_id ? terminal_id : "NULL") + "\n"; + outputDevice->write(msg); // QIODevice + } + pthread_mutex_unlock(&mtx); +} +////////////////////////////////////////////////////////////////////////////////////////////////// +// JSON ĺ ǰö̬ +int terminal_ledger_web(QMap* terminal_dev_map, + const std::vector& codes, + int index, + int num) +{ + //޸ΪindexȡӦ̨ˣnumûˣindexֵҲû + if(1 == MULTIPLE_NODE_FLAG){ + // ֤ + if (num <= 0) { + std::cerr << "Error: 'num' must be greater than 0." << std::endl; + return 1; // ʵĴ + } + + index = index - 1; + if (index < 0 || index >= num) { + std::cerr << "Error: 'index' must be in the range [0, num-1]." << std::endl; + return 1; // ʵĴ + } + } + + // ȡ + if (codes.empty()) { + std::cerr << "Error: 'codes' vector is empty." << std::endl; + return 1; + } + + std::string parm = codes[0]; + + char* ptr = NULL; + + // API + SendJsonAPI_web(WEB_DEVICE, "",parm.c_str(), &ptr); + + if (ptr == NULL) { + std::cerr << "Error: Received NULL response from SendJsonAPI_web." << std::endl; + return 1; + } + + // + printf("ptr:%s\n", ptr); + + cJSON* root = cJSON_Parse(ptr); //jsonʽл + + int retry = 0; + + if (root == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + + //ط + while(root == NULL){ + // ǰͷ֮ǰ ptr Աڴй© + if (ptr != NULL) { + free(ptr); + ptr = NULL; + } + //url + //SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr); + SendJsonAPI_web(WEB_DEVICE, "",parm.c_str(), &ptr); + + if(ptr == NULL){ + retry++;if(retry>3)break; + continue; + } + + root = cJSON_Parse(ptr); + retry++;if(retry>3)break; + } + // ԺȻʧܣȷ˳ǰͷκѷڴ + if (root == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + return 1; // ҪʵĴ + } + } + + // ȡ "code" "msg" + cJSON* codeItem = cJSON_GetObjectItem(root, "code"); + cJSON* msgItem = cJSON_GetObjectItem(root, "msg"); + + // ʹ std::string ȡֵ + std::string code = (codeItem != NULL && codeItem->type == cJSON_String) ? codeItem->valuestring : "not found"; + std::string msg = (msgItem != NULL && msgItem->type == cJSON_String) ? msgItem->valuestring : "not found"; + + // ӡ + std::cout << "code: " << code << std::endl; + std::cout << "msg: " << msg << std::endl; + + // ȡ "data" + cJSON* data = cJSON_GetObjectItem(root, "data"); + if (!data || data->type != cJSON_Array) { + std::cerr << "Error: 'data' is not an array." << std::endl; + cJSON_Delete(root); + free(ptr); + return 1; + } + + int data_size = cJSON_GetArraySize(data); + + std::cout << "data_size " << data_size << std::endl; + + if (data_size == 0) { + std::cerr << "Error: 'data' array is empty." << std::endl; + cJSON_Delete(root); + free(ptr); + return 1; + } + + //޸ΪindexȡӦ̨ˣپ֣ȡ̨˲жϽ̺ + int base_size = 0; + int remainder = 0; + int start_index = 0; + int end_index = data_size; + + if(1 == MULTIPLE_NODE_FLAG){ + // ÿݵĴС + base_size = data_size / num; + remainder = data_size % num; + + // 㵱ǰݵʼͽ + start_index = index * base_size + (index < remainder ? index : remainder); + end_index = start_index + base_size + (index < remainder ? 1 : 0); + + // ȷС + if (end_index > data_size) { + end_index = data_size; + } + } + + // ָΧڵԪ + for (int i = start_index; i < end_index; ++i) { + cJSON* item = cJSON_GetArrayItem(data, i); + if (!item || item->type != cJSON_Object) { + std::cerr << "Warning: Invalid item at index " << i << "." << std::endl; + continue; // Ч + } + + terminal_dev* dev = new terminal_dev(); + memset(dev, 0, sizeof(terminal_dev)); // ʼṹ + + // ֶ + cJSON* id = cJSON_GetObjectItem(item, "id"); // terminal_id + if (id && id->type == cJSON_String) strncpy(dev->terminal_id, id->valuestring, sizeof(dev->terminal_id) - 1); + else strncpy(dev->terminal_id, "N/A", sizeof(dev->terminal_id) - 1); + + cJSON* ip = cJSON_GetObjectItem(item, "ip"); // addr_str + if (ip && ip->type == cJSON_String) strncpy(dev->addr_str, ip->valuestring, sizeof(dev->addr_str) - 1); + else strncpy(dev->addr_str, "N/A", sizeof(dev->addr_str) - 1); + + cJSON* terminalCode = cJSON_GetObjectItem(item, "name"); // terminal_code + if (terminalCode && terminalCode->type == cJSON_String) strncpy(dev->terminal_code, terminalCode->valuestring, sizeof(dev->terminal_code) - 1); + else strncpy(dev->terminal_code, "N/A", sizeof(dev->terminal_code) - 1); + + cJSON* orgName = cJSON_GetObjectItem(item, "org_name"); // org_name + if (orgName && orgName->type == cJSON_String) strncpy(dev->org_name, orgName->valuestring, sizeof(dev->org_name) - 1); + else strncpy(dev->org_name, "N/A", sizeof(dev->org_name) - 1); + + cJSON* maintName = cJSON_GetObjectItem(item, "maint_name"); // maint_name + if (maintName && maintName->type == cJSON_String) strncpy(dev->maint_name, maintName->valuestring, sizeof(dev->maint_name) - 1); + else strncpy(dev->maint_name, "N/A", sizeof(dev->maint_name) - 1); + + cJSON* stationName = cJSON_GetObjectItem(item, "stationName"); // station_name + if (stationName && stationName->type == cJSON_String) strncpy(dev->station_name, stationName->valuestring, sizeof(dev->station_name) - 1); + else strncpy(dev->station_name, "N/A", sizeof(dev->station_name) - 1); + + cJSON* manufacturer = cJSON_GetObjectItem(item, "manufacturer"); // tmnl_factory + if (manufacturer && manufacturer->type == cJSON_String) strncpy(dev->tmnl_factory, manufacturer->valuestring, sizeof(dev->tmnl_factory) - 1); + else strncpy(dev->tmnl_factory, "N/A", sizeof(dev->tmnl_factory) - 1); + + cJSON* status = cJSON_GetObjectItem(item, "status"); // tmnl_status + if (status && status->type == cJSON_String) strncpy(dev->tmnl_status, status->valuestring, sizeof(dev->tmnl_status) - 1); + else strncpy(dev->tmnl_status, "N/A", sizeof(dev->tmnl_status) - 1); + + cJSON* devType = cJSON_GetObjectItem(item, "devType"); // dev_type + if (devType && devType->type == cJSON_String) strncpy(dev->dev_type, devType->valuestring, sizeof(dev->dev_type) - 1); + else strncpy(dev->dev_type, "N/A", sizeof(dev->dev_type) - 1); + + cJSON* devKey = cJSON_GetObjectItem(item, "devKey"); // dev_key + if (devKey && devKey->type == cJSON_String) strncpy(dev->dev_key, devKey->valuestring, sizeof(dev->dev_key) - 1); + else strncpy(dev->dev_key, "N/A", sizeof(dev->dev_key) - 1); + + cJSON* series = cJSON_GetObjectItem(item, "series"); // dev_series + if (series && series->type == cJSON_String) strncpy(dev->dev_series, series->valuestring, sizeof(dev->dev_series) - 1); + else strncpy(dev->dev_series, "N/A", sizeof(dev->dev_series) - 1); + + cJSON* port = cJSON_GetObjectItem(item, "port"); // port + if (port && port->type == cJSON_String) strncpy(dev->port, port->valuestring, sizeof(dev->port) - 1); + else strncpy(dev->port, "N/A", sizeof(dev->port) - 1); + + cJSON* updateTime = cJSON_GetObjectItem(item, "updateTime"); // timestamp + if (updateTime && updateTime->type == cJSON_String) strncpy(dev->timestamp, updateTime->valuestring, sizeof(dev->timestamp) - 1); + else strncpy(dev->timestamp, "N/A", sizeof(dev->timestamp) - 1); + + // monitorData + cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData"); + if (monitorData && monitorData->type == cJSON_Array) { + int j = 0; + cJSON* monitorItem; + cJSON_ArrayForEach(monitorItem, monitorData) { + if (j >= 10){ + std::cout << "һնֻʮ" << std::endl; + break; // Ϊ10 + } + + cJSON* monitor_id = cJSON_GetObjectItem(monitorItem, "id"); // monitor_id + if (monitor_id && monitor_id->type == cJSON_String) strncpy(dev->line[j].monitor_id, monitor_id->valuestring, sizeof(dev->line[j].monitor_id) - 1); + else strncpy(dev->line[j].monitor_id, "N/A", sizeof(dev->line[j].monitor_id) - 1); + + cJSON* monitor_name = cJSON_GetObjectItem(monitorItem, "name"); // monitor_name + if (monitor_name && monitor_name->type == cJSON_String) strncpy(dev->line[j].monitor_name, monitor_name->valuestring, sizeof(dev->line[j].monitor_name) - 1); + else strncpy(dev->line[j].monitor_name, "N/A", sizeof(dev->line[j].monitor_name) - 1); + + cJSON* lineNo = cJSON_GetObjectItem(monitorItem, "lineNo"); // logical_device_seq + if (lineNo && lineNo->type == cJSON_String) strncpy(dev->line[j].logical_device_seq, lineNo->valuestring, sizeof(dev->line[j].logical_device_seq) - 1); + else strncpy(dev->line[j].logical_device_seq, "N/A", sizeof(dev->line[j].logical_device_seq) - 1); + + cJSON* voltageLevel = cJSON_GetObjectItem(monitorItem, "voltageLevel"); // voltage_level + if (voltageLevel && voltageLevel->type == cJSON_String) strncpy(dev->line[j].voltage_level, voltageLevel->valuestring, sizeof(dev->line[j].voltage_level) - 1); + else strncpy(dev->line[j].voltage_level, "N/A", sizeof(dev->line[j].voltage_level) - 1); + + cJSON* ptType = cJSON_GetObjectItem(monitorItem, "ptType"); // terminal_connect + if (ptType && ptType->type == cJSON_String) strncpy(dev->line[j].terminal_connect, ptType->valuestring, sizeof(dev->line[j].terminal_connect) - 1); + else strncpy(dev->line[j].terminal_connect, "N/A", sizeof(dev->line[j].terminal_connect) - 1); + + // Ӽ״̬ + cJSON* monitorstatus = cJSON_GetObjectItem(monitorItem, "status"); // status + if (monitorstatus && monitorstatus->type == cJSON_String) strncpy(dev->line[j].status, monitorstatus->valuestring, sizeof(dev->line[j].status) - 1); + else strncpy(dev->line[j].status, "N/A", sizeof(dev->line[j].status) - 1); + + j++; + } + } + + // ׼ + QString key = QString(dev->terminal_id);//idcode֣еcode + + // Ƿظ + if (terminal_dev_map->contains(key)) { + std::cerr << "Duplicate terminal_code found: " << key.toStdString() << std::endl; + + // ɾɵ terminal_dev Աڴй© + delete terminal_dev_map->value(key); + + // Ƴɵļֵ + terminal_dev_map->remove(key); + + // µ terminal_dev + terminal_dev_map->insert(key, dev);//޸Ϊֻн̺ƥindex¼뵱ǰ + } else { + // µ terminal_dev + terminal_dev_map->insert(key, dev);//޸Ϊֻн̺ƥindex¼뵱ǰ + // + //std::cout << "i = " << i << std::endl; + //std::cout << "terminal_dev_map.size:" << terminal_dev_map->size() << std::endl; + }//ظ־ҪַŲ + + + } + + // ͷԴ + cJSON_Delete(root); + free(ptr); + + return 0; // ȷзֵ +} + +int parse_device_cfg_web() +{ + std::cout << "parse_device_cfg_web" << endl; + + std::vector codes; //μ + +/*//ǰж + if (FRONT_INST == 0 || FRONT_IP[0] == '\0') { + MULTIPLE_NODE_FLAG = 0; + cout << "set MULTIPLE_NODE_FLAG:0,because do not have FRONT_INST or FRONT_IP" << endl; + } + char front_type[2] = {""}; + int mp_num = 0; +//webӿ滻ǰñĶдӿнӽӿֱȡлȡҪֵдʱֱӴΣ + if (MULTIPLE_NODE_FLAG) { +//ǰñȡ滻 + QMap front_map; + codes.push_back("info"); + parse_device_web_test_front_read(&front_map,codes); + codes.clear(); + // QMap + QMap::iterator it; + for (it = front_map.begin(); it != front_map.end(); ++it) { + front_list* value = it.value(); + // ȷ value Ϊ + if (it.key() == "0.0.0.0" && value != nullptr) { + // value жȡ front_typeǰַ + strncpy(front_type, value->front_type, 2); + front_type[2] = '\0'; // ȷԿַβ + // mp_num ַתΪ + mp_num = std::atoi(value->mp_num); + } + } +//ǰñȡ +//ǰñд벿 + codes.push_back("insertfront"); + codes.push_back(std::string(FRONT_IP)); + codes.push_back(intToString(FRONT_INST)); + codes.push_back(std::string(front_type)); + codes.push_back(std::string(PROGRAM_VERSION)); + codes.push_back("01"); //״ֵ̬ + parse_device_web_test_front_write(codes); + codes.clear(); +//ǰñд벿 + } + cout << "mp_num:" << mp_num << " front_type:" << front_type << endl;*/ +//ǰǰòҪǰãǰôļmykafka.iniȡip󣬽ipΪ͸webӿڻȡ̨ + + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + int count_cfg = 0; //ն̨ + int count_real = 0; //ն̨˵ļ + +///////////////////////////////////////////////////////////////////////////////// +/*//ȡնext滻Ϊwebӿ + QMap terminal_ext_map; + //read_terminal_ext_pg(&terminal_ext_map); + codes.push_back("info"); + parse_device_web_test_ext(&terminal_ext_map,codes); + codes.clear(); +//ȡնext滻Ϊwebӿ + +//ȡն̨˱滻Ϊwebӿ + + QMap terminal_dev_map; + + codes.push_back("count_cfg"); + + parse_device_web_test_dev(&terminal_dev_map,codes); + + // QMap + QMap::iterator it; + for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) { + terminal_dev* value = it.value(); + // ȷ value Ϊ + if (it.key() == "count_cfg" && value != nullptr) { + // count ַתΪ + count_cfg = std::atoi(value->count_cfg); + } + // + cout << "count_cfg:" << count_cfg << " value->count_cfg:" << value->count_cfg << endl; + } + + codes.clear(); + + //ȡcountcfgҪ0Ӱȡ̨߼ + terminal_dev_map.clear(); + +//ȡն̨˱滻Ϊwebӿ + +//ȡն̨˱滻Ϊwebӿ + + codes.push_back("info"); + codes.push_back(intToString(FRONT_INST)); + codes.push_back(intToString(mp_num)); + codes.push_back(intToString(count_cfg)); + codes.push_back(intToString(MULTIPLE_NODE_FLAG)); + codes.push_back(intToString(g_front_seg_num)); + + parse_device_web_test_dev(&terminal_dev_map,codes); + + codes.clear(); + + if (MULTIPLE_NODE_FLAG && g_front_seg_num == 0) { + if (mp_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * mp_num; + } + else + { + count_cfg = mp_num; + } + } + else if (MULTIPLE_NODE_FLAG && g_front_seg_num != 0) { + int front_num = (count_cfg / g_front_seg_num) + 1; + if (front_num * FRONT_INST > count_cfg) { + count_cfg = count_cfg - (FRONT_INST - 1) * front_num; + } + else + { + count_cfg = front_num; + } + }*/ +//////////////////////////////////////////////////////////////////////////////// + //ӿںϲֻһwebӿڻȡն̨˺ͼ̨ + QMap terminal_dev_map; + +////////////////////////////////////////////////////////////////////////////// + // + //codes.push_back("code1=ledger"); //FRONT_IP״̬ɲ + + //json + std::string input_jstr = "{"; + input_jstr += "\"ip\":\"" + std::string(FRONT_IP) + "\","; + input_jstr += "\"runFlag\":" + TERMINAL_STATUS + ""; + input_jstr += "}"; + + std::cout << "input_jstr: " << input_jstr << std::endl; // + + codes.push_back(input_jstr); //ǷҪɸѡ״ֱ̬ļ +/////////////////////////////////////////////////////////////////////////////// + + terminal_ledger_web(&terminal_dev_map,codes,g_front_seg_index,g_front_seg_num); + codes.clear(); + + // + //printTerminalDevMap(terminal_dev_map); + + count_cfg = terminal_dev_map.size();//̨˵ + + std::cout << "terminal_ledger_num:" << count_cfg << std::endl; + + g_node->n_clients = count_cfg; //̨ռ + g_node->clients = (ied_t**)apr_pcalloc(g_cfg_pool, count_cfg * sizeof(ied_t*)); + for (int k = 0; k < count_cfg; k++) + g_node->clients[k] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + +//ȡն̨˱滻Ϊwebӿ +////////////////////////////////////////////////////////////////////////////////////////////////// + // + try { + char terminal_id[64]; + char terminal_code[64]; + char org_name[64]; + char maint_name[64]; + char station_name[64]; + char tmnl_factory[64]; + char tmnl_status[64]; + char dev_type[64]; + char dev_key[255]; + char dev_series[255]; + char addr_str[64]; + char port_char[64]; + otl_datetime timestamp; + + // ն̨ + QMap::iterator it; + for (it = terminal_dev_map.begin(); it != terminal_dev_map.end(); ++it) { + terminal_dev* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + strncpy(terminal_id, value->terminal_id, sizeof(terminal_id) - 1); + strncpy(terminal_code, value->terminal_code, sizeof(terminal_code) - 1); + strncpy(org_name, value->org_name, sizeof(org_name) - 1); + strncpy(maint_name, value->maint_name, sizeof(maint_name) - 1); + strncpy(station_name, value->station_name, sizeof(station_name) - 1); + strncpy(tmnl_factory, value->tmnl_factory, sizeof(tmnl_factory) - 1); + strncpy(tmnl_status, value->tmnl_status, sizeof(tmnl_status) - 1); + strncpy(dev_type, value->dev_type, sizeof(dev_type) - 1); + strncpy(dev_key, value->dev_key, sizeof(dev_key) - 1); + strncpy(dev_series, value->dev_series, sizeof(dev_series) - 1); + strncpy(addr_str, value->addr_str, sizeof(addr_str) - 1); + strncpy(port_char, value->port, sizeof(port_char) - 1); + timestamp = parseTimestamp(value->timestamp); + + //ն̨ + ied = g_node->clients[count_real++]; + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + + if (ied_usr == NULL) + return APR_ENOMEM; + + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + ied->cpucount = 0; + + if (strlen(terminal_id) != 0) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id + cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl; + } + if (terminal_code != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code + cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl; + } + /*ҪϢ + if (org_name != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name + cout << "ied_usr->org_name:" << ied_usr->org_name << endl; + + } + if (maint_name != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name + cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl; + + } + if (station_name != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name + cout << "ied_usr->station_name:" << ied_usr->station_name << endl; + } + */ + if (tmnl_factory != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory + cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl; + } + if (tmnl_status != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status + cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl; + } + if (dev_type != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type + cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl; + } + if (dev_series != NULL) { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", dev_series);//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + else + { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + if (dev_key != NULL) { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", dev_key);//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + } + else + { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + } + + //lnk20241125ʵʱ + ied_usr->dev_idx = count_real; + cout << "dev_idx:" << ied_usr->dev_idx << endl; + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + if (addr_str != NULL) { + ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + } + else + { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + } + if (port_char != NULL) { + int port = 102; + if (stringToInt(port_char, &port)) { + // תɹportStrȫΪ֣ѾתΪint͵port + ied->channel[0].port = port;//DEV_PortID + cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID + } + else { + ied->channel[0].port = 102;//DEV_PortID + cout << "ied_usr->port:" << port_char << ",ǺϷ˿.ʹĬ϶˿:" << ied->channel[0].port << endl;//DEV_PortID + } + } + if (timestamp.year != 0) { + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + time_t time = std::mktime(&timeinfo); + ied_usr->time = static_cast(time); + cout << "ied_usr->time:" << ied_usr->time << endl; + } + + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + // + //std::cout << "value:" << terminal_id <<" "<n_clients << std::endl; + + if (g_node->n_clients <= 0) { + std::cout << "no terminal exist " << std::endl; + return APR_EBADF; + } + + char monitor_id[64]; + //char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + char monitor_status[64]; + //otl_datetime timestamp; + + //for (int j = 0; j < 10; ++j) { // 10 + for (int j = 0; value->line[j].monitor_id[0] != '\0'; ++j){ + ledger_monitor& monitor = value->line[j]; + + // ID ǷΪԱЧ + /*if (monitor.monitor_id[0] != '\0') { + std::cout << " Monitor ID: " << monitor.monitor_id << std::endl; + std::cout << " Terminal Code: " << monitor.terminal_code << std::endl; //ӦΪգjson + std::cout << " Monitor Name: " << monitor.monitor_name << std::endl; + std::cout << " Logical Device Seq: " << monitor.logical_device_seq << std::endl; + std::cout << " Voltage Level: " << monitor.voltage_level << std::endl; + std::cout << " Terminal Connect: " << monitor.terminal_connect << std::endl; + std::cout << " Timestamp: " << monitor.timestamp << std::endl; //ӦΪjson + std::cout << " monitor_status: " << monitor.status << std::endl;*/ + + strncpy(monitor_id, monitor.monitor_id, sizeof(monitor_id) - 1); + //strncpy(terminal_code, monitor.terminal_code, sizeof(terminal_code) - 1); //ϼȡ + strncpy(monitor_name, monitor.monitor_name, sizeof(monitor_name) - 1); + strncpy(logical_device_seq, monitor.logical_device_seq, sizeof(logical_device_seq) - 1); + strncpy(voltage_level, monitor.voltage_level, sizeof(voltage_level) - 1); + strncpy(terminal_connect, monitor.terminal_connect, sizeof(terminal_connect) - 1); + //timestamp = parseTimestamp(monitor.timestamp); //ϼȡ + strncpy(monitor_status, monitor.status, sizeof(monitor_status) - 1);//Ӽ״̬ + //̨˴ + count_real_monitor++; + + memset(&line_info, 0, sizeof(line_info)); + + line_info.line_id = count_real_monitor; //ź + cout << "line_id:" << line_info.line_id << endl; + + strcpy(line_info.mp_id, monitor_id); + cout << "mp_id:" << line_info.mp_id << endl; + + strcpy(line_info.terminal_code, terminal_code); //ϼȡն˺ + cout << "terminal_code:" << line_info.terminal_code << endl; + + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; //Ĭϼʵ1 + cout << "logical_device_seq:is null,set cpuno:"<< line_info.cpuno << endl; + } + else { + line_info.cpuno = std::atoi(logical_device_seq); + cout << "logical_device_seq:"<< line_info.cpuno << endl; + } + //cout << "cpuno:" << line_info.cpuno << endl; + + strcpy(line_info.voltage_level, voltage_level); + cout << "voltage_level:" << line_info.voltage_level << endl; + + strcpy(line_info.v_wiring_type, terminal_connect); + cout << "v_wiring_type:" << line_info.v_wiring_type << endl; + + strcpy(line_info.monitor_status, monitor_status); + cout << "monitor_status:" << line_info.monitor_status << endl; + + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 //ϼȡtimestamp + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t time = std::mktime(&timeinfo); + line_info.time = static_cast(time); + cout << "time:" << line_info.time << endl; + + strcpy(line_info.name, monitor_name); + cout << "name:" << line_info.name << endl; + + line_info.read_flag = 1; //Ч + + //ied = find_ied_from_dev_code(line_info.terminal_code); //ҪϼնˣѾն + + if (ied && ied->usr_ext && line_info.cpuno && (static_cast(line_info.cpuno) < 10)) { + char str[256]; + byte_t cpuno = line_info.cpuno; + + cout << "cpuno:" << line_info.cpuno << endl; + cout << "index cpuno:" << cpuno-1 << endl; + + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; //cpunoĬ1 + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + cout << "rptcount:" << ied_usr->LD_info[cpuno - 1].rptcount << endl; + + if (cpuno > ied->cpucount) { + ied->cpucount = cpuno; + } + } + //} + } + } + } +////////////////////////////////////////////////////////////////////////////////////////////////// +#if 0 + ied = g_node->clients[count_real++]; + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + + if (ied_usr == NULL) + return APR_ENOMEM; + + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + ied->cpucount = 0; + + if (strlen(terminal_id) != 0) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", terminal_id);//terminal_id + cout << "ied_usr->terminal_id:" << ied_usr->terminal_id << endl; + } + if (terminal_code != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", terminal_code);//terminal_code + cout << "ied_usr->terminal_code:" << ied_usr->terminal_code << endl; + + } +/*ҪϢ + if (org_name != NULL) { + apr_snprintf(ied_usr->org_name, sizeof(ied_usr->org_name), "%s", org_name);//org_name + cout << "ied_usr->org_name:" << ied_usr->org_name << endl; + + } + if (maint_name != NULL) { + apr_snprintf(ied_usr->maint_name, sizeof(ied_usr->maint_name), "%s", maint_name);//maint_name + cout << "ied_usr->maint_name:" << ied_usr->maint_name << endl; + + } + if (station_name != NULL) { + apr_snprintf(ied_usr->station_name, sizeof(ied_usr->station_name), "%s", station_name);//station_name + cout << "ied_usr->station_name:" << ied_usr->station_name << endl; + } + */ + if (tmnl_factory != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", tmnl_factory);//tmnl_factory + cout << "ied_usr->tmnl_factory:" << ied_usr->tmnl_factory << endl; + + } + if (tmnl_status != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", tmnl_status);//tmnl_status + cout << "ied_usr->tmnl_status:" << ied_usr->tmnl_status << endl; + } + if (dev_type != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", dev_type);//dev_type + cout << "ied_usr->dev_type:" << ied_usr->dev_type << endl; + } + if (dev_series != NULL) { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", dev_seri);//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + else + { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + } + if (dev_key != NULL) { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", dev_key);//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + } + else + { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + } + +//ϲ +/* cout << "code" << ied_usr->terminal_code << endl; + if (terminal_ext_map.contains(QString::fromUtf8(ied_usr->terminal_code))) { + terminal_ext* ext = terminal_ext_map.value(QString::fromUtf8(ied_usr->terminal_code)); + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ext->terminal_key);//DEV_Key + cout << "dev_key:" << ied_usr->dev_key << endl; + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ext->terminal_identify_code);//DEV_Series + cout << "dev_series:" << ied_usr->dev_series << endl; + } + else + { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key + cout << "defalut dev_key:" << ied_usr->dev_key << endl; + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", "");//DEV_Series + cout << "defalut dev_series:" << ied_usr->dev_series << endl; + }*/ + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4;//channel + ied->channel[0].addr_str[LONGNAME - 1] = 0;//DEV_IP + if (addr_str != NULL) { + ied->channel[0].addr = ntohl(inet_addr(addr_str));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + } + else + { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.0"));//DEV_IP + strncpy(ied->channel[0].addr_str, addr_str, LONGNAME - 1);//DEV_IP + cout << "ied_usr->addr_str:" << ied->channel[0].addr_str << endl; + } + if (port_char != NULL) { + int port = 102; + if (stringToInt(port_char, &port)) { + // תɹportStrȫΪ֣ѾתΪint͵port + ied->channel[0].port = port;//DEV_PortID + cout << "ied_usr->port:" << ied->channel[0].port << endl;//DEV_PortID + } + else { + ied->channel[0].port = 102;//DEV_PortID + cout << "ied_usr->port:" << port_char << ",ǺϷ˿.ʹĬ϶˿:" << ied->channel[0].port << endl;//DEV_PortID + } + } + if (timestamp.year != 0) { + //// struct tm + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + time_t time = std::mktime(&timeinfo); + ied_usr->time = static_cast(time); + cout << "ied_usr->time:" << ied_usr->time << endl; + } + + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + // + std::cout << "value:" << terminal_id <<" "<n_clients = count_real; + if (count_cfg != count_real) + return APR_EBADF; + cout << "dev init create count:" << count_real; + return APR_SUCCESS; + } + catch (otl_exception& e) + { + printf("\ndev tr\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } +} + +int parse_model_web(QMap* icd_model_map,const std::vector& codes) +{ + std::string parm = codes[0]; //װͺбʽ["ͺ1","ͺ2"...] + + char* ptr=NULL; + + //url + //SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr); + SendJsonAPI_web(WEB_ICD,"",parm.c_str(),&ptr); + + // ptr ǷΪ NULL std::string ʼʧ + if (ptr == NULL) { + // ptr Ϊ NULL ־¼ + std::cout << "Error: Received NULL response"<< std::endl; + return 1; + } + + // + printf("ptr:%s\n",ptr); + + cJSON* root = cJSON_Parse(ptr); //jsonʽл + + int retry = 0; + + if (root == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + + //ط + while(root == NULL){ + // ǰͷ֮ǰ ptr Աڴй© + if (ptr != NULL) { + free(ptr); + ptr = NULL; + } + //url + //SendJsonAPI_web("http://192.168.1.149:8091/powerQuality/getProperties", parm.c_str(), "",&ptr); + SendJsonAPI_web(WEB_ICD,"",parm.c_str(),&ptr); + if(ptr == NULL){ + retry++;if(retry>3)break; + continue; + } + root = cJSON_Parse(ptr); + retry++;if(retry>3)break; + } + if (root == NULL) { + printf("web error %s\n", cJSON_GetErrorPtr()); + return 1; + } + } + + cJSON* codeItem = cJSON_GetObjectItem(root, "code"); + cJSON* msgItem = cJSON_GetObjectItem(root, "msg"); + + // ʹ std::string ȡֵ + std::string code = (codeItem != NULL) ? codeItem->valuestring : "not found"; + std::string msg = (msgItem != NULL) ? msgItem->valuestring : "not found"; + + // ӡ + std::cout << "code: " << code << std::endl; + std::cout << "msg: " << msg << std::endl; + + cJSON* data = cJSON_GetObjectItem(root, "data"); + if (data && data->type == cJSON_Array) { + cJSON* item; + cJSON_ArrayForEach(item, data) { + icd_model* model = new icd_model; + + cJSON* id = cJSON_GetObjectItem(item, "id");//model_id + if (id && id->type == cJSON_String) strncpy(model->model_id, id->valuestring, sizeof(model->model_id) - 1); + + cJSON* fileName = cJSON_GetObjectItem(item, "fileName");//file_name + if (fileName && fileName->type == cJSON_String) strncpy(model->file_name, fileName->valuestring, sizeof(model->file_name) - 1); + + cJSON* filePath = cJSON_GetObjectItem(item, "filePath");// + if (filePath && filePath->type == cJSON_String) strncpy(model->file_path, filePath->valuestring, sizeof(model->file_path) - 1); + + cJSON* devType = cJSON_GetObjectItem(item, "devType");//tmnl_type + if (devType && devType->type == cJSON_String) strncpy(model->tmnl_type, devType->valuestring, sizeof(model->tmnl_type) - 1); + + cJSON* updateTime = cJSON_GetObjectItem(item, "updateTime");//timestamp + if (updateTime && updateTime->type == cJSON_String) strncpy(model->timestamp, updateTime->valuestring, sizeof(model->timestamp) - 1); + + // ӵ QMap + icd_model_map->insert(model->model_id, model); + } + } + + cJSON_Delete(root); + free(ptr); // SendJsonAPI_web ڴ棬ǵͷ + + return 0; // ȷзֵ +} + +int parse_model_cfg_web() +{ + std::vector codes;//μ + QMap icd_model_map; +///////////////////////////////////////////////////////////////////////// + // + //codes.push_back("code1=model1"); //նͺб + + //ʹжͺбjsonַ + // ǰм + ied_t* ied; + ied_usr_t* ied_usr; + std::cout << "g_node->n_clients" << g_node->n_clients << std::endl; + std::set devTypes; // ȥصļset + + for (int t = 0; t < g_node->n_clients; t++) { + ied = (ied_t*)g_node->clients[t]; + ied_usr = (ied_usr_t*)ied->usr_ext; + + // dev_type һַͣ뼯 ,ȥ + if (strlen(ied_usr->dev_type) > 0) { + devTypes.insert(std::string(ied_usr->dev_type)); + } + } + + // ֶ JSON ַ + std::string input_jstr = "["; + bool first = true; // ڴ + + for (std::set::iterator it = devTypes.begin(); it != devTypes.end(); ++it) { + if (!first) { + input_jstr += ","; // Ӷ + } + first = false; // һ֮Ϊ false + input_jstr += "\"" + *it + "\""; // ַ + } + + input_jstr += "]"; // JSON + std::cout << "input_jstr: " << input_jstr << std::endl; // + + if(ICD_FLAG == "1"){ + codes.push_back(input_jstr); //նͺб-ȡָicdļ + } + else{ + codes.push_back("[]"); //-ȡеicdļ + } + +///////////////////////////////////////////////////////////////////////// + parse_model_web(&icd_model_map,codes); + + codes.clear(); + + try { + char model_id[64]; + char tmnl_type[64]; + //char tmnl_factory[64]; + char file_name[128]; + char file_path[128]; + //char timestamp[64]; + otl_datetime timestamp; + + // ն̨ + QMap::iterator it; + for (it = icd_model_map.begin(); it != icd_model_map.end(); ++it) { + icd_model* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + strncpy(model_id, value->model_id, sizeof(model_id) - 1); + strncpy(tmnl_type, value->tmnl_type, sizeof(tmnl_type) - 1); + strncpy(file_path, value->file_path, sizeof(file_path) - 1); + strncpy(file_name, value->file_name, sizeof(file_name) - 1); + //strncpy(timestamp, value->timestamp, sizeof(timestamp) - 1); + + std::cout << "model_id" << model_id << std::endl; + std::cout << "tmnl_type" << tmnl_type << std::endl; + std::cout << "filepath" << file_path << std::endl; + std::cout << "filename" << file_name << std::endl; + + //lnk20241125 + //strncpy(tmnl_type, "PS_NET", sizeof(tmnl_type) - 1); + + Set_xml_databaseinfo(model_id, tmnl_type, file_path, file_name, timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second); + } + } + return APR_SUCCESS; + } + catch (otl_exception& e) + { + printf("\nicd model\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return e.code; + } +} + +//Զнӿڣݲ޸ģܲʹ +#if 0 +bool CheckPG_To_Recall_web(long long start, long long end, char* Monitorid) +{ + QDateTime deltime_Qtime = QDateTime::fromTime_t(start); + QDateTime deltime_Qtime_end = QDateTime::fromTime_t(end); + QString tmp_chr1 = deltime_Qtime.toString("yyyy-MM-dd"); //ǰ + QString start_chr1 = deltime_Qtime.toString("yyyy-MM-dd hh:mm:ss"); //ǰ + QString end_chr1 = deltime_Qtime_end.toString("yyyy-MM-dd hh:mm:ss"); //ǰ + + int timespan = 3;//Ĭʱ + + try { + + std::vector codes;//μ + QMap intact_list_map; + + codes.push_back("deciderecall"); + codes.push_back(tmp_chr1.toStdString()); + codes.push_back(std::string(Monitorid)); + + parse_intact_web_test_read(&intact_list_map,codes); + + codes.clear(); + + try { + + double exp_num; + double act_num; + + // ն̨ + QMap::iterator it; + for (it = intact_list_map.begin(); it != intact_list_map.end(); ++it) { + intact_list* value = it.value(); + + // ȷ value Ϊ + if (value != nullptr) { + // ҵжӦƲȡֵ + + exp_num = atof(value->exp_num); + act_num = atof(value->act_num); + + std::cout << exp_num << " " << act_num << std::endl; + + timespan = 1440 / exp_num; + printf("\n %f %f %d \n", exp_num, act_num, timespan); + } + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + //OTLDisconnect(); + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + + try { + long long starttime = start; //ʼʱ + long long endtime = starttime + 3599; //нʱ + QList timestamp_list; //ݿԼ¼ʱ + QList recallinfo_list; //ж + QList recallinfo_list_hour; //ж-СʱΪ + + std::vector codes;//μ + QMap intact_list_map; + codes.push_back("handlerecall"); + codes.push_back(tmp_chr1.toStdString()); + codes.push_back(std::string(Monitorid)); + codes.push_back(start_chr1.toStdString()); + codes.push_back(end_chr1.toStdString()); + + parse_intact_web_test_read(&intact_list_map,codes); + + codes.clear(); + + try { + otl_datetime timestamp; + + // ն̨ + if (intact_list_map.contains(Monitorid)) { + intact_list* value = intact_list_map.value(Monitorid); // ҵֵΪ "id" Ķ + + if (value != nullptr) { + // value_time ʱַ + for (std::vector::const_iterator it = value->value_time.begin(); it != value->value_time.end(); ++it) { + const std::string& time = *it; + + std::cout << "Time: " << time << std::endl; + + timestamp = parseTimestamp(time); + + struct tm timeinfo; + timeinfo.tm_year = timestamp.year - 1900; // Ҫȥ1900 + timeinfo.tm_mon = timestamp.month - 1; // ·Ҫȥ1 + timeinfo.tm_mday = timestamp.day; + timeinfo.tm_hour = timestamp.hour; + timeinfo.tm_min = timestamp.minute; + timeinfo.tm_sec = timestamp.second; + + time_t timestamp = std::mktime(&timeinfo); + long long stamp = static_cast(timestamp); + timestamp_list.append(stamp); + } + } + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + //OTLDisconnect(); + + if (timestamp_list.size() <= (60 / timespan) * 0.97) //ݱ + { + printf("\n return ture %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97); + return true; + } + else + { + printf("\n return false %d %f\n", timestamp_list.size(), (60 / timespan) * 0.97); + return false; + } + } + catch (otl_exception& e) + { + printf("\nPostgreSL\"%s\"select error,ERROR code= %d,msg= %s \n", g_strOTLConnect.c_str(), e.code, e.msg); + return false; + } + printf("\n>>>error quit!!\n"); + return true; +} +#endif +//ʱҪʱ־һЩܣͳһ޸ +void OnTimerThread::run() +{ + msleep(10000); + printf("OnTimerThread::run() is called ...... \n"); + + bool account_update = true; + bool asd = true; + + //ǰʱȡ + apr_time_t previousTime = apr_time_now();// + apr_time_exp_t localTime; + apr_time_exp_gmt(&localTime, previousTime); + cout << "Local Time: " + << localTime.tm_year + 1900 << "-" << localTime.tm_mon + 1 << "-" << localTime.tm_mday << " " + << localTime.tm_hour << ":" << localTime.tm_min << ":" << localTime.tm_sec + << endl; + + //webֶеḶ̌ǰӵն + int ip_count = 0; + int telnet_count = 0; + if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) { + //ڲʱ̨˼lnk20250114 + pthread_mutex_lock(&mtx); + init_ping_telnet(ip_count, telnet_count); + Cout_account_information(); + pthread_mutex_unlock(&mtx);// + } + + //ģʽ + if (g_onlyIP[0] != 0) + { + printf("g_onlyIP[0]=!0 ontimer--%s--\n", g_onlyIP); + add_comm_log(const_cast("g_onlyIP[0]=!0,g_onlyIP is --%s--", g_onlyIP)); + } + else + { + printf("g_onlyIP[0] == 0!"); + } + + int pgflag = 0; + int pgmin = 0; + int mp_num_hour = 0; + int recall_flag1 = 1; //б־ + + // + std::vector codes; + + while (1) + { + //߳ʱ + previousTime = apr_time_now(); + apr_time_exp_gmt(&localTime, previousTime); + + if (strcmp(subdir, "cfg_stat_data") == 0 || strcmp(subdir, "cfg_newhis_data") == 0) {//̨˸,ڵ,ͨѶ + + //Ҫǰñ + /*//жִдʱǷ 񱻶 + if (MULTIPLE_NODE_FLAG && pgflag) { + if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + + + codes.push_back("updatefront"); + codes.push_back(std::string(FRONT_IP)); + codes.push_back(intToString(FRONT_INST)); + codes.push_back(intToString(FRONT_MP_NUM)); + codes.push_back(std::string(PROGRAM_VERSION)); + parse_device_web_test_front_write(codes); + codes.clear(); + + } + pgflag = 0; + } + else if (MULTIPLE_NODE_FLAG && pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + }*/ + + //־¼ + if (mp_num_hour != localTime.tm_hour) { + pthread_mutex_lock(&mtx);//lnk20250114 + std::string mp_num_str = ""; + mp_num_str.append("connected device count:"); + mp_num_str.append(QString::number(FRONT_MP_NUM).toStdString()); + mp_num_str.append(",g_node clients:"); + mp_num_str.append(QString::number(g_node->n_clients).toStdString()); + + add_comm_log(const_cast(mp_num_str.c_str())); + mp_num_hour = localTime.tm_hour; + pthread_mutex_unlock(&mtx);// + } + + } +//ʹõĴlnk20241206 +#if 0 + if (strcmp(subdir, "cfg_newhis_data") == 0) {//Ϻʱװ־ + static int hour_time = 0; + if (localTime.tm_hour != hour_time) { + hour_time = localTime.tm_hour; + + printf(">>>cfg_newhis_data is run!!!\n"); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + long long start = stamp - (stamp % 3600) - 3600 - 3600;//ʼʱ ǰֵǰСʱ + long long end = start + 3599;//ʱ + + QList recallinfo_list_hour; + RecallInfo info; + info.starttime = start - 10; + info.endtime = end; + recallinfo_list_hour.append(info); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + + i++; + } + } + } + + //ȫнͨweb·ֶݿ + if (strcmp(subdir, "cfg_recallall_data") == 0) + { + static int recall_xml_time = 0; + if (localTime.tm_min != recall_xml_time) + { + recall_xml_time = localTime.tm_min; + //пʼֹʱ + static long long recall_start_time = 0; + static long long recall_end_time = 0; + static int flag = 0; + if (recall_start_time == 0 && recall_end_time == 0) {//޻ + //ѯһ -1״̬()ļ¼ + char front_ip[42]; + cout << "start select:" << endl; + + QMap front_map; + codes.push_back("frontip"); + codes.push_back("g_front_seg_index"); + codes.push_back("-1"); + parse_device_web_test_front_read(&front_map,codes); + codes.clear(); + // QMap + QMap::iterator it; + for (it = front_map.begin(); it != front_map.end(); ++it) { + front_list* value = it.value(); + // ȷ value Ϊ + if (value != nullptr) { + // value жȡ front_ip + strncpy(front_ip, value->front_ip, sizeof(front_ip) - 1); + //Ӧֻһ¼ + std::cout << "front_ip:" <::iterator it; + for (it = front_map.begin(); it != front_map.end(); ++it) { + front_list* value = it.value(); + // ȷ value Ϊ + if (value != nullptr) { + // value жȡ front_ip + strncpy(front_status, value->front_status, sizeof(front_status) - 1); + //Ӧֻһ¼ + std::cout << "front_status:" < duration) { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].endtime; + + RecallInfo info; + info.starttime = start; + info.endtime = end; + recallinfo_list_hour.append(info); + } + else { + long long start = recallinfo_list[i].starttime + j; + long long end = recallinfo_list[i].starttime + j + max_interval; + + RecallInfo info; + info.starttime = start; + info.endtime = end - 1; + recallinfo_list_hour.append(info); + } + } + } + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + printf("/home/pq mpid=%s %d\n", LD_info->mp_id, LD_info->read_flag); + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) { + continue; + } + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + g_StatisticLackList_list_mutex.lock(); + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + +//滻webӿ 2024-10-21 lnk + // if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + // printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + + continue; + } + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList.push_back(jr); + + } + g_StatisticLackList_list_mutex.unlock(); + } + } + i++; + } + } + } + } + + //ԶпܸΪwebѯ· + if (strcmp(subdir, "cfg_his_data") == 0) + { + if (pgflag) { + + //ǰҪʵʱǰñӦļ + /*if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + codes.push_back("his"); + codes.push_back("his"); //ip + codes.push_back(std::string(PROGRAM_VERSION)); + codes.push_back(intToString(FRONT_MP_NUM)); // + parse_device_web_test_front_write(codes); + codes.clear(); + }*/ + + pgflag = 0; + } + else if (pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + + static int cfg_his_data_hour_time = 0; + if (localTime.tm_hour != cfg_his_data_hour_time) { + cfg_his_data_hour_time = localTime.tm_hour; + + printf(">>>cfg_his_data is run!!!\n"); + long long stamp = static_cast(previousTime) / 1000000; + cout << ">>>>>>>>>The Time is: " << stamp << endl; + long long start = stamp - (stamp % 3600) - 3600 - 3600;//ʼʱ ǰֵǰСʱ + long long end = start + 3599;//ʱ + + QList recallinfo_list_hour; + RecallInfo info; + info.starttime = start - 10; + info.endtime = end; + recallinfo_list_hour.append(info); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + //if (chnl_usr->m_state == CHANNEL_CONNECTED) { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + cpuno++; + if (LD_info->logcount <= 0 || LD_info->read_flag == 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + + if (recallinfo_list_hour.size() != 0) { + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + +//滻webӿ 2024-10-21 lnk + //if (CheckPG_To_Recall(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + //printf("CheckPG_To_Recall == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + if (CheckPG_To_Recall_web(recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id) == false) { + printf("CheckPG_To_Recall_web == false %d-%d %s\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime, LD_info->mp_id); + + continue; + } + CJournalRecall jr; + jr.MonitorID = QString(LD_info->mp_id); + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + jr.STEADY = QString::number(1, 10); + jr.VOLTAGE = QString::number(1, 10); + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + i++; + } + } + } +#endif + //webcfg_recallhis_dataʱһרõĶ˿ڣû + if (strcmp(subdir, "cfg_recallhis_data") == 0) + { + if (pgflag) { + + //ǰҪʵʱǰñӦļ + /*if (FRONT_INST != 0 && FRONT_IP[0] != '\0') { + codes.push_back("his"); + codes.push_back("recallhis"); //ip + codes.push_back(std::string(PROGRAM_VERSION)); + codes.push_back(intToString(FRONT_MP_NUM)); // + parse_device_web_test_front_write(codes); + codes.clear(); + }*/ + pgflag = 0; + } + else if (pgmin != localTime.tm_min) + { + pgmin = localTime.tm_min; + pgflag = 1; + } + } + +//ʹõĴlnk20241206 +#if 0 + //Զд + if (0 && g_node_id == HIS_DATA_BASE_NODE_ID && (localTime.tm_hour <= 12 || localTime.tm_hour >= 20) && recall_flag1 == 1) { + recall_flag1 = 0; + QString MyKafkaIniFilename = QString("../etc/") + QString("mykafka.ini"); //+QString::fromAscii(subdir) + QSettings settings(MyKafkaIniFilename, QSettings::IniFormat); + + QString dateString = settings.value("Recall/select_day").toString(); + + QList recallinfo_list_hour; + QByteArray byteArray = dateString.toUtf8(); // ʹ UTF-8 + char* charArray = byteArray.data(); + Get_Recall_Time(charArray, recallinfo_list_hour); + + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info->logcount <= 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); + printf("\n %d ===== %d\n", recallinfo_list_hour.size(), LD_info->autorecallflag); + if (recallinfo_list_hour.size() != 0) { + if (LD_info->autorecallcount != 0) { + for (int j = 0; j < LD_info->autorecallcount; j++) { + delete LD_info->autorecall[j]; + } + delete LD_info->autorecall; + LD_info->autorecallcount = 0; + } + LD_info->autorecallflag = 0; + LD_info->autorecallcount = recallinfo_list_hour.size(); + LD_info->autorecall = new autorecall_t * [recallinfo_list_hour.size()]; + printf("/home/pq recall mpid=%s\n", LD_info->mp_id); + + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + printf("\n %lld ===== %11d\n", recallinfo_list_hour[j].starttime, recallinfo_list_hour[j].endtime); + LD_info->autorecall[j] = new autorecall_t[1]; + LD_info->autorecall[j]->start = recallinfo_list_hour[j].starttime; + + LD_info->autorecall[j]->end = recallinfo_list_hour[j].endtime; + } + } + cpuno++; + } + i++; + } + + QDate date = QDate::fromString(dateString, "yyyy-MM-dd"); + date.addDays(-1); // һ + settings.setValue("Recall/select_day", date.toString("yyyy-MM-dd")); // дַ + } +#endif + if (localTime.tm_hour > 12 && localTime.tm_hour < 20 && recall_flag1 == 0) { + recall_flag1 = 1; + } + msleep(1000); + } + printf(">>>OnTimerThread::run() is end!!!\n"); +} + +//web +/*int HandleRecall_http(const httplib::Request& req, httplib::Response& res) //ղWebͻ˷Ϣ +{ + // ӡIJѯ + std::cout << "Query parameters: " << std::endl; + + if (req.body.empty()) { + res.status = 400; // 400 Bad Request + res.set_content("Missing code or parameter", "application/json"); + return 10000; + } + + std::cout << "Received code: " << req.body<< std::endl; + + try + { + printf("webͻϢ\n"); + cJSON* json_root = cJSON_Parse(req.body.c_str()); //jsonʽл //һ + if (json_root == NULL) { + return 10000; + }*/ +int recall_json_handle(const char* jstr) +{ + //ָ̬/̬ȫ + int stat = 0; // + int voltage= 0; + try{ + + std::vector recallParams; + cJSON* json_root = cJSON_Parse(jstr); //jsonʽл //һ + if (json_root == NULL) { + std::cout << "json root"<< std::endl; + return 10000; + } + /*cJSON* json_code = NULL; + cJSON* json_msg = NULL; + + std::vector recallParams; + + json_code = cJSON_GetObjectItem(json_root, "code"); //ȡcode + if (json_code != NULL) { + std::cout << "Received code: " << json_code->valuestring << std::endl; + } + else { + return 10000; + } + json_msg = cJSON_GetObjectItem(json_root, "msg"); //ȡmsg + if (json_code != NULL) { + std::cout << "Received msg: " << json_msg->valuestring << std::endl; + } + else { + return 10000; + }*/ + // ȡ "data" + //cJSON* dataArray = cJSON_GetObjectItem(json_root, "data"); + + // ÿ + if (json_root->type == cJSON_Array) { + for (cJSON* item = json_root->child; item != nullptr; item = item->next) { + // ȡ monitorId + cJSON* monitorIdArray = cJSON_GetObjectItem(item, "monitorId"); + cJSON* timeIntervalArray = cJSON_GetObjectItem(item, "timeInterval"); + //жdataTypeǷΪ + cJSON* datatype = cJSON_GetObjectItem(item, "dataType"); + + //쳣жϷֹ + if(monitorIdArray == NULL || timeIntervalArray == NULL || datatype == NULL ){ + std::cout << "jsonݽ "<< std::endl; + return 10000; + } + + if(strcmp(datatype->valuestring, "") != 0)//ǿ + { + stat = (strcmp(datatype->valuestring, "0") == 0) ? 1 : 0;//̬ + voltage= (strcmp(datatype->valuestring, "1") == 0) ? 1 : 0;//̬ + } + else //ջ + { + stat = 1; + voltage= 1; + } + + // + if(monitorIdArray != nullptr && monitorIdArray->child != nullptr)std::cout << "monitorIdArrayijԱΪ"<< monitorIdArray->child->valuestring << std::endl; + if(monitorIdArray != nullptr && monitorIdArray->child == nullptr)std::cout << "monitorIdArrayûгԱ"<< std::endl; + + //monitorIdArrayݵ + if (monitorIdArray != nullptr && monitorIdArray->type == cJSON_Array && timeIntervalArray->type == cJSON_Array && monitorIdArray->child != nullptr) { + // monitorId + for (cJSON* idItem = monitorIdArray->child; idItem != nullptr; idItem = idItem->next) { + QString monitorId = QString(idItem->valuestring); + + //жеǰǷڱ20241230ַֹDZ̵ļ㴥 + int mppair = 0; + ied_t* ied; + ied_usr_t* ied_usr; + for (int t = 0; t < g_node->n_clients; t++){ + ied = (ied_t*)g_node->clients[t]; + ied_usr = (ied_usr_t*)ied->usr_ext; + for (int m = 0; m<10; m++){//10 + + if(strcmp(ied_usr->LD_info[m].mp_id,"") == 0)continue;//յ + + if(strcmp(ied_usr->LD_info[m].mp_id,monitorId.toStdString().c_str()) == 0){//ƥ + + mppair = 1; + break;//ҵ˳ѭ + } + + } + if(mppair == 1)break;//ҵ˳նѭ + } + if(mppair == 0)continue;//ǰ̵ļ㶼ûҵţ˵DZ̵ļ㣬һ + // + std::cout << "find mpid:" << monitorId.toStdString() << "in this process,mppair=" << mppair <child; timeItem != nullptr; timeItem = timeItem->next) { + QString timeInterval = QString(timeItem->valuestring); + QString start = timeInterval.left(timeInterval.indexOf("~")); + QString end = timeInterval.mid(timeInterval.indexOf("~") + 1); + + // RecallParam ӵб + + RecallParam param; + param.mp_id = monitorId; + param.start = start; + param.end = end; + param.stat = stat; + param.voltage = voltage; + recallParams.push_back(param); + } + } + } + //monitorIdArrayΪյ + else if (monitorIdArray != nullptr && monitorIdArray->type == cJSON_Array && monitorIdArray->child == nullptr) { + // monitorIdArray Ϊ + std::cout << "monitorIdArray is null" << std::endl; + //м㲹 + // ǰм + ied_t* ied; + ied_usr_t* ied_usr; + std::cout << "g_node->n_clients" << g_node->n_clients << std::endl; + for (int t = 0; t < g_node->n_clients; t++){ + ied = (ied_t*)g_node->clients[t]; + ied_usr = (ied_usr_t*)ied->usr_ext; + for (int m = 0; m<10; m++){ + + if(strcmp(ied_usr->LD_info[m].mp_id,"") == 0)continue; + std::cout << "ied_usr->LD_info[m].mp_id" << m << " "<< ied_usr->LD_info[m].mp_id << std::endl; + QString monitorId = QString(ied_usr->LD_info[m].mp_id); + + // timeInterval + for (cJSON* timeItem = timeIntervalArray->child; timeItem != nullptr; timeItem = timeItem->next) { + QString timeInterval = QString(timeItem->valuestring); + QString start = timeInterval.left(timeInterval.indexOf("~")); + QString end = timeInterval.mid(timeInterval.indexOf("~") + 1); + + // RecallParam ӵб + RecallParam param; + param.mp_id = monitorId; + param.start = start; + param.end = end; + param.stat = stat; + param.voltage = voltage; + recallParams.push_back(param); + } + } + } + } + else{ + std::cout << "monitorIdArray ڻͲȷ" << std::endl; + } + } + } + cJSON_Delete(json_root); //webδ + //ȡв + for (std::vector::iterator it = recallParams.begin(); it != recallParams.end(); ++it) { + + QList recallinfo_list_hour; + char start_time[64]; + char end_time[64]; + QString mp_id; + + mp_id = it->mp_id; + apr_snprintf(start_time, sizeof(start_time), "%s", it->start.toStdString().c_str());//start_time + apr_snprintf(end_time, sizeof(end_time), "%s", it->end.toStdString().c_str());//end_time + + qDebug() << "mp_id" << mp_id << " " << "start_time" << start_time << " " << "end_time" << " " << "stat" << it->stat << " " << "voltage" << it->voltage<< end_time; + + Get_Recall_Time_Char(start_time, end_time, recallinfo_list_hour); + + for (int j = 0; j < recallinfo_list_hour.size(); j++) { + CJournalRecall jr; + jr.MonitorID = mp_id; + jr.StartTime = QDateTime::fromTime_t(recallinfo_list_hour[j].starttime).toString("yyyy-MM-dd hh:mm:ss"); + jr.EndTime = QDateTime::fromTime_t(recallinfo_list_hour[j].endtime).toString("yyyy-MM-dd hh:mm:ss"); + + //̬̬webȡ + //jr.STEADY = QString::number(1, 10); // 1 תΪֵַ + //jr.VOLTAGE = QString::number(1, 10);// 1 תΪֵַ + // + //std::cout << "stat" << it->stat << "voltage" << it->voltage << std::endl; + jr.STEADY = QString::number(it->stat); + jr.VOLTAGE = QString::number(it->voltage); + + g_StatisticLackList_list_mutex.lock(); + g_StatisticLackList.push_back(jr); + g_StatisticLackList_list_mutex.unlock(); + } + } + } + catch (exception& e) + { + printf("ͻ˷͵Ϣԭ%s\n", e.what()); + return 10004; + } + + return 000000; +} + +int rtdata_http(const char* jstr) +{ + +} + +// ⲿhttpÿӣ +#ifdef __cplusplus +extern "C" { +#endif + +void httprun(); +const char* getReceivedData(int fun); +void threadmsgweb(int fun); +bool threadmsghttp(int fun); + +#ifdef __cplusplus +} +#endif +#if 0 +void RecallJsonResponse(int result) { + char* ptr=NULL; + + // JSON + cJSON* json_response = cJSON_CreateObject(); + + // ֶ + if(result == 000000){ + cJSON_AddStringToObject(json_response, "code", "A0000"); + cJSON_AddStringToObject(json_response, "msg", "ݲִгɹ"); + } + else{ + cJSON_AddStringToObject(json_response, "code", "A0002"); + cJSON_AddStringToObject(json_response, "msg", "ݲִʧ"); + } + + cJSON_AddNullToObject(json_response, "data"); // Ϊ null + + // JSON תΪַ + char* json_string = cJSON_Print(json_response); + std::cout << json_string << std::endl; + + //ͻظԷֻһ + SendJsonAPI_web("÷", "", json_string ,&ptr); + + // + cJSON_Delete(json_response); + free(json_string); // ͷŴӡַڴ +} +#endif + +void WebhttpThread::run() +{ + int ret = 1; + printf("WebhttpThread::run() is called ...... \n"); + + while(1){ + + //н + if (!threadmsghttp(1) && g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {//httpһϢ,״̬ΪfalseٴϢhttpʱϢDz߳̿ʼȡ + + const char* data = getReceivedData(1);//httpȡ,ָ + + std::cout << "recall data cfg:" << data <= 0) { + // val ĸ 6 λתΪ Base64 ַӵ + out.push_back(base64_chars[(val >> valb) & 0x3F]); + valb -= 6; // ÿαλƫ 6 λ + } + } + + // ʣλ '=' ַ + while (valb > -6) { + out.push_back('='); + valb -= 6; // ÿһ '='λƫ 6 λ + } + + return out; // رַ +} + +void handleUploadResponse(const std::string& response, char* wavepath) { + + // JSON Ӧ + cJSON* json_data = cJSON_Parse(response.c_str()); + if (json_data == nullptr) { + std::cerr << "Error parsing response: " << cJSON_GetErrorPtr() << std::endl; + return; + } + + // ȡֶ + cJSON* codeItem = cJSON_GetObjectItem(json_data, "code"); + cJSON* msgItem = cJSON_GetObjectItem(json_data, "msg"); + cJSON* dataItem = cJSON_GetObjectItem(json_data, "data"); + + if (codeItem && dataItem) { + std::string code = codeItem->valuestring; + std::cout << "Response Code: " << code << std::endl; + std::string msg = (msgItem != NULL) ? msgItem->valuestring : "not found"; + std::cout << "Message: " << msg << std::endl; + + cJSON* nameItem = cJSON_GetObjectItem(dataItem, "name"); + cJSON* fileNameItem = cJSON_GetObjectItem(dataItem, "fileName"); + cJSON* urlItem = cJSON_GetObjectItem(dataItem, "url"); + + if (nameItem && fileNameItem && urlItem) { + std::string name = nameItem->valuestring; + std::string fileName = fileNameItem->valuestring; + std::string url = urlItem->valuestring; + + // Ϣ + std::cout << "File Path: " << name << std::endl; + std::cout << "Uploaded File Name: " << fileName << std::endl; + std::cout << "File URL: " << url << std::endl; + + //¼صļ·ļ + strcpy(wavepath, nameItem->valuestring); + } + } else { + std::cerr << "Error: Missing expected fields in JSON response." << std::endl; + } + + // ͷ JSON + cJSON_Delete(json_data); +} +//jsonṹ͵ķʽ +/*void SendFileWeb(const std::string& strUrl, const char* localpath, const char* cloudpath, char* wavepath) { + // ӱ·ȡļ + std::ifstream file(localpath, std::ios::binary); + if (!file) { + std::cerr << "Failed to open file: " << localpath << std::endl; + return; + } + + std::ostringstream ss; + ss << file.rdbuf(); + std::string fileContent = ss.str();//ļ + std::string encodedFile = base64_encode(fileContent);//ļ + + // JSON ʵҪ + + cJSON* json_root = cJSON_CreateObject(); + cJSON_AddItemToObject(json_root, "multipartFile", cJSON_CreateString(encodedFile.c_str())); + cJSON_AddItemToObject(json_root, "path", cJSON_CreateString(cloudpath));//Զ· + cJSON_AddItemToObject(json_root, "isReserveName", cJSON_CreateBool(true)); // ֵ + + char* szjson = cJSON_Print(json_root); + std::cout << ">>> json: " << szjson << std::endl; + + // curl ʼ + CURL* curl = curl_easy_init(); + if (curl) { + // Ϊ POST + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, "Content-Type: application/json")); + + // óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + std::string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); // ݽպд뺯 + + // ִ + CURLcode res = curl_easy_perform(curl); + if (res != CURLE_OK) { + std::cerr << "lnk web failed: " << curl_easy_strerror(res) << std::endl; + } else { + std::cout << "lnk web success, response: " << resPost0 << std::endl; + handleUploadResponse(resPost0,wavepath); // Ӧ + } + + // + free(szjson); + } else { + std::cerr << ">>> curl init failed" << std::endl; + } + curl_easy_cleanup(curl); + cJSON_Delete(json_root); +}*/ + +//dataformͷʽ +void SendFileWeb(const std::string& strUrl, const char* localpath, const char* cloudpath, char* wavepath) { + // ʼ curl + CURL* curl = curl_easy_init(); + if (curl) { + // URL POST + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + curl_easy_setopt(curl, CURLOPT_POST, 1); + + // + curl_httppost* formpost = nullptr; + curl_httppost* lastptr = nullptr; + + // ļֶΣֱӴӱ·ȡļ + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "file", + CURLFORM_FILE, localpath, + CURLFORM_END); + + // `path` ֶ + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "path", + CURLFORM_COPYCONTENTS, cloudpath, + CURLFORM_END); + + // `isReserveName` ֶ + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "isReserveName", + CURLFORM_COPYCONTENTS, "true", + CURLFORM_END); + + // ñݵ + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + // ͷϢ + struct curl_slist* header_list = nullptr; + header_list = curl_slist_append(header_list, "Content-Type: multipart/form-data"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + // óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + // дӦݵĺ + std::string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_web); + + // ִ + CURLcode res = curl_easy_perform(curl); + if (res != CURLE_OK) { + std::cerr << "http web failed: " << curl_easy_strerror(res) << std::endl; + } else { + std::cout << "http web success, response: " << resPost0 << std::endl; + handleUploadResponse(resPost0, wavepath); // Ӧ + } + + // + curl_formfree(formpost); // ͷű + curl_slist_free_all(header_list); // ͷͷб + curl_easy_cleanup(curl); + } else { + std::cerr << ">>> curl init failed" << std::endl; + } +} + +void SOEFileWeb(char* localpath,char* cloudpath, char* wavepath) +{ + //ʾipΪʵip + SendFileWeb(WEB_FILEUPLOAD,localpath,cloudpath,wavepath); +} + +void SOEFileWeb_test() +{ + char localpath[128] = {"./file_test.txt"}; + char cloudpath[128] = {"/comtrade/file_test.txt"}; + char wavepath[128] = {""}; + SOEFileWeb(localpath,cloudpath,wavepath); + std::cout << "wavepath" << wavepath << std::endl; +} +/*/////////////////////////////////////////////////////////lnk10-24webӿ޸/////////////////////////////////////////////////////////////*/ +/*װCɵǫ̃˸º *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//3-д̨////////////////////////////// +int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_index) +{ + chnl_usr_t* chnl_usr = NULL; + ied_usr_t* ied_usr = NULL; + ied_usr = (ied_usr_t*)ied->usr_ext; + + // update[i] ед뵽 ied_usr + if (strlen(update[i].terminal_id) != 0) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", update[i].terminal_id); + printf("ied_usr->terminal_id: %s\n", ied_usr->terminal_id); + } + if (update[i].terminal_code != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", update[i].terminal_code); + printf("ied_usr->terminal_code: %s\n", ied_usr->terminal_code); + } + if (update[i].tmnl_factory != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", update[i].tmnl_factory); + printf("ied_usr->tmnl_factory: %s\n", ied_usr->tmnl_factory); + } + if (update[i].tmnl_status != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", update[i].tmnl_status); + printf("ied_usr->tmnl_status: %s\n", ied_usr->tmnl_status); + } + if (update[i].dev_type != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", update[i].dev_type); + printf("ied_usr->dev_type: %s\n", ied_usr->dev_type); + } + if (update[i].dev_series != NULL) { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", update[i].dev_series); + printf("ied_usr->dev_series: %s\n", ied_usr->dev_series); + } else { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ""); // ĬΪַ + printf("ied_usr->dev_series (default): %s\n", ied_usr->dev_series); + } + if (update[i].dev_key != NULL) { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", update[i].dev_key); + printf("ied_usr->dev_key: %s\n", ied_usr->dev_key); + } else { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ""); // ĬΪַ + printf("ied_usr->dev_key (default): %s\n", ied_usr->dev_key); + } + ied_usr->dev_idx = terminal_index; // µһնź + printf("dev_idx: %d\n", ied_usr->dev_idx); + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4; // channel + ied->channel[0].addr_str[LONGNAME - 1] = 0; // DEV_IP + if (update[i].addr_str != NULL) { + ied->channel[0].addr = ntohl(inet_addr(update[i].addr_str)); // DEV_IP + strncpy(ied->channel[0].addr_str, update[i].addr_str, LONGNAME - 1); // DEV_IP + printf("ied_usr->addr_str: %s\n", ied->channel[0].addr_str); + } else { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.0")); // DEV_IP + strncpy(ied->channel[0].addr_str, update[i].addr_str, LONGNAME - 1); // DEV_IP + printf("ied_usr->addr_str: %s\n", ied->channel[0].addr_str); + } + if (update[i].port != NULL) { + int port = 102; + if (stringToInt(update[i].port, &port)) { + // תɹportStrȫΪ֣ѾתΪint͵port + ied->channel[0].port = port; // DEV_PortID + printf("ied_usr->port: %d\n", ied->channel[0].port); // DEV_PortID + } else { + ied->channel[0].port = 102; // DEV_PortID + printf("ied_usr->port: %s, ǺϷ˿. ʹĬ϶˿: %d\n", update[i].port, ied->channel[0].port); // DEV_PortID + } + } + if (update[i].timestamp != NULL && strlen(update[i].timestamp) > 0) { + // struct tm + struct tm timeinfo = {0}; // ʼΪ0 + // ʱַʽΪ "YYYY-MM-DD HH:MM:SS" + // ʹsscanfַȡʱֶ + if (sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d", + &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, + &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec) == 6) { + // ݴ1900ʼ + timeinfo.tm_year -= 1900; + // ·ݴ0ʼ㣬ȥ1 + timeinfo.tm_mon -= 1; + // tm_isdstгʼͨΪ-1mktimeԶж + timeinfo.tm_isdst = -1; + // ʹmktimestruct tmתΪtime_t + time_t raw_time = mktime(&timeinfo); + // жmktimeǷɹ + if (raw_time != -1) { + ied_usr->time = (long long)raw_time; + printf("ied_usr->time: %lld\n", ied_usr->time); + } else { + printf("Error: mktime failed.\n"); + } + } else { + printf("Error: sscanf failed. Invalid timestamp format.\n"); + return -1; + } + } + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + // monitorData ед뵽 LD_info + int count_real_monitor = 0; //̨˵ļ + int j; + for (j = 0; j < 10 && update[i].line[j].monitor_id[0] != '\0'; ++j) { + monitor monitor_data = update[i].line[j]; + // + count_real_monitor++; + // ʼ LD_info + LD_info_t line_info; + memset(&line_info, 0, sizeof(line_info)); + char logical_device_seq[64]; + // Ϣ + strncpy(line_info.mp_id, monitor_data.monitor_id, sizeof(line_info.mp_id) - 1); + strncpy(line_info.name, monitor_data.monitor_name, sizeof(line_info.name) - 1); + strncpy(line_info.voltage_level, monitor_data.voltage_level, sizeof(line_info.voltage_level) - 1); + strncpy(line_info.v_wiring_type, monitor_data.terminal_connect, sizeof(line_info.v_wiring_type) - 1); + strncpy(line_info.monitor_status, monitor_data.status, sizeof(line_info.monitor_status) - 1); + strncpy(line_info.terminal_code, monitor_data.terminal_code, sizeof(line_info.terminal_code) - 1); + strncpy(logical_device_seq, monitor_data.logical_device_seq, sizeof(logical_device_seq) - 1); + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; // Ĭϼʵ1 + printf("logical_device_seq: is null, set cpuno: %d\n", line_info.cpuno); + } else { + line_info.cpuno = atoi(logical_device_seq); + printf("logical_device_seq: %d\n", line_info.cpuno); + } + line_info.line_id = count_real_monitor; // ¼նź + printf("line_id: %d\n", line_info.line_id); + printf("mp_id: %d\n", line_info.mp_id); + printf("terminal_code: %s\n", line_info.terminal_code); + printf("voltage_level: %d\n", line_info.voltage_level); + printf("v_wiring_type: %d\n", line_info.v_wiring_type); + printf("monitor_status: %d\n", line_info.monitor_status); + printf("name: %s\n", line_info.name); + // ʱ + if (update[i].timestamp[0] != '\0') { + struct tm timeinfo; + char timestamp[64]; + // update[i].timestampʽΪ "YYYY-MM-DD HH:MM:SS" + // 磺"2023-01-14 12:34:56" + sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d", + &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, + &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); + // ݴ1900꿪ʼ + timeinfo.tm_year -= 1900; + // ·ݴ0ʼ1 + timeinfo.tm_mon -= 1; + // tm_isdstгʼͨΪ-1mktimeԶж + timeinfo.tm_isdst = -1; + // ʹmktimestruct tmתΪtime_t + time_t raw_time = mktime(&timeinfo); + // жmktimeǷɹ + if (raw_time != -1) { + line_info.time = (long long)raw_time; + printf("time: %lld\n", line_info.time); + } else { + printf("Error: mktime failed.\n"); + return -1; + } + } + line_info.read_flag = 1; //Ч + // LD_info + if (ied && ied->usr_ext && line_info.cpuno && ((int)line_info.cpuno < 10)) { + char str[256]; + byte_t cpuno = line_info.cpuno; + printf("cpuno: %d\n", line_info.cpuno); + printf("index cpuno: %d\n", cpuno - 1); + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; // cpunoĬ1 + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + printf("rptcount: %d\n", ied_usr->LD_info[cpuno - 1].rptcount); + if (cpuno > ied->cpucount) { + ied->cpucount = cpuno; + } + } + // ied_usr->LD_info[j] = line_info; + printf("Monitor Info [ID: %s, Name: %s] saved in LD_info\n", line_info.mp_id, line_info.name); + } + return 0; +} + //3-д̨/////////////////////////////////// + //4-ӳļ////////////////////////////// + + //4-ӳļ/////////////////////////////////// + //5-ʼ////////////////////////////// + //5-ʼ/////////////////////////////////// + //6-init_rem_dib_table////////////////////////////// + //6-init_rem_dib_table/////////////////////////////////// + + +/*װCɵǫ̃˸º *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + + diff --git a/cfg_parse/datahub.cpp b/cfg_parse/datahub.cpp new file mode 100644 index 0000000..aea5396 --- /dev/null +++ b/cfg_parse/datahub.cpp @@ -0,0 +1,132 @@ +/** +* @file: $RCSfile: datahub.cpp,v $ +* @brief: $aliyun datahub include +* +* @version: $Revision: 1.00 $ +* @date: $Date: 2023/10/10 18:34:00 $ +* @author: $Author: wangwei $ +* @state: $State: Exp $ +* +* @latest: $Id: datahub.cpp,v 1.00 2023/10/10 18:34:00 wangwei Exp $ +* +*/ + +using namespace std; + +#include + +#include +#include + +#include "../mms/db_interface.h" +#include "../json/cjson.h"//WW 2023-08-27json +#include "../include/curl/curl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +size_t req_reply_datahub(void* ptr, size_t size, size_t nmemb, void* stream) +{ + //ע͵ԴӡcookieϢ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + //printf(">>>GetDevice in reply %s\n", (char*)ptr); + //GetCJson(ptr); + return size * nmemb; +} + +void SendWebAPI_Datahub(const string strUrl,char* topic,char* data) +{ + + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + + //cJSON_AddItemToObject(json_root, "topic", cJSON_CreateString("ems_pq_mmxu_stat")); + //cJSON_AddItemToObject(json_root, "data", cJSON_CreateString("{\"DATA_TYPE\": \"04\",\"Monitor\": \"4563\",\"Value\": {\"FLAG\": 1,\"TIME\": 1512097260000,\"VOLTAGE\": {\"MAG\": 56.23,\"DUR\": 23,\"STARTTIME\": 1512097260000,\"ENDTIME\": 1512097283000,\"DISKIND\": \"01\",\"WAVEFILE\": \"PQMonitor_PQM1_000001_20230707_103916_596\",\"PHASIC\": \"unknow\"}}}")); + cJSON_AddItemToObject(json_root, "topic", cJSON_CreateString(topic)); + cJSON_AddItemToObject(json_root, "data", cJSON_CreateString(data)); + + char* szjson = cJSON_Print(json_root); + //printf(">>>json %s\n", szjson); + //string strjson = szjson; + //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_datahub); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>Testaliyun datahub Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("aliyun datahub failed res code: "); + } + else { + printf("aliyun datahub success,string %s", resPost0.c_str()); + //webapiֵж + } + + curl_slist_free_all(header_list); + free(szjson); + cJSON_Delete(json_root); + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} + + +void DataHub_Send_Datahub(char* topic,char* data) +{ + SendWebAPI_Datahub("http://127.0.0.1:8091/powerQuality/PQDATAHUB",topic,data); + +} + + +#ifdef __cplusplus +} +#endif diff --git a/cfg_parse/httplib.h b/cfg_parse/httplib.h new file mode 100644 index 0000000..3bfa9e9 --- /dev/null +++ b/cfg_parse/httplib.h @@ -0,0 +1,10191 @@ +// +// httplib.h +// +// Copyright (c) 2024 Yuji Hirose. All rights reserved. +// MIT License +// + +#ifndef CPPHTTPLIB_HTTPLIB_H +#define CPPHTTPLIB_HTTPLIB_H + +#define CPPHTTPLIB_VERSION "0.18.1" + +/* + * Configuration + */ + +#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5 +#endif + +#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 10000 +#endif + +#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT +#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 100 +#endif + +#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND +#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300 +#endif + +#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND +#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND +#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 5 +#endif + +#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND +#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND +#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 5 +#endif + +#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND +#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND +#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 300 +#endif + +#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND +#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND +#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 5 +#endif + +#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND +#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND +#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0 +#endif + +#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND +#ifdef _WIN32 +#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000 +#else +#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0 +#endif +#endif + +#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH +#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 +#endif + +#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH +#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192 +#endif + +#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT +#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20 +#endif + +#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT +#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024 +#endif + +#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH +#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits::max)()) +#endif + +#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH +#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192 +#endif + +#ifndef CPPHTTPLIB_RANGE_MAX_COUNT +#define CPPHTTPLIB_RANGE_MAX_COUNT 1024 +#endif + +#ifndef CPPHTTPLIB_TCP_NODELAY +#define CPPHTTPLIB_TCP_NODELAY false +#endif + +#ifndef CPPHTTPLIB_IPV6_V6ONLY +#define CPPHTTPLIB_IPV6_V6ONLY false +#endif + +#ifndef CPPHTTPLIB_RECV_BUFSIZ +#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u) +#endif + +#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ +#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u) +#endif + +#ifndef CPPHTTPLIB_THREAD_POOL_COUNT +#define CPPHTTPLIB_THREAD_POOL_COUNT \ + ((std::max)(8u, std::thread::hardware_concurrency() > 0 \ + ? std::thread::hardware_concurrency() - 1 \ + : 0)) +#endif + +#ifndef CPPHTTPLIB_RECV_FLAGS +#define CPPHTTPLIB_RECV_FLAGS 0 +#endif + +#ifndef CPPHTTPLIB_SEND_FLAGS +#define CPPHTTPLIB_SEND_FLAGS 0 +#endif + +#ifndef CPPHTTPLIB_LISTEN_BACKLOG +#define CPPHTTPLIB_LISTEN_BACKLOG 5 +#endif + +/* + * Headers + */ + +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif //_CRT_SECURE_NO_WARNINGS + +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif //_CRT_NONSTDC_NO_DEPRECATE + +#if defined(_MSC_VER) +#if _MSC_VER < 1900 +#error Sorry, Visual Studio versions prior to 2015 are not supported +#endif + +#pragma comment(lib, "ws2_32.lib") + +#ifdef _WIN64 +using ssize_t = __int64; +#else +using ssize_t = long; +#endif +#endif // _MSC_VER + +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG) +#endif // S_ISREG + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR) +#endif // S_ISDIR + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +#include +#include +#include + +#ifndef WSA_FLAG_NO_HANDLE_INHERIT +#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 +#endif + +using socket_t = SOCKET; +#ifdef CPPHTTPLIB_USE_POLL +#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout) +#endif + +#else // not _WIN32 + +#include +#if !defined(_AIX) && !defined(__MVS__) +#include +#endif +#ifdef __MVS__ +#include +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif +#endif +#include +#include +#include +#ifdef __linux__ +#include +#endif +#include +#ifdef CPPHTTPLIB_USE_POLL +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +using socket_t = int; +#ifndef INVALID_SOCKET +#define INVALID_SOCKET (-1) +#endif +#endif //_WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +#ifdef _WIN32 +#include + +// these are defined in wincrypt.h and it breaks compilation if BoringSSL is +// used +#undef X509_NAME +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#undef PKCS7_SIGNER_INFO + +#ifdef _MSC_VER +#pragma comment(lib, "crypt32.lib") +#endif +#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) +#include +#if TARGET_OS_OSX +#include +#include +#endif // TARGET_OS_OSX +#endif // _WIN32 + +#include +#include +#include +#include + +#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK) +#include +#endif + +#include +#include + +#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x1010107f +#error Please use OpenSSL or a current version of BoringSSL +#endif +#define SSL_get1_peer_certificate SSL_get_peer_certificate +#elif OPENSSL_VERSION_NUMBER < 0x30000000L +#error Sorry, OpenSSL versions prior to 3.0.0 are not supported +#endif + +#endif + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT +#include +#endif + +#ifdef CPPHTTPLIB_BROTLI_SUPPORT +#include +#include +#endif + +/* + * Declaration + */ +namespace httplib { + +namespace detail { + +/* + * Backport std::make_unique from C++14. + * + * NOTE: This code came up with the following stackoverflow post: + * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique + * + */ + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Args &&...args) { + return std::unique_ptr(new T(std::forward(args)...)); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(std::size_t n) { + typedef typename std::remove_extent::type RT; + return std::unique_ptr(new RT[n]); +} + +namespace case_ignore { + +inline unsigned char to_lower(int c) { + const static unsigned char table[256] = { + 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, 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, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, + }; + return table[(unsigned char)(char)c]; +} + +inline bool equal(const std::string &a, const std::string &b) { + return a.size() == b.size() && + std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) { + return to_lower(ca) == to_lower(cb); + }); +} + +struct equal_to { + bool operator()(const std::string &a, const std::string &b) const { + return equal(a, b); + } +}; + +struct hash { + size_t operator()(const std::string &key) const { + return hash_core(key.data(), key.size(), 0); + } + + size_t hash_core(const char *s, size_t l, size_t h) const { + return (l == 0) ? h + : hash_core(s + 1, l - 1, + // Unsets the 6 high bits of h, therefore no + // overflow happens + (((std::numeric_limits::max)() >> 6) & + h * 33) ^ + static_cast(to_lower(*s))); + } +}; + +} // namespace case_ignore + +// This is based on +// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189". + +struct scope_exit { + explicit scope_exit(std::function &&f) + : exit_function(std::move(f)), execute_on_destruction{true} {} + + scope_exit(scope_exit &&rhs) noexcept + : exit_function(std::move(rhs.exit_function)), + execute_on_destruction{rhs.execute_on_destruction} { + rhs.release(); + } + + ~scope_exit() { + if (execute_on_destruction) { this->exit_function(); } + } + + void release() { this->execute_on_destruction = false; } + +private: + scope_exit(const scope_exit &) = delete; + void operator=(const scope_exit &) = delete; + scope_exit &operator=(scope_exit &&) = delete; + + std::function exit_function; + bool execute_on_destruction; +}; + +} // namespace detail + +enum StatusCode { + // Information responses + Continue_100 = 100, + SwitchingProtocol_101 = 101, + Processing_102 = 102, + EarlyHints_103 = 103, + + // Successful responses + OK_200 = 200, + Created_201 = 201, + Accepted_202 = 202, + NonAuthoritativeInformation_203 = 203, + NoContent_204 = 204, + ResetContent_205 = 205, + PartialContent_206 = 206, + MultiStatus_207 = 207, + AlreadyReported_208 = 208, + IMUsed_226 = 226, + + // Redirection messages + MultipleChoices_300 = 300, + MovedPermanently_301 = 301, + Found_302 = 302, + SeeOther_303 = 303, + NotModified_304 = 304, + UseProxy_305 = 305, + unused_306 = 306, + TemporaryRedirect_307 = 307, + PermanentRedirect_308 = 308, + + // Client error responses + BadRequest_400 = 400, + Unauthorized_401 = 401, + PaymentRequired_402 = 402, + Forbidden_403 = 403, + NotFound_404 = 404, + MethodNotAllowed_405 = 405, + NotAcceptable_406 = 406, + ProxyAuthenticationRequired_407 = 407, + RequestTimeout_408 = 408, + Conflict_409 = 409, + Gone_410 = 410, + LengthRequired_411 = 411, + PreconditionFailed_412 = 412, + PayloadTooLarge_413 = 413, + UriTooLong_414 = 414, + UnsupportedMediaType_415 = 415, + RangeNotSatisfiable_416 = 416, + ExpectationFailed_417 = 417, + ImATeapot_418 = 418, + MisdirectedRequest_421 = 421, + UnprocessableContent_422 = 422, + Locked_423 = 423, + FailedDependency_424 = 424, + TooEarly_425 = 425, + UpgradeRequired_426 = 426, + PreconditionRequired_428 = 428, + TooManyRequests_429 = 429, + RequestHeaderFieldsTooLarge_431 = 431, + UnavailableForLegalReasons_451 = 451, + + // Server error responses + InternalServerError_500 = 500, + NotImplemented_501 = 501, + BadGateway_502 = 502, + ServiceUnavailable_503 = 503, + GatewayTimeout_504 = 504, + HttpVersionNotSupported_505 = 505, + VariantAlsoNegotiates_506 = 506, + InsufficientStorage_507 = 507, + LoopDetected_508 = 508, + NotExtended_510 = 510, + NetworkAuthenticationRequired_511 = 511, +}; + +using Headers = + std::unordered_multimap; + +using Params = std::multimap; +using Match = std::smatch; + +using Progress = std::function; + +struct Response; +using ResponseHandler = std::function; + +struct MultipartFormData { + std::string name; + std::string content; + std::string filename; + std::string content_type; +}; +using MultipartFormDataItems = std::vector; +using MultipartFormDataMap = std::multimap; + +class DataSink { +public: + DataSink() : os(&sb_), sb_(*this) {} + + DataSink(const DataSink &) = delete; + DataSink &operator=(const DataSink &) = delete; + DataSink(DataSink &&) = delete; + DataSink &operator=(DataSink &&) = delete; + + std::function write; + std::function is_writable; + std::function done; + std::function done_with_trailer; + std::ostream os; + +private: + class data_sink_streambuf final : public std::streambuf { + public: + explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {} + + protected: + std::streamsize xsputn(const char *s, std::streamsize n) override { + sink_.write(s, static_cast(n)); + return n; + } + + private: + DataSink &sink_; + }; + + data_sink_streambuf sb_; +}; + +using ContentProvider = + std::function; + +using ContentProviderWithoutLength = + std::function; + +using ContentProviderResourceReleaser = std::function; + +struct MultipartFormDataProvider { + std::string name; + ContentProviderWithoutLength provider; + std::string filename; + std::string content_type; +}; +using MultipartFormDataProviderItems = std::vector; + +using ContentReceiverWithProgress = + std::function; + +using ContentReceiver = + std::function; + +using MultipartContentHeader = + std::function; + +class ContentReader { +public: + using Reader = std::function; + using MultipartReader = std::function; + + ContentReader(Reader reader, MultipartReader multipart_reader) + : reader_(std::move(reader)), + multipart_reader_(std::move(multipart_reader)) {} + + bool operator()(MultipartContentHeader header, + ContentReceiver receiver) const { + return multipart_reader_(std::move(header), std::move(receiver)); + } + + bool operator()(ContentReceiver receiver) const { + return reader_(std::move(receiver)); + } + + Reader reader_; + MultipartReader multipart_reader_; +}; + +using Range = std::pair; +using Ranges = std::vector; + +struct Request { + std::string method; + std::string path; + Headers headers; + std::string body; + + std::string remote_addr; + int remote_port = -1; + std::string local_addr; + int local_port = -1; + + // for server + std::string version; + std::string target; + Params params; + MultipartFormDataMap files; + Ranges ranges; + Match matches; + std::unordered_map path_params; + + // for client + ResponseHandler response_handler; + ContentReceiverWithProgress content_receiver; + Progress progress; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + const SSL *ssl = nullptr; +#endif + + bool has_header(const std::string &key) const; + std::string get_header_value(const std::string &key, const char *def = "", + size_t id = 0) const; + uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0, + size_t id = 0) const; + size_t get_header_value_count(const std::string &key) const; + void set_header(const std::string &key, const std::string &val); + + bool has_param(const std::string &key) const; + std::string get_param_value(const std::string &key, size_t id = 0) const; + size_t get_param_value_count(const std::string &key) const; + + bool is_multipart_form_data() const; + + bool has_file(const std::string &key) const; + MultipartFormData get_file_value(const std::string &key) const; + std::vector get_file_values(const std::string &key) const; + + // private members... + size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT; + size_t content_length_ = 0; + ContentProvider content_provider_; + bool is_chunked_content_provider_ = false; + size_t authorization_count_ = 0; +}; + +struct Response { + std::string version; + int status = -1; + std::string reason; + Headers headers; + std::string body; + std::string location; // Redirect location + + bool has_header(const std::string &key) const; + std::string get_header_value(const std::string &key, const char *def = "", + size_t id = 0) const; + uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0, + size_t id = 0) const; + size_t get_header_value_count(const std::string &key) const; + void set_header(const std::string &key, const std::string &val); + + void set_redirect(const std::string &url, int status = StatusCode::Found_302); + void set_content(const char *s, size_t n, const std::string &content_type); + void set_content(const std::string &s, const std::string &content_type); + void set_content(std::string &&s, const std::string &content_type); + + void set_content_provider( + size_t length, const std::string &content_type, ContentProvider provider, + ContentProviderResourceReleaser resource_releaser = nullptr); + + void set_content_provider( + const std::string &content_type, ContentProviderWithoutLength provider, + ContentProviderResourceReleaser resource_releaser = nullptr); + + void set_chunked_content_provider( + const std::string &content_type, ContentProviderWithoutLength provider, + ContentProviderResourceReleaser resource_releaser = nullptr); + + void set_file_content(const std::string &path, + const std::string &content_type); + void set_file_content(const std::string &path); + + Response() = default; + Response(const Response &) = default; + Response &operator=(const Response &) = default; + Response(Response &&) = default; + Response &operator=(Response &&) = default; + ~Response() { + if (content_provider_resource_releaser_) { + content_provider_resource_releaser_(content_provider_success_); + } + } + + // private members... + size_t content_length_ = 0; + ContentProvider content_provider_; + ContentProviderResourceReleaser content_provider_resource_releaser_; + bool is_chunked_content_provider_ = false; + bool content_provider_success_ = false; + std::string file_content_path_; + std::string file_content_content_type_; +}; + +class Stream { +public: + virtual ~Stream() = default; + + virtual bool is_readable() const = 0; + virtual bool is_writable() const = 0; + + virtual ssize_t read(char *ptr, size_t size) = 0; + virtual ssize_t write(const char *ptr, size_t size) = 0; + virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0; + virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0; + virtual socket_t socket() const = 0; + + ssize_t write(const char *ptr); + ssize_t write(const std::string &s); +}; + +class TaskQueue { +public: + TaskQueue() = default; + virtual ~TaskQueue() = default; + + virtual bool enqueue(std::function fn) = 0; + virtual void shutdown() = 0; + + virtual void on_idle() {} +}; + +class ThreadPool final : public TaskQueue { +public: + explicit ThreadPool(size_t n, size_t mqr = 0) + : shutdown_(false), max_queued_requests_(mqr) { + while (n) { + threads_.emplace_back(worker(*this)); + n--; + } + } + + ThreadPool(const ThreadPool &) = delete; + ~ThreadPool() override = default; + + bool enqueue(std::function fn) override { + { + std::unique_lock lock(mutex_); + if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) { + return false; + } + jobs_.push_back(std::move(fn)); + } + + cond_.notify_one(); + return true; + } + + void shutdown() override { + // Stop all worker threads... + { + std::unique_lock lock(mutex_); + shutdown_ = true; + } + + cond_.notify_all(); + + // Join... + for (auto &t : threads_) { + t.join(); + } + } + +private: + struct worker { + explicit worker(ThreadPool &pool) : pool_(pool) {} + + void operator()() { + for (;;) { + std::function fn; + { + std::unique_lock lock(pool_.mutex_); + + pool_.cond_.wait( + lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; }); + + if (pool_.shutdown_ && pool_.jobs_.empty()) { break; } + + fn = pool_.jobs_.front(); + pool_.jobs_.pop_front(); + } + + assert(true == static_cast(fn)); + fn(); + } + +#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(LIBRESSL_VERSION_NUMBER) + OPENSSL_thread_stop(); +#endif + } + + ThreadPool &pool_; + }; + friend struct worker; + + std::vector threads_; + std::list> jobs_; + + bool shutdown_; + size_t max_queued_requests_ = 0; + + std::condition_variable cond_; + std::mutex mutex_; +}; + +using Logger = std::function; + +using SocketOptions = std::function; + +void default_socket_options(socket_t sock); + +const char *status_message(int status); + +std::string get_bearer_token_auth(const Request &req); + +namespace detail { + +class MatcherBase { +public: + virtual ~MatcherBase() = default; + + // Match request path and populate its matches and + virtual bool match(Request &request) const = 0; +}; + +/** + * Captures parameters in request path and stores them in Request::path_params + * + * Capture name is a substring of a pattern from : to /. + * The rest of the pattern is matched agains the request path directly + * Parameters are captured starting from the next character after + * the end of the last matched static pattern fragment until the next /. + * + * Example pattern: + * "/path/fragments/:capture/more/fragments/:second_capture" + * Static fragments: + * "/path/fragments/", "more/fragments/" + * + * Given the following request path: + * "/path/fragments/:1/more/fragments/:2" + * the resulting capture will be + * {{"capture", "1"}, {"second_capture", "2"}} + */ +class PathParamsMatcher final : public MatcherBase { +public: + PathParamsMatcher(const std::string &pattern); + + bool match(Request &request) const override; + +private: + // Treat segment separators as the end of path parameter capture + // Does not need to handle query parameters as they are parsed before path + // matching + static constexpr char separator = '/'; + + // Contains static path fragments to match against, excluding the '/' after + // path params + // Fragments are separated by path params + std::vector static_fragments_; + // Stores the names of the path parameters to be used as keys in the + // Request::path_params map + std::vector param_names_; +}; + +/** + * Performs std::regex_match on request path + * and stores the result in Request::matches + * + * Note that regex match is performed directly on the whole request. + * This means that wildcard patterns may match multiple path segments with /: + * "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end". + */ +class RegexMatcher final : public MatcherBase { +public: + RegexMatcher(const std::string &pattern) : regex_(pattern) {} + + bool match(Request &request) const override; + +private: + std::regex regex_; +}; + +ssize_t write_headers(Stream &strm, const Headers &headers); + +} // namespace detail + +class Server { +public: + using Handler = std::function; + + using ExceptionHandler = + std::function; + + enum class HandlerResponse { + Handled, + Unhandled, + }; + using HandlerWithResponse = + std::function; + + using HandlerWithContentReader = std::function; + + using Expect100ContinueHandler = + std::function; + + Server(); + + virtual ~Server(); + + virtual bool is_valid() const; + + Server &Get(const std::string &pattern, Handler handler); + Server &Post(const std::string &pattern, Handler handler); + Server &Post(const std::string &pattern, HandlerWithContentReader handler); + Server &Put(const std::string &pattern, Handler handler); + Server &Put(const std::string &pattern, HandlerWithContentReader handler); + Server &Patch(const std::string &pattern, Handler handler); + Server &Patch(const std::string &pattern, HandlerWithContentReader handler); + Server &Delete(const std::string &pattern, Handler handler); + Server &Delete(const std::string &pattern, HandlerWithContentReader handler); + Server &Options(const std::string &pattern, Handler handler); + + bool set_base_dir(const std::string &dir, + const std::string &mount_point = std::string()); + bool set_mount_point(const std::string &mount_point, const std::string &dir, + Headers headers = Headers()); + bool remove_mount_point(const std::string &mount_point); + Server &set_file_extension_and_mimetype_mapping(const std::string &ext, + const std::string &mime); + Server &set_default_file_mimetype(const std::string &mime); + Server &set_file_request_handler(Handler handler); + + template + Server &set_error_handler(ErrorHandlerFunc &&handler) { + return set_error_handler_core( + std::forward(handler), + std::is_convertible{}); + } + + Server &set_exception_handler(ExceptionHandler handler); + Server &set_pre_routing_handler(HandlerWithResponse handler); + Server &set_post_routing_handler(Handler handler); + + Server &set_expect_100_continue_handler(Expect100ContinueHandler handler); + Server &set_logger(Logger logger); + + Server &set_address_family(int family); + Server &set_tcp_nodelay(bool on); + Server &set_ipv6_v6only(bool on); + Server &set_socket_options(SocketOptions socket_options); + + Server &set_default_headers(Headers headers); + Server & + set_header_writer(std::function const &writer); + + Server &set_keep_alive_max_count(size_t count); + Server &set_keep_alive_timeout(time_t sec); + + Server &set_read_timeout(time_t sec, time_t usec = 0); + template + Server &set_read_timeout(const std::chrono::duration &duration); + + Server &set_write_timeout(time_t sec, time_t usec = 0); + template + Server &set_write_timeout(const std::chrono::duration &duration); + + Server &set_idle_interval(time_t sec, time_t usec = 0); + template + Server &set_idle_interval(const std::chrono::duration &duration); + + Server &set_payload_max_length(size_t length); + + bool bind_to_port(const std::string &host, int port, int socket_flags = 0); + int bind_to_any_port(const std::string &host, int socket_flags = 0); + bool listen_after_bind(); + + bool listen(const std::string &host, int port, int socket_flags = 0); + + bool is_running() const; + void wait_until_ready() const; + void stop(); + void decommission(); + + std::function new_task_queue; + +protected: + bool process_request(Stream &strm, const std::string &remote_addr, + int remote_port, const std::string &local_addr, + int local_port, bool close_connection, + bool &connection_closed, + const std::function &setup_request); + + std::atomic svr_sock_{INVALID_SOCKET}; + size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT; + time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND; + time_t read_timeout_sec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND; + time_t read_timeout_usec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND; + time_t write_timeout_sec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND; + time_t write_timeout_usec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND; + time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND; + time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND; + size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH; + +private: + using Handlers = + std::vector, Handler>>; + using HandlersForContentReader = + std::vector, + HandlerWithContentReader>>; + + static std::unique_ptr + make_matcher(const std::string &pattern); + + Server &set_error_handler_core(HandlerWithResponse handler, std::true_type); + Server &set_error_handler_core(Handler handler, std::false_type); + + socket_t create_server_socket(const std::string &host, int port, + int socket_flags, + SocketOptions socket_options) const; + int bind_internal(const std::string &host, int port, int socket_flags); + bool listen_internal(); + + bool routing(Request &req, Response &res, Stream &strm); + bool handle_file_request(const Request &req, Response &res, + bool head = false); + bool dispatch_request(Request &req, Response &res, + const Handlers &handlers) const; + bool dispatch_request_for_content_reader( + Request &req, Response &res, ContentReader content_reader, + const HandlersForContentReader &handlers) const; + + bool parse_request_line(const char *s, Request &req) const; + void apply_ranges(const Request &req, Response &res, + std::string &content_type, std::string &boundary) const; + bool write_response(Stream &strm, bool close_connection, Request &req, + Response &res); + bool write_response_with_content(Stream &strm, bool close_connection, + const Request &req, Response &res); + bool write_response_core(Stream &strm, bool close_connection, + const Request &req, Response &res, + bool need_apply_ranges); + bool write_content_with_provider(Stream &strm, const Request &req, + Response &res, const std::string &boundary, + const std::string &content_type); + bool read_content(Stream &strm, Request &req, Response &res); + bool + read_content_with_content_receiver(Stream &strm, Request &req, Response &res, + ContentReceiver receiver, + MultipartContentHeader multipart_header, + ContentReceiver multipart_receiver); + bool read_content_core(Stream &strm, Request &req, Response &res, + ContentReceiver receiver, + MultipartContentHeader multipart_header, + ContentReceiver multipart_receiver) const; + + virtual bool process_and_close_socket(socket_t sock); + + std::atomic is_running_{false}; + std::atomic is_decommisioned{false}; + + struct MountPointEntry { + std::string mount_point; + std::string base_dir; + Headers headers; + }; + std::vector base_dirs_; + std::map file_extension_and_mimetype_map_; + std::string default_file_mimetype_ = "application/octet-stream"; + Handler file_request_handler_; + + Handlers get_handlers_; + Handlers post_handlers_; + HandlersForContentReader post_handlers_for_content_reader_; + Handlers put_handlers_; + HandlersForContentReader put_handlers_for_content_reader_; + Handlers patch_handlers_; + HandlersForContentReader patch_handlers_for_content_reader_; + Handlers delete_handlers_; + HandlersForContentReader delete_handlers_for_content_reader_; + Handlers options_handlers_; + + HandlerWithResponse error_handler_; + ExceptionHandler exception_handler_; + HandlerWithResponse pre_routing_handler_; + Handler post_routing_handler_; + Expect100ContinueHandler expect_100_continue_handler_; + + Logger logger_; + + int address_family_ = AF_UNSPEC; + bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY; + bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY; + SocketOptions socket_options_ = default_socket_options; + + Headers default_headers_; + std::function header_writer_ = + detail::write_headers; +}; + +enum class Error { + Success = 0, + Unknown, + Connection, + BindIPAddress, + Read, + Write, + ExceedRedirectCount, + Canceled, + SSLConnection, + SSLLoadingCerts, + SSLServerVerification, + SSLServerHostnameVerification, + UnsupportedMultipartBoundaryChars, + Compression, + ConnectionTimeout, + ProxyConnection, + + // For internal use only + SSLPeerCouldBeClosed_, +}; + +std::string to_string(Error error); + +std::ostream &operator<<(std::ostream &os, const Error &obj); + +class Result { +public: + Result() = default; + Result(std::unique_ptr &&res, Error err, + Headers &&request_headers = Headers{}) + : res_(std::move(res)), err_(err), + request_headers_(std::move(request_headers)) {} + // Response + operator bool() const { return res_ != nullptr; } + bool operator==(std::nullptr_t) const { return res_ == nullptr; } + bool operator!=(std::nullptr_t) const { return res_ != nullptr; } + const Response &value() const { return *res_; } + Response &value() { return *res_; } + const Response &operator*() const { return *res_; } + Response &operator*() { return *res_; } + const Response *operator->() const { return res_.get(); } + Response *operator->() { return res_.get(); } + + // Error + Error error() const { return err_; } + + // Request Headers + bool has_request_header(const std::string &key) const; + std::string get_request_header_value(const std::string &key, + const char *def = "", + size_t id = 0) const; + uint64_t get_request_header_value_u64(const std::string &key, + uint64_t def = 0, size_t id = 0) const; + size_t get_request_header_value_count(const std::string &key) const; + +private: + std::unique_ptr res_; + Error err_ = Error::Unknown; + Headers request_headers_; +}; + +class ClientImpl { +public: + explicit ClientImpl(const std::string &host); + + explicit ClientImpl(const std::string &host, int port); + + explicit ClientImpl(const std::string &host, int port, + const std::string &client_cert_path, + const std::string &client_key_path); + + virtual ~ClientImpl(); + + virtual bool is_valid() const; + + Result Get(const std::string &path); + Result Get(const std::string &path, const Headers &headers); + Result Get(const std::string &path, Progress progress); + Result Get(const std::string &path, const Headers &headers, + Progress progress); + Result Get(const std::string &path, ContentReceiver content_receiver); + Result Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver); + Result Get(const std::string &path, ContentReceiver content_receiver, + Progress progress); + Result Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver, Progress progress); + Result Get(const std::string &path, ResponseHandler response_handler, + ContentReceiver content_receiver); + Result Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver); + Result Get(const std::string &path, ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress); + Result Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, ContentReceiver content_receiver, + Progress progress); + + Result Get(const std::string &path, const Params ¶ms, + const Headers &headers, Progress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, + const Headers &headers, ContentReceiver content_receiver, + Progress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, + const Headers &headers, ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress = nullptr); + + Result Head(const std::string &path); + Result Head(const std::string &path, const Headers &headers); + + Result Post(const std::string &path); + Result Post(const std::string &path, const Headers &headers); + Result Post(const std::string &path, const char *body, size_t content_length, + const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type, + Progress progress); + Result Post(const std::string &path, const std::string &body, + const std::string &content_type); + Result Post(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Post(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + Result Post(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type); + Result Post(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, + size_t content_length, ContentProvider content_provider, + const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Post(const std::string &path, const Params ¶ms); + Result Post(const std::string &path, const Headers &headers, + const Params ¶ms); + Result Post(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress); + Result Post(const std::string &path, const MultipartFormDataItems &items); + Result Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items); + Result Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, const std::string &boundary); + Result Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items); + + Result Put(const std::string &path); + Result Put(const std::string &path, const char *body, size_t content_length, + const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type, + Progress progress); + Result Put(const std::string &path, const std::string &body, + const std::string &content_type); + Result Put(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Put(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + Result Put(const std::string &path, size_t content_length, + ContentProvider content_provider, const std::string &content_type); + Result Put(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, + size_t content_length, ContentProvider content_provider, + const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Put(const std::string &path, const Params ¶ms); + Result Put(const std::string &path, const Headers &headers, + const Params ¶ms); + Result Put(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress); + Result Put(const std::string &path, const MultipartFormDataItems &items); + Result Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items); + Result Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, const std::string &boundary); + Result Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items); + + Result Patch(const std::string &path); + Result Patch(const std::string &path, const char *body, size_t content_length, + const std::string &content_type); + Result Patch(const std::string &path, const char *body, size_t content_length, + const std::string &content_type, Progress progress); + Result Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, Progress progress); + Result Patch(const std::string &path, const std::string &body, + const std::string &content_type); + Result Patch(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Patch(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + Result Patch(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type); + Result Patch(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + size_t content_length, ContentProvider content_provider, + const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + + Result Delete(const std::string &path); + Result Delete(const std::string &path, const Headers &headers); + Result Delete(const std::string &path, const char *body, + size_t content_length, const std::string &content_type); + Result Delete(const std::string &path, const char *body, + size_t content_length, const std::string &content_type, + Progress progress); + Result Delete(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type); + Result Delete(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, Progress progress); + Result Delete(const std::string &path, const std::string &body, + const std::string &content_type); + Result Delete(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Delete(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Delete(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + + Result Options(const std::string &path); + Result Options(const std::string &path, const Headers &headers); + + bool send(Request &req, Response &res, Error &error); + Result send(const Request &req); + + void stop(); + + std::string host() const; + int port() const; + + size_t is_socket_open() const; + socket_t socket() const; + + void set_hostname_addr_map(std::map addr_map); + + void set_default_headers(Headers headers); + + void + set_header_writer(std::function const &writer); + + void set_address_family(int family); + void set_tcp_nodelay(bool on); + void set_ipv6_v6only(bool on); + void set_socket_options(SocketOptions socket_options); + + void set_connection_timeout(time_t sec, time_t usec = 0); + template + void + set_connection_timeout(const std::chrono::duration &duration); + + void set_read_timeout(time_t sec, time_t usec = 0); + template + void set_read_timeout(const std::chrono::duration &duration); + + void set_write_timeout(time_t sec, time_t usec = 0); + template + void set_write_timeout(const std::chrono::duration &duration); + + void set_basic_auth(const std::string &username, const std::string &password); + void set_bearer_token_auth(const std::string &token); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void set_digest_auth(const std::string &username, + const std::string &password); +#endif + + void set_keep_alive(bool on); + void set_follow_location(bool on); + + void set_url_encode(bool on); + + void set_compress(bool on); + + void set_decompress(bool on); + + void set_interface(const std::string &intf); + + void set_proxy(const std::string &host, int port); + void set_proxy_basic_auth(const std::string &username, + const std::string &password); + void set_proxy_bearer_token_auth(const std::string &token); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void set_proxy_digest_auth(const std::string &username, + const std::string &password); +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void set_ca_cert_path(const std::string &ca_cert_file_path, + const std::string &ca_cert_dir_path = std::string()); + void set_ca_cert_store(X509_STORE *ca_cert_store); + X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const; +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void enable_server_certificate_verification(bool enabled); + void enable_server_hostname_verification(bool enabled); + void set_server_certificate_verifier(std::function verifier); +#endif + + void set_logger(Logger logger); + +protected: + struct Socket { + socket_t sock = INVALID_SOCKET; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + SSL *ssl = nullptr; +#endif + + bool is_open() const { return sock != INVALID_SOCKET; } + }; + + virtual bool create_and_connect_socket(Socket &socket, Error &error); + + // All of: + // shutdown_ssl + // shutdown_socket + // close_socket + // should ONLY be called when socket_mutex_ is locked. + // Also, shutdown_ssl and close_socket should also NOT be called concurrently + // with a DIFFERENT thread sending requests using that socket. + virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully); + void shutdown_socket(Socket &socket) const; + void close_socket(Socket &socket); + + bool process_request(Stream &strm, Request &req, Response &res, + bool close_connection, Error &error); + + bool write_content_with_provider(Stream &strm, const Request &req, + Error &error) const; + + void copy_settings(const ClientImpl &rhs); + + // Socket endpoint information + const std::string host_; + const int port_; + const std::string host_and_port_; + + // Current open socket + Socket socket_; + mutable std::mutex socket_mutex_; + std::recursive_mutex request_mutex_; + + // These are all protected under socket_mutex + size_t socket_requests_in_flight_ = 0; + std::thread::id socket_requests_are_from_thread_ = std::thread::id(); + bool socket_should_be_closed_when_request_is_done_ = false; + + // Hostname-IP map + std::map addr_map_; + + // Default headers + Headers default_headers_; + + // Header writer + std::function header_writer_ = + detail::write_headers; + + // Settings + std::string client_cert_path_; + std::string client_key_path_; + + time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND; + time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND; + time_t read_timeout_sec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND; + time_t read_timeout_usec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND; + time_t write_timeout_sec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND; + time_t write_timeout_usec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND; + + std::string basic_auth_username_; + std::string basic_auth_password_; + std::string bearer_token_auth_token_; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + std::string digest_auth_username_; + std::string digest_auth_password_; +#endif + + bool keep_alive_ = false; + bool follow_location_ = false; + + bool url_encode_ = true; + + int address_family_ = AF_UNSPEC; + bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY; + bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY; + SocketOptions socket_options_ = nullptr; + + bool compress_ = false; + bool decompress_ = true; + + std::string interface_; + + std::string proxy_host_; + int proxy_port_ = -1; + + std::string proxy_basic_auth_username_; + std::string proxy_basic_auth_password_; + std::string proxy_bearer_token_auth_token_; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + std::string proxy_digest_auth_username_; + std::string proxy_digest_auth_password_; +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + std::string ca_cert_file_path_; + std::string ca_cert_dir_path_; + + X509_STORE *ca_cert_store_ = nullptr; +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + bool server_certificate_verification_ = true; + bool server_hostname_verification_ = true; + std::function server_certificate_verifier_; +#endif + + Logger logger_; + +private: + bool send_(Request &req, Response &res, Error &error); + Result send_(Request &&req); + + socket_t create_client_socket(Error &error) const; + bool read_response_line(Stream &strm, const Request &req, + Response &res) const; + bool write_request(Stream &strm, Request &req, bool close_connection, + Error &error); + bool redirect(Request &req, Response &res, Error &error); + bool handle_request(Stream &strm, Request &req, Response &res, + bool close_connection, Error &error); + std::unique_ptr send_with_content_provider( + Request &req, const char *body, size_t content_length, + ContentProvider content_provider, + ContentProviderWithoutLength content_provider_without_length, + const std::string &content_type, Error &error); + Result send_with_content_provider( + const std::string &method, const std::string &path, + const Headers &headers, const char *body, size_t content_length, + ContentProvider content_provider, + ContentProviderWithoutLength content_provider_without_length, + const std::string &content_type, Progress progress); + ContentProviderWithoutLength get_multipart_content_provider( + const std::string &boundary, const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items) const; + + std::string adjust_host_string(const std::string &host) const; + + virtual bool process_socket(const Socket &socket, + std::function callback); + virtual bool is_ssl() const; +}; + +class Client { +public: + // Universal interface + explicit Client(const std::string &scheme_host_port); + + explicit Client(const std::string &scheme_host_port, + const std::string &client_cert_path, + const std::string &client_key_path); + + // HTTP only interface + explicit Client(const std::string &host, int port); + + explicit Client(const std::string &host, int port, + const std::string &client_cert_path, + const std::string &client_key_path); + + Client(Client &&) = default; + Client &operator=(Client &&) = default; + + ~Client(); + + bool is_valid() const; + + Result Get(const std::string &path); + Result Get(const std::string &path, const Headers &headers); + Result Get(const std::string &path, Progress progress); + Result Get(const std::string &path, const Headers &headers, + Progress progress); + Result Get(const std::string &path, ContentReceiver content_receiver); + Result Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver); + Result Get(const std::string &path, ContentReceiver content_receiver, + Progress progress); + Result Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver, Progress progress); + Result Get(const std::string &path, ResponseHandler response_handler, + ContentReceiver content_receiver); + Result Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver); + Result Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, ContentReceiver content_receiver, + Progress progress); + Result Get(const std::string &path, ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress); + + Result Get(const std::string &path, const Params ¶ms, + const Headers &headers, Progress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, + const Headers &headers, ContentReceiver content_receiver, + Progress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, + const Headers &headers, ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress = nullptr); + + Result Head(const std::string &path); + Result Head(const std::string &path, const Headers &headers); + + Result Post(const std::string &path); + Result Post(const std::string &path, const Headers &headers); + Result Post(const std::string &path, const char *body, size_t content_length, + const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type, + Progress progress); + Result Post(const std::string &path, const std::string &body, + const std::string &content_type); + Result Post(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Post(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + Result Post(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type); + Result Post(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, + size_t content_length, ContentProvider content_provider, + const std::string &content_type); + Result Post(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Post(const std::string &path, const Params ¶ms); + Result Post(const std::string &path, const Headers &headers, + const Params ¶ms); + Result Post(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress); + Result Post(const std::string &path, const MultipartFormDataItems &items); + Result Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items); + Result Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, const std::string &boundary); + Result Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items); + + Result Put(const std::string &path); + Result Put(const std::string &path, const char *body, size_t content_length, + const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, const char *body, + size_t content_length, const std::string &content_type, + Progress progress); + Result Put(const std::string &path, const std::string &body, + const std::string &content_type); + Result Put(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Put(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + Result Put(const std::string &path, size_t content_length, + ContentProvider content_provider, const std::string &content_type); + Result Put(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, + size_t content_length, ContentProvider content_provider, + const std::string &content_type); + Result Put(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Put(const std::string &path, const Params ¶ms); + Result Put(const std::string &path, const Headers &headers, + const Params ¶ms); + Result Put(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress); + Result Put(const std::string &path, const MultipartFormDataItems &items); + Result Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items); + Result Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, const std::string &boundary); + Result Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items); + + Result Patch(const std::string &path); + Result Patch(const std::string &path, const char *body, size_t content_length, + const std::string &content_type); + Result Patch(const std::string &path, const char *body, size_t content_length, + const std::string &content_type, Progress progress); + Result Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, Progress progress); + Result Patch(const std::string &path, const std::string &body, + const std::string &content_type); + Result Patch(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Patch(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + Result Patch(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type); + Result Patch(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + size_t content_length, ContentProvider content_provider, + const std::string &content_type); + Result Patch(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type); + + Result Delete(const std::string &path); + Result Delete(const std::string &path, const Headers &headers); + Result Delete(const std::string &path, const char *body, + size_t content_length, const std::string &content_type); + Result Delete(const std::string &path, const char *body, + size_t content_length, const std::string &content_type, + Progress progress); + Result Delete(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type); + Result Delete(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, Progress progress); + Result Delete(const std::string &path, const std::string &body, + const std::string &content_type); + Result Delete(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress); + Result Delete(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type); + Result Delete(const std::string &path, const Headers &headers, + const std::string &body, const std::string &content_type, + Progress progress); + + Result Options(const std::string &path); + Result Options(const std::string &path, const Headers &headers); + + bool send(Request &req, Response &res, Error &error); + Result send(const Request &req); + + void stop(); + + std::string host() const; + int port() const; + + size_t is_socket_open() const; + socket_t socket() const; + + void set_hostname_addr_map(std::map addr_map); + + void set_default_headers(Headers headers); + + void + set_header_writer(std::function const &writer); + + void set_address_family(int family); + void set_tcp_nodelay(bool on); + void set_socket_options(SocketOptions socket_options); + + void set_connection_timeout(time_t sec, time_t usec = 0); + template + void + set_connection_timeout(const std::chrono::duration &duration); + + void set_read_timeout(time_t sec, time_t usec = 0); + template + void set_read_timeout(const std::chrono::duration &duration); + + void set_write_timeout(time_t sec, time_t usec = 0); + template + void set_write_timeout(const std::chrono::duration &duration); + + void set_basic_auth(const std::string &username, const std::string &password); + void set_bearer_token_auth(const std::string &token); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void set_digest_auth(const std::string &username, + const std::string &password); +#endif + + void set_keep_alive(bool on); + void set_follow_location(bool on); + + void set_url_encode(bool on); + + void set_compress(bool on); + + void set_decompress(bool on); + + void set_interface(const std::string &intf); + + void set_proxy(const std::string &host, int port); + void set_proxy_basic_auth(const std::string &username, + const std::string &password); + void set_proxy_bearer_token_auth(const std::string &token); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void set_proxy_digest_auth(const std::string &username, + const std::string &password); +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void enable_server_certificate_verification(bool enabled); + void enable_server_hostname_verification(bool enabled); + void set_server_certificate_verifier(std::function verifier); +#endif + + void set_logger(Logger logger); + + // SSL +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + void set_ca_cert_path(const std::string &ca_cert_file_path, + const std::string &ca_cert_dir_path = std::string()); + + void set_ca_cert_store(X509_STORE *ca_cert_store); + void load_ca_cert_store(const char *ca_cert, std::size_t size); + + long get_openssl_verify_result() const; + + SSL_CTX *ssl_context() const; +#endif + +private: + std::unique_ptr cli_; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + bool is_ssl_ = false; +#endif +}; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +class SSLServer : public Server { +public: + SSLServer(const char *cert_path, const char *private_key_path, + const char *client_ca_cert_file_path = nullptr, + const char *client_ca_cert_dir_path = nullptr, + const char *private_key_password = nullptr); + + SSLServer(X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store = nullptr); + + SSLServer( + const std::function &setup_ssl_ctx_callback); + + ~SSLServer() override; + + bool is_valid() const override; + + SSL_CTX *ssl_context() const; + + void update_certs(X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store = nullptr); + +private: + bool process_and_close_socket(socket_t sock) override; + + SSL_CTX *ctx_; + std::mutex ctx_mutex_; +}; + +class SSLClient final : public ClientImpl { +public: + explicit SSLClient(const std::string &host); + + explicit SSLClient(const std::string &host, int port); + + explicit SSLClient(const std::string &host, int port, + const std::string &client_cert_path, + const std::string &client_key_path, + const std::string &private_key_password = std::string()); + + explicit SSLClient(const std::string &host, int port, X509 *client_cert, + EVP_PKEY *client_key, + const std::string &private_key_password = std::string()); + + ~SSLClient() override; + + bool is_valid() const override; + + void set_ca_cert_store(X509_STORE *ca_cert_store); + void load_ca_cert_store(const char *ca_cert, std::size_t size); + + long get_openssl_verify_result() const; + + SSL_CTX *ssl_context() const; + +private: + bool create_and_connect_socket(Socket &socket, Error &error) override; + void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override; + void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully); + + bool process_socket(const Socket &socket, + std::function callback) override; + bool is_ssl() const override; + + bool connect_with_proxy(Socket &sock, Response &res, bool &success, + Error &error); + bool initialize_ssl(Socket &socket, Error &error); + + bool load_certs(); + + bool verify_host(X509 *server_cert) const; + bool verify_host_with_subject_alt_name(X509 *server_cert) const; + bool verify_host_with_common_name(X509 *server_cert) const; + bool check_host_name(const char *pattern, size_t pattern_len) const; + + SSL_CTX *ctx_; + std::mutex ctx_mutex_; + std::once_flag initialize_cert_; + + std::vector host_components_; + + long verify_result_ = 0; + + friend class ClientImpl; +}; +#endif + +/* + * Implementation of template methods. + */ + +namespace detail { + +template +inline void duration_to_sec_and_usec(const T &duration, U callback) { + auto sec = std::chrono::duration_cast(duration).count(); + auto usec = std::chrono::duration_cast( + duration - std::chrono::seconds(sec)) + .count(); + callback(static_cast(sec), static_cast(usec)); +} + +inline uint64_t get_header_value_u64(const Headers &headers, + const std::string &key, uint64_t def, + size_t id) { + auto rng = headers.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { + return std::strtoull(it->second.data(), nullptr, 10); + } + return def; +} + +} // namespace detail + +inline uint64_t Request::get_header_value_u64(const std::string &key, + uint64_t def, size_t id) const { + return detail::get_header_value_u64(headers, key, def, id); +} + +inline uint64_t Response::get_header_value_u64(const std::string &key, + uint64_t def, size_t id) const { + return detail::get_header_value_u64(headers, key, def, id); +} + +inline void default_socket_options(socket_t sock) { + int opt = 1; +#ifdef _WIN32 + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&opt), sizeof(opt)); + setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, + reinterpret_cast(&opt), sizeof(opt)); +#else +#ifdef SO_REUSEPORT + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, + reinterpret_cast(&opt), sizeof(opt)); +#else + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&opt), sizeof(opt)); +#endif +#endif +} + +inline const char *status_message(int status) { + switch (status) { + case StatusCode::Continue_100: return "Continue"; + case StatusCode::SwitchingProtocol_101: return "Switching Protocol"; + case StatusCode::Processing_102: return "Processing"; + case StatusCode::EarlyHints_103: return "Early Hints"; + case StatusCode::OK_200: return "OK"; + case StatusCode::Created_201: return "Created"; + case StatusCode::Accepted_202: return "Accepted"; + case StatusCode::NonAuthoritativeInformation_203: + return "Non-Authoritative Information"; + case StatusCode::NoContent_204: return "No Content"; + case StatusCode::ResetContent_205: return "Reset Content"; + case StatusCode::PartialContent_206: return "Partial Content"; + case StatusCode::MultiStatus_207: return "Multi-Status"; + case StatusCode::AlreadyReported_208: return "Already Reported"; + case StatusCode::IMUsed_226: return "IM Used"; + case StatusCode::MultipleChoices_300: return "Multiple Choices"; + case StatusCode::MovedPermanently_301: return "Moved Permanently"; + case StatusCode::Found_302: return "Found"; + case StatusCode::SeeOther_303: return "See Other"; + case StatusCode::NotModified_304: return "Not Modified"; + case StatusCode::UseProxy_305: return "Use Proxy"; + case StatusCode::unused_306: return "unused"; + case StatusCode::TemporaryRedirect_307: return "Temporary Redirect"; + case StatusCode::PermanentRedirect_308: return "Permanent Redirect"; + case StatusCode::BadRequest_400: return "Bad Request"; + case StatusCode::Unauthorized_401: return "Unauthorized"; + case StatusCode::PaymentRequired_402: return "Payment Required"; + case StatusCode::Forbidden_403: return "Forbidden"; + case StatusCode::NotFound_404: return "Not Found"; + case StatusCode::MethodNotAllowed_405: return "Method Not Allowed"; + case StatusCode::NotAcceptable_406: return "Not Acceptable"; + case StatusCode::ProxyAuthenticationRequired_407: + return "Proxy Authentication Required"; + case StatusCode::RequestTimeout_408: return "Request Timeout"; + case StatusCode::Conflict_409: return "Conflict"; + case StatusCode::Gone_410: return "Gone"; + case StatusCode::LengthRequired_411: return "Length Required"; + case StatusCode::PreconditionFailed_412: return "Precondition Failed"; + case StatusCode::PayloadTooLarge_413: return "Payload Too Large"; + case StatusCode::UriTooLong_414: return "URI Too Long"; + case StatusCode::UnsupportedMediaType_415: return "Unsupported Media Type"; + case StatusCode::RangeNotSatisfiable_416: return "Range Not Satisfiable"; + case StatusCode::ExpectationFailed_417: return "Expectation Failed"; + case StatusCode::ImATeapot_418: return "I'm a teapot"; + case StatusCode::MisdirectedRequest_421: return "Misdirected Request"; + case StatusCode::UnprocessableContent_422: return "Unprocessable Content"; + case StatusCode::Locked_423: return "Locked"; + case StatusCode::FailedDependency_424: return "Failed Dependency"; + case StatusCode::TooEarly_425: return "Too Early"; + case StatusCode::UpgradeRequired_426: return "Upgrade Required"; + case StatusCode::PreconditionRequired_428: return "Precondition Required"; + case StatusCode::TooManyRequests_429: return "Too Many Requests"; + case StatusCode::RequestHeaderFieldsTooLarge_431: + return "Request Header Fields Too Large"; + case StatusCode::UnavailableForLegalReasons_451: + return "Unavailable For Legal Reasons"; + case StatusCode::NotImplemented_501: return "Not Implemented"; + case StatusCode::BadGateway_502: return "Bad Gateway"; + case StatusCode::ServiceUnavailable_503: return "Service Unavailable"; + case StatusCode::GatewayTimeout_504: return "Gateway Timeout"; + case StatusCode::HttpVersionNotSupported_505: + return "HTTP Version Not Supported"; + case StatusCode::VariantAlsoNegotiates_506: return "Variant Also Negotiates"; + case StatusCode::InsufficientStorage_507: return "Insufficient Storage"; + case StatusCode::LoopDetected_508: return "Loop Detected"; + case StatusCode::NotExtended_510: return "Not Extended"; + case StatusCode::NetworkAuthenticationRequired_511: + return "Network Authentication Required"; + + default: + case StatusCode::InternalServerError_500: return "Internal Server Error"; + } +} + +inline std::string get_bearer_token_auth(const Request &req) { + if (req.has_header("Authorization")) { + static std::string BearerHeaderPrefix = "Bearer "; + return req.get_header_value("Authorization") + .substr(BearerHeaderPrefix.length()); + } + return ""; +} + +template +inline Server & +Server::set_read_timeout(const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); }); + return *this; +} + +template +inline Server & +Server::set_write_timeout(const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); }); + return *this; +} + +template +inline Server & +Server::set_idle_interval(const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); }); + return *this; +} + +inline std::string to_string(const Error error) { + switch (error) { + case Error::Success: return "Success (no error)"; + case Error::Connection: return "Could not establish connection"; + case Error::BindIPAddress: return "Failed to bind IP address"; + case Error::Read: return "Failed to read connection"; + case Error::Write: return "Failed to write connection"; + case Error::ExceedRedirectCount: return "Maximum redirect count exceeded"; + case Error::Canceled: return "Connection handling canceled"; + case Error::SSLConnection: return "SSL connection failed"; + case Error::SSLLoadingCerts: return "SSL certificate loading failed"; + case Error::SSLServerVerification: return "SSL server verification failed"; + case Error::SSLServerHostnameVerification: + return "SSL server hostname verification failed"; + case Error::UnsupportedMultipartBoundaryChars: + return "Unsupported HTTP multipart boundary characters"; + case Error::Compression: return "Compression failed"; + case Error::ConnectionTimeout: return "Connection timed out"; + case Error::ProxyConnection: return "Proxy connection failed"; + case Error::Unknown: return "Unknown"; + default: break; + } + + return "Invalid"; +} + +inline std::ostream &operator<<(std::ostream &os, const Error &obj) { + os << to_string(obj); + os << " (" << static_cast::type>(obj) << ')'; + return os; +} + +inline uint64_t Result::get_request_header_value_u64(const std::string &key, + uint64_t def, + size_t id) const { + return detail::get_header_value_u64(request_headers_, key, def, id); +} + +template +inline void ClientImpl::set_connection_timeout( + const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) { + set_connection_timeout(sec, usec); + }); +} + +template +inline void ClientImpl::set_read_timeout( + const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); }); +} + +template +inline void ClientImpl::set_write_timeout( + const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); }); +} + +template +inline void Client::set_connection_timeout( + const std::chrono::duration &duration) { + cli_->set_connection_timeout(duration); +} + +template +inline void +Client::set_read_timeout(const std::chrono::duration &duration) { + cli_->set_read_timeout(duration); +} + +template +inline void +Client::set_write_timeout(const std::chrono::duration &duration) { + cli_->set_write_timeout(duration); +} + +/* + * Forward declarations and types that will be part of the .h file if split into + * .h + .cc. + */ + +std::string hosted_at(const std::string &hostname); + +void hosted_at(const std::string &hostname, std::vector &addrs); + +std::string append_query_params(const std::string &path, const Params ¶ms); + +std::pair make_range_header(const Ranges &ranges); + +std::pair +make_basic_authentication_header(const std::string &username, + const std::string &password, + bool is_proxy = false); + +namespace detail { + +struct FileStat { + FileStat(const std::string &path); + bool is_file() const; + bool is_dir() const; + +private: + struct stat st_; + int ret_ = -1; +}; + +std::string encode_query_param(const std::string &value); + +std::string decode_url(const std::string &s, bool convert_plus_to_space); + +void read_file(const std::string &path, std::string &out); + +std::string trim_copy(const std::string &s); + +void divide( + const char *data, std::size_t size, char d, + std::function + fn); + +void divide( + const std::string &str, char d, + std::function + fn); + +void split(const char *b, const char *e, char d, + std::function fn); + +void split(const char *b, const char *e, char d, size_t m, + std::function fn); + +bool process_client_socket(socket_t sock, time_t read_timeout_sec, + time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec, + std::function callback); + +socket_t create_client_socket(const std::string &host, const std::string &ip, + int port, int address_family, bool tcp_nodelay, + bool ipv6_v6only, SocketOptions socket_options, + time_t connection_timeout_sec, + time_t connection_timeout_usec, + time_t read_timeout_sec, time_t read_timeout_usec, + time_t write_timeout_sec, + time_t write_timeout_usec, + const std::string &intf, Error &error); + +const char *get_header_value(const Headers &headers, const std::string &key, + const char *def, size_t id); + +std::string params_to_query_str(const Params ¶ms); + +void parse_query_text(const char *data, std::size_t size, Params ¶ms); + +void parse_query_text(const std::string &s, Params ¶ms); + +bool parse_multipart_boundary(const std::string &content_type, + std::string &boundary); + +bool parse_range_header(const std::string &s, Ranges &ranges); + +int close_socket(socket_t sock); + +ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags); + +ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags); + +enum class EncodingType { None = 0, Gzip, Brotli }; + +EncodingType encoding_type(const Request &req, const Response &res); + +class BufferStream final : public Stream { +public: + BufferStream() = default; + ~BufferStream() override = default; + + bool is_readable() const override; + bool is_writable() const override; + ssize_t read(char *ptr, size_t size) override; + ssize_t write(const char *ptr, size_t size) override; + void get_remote_ip_and_port(std::string &ip, int &port) const override; + void get_local_ip_and_port(std::string &ip, int &port) const override; + socket_t socket() const override; + + const std::string &get_buffer() const; + +private: + std::string buffer; + size_t position = 0; +}; + +class compressor { +public: + virtual ~compressor() = default; + + typedef std::function Callback; + virtual bool compress(const char *data, size_t data_length, bool last, + Callback callback) = 0; +}; + +class decompressor { +public: + virtual ~decompressor() = default; + + virtual bool is_valid() const = 0; + + typedef std::function Callback; + virtual bool decompress(const char *data, size_t data_length, + Callback callback) = 0; +}; + +class nocompressor final : public compressor { +public: + ~nocompressor() override = default; + + bool compress(const char *data, size_t data_length, bool /*last*/, + Callback callback) override; +}; + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT +class gzip_compressor final : public compressor { +public: + gzip_compressor(); + ~gzip_compressor() override; + + bool compress(const char *data, size_t data_length, bool last, + Callback callback) override; + +private: + bool is_valid_ = false; + z_stream strm_; +}; + +class gzip_decompressor final : public decompressor { +public: + gzip_decompressor(); + ~gzip_decompressor() override; + + bool is_valid() const override; + + bool decompress(const char *data, size_t data_length, + Callback callback) override; + +private: + bool is_valid_ = false; + z_stream strm_; +}; +#endif + +#ifdef CPPHTTPLIB_BROTLI_SUPPORT +class brotli_compressor final : public compressor { +public: + brotli_compressor(); + ~brotli_compressor(); + + bool compress(const char *data, size_t data_length, bool last, + Callback callback) override; + +private: + BrotliEncoderState *state_ = nullptr; +}; + +class brotli_decompressor final : public decompressor { +public: + brotli_decompressor(); + ~brotli_decompressor(); + + bool is_valid() const override; + + bool decompress(const char *data, size_t data_length, + Callback callback) override; + +private: + BrotliDecoderResult decoder_r; + BrotliDecoderState *decoder_s = nullptr; +}; +#endif + +// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer` +// to store data. The call can set memory on stack for performance. +class stream_line_reader { +public: + stream_line_reader(Stream &strm, char *fixed_buffer, + size_t fixed_buffer_size); + const char *ptr() const; + size_t size() const; + bool end_with_crlf() const; + bool getline(); + +private: + void append(char c); + + Stream &strm_; + char *fixed_buffer_; + const size_t fixed_buffer_size_; + size_t fixed_buffer_used_size_ = 0; + std::string glowable_buffer_; +}; + +class mmap { +public: + mmap(const char *path); + ~mmap(); + + bool open(const char *path); + void close(); + + bool is_open() const; + size_t size() const; + const char *data() const; + +private: +#if defined(_WIN32) + HANDLE hFile_ = NULL; + HANDLE hMapping_ = NULL; +#else + int fd_ = -1; +#endif + size_t size_ = 0; + void *addr_ = nullptr; + bool is_open_empty_file = false; +}; + +} // namespace detail + +// ---------------------------------------------------------------------------- + +/* + * Implementation that will be part of the .cc file if split into .h + .cc. + */ + +namespace detail { + +inline bool is_hex(char c, int &v) { + if (0x20 <= c && isdigit(c)) { + v = c - '0'; + return true; + } else if ('A' <= c && c <= 'F') { + v = c - 'A' + 10; + return true; + } else if ('a' <= c && c <= 'f') { + v = c - 'a' + 10; + return true; + } + return false; +} + +inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, + int &val) { + if (i >= s.size()) { return false; } + + val = 0; + for (; cnt; i++, cnt--) { + if (!s[i]) { return false; } + auto v = 0; + if (is_hex(s[i], v)) { + val = val * 16 + v; + } else { + return false; + } + } + return true; +} + +inline std::string from_i_to_hex(size_t n) { + static const auto charset = "0123456789abcdef"; + std::string ret; + do { + ret = charset[n & 15] + ret; + n >>= 4; + } while (n > 0); + return ret; +} + +inline size_t to_utf8(int code, char *buff) { + if (code < 0x0080) { + buff[0] = static_cast(code & 0x7F); + return 1; + } else if (code < 0x0800) { + buff[0] = static_cast(0xC0 | ((code >> 6) & 0x1F)); + buff[1] = static_cast(0x80 | (code & 0x3F)); + return 2; + } else if (code < 0xD800) { + buff[0] = static_cast(0xE0 | ((code >> 12) & 0xF)); + buff[1] = static_cast(0x80 | ((code >> 6) & 0x3F)); + buff[2] = static_cast(0x80 | (code & 0x3F)); + return 3; + } else if (code < 0xE000) { // D800 - DFFF is invalid... + return 0; + } else if (code < 0x10000) { + buff[0] = static_cast(0xE0 | ((code >> 12) & 0xF)); + buff[1] = static_cast(0x80 | ((code >> 6) & 0x3F)); + buff[2] = static_cast(0x80 | (code & 0x3F)); + return 3; + } else if (code < 0x110000) { + buff[0] = static_cast(0xF0 | ((code >> 18) & 0x7)); + buff[1] = static_cast(0x80 | ((code >> 12) & 0x3F)); + buff[2] = static_cast(0x80 | ((code >> 6) & 0x3F)); + buff[3] = static_cast(0x80 | (code & 0x3F)); + return 4; + } + + // NOTREACHED + return 0; +} + +// NOTE: This code came up with the following stackoverflow post: +// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c +inline std::string base64_encode(const std::string &in) { + static const auto lookup = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string out; + out.reserve(in.size()); + + auto val = 0; + auto valb = -6; + + for (auto c : in) { + val = (val << 8) + static_cast(c); + valb += 8; + while (valb >= 0) { + out.push_back(lookup[(val >> valb) & 0x3F]); + valb -= 6; + } + } + + if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); } + + while (out.size() % 4) { + out.push_back('='); + } + + return out; +} + +inline bool is_valid_path(const std::string &path) { + size_t level = 0; + size_t i = 0; + + // Skip slash + while (i < path.size() && path[i] == '/') { + i++; + } + + while (i < path.size()) { + // Read component + auto beg = i; + while (i < path.size() && path[i] != '/') { + if (path[i] == '\0') { + return false; + } else if (path[i] == '\\') { + return false; + } + i++; + } + + auto len = i - beg; + assert(len > 0); + + if (!path.compare(beg, len, ".")) { + ; + } else if (!path.compare(beg, len, "..")) { + if (level == 0) { return false; } + level--; + } else { + level++; + } + + // Skip slash + while (i < path.size() && path[i] == '/') { + i++; + } + } + + return true; +} + +inline FileStat::FileStat(const std::string &path) { + ret_ = stat(path.c_str(), &st_); +} +inline bool FileStat::is_file() const { + return ret_ >= 0 && S_ISREG(st_.st_mode); +} +inline bool FileStat::is_dir() const { + return ret_ >= 0 && S_ISDIR(st_.st_mode); +} + +inline std::string encode_query_param(const std::string &value) { + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + + for (auto c : value) { + if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || + c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' || + c == ')') { + escaped << c; + } else { + escaped << std::uppercase; + escaped << '%' << std::setw(2) + << static_cast(static_cast(c)); + escaped << std::nouppercase; + } + } + + return escaped.str(); +} + +inline std::string encode_url(const std::string &s) { + std::string result; + result.reserve(s.size()); + + for (size_t i = 0; s[i]; i++) { + switch (s[i]) { + case ' ': result += "%20"; break; + case '+': result += "%2B"; break; + case '\r': result += "%0D"; break; + case '\n': result += "%0A"; break; + case '\'': result += "%27"; break; + case ',': result += "%2C"; break; + // case ':': result += "%3A"; break; // ok? probably... + case ';': result += "%3B"; break; + default: + auto c = static_cast(s[i]); + if (c >= 0x80) { + result += '%'; + char hex[4]; + auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c); + assert(len == 2); + result.append(hex, static_cast(len)); + } else { + result += s[i]; + } + break; + } + } + + return result; +} + +inline std::string decode_url(const std::string &s, + bool convert_plus_to_space) { + std::string result; + + for (size_t i = 0; i < s.size(); i++) { + if (s[i] == '%' && i + 1 < s.size()) { + if (s[i + 1] == 'u') { + auto val = 0; + if (from_hex_to_i(s, i + 2, 4, val)) { + // 4 digits Unicode codes + char buff[4]; + size_t len = to_utf8(val, buff); + if (len > 0) { result.append(buff, len); } + i += 5; // 'u0000' + } else { + result += s[i]; + } + } else { + auto val = 0; + if (from_hex_to_i(s, i + 1, 2, val)) { + // 2 digits hex codes + result += static_cast(val); + i += 2; // '00' + } else { + result += s[i]; + } + } + } else if (convert_plus_to_space && s[i] == '+') { + result += ' '; + } else { + result += s[i]; + } + } + + return result; +} + +inline void read_file(const std::string &path, std::string &out) { + std::ifstream fs(path, std::ios_base::binary); + fs.seekg(0, std::ios_base::end); + auto size = fs.tellg(); + fs.seekg(0); + out.resize(static_cast(size)); + fs.read(&out[0], static_cast(size)); +} + +inline std::string file_extension(const std::string &path) { + std::smatch m; + static auto re = std::regex("\\.([a-zA-Z0-9]+)$"); + if (std::regex_search(path, m, re)) { return m[1].str(); } + return std::string(); +} + +inline bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; } + +inline std::pair trim(const char *b, const char *e, size_t left, + size_t right) { + while (b + left < e && is_space_or_tab(b[left])) { + left++; + } + while (right > 0 && is_space_or_tab(b[right - 1])) { + right--; + } + return std::make_pair(left, right); +} + +inline std::string trim_copy(const std::string &s) { + auto r = trim(s.data(), s.data() + s.size(), 0, s.size()); + return s.substr(r.first, r.second - r.first); +} + +inline std::string trim_double_quotes_copy(const std::string &s) { + if (s.length() >= 2 && s.front() == '"' && s.back() == '"') { + return s.substr(1, s.size() - 2); + } + return s; +} + +inline void +divide(const char *data, std::size_t size, char d, + std::function + fn) { + const auto it = std::find(data, data + size, d); + const auto found = static_cast(it != data + size); + const auto lhs_data = data; + const auto lhs_size = static_cast(it - data); + const auto rhs_data = it + found; + const auto rhs_size = size - lhs_size - found; + + fn(lhs_data, lhs_size, rhs_data, rhs_size); +} + +inline void +divide(const std::string &str, char d, + std::function + fn) { + divide(str.data(), str.size(), d, std::move(fn)); +} + +inline void split(const char *b, const char *e, char d, + std::function fn) { + return split(b, e, d, (std::numeric_limits::max)(), std::move(fn)); +} + +inline void split(const char *b, const char *e, char d, size_t m, + std::function fn) { + size_t i = 0; + size_t beg = 0; + size_t count = 1; + + while (e ? (b + i < e) : (b[i] != '\0')) { + if (b[i] == d && count < m) { + auto r = trim(b, e, beg, i); + if (r.first < r.second) { fn(&b[r.first], &b[r.second]); } + beg = i + 1; + count++; + } + i++; + } + + if (i) { + auto r = trim(b, e, beg, i); + if (r.first < r.second) { fn(&b[r.first], &b[r.second]); } + } +} + +inline stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer, + size_t fixed_buffer_size) + : strm_(strm), fixed_buffer_(fixed_buffer), + fixed_buffer_size_(fixed_buffer_size) {} + +inline const char *stream_line_reader::ptr() const { + if (glowable_buffer_.empty()) { + return fixed_buffer_; + } else { + return glowable_buffer_.data(); + } +} + +inline size_t stream_line_reader::size() const { + if (glowable_buffer_.empty()) { + return fixed_buffer_used_size_; + } else { + return glowable_buffer_.size(); + } +} + +inline bool stream_line_reader::end_with_crlf() const { + auto end = ptr() + size(); + return size() >= 2 && end[-2] == '\r' && end[-1] == '\n'; +} + +inline bool stream_line_reader::getline() { + fixed_buffer_used_size_ = 0; + glowable_buffer_.clear(); + +#ifndef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR + char prev_byte = 0; +#endif + + for (size_t i = 0;; i++) { + char byte; + auto n = strm_.read(&byte, 1); + + if (n < 0) { + return false; + } else if (n == 0) { + if (i == 0) { + return false; + } else { + break; + } + } + + append(byte); + +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR + if (byte == '\n') { break; } +#else + if (prev_byte == '\r' && byte == '\n') { break; } + prev_byte = byte; +#endif + } + + return true; +} + +inline void stream_line_reader::append(char c) { + if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) { + fixed_buffer_[fixed_buffer_used_size_++] = c; + fixed_buffer_[fixed_buffer_used_size_] = '\0'; + } else { + if (glowable_buffer_.empty()) { + assert(fixed_buffer_[fixed_buffer_used_size_] == '\0'); + glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); + } + glowable_buffer_ += c; + } +} + +inline mmap::mmap(const char *path) { open(path); } + +inline mmap::~mmap() { close(); } + +inline bool mmap::open(const char *path) { + close(); + +#if defined(_WIN32) + std::wstring wpath; + for (size_t i = 0; i < strlen(path); i++) { + wpath += path[i]; + } + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8 + hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, NULL); +#else + hFile_ = ::CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +#endif + + if (hFile_ == INVALID_HANDLE_VALUE) { return false; } + + LARGE_INTEGER size{}; + if (!::GetFileSizeEx(hFile_, &size)) { return false; } + // If the following line doesn't compile due to QuadPart, update Windows SDK. + // See: + // https://github.com/yhirose/cpp-httplib/issues/1903#issuecomment-2316520721 + if (static_cast(size.QuadPart) > + (std::numeric_limits::max)()) { + // `size_t` might be 32-bits, on 32-bits Windows. + return false; + } + size_ = static_cast(size.QuadPart); + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8 + hMapping_ = + ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL); +#else + hMapping_ = ::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, 0, 0, NULL); +#endif + + // Special treatment for an empty file... + if (hMapping_ == NULL && size_ == 0) { + close(); + is_open_empty_file = true; + return true; + } + + if (hMapping_ == NULL) { + close(); + return false; + } + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8 + addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0); +#else + addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0); +#endif + + if (addr_ == nullptr) { + close(); + return false; + } +#else + fd_ = ::open(path, O_RDONLY); + if (fd_ == -1) { return false; } + + struct stat sb; + if (fstat(fd_, &sb) == -1) { + close(); + return false; + } + size_ = static_cast(sb.st_size); + + addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0); + + // Special treatment for an empty file... + if (addr_ == MAP_FAILED && size_ == 0) { + close(); + is_open_empty_file = true; + return false; + } +#endif + + return true; +} + +inline bool mmap::is_open() const { + return is_open_empty_file ? true : addr_ != nullptr; +} + +inline size_t mmap::size() const { return size_; } + +inline const char *mmap::data() const { + return is_open_empty_file ? "" : static_cast(addr_); +} + +inline void mmap::close() { +#if defined(_WIN32) + if (addr_) { + ::UnmapViewOfFile(addr_); + addr_ = nullptr; + } + + if (hMapping_) { + ::CloseHandle(hMapping_); + hMapping_ = NULL; + } + + if (hFile_ != INVALID_HANDLE_VALUE) { + ::CloseHandle(hFile_); + hFile_ = INVALID_HANDLE_VALUE; + } + + is_open_empty_file = false; +#else + if (addr_ != nullptr) { + munmap(addr_, size_); + addr_ = nullptr; + } + + if (fd_ != -1) { + ::close(fd_); + fd_ = -1; + } +#endif + size_ = 0; +} +inline int close_socket(socket_t sock) { +#ifdef _WIN32 + return closesocket(sock); +#else + return close(sock); +#endif +} + +template inline ssize_t handle_EINTR(T fn) { + ssize_t res = 0; + while (true) { + res = fn(); + if (res < 0 && errno == EINTR) { + std::this_thread::sleep_for(std::chrono::microseconds{1}); + continue; + } + break; + } + return res; +} + +inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) { + return handle_EINTR([&]() { + return recv(sock, +#ifdef _WIN32 + static_cast(ptr), static_cast(size), +#else + ptr, size, +#endif + flags); + }); +} + +inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size, + int flags) { + return handle_EINTR([&]() { + return send(sock, +#ifdef _WIN32 + static_cast(ptr), static_cast(size), +#else + ptr, size, +#endif + flags); + }); +} + +inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) { +#ifdef CPPHTTPLIB_USE_POLL + struct pollfd pfd_read; + pfd_read.fd = sock; + pfd_read.events = POLLIN; + + auto timeout = static_cast(sec * 1000 + usec / 1000); + + return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); +#else +#ifndef _WIN32 + if (sock >= FD_SETSIZE) { return -1; } +#endif + + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + return handle_EINTR([&]() { + return select(static_cast(sock + 1), &fds, nullptr, nullptr, &tv); + }); +#endif +} + +inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) { +#ifdef CPPHTTPLIB_USE_POLL + struct pollfd pfd_read; + pfd_read.fd = sock; + pfd_read.events = POLLOUT; + + auto timeout = static_cast(sec * 1000 + usec / 1000); + + return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); +#else +#ifndef _WIN32 + if (sock >= FD_SETSIZE) { return -1; } +#endif + + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + return handle_EINTR([&]() { + return select(static_cast(sock + 1), nullptr, &fds, nullptr, &tv); + }); +#endif +} + +inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, + time_t usec) { +#ifdef CPPHTTPLIB_USE_POLL + struct pollfd pfd_read; + pfd_read.fd = sock; + pfd_read.events = POLLIN | POLLOUT; + + auto timeout = static_cast(sec * 1000 + usec / 1000); + + auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); + + if (poll_res == 0) { return Error::ConnectionTimeout; } + + if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) { + auto error = 0; + socklen_t len = sizeof(error); + auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&error), &len); + auto successful = res >= 0 && !error; + return successful ? Error::Success : Error::Connection; + } + + return Error::Connection; +#else +#ifndef _WIN32 + if (sock >= FD_SETSIZE) { return Error::Connection; } +#endif + + fd_set fdsr; + FD_ZERO(&fdsr); + FD_SET(sock, &fdsr); + + auto fdsw = fdsr; + auto fdse = fdsr; + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + auto ret = handle_EINTR([&]() { + return select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv); + }); + + if (ret == 0) { return Error::ConnectionTimeout; } + + if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { + auto error = 0; + socklen_t len = sizeof(error); + auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&error), &len); + auto successful = res >= 0 && !error; + return successful ? Error::Success : Error::Connection; + } + return Error::Connection; +#endif +} + +inline bool is_socket_alive(socket_t sock) { + const auto val = detail::select_read(sock, 0, 0); + if (val == 0) { + return true; + } else if (val < 0 && errno == EBADF) { + return false; + } + char buf[1]; + return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0; +} + +class SocketStream final : public Stream { +public: + SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec, + time_t write_timeout_sec, time_t write_timeout_usec); + ~SocketStream() override; + + bool is_readable() const override; + bool is_writable() const override; + ssize_t read(char *ptr, size_t size) override; + ssize_t write(const char *ptr, size_t size) override; + void get_remote_ip_and_port(std::string &ip, int &port) const override; + void get_local_ip_and_port(std::string &ip, int &port) const override; + socket_t socket() const override; + +private: + socket_t sock_; + time_t read_timeout_sec_; + time_t read_timeout_usec_; + time_t write_timeout_sec_; + time_t write_timeout_usec_; + + std::vector read_buff_; + size_t read_buff_off_ = 0; + size_t read_buff_content_size_ = 0; + + static const size_t read_buff_size_ = 1024l * 4; +}; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +class SSLSocketStream final : public Stream { +public: + SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec, + time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec); + ~SSLSocketStream() override; + + bool is_readable() const override; + bool is_writable() const override; + ssize_t read(char *ptr, size_t size) override; + ssize_t write(const char *ptr, size_t size) override; + void get_remote_ip_and_port(std::string &ip, int &port) const override; + void get_local_ip_and_port(std::string &ip, int &port) const override; + socket_t socket() const override; + +private: + socket_t sock_; + SSL *ssl_; + time_t read_timeout_sec_; + time_t read_timeout_usec_; + time_t write_timeout_sec_; + time_t write_timeout_usec_; +}; +#endif + +inline bool keep_alive(const std::atomic &svr_sock, socket_t sock, + time_t keep_alive_timeout_sec) { + using namespace std::chrono; + + const auto interval_usec = + CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND; + + // Avoid expensive `steady_clock::now()` call for the first time + if (select_read(sock, 0, interval_usec) > 0) { return true; } + + const auto start = steady_clock::now() - microseconds{interval_usec}; + const auto timeout = seconds{keep_alive_timeout_sec}; + + while (true) { + if (svr_sock == INVALID_SOCKET) { + break; // Server socket is closed + } + + auto val = select_read(sock, 0, interval_usec); + if (val < 0) { + break; // Ssocket error + } else if (val == 0) { + if (steady_clock::now() - start > timeout) { + break; // Timeout + } + } else { + return true; // Ready for read + } + + std::this_thread::sleep_for(microseconds{interval_usec}); + } + + return false; +} + +template +inline bool +process_server_socket_core(const std::atomic &svr_sock, socket_t sock, + size_t keep_alive_max_count, + time_t keep_alive_timeout_sec, T callback) { + assert(keep_alive_max_count > 0); + auto ret = false; + auto count = keep_alive_max_count; + while (count > 0 && keep_alive(svr_sock, sock, keep_alive_timeout_sec)) { + auto close_connection = count == 1; + auto connection_closed = false; + ret = callback(close_connection, connection_closed); + if (!ret || connection_closed) { break; } + count--; + } + return ret; +} + +template +inline bool +process_server_socket(const std::atomic &svr_sock, socket_t sock, + size_t keep_alive_max_count, + time_t keep_alive_timeout_sec, time_t read_timeout_sec, + time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec, T callback) { + return process_server_socket_core( + svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec, + [&](bool close_connection, bool &connection_closed) { + SocketStream strm(sock, read_timeout_sec, read_timeout_usec, + write_timeout_sec, write_timeout_usec); + return callback(strm, close_connection, connection_closed); + }); +} + +inline bool process_client_socket(socket_t sock, time_t read_timeout_sec, + time_t read_timeout_usec, + time_t write_timeout_sec, + time_t write_timeout_usec, + std::function callback) { + SocketStream strm(sock, read_timeout_sec, read_timeout_usec, + write_timeout_sec, write_timeout_usec); + return callback(strm); +} + +inline int shutdown_socket(socket_t sock) { +#ifdef _WIN32 + return shutdown(sock, SD_BOTH); +#else + return shutdown(sock, SHUT_RDWR); +#endif +} + +inline std::string escape_abstract_namespace_unix_domain(const std::string &s) { + if (s.size() > 1 && s[0] == '\0') { + auto ret = s; + ret[0] = '@'; + return ret; + } + return s; +} + +inline std::string +unescape_abstract_namespace_unix_domain(const std::string &s) { + if (s.size() > 1 && s[0] == '@') { + auto ret = s; + ret[0] = '\0'; + return ret; + } + return s; +} + +template +socket_t create_socket(const std::string &host, const std::string &ip, int port, + int address_family, int socket_flags, bool tcp_nodelay, + bool ipv6_v6only, SocketOptions socket_options, + BindOrConnect bind_or_connect) { + // Get address info + const char *node = nullptr; + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_IP; + + if (!ip.empty()) { + node = ip.c_str(); + // Ask getaddrinfo to convert IP in c-string to address + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + } else { + if (!host.empty()) { node = host.c_str(); } + hints.ai_family = address_family; + hints.ai_flags = socket_flags; + } + +#ifndef _WIN32 + if (hints.ai_family == AF_UNIX) { + const auto addrlen = host.length(); + if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; } + +#ifdef SOCK_CLOEXEC + auto sock = socket(hints.ai_family, hints.ai_socktype | SOCK_CLOEXEC, + hints.ai_protocol); +#else + auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); +#endif + + if (sock != INVALID_SOCKET) { + sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + + auto unescaped_host = unescape_abstract_namespace_unix_domain(host); + std::copy(unescaped_host.begin(), unescaped_host.end(), addr.sun_path); + + hints.ai_addr = reinterpret_cast(&addr); + hints.ai_addrlen = static_cast( + sizeof(addr) - sizeof(addr.sun_path) + addrlen); + +#ifndef SOCK_CLOEXEC + fcntl(sock, F_SETFD, FD_CLOEXEC); +#endif + + if (socket_options) { socket_options(sock); } + + bool dummy; + if (!bind_or_connect(sock, hints, dummy)) { + close_socket(sock); + sock = INVALID_SOCKET; + } + } + return sock; + } +#endif + + auto service = std::to_string(port); + + if (getaddrinfo(node, service.c_str(), &hints, &result)) { +#if defined __linux__ && !defined __ANDROID__ + res_init(); +#endif + return INVALID_SOCKET; + } + auto se = detail::scope_exit([&] { freeaddrinfo(result); }); + + for (auto rp = result; rp; rp = rp->ai_next) { + // Create a socket +#ifdef _WIN32 + auto sock = + WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0, + WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED); + /** + * Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1 + * and above the socket creation fails on older Windows Systems. + * + * Let's try to create a socket the old way in this case. + * + * Reference: + * https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa + * + * WSA_FLAG_NO_HANDLE_INHERIT: + * This flag is supported on Windows 7 with SP1, Windows Server 2008 R2 with + * SP1, and later + * + */ + if (sock == INVALID_SOCKET) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + } +#else + +#ifdef SOCK_CLOEXEC + auto sock = + socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol); +#else + auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); +#endif + +#endif + if (sock == INVALID_SOCKET) { continue; } + +#if !defined _WIN32 && !defined SOCK_CLOEXEC + if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { + close_socket(sock); + continue; + } +#endif + + if (tcp_nodelay) { + auto opt = 1; +#ifdef _WIN32 + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&opt), sizeof(opt)); +#else + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&opt), sizeof(opt)); +#endif + } + + if (rp->ai_family == AF_INET6) { + auto opt = ipv6_v6only ? 1 : 0; +#ifdef _WIN32 + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&opt), sizeof(opt)); +#else + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&opt), sizeof(opt)); +#endif + } + + if (socket_options) { socket_options(sock); } + + // bind or connect + auto quit = false; + if (bind_or_connect(sock, *rp, quit)) { return sock; } + + close_socket(sock); + + if (quit) { break; } + } + + return INVALID_SOCKET; +} + +inline void set_nonblocking(socket_t sock, bool nonblocking) { +#ifdef _WIN32 + auto flags = nonblocking ? 1UL : 0UL; + ioctlsocket(sock, FIONBIO, &flags); +#else + auto flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, + nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK))); +#endif +} + +inline bool is_connection_error() { +#ifdef _WIN32 + return WSAGetLastError() != WSAEWOULDBLOCK; +#else + return errno != EINPROGRESS; +#endif +} + +inline bool bind_ip_address(socket_t sock, const std::string &host) { + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; } + auto se = detail::scope_exit([&] { freeaddrinfo(result); }); + + auto ret = false; + for (auto rp = result; rp; rp = rp->ai_next) { + const auto &ai = *rp; + if (!::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { + ret = true; + break; + } + } + + return ret; +} + +#if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__ +#define USE_IF2IP +#endif + +#ifdef USE_IF2IP +inline std::string if2ip(int address_family, const std::string &ifn) { + struct ifaddrs *ifap; + getifaddrs(&ifap); + auto se = detail::scope_exit([&] { freeifaddrs(ifap); }); + + std::string addr_candidate; + for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr && ifn == ifa->ifa_name && + (AF_UNSPEC == address_family || + ifa->ifa_addr->sa_family == address_family)) { + if (ifa->ifa_addr->sa_family == AF_INET) { + auto sa = reinterpret_cast(ifa->ifa_addr); + char buf[INET_ADDRSTRLEN]; + if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) { + return std::string(buf, INET_ADDRSTRLEN); + } + } else if (ifa->ifa_addr->sa_family == AF_INET6) { + auto sa = reinterpret_cast(ifa->ifa_addr); + if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) { + char buf[INET6_ADDRSTRLEN] = {}; + if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) { + // equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL + auto s6_addr_head = sa->sin6_addr.s6_addr[0]; + if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) { + addr_candidate = std::string(buf, INET6_ADDRSTRLEN); + } else { + return std::string(buf, INET6_ADDRSTRLEN); + } + } + } + } + } + } + return addr_candidate; +} +#endif + +inline socket_t create_client_socket( + const std::string &host, const std::string &ip, int port, + int address_family, bool tcp_nodelay, bool ipv6_v6only, + SocketOptions socket_options, time_t connection_timeout_sec, + time_t connection_timeout_usec, time_t read_timeout_sec, + time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec, const std::string &intf, Error &error) { + auto sock = create_socket( + host, ip, port, address_family, 0, tcp_nodelay, ipv6_v6only, + std::move(socket_options), + [&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool { + if (!intf.empty()) { +#ifdef USE_IF2IP + auto ip_from_if = if2ip(address_family, intf); + if (ip_from_if.empty()) { ip_from_if = intf; } + if (!bind_ip_address(sock2, ip_from_if)) { + error = Error::BindIPAddress; + return false; + } +#endif + } + + set_nonblocking(sock2, true); + + auto ret = + ::connect(sock2, ai.ai_addr, static_cast(ai.ai_addrlen)); + + if (ret < 0) { + if (is_connection_error()) { + error = Error::Connection; + return false; + } + error = wait_until_socket_is_ready(sock2, connection_timeout_sec, + connection_timeout_usec); + if (error != Error::Success) { + if (error == Error::ConnectionTimeout) { quit = true; } + return false; + } + } + + set_nonblocking(sock2, false); + + { +#ifdef _WIN32 + auto timeout = static_cast(read_timeout_sec * 1000 + + read_timeout_usec / 1000); + setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&timeout), sizeof(timeout)); +#else + timeval tv; + tv.tv_sec = static_cast(read_timeout_sec); + tv.tv_usec = static_cast(read_timeout_usec); + setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&tv), sizeof(tv)); +#endif + } + { + +#ifdef _WIN32 + auto timeout = static_cast(write_timeout_sec * 1000 + + write_timeout_usec / 1000); + setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, + reinterpret_cast(&timeout), sizeof(timeout)); +#else + timeval tv; + tv.tv_sec = static_cast(write_timeout_sec); + tv.tv_usec = static_cast(write_timeout_usec); + setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, + reinterpret_cast(&tv), sizeof(tv)); +#endif + } + + error = Error::Success; + return true; + }); + + if (sock != INVALID_SOCKET) { + error = Error::Success; + } else { + if (error == Error::Success) { error = Error::Connection; } + } + + return sock; +} + +inline bool get_ip_and_port(const struct sockaddr_storage &addr, + socklen_t addr_len, std::string &ip, int &port) { + if (addr.ss_family == AF_INET) { + port = ntohs(reinterpret_cast(&addr)->sin_port); + } else if (addr.ss_family == AF_INET6) { + port = + ntohs(reinterpret_cast(&addr)->sin6_port); + } else { + return false; + } + + std::array ipstr{}; + if (getnameinfo(reinterpret_cast(&addr), addr_len, + ipstr.data(), static_cast(ipstr.size()), nullptr, + 0, NI_NUMERICHOST)) { + return false; + } + + ip = ipstr.data(); + return true; +} + +inline void get_local_ip_and_port(socket_t sock, std::string &ip, int &port) { + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + if (!getsockname(sock, reinterpret_cast(&addr), + &addr_len)) { + get_ip_and_port(addr, addr_len, ip, port); + } +} + +inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) { + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + + if (!getpeername(sock, reinterpret_cast(&addr), + &addr_len)) { +#ifndef _WIN32 + if (addr.ss_family == AF_UNIX) { +#if defined(__linux__) + struct ucred ucred; + socklen_t len = sizeof(ucred); + if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) { + port = ucred.pid; + } +#elif defined(SOL_LOCAL) && defined(SO_PEERPID) // __APPLE__ + pid_t pid; + socklen_t len = sizeof(pid); + if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) { + port = pid; + } +#endif + return; + } +#endif + get_ip_and_port(addr, addr_len, ip, port); + } +} + +inline constexpr unsigned int str2tag_core(const char *s, size_t l, + unsigned int h) { + return (l == 0) + ? h + : str2tag_core( + s + 1, l - 1, + // Unsets the 6 high bits of h, therefore no overflow happens + (((std::numeric_limits::max)() >> 6) & + h * 33) ^ + static_cast(*s)); +} + +inline unsigned int str2tag(const std::string &s) { + return str2tag_core(s.data(), s.size(), 0); +} + +namespace udl { + +inline constexpr unsigned int operator"" _t(const char *s, size_t l) { + return str2tag_core(s, l, 0); +} + +} // namespace udl + +inline std::string +find_content_type(const std::string &path, + const std::map &user_data, + const std::string &default_content_type) { + auto ext = file_extension(path); + + auto it = user_data.find(ext); + if (it != user_data.end()) { return it->second; } + + using udl::operator"" _t; + + switch (str2tag(ext)) { + default: return default_content_type; + + case "css"_t: return "text/css"; + case "csv"_t: return "text/csv"; + case "htm"_t: + case "html"_t: return "text/html"; + case "js"_t: + case "mjs"_t: return "text/javascript"; + case "txt"_t: return "text/plain"; + case "vtt"_t: return "text/vtt"; + + case "apng"_t: return "image/apng"; + case "avif"_t: return "image/avif"; + case "bmp"_t: return "image/bmp"; + case "gif"_t: return "image/gif"; + case "png"_t: return "image/png"; + case "svg"_t: return "image/svg+xml"; + case "webp"_t: return "image/webp"; + case "ico"_t: return "image/x-icon"; + case "tif"_t: return "image/tiff"; + case "tiff"_t: return "image/tiff"; + case "jpg"_t: + case "jpeg"_t: return "image/jpeg"; + + case "mp4"_t: return "video/mp4"; + case "mpeg"_t: return "video/mpeg"; + case "webm"_t: return "video/webm"; + + case "mp3"_t: return "audio/mp3"; + case "mpga"_t: return "audio/mpeg"; + case "weba"_t: return "audio/webm"; + case "wav"_t: return "audio/wave"; + + case "otf"_t: return "font/otf"; + case "ttf"_t: return "font/ttf"; + case "woff"_t: return "font/woff"; + case "woff2"_t: return "font/woff2"; + + case "7z"_t: return "application/x-7z-compressed"; + case "atom"_t: return "application/atom+xml"; + case "pdf"_t: return "application/pdf"; + case "json"_t: return "application/json"; + case "rss"_t: return "application/rss+xml"; + case "tar"_t: return "application/x-tar"; + case "xht"_t: + case "xhtml"_t: return "application/xhtml+xml"; + case "xslt"_t: return "application/xslt+xml"; + case "xml"_t: return "application/xml"; + case "gz"_t: return "application/gzip"; + case "zip"_t: return "application/zip"; + case "wasm"_t: return "application/wasm"; + } +} + +inline bool can_compress_content_type(const std::string &content_type) { + using udl::operator"" _t; + + auto tag = str2tag(content_type); + + switch (tag) { + case "image/svg+xml"_t: + case "application/javascript"_t: + case "application/json"_t: + case "application/xml"_t: + case "application/protobuf"_t: + case "application/xhtml+xml"_t: return true; + + case "text/event-stream"_t: return false; + + default: return !content_type.rfind("text/", 0); + } +} + +inline EncodingType encoding_type(const Request &req, const Response &res) { + auto ret = + detail::can_compress_content_type(res.get_header_value("Content-Type")); + if (!ret) { return EncodingType::None; } + + const auto &s = req.get_header_value("Accept-Encoding"); + (void)(s); + +#ifdef CPPHTTPLIB_BROTLI_SUPPORT + // TODO: 'Accept-Encoding' has br, not br;q=0 + ret = s.find("br") != std::string::npos; + if (ret) { return EncodingType::Brotli; } +#endif + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + // TODO: 'Accept-Encoding' has gzip, not gzip;q=0 + ret = s.find("gzip") != std::string::npos; + if (ret) { return EncodingType::Gzip; } +#endif + + return EncodingType::None; +} + +inline bool nocompressor::compress(const char *data, size_t data_length, + bool /*last*/, Callback callback) { + if (!data_length) { return true; } + return callback(data, data_length); +} + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT +inline gzip_compressor::gzip_compressor() { + std::memset(&strm_, 0, sizeof(strm_)); + strm_.zalloc = Z_NULL; + strm_.zfree = Z_NULL; + strm_.opaque = Z_NULL; + + is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, + Z_DEFAULT_STRATEGY) == Z_OK; +} + +inline gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); } + +inline bool gzip_compressor::compress(const char *data, size_t data_length, + bool last, Callback callback) { + assert(is_valid_); + + do { + constexpr size_t max_avail_in = + (std::numeric_limits::max)(); + + strm_.avail_in = static_cast( + (std::min)(data_length, max_avail_in)); + strm_.next_in = const_cast(reinterpret_cast(data)); + + data_length -= strm_.avail_in; + data += strm_.avail_in; + + auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH; + auto ret = Z_OK; + + std::array buff{}; + do { + strm_.avail_out = static_cast(buff.size()); + strm_.next_out = reinterpret_cast(buff.data()); + + ret = deflate(&strm_, flush); + if (ret == Z_STREAM_ERROR) { return false; } + + if (!callback(buff.data(), buff.size() - strm_.avail_out)) { + return false; + } + } while (strm_.avail_out == 0); + + assert((flush == Z_FINISH && ret == Z_STREAM_END) || + (flush == Z_NO_FLUSH && ret == Z_OK)); + assert(strm_.avail_in == 0); + } while (data_length > 0); + + return true; +} + +inline gzip_decompressor::gzip_decompressor() { + std::memset(&strm_, 0, sizeof(strm_)); + strm_.zalloc = Z_NULL; + strm_.zfree = Z_NULL; + strm_.opaque = Z_NULL; + + // 15 is the value of wbits, which should be at the maximum possible value + // to ensure that any gzip stream can be decoded. The offset of 32 specifies + // that the stream type should be automatically detected either gzip or + // deflate. + is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK; +} + +inline gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); } + +inline bool gzip_decompressor::is_valid() const { return is_valid_; } + +inline bool gzip_decompressor::decompress(const char *data, size_t data_length, + Callback callback) { + assert(is_valid_); + + auto ret = Z_OK; + + do { + constexpr size_t max_avail_in = + (std::numeric_limits::max)(); + + strm_.avail_in = static_cast( + (std::min)(data_length, max_avail_in)); + strm_.next_in = const_cast(reinterpret_cast(data)); + + data_length -= strm_.avail_in; + data += strm_.avail_in; + + std::array buff{}; + while (strm_.avail_in > 0 && ret == Z_OK) { + strm_.avail_out = static_cast(buff.size()); + strm_.next_out = reinterpret_cast(buff.data()); + + ret = inflate(&strm_, Z_NO_FLUSH); + + assert(ret != Z_STREAM_ERROR); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: inflateEnd(&strm_); return false; + } + + if (!callback(buff.data(), buff.size() - strm_.avail_out)) { + return false; + } + } + + if (ret != Z_OK && ret != Z_STREAM_END) { return false; } + + } while (data_length > 0); + + return true; +} +#endif + +#ifdef CPPHTTPLIB_BROTLI_SUPPORT +inline brotli_compressor::brotli_compressor() { + state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr); +} + +inline brotli_compressor::~brotli_compressor() { + BrotliEncoderDestroyInstance(state_); +} + +inline bool brotli_compressor::compress(const char *data, size_t data_length, + bool last, Callback callback) { + std::array buff{}; + + auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS; + auto available_in = data_length; + auto next_in = reinterpret_cast(data); + + for (;;) { + if (last) { + if (BrotliEncoderIsFinished(state_)) { break; } + } else { + if (!available_in) { break; } + } + + auto available_out = buff.size(); + auto next_out = buff.data(); + + if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in, + &available_out, &next_out, nullptr)) { + return false; + } + + auto output_bytes = buff.size() - available_out; + if (output_bytes) { + callback(reinterpret_cast(buff.data()), output_bytes); + } + } + + return true; +} + +inline brotli_decompressor::brotli_decompressor() { + decoder_s = BrotliDecoderCreateInstance(0, 0, 0); + decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT + : BROTLI_DECODER_RESULT_ERROR; +} + +inline brotli_decompressor::~brotli_decompressor() { + if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); } +} + +inline bool brotli_decompressor::is_valid() const { return decoder_s; } + +inline bool brotli_decompressor::decompress(const char *data, + size_t data_length, + Callback callback) { + if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS || + decoder_r == BROTLI_DECODER_RESULT_ERROR) { + return 0; + } + + auto next_in = reinterpret_cast(data); + size_t avail_in = data_length; + size_t total_out; + + decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; + + std::array buff{}; + while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { + char *next_out = buff.data(); + size_t avail_out = buff.size(); + + decoder_r = BrotliDecoderDecompressStream( + decoder_s, &avail_in, &next_in, &avail_out, + reinterpret_cast(&next_out), &total_out); + + if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; } + + if (!callback(buff.data(), buff.size() - avail_out)) { return false; } + } + + return decoder_r == BROTLI_DECODER_RESULT_SUCCESS || + decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT; +} +#endif + +inline bool has_header(const Headers &headers, const std::string &key) { + return headers.find(key) != headers.end(); +} + +inline const char *get_header_value(const Headers &headers, + const std::string &key, const char *def, + size_t id) { + auto rng = headers.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { return it->second.c_str(); } + return def; +} + +template +inline bool parse_header(const char *beg, const char *end, T fn) { + // Skip trailing spaces and tabs. + while (beg < end && is_space_or_tab(end[-1])) { + end--; + } + + auto p = beg; + while (p < end && *p != ':') { + p++; + } + + if (p == end) { return false; } + + auto key_end = p; + + if (*p++ != ':') { return false; } + + while (p < end && is_space_or_tab(*p)) { + p++; + } + + if (p <= end) { + auto key_len = key_end - beg; + if (!key_len) { return false; } + + auto key = std::string(beg, key_end); + auto val = case_ignore::equal(key, "Location") + ? std::string(p, end) + : decode_url(std::string(p, end), false); + + // NOTE: From RFC 9110: + // Field values containing CR, LF, or NUL characters are + // invalid and dangerous, due to the varying ways that + // implementations might parse and interpret those + // characters; a recipient of CR, LF, or NUL within a field + // value MUST either reject the message or replace each of + // those characters with SP before further processing or + // forwarding of that message. + static const std::string CR_LF_NUL("\r\n\0", 3); + if (val.find_first_of(CR_LF_NUL) != std::string::npos) { return false; } + + fn(key, val); + return true; + } + + return false; +} + +inline bool read_headers(Stream &strm, Headers &headers) { + const auto bufsiz = 2048; + char buf[bufsiz]; + stream_line_reader line_reader(strm, buf, bufsiz); + + for (;;) { + if (!line_reader.getline()) { return false; } + + // Check if the line ends with CRLF. + auto line_terminator_len = 2; + if (line_reader.end_with_crlf()) { + // Blank line indicates end of headers. + if (line_reader.size() == 2) { break; } + } else { +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR + // Blank line indicates end of headers. + if (line_reader.size() == 1) { break; } + line_terminator_len = 1; +#else + continue; // Skip invalid line. +#endif + } + + if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } + + // Exclude line terminator + auto end = line_reader.ptr() + line_reader.size() - line_terminator_len; + + if (!parse_header(line_reader.ptr(), end, + [&](const std::string &key, std::string &val) { + headers.emplace(key, val); + })) { + return false; + } + } + + return true; +} + +inline bool read_content_with_length(Stream &strm, uint64_t len, + Progress progress, + ContentReceiverWithProgress out) { + char buf[CPPHTTPLIB_RECV_BUFSIZ]; + + uint64_t r = 0; + while (r < len) { + auto read_len = static_cast(len - r); + auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ)); + if (n <= 0) { return false; } + + if (!out(buf, static_cast(n), r, len)) { return false; } + r += static_cast(n); + + if (progress) { + if (!progress(r, len)) { return false; } + } + } + + return true; +} + +inline void skip_content_with_length(Stream &strm, uint64_t len) { + char buf[CPPHTTPLIB_RECV_BUFSIZ]; + uint64_t r = 0; + while (r < len) { + auto read_len = static_cast(len - r); + auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ)); + if (n <= 0) { return; } + r += static_cast(n); + } +} + +inline bool read_content_without_length(Stream &strm, + ContentReceiverWithProgress out) { + char buf[CPPHTTPLIB_RECV_BUFSIZ]; + uint64_t r = 0; + for (;;) { + auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ); + if (n <= 0) { return true; } + + if (!out(buf, static_cast(n), r, 0)) { return false; } + r += static_cast(n); + } + + return true; +} + +template +inline bool read_content_chunked(Stream &strm, T &x, + ContentReceiverWithProgress out) { + const auto bufsiz = 16; + char buf[bufsiz]; + + stream_line_reader line_reader(strm, buf, bufsiz); + + if (!line_reader.getline()) { return false; } + + unsigned long chunk_len; + while (true) { + char *end_ptr; + + chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16); + + if (end_ptr == line_reader.ptr()) { return false; } + if (chunk_len == ULONG_MAX) { return false; } + + if (chunk_len == 0) { break; } + + if (!read_content_with_length(strm, chunk_len, nullptr, out)) { + return false; + } + + if (!line_reader.getline()) { return false; } + + if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; } + + if (!line_reader.getline()) { return false; } + } + + assert(chunk_len == 0); + + // NOTE: In RFC 9112, '7.1 Chunked Transfer Coding' mentiones "The chunked + // transfer coding is complete when a chunk with a chunk-size of zero is + // received, possibly followed by a trailer section, and finally terminated by + // an empty line". https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1 + // + // In '7.1.3. Decoding Chunked', however, the pseudo-code in the section + // does't care for the existence of the final CRLF. In other words, it seems + // to be ok whether the final CRLF exists or not in the chunked data. + // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1.3 + // + // According to the reference code in RFC 9112, cpp-htpplib now allows + // chuncked transfer coding data without the final CRLF. + if (!line_reader.getline()) { return true; } + + while (strcmp(line_reader.ptr(), "\r\n") != 0) { + if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } + + // Exclude line terminator + constexpr auto line_terminator_len = 2; + auto end = line_reader.ptr() + line_reader.size() - line_terminator_len; + + parse_header(line_reader.ptr(), end, + [&](const std::string &key, const std::string &val) { + x.headers.emplace(key, val); + }); + + if (!line_reader.getline()) { return false; } + } + + return true; +} + +inline bool is_chunked_transfer_encoding(const Headers &headers) { + return case_ignore::equal( + get_header_value(headers, "Transfer-Encoding", "", 0), "chunked"); +} + +template +bool prepare_content_receiver(T &x, int &status, + ContentReceiverWithProgress receiver, + bool decompress, U callback) { + if (decompress) { + std::string encoding = x.get_header_value("Content-Encoding"); + std::unique_ptr decompressor; + + if (encoding == "gzip" || encoding == "deflate") { +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + decompressor = detail::make_unique(); +#else + status = StatusCode::UnsupportedMediaType_415; + return false; +#endif + } else if (encoding.find("br") != std::string::npos) { +#ifdef CPPHTTPLIB_BROTLI_SUPPORT + decompressor = detail::make_unique(); +#else + status = StatusCode::UnsupportedMediaType_415; + return false; +#endif + } + + if (decompressor) { + if (decompressor->is_valid()) { + ContentReceiverWithProgress out = [&](const char *buf, size_t n, + uint64_t off, uint64_t len) { + return decompressor->decompress(buf, n, + [&](const char *buf2, size_t n2) { + return receiver(buf2, n2, off, len); + }); + }; + return callback(std::move(out)); + } else { + status = StatusCode::InternalServerError_500; + return false; + } + } + } + + ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off, + uint64_t len) { + return receiver(buf, n, off, len); + }; + return callback(std::move(out)); +} + +template +bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, + Progress progress, ContentReceiverWithProgress receiver, + bool decompress) { + return prepare_content_receiver( + x, status, std::move(receiver), decompress, + [&](const ContentReceiverWithProgress &out) { + auto ret = true; + auto exceed_payload_max_length = false; + + if (is_chunked_transfer_encoding(x.headers)) { + ret = read_content_chunked(strm, x, out); + } else if (!has_header(x.headers, "Content-Length")) { + ret = read_content_without_length(strm, out); + } else { + auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0); + if (len > payload_max_length) { + exceed_payload_max_length = true; + skip_content_with_length(strm, len); + ret = false; + } else if (len > 0) { + ret = read_content_with_length(strm, len, std::move(progress), out); + } + } + + if (!ret) { + status = exceed_payload_max_length ? StatusCode::PayloadTooLarge_413 + : StatusCode::BadRequest_400; + } + return ret; + }); +} + +inline ssize_t write_request_line(Stream &strm, const std::string &method, + const std::string &path) { + std::string s = method; + s += " "; + s += path; + s += " HTTP/1.1\r\n"; + return strm.write(s.data(), s.size()); +} + +inline ssize_t write_response_line(Stream &strm, int status) { + std::string s = "HTTP/1.1 "; + s += std::to_string(status); + s += " "; + s += httplib::status_message(status); + s += "\r\n"; + return strm.write(s.data(), s.size()); +} + +inline ssize_t write_headers(Stream &strm, const Headers &headers) { + ssize_t write_len = 0; + for (const auto &x : headers) { + std::string s; + s = x.first; + s += ": "; + s += x.second; + s += "\r\n"; + + auto len = strm.write(s.data(), s.size()); + if (len < 0) { return len; } + write_len += len; + } + auto len = strm.write("\r\n"); + if (len < 0) { return len; } + write_len += len; + return write_len; +} + +inline bool write_data(Stream &strm, const char *d, size_t l) { + size_t offset = 0; + while (offset < l) { + auto length = strm.write(d + offset, l - offset); + if (length < 0) { return false; } + offset += static_cast(length); + } + return true; +} + +template +inline bool write_content(Stream &strm, const ContentProvider &content_provider, + size_t offset, size_t length, T is_shutting_down, + Error &error) { + size_t end_offset = offset + length; + auto ok = true; + DataSink data_sink; + + data_sink.write = [&](const char *d, size_t l) -> bool { + if (ok) { + if (strm.is_writable() && write_data(strm, d, l)) { + offset += l; + } else { + ok = false; + } + } + return ok; + }; + + data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; + + while (offset < end_offset && !is_shutting_down()) { + if (!strm.is_writable()) { + error = Error::Write; + return false; + } else if (!content_provider(offset, end_offset - offset, data_sink)) { + error = Error::Canceled; + return false; + } else if (!ok) { + error = Error::Write; + return false; + } + } + + error = Error::Success; + return true; +} + +template +inline bool write_content(Stream &strm, const ContentProvider &content_provider, + size_t offset, size_t length, + const T &is_shutting_down) { + auto error = Error::Success; + return write_content(strm, content_provider, offset, length, is_shutting_down, + error); +} + +template +inline bool +write_content_without_length(Stream &strm, + const ContentProvider &content_provider, + const T &is_shutting_down) { + size_t offset = 0; + auto data_available = true; + auto ok = true; + DataSink data_sink; + + data_sink.write = [&](const char *d, size_t l) -> bool { + if (ok) { + offset += l; + if (!strm.is_writable() || !write_data(strm, d, l)) { ok = false; } + } + return ok; + }; + + data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; + + data_sink.done = [&](void) { data_available = false; }; + + while (data_available && !is_shutting_down()) { + if (!strm.is_writable()) { + return false; + } else if (!content_provider(offset, 0, data_sink)) { + return false; + } else if (!ok) { + return false; + } + } + return true; +} + +template +inline bool +write_content_chunked(Stream &strm, const ContentProvider &content_provider, + const T &is_shutting_down, U &compressor, Error &error) { + size_t offset = 0; + auto data_available = true; + auto ok = true; + DataSink data_sink; + + data_sink.write = [&](const char *d, size_t l) -> bool { + if (ok) { + data_available = l > 0; + offset += l; + + std::string payload; + if (compressor.compress(d, l, false, + [&](const char *data, size_t data_len) { + payload.append(data, data_len); + return true; + })) { + if (!payload.empty()) { + // Emit chunked response header and footer for each chunk + auto chunk = + from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; + if (!strm.is_writable() || + !write_data(strm, chunk.data(), chunk.size())) { + ok = false; + } + } + } else { + ok = false; + } + } + return ok; + }; + + data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; + + auto done_with_trailer = [&](const Headers *trailer) { + if (!ok) { return; } + + data_available = false; + + std::string payload; + if (!compressor.compress(nullptr, 0, true, + [&](const char *data, size_t data_len) { + payload.append(data, data_len); + return true; + })) { + ok = false; + return; + } + + if (!payload.empty()) { + // Emit chunked response header and footer for each chunk + auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; + if (!strm.is_writable() || + !write_data(strm, chunk.data(), chunk.size())) { + ok = false; + return; + } + } + + static const std::string done_marker("0\r\n"); + if (!write_data(strm, done_marker.data(), done_marker.size())) { + ok = false; + } + + // Trailer + if (trailer) { + for (const auto &kv : *trailer) { + std::string field_line = kv.first + ": " + kv.second + "\r\n"; + if (!write_data(strm, field_line.data(), field_line.size())) { + ok = false; + } + } + } + + static const std::string crlf("\r\n"); + if (!write_data(strm, crlf.data(), crlf.size())) { ok = false; } + }; + + data_sink.done = [&](void) { done_with_trailer(nullptr); }; + + data_sink.done_with_trailer = [&](const Headers &trailer) { + done_with_trailer(&trailer); + }; + + while (data_available && !is_shutting_down()) { + if (!strm.is_writable()) { + error = Error::Write; + return false; + } else if (!content_provider(offset, 0, data_sink)) { + error = Error::Canceled; + return false; + } else if (!ok) { + error = Error::Write; + return false; + } + } + + error = Error::Success; + return true; +} + +template +inline bool write_content_chunked(Stream &strm, + const ContentProvider &content_provider, + const T &is_shutting_down, U &compressor) { + auto error = Error::Success; + return write_content_chunked(strm, content_provider, is_shutting_down, + compressor, error); +} + +template +inline bool redirect(T &cli, Request &req, Response &res, + const std::string &path, const std::string &location, + Error &error) { + Request new_req = req; + new_req.path = path; + new_req.redirect_count_ -= 1; + + if (res.status == StatusCode::SeeOther_303 && + (req.method != "GET" && req.method != "HEAD")) { + new_req.method = "GET"; + new_req.body.clear(); + new_req.headers.clear(); + } + + Response new_res; + + auto ret = cli.send(new_req, new_res, error); + if (ret) { + req = new_req; + res = new_res; + + if (res.location.empty()) { res.location = location; } + } + return ret; +} + +inline std::string params_to_query_str(const Params ¶ms) { + std::string query; + + for (auto it = params.begin(); it != params.end(); ++it) { + if (it != params.begin()) { query += "&"; } + query += it->first; + query += "="; + query += encode_query_param(it->second); + } + return query; +} + +inline void parse_query_text(const char *data, std::size_t size, + Params ¶ms) { + std::set cache; + split(data, data + size, '&', [&](const char *b, const char *e) { + std::string kv(b, e); + if (cache.find(kv) != cache.end()) { return; } + cache.insert(std::move(kv)); + + std::string key; + std::string val; + divide(b, static_cast(e - b), '=', + [&](const char *lhs_data, std::size_t lhs_size, const char *rhs_data, + std::size_t rhs_size) { + key.assign(lhs_data, lhs_size); + val.assign(rhs_data, rhs_size); + }); + + if (!key.empty()) { + params.emplace(decode_url(key, true), decode_url(val, true)); + } + }); +} + +inline void parse_query_text(const std::string &s, Params ¶ms) { + parse_query_text(s.data(), s.size(), params); +} + +inline bool parse_multipart_boundary(const std::string &content_type, + std::string &boundary) { + auto boundary_keyword = "boundary="; + auto pos = content_type.find(boundary_keyword); + if (pos == std::string::npos) { return false; } + auto end = content_type.find(';', pos); + auto beg = pos + strlen(boundary_keyword); + boundary = trim_double_quotes_copy(content_type.substr(beg, end - beg)); + return !boundary.empty(); +} + +inline void parse_disposition_params(const std::string &s, Params ¶ms) { + std::set cache; + split(s.data(), s.data() + s.size(), ';', [&](const char *b, const char *e) { + std::string kv(b, e); + if (cache.find(kv) != cache.end()) { return; } + cache.insert(kv); + + std::string key; + std::string val; + split(b, e, '=', [&](const char *b2, const char *e2) { + if (key.empty()) { + key.assign(b2, e2); + } else { + val.assign(b2, e2); + } + }); + + if (!key.empty()) { + params.emplace(trim_double_quotes_copy((key)), + trim_double_quotes_copy((val))); + } + }); +} + +#ifdef CPPHTTPLIB_NO_EXCEPTIONS +inline bool parse_range_header(const std::string &s, Ranges &ranges) { +#else +inline bool parse_range_header(const std::string &s, Ranges &ranges) try { +#endif + auto is_valid = [](const std::string &str) { + return std::all_of(str.cbegin(), str.cend(), + [](unsigned char c) { return std::isdigit(c); }); + }; + + if (s.size() > 7 && s.compare(0, 6, "bytes=") == 0) { + const auto pos = static_cast(6); + const auto len = static_cast(s.size() - 6); + auto all_valid_ranges = true; + split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) { + if (!all_valid_ranges) { return; } + + const auto it = std::find(b, e, '-'); + if (it == e) { + all_valid_ranges = false; + return; + } + + const auto lhs = std::string(b, it); + const auto rhs = std::string(it + 1, e); + if (!is_valid(lhs) || !is_valid(rhs)) { + all_valid_ranges = false; + return; + } + + const auto first = + static_cast(lhs.empty() ? -1 : std::stoll(lhs)); + const auto last = + static_cast(rhs.empty() ? -1 : std::stoll(rhs)); + if ((first == -1 && last == -1) || + (first != -1 && last != -1 && first > last)) { + all_valid_ranges = false; + return; + } + + ranges.emplace_back(first, last); + }); + return all_valid_ranges && !ranges.empty(); + } + return false; +#ifdef CPPHTTPLIB_NO_EXCEPTIONS +} +#else +} catch (...) { return false; } +#endif + +class MultipartFormDataParser { +public: + MultipartFormDataParser() = default; + + void set_boundary(std::string &&boundary) { + boundary_ = boundary; + dash_boundary_crlf_ = dash_ + boundary_ + crlf_; + crlf_dash_boundary_ = crlf_ + dash_ + boundary_; + } + + bool is_valid() const { return is_valid_; } + + bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, + const MultipartContentHeader &header_callback) { + + buf_append(buf, n); + + while (buf_size() > 0) { + switch (state_) { + case 0: { // Initial boundary + buf_erase(buf_find(dash_boundary_crlf_)); + if (dash_boundary_crlf_.size() > buf_size()) { return true; } + if (!buf_start_with(dash_boundary_crlf_)) { return false; } + buf_erase(dash_boundary_crlf_.size()); + state_ = 1; + break; + } + case 1: { // New entry + clear_file_info(); + state_ = 2; + break; + } + case 2: { // Headers + auto pos = buf_find(crlf_); + if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } + while (pos < buf_size()) { + // Empty line + if (pos == 0) { + if (!header_callback(file_)) { + is_valid_ = false; + return false; + } + buf_erase(crlf_.size()); + state_ = 3; + break; + } + + const auto header = buf_head(pos); + + if (!parse_header(header.data(), header.data() + header.size(), + [&](const std::string &, const std::string &) {})) { + is_valid_ = false; + return false; + } + + static const std::string header_content_type = "Content-Type:"; + + if (start_with_case_ignore(header, header_content_type)) { + file_.content_type = + trim_copy(header.substr(header_content_type.size())); + } else { + static const std::regex re_content_disposition( + R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~", + std::regex_constants::icase); + + std::smatch m; + if (std::regex_match(header, m, re_content_disposition)) { + Params params; + parse_disposition_params(m[1], params); + + auto it = params.find("name"); + if (it != params.end()) { + file_.name = it->second; + } else { + is_valid_ = false; + return false; + } + + it = params.find("filename"); + if (it != params.end()) { file_.filename = it->second; } + + it = params.find("filename*"); + if (it != params.end()) { + // Only allow UTF-8 enconnding... + static const std::regex re_rfc5987_encoding( + R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase); + + std::smatch m2; + if (std::regex_match(it->second, m2, re_rfc5987_encoding)) { + file_.filename = decode_url(m2[1], false); // override... + } else { + is_valid_ = false; + return false; + } + } + } + } + buf_erase(pos + crlf_.size()); + pos = buf_find(crlf_); + } + if (state_ != 3) { return true; } + break; + } + case 3: { // Body + if (crlf_dash_boundary_.size() > buf_size()) { return true; } + auto pos = buf_find(crlf_dash_boundary_); + if (pos < buf_size()) { + if (!content_callback(buf_data(), pos)) { + is_valid_ = false; + return false; + } + buf_erase(pos + crlf_dash_boundary_.size()); + state_ = 4; + } else { + auto len = buf_size() - crlf_dash_boundary_.size(); + if (len > 0) { + if (!content_callback(buf_data(), len)) { + is_valid_ = false; + return false; + } + buf_erase(len); + } + return true; + } + break; + } + case 4: { // Boundary + if (crlf_.size() > buf_size()) { return true; } + if (buf_start_with(crlf_)) { + buf_erase(crlf_.size()); + state_ = 1; + } else { + if (dash_.size() > buf_size()) { return true; } + if (buf_start_with(dash_)) { + buf_erase(dash_.size()); + is_valid_ = true; + buf_erase(buf_size()); // Remove epilogue + } else { + return true; + } + } + break; + } + } + } + + return true; + } + +private: + void clear_file_info() { + file_.name.clear(); + file_.filename.clear(); + file_.content_type.clear(); + } + + bool start_with_case_ignore(const std::string &a, + const std::string &b) const { + if (a.size() < b.size()) { return false; } + for (size_t i = 0; i < b.size(); i++) { + if (case_ignore::to_lower(a[i]) != case_ignore::to_lower(b[i])) { + return false; + } + } + return true; + } + + const std::string dash_ = "--"; + const std::string crlf_ = "\r\n"; + std::string boundary_; + std::string dash_boundary_crlf_; + std::string crlf_dash_boundary_; + + size_t state_ = 0; + bool is_valid_ = false; + MultipartFormData file_; + + // Buffer + bool start_with(const std::string &a, size_t spos, size_t epos, + const std::string &b) const { + if (epos - spos < b.size()) { return false; } + for (size_t i = 0; i < b.size(); i++) { + if (a[i + spos] != b[i]) { return false; } + } + return true; + } + + size_t buf_size() const { return buf_epos_ - buf_spos_; } + + const char *buf_data() const { return &buf_[buf_spos_]; } + + std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); } + + bool buf_start_with(const std::string &s) const { + return start_with(buf_, buf_spos_, buf_epos_, s); + } + + size_t buf_find(const std::string &s) const { + auto c = s.front(); + + size_t off = buf_spos_; + while (off < buf_epos_) { + auto pos = off; + while (true) { + if (pos == buf_epos_) { return buf_size(); } + if (buf_[pos] == c) { break; } + pos++; + } + + auto remaining_size = buf_epos_ - pos; + if (s.size() > remaining_size) { return buf_size(); } + + if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; } + + off = pos + 1; + } + + return buf_size(); + } + + void buf_append(const char *data, size_t n) { + auto remaining_size = buf_size(); + if (remaining_size > 0 && buf_spos_ > 0) { + for (size_t i = 0; i < remaining_size; i++) { + buf_[i] = buf_[buf_spos_ + i]; + } + } + buf_spos_ = 0; + buf_epos_ = remaining_size; + + if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); } + + for (size_t i = 0; i < n; i++) { + buf_[buf_epos_ + i] = data[i]; + } + buf_epos_ += n; + } + + void buf_erase(size_t size) { buf_spos_ += size; } + + std::string buf_; + size_t buf_spos_ = 0; + size_t buf_epos_ = 0; +}; + +inline std::string random_string(size_t length) { + static const char data[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + // std::random_device might actually be deterministic on some + // platforms, but due to lack of support in the c++ standard library, + // doing better requires either some ugly hacks or breaking portability. + static std::random_device seed_gen; + + // Request 128 bits of entropy for initialization + static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), + seed_gen()}; + + static std::mt19937 engine(seed_sequence); + + std::string result; + for (size_t i = 0; i < length; i++) { + result += data[engine() % (sizeof(data) - 1)]; + } + return result; +} + +inline std::string make_multipart_data_boundary() { + return "--cpp-httplib-multipart-data-" + detail::random_string(16); +} + +inline bool is_multipart_boundary_chars_valid(const std::string &boundary) { + auto valid = true; + for (size_t i = 0; i < boundary.size(); i++) { + auto c = boundary[i]; + if (!std::isalnum(c) && c != '-' && c != '_') { + valid = false; + break; + } + } + return valid; +} + +template +inline std::string +serialize_multipart_formdata_item_begin(const T &item, + const std::string &boundary) { + std::string body = "--" + boundary + "\r\n"; + body += "Content-Disposition: form-data; name=\"" + item.name + "\""; + if (!item.filename.empty()) { + body += "; filename=\"" + item.filename + "\""; + } + body += "\r\n"; + if (!item.content_type.empty()) { + body += "Content-Type: " + item.content_type + "\r\n"; + } + body += "\r\n"; + + return body; +} + +inline std::string serialize_multipart_formdata_item_end() { return "\r\n"; } + +inline std::string +serialize_multipart_formdata_finish(const std::string &boundary) { + return "--" + boundary + "--\r\n"; +} + +inline std::string +serialize_multipart_formdata_get_content_type(const std::string &boundary) { + return "multipart/form-data; boundary=" + boundary; +} + +inline std::string +serialize_multipart_formdata(const MultipartFormDataItems &items, + const std::string &boundary, bool finish = true) { + std::string body; + + for (const auto &item : items) { + body += serialize_multipart_formdata_item_begin(item, boundary); + body += item.content + serialize_multipart_formdata_item_end(); + } + + if (finish) { body += serialize_multipart_formdata_finish(boundary); } + + return body; +} + +inline bool range_error(Request &req, Response &res) { + if (!req.ranges.empty() && 200 <= res.status && res.status < 300) { + ssize_t contant_len = static_cast( + res.content_length_ ? res.content_length_ : res.body.size()); + + ssize_t prev_first_pos = -1; + ssize_t prev_last_pos = -1; + size_t overwrapping_count = 0; + + // NOTE: The following Range check is based on '14.2. Range' in RFC 9110 + // 'HTTP Semantics' to avoid potential denial-of-service attacks. + // https://www.rfc-editor.org/rfc/rfc9110#section-14.2 + + // Too many ranges + if (req.ranges.size() > CPPHTTPLIB_RANGE_MAX_COUNT) { return true; } + + for (auto &r : req.ranges) { + auto &first_pos = r.first; + auto &last_pos = r.second; + + if (first_pos == -1 && last_pos == -1) { + first_pos = 0; + last_pos = contant_len; + } + + if (first_pos == -1) { + first_pos = contant_len - last_pos; + last_pos = contant_len - 1; + } + + if (last_pos == -1) { last_pos = contant_len - 1; } + + // Range must be within content length + if (!(0 <= first_pos && first_pos <= last_pos && + last_pos <= contant_len - 1)) { + return true; + } + + // Ranges must be in ascending order + if (first_pos <= prev_first_pos) { return true; } + + // Request must not have more than two overlapping ranges + if (first_pos <= prev_last_pos) { + overwrapping_count++; + if (overwrapping_count > 2) { return true; } + } + + prev_first_pos = (std::max)(prev_first_pos, first_pos); + prev_last_pos = (std::max)(prev_last_pos, last_pos); + } + } + + return false; +} + +inline std::pair +get_range_offset_and_length(Range r, size_t content_length) { + assert(r.first != -1 && r.second != -1); + assert(0 <= r.first && r.first < static_cast(content_length)); + assert(r.first <= r.second && + r.second < static_cast(content_length)); + (void)(content_length); + return std::make_pair(r.first, static_cast(r.second - r.first) + 1); +} + +inline std::string make_content_range_header_field( + const std::pair &offset_and_length, size_t content_length) { + auto st = offset_and_length.first; + auto ed = st + offset_and_length.second - 1; + + std::string field = "bytes "; + field += std::to_string(st); + field += "-"; + field += std::to_string(ed); + field += "/"; + field += std::to_string(content_length); + return field; +} + +template +bool process_multipart_ranges_data(const Request &req, + const std::string &boundary, + const std::string &content_type, + size_t content_length, SToken stoken, + CToken ctoken, Content content) { + for (size_t i = 0; i < req.ranges.size(); i++) { + ctoken("--"); + stoken(boundary); + ctoken("\r\n"); + if (!content_type.empty()) { + ctoken("Content-Type: "); + stoken(content_type); + ctoken("\r\n"); + } + + auto offset_and_length = + get_range_offset_and_length(req.ranges[i], content_length); + + ctoken("Content-Range: "); + stoken(make_content_range_header_field(offset_and_length, content_length)); + ctoken("\r\n"); + ctoken("\r\n"); + + if (!content(offset_and_length.first, offset_and_length.second)) { + return false; + } + ctoken("\r\n"); + } + + ctoken("--"); + stoken(boundary); + ctoken("--"); + + return true; +} + +inline void make_multipart_ranges_data(const Request &req, Response &res, + const std::string &boundary, + const std::string &content_type, + size_t content_length, + std::string &data) { + process_multipart_ranges_data( + req, boundary, content_type, content_length, + [&](const std::string &token) { data += token; }, + [&](const std::string &token) { data += token; }, + [&](size_t offset, size_t length) { + assert(offset + length <= content_length); + data += res.body.substr(offset, length); + return true; + }); +} + +inline size_t get_multipart_ranges_data_length(const Request &req, + const std::string &boundary, + const std::string &content_type, + size_t content_length) { + size_t data_length = 0; + + process_multipart_ranges_data( + req, boundary, content_type, content_length, + [&](const std::string &token) { data_length += token.size(); }, + [&](const std::string &token) { data_length += token.size(); }, + [&](size_t /*offset*/, size_t length) { + data_length += length; + return true; + }); + + return data_length; +} + +template +inline bool +write_multipart_ranges_data(Stream &strm, const Request &req, Response &res, + const std::string &boundary, + const std::string &content_type, + size_t content_length, const T &is_shutting_down) { + return process_multipart_ranges_data( + req, boundary, content_type, content_length, + [&](const std::string &token) { strm.write(token); }, + [&](const std::string &token) { strm.write(token); }, + [&](size_t offset, size_t length) { + return write_content(strm, res.content_provider_, offset, length, + is_shutting_down); + }); +} + +inline bool expect_content(const Request &req) { + if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" || + req.method == "PRI" || req.method == "DELETE") { + return true; + } + // TODO: check if Content-Length is set + return false; +} + +inline bool has_crlf(const std::string &s) { + auto p = s.c_str(); + while (*p) { + if (*p == '\r' || *p == '\n') { return true; } + p++; + } + return false; +} + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline std::string message_digest(const std::string &s, const EVP_MD *algo) { + auto context = std::unique_ptr( + EVP_MD_CTX_new(), EVP_MD_CTX_free); + + unsigned int hash_length = 0; + unsigned char hash[EVP_MAX_MD_SIZE]; + + EVP_DigestInit_ex(context.get(), algo, nullptr); + EVP_DigestUpdate(context.get(), s.c_str(), s.size()); + EVP_DigestFinal_ex(context.get(), hash, &hash_length); + + std::stringstream ss; + for (auto i = 0u; i < hash_length; ++i) { + ss << std::hex << std::setw(2) << std::setfill('0') + << static_cast(hash[i]); + } + + return ss.str(); +} + +inline std::string MD5(const std::string &s) { + return message_digest(s, EVP_md5()); +} + +inline std::string SHA_256(const std::string &s) { + return message_digest(s, EVP_sha256()); +} + +inline std::string SHA_512(const std::string &s) { + return message_digest(s, EVP_sha512()); +} +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +#ifdef _WIN32 +// NOTE: This code came up with the following stackoverflow post: +// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store +inline bool load_system_certs_on_windows(X509_STORE *store) { + auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT"); + if (!hStore) { return false; } + + auto result = false; + PCCERT_CONTEXT pContext = NULL; + while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != + nullptr) { + auto encoded_cert = + static_cast(pContext->pbCertEncoded); + + auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if (x509) { + X509_STORE_add_cert(store, x509); + X509_free(x509); + result = true; + } + } + + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + return result; +} +#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) +#if TARGET_OS_OSX +template +using CFObjectPtr = + std::unique_ptr::type, void (*)(CFTypeRef)>; + +inline void cf_object_ptr_deleter(CFTypeRef obj) { + if (obj) { CFRelease(obj); } +} + +inline bool retrieve_certs_from_keychain(CFObjectPtr &certs) { + CFStringRef keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef}; + CFTypeRef values[] = {kSecClassCertificate, kSecMatchLimitAll, + kCFBooleanTrue}; + + CFObjectPtr query( + CFDictionaryCreate(nullptr, reinterpret_cast(keys), values, + sizeof(keys) / sizeof(keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), + cf_object_ptr_deleter); + + if (!query) { return false; } + + CFTypeRef security_items = nullptr; + if (SecItemCopyMatching(query.get(), &security_items) != errSecSuccess || + CFArrayGetTypeID() != CFGetTypeID(security_items)) { + return false; + } + + certs.reset(reinterpret_cast(security_items)); + return true; +} + +inline bool retrieve_root_certs_from_keychain(CFObjectPtr &certs) { + CFArrayRef root_security_items = nullptr; + if (SecTrustCopyAnchorCertificates(&root_security_items) != errSecSuccess) { + return false; + } + + certs.reset(root_security_items); + return true; +} + +inline bool add_certs_to_x509_store(CFArrayRef certs, X509_STORE *store) { + auto result = false; + for (auto i = 0; i < CFArrayGetCount(certs); ++i) { + const auto cert = reinterpret_cast( + CFArrayGetValueAtIndex(certs, i)); + + if (SecCertificateGetTypeID() != CFGetTypeID(cert)) { continue; } + + CFDataRef cert_data = nullptr; + if (SecItemExport(cert, kSecFormatX509Cert, 0, nullptr, &cert_data) != + errSecSuccess) { + continue; + } + + CFObjectPtr cert_data_ptr(cert_data, cf_object_ptr_deleter); + + auto encoded_cert = static_cast( + CFDataGetBytePtr(cert_data_ptr.get())); + + auto x509 = + d2i_X509(NULL, &encoded_cert, CFDataGetLength(cert_data_ptr.get())); + + if (x509) { + X509_STORE_add_cert(store, x509); + X509_free(x509); + result = true; + } + } + + return result; +} + +inline bool load_system_certs_on_macos(X509_STORE *store) { + auto result = false; + CFObjectPtr certs(nullptr, cf_object_ptr_deleter); + if (retrieve_certs_from_keychain(certs) && certs) { + result = add_certs_to_x509_store(certs.get(), store); + } + + if (retrieve_root_certs_from_keychain(certs) && certs) { + result = add_certs_to_x509_store(certs.get(), store) || result; + } + + return result; +} +#endif // TARGET_OS_OSX +#endif // _WIN32 +#endif // CPPHTTPLIB_OPENSSL_SUPPORT + +#ifdef _WIN32 +class WSInit { +public: + WSInit() { + WSADATA wsaData; + if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true; + } + + ~WSInit() { + if (is_valid_) WSACleanup(); + } + + bool is_valid_ = false; +}; + +static WSInit wsinit_; +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline std::pair make_digest_authentication_header( + const Request &req, const std::map &auth, + size_t cnonce_count, const std::string &cnonce, const std::string &username, + const std::string &password, bool is_proxy = false) { + std::string nc; + { + std::stringstream ss; + ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count; + nc = ss.str(); + } + + std::string qop; + if (auth.find("qop") != auth.end()) { + qop = auth.at("qop"); + if (qop.find("auth-int") != std::string::npos) { + qop = "auth-int"; + } else if (qop.find("auth") != std::string::npos) { + qop = "auth"; + } else { + qop.clear(); + } + } + + std::string algo = "MD5"; + if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); } + + std::string response; + { + auto H = algo == "SHA-256" ? detail::SHA_256 + : algo == "SHA-512" ? detail::SHA_512 + : detail::MD5; + + auto A1 = username + ":" + auth.at("realm") + ":" + password; + + auto A2 = req.method + ":" + req.path; + if (qop == "auth-int") { A2 += ":" + H(req.body); } + + if (qop.empty()) { + response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2)); + } else { + response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce + + ":" + qop + ":" + H(A2)); + } + } + + auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : ""; + + auto field = "Digest username=\"" + username + "\", realm=\"" + + auth.at("realm") + "\", nonce=\"" + auth.at("nonce") + + "\", uri=\"" + req.path + "\", algorithm=" + algo + + (qop.empty() ? ", response=\"" + : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" + + cnonce + "\", response=\"") + + response + "\"" + + (opaque.empty() ? "" : ", opaque=\"" + opaque + "\""); + + auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; + return std::make_pair(key, field); +} +#endif + +inline bool parse_www_authenticate(const Response &res, + std::map &auth, + bool is_proxy) { + auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate"; + if (res.has_header(auth_key)) { + static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"); + auto s = res.get_header_value(auth_key); + auto pos = s.find(' '); + if (pos != std::string::npos) { + auto type = s.substr(0, pos); + if (type == "Basic") { + return false; + } else if (type == "Digest") { + s = s.substr(pos + 1); + auto beg = std::sregex_iterator(s.begin(), s.end(), re); + for (auto i = beg; i != std::sregex_iterator(); ++i) { + const auto &m = *i; + auto key = s.substr(static_cast(m.position(1)), + static_cast(m.length(1))); + auto val = m.length(2) > 0 + ? s.substr(static_cast(m.position(2)), + static_cast(m.length(2))) + : s.substr(static_cast(m.position(3)), + static_cast(m.length(3))); + auth[key] = val; + } + return true; + } + } + } + return false; +} + +class ContentProviderAdapter { +public: + explicit ContentProviderAdapter( + ContentProviderWithoutLength &&content_provider) + : content_provider_(content_provider) {} + + bool operator()(size_t offset, size_t, DataSink &sink) { + return content_provider_(offset, sink); + } + +private: + ContentProviderWithoutLength content_provider_; +}; + +} // namespace detail + +inline std::string hosted_at(const std::string &hostname) { + std::vector addrs; + hosted_at(hostname, addrs); + if (addrs.empty()) { return std::string(); } + return addrs[0]; +} + +inline void hosted_at(const std::string &hostname, + std::vector &addrs) { + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) { +#if defined __linux__ && !defined __ANDROID__ + res_init(); +#endif + return; + } + auto se = detail::scope_exit([&] { freeaddrinfo(result); }); + + for (auto rp = result; rp; rp = rp->ai_next) { + const auto &addr = + *reinterpret_cast(rp->ai_addr); + std::string ip; + auto dummy = -1; + if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage), ip, + dummy)) { + addrs.push_back(ip); + } + } +} + +inline std::string append_query_params(const std::string &path, + const Params ¶ms) { + std::string path_with_query = path; + const static std::regex re("[^?]+\\?.*"); + auto delm = std::regex_match(path, re) ? '&' : '?'; + path_with_query += delm + detail::params_to_query_str(params); + return path_with_query; +} + +// Header utilities +inline std::pair +make_range_header(const Ranges &ranges) { + std::string field = "bytes="; + auto i = 0; + for (const auto &r : ranges) { + if (i != 0) { field += ", "; } + if (r.first != -1) { field += std::to_string(r.first); } + field += '-'; + if (r.second != -1) { field += std::to_string(r.second); } + i++; + } + return std::make_pair("Range", std::move(field)); +} + +inline std::pair +make_basic_authentication_header(const std::string &username, + const std::string &password, bool is_proxy) { + auto field = "Basic " + detail::base64_encode(username + ":" + password); + auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; + return std::make_pair(key, std::move(field)); +} + +inline std::pair +make_bearer_token_authentication_header(const std::string &token, + bool is_proxy = false) { + auto field = "Bearer " + token; + auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; + return std::make_pair(key, std::move(field)); +} + +// Request implementation +inline bool Request::has_header(const std::string &key) const { + return detail::has_header(headers, key); +} + +inline std::string Request::get_header_value(const std::string &key, + const char *def, size_t id) const { + return detail::get_header_value(headers, key, def, id); +} + +inline size_t Request::get_header_value_count(const std::string &key) const { + auto r = headers.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + +inline void Request::set_header(const std::string &key, + const std::string &val) { + if (!detail::has_crlf(key) && !detail::has_crlf(val)) { + headers.emplace(key, val); + } +} + +inline bool Request::has_param(const std::string &key) const { + return params.find(key) != params.end(); +} + +inline std::string Request::get_param_value(const std::string &key, + size_t id) const { + auto rng = params.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { return it->second; } + return std::string(); +} + +inline size_t Request::get_param_value_count(const std::string &key) const { + auto r = params.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + +inline bool Request::is_multipart_form_data() const { + const auto &content_type = get_header_value("Content-Type"); + return !content_type.rfind("multipart/form-data", 0); +} + +inline bool Request::has_file(const std::string &key) const { + return files.find(key) != files.end(); +} + +inline MultipartFormData Request::get_file_value(const std::string &key) const { + auto it = files.find(key); + if (it != files.end()) { return it->second; } + return MultipartFormData(); +} + +inline std::vector +Request::get_file_values(const std::string &key) const { + std::vector values; + auto rng = files.equal_range(key); + for (auto it = rng.first; it != rng.second; it++) { + values.push_back(it->second); + } + return values; +} + +// Response implementation +inline bool Response::has_header(const std::string &key) const { + return headers.find(key) != headers.end(); +} + +inline std::string Response::get_header_value(const std::string &key, + const char *def, + size_t id) const { + return detail::get_header_value(headers, key, def, id); +} + +inline size_t Response::get_header_value_count(const std::string &key) const { + auto r = headers.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + +inline void Response::set_header(const std::string &key, + const std::string &val) { + if (!detail::has_crlf(key) && !detail::has_crlf(val)) { + headers.emplace(key, val); + } +} + +inline void Response::set_redirect(const std::string &url, int stat) { + if (!detail::has_crlf(url)) { + set_header("Location", url); + if (300 <= stat && stat < 400) { + this->status = stat; + } else { + this->status = StatusCode::Found_302; + } + } +} + +inline void Response::set_content(const char *s, size_t n, + const std::string &content_type) { + body.assign(s, n); + + auto rng = headers.equal_range("Content-Type"); + headers.erase(rng.first, rng.second); + set_header("Content-Type", content_type); +} + +inline void Response::set_content(const std::string &s, + const std::string &content_type) { + set_content(s.data(), s.size(), content_type); +} + +inline void Response::set_content(std::string &&s, + const std::string &content_type) { + body = std::move(s); + + auto rng = headers.equal_range("Content-Type"); + headers.erase(rng.first, rng.second); + set_header("Content-Type", content_type); +} + +inline void Response::set_content_provider( + size_t in_length, const std::string &content_type, ContentProvider provider, + ContentProviderResourceReleaser resource_releaser) { + set_header("Content-Type", content_type); + content_length_ = in_length; + if (in_length > 0) { content_provider_ = std::move(provider); } + content_provider_resource_releaser_ = std::move(resource_releaser); + is_chunked_content_provider_ = false; +} + +inline void Response::set_content_provider( + const std::string &content_type, ContentProviderWithoutLength provider, + ContentProviderResourceReleaser resource_releaser) { + set_header("Content-Type", content_type); + content_length_ = 0; + content_provider_ = detail::ContentProviderAdapter(std::move(provider)); + content_provider_resource_releaser_ = std::move(resource_releaser); + is_chunked_content_provider_ = false; +} + +inline void Response::set_chunked_content_provider( + const std::string &content_type, ContentProviderWithoutLength provider, + ContentProviderResourceReleaser resource_releaser) { + set_header("Content-Type", content_type); + content_length_ = 0; + content_provider_ = detail::ContentProviderAdapter(std::move(provider)); + content_provider_resource_releaser_ = std::move(resource_releaser); + is_chunked_content_provider_ = true; +} + +inline void Response::set_file_content(const std::string &path, + const std::string &content_type) { + file_content_path_ = path; + file_content_content_type_ = content_type; +} + +inline void Response::set_file_content(const std::string &path) { + file_content_path_ = path; +} + +// Result implementation +inline bool Result::has_request_header(const std::string &key) const { + return request_headers_.find(key) != request_headers_.end(); +} + +inline std::string Result::get_request_header_value(const std::string &key, + const char *def, + size_t id) const { + return detail::get_header_value(request_headers_, key, def, id); +} + +inline size_t +Result::get_request_header_value_count(const std::string &key) const { + auto r = request_headers_.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + +// Stream implementation +inline ssize_t Stream::write(const char *ptr) { + return write(ptr, strlen(ptr)); +} + +inline ssize_t Stream::write(const std::string &s) { + return write(s.data(), s.size()); +} + +namespace detail { + +// Socket stream implementation +inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec, + time_t read_timeout_usec, + time_t write_timeout_sec, + time_t write_timeout_usec) + : sock_(sock), read_timeout_sec_(read_timeout_sec), + read_timeout_usec_(read_timeout_usec), + write_timeout_sec_(write_timeout_sec), + write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {} + +inline SocketStream::~SocketStream() = default; + +inline bool SocketStream::is_readable() const { + return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; +} + +inline bool SocketStream::is_writable() const { + return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 && + is_socket_alive(sock_); +} + +inline ssize_t SocketStream::read(char *ptr, size_t size) { +#ifdef _WIN32 + size = + (std::min)(size, static_cast((std::numeric_limits::max)())); +#else + size = (std::min)(size, + static_cast((std::numeric_limits::max)())); +#endif + + if (read_buff_off_ < read_buff_content_size_) { + auto remaining_size = read_buff_content_size_ - read_buff_off_; + if (size <= remaining_size) { + memcpy(ptr, read_buff_.data() + read_buff_off_, size); + read_buff_off_ += size; + return static_cast(size); + } else { + memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size); + read_buff_off_ += remaining_size; + return static_cast(remaining_size); + } + } + + if (!is_readable()) { return -1; } + + read_buff_off_ = 0; + read_buff_content_size_ = 0; + + if (size < read_buff_size_) { + auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, + CPPHTTPLIB_RECV_FLAGS); + if (n <= 0) { + return n; + } else if (n <= static_cast(size)) { + memcpy(ptr, read_buff_.data(), static_cast(n)); + return n; + } else { + memcpy(ptr, read_buff_.data(), size); + read_buff_off_ = size; + read_buff_content_size_ = static_cast(n); + return static_cast(size); + } + } else { + return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS); + } +} + +inline ssize_t SocketStream::write(const char *ptr, size_t size) { + if (!is_writable()) { return -1; } + +#if defined(_WIN32) && !defined(_WIN64) + size = + (std::min)(size, static_cast((std::numeric_limits::max)())); +#endif + + return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS); +} + +inline void SocketStream::get_remote_ip_and_port(std::string &ip, + int &port) const { + return detail::get_remote_ip_and_port(sock_, ip, port); +} + +inline void SocketStream::get_local_ip_and_port(std::string &ip, + int &port) const { + return detail::get_local_ip_and_port(sock_, ip, port); +} + +inline socket_t SocketStream::socket() const { return sock_; } + +// Buffer stream implementation +inline bool BufferStream::is_readable() const { return true; } + +inline bool BufferStream::is_writable() const { return true; } + +inline ssize_t BufferStream::read(char *ptr, size_t size) { +#if defined(_MSC_VER) && _MSC_VER < 1910 + auto len_read = buffer._Copy_s(ptr, size, size, position); +#else + auto len_read = buffer.copy(ptr, size, position); +#endif + position += static_cast(len_read); + return static_cast(len_read); +} + +inline ssize_t BufferStream::write(const char *ptr, size_t size) { + buffer.append(ptr, size); + return static_cast(size); +} + +inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/, + int & /*port*/) const {} + +inline void BufferStream::get_local_ip_and_port(std::string & /*ip*/, + int & /*port*/) const {} + +inline socket_t BufferStream::socket() const { return 0; } + +inline const std::string &BufferStream::get_buffer() const { return buffer; } + +inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) { + static constexpr char marker[] = "/:"; + + // One past the last ending position of a path param substring + std::size_t last_param_end = 0; + +#ifndef CPPHTTPLIB_NO_EXCEPTIONS + // Needed to ensure that parameter names are unique during matcher + // construction + // If exceptions are disabled, only last duplicate path + // parameter will be set + std::unordered_set param_name_set; +#endif + + while (true) { + const auto marker_pos = pattern.find( + marker, last_param_end == 0 ? last_param_end : last_param_end - 1); + if (marker_pos == std::string::npos) { break; } + + static_fragments_.push_back( + pattern.substr(last_param_end, marker_pos - last_param_end + 1)); + + const auto param_name_start = marker_pos + 2; + + auto sep_pos = pattern.find(separator, param_name_start); + if (sep_pos == std::string::npos) { sep_pos = pattern.length(); } + + auto param_name = + pattern.substr(param_name_start, sep_pos - param_name_start); + +#ifndef CPPHTTPLIB_NO_EXCEPTIONS + if (param_name_set.find(param_name) != param_name_set.cend()) { + std::string msg = "Encountered path parameter '" + param_name + + "' multiple times in route pattern '" + pattern + "'."; + throw std::invalid_argument(msg); + } +#endif + + param_names_.push_back(std::move(param_name)); + + last_param_end = sep_pos + 1; + } + + if (last_param_end < pattern.length()) { + static_fragments_.push_back(pattern.substr(last_param_end)); + } +} + +inline bool PathParamsMatcher::match(Request &request) const { + request.matches = std::smatch(); + request.path_params.clear(); + request.path_params.reserve(param_names_.size()); + + // One past the position at which the path matched the pattern last time + std::size_t starting_pos = 0; + for (size_t i = 0; i < static_fragments_.size(); ++i) { + const auto &fragment = static_fragments_[i]; + + if (starting_pos + fragment.length() > request.path.length()) { + return false; + } + + // Avoid unnecessary allocation by using strncmp instead of substr + + // comparison + if (std::strncmp(request.path.c_str() + starting_pos, fragment.c_str(), + fragment.length()) != 0) { + return false; + } + + starting_pos += fragment.length(); + + // Should only happen when we have a static fragment after a param + // Example: '/users/:id/subscriptions' + // The 'subscriptions' fragment here does not have a corresponding param + if (i >= param_names_.size()) { continue; } + + auto sep_pos = request.path.find(separator, starting_pos); + if (sep_pos == std::string::npos) { sep_pos = request.path.length(); } + + const auto ¶m_name = param_names_[i]; + + request.path_params.emplace( + param_name, request.path.substr(starting_pos, sep_pos - starting_pos)); + + // Mark everything up to '/' as matched + starting_pos = sep_pos + 1; + } + // Returns false if the path is longer than the pattern + return starting_pos >= request.path.length(); +} + +inline bool RegexMatcher::match(Request &request) const { + request.path_params.clear(); + return std::regex_match(request.path, request.matches, regex_); +} + +} // namespace detail + +// HTTP server implementation +inline Server::Server() + : new_task_queue( + [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }) { +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif +} + +inline Server::~Server() = default; + +inline std::unique_ptr +Server::make_matcher(const std::string &pattern) { + if (pattern.find("/:") != std::string::npos) { + return detail::make_unique(pattern); + } else { + return detail::make_unique(pattern); + } +} + +inline Server &Server::Get(const std::string &pattern, Handler handler) { + get_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); + return *this; +} + +inline Server &Server::Post(const std::string &pattern, Handler handler) { + post_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); + return *this; +} + +inline Server &Server::Post(const std::string &pattern, + HandlerWithContentReader handler) { + post_handlers_for_content_reader_.emplace_back(make_matcher(pattern), + std::move(handler)); + return *this; +} + +inline Server &Server::Put(const std::string &pattern, Handler handler) { + put_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); + return *this; +} + +inline Server &Server::Put(const std::string &pattern, + HandlerWithContentReader handler) { + put_handlers_for_content_reader_.emplace_back(make_matcher(pattern), + std::move(handler)); + return *this; +} + +inline Server &Server::Patch(const std::string &pattern, Handler handler) { + patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); + return *this; +} + +inline Server &Server::Patch(const std::string &pattern, + HandlerWithContentReader handler) { + patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern), + std::move(handler)); + return *this; +} + +inline Server &Server::Delete(const std::string &pattern, Handler handler) { + delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); + return *this; +} + +inline Server &Server::Delete(const std::string &pattern, + HandlerWithContentReader handler) { + delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern), + std::move(handler)); + return *this; +} + +inline Server &Server::Options(const std::string &pattern, Handler handler) { + options_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); + return *this; +} + +inline bool Server::set_base_dir(const std::string &dir, + const std::string &mount_point) { + return set_mount_point(mount_point, dir); +} + +inline bool Server::set_mount_point(const std::string &mount_point, + const std::string &dir, Headers headers) { + detail::FileStat stat(dir); + if (stat.is_dir()) { + std::string mnt = !mount_point.empty() ? mount_point : "/"; + if (!mnt.empty() && mnt[0] == '/') { + base_dirs_.push_back({mnt, dir, std::move(headers)}); + return true; + } + } + return false; +} + +inline bool Server::remove_mount_point(const std::string &mount_point) { + for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) { + if (it->mount_point == mount_point) { + base_dirs_.erase(it); + return true; + } + } + return false; +} + +inline Server & +Server::set_file_extension_and_mimetype_mapping(const std::string &ext, + const std::string &mime) { + file_extension_and_mimetype_map_[ext] = mime; + return *this; +} + +inline Server &Server::set_default_file_mimetype(const std::string &mime) { + default_file_mimetype_ = mime; + return *this; +} + +inline Server &Server::set_file_request_handler(Handler handler) { + file_request_handler_ = std::move(handler); + return *this; +} + +inline Server &Server::set_error_handler_core(HandlerWithResponse handler, + std::true_type) { + error_handler_ = std::move(handler); + return *this; +} + +inline Server &Server::set_error_handler_core(Handler handler, + std::false_type) { + error_handler_ = [handler](const Request &req, Response &res) { + handler(req, res); + return HandlerResponse::Handled; + }; + return *this; +} + +inline Server &Server::set_exception_handler(ExceptionHandler handler) { + exception_handler_ = std::move(handler); + return *this; +} + +inline Server &Server::set_pre_routing_handler(HandlerWithResponse handler) { + pre_routing_handler_ = std::move(handler); + return *this; +} + +inline Server &Server::set_post_routing_handler(Handler handler) { + post_routing_handler_ = std::move(handler); + return *this; +} + +inline Server &Server::set_logger(Logger logger) { + logger_ = std::move(logger); + return *this; +} + +inline Server & +Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) { + expect_100_continue_handler_ = std::move(handler); + return *this; +} + +inline Server &Server::set_address_family(int family) { + address_family_ = family; + return *this; +} + +inline Server &Server::set_tcp_nodelay(bool on) { + tcp_nodelay_ = on; + return *this; +} + +inline Server &Server::set_ipv6_v6only(bool on) { + ipv6_v6only_ = on; + return *this; +} + +inline Server &Server::set_socket_options(SocketOptions socket_options) { + socket_options_ = std::move(socket_options); + return *this; +} + +inline Server &Server::set_default_headers(Headers headers) { + default_headers_ = std::move(headers); + return *this; +} + +inline Server &Server::set_header_writer( + std::function const &writer) { + header_writer_ = writer; + return *this; +} + +inline Server &Server::set_keep_alive_max_count(size_t count) { + keep_alive_max_count_ = count; + return *this; +} + +inline Server &Server::set_keep_alive_timeout(time_t sec) { + keep_alive_timeout_sec_ = sec; + return *this; +} + +inline Server &Server::set_read_timeout(time_t sec, time_t usec) { + read_timeout_sec_ = sec; + read_timeout_usec_ = usec; + return *this; +} + +inline Server &Server::set_write_timeout(time_t sec, time_t usec) { + write_timeout_sec_ = sec; + write_timeout_usec_ = usec; + return *this; +} + +inline Server &Server::set_idle_interval(time_t sec, time_t usec) { + idle_interval_sec_ = sec; + idle_interval_usec_ = usec; + return *this; +} + +inline Server &Server::set_payload_max_length(size_t length) { + payload_max_length_ = length; + return *this; +} + +inline bool Server::bind_to_port(const std::string &host, int port, + int socket_flags) { + auto ret = bind_internal(host, port, socket_flags); + if (ret == -1) { is_decommisioned = true; } + return ret >= 0; +} +inline int Server::bind_to_any_port(const std::string &host, int socket_flags) { + auto ret = bind_internal(host, 0, socket_flags); + if (ret == -1) { is_decommisioned = true; } + return ret; +} + +inline bool Server::listen_after_bind() { return listen_internal(); } + +inline bool Server::listen(const std::string &host, int port, + int socket_flags) { + return bind_to_port(host, port, socket_flags) && listen_internal(); +} + +inline bool Server::is_running() const { return is_running_; } + +inline void Server::wait_until_ready() const { + while (!is_running_ && !is_decommisioned) { + std::this_thread::sleep_for(std::chrono::milliseconds{1}); + } +} + +inline void Server::stop() { + if (is_running_) { + assert(svr_sock_ != INVALID_SOCKET); + std::atomic sock(svr_sock_.exchange(INVALID_SOCKET)); + detail::shutdown_socket(sock); + detail::close_socket(sock); + } + is_decommisioned = false; +} + +inline void Server::decommission() { is_decommisioned = true; } + +inline bool Server::parse_request_line(const char *s, Request &req) const { + auto len = strlen(s); + if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; } + len -= 2; + + { + size_t count = 0; + + detail::split(s, s + len, ' ', [&](const char *b, const char *e) { + switch (count) { + case 0: req.method = std::string(b, e); break; + case 1: req.target = std::string(b, e); break; + case 2: req.version = std::string(b, e); break; + default: break; + } + count++; + }); + + if (count != 3) { return false; } + } + + static const std::set methods{ + "GET", "HEAD", "POST", "PUT", "DELETE", + "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"}; + + if (methods.find(req.method) == methods.end()) { return false; } + + if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; } + + { + // Skip URL fragment + for (size_t i = 0; i < req.target.size(); i++) { + if (req.target[i] == '#') { + req.target.erase(i); + break; + } + } + + detail::divide(req.target, '?', + [&](const char *lhs_data, std::size_t lhs_size, + const char *rhs_data, std::size_t rhs_size) { + req.path = detail::decode_url( + std::string(lhs_data, lhs_size), false); + detail::parse_query_text(rhs_data, rhs_size, req.params); + }); + } + + return true; +} + +inline bool Server::write_response(Stream &strm, bool close_connection, + Request &req, Response &res) { + // NOTE: `req.ranges` should be empty, otherwise it will be applied + // incorrectly to the error content. + req.ranges.clear(); + return write_response_core(strm, close_connection, req, res, false); +} + +inline bool Server::write_response_with_content(Stream &strm, + bool close_connection, + const Request &req, + Response &res) { + return write_response_core(strm, close_connection, req, res, true); +} + +inline bool Server::write_response_core(Stream &strm, bool close_connection, + const Request &req, Response &res, + bool need_apply_ranges) { + assert(res.status != -1); + + if (400 <= res.status && error_handler_ && + error_handler_(req, res) == HandlerResponse::Handled) { + need_apply_ranges = true; + } + + std::string content_type; + std::string boundary; + if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); } + + // Prepare additional headers + if (close_connection || req.get_header_value("Connection") == "close") { + res.set_header("Connection", "close"); + } else { + std::string s = "timeout="; + s += std::to_string(keep_alive_timeout_sec_); + s += ", max="; + s += std::to_string(keep_alive_max_count_); + res.set_header("Keep-Alive", s); + } + + if ((!res.body.empty() || res.content_length_ > 0 || res.content_provider_) && + !res.has_header("Content-Type")) { + res.set_header("Content-Type", "text/plain"); + } + + if (res.body.empty() && !res.content_length_ && !res.content_provider_ && + !res.has_header("Content-Length")) { + res.set_header("Content-Length", "0"); + } + + if (req.method == "HEAD" && !res.has_header("Accept-Ranges")) { + res.set_header("Accept-Ranges", "bytes"); + } + + if (post_routing_handler_) { post_routing_handler_(req, res); } + + // Response line and headers + { + detail::BufferStream bstrm; + if (!detail::write_response_line(bstrm, res.status)) { return false; } + if (!header_writer_(bstrm, res.headers)) { return false; } + + // Flush buffer + auto &data = bstrm.get_buffer(); + detail::write_data(strm, data.data(), data.size()); + } + + // Body + auto ret = true; + if (req.method != "HEAD") { + if (!res.body.empty()) { + if (!detail::write_data(strm, res.body.data(), res.body.size())) { + ret = false; + } + } else if (res.content_provider_) { + if (write_content_with_provider(strm, req, res, boundary, content_type)) { + res.content_provider_success_ = true; + } else { + ret = false; + } + } + } + + // Log + if (logger_) { logger_(req, res); } + + return ret; +} + +inline bool +Server::write_content_with_provider(Stream &strm, const Request &req, + Response &res, const std::string &boundary, + const std::string &content_type) { + auto is_shutting_down = [this]() { + return this->svr_sock_ == INVALID_SOCKET; + }; + + if (res.content_length_ > 0) { + if (req.ranges.empty()) { + return detail::write_content(strm, res.content_provider_, 0, + res.content_length_, is_shutting_down); + } else if (req.ranges.size() == 1) { + auto offset_and_length = detail::get_range_offset_and_length( + req.ranges[0], res.content_length_); + + return detail::write_content(strm, res.content_provider_, + offset_and_length.first, + offset_and_length.second, is_shutting_down); + } else { + return detail::write_multipart_ranges_data( + strm, req, res, boundary, content_type, res.content_length_, + is_shutting_down); + } + } else { + if (res.is_chunked_content_provider_) { + auto type = detail::encoding_type(req, res); + + std::unique_ptr compressor; + if (type == detail::EncodingType::Gzip) { +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + compressor = detail::make_unique(); +#endif + } else if (type == detail::EncodingType::Brotli) { +#ifdef CPPHTTPLIB_BROTLI_SUPPORT + compressor = detail::make_unique(); +#endif + } else { + compressor = detail::make_unique(); + } + assert(compressor != nullptr); + + return detail::write_content_chunked(strm, res.content_provider_, + is_shutting_down, *compressor); + } else { + return detail::write_content_without_length(strm, res.content_provider_, + is_shutting_down); + } + } +} + +inline bool Server::read_content(Stream &strm, Request &req, Response &res) { + MultipartFormDataMap::iterator cur; + auto file_count = 0; + if (read_content_core( + strm, req, res, + // Regular + [&](const char *buf, size_t n) { + if (req.body.size() + n > req.body.max_size()) { return false; } + req.body.append(buf, n); + return true; + }, + // Multipart + [&](const MultipartFormData &file) { + if (file_count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) { + return false; + } + cur = req.files.emplace(file.name, file); + return true; + }, + [&](const char *buf, size_t n) { + auto &content = cur->second.content; + if (content.size() + n > content.max_size()) { return false; } + content.append(buf, n); + return true; + })) { + const auto &content_type = req.get_header_value("Content-Type"); + if (!content_type.find("application/x-www-form-urlencoded")) { + if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) { + res.status = StatusCode::PayloadTooLarge_413; // NOTE: should be 414? + return false; + } + detail::parse_query_text(req.body, req.params); + } + return true; + } + return false; +} + +inline bool Server::read_content_with_content_receiver( + Stream &strm, Request &req, Response &res, ContentReceiver receiver, + MultipartContentHeader multipart_header, + ContentReceiver multipart_receiver) { + return read_content_core(strm, req, res, std::move(receiver), + std::move(multipart_header), + std::move(multipart_receiver)); +} + +inline bool +Server::read_content_core(Stream &strm, Request &req, Response &res, + ContentReceiver receiver, + MultipartContentHeader multipart_header, + ContentReceiver multipart_receiver) const { + detail::MultipartFormDataParser multipart_form_data_parser; + ContentReceiverWithProgress out; + + if (req.is_multipart_form_data()) { + const auto &content_type = req.get_header_value("Content-Type"); + std::string boundary; + if (!detail::parse_multipart_boundary(content_type, boundary)) { + res.status = StatusCode::BadRequest_400; + return false; + } + + multipart_form_data_parser.set_boundary(std::move(boundary)); + out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) { + /* For debug + size_t pos = 0; + while (pos < n) { + auto read_size = (std::min)(1, n - pos); + auto ret = multipart_form_data_parser.parse( + buf + pos, read_size, multipart_receiver, multipart_header); + if (!ret) { return false; } + pos += read_size; + } + return true; + */ + return multipart_form_data_parser.parse(buf, n, multipart_receiver, + multipart_header); + }; + } else { + out = [receiver](const char *buf, size_t n, uint64_t /*off*/, + uint64_t /*len*/) { return receiver(buf, n); }; + } + + if (req.method == "DELETE" && !req.has_header("Content-Length")) { + return true; + } + + if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr, + out, true)) { + return false; + } + + if (req.is_multipart_form_data()) { + if (!multipart_form_data_parser.is_valid()) { + res.status = StatusCode::BadRequest_400; + return false; + } + } + + return true; +} + +inline bool Server::handle_file_request(const Request &req, Response &res, + bool head) { + for (const auto &entry : base_dirs_) { + // Prefix match + if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) { + std::string sub_path = "/" + req.path.substr(entry.mount_point.size()); + if (detail::is_valid_path(sub_path)) { + auto path = entry.base_dir + sub_path; + if (path.back() == '/') { path += "index.html"; } + + detail::FileStat stat(path); + + if (stat.is_dir()) { + res.set_redirect(sub_path + "/", StatusCode::MovedPermanently_301); + return true; + } + + if (stat.is_file()) { + for (const auto &kv : entry.headers) { + res.set_header(kv.first, kv.second); + } + + auto mm = std::make_shared(path.c_str()); + if (!mm->is_open()) { return false; } + + res.set_content_provider( + mm->size(), + detail::find_content_type(path, file_extension_and_mimetype_map_, + default_file_mimetype_), + [mm](size_t offset, size_t length, DataSink &sink) -> bool { + sink.write(mm->data() + offset, length); + return true; + }); + + if (!head && file_request_handler_) { + file_request_handler_(req, res); + } + + return true; + } + } + } + } + return false; +} + +inline socket_t +Server::create_server_socket(const std::string &host, int port, + int socket_flags, + SocketOptions socket_options) const { + return detail::create_socket( + host, std::string(), port, address_family_, socket_flags, tcp_nodelay_, + ipv6_v6only_, std::move(socket_options), + [](socket_t sock, struct addrinfo &ai, bool & /*quit*/) -> bool { + if (::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { + return false; + } + if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; } + return true; + }); +} + +inline int Server::bind_internal(const std::string &host, int port, + int socket_flags) { + if (is_decommisioned) { return -1; } + + if (!is_valid()) { return -1; } + + svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_); + if (svr_sock_ == INVALID_SOCKET) { return -1; } + + if (port == 0) { + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + if (getsockname(svr_sock_, reinterpret_cast(&addr), + &addr_len) == -1) { + return -1; + } + if (addr.ss_family == AF_INET) { + return ntohs(reinterpret_cast(&addr)->sin_port); + } else if (addr.ss_family == AF_INET6) { + return ntohs(reinterpret_cast(&addr)->sin6_port); + } else { + return -1; + } + } else { + return port; + } +} + +inline bool Server::listen_internal() { + if (is_decommisioned) { return false; } + + auto ret = true; + is_running_ = true; + auto se = detail::scope_exit([&]() { is_running_ = false; }); + + { + std::unique_ptr task_queue(new_task_queue()); + + while (svr_sock_ != INVALID_SOCKET) { +#ifndef _WIN32 + if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) { +#endif + auto val = detail::select_read(svr_sock_, idle_interval_sec_, + idle_interval_usec_); + if (val == 0) { // Timeout + task_queue->on_idle(); + continue; + } +#ifndef _WIN32 + } +#endif + +#if defined _WIN32 + // sockets conneced via WASAccept inherit flags NO_HANDLE_INHERIT, + // OVERLAPPED + socket_t sock = WSAAccept(svr_sock_, nullptr, nullptr, nullptr, 0); +#elif defined SOCK_CLOEXEC + socket_t sock = accept4(svr_sock_, nullptr, nullptr, SOCK_CLOEXEC); +#else + socket_t sock = accept(svr_sock_, nullptr, nullptr); +#endif + + if (sock == INVALID_SOCKET) { + if (errno == EMFILE) { + // The per-process limit of open file descriptors has been reached. + // Try to accept new connections after a short sleep. + std::this_thread::sleep_for(std::chrono::microseconds{1}); + continue; + } else if (errno == EINTR || errno == EAGAIN) { + continue; + } + if (svr_sock_ != INVALID_SOCKET) { + detail::close_socket(svr_sock_); + ret = false; + } else { + ; // The server socket was closed by user. + } + break; + } + + { +#ifdef _WIN32 + auto timeout = static_cast(read_timeout_sec_ * 1000 + + read_timeout_usec_ / 1000); + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&timeout), sizeof(timeout)); +#else + timeval tv; + tv.tv_sec = static_cast(read_timeout_sec_); + tv.tv_usec = static_cast(read_timeout_usec_); + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&tv), sizeof(tv)); +#endif + } + { + +#ifdef _WIN32 + auto timeout = static_cast(write_timeout_sec_ * 1000 + + write_timeout_usec_ / 1000); + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, + reinterpret_cast(&timeout), sizeof(timeout)); +#else + timeval tv; + tv.tv_sec = static_cast(write_timeout_sec_); + tv.tv_usec = static_cast(write_timeout_usec_); + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, + reinterpret_cast(&tv), sizeof(tv)); +#endif + } + + if (!task_queue->enqueue( + [this, sock]() { process_and_close_socket(sock); })) { + detail::shutdown_socket(sock); + detail::close_socket(sock); + } + } + + task_queue->shutdown(); + } + + is_decommisioned = !ret; + return ret; +} + +inline bool Server::routing(Request &req, Response &res, Stream &strm) { + if (pre_routing_handler_ && + pre_routing_handler_(req, res) == HandlerResponse::Handled) { + return true; + } + + // File handler + auto is_head_request = req.method == "HEAD"; + if ((req.method == "GET" || is_head_request) && + handle_file_request(req, res, is_head_request)) { + return true; + } + + if (detail::expect_content(req)) { + // Content reader handler + { + ContentReader reader( + [&](ContentReceiver receiver) { + return read_content_with_content_receiver( + strm, req, res, std::move(receiver), nullptr, nullptr); + }, + [&](MultipartContentHeader header, ContentReceiver receiver) { + return read_content_with_content_receiver(strm, req, res, nullptr, + std::move(header), + std::move(receiver)); + }); + + if (req.method == "POST") { + if (dispatch_request_for_content_reader( + req, res, std::move(reader), + post_handlers_for_content_reader_)) { + return true; + } + } else if (req.method == "PUT") { + if (dispatch_request_for_content_reader( + req, res, std::move(reader), + put_handlers_for_content_reader_)) { + return true; + } + } else if (req.method == "PATCH") { + if (dispatch_request_for_content_reader( + req, res, std::move(reader), + patch_handlers_for_content_reader_)) { + return true; + } + } else if (req.method == "DELETE") { + if (dispatch_request_for_content_reader( + req, res, std::move(reader), + delete_handlers_for_content_reader_)) { + return true; + } + } + } + + // Read content into `req.body` + if (!read_content(strm, req, res)) { return false; } + } + + // Regular handler + if (req.method == "GET" || req.method == "HEAD") { + return dispatch_request(req, res, get_handlers_); + } else if (req.method == "POST") { + return dispatch_request(req, res, post_handlers_); + } else if (req.method == "PUT") { + return dispatch_request(req, res, put_handlers_); + } else if (req.method == "DELETE") { + return dispatch_request(req, res, delete_handlers_); + } else if (req.method == "OPTIONS") { + return dispatch_request(req, res, options_handlers_); + } else if (req.method == "PATCH") { + return dispatch_request(req, res, patch_handlers_); + } + + res.status = StatusCode::BadRequest_400; + return false; +} + +inline bool Server::dispatch_request(Request &req, Response &res, + const Handlers &handlers) const { + for (const auto &x : handlers) { + const auto &matcher = x.first; + const auto &handler = x.second; + + if (matcher->match(req)) { + handler(req, res); + return true; + } + } + return false; +} + +inline void Server::apply_ranges(const Request &req, Response &res, + std::string &content_type, + std::string &boundary) const { + if (req.ranges.size() > 1 && res.status == StatusCode::PartialContent_206) { + auto it = res.headers.find("Content-Type"); + if (it != res.headers.end()) { + content_type = it->second; + res.headers.erase(it); + } + + boundary = detail::make_multipart_data_boundary(); + + res.set_header("Content-Type", + "multipart/byteranges; boundary=" + boundary); + } + + auto type = detail::encoding_type(req, res); + + if (res.body.empty()) { + if (res.content_length_ > 0) { + size_t length = 0; + if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) { + length = res.content_length_; + } else if (req.ranges.size() == 1) { + auto offset_and_length = detail::get_range_offset_and_length( + req.ranges[0], res.content_length_); + + length = offset_and_length.second; + + auto content_range = detail::make_content_range_header_field( + offset_and_length, res.content_length_); + res.set_header("Content-Range", content_range); + } else { + length = detail::get_multipart_ranges_data_length( + req, boundary, content_type, res.content_length_); + } + res.set_header("Content-Length", std::to_string(length)); + } else { + if (res.content_provider_) { + if (res.is_chunked_content_provider_) { + res.set_header("Transfer-Encoding", "chunked"); + if (type == detail::EncodingType::Gzip) { + res.set_header("Content-Encoding", "gzip"); + } else if (type == detail::EncodingType::Brotli) { + res.set_header("Content-Encoding", "br"); + } + } + } + } + } else { + if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) { + ; + } else if (req.ranges.size() == 1) { + auto offset_and_length = + detail::get_range_offset_and_length(req.ranges[0], res.body.size()); + auto offset = offset_and_length.first; + auto length = offset_and_length.second; + + auto content_range = detail::make_content_range_header_field( + offset_and_length, res.body.size()); + res.set_header("Content-Range", content_range); + + assert(offset + length <= res.body.size()); + res.body = res.body.substr(offset, length); + } else { + std::string data; + detail::make_multipart_ranges_data(req, res, boundary, content_type, + res.body.size(), data); + res.body.swap(data); + } + + if (type != detail::EncodingType::None) { + std::unique_ptr compressor; + std::string content_encoding; + + if (type == detail::EncodingType::Gzip) { +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + compressor = detail::make_unique(); + content_encoding = "gzip"; +#endif + } else if (type == detail::EncodingType::Brotli) { +#ifdef CPPHTTPLIB_BROTLI_SUPPORT + compressor = detail::make_unique(); + content_encoding = "br"; +#endif + } + + if (compressor) { + std::string compressed; + if (compressor->compress(res.body.data(), res.body.size(), true, + [&](const char *data, size_t data_len) { + compressed.append(data, data_len); + return true; + })) { + res.body.swap(compressed); + res.set_header("Content-Encoding", content_encoding); + } + } + } + + auto length = std::to_string(res.body.size()); + res.set_header("Content-Length", length); + } +} + +inline bool Server::dispatch_request_for_content_reader( + Request &req, Response &res, ContentReader content_reader, + const HandlersForContentReader &handlers) const { + for (const auto &x : handlers) { + const auto &matcher = x.first; + const auto &handler = x.second; + + if (matcher->match(req)) { + handler(req, res, content_reader); + return true; + } + } + return false; +} + +inline bool +Server::process_request(Stream &strm, const std::string &remote_addr, + int remote_port, const std::string &local_addr, + int local_port, bool close_connection, + bool &connection_closed, + const std::function &setup_request) { + std::array buf{}; + + detail::stream_line_reader line_reader(strm, buf.data(), buf.size()); + + // Connection has been closed on client + if (!line_reader.getline()) { return false; } + + Request req; + + Response res; + res.version = "HTTP/1.1"; + res.headers = default_headers_; + +#ifdef _WIN32 + // TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL). +#else +#ifndef CPPHTTPLIB_USE_POLL + // Socket file descriptor exceeded FD_SETSIZE... + if (strm.socket() >= FD_SETSIZE) { + Headers dummy; + detail::read_headers(strm, dummy); + res.status = StatusCode::InternalServerError_500; + return write_response(strm, close_connection, req, res); + } +#endif +#endif + + // Check if the request URI doesn't exceed the limit + if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { + Headers dummy; + detail::read_headers(strm, dummy); + res.status = StatusCode::UriTooLong_414; + return write_response(strm, close_connection, req, res); + } + + // Request line and headers + if (!parse_request_line(line_reader.ptr(), req) || + !detail::read_headers(strm, req.headers)) { + res.status = StatusCode::BadRequest_400; + return write_response(strm, close_connection, req, res); + } + + if (req.get_header_value("Connection") == "close") { + connection_closed = true; + } + + if (req.version == "HTTP/1.0" && + req.get_header_value("Connection") != "Keep-Alive") { + connection_closed = true; + } + + req.remote_addr = remote_addr; + req.remote_port = remote_port; + req.set_header("REMOTE_ADDR", req.remote_addr); + req.set_header("REMOTE_PORT", std::to_string(req.remote_port)); + + req.local_addr = local_addr; + req.local_port = local_port; + req.set_header("LOCAL_ADDR", req.local_addr); + req.set_header("LOCAL_PORT", std::to_string(req.local_port)); + + if (req.has_header("Range")) { + const auto &range_header_value = req.get_header_value("Range"); + if (!detail::parse_range_header(range_header_value, req.ranges)) { + res.status = StatusCode::RangeNotSatisfiable_416; + return write_response(strm, close_connection, req, res); + } + } + + if (setup_request) { setup_request(req); } + + if (req.get_header_value("Expect") == "100-continue") { + int status = StatusCode::Continue_100; + if (expect_100_continue_handler_) { + status = expect_100_continue_handler_(req, res); + } + switch (status) { + case StatusCode::Continue_100: + case StatusCode::ExpectationFailed_417: + detail::write_response_line(strm, status); + strm.write("\r\n"); + break; + default: + connection_closed = true; + return write_response(strm, true, req, res); + } + } + + // Routing + auto routed = false; +#ifdef CPPHTTPLIB_NO_EXCEPTIONS + routed = routing(req, res, strm); +#else + try { + routed = routing(req, res, strm); + } catch (std::exception &e) { + if (exception_handler_) { + auto ep = std::current_exception(); + exception_handler_(req, res, ep); + routed = true; + } else { + res.status = StatusCode::InternalServerError_500; + std::string val; + auto s = e.what(); + for (size_t i = 0; s[i]; i++) { + switch (s[i]) { + case '\r': val += "\\r"; break; + case '\n': val += "\\n"; break; + default: val += s[i]; break; + } + } + res.set_header("EXCEPTION_WHAT", val); + } + } catch (...) { + if (exception_handler_) { + auto ep = std::current_exception(); + exception_handler_(req, res, ep); + routed = true; + } else { + res.status = StatusCode::InternalServerError_500; + res.set_header("EXCEPTION_WHAT", "UNKNOWN"); + } + } +#endif + if (routed) { + if (res.status == -1) { + res.status = req.ranges.empty() ? StatusCode::OK_200 + : StatusCode::PartialContent_206; + } + + if (detail::range_error(req, res)) { + res.body.clear(); + res.content_length_ = 0; + res.content_provider_ = nullptr; + res.status = StatusCode::RangeNotSatisfiable_416; + return write_response(strm, close_connection, req, res); + } + + // Serve file content by using a content provider + if (!res.file_content_path_.empty()) { + const auto &path = res.file_content_path_; + auto mm = std::make_shared(path.c_str()); + if (!mm->is_open()) { + res.body.clear(); + res.content_length_ = 0; + res.content_provider_ = nullptr; + res.status = StatusCode::NotFound_404; + return write_response(strm, close_connection, req, res); + } + + auto content_type = res.file_content_content_type_; + if (content_type.empty()) { + content_type = detail::find_content_type( + path, file_extension_and_mimetype_map_, default_file_mimetype_); + } + + res.set_content_provider( + mm->size(), content_type, + [mm](size_t offset, size_t length, DataSink &sink) -> bool { + sink.write(mm->data() + offset, length); + return true; + }); + } + + return write_response_with_content(strm, close_connection, req, res); + } else { + if (res.status == -1) { res.status = StatusCode::NotFound_404; } + + return write_response(strm, close_connection, req, res); + } +} + +inline bool Server::is_valid() const { return true; } + +inline bool Server::process_and_close_socket(socket_t sock) { + std::string remote_addr; + int remote_port = 0; + detail::get_remote_ip_and_port(sock, remote_addr, remote_port); + + std::string local_addr; + int local_port = 0; + detail::get_local_ip_and_port(sock, local_addr, local_port); + + auto ret = detail::process_server_socket( + svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_, + read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, + write_timeout_usec_, + [&](Stream &strm, bool close_connection, bool &connection_closed) { + return process_request(strm, remote_addr, remote_port, local_addr, + local_port, close_connection, connection_closed, + nullptr); + }); + + detail::shutdown_socket(sock); + detail::close_socket(sock); + return ret; +} + +// HTTP client implementation +inline ClientImpl::ClientImpl(const std::string &host) + : ClientImpl(host, 80, std::string(), std::string()) {} + +inline ClientImpl::ClientImpl(const std::string &host, int port) + : ClientImpl(host, port, std::string(), std::string()) {} + +inline ClientImpl::ClientImpl(const std::string &host, int port, + const std::string &client_cert_path, + const std::string &client_key_path) + : host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port), + host_and_port_(adjust_host_string(host_) + ":" + std::to_string(port)), + client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} + +inline ClientImpl::~ClientImpl() { + std::lock_guard guard(socket_mutex_); + shutdown_socket(socket_); + close_socket(socket_); +} + +inline bool ClientImpl::is_valid() const { return true; } + +inline void ClientImpl::copy_settings(const ClientImpl &rhs) { + client_cert_path_ = rhs.client_cert_path_; + client_key_path_ = rhs.client_key_path_; + connection_timeout_sec_ = rhs.connection_timeout_sec_; + read_timeout_sec_ = rhs.read_timeout_sec_; + read_timeout_usec_ = rhs.read_timeout_usec_; + write_timeout_sec_ = rhs.write_timeout_sec_; + write_timeout_usec_ = rhs.write_timeout_usec_; + basic_auth_username_ = rhs.basic_auth_username_; + basic_auth_password_ = rhs.basic_auth_password_; + bearer_token_auth_token_ = rhs.bearer_token_auth_token_; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + digest_auth_username_ = rhs.digest_auth_username_; + digest_auth_password_ = rhs.digest_auth_password_; +#endif + keep_alive_ = rhs.keep_alive_; + follow_location_ = rhs.follow_location_; + url_encode_ = rhs.url_encode_; + address_family_ = rhs.address_family_; + tcp_nodelay_ = rhs.tcp_nodelay_; + ipv6_v6only_ = rhs.ipv6_v6only_; + socket_options_ = rhs.socket_options_; + compress_ = rhs.compress_; + decompress_ = rhs.decompress_; + interface_ = rhs.interface_; + proxy_host_ = rhs.proxy_host_; + proxy_port_ = rhs.proxy_port_; + proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_; + proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_; + proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_; + proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_; +#endif +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + ca_cert_file_path_ = rhs.ca_cert_file_path_; + ca_cert_dir_path_ = rhs.ca_cert_dir_path_; + ca_cert_store_ = rhs.ca_cert_store_; +#endif +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + server_certificate_verification_ = rhs.server_certificate_verification_; + server_hostname_verification_ = rhs.server_hostname_verification_; + server_certificate_verifier_ = rhs.server_certificate_verifier_; +#endif + logger_ = rhs.logger_; +} + +inline socket_t ClientImpl::create_client_socket(Error &error) const { + if (!proxy_host_.empty() && proxy_port_ != -1) { + return detail::create_client_socket( + proxy_host_, std::string(), proxy_port_, address_family_, tcp_nodelay_, + ipv6_v6only_, socket_options_, connection_timeout_sec_, + connection_timeout_usec_, read_timeout_sec_, read_timeout_usec_, + write_timeout_sec_, write_timeout_usec_, interface_, error); + } + + // Check is custom IP specified for host_ + std::string ip; + auto it = addr_map_.find(host_); + if (it != addr_map_.end()) { ip = it->second; } + + return detail::create_client_socket( + host_, ip, port_, address_family_, tcp_nodelay_, ipv6_v6only_, + socket_options_, connection_timeout_sec_, connection_timeout_usec_, + read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, + write_timeout_usec_, interface_, error); +} + +inline bool ClientImpl::create_and_connect_socket(Socket &socket, + Error &error) { + auto sock = create_client_socket(error); + if (sock == INVALID_SOCKET) { return false; } + socket.sock = sock; + return true; +} + +inline void ClientImpl::shutdown_ssl(Socket & /*socket*/, + bool /*shutdown_gracefully*/) { + // If there are any requests in flight from threads other than us, then it's + // a thread-unsafe race because individual ssl* objects are not thread-safe. + assert(socket_requests_in_flight_ == 0 || + socket_requests_are_from_thread_ == std::this_thread::get_id()); +} + +inline void ClientImpl::shutdown_socket(Socket &socket) const { + if (socket.sock == INVALID_SOCKET) { return; } + detail::shutdown_socket(socket.sock); +} + +inline void ClientImpl::close_socket(Socket &socket) { + // If there are requests in flight in another thread, usually closing + // the socket will be fine and they will simply receive an error when + // using the closed socket, but it is still a bug since rarely the OS + // may reassign the socket id to be used for a new socket, and then + // suddenly they will be operating on a live socket that is different + // than the one they intended! + assert(socket_requests_in_flight_ == 0 || + socket_requests_are_from_thread_ == std::this_thread::get_id()); + + // It is also a bug if this happens while SSL is still active +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + assert(socket.ssl == nullptr); +#endif + if (socket.sock == INVALID_SOCKET) { return; } + detail::close_socket(socket.sock); + socket.sock = INVALID_SOCKET; +} + +inline bool ClientImpl::read_response_line(Stream &strm, const Request &req, + Response &res) const { + std::array buf{}; + + detail::stream_line_reader line_reader(strm, buf.data(), buf.size()); + + if (!line_reader.getline()) { return false; } + +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR + const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"); +#else + const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"); +#endif + + std::cmatch m; + if (!std::regex_match(line_reader.ptr(), m, re)) { + return req.method == "CONNECT"; + } + res.version = std::string(m[1]); + res.status = std::stoi(std::string(m[2])); + res.reason = std::string(m[3]); + + // Ignore '100 Continue' + while (res.status == StatusCode::Continue_100) { + if (!line_reader.getline()) { return false; } // CRLF + if (!line_reader.getline()) { return false; } // next response line + + if (!std::regex_match(line_reader.ptr(), m, re)) { return false; } + res.version = std::string(m[1]); + res.status = std::stoi(std::string(m[2])); + res.reason = std::string(m[3]); + } + + return true; +} + +inline bool ClientImpl::send(Request &req, Response &res, Error &error) { + std::lock_guard request_mutex_guard(request_mutex_); + auto ret = send_(req, res, error); + if (error == Error::SSLPeerCouldBeClosed_) { + assert(!ret); + ret = send_(req, res, error); + } + return ret; +} + +inline bool ClientImpl::send_(Request &req, Response &res, Error &error) { + { + std::lock_guard guard(socket_mutex_); + + // Set this to false immediately - if it ever gets set to true by the end of + // the request, we know another thread instructed us to close the socket. + socket_should_be_closed_when_request_is_done_ = false; + + auto is_alive = false; + if (socket_.is_open()) { + is_alive = detail::is_socket_alive(socket_.sock); + if (!is_alive) { + // Attempt to avoid sigpipe by shutting down nongracefully if it seems + // like the other side has already closed the connection Also, there + // cannot be any requests in flight from other threads since we locked + // request_mutex_, so safe to close everything immediately + const bool shutdown_gracefully = false; + shutdown_ssl(socket_, shutdown_gracefully); + shutdown_socket(socket_); + close_socket(socket_); + } + } + + if (!is_alive) { + if (!create_and_connect_socket(socket_, error)) { return false; } + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + // TODO: refactoring + if (is_ssl()) { + auto &scli = static_cast(*this); + if (!proxy_host_.empty() && proxy_port_ != -1) { + auto success = false; + if (!scli.connect_with_proxy(socket_, res, success, error)) { + return success; + } + } + + if (!scli.initialize_ssl(socket_, error)) { return false; } + } +#endif + } + + // Mark the current socket as being in use so that it cannot be closed by + // anyone else while this request is ongoing, even though we will be + // releasing the mutex. + if (socket_requests_in_flight_ > 1) { + assert(socket_requests_are_from_thread_ == std::this_thread::get_id()); + } + socket_requests_in_flight_ += 1; + socket_requests_are_from_thread_ = std::this_thread::get_id(); + } + + for (const auto &header : default_headers_) { + if (req.headers.find(header.first) == req.headers.end()) { + req.headers.insert(header); + } + } + + auto ret = false; + auto close_connection = !keep_alive_; + + auto se = detail::scope_exit([&]() { + // Briefly lock mutex in order to mark that a request is no longer ongoing + std::lock_guard guard(socket_mutex_); + socket_requests_in_flight_ -= 1; + if (socket_requests_in_flight_ <= 0) { + assert(socket_requests_in_flight_ == 0); + socket_requests_are_from_thread_ = std::thread::id(); + } + + if (socket_should_be_closed_when_request_is_done_ || close_connection || + !ret) { + shutdown_ssl(socket_, true); + shutdown_socket(socket_); + close_socket(socket_); + } + }); + + ret = process_socket(socket_, [&](Stream &strm) { + return handle_request(strm, req, res, close_connection, error); + }); + + if (!ret) { + if (error == Error::Success) { error = Error::Unknown; } + } + + return ret; +} + +inline Result ClientImpl::send(const Request &req) { + auto req2 = req; + return send_(std::move(req2)); +} + +inline Result ClientImpl::send_(Request &&req) { + auto res = detail::make_unique(); + auto error = Error::Success; + auto ret = send(req, *res, error); + return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)}; +} + +inline bool ClientImpl::handle_request(Stream &strm, Request &req, + Response &res, bool close_connection, + Error &error) { + if (req.path.empty()) { + error = Error::Connection; + return false; + } + + auto req_save = req; + + bool ret; + + if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) { + auto req2 = req; + req2.path = "http://" + host_and_port_ + req.path; + ret = process_request(strm, req2, res, close_connection, error); + req = req2; + req.path = req_save.path; + } else { + ret = process_request(strm, req, res, close_connection, error); + } + + if (!ret) { return false; } + + if (res.get_header_value("Connection") == "close" || + (res.version == "HTTP/1.0" && res.reason != "Connection established")) { + // TODO this requires a not-entirely-obvious chain of calls to be correct + // for this to be safe. + + // This is safe to call because handle_request is only called by send_ + // which locks the request mutex during the process. It would be a bug + // to call it from a different thread since it's a thread-safety issue + // to do these things to the socket if another thread is using the socket. + std::lock_guard guard(socket_mutex_); + shutdown_ssl(socket_, true); + shutdown_socket(socket_); + close_socket(socket_); + } + + if (300 < res.status && res.status < 400 && follow_location_) { + req = req_save; + ret = redirect(req, res, error); + } + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if ((res.status == StatusCode::Unauthorized_401 || + res.status == StatusCode::ProxyAuthenticationRequired_407) && + req.authorization_count_ < 5) { + auto is_proxy = res.status == StatusCode::ProxyAuthenticationRequired_407; + const auto &username = + is_proxy ? proxy_digest_auth_username_ : digest_auth_username_; + const auto &password = + is_proxy ? proxy_digest_auth_password_ : digest_auth_password_; + + if (!username.empty() && !password.empty()) { + std::map auth; + if (detail::parse_www_authenticate(res, auth, is_proxy)) { + Request new_req = req; + new_req.authorization_count_ += 1; + new_req.headers.erase(is_proxy ? "Proxy-Authorization" + : "Authorization"); + new_req.headers.insert(detail::make_digest_authentication_header( + req, auth, new_req.authorization_count_, detail::random_string(10), + username, password, is_proxy)); + + Response new_res; + + ret = send(new_req, new_res, error); + if (ret) { res = new_res; } + } + } + } +#endif + + return ret; +} + +inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) { + if (req.redirect_count_ == 0) { + error = Error::ExceedRedirectCount; + return false; + } + + auto location = res.get_header_value("location"); + if (location.empty()) { return false; } + + const static std::regex re( + R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"); + + std::smatch m; + if (!std::regex_match(location, m, re)) { return false; } + + auto scheme = is_ssl() ? "https" : "http"; + + auto next_scheme = m[1].str(); + auto next_host = m[2].str(); + if (next_host.empty()) { next_host = m[3].str(); } + auto port_str = m[4].str(); + auto next_path = m[5].str(); + auto next_query = m[6].str(); + + auto next_port = port_; + if (!port_str.empty()) { + next_port = std::stoi(port_str); + } else if (!next_scheme.empty()) { + next_port = next_scheme == "https" ? 443 : 80; + } + + if (next_scheme.empty()) { next_scheme = scheme; } + if (next_host.empty()) { next_host = host_; } + if (next_path.empty()) { next_path = "/"; } + + auto path = detail::decode_url(next_path, true) + next_query; + + if (next_scheme == scheme && next_host == host_ && next_port == port_) { + return detail::redirect(*this, req, res, path, location, error); + } else { + if (next_scheme == "https") { +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + SSLClient cli(next_host, next_port); + cli.copy_settings(*this); + if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); } + return detail::redirect(cli, req, res, path, location, error); +#else + return false; +#endif + } else { + ClientImpl cli(next_host, next_port); + cli.copy_settings(*this); + return detail::redirect(cli, req, res, path, location, error); + } + } +} + +inline bool ClientImpl::write_content_with_provider(Stream &strm, + const Request &req, + Error &error) const { + auto is_shutting_down = []() { return false; }; + + if (req.is_chunked_content_provider_) { + // TODO: Brotli support + std::unique_ptr compressor; +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + if (compress_) { + compressor = detail::make_unique(); + } else +#endif + { + compressor = detail::make_unique(); + } + + return detail::write_content_chunked(strm, req.content_provider_, + is_shutting_down, *compressor, error); + } else { + return detail::write_content(strm, req.content_provider_, 0, + req.content_length_, is_shutting_down, error); + } +} + +inline bool ClientImpl::write_request(Stream &strm, Request &req, + bool close_connection, Error &error) { + // Prepare additional headers + if (close_connection) { + if (!req.has_header("Connection")) { + req.set_header("Connection", "close"); + } + } + + if (!req.has_header("Host")) { + if (is_ssl()) { + if (port_ == 443) { + req.set_header("Host", host_); + } else { + req.set_header("Host", host_and_port_); + } + } else { + if (port_ == 80) { + req.set_header("Host", host_); + } else { + req.set_header("Host", host_and_port_); + } + } + } + + if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); } + +#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT + if (!req.has_header("User-Agent")) { + auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION; + req.set_header("User-Agent", agent); + } +#endif + + if (req.body.empty()) { + if (req.content_provider_) { + if (!req.is_chunked_content_provider_) { + if (!req.has_header("Content-Length")) { + auto length = std::to_string(req.content_length_); + req.set_header("Content-Length", length); + } + } + } else { + if (req.method == "POST" || req.method == "PUT" || + req.method == "PATCH") { + req.set_header("Content-Length", "0"); + } + } + } else { + if (!req.has_header("Content-Type")) { + req.set_header("Content-Type", "text/plain"); + } + + if (!req.has_header("Content-Length")) { + auto length = std::to_string(req.body.size()); + req.set_header("Content-Length", length); + } + } + + if (!basic_auth_password_.empty() || !basic_auth_username_.empty()) { + if (!req.has_header("Authorization")) { + req.headers.insert(make_basic_authentication_header( + basic_auth_username_, basic_auth_password_, false)); + } + } + + if (!proxy_basic_auth_username_.empty() && + !proxy_basic_auth_password_.empty()) { + if (!req.has_header("Proxy-Authorization")) { + req.headers.insert(make_basic_authentication_header( + proxy_basic_auth_username_, proxy_basic_auth_password_, true)); + } + } + + if (!bearer_token_auth_token_.empty()) { + if (!req.has_header("Authorization")) { + req.headers.insert(make_bearer_token_authentication_header( + bearer_token_auth_token_, false)); + } + } + + if (!proxy_bearer_token_auth_token_.empty()) { + if (!req.has_header("Proxy-Authorization")) { + req.headers.insert(make_bearer_token_authentication_header( + proxy_bearer_token_auth_token_, true)); + } + } + + // Request line and headers + { + detail::BufferStream bstrm; + + const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path; + detail::write_request_line(bstrm, req.method, path); + + header_writer_(bstrm, req.headers); + + // Flush buffer + auto &data = bstrm.get_buffer(); + if (!detail::write_data(strm, data.data(), data.size())) { + error = Error::Write; + return false; + } + } + + // Body + if (req.body.empty()) { + return write_content_with_provider(strm, req, error); + } + + if (!detail::write_data(strm, req.body.data(), req.body.size())) { + error = Error::Write; + return false; + } + + return true; +} + +inline std::unique_ptr ClientImpl::send_with_content_provider( + Request &req, const char *body, size_t content_length, + ContentProvider content_provider, + ContentProviderWithoutLength content_provider_without_length, + const std::string &content_type, Error &error) { + if (!content_type.empty()) { req.set_header("Content-Type", content_type); } + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + if (compress_) { req.set_header("Content-Encoding", "gzip"); } +#endif + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + if (compress_ && !content_provider_without_length) { + // TODO: Brotli support + detail::gzip_compressor compressor; + + if (content_provider) { + auto ok = true; + size_t offset = 0; + DataSink data_sink; + + data_sink.write = [&](const char *data, size_t data_len) -> bool { + if (ok) { + auto last = offset + data_len == content_length; + + auto ret = compressor.compress( + data, data_len, last, + [&](const char *compressed_data, size_t compressed_data_len) { + req.body.append(compressed_data, compressed_data_len); + return true; + }); + + if (ret) { + offset += data_len; + } else { + ok = false; + } + } + return ok; + }; + + while (ok && offset < content_length) { + if (!content_provider(offset, content_length - offset, data_sink)) { + error = Error::Canceled; + return nullptr; + } + } + } else { + if (!compressor.compress(body, content_length, true, + [&](const char *data, size_t data_len) { + req.body.append(data, data_len); + return true; + })) { + error = Error::Compression; + return nullptr; + } + } + } else +#endif + { + if (content_provider) { + req.content_length_ = content_length; + req.content_provider_ = std::move(content_provider); + req.is_chunked_content_provider_ = false; + } else if (content_provider_without_length) { + req.content_length_ = 0; + req.content_provider_ = detail::ContentProviderAdapter( + std::move(content_provider_without_length)); + req.is_chunked_content_provider_ = true; + req.set_header("Transfer-Encoding", "chunked"); + } else { + req.body.assign(body, content_length); + } + } + + auto res = detail::make_unique(); + return send(req, *res, error) ? std::move(res) : nullptr; +} + +inline Result ClientImpl::send_with_content_provider( + const std::string &method, const std::string &path, const Headers &headers, + const char *body, size_t content_length, ContentProvider content_provider, + ContentProviderWithoutLength content_provider_without_length, + const std::string &content_type, Progress progress) { + Request req; + req.method = method; + req.headers = headers; + req.path = path; + req.progress = progress; + + auto error = Error::Success; + + auto res = send_with_content_provider( + req, body, content_length, std::move(content_provider), + std::move(content_provider_without_length), content_type, error); + + return Result{std::move(res), error, std::move(req.headers)}; +} + +inline std::string +ClientImpl::adjust_host_string(const std::string &host) const { + if (host.find(':') != std::string::npos) { return "[" + host + "]"; } + return host; +} + +inline bool ClientImpl::process_request(Stream &strm, Request &req, + Response &res, bool close_connection, + Error &error) { + // Send request + if (!write_request(strm, req, close_connection, error)) { return false; } + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (is_ssl()) { + auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1; + if (!is_proxy_enabled) { + char buf[1]; + if (SSL_peek(socket_.ssl, buf, 1) == 0 && + SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) { + error = Error::SSLPeerCouldBeClosed_; + return false; + } + } + } +#endif + + // Receive response and headers + if (!read_response_line(strm, req, res) || + !detail::read_headers(strm, res.headers)) { + error = Error::Read; + return false; + } + + // Body + if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" && + req.method != "CONNECT") { + auto redirect = 300 < res.status && res.status < 400 && follow_location_; + + if (req.response_handler && !redirect) { + if (!req.response_handler(res)) { + error = Error::Canceled; + return false; + } + } + + auto out = + req.content_receiver + ? static_cast( + [&](const char *buf, size_t n, uint64_t off, uint64_t len) { + if (redirect) { return true; } + auto ret = req.content_receiver(buf, n, off, len); + if (!ret) { error = Error::Canceled; } + return ret; + }) + : static_cast( + [&](const char *buf, size_t n, uint64_t /*off*/, + uint64_t /*len*/) { + if (res.body.size() + n > res.body.max_size()) { + return false; + } + res.body.append(buf, n); + return true; + }); + + auto progress = [&](uint64_t current, uint64_t total) { + if (!req.progress || redirect) { return true; } + auto ret = req.progress(current, total); + if (!ret) { error = Error::Canceled; } + return ret; + }; + + if (res.has_header("Content-Length")) { + if (!req.content_receiver) { + auto len = std::min(res.get_header_value_u64("Content-Length"), + res.body.max_size()); + if (len > 0) { res.body.reserve(len); } + } + } + + int dummy_status; + if (!detail::read_content(strm, res, (std::numeric_limits::max)(), + dummy_status, std::move(progress), std::move(out), + decompress_)) { + if (error != Error::Canceled) { error = Error::Read; } + return false; + } + } + + // Log + if (logger_) { logger_(req, res); } + + return true; +} + +inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider( + const std::string &boundary, const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items) const { + size_t cur_item = 0; + size_t cur_start = 0; + // cur_item and cur_start are copied to within the std::function and maintain + // state between successive calls + return [&, cur_item, cur_start](size_t offset, + DataSink &sink) mutable -> bool { + if (!offset && !items.empty()) { + sink.os << detail::serialize_multipart_formdata(items, boundary, false); + return true; + } else if (cur_item < provider_items.size()) { + if (!cur_start) { + const auto &begin = detail::serialize_multipart_formdata_item_begin( + provider_items[cur_item], boundary); + offset += begin.size(); + cur_start = offset; + sink.os << begin; + } + + DataSink cur_sink; + auto has_data = true; + cur_sink.write = sink.write; + cur_sink.done = [&]() { has_data = false; }; + + if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) { + return false; + } + + if (!has_data) { + sink.os << detail::serialize_multipart_formdata_item_end(); + cur_item++; + cur_start = 0; + } + return true; + } else { + sink.os << detail::serialize_multipart_formdata_finish(boundary); + sink.done(); + return true; + } + }; +} + +inline bool +ClientImpl::process_socket(const Socket &socket, + std::function callback) { + return detail::process_client_socket( + socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, + write_timeout_usec_, std::move(callback)); +} + +inline bool ClientImpl::is_ssl() const { return false; } + +inline Result ClientImpl::Get(const std::string &path) { + return Get(path, Headers(), Progress()); +} + +inline Result ClientImpl::Get(const std::string &path, Progress progress) { + return Get(path, Headers(), std::move(progress)); +} + +inline Result ClientImpl::Get(const std::string &path, const Headers &headers) { + return Get(path, headers, Progress()); +} + +inline Result ClientImpl::Get(const std::string &path, const Headers &headers, + Progress progress) { + Request req; + req.method = "GET"; + req.path = path; + req.headers = headers; + req.progress = std::move(progress); + + return send_(std::move(req)); +} + +inline Result ClientImpl::Get(const std::string &path, + ContentReceiver content_receiver) { + return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr); +} + +inline Result ClientImpl::Get(const std::string &path, + ContentReceiver content_receiver, + Progress progress) { + return Get(path, Headers(), nullptr, std::move(content_receiver), + std::move(progress)); +} + +inline Result ClientImpl::Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver) { + return Get(path, headers, nullptr, std::move(content_receiver), nullptr); +} + +inline Result ClientImpl::Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver, + Progress progress) { + return Get(path, headers, nullptr, std::move(content_receiver), + std::move(progress)); +} + +inline Result ClientImpl::Get(const std::string &path, + ResponseHandler response_handler, + ContentReceiver content_receiver) { + return Get(path, Headers(), std::move(response_handler), + std::move(content_receiver), nullptr); +} + +inline Result ClientImpl::Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver) { + return Get(path, headers, std::move(response_handler), + std::move(content_receiver), nullptr); +} + +inline Result ClientImpl::Get(const std::string &path, + ResponseHandler response_handler, + ContentReceiver content_receiver, + Progress progress) { + return Get(path, Headers(), std::move(response_handler), + std::move(content_receiver), std::move(progress)); +} + +inline Result ClientImpl::Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver, + Progress progress) { + Request req; + req.method = "GET"; + req.path = path; + req.headers = headers; + req.response_handler = std::move(response_handler); + req.content_receiver = + [content_receiver](const char *data, size_t data_length, + uint64_t /*offset*/, uint64_t /*total_length*/) { + return content_receiver(data, data_length); + }; + req.progress = std::move(progress); + + return send_(std::move(req)); +} + +inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, + const Headers &headers, Progress progress) { + if (params.empty()) { return Get(path, headers); } + + std::string path_with_query = append_query_params(path, params); + return Get(path_with_query, headers, std::move(progress)); +} + +inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, + const Headers &headers, + ContentReceiver content_receiver, + Progress progress) { + return Get(path, params, headers, nullptr, std::move(content_receiver), + std::move(progress)); +} + +inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, + const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver, + Progress progress) { + if (params.empty()) { + return Get(path, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); + } + + std::string path_with_query = append_query_params(path, params); + return Get(path_with_query, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); +} + +inline Result ClientImpl::Head(const std::string &path) { + return Head(path, Headers()); +} + +inline Result ClientImpl::Head(const std::string &path, + const Headers &headers) { + Request req; + req.method = "HEAD"; + req.headers = headers; + req.path = path; + + return send_(std::move(req)); +} + +inline Result ClientImpl::Post(const std::string &path) { + return Post(path, std::string(), std::string()); +} + +inline Result ClientImpl::Post(const std::string &path, + const Headers &headers) { + return Post(path, headers, nullptr, 0, std::string()); +} + +inline Result ClientImpl::Post(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return Post(path, Headers(), body, content_length, content_type, nullptr); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return send_with_content_provider("POST", path, headers, body, content_length, + nullptr, nullptr, content_type, nullptr); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + Progress progress) { + return send_with_content_provider("POST", path, headers, body, content_length, + nullptr, nullptr, content_type, progress); +} + +inline Result ClientImpl::Post(const std::string &path, const std::string &body, + const std::string &content_type) { + return Post(path, Headers(), body, content_type); +} + +inline Result ClientImpl::Post(const std::string &path, const std::string &body, + const std::string &content_type, + Progress progress) { + return Post(path, Headers(), body, content_type, progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return send_with_content_provider("POST", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + nullptr); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + Progress progress) { + return send_with_content_provider("POST", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Params ¶ms) { + return Post(path, Headers(), params); +} + +inline Result ClientImpl::Post(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return Post(path, Headers(), content_length, std::move(content_provider), + content_type); +} + +inline Result ClientImpl::Post(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return Post(path, Headers(), std::move(content_provider), content_type); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return send_with_content_provider("POST", path, headers, nullptr, + content_length, std::move(content_provider), + nullptr, content_type, nullptr); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr, + std::move(content_provider), content_type, + nullptr); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const Params ¶ms) { + auto query = detail::params_to_query_str(params); + return Post(path, headers, query, "application/x-www-form-urlencoded"); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress) { + auto query = detail::params_to_query_str(params); + return Post(path, headers, query, "application/x-www-form-urlencoded", + progress); +} + +inline Result ClientImpl::Post(const std::string &path, + const MultipartFormDataItems &items) { + return Post(path, Headers(), items); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + const auto &body = detail::serialize_multipart_formdata(items, boundary); + return Post(path, headers, body, content_type); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const std::string &boundary) { + if (!detail::is_multipart_boundary_chars_valid(boundary)) { + return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; + } + + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + const auto &body = detail::serialize_multipart_formdata(items, boundary); + return Post(path, headers, body, content_type); +} + +inline Result +ClientImpl::Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + return send_with_content_provider( + "POST", path, headers, nullptr, 0, nullptr, + get_multipart_content_provider(boundary, items, provider_items), + content_type, nullptr); +} + +inline Result ClientImpl::Put(const std::string &path) { + return Put(path, std::string(), std::string()); +} + +inline Result ClientImpl::Put(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return Put(path, Headers(), body, content_length, content_type); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return send_with_content_provider("PUT", path, headers, body, content_length, + nullptr, nullptr, content_type, nullptr); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + Progress progress) { + return send_with_content_provider("PUT", path, headers, body, content_length, + nullptr, nullptr, content_type, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const std::string &body, + const std::string &content_type) { + return Put(path, Headers(), body, content_type); +} + +inline Result ClientImpl::Put(const std::string &path, const std::string &body, + const std::string &content_type, + Progress progress) { + return Put(path, Headers(), body, content_type, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return send_with_content_provider("PUT", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + nullptr); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + Progress progress) { + return send_with_content_provider("PUT", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + progress); +} + +inline Result ClientImpl::Put(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return Put(path, Headers(), content_length, std::move(content_provider), + content_type); +} + +inline Result ClientImpl::Put(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return Put(path, Headers(), std::move(content_provider), content_type); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return send_with_content_provider("PUT", path, headers, nullptr, + content_length, std::move(content_provider), + nullptr, content_type, nullptr); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr, + std::move(content_provider), content_type, + nullptr); +} + +inline Result ClientImpl::Put(const std::string &path, const Params ¶ms) { + return Put(path, Headers(), params); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const Params ¶ms) { + auto query = detail::params_to_query_str(params); + return Put(path, headers, query, "application/x-www-form-urlencoded"); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress) { + auto query = detail::params_to_query_str(params); + return Put(path, headers, query, "application/x-www-form-urlencoded", + progress); +} + +inline Result ClientImpl::Put(const std::string &path, + const MultipartFormDataItems &items) { + return Put(path, Headers(), items); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + const auto &body = detail::serialize_multipart_formdata(items, boundary); + return Put(path, headers, body, content_type); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const std::string &boundary) { + if (!detail::is_multipart_boundary_chars_valid(boundary)) { + return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; + } + + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + const auto &body = detail::serialize_multipart_formdata(items, boundary); + return Put(path, headers, body, content_type); +} + +inline Result +ClientImpl::Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + return send_with_content_provider( + "PUT", path, headers, nullptr, 0, nullptr, + get_multipart_content_provider(boundary, items, provider_items), + content_type, nullptr); +} +inline Result ClientImpl::Patch(const std::string &path) { + return Patch(path, std::string(), std::string()); +} + +inline Result ClientImpl::Patch(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return Patch(path, Headers(), body, content_length, content_type); +} + +inline Result ClientImpl::Patch(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type, + Progress progress) { + return Patch(path, Headers(), body, content_length, content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return Patch(path, headers, body, content_length, content_type, nullptr); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + Progress progress) { + return send_with_content_provider("PATCH", path, headers, body, + content_length, nullptr, nullptr, + content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, + const std::string &body, + const std::string &content_type) { + return Patch(path, Headers(), body, content_type); +} + +inline Result ClientImpl::Patch(const std::string &path, + const std::string &body, + const std::string &content_type, + Progress progress) { + return Patch(path, Headers(), body, content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return Patch(path, headers, body, content_type, nullptr); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + Progress progress) { + return send_with_content_provider("PATCH", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + progress); +} + +inline Result ClientImpl::Patch(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return Patch(path, Headers(), content_length, std::move(content_provider), + content_type); +} + +inline Result ClientImpl::Patch(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return Patch(path, Headers(), std::move(content_provider), content_type); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return send_with_content_provider("PATCH", path, headers, nullptr, + content_length, std::move(content_provider), + nullptr, content_type, nullptr); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr, + std::move(content_provider), content_type, + nullptr); +} + +inline Result ClientImpl::Delete(const std::string &path) { + return Delete(path, Headers(), std::string(), std::string()); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers) { + return Delete(path, headers, std::string(), std::string()); +} + +inline Result ClientImpl::Delete(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return Delete(path, Headers(), body, content_length, content_type); +} + +inline Result ClientImpl::Delete(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type, + Progress progress) { + return Delete(path, Headers(), body, content_length, content_type, progress); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers, const char *body, + size_t content_length, + const std::string &content_type) { + return Delete(path, headers, body, content_length, content_type, nullptr); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers, const char *body, + size_t content_length, + const std::string &content_type, + Progress progress) { + Request req; + req.method = "DELETE"; + req.headers = headers; + req.path = path; + req.progress = progress; + + if (!content_type.empty()) { req.set_header("Content-Type", content_type); } + req.body.assign(body, content_length); + + return send_(std::move(req)); +} + +inline Result ClientImpl::Delete(const std::string &path, + const std::string &body, + const std::string &content_type) { + return Delete(path, Headers(), body.data(), body.size(), content_type); +} + +inline Result ClientImpl::Delete(const std::string &path, + const std::string &body, + const std::string &content_type, + Progress progress) { + return Delete(path, Headers(), body.data(), body.size(), content_type, + progress); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers, + const std::string &body, + const std::string &content_type) { + return Delete(path, headers, body.data(), body.size(), content_type); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers, + const std::string &body, + const std::string &content_type, + Progress progress) { + return Delete(path, headers, body.data(), body.size(), content_type, + progress); +} + +inline Result ClientImpl::Options(const std::string &path) { + return Options(path, Headers()); +} + +inline Result ClientImpl::Options(const std::string &path, + const Headers &headers) { + Request req; + req.method = "OPTIONS"; + req.headers = headers; + req.path = path; + + return send_(std::move(req)); +} + +inline void ClientImpl::stop() { + std::lock_guard guard(socket_mutex_); + + // If there is anything ongoing right now, the ONLY thread-safe thing we can + // do is to shutdown_socket, so that threads using this socket suddenly + // discover they can't read/write any more and error out. Everything else + // (closing the socket, shutting ssl down) is unsafe because these actions are + // not thread-safe. + if (socket_requests_in_flight_ > 0) { + shutdown_socket(socket_); + + // Aside from that, we set a flag for the socket to be closed when we're + // done. + socket_should_be_closed_when_request_is_done_ = true; + return; + } + + // Otherwise, still holding the mutex, we can shut everything down ourselves + shutdown_ssl(socket_, true); + shutdown_socket(socket_); + close_socket(socket_); +} + +inline std::string ClientImpl::host() const { return host_; } + +inline int ClientImpl::port() const { return port_; } + +inline size_t ClientImpl::is_socket_open() const { + std::lock_guard guard(socket_mutex_); + return socket_.is_open(); +} + +inline socket_t ClientImpl::socket() const { return socket_.sock; } + +inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) { + connection_timeout_sec_ = sec; + connection_timeout_usec_ = usec; +} + +inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) { + read_timeout_sec_ = sec; + read_timeout_usec_ = usec; +} + +inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) { + write_timeout_sec_ = sec; + write_timeout_usec_ = usec; +} + +inline void ClientImpl::set_basic_auth(const std::string &username, + const std::string &password) { + basic_auth_username_ = username; + basic_auth_password_ = password; +} + +inline void ClientImpl::set_bearer_token_auth(const std::string &token) { + bearer_token_auth_token_ = token; +} + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline void ClientImpl::set_digest_auth(const std::string &username, + const std::string &password) { + digest_auth_username_ = username; + digest_auth_password_ = password; +} +#endif + +inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; } + +inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; } + +inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; } + +inline void +ClientImpl::set_hostname_addr_map(std::map addr_map) { + addr_map_ = std::move(addr_map); +} + +inline void ClientImpl::set_default_headers(Headers headers) { + default_headers_ = std::move(headers); +} + +inline void ClientImpl::set_header_writer( + std::function const &writer) { + header_writer_ = writer; +} + +inline void ClientImpl::set_address_family(int family) { + address_family_ = family; +} + +inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; } + +inline void ClientImpl::set_ipv6_v6only(bool on) { ipv6_v6only_ = on; } + +inline void ClientImpl::set_socket_options(SocketOptions socket_options) { + socket_options_ = std::move(socket_options); +} + +inline void ClientImpl::set_compress(bool on) { compress_ = on; } + +inline void ClientImpl::set_decompress(bool on) { decompress_ = on; } + +inline void ClientImpl::set_interface(const std::string &intf) { + interface_ = intf; +} + +inline void ClientImpl::set_proxy(const std::string &host, int port) { + proxy_host_ = host; + proxy_port_ = port; +} + +inline void ClientImpl::set_proxy_basic_auth(const std::string &username, + const std::string &password) { + proxy_basic_auth_username_ = username; + proxy_basic_auth_password_ = password; +} + +inline void ClientImpl::set_proxy_bearer_token_auth(const std::string &token) { + proxy_bearer_token_auth_token_ = token; +} + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline void ClientImpl::set_proxy_digest_auth(const std::string &username, + const std::string &password) { + proxy_digest_auth_username_ = username; + proxy_digest_auth_password_ = password; +} + +inline void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path, + const std::string &ca_cert_dir_path) { + ca_cert_file_path_ = ca_cert_file_path; + ca_cert_dir_path_ = ca_cert_dir_path; +} + +inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) { + if (ca_cert_store && ca_cert_store != ca_cert_store_) { + ca_cert_store_ = ca_cert_store; + } +} + +inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert, + std::size_t size) const { + auto mem = BIO_new_mem_buf(ca_cert, static_cast(size)); + auto se = detail::scope_exit([&] { BIO_free_all(mem); }); + if (!mem) { return nullptr; } + + auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr); + if (!inf) { return nullptr; } + + auto cts = X509_STORE_new(); + if (cts) { + for (auto i = 0; i < static_cast(sk_X509_INFO_num(inf)); i++) { + auto itmp = sk_X509_INFO_value(inf, i); + if (!itmp) { continue; } + + if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); } + if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); } + } + } + + sk_X509_INFO_pop_free(inf, X509_INFO_free); + return cts; +} + +inline void ClientImpl::enable_server_certificate_verification(bool enabled) { + server_certificate_verification_ = enabled; +} + +inline void ClientImpl::enable_server_hostname_verification(bool enabled) { + server_hostname_verification_ = enabled; +} + +inline void ClientImpl::set_server_certificate_verifier( + std::function verifier) { + server_certificate_verifier_ = verifier; +} +#endif + +inline void ClientImpl::set_logger(Logger logger) { + logger_ = std::move(logger); +} + +/* + * SSL Implementation + */ +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +namespace detail { + +template +inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex, + U SSL_connect_or_accept, V setup) { + SSL *ssl = nullptr; + { + std::lock_guard guard(ctx_mutex); + ssl = SSL_new(ctx); + } + + if (ssl) { + set_nonblocking(sock, true); + auto bio = BIO_new_socket(static_cast(sock), BIO_NOCLOSE); + BIO_set_nbio(bio, 1); + SSL_set_bio(ssl, bio, bio); + + if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) { + SSL_shutdown(ssl); + { + std::lock_guard guard(ctx_mutex); + SSL_free(ssl); + } + set_nonblocking(sock, false); + return nullptr; + } + BIO_set_nbio(bio, 0); + set_nonblocking(sock, false); + } + + return ssl; +} + +inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, socket_t sock, + bool shutdown_gracefully) { + // sometimes we may want to skip this to try to avoid SIGPIPE if we know + // the remote has closed the network connection + // Note that it is not always possible to avoid SIGPIPE, this is merely a + // best-efforts. + if (shutdown_gracefully) { +#ifdef _WIN32 + SSL_shutdown(ssl); +#else + timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&tv), sizeof(tv)); + + auto ret = SSL_shutdown(ssl); + while (ret == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds{100}); + ret = SSL_shutdown(ssl); + } +#endif + } + + std::lock_guard guard(ctx_mutex); + SSL_free(ssl); +} + +template +bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl, + U ssl_connect_or_accept, + time_t timeout_sec, + time_t timeout_usec) { + auto res = 0; + while ((res = ssl_connect_or_accept(ssl)) != 1) { + auto err = SSL_get_error(ssl, res); + switch (err) { + case SSL_ERROR_WANT_READ: + if (select_read(sock, timeout_sec, timeout_usec) > 0) { continue; } + break; + case SSL_ERROR_WANT_WRITE: + if (select_write(sock, timeout_sec, timeout_usec) > 0) { continue; } + break; + default: break; + } + return false; + } + return true; +} + +template +inline bool process_server_socket_ssl( + const std::atomic &svr_sock, SSL *ssl, socket_t sock, + size_t keep_alive_max_count, time_t keep_alive_timeout_sec, + time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec, T callback) { + return process_server_socket_core( + svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec, + [&](bool close_connection, bool &connection_closed) { + SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec, + write_timeout_sec, write_timeout_usec); + return callback(strm, close_connection, connection_closed); + }); +} + +template +inline bool +process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec, + time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec, T callback) { + SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec, + write_timeout_sec, write_timeout_usec); + return callback(strm); +} + +class SSLInit { +public: + SSLInit() { + OPENSSL_init_ssl( + OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + } +}; + +// SSL socket stream implementation +inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl, + time_t read_timeout_sec, + time_t read_timeout_usec, + time_t write_timeout_sec, + time_t write_timeout_usec) + : sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec), + read_timeout_usec_(read_timeout_usec), + write_timeout_sec_(write_timeout_sec), + write_timeout_usec_(write_timeout_usec) { + SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY); +} + +inline SSLSocketStream::~SSLSocketStream() = default; + +inline bool SSLSocketStream::is_readable() const { + return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; +} + +inline bool SSLSocketStream::is_writable() const { + return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 && + is_socket_alive(sock_); +} + +inline ssize_t SSLSocketStream::read(char *ptr, size_t size) { + if (SSL_pending(ssl_) > 0) { + return SSL_read(ssl_, ptr, static_cast(size)); + } else if (is_readable()) { + auto ret = SSL_read(ssl_, ptr, static_cast(size)); + if (ret < 0) { + auto err = SSL_get_error(ssl_, ret); + auto n = 1000; +#ifdef _WIN32 + while (--n >= 0 && (err == SSL_ERROR_WANT_READ || + (err == SSL_ERROR_SYSCALL && + WSAGetLastError() == WSAETIMEDOUT))) { +#else + while (--n >= 0 && err == SSL_ERROR_WANT_READ) { +#endif + if (SSL_pending(ssl_) > 0) { + return SSL_read(ssl_, ptr, static_cast(size)); + } else if (is_readable()) { + std::this_thread::sleep_for(std::chrono::microseconds{10}); + ret = SSL_read(ssl_, ptr, static_cast(size)); + if (ret >= 0) { return ret; } + err = SSL_get_error(ssl_, ret); + } else { + return -1; + } + } + } + return ret; + } + return -1; +} + +inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) { + if (is_writable()) { + auto handle_size = static_cast( + std::min(size, (std::numeric_limits::max)())); + + auto ret = SSL_write(ssl_, ptr, static_cast(handle_size)); + if (ret < 0) { + auto err = SSL_get_error(ssl_, ret); + auto n = 1000; +#ifdef _WIN32 + while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE || + (err == SSL_ERROR_SYSCALL && + WSAGetLastError() == WSAETIMEDOUT))) { +#else + while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) { +#endif + if (is_writable()) { + std::this_thread::sleep_for(std::chrono::microseconds{10}); + ret = SSL_write(ssl_, ptr, static_cast(handle_size)); + if (ret >= 0) { return ret; } + err = SSL_get_error(ssl_, ret); + } else { + return -1; + } + } + } + return ret; + } + return -1; +} + +inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip, + int &port) const { + detail::get_remote_ip_and_port(sock_, ip, port); +} + +inline void SSLSocketStream::get_local_ip_and_port(std::string &ip, + int &port) const { + detail::get_local_ip_and_port(sock_, ip, port); +} + +inline socket_t SSLSocketStream::socket() const { return sock_; } + +static SSLInit sslinit_; + +} // namespace detail + +// SSL HTTP server implementation +inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, + const char *client_ca_cert_file_path, + const char *client_ca_cert_dir_path, + const char *private_key_password) { + ctx_ = SSL_CTX_new(TLS_server_method()); + + if (ctx_) { + SSL_CTX_set_options(ctx_, + SSL_OP_NO_COMPRESSION | + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); + + SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION); + + if (private_key_password != nullptr && (private_key_password[0] != '\0')) { + SSL_CTX_set_default_passwd_cb_userdata( + ctx_, + reinterpret_cast(const_cast(private_key_password))); + } + + if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || + SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != + 1 || + SSL_CTX_check_private_key(ctx_) != 1) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } else if (client_ca_cert_file_path || client_ca_cert_dir_path) { + SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path, + client_ca_cert_dir_path); + + SSL_CTX_set_verify( + ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); + } + } +} + +inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store) { + ctx_ = SSL_CTX_new(TLS_server_method()); + + if (ctx_) { + SSL_CTX_set_options(ctx_, + SSL_OP_NO_COMPRESSION | + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); + + SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION); + + if (SSL_CTX_use_certificate(ctx_, cert) != 1 || + SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } else if (client_ca_cert_store) { + SSL_CTX_set_cert_store(ctx_, client_ca_cert_store); + + SSL_CTX_set_verify( + ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); + } + } +} + +inline SSLServer::SSLServer( + const std::function &setup_ssl_ctx_callback) { + ctx_ = SSL_CTX_new(TLS_method()); + if (ctx_) { + if (!setup_ssl_ctx_callback(*ctx_)) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } + } +} + +inline SSLServer::~SSLServer() { + if (ctx_) { SSL_CTX_free(ctx_); } +} + +inline bool SSLServer::is_valid() const { return ctx_; } + +inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; } + +inline void SSLServer::update_certs(X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store) { + + std::lock_guard guard(ctx_mutex_); + + SSL_CTX_use_certificate(ctx_, cert); + SSL_CTX_use_PrivateKey(ctx_, private_key); + + if (client_ca_cert_store != nullptr) { + SSL_CTX_set_cert_store(ctx_, client_ca_cert_store); + } +} + +inline bool SSLServer::process_and_close_socket(socket_t sock) { + auto ssl = detail::ssl_new( + sock, ctx_, ctx_mutex_, + [&](SSL *ssl2) { + return detail::ssl_connect_or_accept_nonblocking( + sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_); + }, + [](SSL * /*ssl2*/) { return true; }); + + auto ret = false; + if (ssl) { + std::string remote_addr; + int remote_port = 0; + detail::get_remote_ip_and_port(sock, remote_addr, remote_port); + + std::string local_addr; + int local_port = 0; + detail::get_local_ip_and_port(sock, local_addr, local_port); + + ret = detail::process_server_socket_ssl( + svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_, + read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, + write_timeout_usec_, + [&](Stream &strm, bool close_connection, bool &connection_closed) { + return process_request(strm, remote_addr, remote_port, local_addr, + local_port, close_connection, + connection_closed, + [&](Request &req) { req.ssl = ssl; }); + }); + + // Shutdown gracefully if the result seemed successful, non-gracefully if + // the connection appeared to be closed. + const bool shutdown_gracefully = ret; + detail::ssl_delete(ctx_mutex_, ssl, sock, shutdown_gracefully); + } + + detail::shutdown_socket(sock); + detail::close_socket(sock); + return ret; +} + +// SSL HTTP client implementation +inline SSLClient::SSLClient(const std::string &host) + : SSLClient(host, 443, std::string(), std::string()) {} + +inline SSLClient::SSLClient(const std::string &host, int port) + : SSLClient(host, port, std::string(), std::string()) {} + +inline SSLClient::SSLClient(const std::string &host, int port, + const std::string &client_cert_path, + const std::string &client_key_path, + const std::string &private_key_password) + : ClientImpl(host, port, client_cert_path, client_key_path) { + ctx_ = SSL_CTX_new(TLS_client_method()); + + SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION); + + detail::split(&host_[0], &host_[host_.size()], '.', + [&](const char *b, const char *e) { + host_components_.emplace_back(b, e); + }); + + if (!client_cert_path.empty() && !client_key_path.empty()) { + if (!private_key_password.empty()) { + SSL_CTX_set_default_passwd_cb_userdata( + ctx_, reinterpret_cast( + const_cast(private_key_password.c_str()))); + } + + if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(), + SSL_FILETYPE_PEM) != 1 || + SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(), + SSL_FILETYPE_PEM) != 1) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } + } +} + +inline SSLClient::SSLClient(const std::string &host, int port, + X509 *client_cert, EVP_PKEY *client_key, + const std::string &private_key_password) + : ClientImpl(host, port) { + ctx_ = SSL_CTX_new(TLS_client_method()); + + detail::split(&host_[0], &host_[host_.size()], '.', + [&](const char *b, const char *e) { + host_components_.emplace_back(b, e); + }); + + if (client_cert != nullptr && client_key != nullptr) { + if (!private_key_password.empty()) { + SSL_CTX_set_default_passwd_cb_userdata( + ctx_, reinterpret_cast( + const_cast(private_key_password.c_str()))); + } + + if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 || + SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } + } +} + +inline SSLClient::~SSLClient() { + if (ctx_) { SSL_CTX_free(ctx_); } + // Make sure to shut down SSL since shutdown_ssl will resolve to the + // base function rather than the derived function once we get to the + // base class destructor, and won't free the SSL (causing a leak). + shutdown_ssl_impl(socket_, true); +} + +inline bool SSLClient::is_valid() const { return ctx_; } + +inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) { + if (ca_cert_store) { + if (ctx_) { + if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) { + // Free memory allocated for old cert and use new store `ca_cert_store` + SSL_CTX_set_cert_store(ctx_, ca_cert_store); + } + } else { + X509_STORE_free(ca_cert_store); + } + } +} + +inline void SSLClient::load_ca_cert_store(const char *ca_cert, + std::size_t size) { + set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size)); +} + +inline long SSLClient::get_openssl_verify_result() const { + return verify_result_; +} + +inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; } + +inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) { + return is_valid() && ClientImpl::create_and_connect_socket(socket, error); +} + +// Assumes that socket_mutex_ is locked and that there are no requests in flight +inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, + bool &success, Error &error) { + success = true; + Response proxy_res; + if (!detail::process_client_socket( + socket.sock, read_timeout_sec_, read_timeout_usec_, + write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) { + Request req2; + req2.method = "CONNECT"; + req2.path = host_and_port_; + return process_request(strm, req2, proxy_res, false, error); + })) { + // Thread-safe to close everything because we are assuming there are no + // requests in flight + shutdown_ssl(socket, true); + shutdown_socket(socket); + close_socket(socket); + success = false; + return false; + } + + if (proxy_res.status == StatusCode::ProxyAuthenticationRequired_407) { + if (!proxy_digest_auth_username_.empty() && + !proxy_digest_auth_password_.empty()) { + std::map auth; + if (detail::parse_www_authenticate(proxy_res, auth, true)) { + proxy_res = Response(); + if (!detail::process_client_socket( + socket.sock, read_timeout_sec_, read_timeout_usec_, + write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) { + Request req3; + req3.method = "CONNECT"; + req3.path = host_and_port_; + req3.headers.insert(detail::make_digest_authentication_header( + req3, auth, 1, detail::random_string(10), + proxy_digest_auth_username_, proxy_digest_auth_password_, + true)); + return process_request(strm, req3, proxy_res, false, error); + })) { + // Thread-safe to close everything because we are assuming there are + // no requests in flight + shutdown_ssl(socket, true); + shutdown_socket(socket); + close_socket(socket); + success = false; + return false; + } + } + } + } + + // If status code is not 200, proxy request is failed. + // Set error to ProxyConnection and return proxy response + // as the response of the request + if (proxy_res.status != StatusCode::OK_200) { + error = Error::ProxyConnection; + res = std::move(proxy_res); + // Thread-safe to close everything because we are assuming there are + // no requests in flight + shutdown_ssl(socket, true); + shutdown_socket(socket); + close_socket(socket); + return false; + } + + return true; +} + +inline bool SSLClient::load_certs() { + auto ret = true; + + std::call_once(initialize_cert_, [&]() { + std::lock_guard guard(ctx_mutex_); + if (!ca_cert_file_path_.empty()) { + if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(), + nullptr)) { + ret = false; + } + } else if (!ca_cert_dir_path_.empty()) { + if (!SSL_CTX_load_verify_locations(ctx_, nullptr, + ca_cert_dir_path_.c_str())) { + ret = false; + } + } else { + auto loaded = false; +#ifdef _WIN32 + loaded = + detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_)); +#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) +#if TARGET_OS_OSX + loaded = detail::load_system_certs_on_macos(SSL_CTX_get_cert_store(ctx_)); +#endif // TARGET_OS_OSX +#endif // _WIN32 + if (!loaded) { SSL_CTX_set_default_verify_paths(ctx_); } + } + }); + + return ret; +} + +inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { + auto ssl = detail::ssl_new( + socket.sock, ctx_, ctx_mutex_, + [&](SSL *ssl2) { + if (server_certificate_verification_) { + if (!load_certs()) { + error = Error::SSLLoadingCerts; + return false; + } + SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr); + } + + if (!detail::ssl_connect_or_accept_nonblocking( + socket.sock, ssl2, SSL_connect, connection_timeout_sec_, + connection_timeout_usec_)) { + error = Error::SSLConnection; + return false; + } + + if (server_certificate_verification_) { + if (server_certificate_verifier_) { + if (!server_certificate_verifier_(ssl2)) { + error = Error::SSLServerVerification; + return false; + } + } else { + verify_result_ = SSL_get_verify_result(ssl2); + + if (verify_result_ != X509_V_OK) { + error = Error::SSLServerVerification; + return false; + } + + auto server_cert = SSL_get1_peer_certificate(ssl2); + auto se = detail::scope_exit([&] { X509_free(server_cert); }); + + if (server_cert == nullptr) { + error = Error::SSLServerVerification; + return false; + } + + if (server_hostname_verification_) { + if (!verify_host(server_cert)) { + error = Error::SSLServerHostnameVerification; + return false; + } + } + } + } + + return true; + }, + [&](SSL *ssl2) { +#if defined(OPENSSL_IS_BORINGSSL) + SSL_set_tlsext_host_name(ssl2, host_.c_str()); +#else + // NOTE: Direct call instead of using the OpenSSL macro to suppress + // -Wold-style-cast warning + SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, + static_cast(const_cast(host_.c_str()))); +#endif + return true; + }); + + if (ssl) { + socket.ssl = ssl; + return true; + } + + shutdown_socket(socket); + close_socket(socket); + return false; +} + +inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) { + shutdown_ssl_impl(socket, shutdown_gracefully); +} + +inline void SSLClient::shutdown_ssl_impl(Socket &socket, + bool shutdown_gracefully) { + if (socket.sock == INVALID_SOCKET) { + assert(socket.ssl == nullptr); + return; + } + if (socket.ssl) { + detail::ssl_delete(ctx_mutex_, socket.ssl, socket.sock, + shutdown_gracefully); + socket.ssl = nullptr; + } + assert(socket.ssl == nullptr); +} + +inline bool +SSLClient::process_socket(const Socket &socket, + std::function callback) { + assert(socket.ssl); + return detail::process_client_socket_ssl( + socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_, + write_timeout_sec_, write_timeout_usec_, std::move(callback)); +} + +inline bool SSLClient::is_ssl() const { return true; } + +inline bool SSLClient::verify_host(X509 *server_cert) const { + /* Quote from RFC2818 section 3.1 "Server Identity" + + If a subjectAltName extension of type dNSName is present, that MUST + be used as the identity. Otherwise, the (most specific) Common Name + field in the Subject field of the certificate MUST be used. Although + the use of the Common Name is existing practice, it is deprecated and + Certification Authorities are encouraged to use the dNSName instead. + + Matching is performed using the matching rules specified by + [RFC2459]. If more than one identity of a given type is present in + the certificate (e.g., more than one dNSName name, a match in any one + of the set is considered acceptable.) Names may contain the wildcard + character * which is considered to match any single domain name + component or component fragment. E.g., *.a.com matches foo.a.com but + not bar.foo.a.com. f*.com matches foo.com but not bar.com. + + In some cases, the URI is specified as an IP address rather than a + hostname. In this case, the iPAddress subjectAltName must be present + in the certificate and must exactly match the IP in the URI. + + */ + return verify_host_with_subject_alt_name(server_cert) || + verify_host_with_common_name(server_cert); +} + +inline bool +SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { + auto ret = false; + + auto type = GEN_DNS; + + struct in6_addr addr6{}; + struct in_addr addr{}; + size_t addr_len = 0; + +#ifndef __MINGW32__ + if (inet_pton(AF_INET6, host_.c_str(), &addr6)) { + type = GEN_IPADD; + addr_len = sizeof(struct in6_addr); + } else if (inet_pton(AF_INET, host_.c_str(), &addr)) { + type = GEN_IPADD; + addr_len = sizeof(struct in_addr); + } +#endif + + auto alt_names = static_cast( + X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr)); + + if (alt_names) { + auto dsn_matched = false; + auto ip_matched = false; + + auto count = sk_GENERAL_NAME_num(alt_names); + + for (decltype(count) i = 0; i < count && !dsn_matched; i++) { + auto val = sk_GENERAL_NAME_value(alt_names, i); + if (val->type == type) { + auto name = + reinterpret_cast(ASN1_STRING_get0_data(val->d.ia5)); + auto name_len = static_cast(ASN1_STRING_length(val->d.ia5)); + + switch (type) { + case GEN_DNS: dsn_matched = check_host_name(name, name_len); break; + + case GEN_IPADD: + if (!memcmp(&addr6, name, addr_len) || + !memcmp(&addr, name, addr_len)) { + ip_matched = true; + } + break; + } + } + } + + if (dsn_matched || ip_matched) { ret = true; } + } + + GENERAL_NAMES_free(const_cast( + reinterpret_cast(alt_names))); + return ret; +} + +inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const { + const auto subject_name = X509_get_subject_name(server_cert); + + if (subject_name != nullptr) { + char name[BUFSIZ]; + auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName, + name, sizeof(name)); + + if (name_len != -1) { + return check_host_name(name, static_cast(name_len)); + } + } + + return false; +} + +inline bool SSLClient::check_host_name(const char *pattern, + size_t pattern_len) const { + if (host_.size() == pattern_len && host_ == pattern) { return true; } + + // Wildcard match + // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484 + std::vector pattern_components; + detail::split(&pattern[0], &pattern[pattern_len], '.', + [&](const char *b, const char *e) { + pattern_components.emplace_back(b, e); + }); + + if (host_components_.size() != pattern_components.size()) { return false; } + + auto itr = pattern_components.begin(); + for (const auto &h : host_components_) { + auto &p = *itr; + if (p != h && p != "*") { + auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' && + !p.compare(0, p.size() - 1, h)); + if (!partial_match) { return false; } + } + ++itr; + } + + return true; +} +#endif + +// Universal client implementation +inline Client::Client(const std::string &scheme_host_port) + : Client(scheme_host_port, std::string(), std::string()) {} + +inline Client::Client(const std::string &scheme_host_port, + const std::string &client_cert_path, + const std::string &client_key_path) { + const static std::regex re( + R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)"); + + std::smatch m; + if (std::regex_match(scheme_host_port, m, re)) { + auto scheme = m[1].str(); + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (!scheme.empty() && (scheme != "http" && scheme != "https")) { +#else + if (!scheme.empty() && scheme != "http") { +#endif +#ifndef CPPHTTPLIB_NO_EXCEPTIONS + std::string msg = "'" + scheme + "' scheme is not supported."; + throw std::invalid_argument(msg); +#endif + return; + } + + auto is_ssl = scheme == "https"; + + auto host = m[2].str(); + if (host.empty()) { host = m[3].str(); } + + auto port_str = m[4].str(); + auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80); + + if (is_ssl) { +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + cli_ = detail::make_unique(host, port, client_cert_path, + client_key_path); + is_ssl_ = is_ssl; +#endif + } else { + cli_ = detail::make_unique(host, port, client_cert_path, + client_key_path); + } + } else { + // NOTE: Update TEST(UniversalClientImplTest, Ipv6LiteralAddress) + // if port param below changes. + cli_ = detail::make_unique(scheme_host_port, 80, + client_cert_path, client_key_path); + } +} // namespace detail + +inline Client::Client(const std::string &host, int port) + : cli_(detail::make_unique(host, port)) {} + +inline Client::Client(const std::string &host, int port, + const std::string &client_cert_path, + const std::string &client_key_path) + : cli_(detail::make_unique(host, port, client_cert_path, + client_key_path)) {} + +inline Client::~Client() = default; + +inline bool Client::is_valid() const { + return cli_ != nullptr && cli_->is_valid(); +} + +inline Result Client::Get(const std::string &path) { return cli_->Get(path); } +inline Result Client::Get(const std::string &path, const Headers &headers) { + return cli_->Get(path, headers); +} +inline Result Client::Get(const std::string &path, Progress progress) { + return cli_->Get(path, std::move(progress)); +} +inline Result Client::Get(const std::string &path, const Headers &headers, + Progress progress) { + return cli_->Get(path, headers, std::move(progress)); +} +inline Result Client::Get(const std::string &path, + ContentReceiver content_receiver) { + return cli_->Get(path, std::move(content_receiver)); +} +inline Result Client::Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver) { + return cli_->Get(path, headers, std::move(content_receiver)); +} +inline Result Client::Get(const std::string &path, + ContentReceiver content_receiver, Progress progress) { + return cli_->Get(path, std::move(content_receiver), std::move(progress)); +} +inline Result Client::Get(const std::string &path, const Headers &headers, + ContentReceiver content_receiver, Progress progress) { + return cli_->Get(path, headers, std::move(content_receiver), + std::move(progress)); +} +inline Result Client::Get(const std::string &path, + ResponseHandler response_handler, + ContentReceiver content_receiver) { + return cli_->Get(path, std::move(response_handler), + std::move(content_receiver)); +} +inline Result Client::Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver) { + return cli_->Get(path, headers, std::move(response_handler), + std::move(content_receiver)); +} +inline Result Client::Get(const std::string &path, + ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress) { + return cli_->Get(path, std::move(response_handler), + std::move(content_receiver), std::move(progress)); +} +inline Result Client::Get(const std::string &path, const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress) { + return cli_->Get(path, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); +} +inline Result Client::Get(const std::string &path, const Params ¶ms, + const Headers &headers, Progress progress) { + return cli_->Get(path, params, headers, std::move(progress)); +} +inline Result Client::Get(const std::string &path, const Params ¶ms, + const Headers &headers, + ContentReceiver content_receiver, Progress progress) { + return cli_->Get(path, params, headers, std::move(content_receiver), + std::move(progress)); +} +inline Result Client::Get(const std::string &path, const Params ¶ms, + const Headers &headers, + ResponseHandler response_handler, + ContentReceiver content_receiver, Progress progress) { + return cli_->Get(path, params, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); +} + +inline Result Client::Head(const std::string &path) { return cli_->Head(path); } +inline Result Client::Head(const std::string &path, const Headers &headers) { + return cli_->Head(path, headers); +} + +inline Result Client::Post(const std::string &path) { return cli_->Post(path); } +inline Result Client::Post(const std::string &path, const Headers &headers) { + return cli_->Post(path, headers); +} +inline Result Client::Post(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return cli_->Post(path, body, content_length, content_type); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return cli_->Post(path, headers, body, content_length, content_type); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, Progress progress) { + return cli_->Post(path, headers, body, content_length, content_type, + progress); +} +inline Result Client::Post(const std::string &path, const std::string &body, + const std::string &content_type) { + return cli_->Post(path, body, content_type); +} +inline Result Client::Post(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress) { + return cli_->Post(path, body, content_type, progress); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return cli_->Post(path, headers, body, content_type); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, Progress progress) { + return cli_->Post(path, headers, body, content_type, progress); +} +inline Result Client::Post(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return cli_->Post(path, content_length, std::move(content_provider), + content_type); +} +inline Result Client::Post(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return cli_->Post(path, std::move(content_provider), content_type); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return cli_->Post(path, headers, content_length, std::move(content_provider), + content_type); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return cli_->Post(path, headers, std::move(content_provider), content_type); +} +inline Result Client::Post(const std::string &path, const Params ¶ms) { + return cli_->Post(path, params); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const Params ¶ms) { + return cli_->Post(path, headers, params); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress) { + return cli_->Post(path, headers, params, progress); +} +inline Result Client::Post(const std::string &path, + const MultipartFormDataItems &items) { + return cli_->Post(path, items); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items) { + return cli_->Post(path, headers, items); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const std::string &boundary) { + return cli_->Post(path, headers, items, boundary); +} +inline Result +Client::Post(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items) { + return cli_->Post(path, headers, items, provider_items); +} +inline Result Client::Put(const std::string &path) { return cli_->Put(path); } +inline Result Client::Put(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return cli_->Put(path, body, content_length, content_type); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return cli_->Put(path, headers, body, content_length, content_type); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, Progress progress) { + return cli_->Put(path, headers, body, content_length, content_type, progress); +} +inline Result Client::Put(const std::string &path, const std::string &body, + const std::string &content_type) { + return cli_->Put(path, body, content_type); +} +inline Result Client::Put(const std::string &path, const std::string &body, + const std::string &content_type, Progress progress) { + return cli_->Put(path, body, content_type, progress); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return cli_->Put(path, headers, body, content_type); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, Progress progress) { + return cli_->Put(path, headers, body, content_type, progress); +} +inline Result Client::Put(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return cli_->Put(path, content_length, std::move(content_provider), + content_type); +} +inline Result Client::Put(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return cli_->Put(path, std::move(content_provider), content_type); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return cli_->Put(path, headers, content_length, std::move(content_provider), + content_type); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return cli_->Put(path, headers, std::move(content_provider), content_type); +} +inline Result Client::Put(const std::string &path, const Params ¶ms) { + return cli_->Put(path, params); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const Params ¶ms) { + return cli_->Put(path, headers, params); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const Params ¶ms, Progress progress) { + return cli_->Put(path, headers, params, progress); +} +inline Result Client::Put(const std::string &path, + const MultipartFormDataItems &items) { + return cli_->Put(path, items); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items) { + return cli_->Put(path, headers, items); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const std::string &boundary) { + return cli_->Put(path, headers, items, boundary); +} +inline Result +Client::Put(const std::string &path, const Headers &headers, + const MultipartFormDataItems &items, + const MultipartFormDataProviderItems &provider_items) { + return cli_->Put(path, headers, items, provider_items); +} +inline Result Client::Patch(const std::string &path) { + return cli_->Patch(path); +} +inline Result Client::Patch(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return cli_->Patch(path, body, content_length, content_type); +} +inline Result Client::Patch(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type, + Progress progress) { + return cli_->Patch(path, body, content_length, content_type, progress); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return cli_->Patch(path, headers, body, content_length, content_type); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + Progress progress) { + return cli_->Patch(path, headers, body, content_length, content_type, + progress); +} +inline Result Client::Patch(const std::string &path, const std::string &body, + const std::string &content_type) { + return cli_->Patch(path, body, content_type); +} +inline Result Client::Patch(const std::string &path, const std::string &body, + const std::string &content_type, + Progress progress) { + return cli_->Patch(path, body, content_type, progress); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return cli_->Patch(path, headers, body, content_type); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + Progress progress) { + return cli_->Patch(path, headers, body, content_type, progress); +} +inline Result Client::Patch(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return cli_->Patch(path, content_length, std::move(content_provider), + content_type); +} +inline Result Client::Patch(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return cli_->Patch(path, std::move(content_provider), content_type); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type) { + return cli_->Patch(path, headers, content_length, std::move(content_provider), + content_type); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type) { + return cli_->Patch(path, headers, std::move(content_provider), content_type); +} +inline Result Client::Delete(const std::string &path) { + return cli_->Delete(path); +} +inline Result Client::Delete(const std::string &path, const Headers &headers) { + return cli_->Delete(path, headers); +} +inline Result Client::Delete(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type) { + return cli_->Delete(path, body, content_length, content_type); +} +inline Result Client::Delete(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type, + Progress progress) { + return cli_->Delete(path, body, content_length, content_type, progress); +} +inline Result Client::Delete(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type) { + return cli_->Delete(path, headers, body, content_length, content_type); +} +inline Result Client::Delete(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + Progress progress) { + return cli_->Delete(path, headers, body, content_length, content_type, + progress); +} +inline Result Client::Delete(const std::string &path, const std::string &body, + const std::string &content_type) { + return cli_->Delete(path, body, content_type); +} +inline Result Client::Delete(const std::string &path, const std::string &body, + const std::string &content_type, + Progress progress) { + return cli_->Delete(path, body, content_type, progress); +} +inline Result Client::Delete(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type) { + return cli_->Delete(path, headers, body, content_type); +} +inline Result Client::Delete(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + Progress progress) { + return cli_->Delete(path, headers, body, content_type, progress); +} +inline Result Client::Options(const std::string &path) { + return cli_->Options(path); +} +inline Result Client::Options(const std::string &path, const Headers &headers) { + return cli_->Options(path, headers); +} + +inline bool Client::send(Request &req, Response &res, Error &error) { + return cli_->send(req, res, error); +} + +inline Result Client::send(const Request &req) { return cli_->send(req); } + +inline void Client::stop() { cli_->stop(); } + +inline std::string Client::host() const { return cli_->host(); } + +inline int Client::port() const { return cli_->port(); } + +inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); } + +inline socket_t Client::socket() const { return cli_->socket(); } + +inline void +Client::set_hostname_addr_map(std::map addr_map) { + cli_->set_hostname_addr_map(std::move(addr_map)); +} + +inline void Client::set_default_headers(Headers headers) { + cli_->set_default_headers(std::move(headers)); +} + +inline void Client::set_header_writer( + std::function const &writer) { + cli_->set_header_writer(writer); +} + +inline void Client::set_address_family(int family) { + cli_->set_address_family(family); +} + +inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); } + +inline void Client::set_socket_options(SocketOptions socket_options) { + cli_->set_socket_options(std::move(socket_options)); +} + +inline void Client::set_connection_timeout(time_t sec, time_t usec) { + cli_->set_connection_timeout(sec, usec); +} + +inline void Client::set_read_timeout(time_t sec, time_t usec) { + cli_->set_read_timeout(sec, usec); +} + +inline void Client::set_write_timeout(time_t sec, time_t usec) { + cli_->set_write_timeout(sec, usec); +} + +inline void Client::set_basic_auth(const std::string &username, + const std::string &password) { + cli_->set_basic_auth(username, password); +} +inline void Client::set_bearer_token_auth(const std::string &token) { + cli_->set_bearer_token_auth(token); +} +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline void Client::set_digest_auth(const std::string &username, + const std::string &password) { + cli_->set_digest_auth(username, password); +} +#endif + +inline void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); } +inline void Client::set_follow_location(bool on) { + cli_->set_follow_location(on); +} + +inline void Client::set_url_encode(bool on) { cli_->set_url_encode(on); } + +inline void Client::set_compress(bool on) { cli_->set_compress(on); } + +inline void Client::set_decompress(bool on) { cli_->set_decompress(on); } + +inline void Client::set_interface(const std::string &intf) { + cli_->set_interface(intf); +} + +inline void Client::set_proxy(const std::string &host, int port) { + cli_->set_proxy(host, port); +} +inline void Client::set_proxy_basic_auth(const std::string &username, + const std::string &password) { + cli_->set_proxy_basic_auth(username, password); +} +inline void Client::set_proxy_bearer_token_auth(const std::string &token) { + cli_->set_proxy_bearer_token_auth(token); +} +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline void Client::set_proxy_digest_auth(const std::string &username, + const std::string &password) { + cli_->set_proxy_digest_auth(username, password); +} +#endif + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline void Client::enable_server_certificate_verification(bool enabled) { + cli_->enable_server_certificate_verification(enabled); +} + +inline void Client::enable_server_hostname_verification(bool enabled) { + cli_->enable_server_hostname_verification(enabled); +} + +inline void Client::set_server_certificate_verifier( + std::function verifier) { + cli_->set_server_certificate_verifier(verifier); +} +#endif + +inline void Client::set_logger(Logger logger) { + cli_->set_logger(std::move(logger)); +} + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path, + const std::string &ca_cert_dir_path) { + cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path); +} + +inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) { + if (is_ssl_) { + static_cast(*cli_).set_ca_cert_store(ca_cert_store); + } else { + cli_->set_ca_cert_store(ca_cert_store); + } +} + +inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) { + set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size)); +} + +inline long Client::get_openssl_verify_result() const { + if (is_ssl_) { + return static_cast(*cli_).get_openssl_verify_result(); + } + return -1; // NOTE: -1 doesn't match any of X509_V_ERR_??? +} + +inline SSL_CTX *Client::ssl_context() const { + if (is_ssl_) { return static_cast(*cli_).ssl_context(); } + return nullptr; +} +#endif + +// ---------------------------------------------------------------------------- + +} // namespace httplib + +#if defined(_WIN32) && defined(CPPHTTPLIB_USE_POLL) +#undef poll +#endif + +#endif // CPPHTTPLIB_HTTPLIB_H diff --git a/cfg_parse/httprun.cpp b/cfg_parse/httprun.cpp new file mode 100644 index 0000000..a1b53be --- /dev/null +++ b/cfg_parse/httprun.cpp @@ -0,0 +1,247 @@ +#include +#include +#include "httplib.h" +#include +#include "../json/cjson.h" + +//#include + +//#include + +//std::mutex data_mutex; // 用来保护 receivedData 变量 + +//#include +//std::atomic isrunning(false); // 使用原子变量保证 isrunning 的内存可见性 + +//std::queue receivedData; // 用于存储接收到的数据 +bool isrunning = true; //用于线程同步 +std::string receivedData; + +//std::queue receivedData2; // 用于存储接收到的数据 +bool isrunning2 = true; //用于线程同步 +std::string receivedData2; + +extern std::string HTTP_IP; +extern int HTTP_PORT; + +//设置回复消息体 +std::string recall_success = "{\"code\":\"A0000\", \"msg\":\"数据补招执行成功\", \"data\":null}"; +std::string recall_fail = "{\"code\":\"A0002\", \"msg\":\"数据补招执行失败\", \"data\":null}"; +std::string rtdata_success = "{\"code\":\"A0000\", \"msg\":\"3s数据执行成功\", \"data\":null}"; +std::string rtdata_fail = "{\"code\":\"A0002\", \"msg\":\"3s数据执行失败\", \"data\":null}"; + +// 处理补招请求的函数 +std::string HandleRecall_http(const httplib::Request& req, httplib::Response& res) { + // 打印请求的查询参数 + //std::cout << "Query parameters: " << std::endl; + + //std::lock_guard lock(data_mutex); + + if(isrunning == true){ //收到前置信号,收到信息可以处理消息 + if (req.body.empty()) { //消息体为空 + + std::cout << "req.body.empty" << std::endl; + + res.status = 400; + res.set_content(recall_fail, "application/json"); + return recall_fail; + } + + // 消息体不为空,解析 JSON 数据 + cJSON* json_root = cJSON_Parse(req.body.c_str()); + //解析失败或者消息体不为数组 + if (json_root == NULL || json_root->type != cJSON_Array) { + + std::cout << "json_root NULL or json_roottype not cJSON_Array" << std::endl; + + res.status = 400; + res.set_content(recall_fail, "application/json"); + cJSON_Delete(json_root); + return recall_fail; + } + + bool is_valid = true;//默认消息体正常 + //检查数组每个成员 + for (cJSON* item = json_root->child; item != NULL; item = item->next) { + // 检查每个对象是否包含 monitorId、dataType、timeInterval 且不为空 + cJSON* monitorId = cJSON_GetObjectItem(item, "monitorId"); + cJSON* dataType = cJSON_GetObjectItem(item, "dataType"); + cJSON* timeInterval = cJSON_GetObjectItem(item, "timeInterval"); + + //调试用 + std::cout << "!timeInterval" << !timeInterval << " " << (timeInterval->type != cJSON_Array) << " "<< (timeInterval->child == NULL) << std::endl; + + if (!timeInterval || //元素必须不为空 + timeInterval->type != cJSON_Array || timeInterval->child == NULL) { // timeInterval 必须为非空数组 + is_valid = false; //不满足结构则消息体不正常 + break; + } + } + + // 清理 JSON 数据 + cJSON_Delete(json_root); + + // 设置响应内容 + if (is_valid) { + res.status = 200; //消息体正常返回补招执行成功 + res.set_content(recall_success, "application/json"); + + receivedData = req.body; //提供给前置获取消息体处理 + isrunning = false; //停止处理http收到的消息直到收到前置的信号 + + return recall_success; + } else { + + std::cout << "json not right" << std::endl; + + res.status = 400; + res.set_content(recall_fail, "application/json"); + return recall_fail; + } + + } + return req.body; // 返回接收到的未处理的 JSON,暂时没有任何地方使用 +} + +// 处理实时数据请求的函数 +std::string HandleRtdata_http(const httplib::Request& req, httplib::Response& res) { + + if(isrunning2 == true){ //收到前置信号,收到信息可以处理消息 + if (req.body.empty()) { //消息体为空 + + std::cout << "req.body.empty" << std::endl; + + res.status = 400; + res.set_content(rtdata_fail, "application/json"); + return rtdata_fail; + } + + // 消息体不为空,解析 JSON 数据 + cJSON* json_root = cJSON_Parse(req.body.c_str()); + //解析失败或者消息体不为数组 + if (json_root == NULL || json_root->type != cJSON_Array) { + + std::cout << "json_root NULL or json_roottype not cJSON_Array" << std::endl; + + res.status = 400; + res.set_content(rtdata_fail, "application/json"); + cJSON_Delete(json_root); + return rtdata_fail; + } + + bool is_valid = true;//默认消息体正常 + //检查数组每个成员 + for (cJSON* item = json_root->child; item != NULL; item = item->next) { + // 检查每个对象不为空 + cJSON* DevSeries = cJSON_GetObjectItem(item, "DevSeries"); + cJSON* Line = cJSON_GetObjectItem(item, "Line"); + cJSON* RealData = cJSON_GetObjectItem(item, "RealData"); + cJSON* SOEData = cJSON_GetObjectItem(item, "SOEData"); + cJSON* Limit = cJSON_GetObjectItem(item, "Limit"); + cJSON* Count = cJSON_GetObjectItem(item, "Count"); + + if (!DevSeries || !Line || !RealData || !SOEData || !Limit || !Count) { + is_valid = false; //不满足结构则消息体不正常 + break; + } + } + + // 清理 JSON 数据 + cJSON_Delete(json_root); + + // 设置响应内容 + if (is_valid) { + res.status = 200; //消息体正常返回补招执行成功 + res.set_content(rtdata_success, "application/json"); + + receivedData2 = req.body; + isrunning2 = false; //停止处理http收到的消息直到收到前置的信号 + + return rtdata_success; + } else { + + std::cout << "json not right" << std::endl; + + res.status = 400; + res.set_content(rtdata_fail, "application/json"); + return rtdata_fail; + } + + } + return req.body; // 返回接收到的未处理的 JSON,暂时没有任何地方使用 +} + +//处理台账更新请求函数 +std::string Handleupdate_http(const httplib::Request& req, httplib::Response& res){ + +} + +// 获取接收到的字符串 +//extern "C" std::string getReceivedData() { +extern "C" const char* getReceivedData(int fun) { + if(1 == fun){ + /*if (!receivedData.empty()) { + std::string msg = receivedData.front(); // 获取队列中的第一条消息 + receivedData.pop(); // 从队列中移除这条消息 + return msg.c_str(); + } + return "recall queue empty";*/ + return receivedData.c_str(); + } + if(2 == fun){ + /*if (!receivedData2.empty()) { + std::string msg = receivedData2.front(); // 获取队列中的第一条消息 + receivedData2.pop(); // 从队列中移除这条消息 + return msg.c_str(); + } + return "rtdata queue empty";*/ + return receivedData2.c_str(); + } + return "all queue empty"; +} + +// 收取信号 1是补招,2是实时数据 +extern "C" void threadmsgweb(int fun) { + if(1 == fun){ + isrunning = true; + } + if(2 == fun){ + isrunning2 = true; + } +} + +// 发送信号 +extern "C" bool threadmsghttp(int fun) { + if(1 == fun){ + return isrunning; + } + if(2 == fun){ + return isrunning2; + } + return true; +} + +// 启动 HTTP 服务器的函数 +extern "C" void httprun() { + //std::cout << "WebhttpThread::run() is called ...... " << std::endl; + + // 创建 HTTP 服务器对象 + httplib::Server svr; + + // 监听路径 /powerQuality/recall,绑定处理函数 + svr.Post("/powerQuality/recall", HandleRecall_http); // 使用 POST 方法处理请求 + + // 监听路径 /powerQuality/rtdata,绑定处理函数 + svr.Post("/powerQuality/rtdata", HandleRtdata_http); // 使用 POST 方法处理请求 + + // 监听路径 /powerQuality/update,绑定处理函数 + svr.Post("/powerQuality/update", Handleupdate_http); // 使用 POST 方法处理请求 + + // 监听端口 10004 + //std::cout << "Server started at http://0.0.0.0:10004" << std::endl; + if (!svr.listen(HTTP_IP, HTTP_PORT)) { // 监听所有 IP + std::cerr << "Error: Unable to start server on port 10004" << std::endl; + } + + //std::cout << "WebhttpThread::run() is end ...... " << std::endl; +} \ No newline at end of file diff --git a/cfg_parse/nacos.cpp b/cfg_parse/nacos.cpp new file mode 100644 index 0000000..227c46d --- /dev/null +++ b/cfg_parse/nacos.cpp @@ -0,0 +1,742 @@ +/** +* @file: $RCSfile: nacos.cpp,v $ +* @brief: $aliyun datahub include +* +* @version: $Revision: 1.00 $ +* @date: $Date: 2023/10/24 18:34:00 $ +* @author: $Author: wangwei $ +* @state: $State: Exp $ +* +* @latest: $Id: nacos.cpp,v 1.00 2023/10/24 18:34:00 caizhouyu Exp $ +* +*/ + +using namespace std; + +#include + +/*lnk10-12*/ +#include + +#include +#include + +#include "../mms/db_interface.h" +#include "../json/cjson.h"//WW 2023-08-27json +#include "../include/curl/curl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + size_t req_reply_nacos(void* ptr, size_t size, size_t nmemb, void* stream) + { + //((std::string*)userp)->append((char*)contents, size * nmemb); + //ע͵ԴӡcookieϢ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + //printf(">>>GetDevice in reply %s\n", (char*)ptr); + + //GetCJson(ptr); + return size * nmemb; + } + + void read_nacos_param(const char* ptr, char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret) { + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + + if (json == NULL) { + printf("nacos error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || json_node->valuestring == NULL || json_node->valuestring == "/0" || json_node->valuestring == "" || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || json_node->valuestring == NULL || json_node->valuestring == "/0" || json_node->valuestring == "" || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "postgres_uid"); //ȡresult + if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { + strcpy(postgres_uid, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "postgres_pwd"); //ȡresult + if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { + //***postgres_pwd = json_node->valuestring; + strcpy(postgres_pwd, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "web_clientid"); //ȡresult + if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { + strcpy(web_clientid, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "web_clientsecret"); //ȡresult + if (json_node != NULL && strcmp(json_node->valuestring, "null") != 0) { + strcpy(web_clientsecret, json_node->valuestring); + } + + } + } + cJSON_Delete(json); + } + + void releaseMemory(char** ptr) { + if (*ptr != NULL) { + free(*ptr); // ͷڴ + } + } + + void SendWebAPI_Nacos(const string strUrl, const char* code, char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret) + { + + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + + cJSON_AddItemToObject(json_root, "code", cJSON_CreateString(code)); + + char* szjson = cJSON_Print(json_root); + printf(">>>json %s\n", szjson); + //string strjson = szjson; + //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_nacos); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>Test nacos Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("nacos failed res code: "); + } + else { + printf("nacos success,string %s", resPost0.c_str()); + //webapiֵж + read_nacos_param(resPost0.c_str(), postgres_uid, postgres_pwd, web_clientid, web_clientsecret); + } + + curl_slist_free_all(header_list); + free(szjson); + cJSON_Delete(json_root); + } + else + { + printf(">>> nacos curl init failed"); + } + curl_easy_cleanup(curl); + } + + void SendWebAPI_Nacos_Ptr(const string strUrl, const char* code, char** ptr) + { + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + char url[100]; + sprintf(url, "%s?code=%s", strUrl.c_str(), code); + printf(">>>json %s\n", url); + + // URL + curl_easy_setopt(curl, CURLOPT_URL, url); + + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_nacos); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + + // post + res = curl_easy_perform(curl); + + // Ƿɹ + if (res != CURLE_OK) { + printf("nacos failed res code: "); + } + else { + printf(">>> nacos return str:%s \n", resPost0.c_str()); + //*ptr = strdup(resPost0.c_str()); + *ptr = (char*)malloc(strlen(resPost0.c_str()) + 1); // 㹻ڴռ + if (*ptr != NULL) { + strcpy(*ptr, resPost0.c_str()); + } + else { + printf("Memory allocation failed!\n"); + } + //printf(">>>json %s\n", *ptr); + //webapiֵж + } + + //free(url); + } + else + { + printf(">>> nacos curl init failed"); + } + curl_easy_cleanup(curl); + } + + + void Nacos_GetParam(char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret) + { + SendWebAPI_Nacos("http://127.0.0.1:8091/powerQuality/PQNACOS", "200", postgres_uid, postgres_pwd, web_clientid, web_clientsecret); + } + + void Nacos_GetParam_Ptr(const char* code, char** ptr) + { + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", code, ptr); + } + + void Read_Nacos_Param_Postgres(char** database_ip, char** database_port, char** postgres_database, char** postgres_username, char** postgres_password, char** postgres_schema, char** postgres_dnsname, char** postgres_tableprefix) { + char* ptr=NULL; + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "postgres", &ptr); + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + + if (json == NULL) { + printf("nacos error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "ip"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*database_ip != NULL) { + // Ѿڴ棬ͷڴ + free(*database_ip); + } + *database_ip = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*database_ip, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "port"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*database_port != NULL) { + // Ѿڴ棬ͷڴ + free(*database_port); + } + *database_port = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*database_port, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "database"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*postgres_database != NULL) { + // Ѿڴ棬ͷڴ + free(*postgres_database); + } + *postgres_database = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*postgres_database, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "username"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + //***postgres_pwd = json_node->valuestring; + if (*postgres_username != NULL) { + // Ѿڴ棬ͷڴ + free(*postgres_username); + } + *postgres_username = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*postgres_username, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "password"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*postgres_password != NULL) { + // Ѿڴ棬ͷڴ + free(*postgres_password); + } + *postgres_password = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*postgres_password, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "schema"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*postgres_schema != NULL) { + // Ѿڴ棬ͷڴ + free(*postgres_schema); + } + *postgres_schema = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*postgres_schema, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "dnsname"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*postgres_dnsname != NULL) { + // Ѿڴ棬ͷڴ + free(*postgres_dnsname); + } + *postgres_dnsname = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*postgres_dnsname, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "tablePrefix"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*postgres_tableprefix != NULL) { + // Ѿڴ棬ͷڴ + free(*postgres_tableprefix); + } + *postgres_tableprefix = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*postgres_tableprefix, json_node->valuestring); + } + + } + } + if (ptr) { + free(ptr); + } + cJSON_Delete(json); + } + + void Read_Nacos_Param_Kafka(char** broker_list, char** topic_stat, char** topic_pst, char** topic_plt, char** topic_event, char** topic_alarm, char** topic_sng,char** protocol ,char** mechanisms, char** service_name, char** principal, char** domain_name) { + char* ptr = NULL; + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "kafka", &ptr); + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + if (json == NULL) { + printf("nacos error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "brokerList"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*broker_list != NULL) { + // Ѿڴ棬ͷڴ + free(*broker_list); + } + *broker_list = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*broker_list, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "hisTopic"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*topic_stat != NULL) { + // Ѿڴ棬ͷڴ + free(*topic_stat); + } + *topic_stat = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*topic_stat, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "pstTopic"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*topic_pst != NULL) { + // Ѿڴ棬ͷڴ + free(*topic_pst); + } + *topic_pst = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*topic_pst, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "pltTopic"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*topic_plt != NULL) { + // Ѿڴ棬ͷڴ + free(*topic_plt); + } + *topic_plt = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*topic_plt, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "eventTopic"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*topic_event != NULL) { + // Ѿڴ棬ͷڴ + free(*topic_event); + } + *topic_event = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*topic_event, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "almTopic"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*topic_alarm != NULL) { + // Ѿڴ棬ͷڴ + free(*topic_alarm); + } + *topic_alarm = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*topic_alarm, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "sngTopic"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*topic_sng != NULL) { + // Ѿڴ棬ͷڴ + free(*topic_sng); + } + *topic_sng = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*topic_sng, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "protocol"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*protocol != NULL) { + // Ѿڴ棬ͷڴ + free(*protocol); + } + *protocol = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*protocol, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "mechanisms"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*mechanisms != NULL) { + // Ѿڴ棬ͷڴ + free(*mechanisms); + } + *mechanisms = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*mechanisms, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "serviceName"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*service_name != NULL) { + // Ѿڴ棬ͷڴ + free(*service_name); + } + *service_name = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*service_name, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "principal"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*principal != NULL) { + // Ѿڴ棬ͷڴ + free(*principal); + } + *principal = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*principal, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "domainName"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*domain_name != NULL) { + // Ѿڴ棬ͷڴ + free(*domain_name); + } + *domain_name = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*domain_name, json_node->valuestring); + } + + } + } + cJSON_Delete(json); + } + + void Read_Nacos_Param_Web(char** client_id, char** client_secret, char** token_url, char** device_url, char** grant_type) { + char* ptr = NULL; + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "web", &ptr); + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + + if (json == NULL) { + printf("nacos error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "clientId"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*client_id != NULL) { + // Ѿڴ棬ͷڴ + free(*client_id); + } + *client_id = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*client_id, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "clientSecret"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*client_secret != NULL) { + // Ѿڴ棬ͷڴ + free(*client_secret); + } + *client_secret = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*client_secret, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "tokenUrl"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*token_url != NULL) { + // Ѿڴ棬ͷڴ + free(*token_url); + } + *token_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*token_url, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "deviceUrl"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + //***postgres_pwd = json_node->valuestring; + if (*device_url != NULL) { + // Ѿڴ棬ͷڴ + free(*device_url); + } + *device_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*device_url, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "grantType"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*grant_type != NULL) { + // Ѿڴ棬ͷڴ + free(*grant_type); + } + *grant_type = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*grant_type, json_node->valuestring); + } + + + } + } + cJSON_Delete(json); + } + + void Read_Nacos_Param_Flag(int* file_flag, int* send_flag, int* front_inst, char** front_ip) { + char* ptr = NULL; + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "flag", &ptr); + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + + if (json == NULL) { + printf("nacos error: %s\n", ptr); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "fileFlag"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + *file_flag= atoi(json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "sendFlag"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + *send_flag = atoi(json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "frontInst"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + *front_inst = atoi(json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "frontIP"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + //***postgres_pwd = json_node->valuestring; + if (*front_ip != NULL) { + // Ѿڴ棬ͷڴ + free(*front_ip); + } + *front_ip = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*front_ip, json_node->valuestring); + } + + + } + } + cJSON_Delete(json); + } + + void Read_Nacos_Param_Recall(int* recall_len, int* recall_sta, int* recall_daily) { + char* ptr = NULL; + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "recall", &ptr); + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + + if (json == NULL) { + printf("nacos error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "recall_lenth"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + *recall_len = atoi(json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "recall_start"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + *recall_sta = atoi(json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "recall_dailytime"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + *recall_daily = atoi(json_node->valuestring); + } + + } + } + cJSON_Delete(json); + } + + void Read_Nacos_Param_Uds(char** uds_upload_url, char** uds_download_url, char** uds_delete_url) { + char* ptr = NULL; + SendWebAPI_Nacos_Ptr("http://127.0.0.1:8091/powerQuality/getProperties", "uds", &ptr); + //cout << ">>>GetDevice in reply" << (char*)ptr; + int flag = 1; + cJSON* json = cJSON_Parse(ptr); //jsonʽл + cJSON* json_node; + cJSON* json_param; + + if (json == NULL) { + printf("nacos error %s\n", cJSON_GetErrorPtr()); + } + else { + json_node = cJSON_GetObjectItem(json, "status"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "000000") != 0) { + printf("status error :%s\n", cJSON_GetErrorPtr()); + flag = 0; + } + json_node = cJSON_GetObjectItem(json, "errors"); //ȡresult + if (json_node == NULL || strcmp(json_node->valuestring, "success") != 0) { + printf("errors get falie: %s\n", cJSON_GetErrorPtr()); + flag = 0; + } + if (flag) { + printf("read nacos success\n"); + + json_param = cJSON_GetObjectItem(json, "param"); //ȡresult + json_node = cJSON_GetObjectItem(json_param, "udsUploadUrl"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*uds_upload_url != NULL) { + // Ѿڴ棬ͷڴ + free(*uds_upload_url); + } + *uds_upload_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*uds_upload_url, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "udsDownloadUrl"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*uds_download_url != NULL) { + // Ѿڴ棬ͷڴ + free(*uds_download_url); + } + *uds_download_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*uds_download_url, json_node->valuestring); + } + json_node = cJSON_GetObjectItem(json_param, "UdsDeleteUrl"); //ȡresult + if (json_node && json_node->type == cJSON_String) { + if (*uds_delete_url != NULL) { + // Ѿڴ棬ͷڴ + free(*uds_delete_url); + } + *uds_delete_url = (char*)malloc(strlen(json_node->valuestring) + 1); // ڴ + strcpy(*uds_delete_url, json_node->valuestring); + } + + } + } + cJSON_Delete(json); + } + + + + + +#ifdef __cplusplus +} +#endif diff --git a/cfg_parse/obs_huaweiyun.cpp b/cfg_parse/obs_huaweiyun.cpp new file mode 100644 index 0000000..ae4ba3f --- /dev/null +++ b/cfg_parse/obs_huaweiyun.cpp @@ -0,0 +1,306 @@ +/** +* @file: $RCSfile: obs_huaweiyun.cpp,v $ +* @brief: $huaweiyun obs include +* +* @version: $Revision: 1.00 $ +* @date: $Date: 2023/09/04 18:34:00 $ +* @author: $Author: wangwei $ +* @state: $State: Exp $ +* +* @latest: $Id: obs_huaweiyun.cpp,v 1.00 2023/09/04 18:34:00 wangwei Exp $ +* +*/ + +using namespace std; + +#include + +#include +#include + +#include "../mms/db_interface.h" +#include "../json/cjson.h"//WW 2023-08-27json +#include "../include/curl/curl.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +char ACCESS_KEY_ID_OBS[2048] = { "J9GS9EA79PZ60OK23LWP" }; +char SECRET_ACCESS_KEY[2048] = { "BirGrAFDSLxU8ow5fffyXgZRAmMRb1R1AdqCI60d" }; +char HOST_NAME[2048] = { "obs.cn-east-3.myhuaweicloud.com" }; +char BUCKET_NAME_OBS[2048] = { "test-8601" }; + +size_t req_reply_device(void* ptr, size_t size, size_t nmemb, void* stream) +{ + //ע͵ԴӡcookieϢ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + //printf(">>>GetDevice in reply %s\n", (char*)ptr); + //GetCJson(ptr); + return size * nmemb; +} + +void SendWebAPI_Test(const string strUrl) +{ + + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + cJSON* json_param = cJSON_CreateObject(); + + cJSON_AddItemToObject(json_root, "code", cJSON_CreateString("putObject")); + cJSON_AddItemToObject(json_root, "param", json_param); + //param + cJSON_AddItemToObject(json_param, "object_name", cJSON_CreateString("comtrade/pq/Device.xml")); + cJSON_AddItemToObject(json_param, "localfile_name", cJSON_CreateString("/FeProject/etc/Device_Config.xml")); + + + char* szjson = cJSON_Print(json_root); + printf(">>>json %s\n", szjson); + //string strjson = szjson; + //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_device); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>TestHuaweiyun Obs Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("Huaweiyun Obs failed res code: " ); + } + else { + printf("Huaweiyun Obs success,string %s",resPost0.c_str()); + } + + curl_slist_free_all(header_list); + free(szjson); + cJSON_Delete(json_root); + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} + +void TestOBS() +{ + SendWebAPI_Test("http://127.0.0.1:8091/powerQuality/PQOBS"); +} + +void SendWebAPI(const string strUrl, char* localpath, char* cloudpath,const char* code) +{ + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + cJSON* json_param = cJSON_CreateObject(); + cJSON_AddItemToObject(json_root, "code", cJSON_CreateString(code)); + cJSON_AddItemToObject(json_root, "param", json_param); + //param + cJSON_AddItemToObject(json_param, "object_name", cJSON_CreateString(cloudpath)); + cJSON_AddItemToObject(json_param, "localfile_name", cJSON_CreateString(localpath)); + + char* szjson = cJSON_Print(json_root); + printf(">>>json %s\n", szjson); + //string strjson = szjson; + //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_device); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>TestHuaweiyun Obs Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("Huaweiyun Obs failed res code: "); + } + else { + printf("Huaweiyun Obs success,string %s", resPost0.c_str()); + } + + curl_slist_free_all(header_list); + free(szjson); + cJSON_Delete(json_root); + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} + +void OBSFile(char* localpath,char* cloudpath,const char* code) +{ + SendWebAPI("http://127.0.0.1:8091/powerQuality/PQOBS",localpath,cloudpath,code); +} + +void SendWebAPI_del(const string strUrl, char* cloudpath, const char* code) +{ + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + cJSON* json_param = cJSON_CreateObject(); + cJSON_AddItemToObject(json_root, "code", cJSON_CreateString(code)); + cJSON_AddItemToObject(json_root, "param", json_param); + //param + cJSON_AddItemToObject(json_param, "object_name", cJSON_CreateString(cloudpath)); + cJSON_AddNullToObject(json_param, "localfile_name"); + //cJSON_AddItemToObject(json_param, "localfile_name", cJSON_CreateString(localpath)); + + char* szjson = cJSON_Print(json_root); + printf(">>>json %s\n", szjson); + //string strjson = szjson; + //char* pszEncodeSecret = curl_easy_escape(curl, strclientsecret.c_str(), strclientsecret.length()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply_device); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>TestHuaweiyun Obs Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("Huaweiyun Obs failed res code: "); + } + else { + printf("Huaweiyun Obs success,string %s", resPost0.c_str()); + } + + curl_slist_free_all(header_list); + free(szjson); + cJSON_Delete(json_root); + } + else + { + printf(">>> token curl init failed"); + } + curl_easy_cleanup(curl); +} + +void OBSFile_del(char* cloudpath, const char* code) +{ + SendWebAPI_del("http://127.0.0.1:8091/powerQuality/PQOBS", cloudpath, code); +} +#ifdef __cplusplus +} +#endif diff --git a/cfg_parse/oss_aliyun.cpp b/cfg_parse/oss_aliyun.cpp new file mode 100644 index 0000000..d62fc12 --- /dev/null +++ b/cfg_parse/oss_aliyun.cpp @@ -0,0 +1,510 @@ +/** +* @file: $RCSfile: oss_aliyun.cpp,v $ +* @brief: $aliyun oss include +* +* @version: $Revision: 1.01 $ +* @date: $Date: 2023/08/31 23:02:00 $ +* @author: $Author: wangwei $ +* @state: $State: Exp $ +* +* @latest: $Id: oss_aliyun.cpp,v 1.01 2023/08/31 23:02:00 wangwei Exp $ +* +*/ + +using namespace std; + +#include "aos_log.h" +#include "aos_util.h" +#include "aos_string.h" +#include "aos_status.h" +#include "oss_auth.h" +#include "oss_util.h" +#include "oss_api.h" +#include "../mms/db_interface.h" +#include + + char* OSS_ENDPOINT; + char* ACCESS_KEY_ID; + char* ACCESS_KEY_SECRET; +char* BUCKET_NAME; + +//const char OSS_ENDPOINT[] = "oss-cn-nanjing.aliyuncs.com"; +//const char ACCESS_KEY_ID[] = "LTAI5tER4bgJxT6Ptie7t2X7"; +//const char ACCESS_KEY_SECRET[] = "dSYIC5hD3flhTNoLMAxCoKjSPdWFSz"; +//const char BUCKET_NAME[] = "cn-pq-test"; +const char OBJECT_NAME[] = "comtrade/temp.json"; + +void init_sample_request_options(oss_request_options_t *options, int is_cname); + +void put_object_from_buffer(); +void put_object_from_buffer_new(char* File_Name, char* data); +void put_object_from_file(); +void put_object_from_file_new(char* File_Name, char* path); +void get_object_to_buffer(); +void get_object_to_file(); +void get_object_to_file_new(char* File_Name, char* savepath); +void delete_object(); +void delete_object_new(char* File_Name); + +void TestOSS() +{ + apr_file_t *output = NULL; + aos_pool_t *pool = NULL; + apr_status_t ret; + + // initialize http io system, call it olny once + /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + printf(">>>TestOSS ini Start"); + if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { + return; + } + + + printf(">>>TestOSS put Start"); + // run samples + //put_object_from_buffer(); + //put_object_from_file(); + put_object_from_buffer(); + get_object_to_file(); + //get_object_to_buffer(); + //get_object_to_file(); + //delete_object(); + printf(">>>TestOSS put End"); + + + // deinitialize http io system, call it olny once + aos_http_io_deinitialize(); + + return ; +} + +void PutOSS(char* File_Name,char* data) //zw޸ 2023-9-7 ossļ +{ + apr_file_t* output = NULL; + aos_pool_t* pool = NULL; + apr_status_t ret; + + // initialize http io system, call it olny once + /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + printf(">>>PutOSS ini Start"); + printf(File_Name); + printf(data); + if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { + return; + } + + + printf(">>>PutOSS put Start"); + + put_object_from_file_new(File_Name, data);//ʹbufferļ + + printf(">>>PutOSS put End"); + + + // deinitialize http io system, call it olny once + aos_http_io_deinitialize(); + + return; +} + +void GetOSS(char* File_Name,char* savepath) //zw޸ 2023-9-7 ȡossļ +{ + apr_file_t* output = NULL; + aos_pool_t* pool = NULL; + apr_status_t ret; + + // initialize http io system, call it olny once + /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + printf(">>>GetOSS ini Start"); + if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { + return; + } + + + printf(">>>GetOSS put Start"); + + get_object_to_file_new(File_Name,savepath);//ʹbufferļ + + printf(">>>GetOSS put End"); + + + // deinitialize http io system, call it olny once + aos_http_io_deinitialize(); + + return; +} + +void DelOSS(char* File_Name) +{ + apr_file_t* output = NULL; + aos_pool_t* pool = NULL; + apr_status_t ret; + + // initialize http io system, call it olny once + /* ڳڵaos_http_io_initializeʼ硢ڴȫԴ*/ + printf(">>>DelOSS ini Start"); + if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { + return; + } + + + printf(">>>DelOSS put Start"); + delete_object_new(File_Name);//ʹbufferļ + + printf(">>>DelOSS put End"); + + + // deinitialize http io system, call it olny once + aos_http_io_deinitialize(); + + return; +} + +void coutTest() { + std:: cout << "OSS_ENDPOINT:" << OSS_ENDPOINT << std::endl; + std::cout << "ACCESS_KEY_ID:" << ACCESS_KEY_ID << std::endl; + std::cout << "ACCESS_KEY_SECRET:" << ACCESS_KEY_SECRET << std::endl; + std::cout << "BUCKET_NAME:" << BUCKET_NAME << std::endl; + +} + +void init_sample_request_options(oss_request_options_t *options, int is_cname) +{ + options->config = oss_config_create(options->pool); + aos_str_set(&options->config->endpoint, OSS_ENDPOINT); + aos_str_set(&options->config->access_key_id, ACCESS_KEY_ID); + aos_str_set(&options->config->access_key_secret, ACCESS_KEY_SECRET); + options->config->is_cname = is_cname; + + options->ctl = aos_http_controller_create(options->pool, 0); +} + +void put_object_from_buffer() +{ + aos_pool_t *p = NULL; + aos_string_t bucket; + aos_string_t object; + int is_cname = 0; + aos_table_t *headers = NULL; + aos_table_t *resp_headers = NULL; + oss_request_options_t *options = NULL; + aos_list_t buffer; + aos_buf_t *content = NULL; + char *str = "test oss c sdk"; + aos_status_t *s = NULL; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + headers = aos_table_make(p, 1); + apr_table_set(headers, "x-oss-meta-author", "oss"); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, OBJECT_NAME); + + aos_list_init(&buffer); + content = aos_buf_pack(options->pool, str, strlen(str)); + aos_list_add_tail(&content->node, &buffer); + + s = oss_put_object_from_buffer(options, &bucket, &object, + &buffer, headers, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("put object from buffer succeeded\n"); + } + else { + printf("put object from buffer failed\n"); + } + + aos_pool_destroy(p); +} + +void put_object_from_buffer_new(char* File_Name,char* data)//zw޸ 2023-9-7 oss +{ + aos_pool_t* p = NULL; + aos_string_t bucket; + aos_string_t object; + int is_cname = 0; + aos_table_t* headers = NULL; + aos_table_t* resp_headers = NULL; + oss_request_options_t* options = NULL; + aos_list_t buffer; + aos_buf_t* content = NULL; + char* str = data; + aos_status_t* s = NULL; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + headers = aos_table_make(p, 1); + apr_table_set(headers, "x-oss-meta-author", "oss"); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, File_Name); + + aos_list_init(&buffer); + content = aos_buf_pack(options->pool, str, strlen(str)); + aos_list_add_tail(&content->node, &buffer); + + s = oss_put_object_from_buffer(options, &bucket, &object, + &buffer, headers, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("put object from buffer succeeded\n"); + } + else { + printf("put object from buffer failed\n"); + } + + aos_pool_destroy(p); +} + +void put_object_from_file() +{ + aos_pool_t *p = NULL; + aos_string_t bucket; + aos_string_t object; + /* ǷʹCNAME0ʾʹá*/ + int is_cname = 0; + aos_table_t *headers = NULL; + aos_table_t *resp_headers = NULL; + oss_request_options_t *options = NULL; + char *filename = "/home/pq/FeProject/etc/Device_Config.xml"; + aos_status_t *s = NULL; + aos_string_t file; + + /* ڴڴأpoolȼapr_pool_tʵִaprС*/ + aos_pool_create(&p, NULL); + /* ʼoptionsòendpointaccess_key_idacces_key_secretis_cnamecurlȫϢ*/ + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, OBJECT_NAME); + aos_str_set(&file, filename); + + s = oss_put_object_from_file(options, &bucket, &object, &file, + headers, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("put object from file succeeded\n"); + } + else { + printf("put object from file failed, code:%d, error_code:%s, error_msg:%s, request_id:%s\n", + s->code, s->error_code, s->error_msg, s->req_id); + } + + aos_pool_destroy(p); +} + +void put_object_from_file_new(char* File_Name, char* path) +{ + aos_pool_t* p = NULL; + aos_string_t bucket; + aos_string_t object; + /* ǷʹCNAME0ʾʹá*/ + int is_cname = 0; + aos_table_t* headers = NULL; + aos_table_t* resp_headers = NULL; + oss_request_options_t* options = NULL; + char* filename = path; + aos_status_t* s = NULL; + aos_string_t file; + + /* ڴڴأpoolȼapr_pool_tʵִaprС*/ + aos_pool_create(&p, NULL); + /* ʼoptionsòendpointaccess_key_idacces_key_secretis_cnamecurlȫϢ*/ + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, File_Name); + aos_str_set(&file, filename); + + s = oss_put_object_from_file(options, &bucket, &object, &file, + headers, &resp_headers); + if (aos_status_is_ok(s)) { + printf("put object from file succeeded\n"); + } + else { + printf("put object from file failed, code:%d, error_code:%s, error_msg:%s, request_id:%s\n", + s->code, s->error_code, s->error_msg, s->req_id); + } + + + aos_pool_destroy(p); +} + +void get_object_to_buffer() +{ + aos_pool_t *p = NULL; + aos_string_t bucket; + aos_string_t object; + int is_cname = 0; + oss_request_options_t *options = NULL; + aos_table_t *headers = NULL; + aos_table_t *params = NULL; + aos_table_t *resp_headers = NULL; + aos_status_t *s = NULL; + aos_list_t buffer; + aos_buf_t *content = NULL; + char *buf = NULL; + int64_t len = 0; + int64_t size = 0; + int64_t pos = 0; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, OBJECT_NAME); + aos_list_init(&buffer); + + s = oss_get_object_to_buffer(options, &bucket, &object, + headers, params, &buffer, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("get object to buffer succeeded\n"); + } + else { + printf("get object to buffer failed\n"); + } + + //get buffer len + aos_list_for_each_entry(aos_buf_t, content, &buffer, node) { + len += aos_buf_size(content); + } + + buf = (char*)aos_pcalloc(p, (apr_size_t)(len + 1)); + buf[len] = '\0'; + + //copy buffer content to memory + aos_list_for_each_entry(aos_buf_t, content, &buffer, node) { + size = aos_buf_size(content); + memcpy(buf + pos, content->pos, (size_t)size); + pos += size; + } + + aos_pool_destroy(p); +} + +void get_object_to_file() +{ + aos_pool_t *p = NULL; + aos_string_t bucket; + char *download_filename = "Data/tempbuff.jpg"; + aos_string_t object; + int is_cname = 0; + oss_request_options_t *options = NULL; + aos_table_t *headers = NULL; + aos_table_t *params = NULL; + aos_table_t *resp_headers = NULL; + aos_status_t *s = NULL; + aos_string_t file; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, OBJECT_NAME); + headers = aos_table_make(p, 0); + aos_str_set(&file, download_filename); + + s = oss_get_object_to_file(options, &bucket, &object, headers, + params, &file, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("get object to local file succeeded\n"); + } + else { + printf("get object to local file failed\n"); + } + + aos_pool_destroy(p); +} + +void get_object_to_file_new(char* File_Name,char* savepath) +{ + aos_pool_t* p = NULL; + aos_string_t bucket; + char* download_filename = savepath; + aos_string_t object; + int is_cname = 0; + oss_request_options_t* options = NULL; + aos_table_t* headers = NULL; + aos_table_t* params = NULL; + aos_table_t* resp_headers = NULL; + aos_status_t* s = NULL; + aos_string_t file; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, File_Name); + headers = aos_table_make(p, 0); + aos_str_set(&file, download_filename); + + s = oss_get_object_to_file(options, &bucket, &object, headers, + params, &file, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("get object to local file succeeded\n"); + } + else { + printf("get object to local file failed\n"); + } + + aos_pool_destroy(p); +} + +void delete_object() +{ + aos_pool_t *p = NULL; + aos_string_t bucket; + aos_string_t object; + int is_cname = 0; + oss_request_options_t *options = NULL; + aos_table_t *resp_headers = NULL; + aos_status_t *s = NULL; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, OBJECT_NAME); + + s = oss_delete_object(options, &bucket, &object, &resp_headers); + + if (aos_status_is_ok(s)) { + printf("delete object succeed\n"); + } + else { + printf("delete object failed\n"); + } + + aos_pool_destroy(p); +} + +void delete_object_new(char* File_Name) +{ + aos_pool_t* p = NULL; + aos_string_t bucket; + aos_string_t object; + int is_cname = 0; + oss_request_options_t* options = NULL; + aos_status_t* s = NULL; + + aos_pool_create(&p, NULL); + options = oss_request_options_create(p); + init_sample_request_options(options, is_cname); + aos_str_set(&bucket, BUCKET_NAME); + aos_str_set(&object, File_Name); + + s = oss_delete_objects_by_prefix(options, &bucket, &object); + + if (aos_status_is_ok(s)) { + printf("delete object succeed\n"); + } + else { + printf("delete object failed\n"); + } + + aos_pool_destroy(p); +} diff --git a/cfg_parse/uds_huaweiyun.cpp b/cfg_parse/uds_huaweiyun.cpp new file mode 100644 index 0000000..4974d06 --- /dev/null +++ b/cfg_parse/uds_huaweiyun.cpp @@ -0,0 +1,319 @@ +/** +* @file: $RCSfile: uds_huaweiyun.cpp,v $ +* @brief: $uds_huaweiyun include +* +* @version: $Revision: 1.00 $ +* @date: $Date: 2023/10/24 18:34:00 $ +* @author: $Author: caizhouyu $ +* @state: $State: Exp $ +* +* @latest: $Id: uds_huaweiyun.cpp,v 1.00 2023/10/24 18:34:00 caizhouyu Exp $ +* +*/ + +using namespace std; + +#include + +#include +#include + +#include "../mms/db_interface.h" +#include "../json/cjson.h"//WW 2023-08-27json +#include "../include/curl/curl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + + + size_t req_reply(void* ptr, size_t size, size_t nmemb, void* stream) + { + //ע͵ԴӡcookieϢ + string* str = (string*)stream; + (*str).append((char*)ptr, size * nmemb); + //printf(">>>GetDevice in reply %s\n", (char*)ptr); + //GetCJson(ptr); + return size * nmemb; + } + + /** + * @brief Get_Uuid json,õuuid + * @param ptr + * @param uuid ݴС + * @return int 0ɹ -1Ч + * ע⣺ݵĴС44ı + */ + int Get_Uuid(const char* ptr, char* uuid,char* filename) { + int result = 0; + //cout << ">>>GetDevice in reply" << (char*)ptr; + cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json_code; + cJSON* json_data; + cJSON* json_msg; + + + if (json) { + json_code = cJSON_GetObjectItem(json, "code"); //ȡsuccess + json_msg = cJSON_GetObjectItem(json, "msg"); //ȡsuccess + json_data = cJSON_GetObjectItem(json, "data"); //ȡdata + if (json_code && json_code->type == cJSON_Number && json_code->valueint==0) { + printf("upload uds success\n"); + cJSON* json_uuid; + cJSON* json_filename; + json_uuid = cJSON_GetObjectItem(json_data, "storeId"); //ȡdata + if (json_uuid && json_uuid->type == cJSON_String) { + strcpy(uuid, json_uuid->valuestring); + printf("read uds uuid success:%s\n", uuid); + } + json_filename = cJSON_GetObjectItem(json_data, "fileName"); //ȡdata + if (json_filename && json_filename->type == cJSON_String) { + strcpy(filename, json_filename->valuestring); + printf("read uds filename success:%s\n", filename); + } + result = 1; + } + else if (json_msg && json_msg->valuestring != NULL) + { + printf("uuid get falie msg: %s\n", json_msg->valuestring); + result = 0; + } + else + { + printf("get uds uuid error :do not get msg\n"); + result = 0; + } + } + else { + printf("get uds uuid error:do not get json and %s\n", cJSON_GetErrorPtr()); + result = 0; + } + cJSON_Delete(json); + return result; + } + + // ֽдļ + void Write_Byte_Array_To_File(char* local_path, char* data_array, long size) { + // ֽдļ + FILE* outFile = fopen(local_path, "wb"); + if (outFile != NULL) { + fwrite(data_array, sizeof(char), size, outFile); + fclose(outFile); + printf("File saved successfully.\n"); + } + else { + printf("Failed to open file for writing\n"); + } + } + + void Save_File(const char* ptr, char* local_path) { + //cout << ">>>GetDevice in reply" << (char*)ptr; + cJSON* json = cJSON_Parse((char*)ptr); //jsonʽл + cJSON* json_success; + cJSON* json_data; + cJSON* json_msg; + if (json) { + json_success = cJSON_GetObjectItem(json, "sucess"); //ȡsuccess + json_msg = cJSON_GetObjectItem(json, "msg"); //ȡsuccess + json_data = cJSON_GetObjectItem(json, "data"); //ȡdata + if (json_success && json_success->type == cJSON_True) { + printf("save uds file success\n"); + if (json_data && json_data->type == cJSON_String) { + // ַ + long decodedLen = strlen(json_data->valuestring) * 3 / 4; + char* decodedStr = (char*)malloc(decodedLen + 1); + // Base64 + int success = base64_decode(json_data->valuestring, strlen(json_data->valuestring), decodedStr, &decodedLen); + Write_Byte_Array_To_File(local_path, decodedStr, decodedLen); + free(decodedStr); + } + } + else if (json_msg && json_msg->valuestring != NULL) + { + printf("save uds file falie msg: %s\n", json_msg->valuestring); + } + else + { + printf("save uds file error :do not get msg\n"); + } + } + else { + printf("save uds file error:do not get json and %s\n", cJSON_GetErrorPtr()); + + } + cJSON_Delete(json); + } + + int WebAPI_Uds_Upload(char* strUrl, char* loacl_path, char* uuid,char* filename) + { + int result = 0; + printf("loaclpath: %s\n", loacl_path); + /*char json_buf[] = "{\"code\":0,\"msg\":\"success\",\"data\":\"0903d01092381283918391312131awe\",\"encrypt_data\":null,\"other\":null,\"sucess\":true}"; + Get_Uuid(json_buf, uuid); + printf("loaclpath: %s\n", uuid);*/ + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + //Content-TypeΪmultipart/form-data + header_list = curl_slist_append(header_list, "Content-Type: multipart/form-data"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl); + //postIJ + + + struct curl_httppost* formpost = NULL; + struct curl_httppost* lastptr = NULL; + // form-dataֶ + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_FILE, loacl_path, CURLFORM_END); + //curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "password", CURLFORM_COPYCONTENTS, "secretpassword", CURLFORM_END); + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>uds upload Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("uds upload failed res code: "); + result = 0; + } + else { + printf("uds upload success,string %s", resPost0.c_str()); + //webapiֵж + result=Get_Uuid(resPost0.c_str(), uuid,filename); + } + // ͷԴ + curl_slist_free_all(header_list); + curl_formfree(formpost); + } + else + { + printf(">>> uds upload init failed"); + result = 0; + + } + + curl_easy_cleanup(curl); + return result; + } + + void WebAPI_Uds_Download(char* strUrl, char* uuid, char* local_path,char* filename) + { + //const char json_buf[] = "{\"code\":0,\"msg\":\"success\",\"data\":\"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCASHBBIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+2iiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA9J8CEf6SM846fjXo9eE6Hqsml3iSAnymYCROxzxkjvgfj6EV7LZapaXyBopVz3UsAQfTBOf8g9xQBo0U3en95f8Avof40b0/vL/30P8AGgB1FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABXPeJiP7Kn5Hbv71utNEud0sYx1y6jtnuR2rynxNrpv1ksLNztLc8+hxknpjjGCeCwIPTIBxA6D6ClpACoCnqAAe/I4PP1paACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAp6ySIQVkdSOhVmUj6EEYplFAE/wBquf8An4n/AO/0n/xVH2q5/wCfif8A7/Sf/FVBRQBN9ouP+e83/f1//iqPtFx/z3m/7+v/APFVDRQBN9ouP+e83/f1/wD4qj7Rcf8APeb/AL+v/wDFVDRQBN9ouP8AnvN/39f/AOKo+0XH/Peb/v6//wAVUNFAE32i4/57zf8Af1//AIqj7Rcf895v+/r/APxVQ0UATfaLj/nvN/39f/4qj7Rcf895v+/r/wDxVQ0UATfaLj/nvN/39f8A+Ko+0XH/AD3m/wC/r/8AxVQ0UATfaLj/AJ7zf9/X/wDiqPtFx/z3m/7+v/8AFVDRQBN9ouP+e83/AH9f/wCKo+0XH/Peb/v6/wD8VUNFAE32i4/57zf9/X/+Ko+0XH/Peb/v6/8A8VUNFAE32i4/57zf9/X/APiqPtFx/wA95v8Av6//AMVUNFAEpnnbrNKfrI5/maj3NnO45HQ5OfzpKKADr1ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACilwcbsHb6446469OvH1puRzyOOuOaALfkJ6t+Y/wo8hPVvzH+FUjcEHBZv++m/wpPtJ/vN/303+FAF7yE9W/Mf4UeQnq35j/CqP2k/3m/76b/Cj7Sf7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P1+0W5guLP5DLIhu1IJ6kZGD0wen5dmP9oSmnKuqjpSm1rZt3jpZyl/Ja122l6I/q3hHBZZiFCeBoKlGcKbb0d+WLf2qcb6Ss7pLXXXR/JFnaS6XqmreEWSaa2Mf+iC6hBWGIRyRSAQyb44RJ/HtGCfvcjNegfCPw14V8Barpeq6d4QtNPthrejS64YoY9uqOLjzHZnVAVYk884J61ufEvQvEHguz0PxDrdvb3Gtf2SU1xoFBR3jkMTmIgHJBzgg8gcda89/4TyPTdNfTizpZa3d6dPbu4y9qwG7CuQSoBJwADg8HOTXCszzGk172lNx051tC2zvfVW1s2faVsryuKqKUYXtNNNbvqttd0tF17tH+jt8APGnwy1T4V/C2PwXe6Ppmm+IfC+lXmk6LaKqOJHs7aS4tYIY1VJGtp3e2dEVAht2OOcD6TCAL5bHcBwScjOD16kj6Z9q/jf/AOCUPxf8VX/7SPwV0/WfFFzL4fj0DWNLtLPUdUufskf2Oy1ZbfZDPNNbxuJrYMTHDG20qp4HH9jKzbwGVwwcBgRypDDcCpxggg5BGMiv07IcypY/Dy9nTVKVKNP2i9oqjlOakt1GNuXktbW116v+eOKMmqZLmXLKv7WOLpRrwfLyct5TvCynJO3MmmuV2dnFWMq6sDLPE+3OxicgDqeMEdB2OSeeoIr8of8AgqVqLR/D7SNBjckyXI1IqGIbBJstoGcBck8E/ez3ya/XZWwwbrg56/15r8Uv+CkOorqetyWTPlNLsIVZecc3XnMMDJHBJz17cYr26nT5/oLhhOebUb621/8AJo3s16dz2H9hdNv7P2iowIxf6htBJ4+ewb/0HJ/+vivslQAoA6YFfJn7F6iP4KaUuNq/2pqWBz0+zWDD1PUZr6zXoPoP5VmcvE//ACPcX/ipr5q916q6uhaKKKDxgooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArz34u/8iDrf/XH/ANmSvQq89+Lv/Ig63/1x/wDZ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wX4nnNnpW6yL6LeH7Sd2chjnnOcOMEgjBB5r428Z/BD4n+KPCF/a/wDCvvGkF6TljJomrA/6WCbv7KfsYPy54+pOMkV/Y1RXMvDDALX+0sS3dP8AhLW1nZ/vurWpp/rbiWrexltb/ePK2q9jr59+p/Bdov7On7QcWpppupfDPxbremCR0TVLnwprHnrFkbYkdrVWuijAj74ZQyAOVCqv1h+zn8HvjR4XvPFvhvxH4C8bSW2rKuoW1wPCeqW1vFHCXVUdJoxuZY2UHBHBzx0r+yGivSwvAmHwlnSx0ns3zYa7fK9Hf6xe9tHe9+vZ8tDiTE0Zubg53/6euL+/2cr+d1q+y0P4y/iv+y18R9blupI/hv4ruG+cjydAvQVILYBDICecnOASODjpXinw1+DXx/8Ah5450S90r4c+PrSOHVbRZJYvDOtRReWjsVG+O0ZHL425EgUgncclcf3P0V70cgoxt+9va2vslfT/ALiaGsuKMRJSUqF+ZNP99prbo6TW6XbZdj8+f2u4vHPiv9m74caZHoF3qviTxDZ6Kus2MIkujZFbb/TdysRglgc5HJ6etfNf7LnwG+O/hz4gaFqnhq1vvA/hvSbxBeh8D7ZabSDZfYmPS8Oe3IyMjGK/ZvJIAJJA4AzwB6D0pU+8Px/ka7auWwrKkp1H+6TStG17uP8AedrKNlvv5H2fDfivi+GuG824dweQ5ZiXnEa1Kvjsfy4mVKlWSThRoPDx5XpeUvb3m409I8nvBMpCNMxebaFkds5Z14JIPQ7snHXnmm1JJ2/H+lR16KVkl2Vj8iqO9abfWVN/epBRRRTKCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigB25j1Yn6kn/APV+FNoop3fd/ewWl7aX3tpf1CiiikAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUVrGV9Hv0ff/g/n67gUUUVkAUUUUAFFFFABRRRQAUUUUAFOT7w/H+RptFA07NPs7hRRRQLrf0/C/wDmFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR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SxSlzKS+GmrW5fJ7qV/l5nFS4FySs5SeElBJp255NNS10slpo7fI/pr/AOIhr4cD/m1zx4T6/wDCyNBAP4f8I3j9K7jwt/wX5+C2t3kcGvfA3x74U0/CfadUk8RafrEdqrZG4wWeixPKBjI+ZMjp0r+WD7Gv939T/wDFVILckBTyowADgjH4k15y41z1yX+22Te3LF9VpuvP8NDb/iH2RyaXsJLmdubmmrXsr2621drrtfqv9CP4MfHz4XfH7wpZeMPhf4s0zxFpl3bxzSwW1xE19YO/DQ3tsGMkTo/yk4K5KjIY7R7QQQSDwQcEehFfyBf8Eb/it4g8DftMaZ4Gj1S6h8P/ABH0+fTLnTjNIYGudOtrzVIrqFTtMEsUVvPt8s+UXZZXjZ443H9gn0z+PJ/E8ZP4Cv2HhjNp5tgI1Ksozq0o041JQVk5SjLf3pK/u30turo/JeK8hXD+aVMLCU5UZuU6TmtVH3W0n1iuZJO7e6ewUUUV9IfMBRRRQAUUUUAFFFFABRVa7u7ewge7vJPItIRuuLgjKwqejMMjOTkYyOlYPg/xn4Y8faJH4j8IatBrejS3NzZpqFp81q11ZsqXUCSgkPJAzqsoGNhZQevAB09FFFABRRRQAUUUUAFFFFABRWTrmu6P4a0u81vXtQt9M0qwhee7vLqRY4oYo1LOxLEZIUE7QegJOFBIXQNc0jxRo1l4g0HUbTU9I1GMzWN5azxyx3EHGJFKMwGTuG3J+7wTkUAatFFFABRRRQAUUUUAFFFFABRXEXPxO+HNl43svhvd+LLODxvqNol7YaDIgW4uYCN0zRu0yqTChRmH8QkXGBzXallHf+dADqKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/NpGjwg5Ab/P/AavyaNF8o2HnOB82e3tmur/ALNb1b9P8KuNpWSpCtgHnk+o69/881/GVPHS1vFrR/Ya+y/L+vmf3HUytKK91y1WnK10fk166Hcfs7ab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rKQfSpaKAI4oYoI0hgjjhijUJHFEipGiqAFVUUBVUAAAAAADFSUUUAFJgZJ7nGfw6UtFABRRRQBn/wBmWP2v7b9jsvtWP+Pv7Hb/AGzP/Xzs34xxjGfetD9f8+1FFADDGjdR7ZHWq8lsrqyMFkRwVdJACrKeqspyGU9CCOat0UAVYLK1tgBBbW0AHAEMCRjj0CBQPwFWgMen4DFFFAFWaOOdJIZo0mifIeKVVkjcZzhkcFWGQDggjIB7UkcccKJFCiRRxjCRxKI40HoqIAqjnoABUjdT9T/OkoAsUUUUAIABkgYycn3OAMn8AB9BS0UUAFGAeozRRQAmB6D8hS0UUAFFFFAB/n86CAeDRRQAYHHsMD6f5FIABnAxk5P1PelooAQqCQSMkcj2/wA4oIB6/wCen+ApaKACkIB6ilooAKKKKAGd3+g/ka4Tx7/x52f/AF2f/wBBWu77v9B/I1wnj3/jzs/+uz/+grQB5bRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABSgkEEDJBBx9D9R/OkpQCSADgkgZ+p+h/lQB6P4DB23jgnGARknHBA6cY7+vr3xXow5CnPT9T0/n/X1ryHwfqAt7l7b7qycfXJJ6k+xxyO3bNeuqcKg65A5684yeee/9fSgB9FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFV6sVEyY5HT09P6mgBlSquOT1/l1/OhVxyev8uv50+gAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK4Hx7/AMedn/12f/0EV31eR+MdRF5KYYzmK1wg95Cw3nqR2x68YPQUAcXRSL0H0H8qWgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo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F0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k/Mf/ABdHP95PzH/xdAHA/wDCEXf/AEHL/wDNP/jNH/CEXf8A0HL/APNP/jNd9z/eT8x/8XRz/eT8x/8AF0AcD/whF3/0HL/80/8AjNH/AAhF3/0HL/8ANP8A4zXfc/3k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uxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr1yuxPf8AL/7KjYnv+X/2VAHVf2xb+/5f/Xo/ti39/wAv/r1yuxPf8v8A7KjYnv8Al/8AZUAdV/bFv7/l/wDXo/ti39/y/wDr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wHi/+IoA/wAtT/h2D+3x/wBGyfE3/wAJjX//AJUUf8Owf2+P+jZPib/4TGv/APyor/Ur+w2X/Pna/wDgPF/8RR9hsv8Anztf/AeL/wCIoA/y1P8Ah2D+3x/0bJ8Tf/CY1/8A+VFH/DsH9vj/AKNk+Jv/AITGv/8Ayor/AFK/sNl/z52v/gPF/wDEUfYbL/nztf8AwHi/+IoA/wAtT/h2D+3x/wBGyfE3/wAJjX//AJUUf8Owf2+P+jZPib/4TGv/APyor/Ur+w2X/Pna/wDgPF/8RR9hsv8Anztf/AeL/wCIoA/y1P8Ah2D+3x/0bJ8Tf/CY1/8A+VFH/DsH9vj/AKNk+Jv/AITGv/8Ayor/AFK/sNl/z52v/gPF/wDEUfYbL/nztf8AwHi/+IoA/wAtT/h2D+3x/wBGyfE3/wAJjX//AJUUf8Owf2+P+jZPib/4TGv/APyor/Ur+w2X/Pna/wDgPF/8RR9hsv8Anztf/AeL/wCIoA/y1P8Ah2D+3x/0bJ8Tf/CY1/8A+VFH/DsH9vj/AKNk+Jv/AITGv/8Ayor/AFK/sNl/z52v/gPF/wDEUfYbL/nztf8AwHi/+IoA/wAtT/h2D+3x/wBGyfE3/wAJjX//AJUUf8Owf2+P+jZPib/4TGv/APyor/Ur+w2X/Pna/wDgPF/8RR9hsv8Anztf/AeL/wCIoA/y1P8Ah2D+3x/0bJ8Tf/CY1/8A+VFH/DsH9vj/AKNk+Jv/AITGv/8Ayor/AFK/sNl/z52v/gPF/wDEUfYbL/nztf8AwHi/+IoA/wAtT/h2D+3x/wBGyfE3/wAJjX//AJUUf8Owf2+P+jZPib/4TGv/APyor/Ur+w2X/Pna/wDgPF/8RR9hsv8Anztf/AeL/wCIoA/y1P8Ah2D+3x/0bJ8Tf/CY1/8A+VFH/DsH9vj/AKNk+Jv/AITGv/8Ayor/AFK/sNl/z52v/gPF/wDEUfYbL/nztf8AwHi/+IoA/wAtT/h2D+3x/wBGyfE3/wAJjX//AJUUf8Owf2+P+jZPib/4TGv/APyor/Ur+w2X/Pna/wDgPF/8RR9hsv8Anztf/AeL/wCIoA/y1P8Ah2D+3x/0bJ8Tf/CY1/8A+VFf0of8G9f/AATU/aN/Z5+Mnj39pD47eFtU+G+lzeAtQ+H2h+EPEFrJaavrcut6rp2oTao1s06vBBYro1uYmubPcxuXjjcEyCv62/sNl/z52v8A4Dxf/EVZVVQBUVVUdFUBQPoBgCgABBGRwO1LRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB/9n7LkULAAAAAMmgYjTsXjQVGow4AIccHXk=\",\"encrypt_data\":null,\"other\":null,\"sucess\":true}"; + //Save_File1(json_buf, local_path); + // curlʼ + CURL* curl = curl_easy_init(); + // curlֵ + CURLcode res; + if (curl) + { + //curlͷ + struct curl_slist* header_list = NULL; + header_list = curl_slist_append(header_list, "Content-Type:application/json;"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + + //Ӧͷ0 1 + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + //Ϊpost + curl_easy_setopt(curl, CURLOPT_POST, 1); + + //URLַ + curl_easy_setopt(curl, CURLOPT_URL, strUrl); + //postIJ + cJSON* json_root = cJSON_CreateObject(); + cJSON_AddItemToObject(json_root, "isWrap", cJSON_CreateString("1")); + cJSON_AddItemToObject(json_root, "storeId", cJSON_CreateString(uuid)); + cJSON_AddItemToObject(json_root, "filename", cJSON_CreateString(filename)); + char* szjson = cJSON_Print(json_root); + printf(">>>json %s\n", szjson); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szjson); + + //ssl֤ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + + //CURLOPT_VERBOSEֵΪ1ʱʾϸĵϢ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + + //ݽպд뺯 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); + + + string resPost0; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&resPost0); + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + + //óʱʱ + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); + + printf(">>>uds download Post in curl post\n"); + // post + res = curl_easy_perform(curl); + // Ƿɹ + if (res != CURLE_OK) { + printf("uds download failed res code: "); + } + else { + printf("uds download success,string %s", resPost0.c_str()); + //webapiֵж + Save_File(resPost0.c_str(), local_path); + } + curl_slist_free_all(header_list); + free(szjson); + cJSON_Delete(json_root); + } + else + { + printf(">>> uds download init failed"); + } + curl_easy_cleanup(curl); + } + + +#ifdef __cplusplus +} +#endif diff --git a/fe_common.pri b/fe_common.pri new file mode 100644 index 0000000..bef10bc --- /dev/null +++ b/fe_common.pri @@ -0,0 +1,47 @@ +###################################################################### +# common config for project +###################################################################### + +DEPENDPATH += . + +CONFIG += debug_and_release +CONFIG += warn_off +CONFIG -= warn_on + +CONFIG(debug, debug|release) { + TARGET = $$join(TARGET,,,d) + QMAKE_CXXFLAGS_DEBUG += -DDEBUG +} + +unix { + QMAKE_CXXFLAGS_WARN_ON = -Wall + QMAKE_CXXFLAGS_WARN_OFF = -w + LIBS += -lrt -ldl + OS_VERSION = $$system(uname -a) + contains(OS_VERSION, SunOS) { + #QMAKE_CXXFLAGS +=-D_POSIX_PTHREAD_SEMANTICS + LIBS += -lsocket -lnsl + } + contains(QMAKE_CXXFLAGS, -m64) { + DEFINES +=FE_VERSION_64 + } +} + +win32 { + DEFINES -= UNICODE + QMAKE_INCDIR = $(QTDIR)/include + QMAKE_INCDIR_QT = $(QTDIR)/include + QMAKE_LIBDIR_QT = $(QTDIR)/lib + QMAKE_LFLAGS_RELEASE = /INCREMENTAL:no + QMAKE_LFLAGS_DEBUG += /INCREMENTAL:no + QMAKE_LFLAGS += /MACHINE:X86 + QMAKE_MOC = $$(QTDIR)/bin/moc.exe + QMAKE_RCC = $$(QTDIR)/bin/rcc.exe + QMAKE_UIC = $$(QTDIR)/bin/uic.exe + QMAKE_IDC = $$(QTDIR)/bin/idc.exe + CONFIG -= warn_on + INCLUDEPATH +=$(QTDIR)/mkspecs/win32-msvc2010 + QMAKE_CXXFLAGS +=-DWIN32_LEAN_AND_MEAN + #for remove ACE warning + DEFINES += _CRT_SECURE_NO_DEPRECATE _M_IX86 WIN32 +} diff --git a/include/CVS/Entries b/include/CVS/Entries new file mode 100644 index 0000000..b22976a --- /dev/null +++ b/include/CVS/Entries @@ -0,0 +1,15 @@ +D/apr//// +D/apr-linux//// +D/mmslite//// +/IEC60870DEF.h/1.1/Sat Nov 24 06:54:49 2018// +/ied.h/1.1/Sat Nov 24 06:54:49 2018// +/initools.h/1.1/Sat Nov 24 06:54:49 2018// +/node.h/1.1/Sat Nov 24 06:54:49 2018// +/platform.h/1.1/Sat Nov 24 06:54:50 2018// +/sasstd.h/1.1/Sat Nov 24 06:54:50 2018// +/sasstr.h/1.1/Sat Nov 24 06:54:50 2018// +/sastime.h/1.1/Sat Nov 24 06:54:50 2018// +/utf.h/1.1/Sat Nov 24 06:54:50 2018// +/xmltools.h/1.1/Sat Nov 24 06:54:50 2018// +/sas_system.h/1.2/Thu Dec 20 01:06:15 2018// +/systrace.h/1.2/Wed Apr 17 01:23:51 2019// diff --git a/include/CVS/Entries.Extra b/include/CVS/Entries.Extra new file mode 100644 index 0000000..55c1852 --- /dev/null +++ b/include/CVS/Entries.Extra @@ -0,0 +1,15 @@ +D/apr//////// +D/apr-linux//////// +D/mmslite//////// +/IEC60870DEF.h////*//// +/ied.h////*//// +/initools.h////*//// +/node.h////*//// +/platform.h////*//// +/sasstd.h////*//// +/sasstr.h////*//// +/sastime.h////*//// +/utf.h////*//// +/xmltools.h////*//// +/sas_system.h////*//// +/systrace.h////*//// diff --git a/include/CVS/Entries.Extra.Old b/include/CVS/Entries.Extra.Old new file mode 100644 index 0000000..7531d5f --- /dev/null +++ b/include/CVS/Entries.Extra.Old @@ -0,0 +1,16 @@ +D/apr//////// +D/apr-linux//////// +D/mmslite//////// +/IEC60870DEF.h////*//// +/ied.h////*//// +/initools.h////*//// +/node.h////*//// +/platform.h////*//// +/sasstd.h////*//// +/sasstr.h////*//// +/sastime.h////*//// +/utf.h////*//// +/xmltools.h////*//// +/sas_system.h////*//// +/systrace.h////*//// +D/otl//////// diff --git a/include/CVS/Entries.Old b/include/CVS/Entries.Old new file mode 100644 index 0000000..ed7ca2d --- /dev/null +++ b/include/CVS/Entries.Old @@ -0,0 +1,16 @@ +D/apr//// +D/apr-linux//// +D/mmslite//// +/IEC60870DEF.h/1.1/Sat Nov 24 06:54:49 2018// +/ied.h/1.1/Sat Nov 24 06:54:49 2018// +/initools.h/1.1/Sat Nov 24 06:54:49 2018// +/node.h/1.1/Sat Nov 24 06:54:49 2018// +/platform.h/1.1/Sat Nov 24 06:54:50 2018// +/sasstd.h/1.1/Sat Nov 24 06:54:50 2018// +/sasstr.h/1.1/Sat Nov 24 06:54:50 2018// +/sastime.h/1.1/Sat Nov 24 06:54:50 2018// +/utf.h/1.1/Sat Nov 24 06:54:50 2018// +/xmltools.h/1.1/Sat Nov 24 06:54:50 2018// +/sas_system.h/1.2/Thu Dec 20 01:06:15 2018// +/systrace.h/1.2/Wed Apr 17 01:23:51 2019// +D/otl//// diff --git a/include/CVS/Repository b/include/CVS/Repository new file mode 100644 index 0000000..30c6d14 --- /dev/null +++ b/include/CVS/Repository @@ -0,0 +1 @@ +jspqfe/src/pt61850netd_pqfe/source/include diff --git a/include/CVS/Root b/include/CVS/Root new file mode 100644 index 0000000..0536776 --- /dev/null +++ b/include/CVS/Root @@ -0,0 +1 @@ +:ext:lizhongming@10.0.0.2:/JoyProject diff --git a/include/CVS/Template b/include/CVS/Template new file mode 100644 index 0000000..e69de29 diff --git a/include/IEC60870DEF.h b/include/IEC60870DEF.h new file mode 100644 index 0000000..3e36a2d --- /dev/null +++ b/include/IEC60870DEF.h @@ -0,0 +1,1811 @@ +/** + * @file: $RCSfile: IEC60870DEF.h,v $ + * @brief: $60870ض + * + * @version: $Revision: 1.1 $ + * @date: $Date: 2018/11/24 06:54:49 $ + * @author: $Author: lizhongming $ + * @state: $State: Exp $ + * + * @latest: $Id: IEC60870DEF.h,v 1.1 2018/11/24 06:54:49 lizhongming Exp $ + */ + +/****************************************************************************** +* +* Module: $ IEC60870-5-101 Library. +* Filename: $ IEC60870DEF.h +* Copyright: $ Copyright(C) 2004 SNAC Ltd. All rights reserved. +* Author: $ DGY,YXF +* Release: $ +* Create: $ 2004/08/07 +* Modify: $ ver 0.1 - 2004/09/07 +* $ +* $ +* Language: $ C +* Environment: $ VC6/VC7 - WIN32 - I386 (support) +* $ GCC - LINUX - I386 (support) +* Description: $ Base data type of the IEC60870-5-101 protocol. +* +******************************************************************************/ + +#ifndef _INC_IEC60870_5_101_TYPE_H +#define _INC_IEC60870_5_101_TYPE_H + +/** + * @defgroup S_IEC60870_5_PROTOCOL IEC60870-5 serial protocols type identification + * @{ + */ + +#define INVALID_0 0 /**< Invalid data type */ +/* Process information in monitor direction (station-specific parameter) */ +#define M_SP_NA_1 1 /**< Single-point information */ +#define M_SP_TA_1 2 /**< Single-point information with time tag */ +#define M_DP_NA_1 3 /**< Double-point information */ +#define M_DP_TA_1 4 /**< Double-point information with time tag */ +#define M_ST_NA_1 5 /**< Step position information */ +#define M_ST_TA_1 6 /**< Step position information with time tag */ +#define M_BO_NA_1 7 /**< Bitstring of 32 bit */ +#define M_BO_TA_1 8 /**< Bitstring of 32 bit with time tag */ +#define M_ME_NA_1 9 /**< Measured value, normalised value */ +#define M_ME_TA_1 10 /**< Measured value, normalised value with time tag */ +#define M_ME_NB_1 11 /**< Measured value, scaled value */ +#define M_ME_TB_1 12 /**< Measured value, scaled value with time tag */ +#define M_ME_NC_1 13 /**< Measured value, short floating point value */ +#define M_ME_TC_1 14 /**< Measured value, short floating point value with time tag */ +#define M_IT_NA_1 15 /**< Integrated totals */ +#define M_IT_TA_1 16 /**< Integrated totals with time tag */ +#define M_EP_TA_1 17 /**< Event of protection equipment with time tag */ +#define M_EP_TB_1 18 /**< Packed start events of protection equipment with time tag */ +#define M_EP_TC_1 19 /**< Packed output circuit information of protection equipment with time tag */ +#define M_PS_NA_1 20 /**< Packed single point information with time tag */ +#define M_ME_ND_1 21 /**< Measured value, normalised value without quality descriptor */ +#define M_SP_TB_1 30 /**< Single point information with time tag CP56Time2a */ +#define M_DP_TB_1 31 /**< Double point information with time tag CP56Time2a */ +#define M_ST_TB_1 32 /**< Step position information with time tag CP56Time2a */ +#define M_BO_TB_1 33 /**< Bitstring of 32 bit with time tag CP56Time2a */ +#define M_ME_TD_1 34 /**< Measured value, normalised value with time tag CP56Time2a */ +#define M_ME_TE_1 35 /**< Measured value, scaled value with time tag CP56Time2a */ +#define M_ME_TF_1 36 /**< Measured value, short floating point value with time tag CP56Time2a */ +#define M_IT_TB_1 37 /**< Integrated totals with time tag CP56Time2a */ +#define M_EP_TD_1 38 /**< Event of protection equipment with time tag CP56Time2a */ +#define M_EP_TE_1 39 /**< Packed start events of protection equipment with time tag CP56Time2a */ +#define M_EP_TF_1 40 /**< Packed tripping events of protection equipment with time tag CP56Time2a */ +/* Process information in control direction (station-specific parameter) */ +#define C_SC_NA_1 45 /**< Single command */ +#define C_DC_NA_1 46 /**< Double command */ +#define C_RC_NA_1 47 /**< Regulating step command */ +#define C_SE_NA_1 48 /**< Set point command, normalised value */ +#define C_SE_NB_1 49 /**< Set point command, scaled value */ +#define C_SE_NC_1 50 /**< Set point command, short floating point value */ +#define C_BO_NA_1 51 /**< Bitstring of 32 bit */ +#define C_SC_TA_1 58 /**< Single command with time tag CP56Time2a */ +#define C_DC_TA_1 59 /**< Double command with time tag CP56Time2a */ +#define C_RC_TA_1 60 /**< Regulating step command with time tag CP56Time2a */ +#define C_SE_TA_1 61 /**< Set point command, normalised value with time tag CP56Time2a */ +#define C_SE_TB_1 62 /**< Set point command, scaled value with time tag CP56Time2a */ +#define C_SE_TC_1 63 /**< Set point command, short floating point value with time tag CP56Time2a */ +#define C_BO_TA_1 64 /**< Bitstring of 32 bit with time tag CP56Time2a */ +/* System information in monitor direction (station-specific parameter) */ +#define M_EI_NA_1 70 /**< End of initialisation */ +/* System information in control direction (station-specific parameter) */ +#define C_IC_NA_1 100 /**< Interrogation command ֵٻ */ +#define C_CI_NA_1 101 /**< Counter interrogation command */ +#define C_RD_NA_1 102 /**< Read command */ +#define C_CS_NA_1 103 /**< Clock synchronisation command */ +#define C_TS_NA_1 104 /**< Test command */ +#define C_RP_NA_1 105 /**< Reset process command */ +#define C_CD_NA_1 106 /**< Delay acquisition command */ +#define C_TS_TA_1 107 /**< Test command with time tag CP56Time2a */ +/* Parameter in control direction (station-specific parameter) */ +#define P_ME_NA_1 110 /**< Parameter of measured value, normalised value */ +#define P_ME_NB_1 111 /**< Parameter of measured value, scaled value */ +#define P_ME_NC_1 112 /**< Parameter of measured value, short floating point value */ +#define P_AC_NA_1 113 /**< Active parameter */ +/* File Transfer (station-specific parameter) */ +#define F_FR_NA_1 120 /**< File ready */ +#define F_SR_NA_1 121 /**< Section ready */ +#define F_SC_NA_1 122 /**< Call directory, select file, call file, call section */ +#define F_LS_NA_1 123 /**< Last section, last segment */ +#define F_AF_NA_1 124 /**< Ack file, ack section */ +#define F_SG_NA_1 125 /**< Segment */ +#define F_DR_TA_1 126 /**< Directory */ + +/* Special type for AGC */ +#define C_SE_ND_1 136 /**< Set multi-point command, normalised value */ + +/* EYE-LINUXϵͳ˳ⶨ */ +#define M_ES_NA_1 41 /**< ˳ִϢ͵ */ +#define C_GS_NA_1 114 /**< */ +#define C_SS_NA_1 115 /**< */ + +/* EYE-LINUXϵͳⶨ */ +#define C_MT_ND_1 152 /**< Multi-point transmit command, normalised value (¶ֵ) */ +#define M_EX_TA_1 153 /**< SOEչ */ +#define C_SE_EX_1 154 /**< Set Point Command,ѡֱִ̣ */ + + +#define M_GD_NA_1 160 /**< IEC60870-5-103 GDD type monitor direction data [ַ] */ +#define C_GD_NA_1 168 /**< IEC60870-5-103 GDD type control direction data */ + +/* EYE-LINUXϵͳⶨ */ +#define D_RE_DT_1 180 /**< ¼б */ +#define D_FA_SE_1 181 /**< ¼ */ +#define D_ACC_ACK_1 182 /**< ¼ԼӦ */ + +#define M_IT_S1_1 185 /** Signed int 1 */ +#define M_IT_U1_1 186 /** Unsigned int 1 */ +#define M_IT_S2_1 187 /** Signed int 2 */ +#define M_IT_U2_1 188 /** Unsigned int 2 */ +#define M_IT_S4_1 189 /** Signed int 4 */ +#define M_IT_U4_1 190 /** Unsigned int 4 */ +#define M_IT_F4_1 191 /** float 4 */ +#define M_IT_F8_1 192 /** float 8 */ + +/* ------------------------------------------------------------------------------------ +* IEC60870-5-101 cause of transmission possibilities for each ASDU +* Cause := UI6[1..6] <0..63> +* <14..19> := reserved for further compatible definitions +* <42..47> := reserved for further compatible definitions +*/ +#define COT0_NOTUSED_1 0 /**< not used */ +#define COT1_PERCYC_1 1 /**< periodic, cyclic */ +#define COT2_BACK_1 2 /**< background scan */ +#define COT3_SPONT_1 3 /**< spontaneous */ +#define COT4_INIT_1 4 /**< initialised */ +#define COT5_REQ_1 5 /**< request or requested */ +#define COT6_ACT_1 6 /**< activation */ +#define COT7_ACTCON_1 7 /**< activation confirmation */ +#define COT8_DEACT_1 8 /**< deactivation */ +#define COT9_DEACTCON_1 9 /**< deactivation confirmation */ +#define COT10_ACTTERM_1 10 /**< activation termination */ +#define COT11_RETREM_1 11 /**< return information caused by a remote command */ +#define COT12_RETLOC_1 12 /**< return information caused by a local command */ +#define COT13_FILE_1 13 /**< file transfer */ +#define COT20_INROGEN_1 20 /**< interrogated by general interrogation */ +#define COT21_INRO1_1 21 /**< interrogated by group 1 interrogation */ +#define COT22_INRO2_1 22 /**< interrogated by group 2 interrogation */ +#define COT23_INRO3_1 23 /**< interrogated by group 3 interrogation */ +#define COT24_INRO4_1 24 /**< interrogated by group 4 interrogation */ +#define COT25_INRO5_1 25 /**< interrogated by group 5 interrogation */ +#define COT26_INRO6_1 26 /**< interrogated by group 6 interrogation */ +#define COT27_INRO7_1 27 /**< interrogated by group 7 interrogation */ +#define COT28_INRO8_1 28 /**< interrogated by group 8 interrogation */ +#define COT29_INRO9_1 29 /**< interrogated by group 9 interrogation */ +#define COT30_INRO10_1 30 /**< interrogated by group 10 interrogation */ +#define COT31_INRO11_1 31 /**< interrogated by group 11 interrogation */ +#define COT32_INRO12_1 32 /**< interrogated by group 12 interrogation */ +#define COT33_INRO13_1 33 /**< interrogated by group 13 interrogation */ +#define COT34_INRO14_1 34 /**< interrogated by group 14 interrogation */ +#define COT35_INRO15_1 35 /**< interrogated by group 15 interrogation */ +#define COT36_INRO16_1 36 /**< interrogated by group 16 interrogation */ +#define COT37_REQCOGEN_1 37 /**< reques ted by general counter request */ +#define COT38_REQCO1_1 38 /**< reques ted by group 1 counter request */ +#define COT39_REQCO1_1 39 /**< reques ted by group 2 counter request */ +#define COT40_REQCO1_1 40 /**< reques ted by group 3 counter request */ +#define COT41_REQCO1_1 41 /**< reques ted by group 4 counter request */ + +/**< */ + + + +#ifdef _OS_WIN32_ +#pragma pack(push,1) +#endif + +typedef struct I_STRUCT I_STRUCT; +/** I_STRUCT */ +struct I_STRUCT { + uint32_t flag:1; /**< I format flag = 0 */ + uint32_t SNO:15; /**< Send number */ + uint32_t RES:1; /**< Reserved = 0 */ + uint32_t RNO:15; /**< Recieve number */ +}ALIGNPACKED; /**< I format */ + +typedef struct S_STRUCT S_STRUCT; +/** S_STRUCT */ +struct S_STRUCT { + uint32_t flag:2; /**< S format flag = 01 */ + uint32_t RES:15; /**< Reserved = 0 */ + uint32_t RNO:15; /**< Recieve number */ +}ALIGNPACKED; /**< S format */ + + +typedef struct U_STRUCT U_STRUCT; +/** U_STRUCT */ +struct U_STRUCT { + uint32_t flag:2; /**< U format flag = 11 */ + uint32_t STARTDT:2; /**< STARTDT */ + uint32_t STOPDT:2; /**< STOPDT */ + uint32_t TESTFR:2; /**< TESTFR */ + uint32_t RES:24; /**< Reserved = 0 */ +}ALIGNPACKED; /**< U format */ + +typedef union ctrlarea_t ctrlarea_t; + /** Control field */ +union ctrlarea_t { + byte_t byte[4]; + I_STRUCT I; + S_STRUCT S; + U_STRUCT U; +}ALIGNPACKED; + +typedef struct apci_t apci_t; +/** apci_t */ +struct apci_t { /* IEC60870-5-104 special */ + byte_t startC1; /* Start character = 68H */ + byte_t length1; /* length */ + ctrlarea_t ctrl_field; /* Control field */ +}ALIGNPACKED; +/* FRAME_TYPE()/IS_I_FRAME()/IS_S_FRAME()/IS_U_FRAME()*/ + +typedef struct asdustd_t asdustd_t; +struct asdustd_t { + byte_t typid; /* Type identification */ + byte_t vsq; /* Variable structure qualifier */ + uint16_t cot; /* Cause of transmission */ + uint16_t addr; /* Common address of ASDUs */ + byte_t data[256]; /* Variable structure qualifier */ +}ALIGNPACKED; + +// =============================================================================== +/** Ʒֵĺ + * BL=/δ + * ϢֵΪ˴Ҫ䱻ǰֵͽɵ + * 򵱵ԭ + * SB=ȡ/δȡ + * ϢֵֵԱֵһԶװõȡ + * NT=ǰֵ/ǵǰֵ + * ˢ³ɹֵͳΪǰֵһָʱˢ²ɹֵ + * þͳΪǵǰֵ + * IV=Ч/Ч + * ֵȷɼЧڲɼȷϢԴķ״̬(ɥʧǹˢ)ֵ + * ЧϢֵЩûб塣Чʹߣֵȷ + * ܱʹá + * OV=/δ + * EI=¼״̬ + * ʱֵȷɼΪЧڲɼȷΪ״̬ʱʱֵΪ + * ЧϢ嶯ʱֵЩδ塣Чʹߣֵ + * ȷܱʹá + */ + +typedef struct siq_t siq_t; +/** ƷĵϢ + * SPI=BS1ۣݣ01 + * 0=OFF + * 1=ON + */ +#ifdef PPC_LINUX +struct siq_t { + byte_t IV:1; + byte_t NT:1; + byte_t SB:1; + byte_t BL:1; + byte_t RES:3; + byte_t SPI:1; +}ALIGNPACKED; +#else +struct siq_t { + byte_t SPI:1; + byte_t RES:3; + byte_t BL:1; + byte_t SB:1; + byte_t NT:1; + byte_t IV:1; +}ALIGNPACKED; +#endif + +typedef union SIQ SIQ; +union SIQ { + byte_t bits; + siq_t parts; +}ALIGNPACKED; + +typedef struct diq_t diq_t; +/** Ʒ˫Ϣ + * DPI=UI212ݣ03 + * 0=м״̬ȷ + * 1=ȷ״̬(OFF) + * 2=ȷ״̬(ON) + * 3=м״̬ȷ + */ +#ifdef PPC_LINUX +struct diq_t { + byte_t IV:1; + byte_t NT:1; + byte_t SB:1; + byte_t BL:1; + byte_t RES:2; + byte_t DPI:2; +}ALIGNPACKED; +#else +struct diq_t { + byte_t DPI:2; + byte_t RES:2; + byte_t BL:1; + byte_t SB:1; + byte_t NT:1; + byte_t IV:1; +}ALIGNPACKED; +#endif + +typedef union DIQ DIQ; +union DIQ { + byte_t bits; + diq_t parts; +}ALIGNPACKED; + +typedef struct qdp_t qdp_t; +/** ̵籣װ¼Ʒ */ +#ifdef PPC_LINUX +struct qdp_t { + byte_t IV:1; + byte_t NT:1; + byte_t SB:1; + byte_t BL:1; + byte_t EI:1; + byte_t RES:3; +}ALIGNPACKED; +#else +struct qdp_t { + byte_t RES:3; + byte_t EI:1; + byte_t BL:1; + byte_t SB:1; + byte_t NT:1; + byte_t IV:1; +}ALIGNPACKED; +#endif + +typedef union QDP QDP; +union QDP { + byte_t bits; + qdp_t parts; +}ALIGNPACKED; + +typedef struct qds_t qds_t; +/** Ʒ */ +#ifdef PPC_LINUX +struct qds_t { + byte_t IV:1; + byte_t NT:1; + byte_t SB:1; + byte_t BL:1; + byte_t RES:3; + byte_t OV:1; +}ALIGNPACKED; +#else +struct qds_t { + byte_t OV:1; + byte_t RES:3; + byte_t BL:1; + byte_t SB:1; + byte_t NT:1; + byte_t IV:1; +}ALIGNPACKED; +#endif + +typedef union QDS QDS; +union QDS { + byte_t bits; + qds_t parts; +}ALIGNPACKED; + +typedef struct vti_t vti_t; +/** ˲״ָ̬ʾֵ */ +#ifdef PPC_LINUX +struct vti_t { + byte_t transient:1; + byte_t value:7; +}ALIGNPACKED; +#else +struct vti_t { + byte_t value:7; + byte_t transient:1; +}ALIGNPACKED; +#endif + +typedef union VTI VTI; +union VTI { + byte_t bits; + vti_t parts; +}ALIGNPACKED; + +typedef struct NVA NVA; +/** һֵ */ +struct NVA { + int16_t value; +}ALIGNPACKED; +typedef union VA VA; +union VA { + uint16_t ui; + int16_t i; +}ALIGNPACKED; + +typedef struct sva_t sva_t; +/** Ȼֵ */ +#ifdef PPC_LINUX +struct sva_t { + uint16_t sign:1; + uint16_t value:15; +}ALIGNPACKED; +#else +struct sva_t { + uint16_t value:15; + uint16_t sign:1; +}ALIGNPACKED; +#endif + +typedef union SVA SVA; +union SVA { + int16_t bits; + sva_t parts; +}ALIGNPACKED; + +typedef struct ieee754dp_t ieee754dp_t; +/** IEEE STD754 R64.52 */ +#ifdef PPC_LINUX +struct ieee754dp_t { + uint64_t sign:1; + uint64_t bexp:11; + uint64_t mant:52; +}ALIGNPACKED; +#else +struct ieee754dp_t { + uint64_t mant:52; + uint64_t bexp:11; + uint64_t sign:1; +}ALIGNPACKED; +#endif + +typedef union IEEE754DP IEEE754DP; +union IEEE754DP { + uint64_t bits; + ieee754dp_t parts; + double d; +}ALIGNPACKED; + +typedef struct ieee754sp_t ieee754sp_t; +/** IEEE STD754 R32.23̸ */ +#ifdef PPC_LINUX +struct ieee754sp_t { + uint32_t sign:1; + uint32_t bexp:8; + uint32_t mant:23; +}ALIGNPACKED; +#else +struct ieee754sp_t { + uint32_t mant:23; + uint32_t bexp:8; + uint32_t sign:1; +}ALIGNPACKED; +#endif + +typedef union IEEE754SP IEEE754SP; +union IEEE754SP { + uint32_t bits; + ieee754sp_t parts; + float f; +}ALIGNPACKED; + +typedef struct scd_t scd_t; +/** ״̬״̬仯 */ +struct scd_t { + uint16_t ST; + uint16_t CD; +}ALIGNPACKED; +typedef union SCD SCD; +union SCD { + uint32_t bits; + scd_t parts; +}ALIGNPACKED; + +typedef struct bcr_t bcr_t; +/** Ƽ */ +#ifdef PPC_LINUX +struct bcr_t { + uint32_t counter; + byte_t IV:1; + byte_t CA:1; + byte_t CY:1; + byte_t SQ:5; +}ALIGNPACKED; +#else +struct bcr_t { + uint32_t counter; + byte_t SQ:5; + byte_t CY:1; + byte_t CA:1; + byte_t IV:1; +}ALIGNPACKED; +#endif + +typedef union BCR BCR; +union BCR { + byte_t bits[5]; + bcr_t parts; +}ALIGNPACKED; + +typedef struct sep_t sep_t; +/** ̵籣װõĵ¼ */ +#ifdef PPC_LINUX +struct sep_t { + byte_t IV:1; + byte_t NT:1; + byte_t SB:1; + byte_t BL:1; + byte_t EI:1; + byte_t RES:1; + byte_t ES:2; +}ALIGNPACKED; +#else +struct sep_t { + byte_t ES:2; + byte_t RES:1; + byte_t EI:1; + byte_t BL:1; + byte_t SB:1; + byte_t NT:1; + byte_t IV:1; +}ALIGNPACKED; +#endif + +typedef union SEP SEP; +union SEP { + byte_t bits; + sep_t parts; +}ALIGNPACKED; + +typedef struct spe_t spe_t; +/** ̵籣װ¼ */ +#ifdef PPC_LINUX +struct spe_t { + byte_t RES:2; + byte_t SRD:1; + byte_t SIE:1; + byte_t SL3:1; + byte_t SL2:1; + byte_t SL1:1; + byte_t GS:1; +}ALIGNPACKED; +#else +struct spe_t { + byte_t GS:1; + byte_t SL1:1; + byte_t SL2:1; + byte_t SL3:1; + byte_t SIE:1; + byte_t SRD:1; + byte_t RES:2; +}ALIGNPACKED; +#endif + +typedef union SPE SPE; +union SPE { + byte_t bits; + spe_t parts; +}ALIGNPACKED; + +typedef struct oci_t oci_t; +/** װ·Ϣ */ +#ifdef PPC_LINUX +struct oci_t { + byte_t RES:4; + byte_t CL3:1; + byte_t CL2:1; + byte_t CL1:1; + byte_t GC:1; +}ALIGNPACKED; +#else +struct oci_t { + byte_t GC:1; + byte_t CL1:1; + byte_t CL2:1; + byte_t CL3:1; + byte_t RES:4; +}ALIGNPACKED; +#endif + +typedef union OCI OCI; +union OCI { + byte_t bits; + oci_t parts; +}ALIGNPACKED; + +typedef union BSI BSI; +/** ״̬Ϣ */ +union BSI { + uint32_t bits; + byte_t parts[4]; +}ALIGNPACKED; + +typedef struct sco_t sco_t; +/** */ +#ifdef PPC_LINUX +struct sco_t { + byte_t SE:1; + byte_t QU:5; + byte_t RES:1; + byte_t SCS:1; +}ALIGNPACKED; +#else +struct sco_t { + byte_t SCS:1; + byte_t RES:1; + byte_t QU:5; + byte_t SE:1; +}ALIGNPACKED; +#endif + +typedef union SCO SCO; +union SCO { + byte_t bits; + sco_t parts; +}ALIGNPACKED; + +typedef struct dco_t dco_t; +/** ˫ */ +#ifdef PPC_LINUX +struct dco_t { + byte_t SE:1; + byte_t QU:5; + byte_t DCS:2; +}ALIGNPACKED; +#else +struct dco_t { + byte_t DCS:2; + byte_t QU:5; + byte_t SE:1; +}ALIGNPACKED; +#endif + +typedef union DCO DCO; +union DCO { + byte_t bits; + dco_t parts; +}ALIGNPACKED; + +typedef struct rco_t rco_t; +/** */ +#ifdef PPC_LINUX +struct rco_t { + byte_t SE:1; + byte_t QU:5; + byte_t RCS:2; +}ALIGNPACKED; +#else +struct rco_t { + byte_t RCS:2; + byte_t QU:5; + byte_t SE:1; +}ALIGNPACKED; +#endif + +typedef union RCO RCO; +union RCO { + byte_t bits; + rco_t parts; +}ALIGNPACKED; + +typedef struct qos_t qos_t; +/** ޶ */ +#ifdef PPC_LINUX +struct qos_t { + byte_t SE:1; + byte_t QL:7; +}ALIGNPACKED; +#else +struct qos_t { + byte_t QL:7; + byte_t SE:1; +}ALIGNPACKED; +#endif + +typedef union QOSP QOSP; +union QOSP { + byte_t bits; + qos_t parts; +}ALIGNPACKED; + +typedef struct coi_t coi_t; +/** ʼԭ */ +#ifdef PPC_LINUX +struct coi_t { + byte_t state:1; + byte_t cause:7; +}ALIGNPACKED; +#else +struct coi_t { + byte_t cause:7; + byte_t state:1; +}ALIGNPACKED; +#endif + +typedef union COI COI; +union COI { + byte_t bits; + coi_t parts; +}ALIGNPACKED; + +typedef struct QOI QOI; +/** ٻ޶ */ +struct QOI { + byte_t qoi; +}ALIGNPACKED; + +typedef struct qcc_t qcc_t; +/** ܼٻ޶ */ +#ifdef PPC_LINUX +struct qcc_t { + byte_t FRZ:2; + byte_t RQT:6; +}ALIGNPACKED; +#else +struct qcc_t { + byte_t RQT:6; + byte_t FRZ:2; +}ALIGNPACKED; +#endif + +typedef union QCC QCC; +union QCC { + byte_t bits; + qcc_t parts; +}ALIGNPACKED; + +typedef struct FBP FBP; +/** ̶ */ +struct FBP { + uint16_t HEX; +}ALIGNPACKED; +//#define FBP (uint16_t)(0x55aa) + +typedef struct QRP QRP; +/** λ޶ */ +struct QRP { + byte_t qrp; +}ALIGNPACKED; + +typedef struct qpm_t qpm_t; +/** ֵ޶ */ +#ifdef PPC_LINUX +struct qpm_t { + byte_t POP:1; + byte_t LPC:1; + byte_t KPA:6; +}ALIGNPACKED; +#else +struct qpm_t { + byte_t KPA:6; + byte_t LPC:1; + byte_t POP:1; +}ALIGNPACKED; +#endif + +typedef union QPM QPM; +union QPM { + byte_t bits; + qpm_t parts; +}ALIGNPACKED; + +#define QPM_NOTUSED 0 /** not used */ +#define QPM_THRESHOLD 1 /** threshold value */ +#define QPM_SMOOTHING 2 /** smoothing factor (filter time constant) */ +#define QPM_LOWLIMIT 3 /** high limits */ +#define QPM_HIGHLIMIT 4 /** low limits */ + +typedef struct QPA QPA; +/** ޶ */ +struct QPA { + byte_t qpa; +}ALIGNPACKED; + +/* File Transfer (station-specific parameter) */ + +/* ļ壬ļ28λΪӦñ */ +#define FILE_TRANSPARENT (1) /**< ͸ļ */ +#define FILE_EQUIP (2) /**< ̵籣豸Ŷ */ +#define FILE_EVENT_SEQ (3) /**< ¼ */ +#define FILE_ANALOG_SEQ (4) /**< ¼ģϵ */ +/* ԭ */ +#define FILE_TRAN_DEFAULT (0) /**< ȱʡ */ +#define FILE_TRAN_SEL (1) /**< ѡļ */ +#define FILE_TRAN_REQ (2) /**< ļ */ +#define FILE_TRAN_INACTIVE (3) /**< ֹͣļ */ +#define FILE_TRAN_DELETE (4) /**< ɾļ */ +//.... +#define FILE_ERR_MEM (0) /**< Ŀռ */ +#define FILE_ERR_CHKSUM (1) /**< Уʹ */ +//.... +#define FILE_ERR_FILENAME (4) /**< ļ */ + +/** Name Of File */ +typedef uint16_t NOF; + +/** Name Of Session */ +typedef byte_t NOS; + +typedef struct LOF LOF; +/** Length Of File */ +struct LOF { + byte_t lof[3]; +}ALIGNPACKED; + +/** Length Of Session */ +typedef byte_t LOS; + +/** CHeckSum */ +typedef byte_t CHS; + +typedef struct sof_t sof_t; +/** State Of File */ +#ifdef PPC_LINUX +struct sof_t { + byte_t FA:1; + byte_t FOR:1; + byte_t LFD:1; + byte_t STATUS:5; +}ALIGNPACKED; +#else +struct sof_t { + byte_t STATUS:5; + byte_t LFD:1; + byte_t FOR:1; + byte_t FA:1; +}ALIGNPACKED; +#endif + +typedef union SOF SOF; +/** State Of File */ +union SOF { + byte_t bits; + sof_t parts; +}ALIGNPACKED; + +typedef struct frq_t frq_t; +/** File Ready Qualifier */ +#ifdef PPC_LINUX +struct frq_t { + byte_t ACK:1; /**< =0 ack; =1 deny */ + byte_t FILES:7; +}ALIGNPACKED; +#else +struct frq_t { + byte_t FILES:7; + byte_t ACK:1; /**< =0 ack; =1 deny */ +}ALIGNPACKED; +#endif + +typedef union FRQ FRQ; +/** File Ready Qualifier */ +union FRQ { + byte_t bits; + frq_t parts; +}ALIGNPACKED; + +typedef struct srq_t srq_t; +/** Session Ready Qualifier */ +#ifdef PPC_LINUX +struct srq_t { + byte_t READY:1; + byte_t SESSION:7; +}ALIGNPACKED; +#else +struct srq_t { + byte_t SESSION:7; + byte_t READY:1; +}ALIGNPACKED; +#endif + +typedef union SRQ SRQ; +/** Session Ready Qualifier */ +union SRQ { + byte_t bits; + srq_t parts; +}ALIGNPACKED; + +typedef struct scq_t scq_t; +/** Select/Call Qualifier */ +#ifdef PPC_LINUX +struct scq_t { + byte_t RESPONSE:4; + byte_t REQUEST:4; +}ALIGNPACKED; +#else +struct scq_t { + byte_t REQUEST:4; + byte_t RESPONSE:4; +}ALIGNPACKED; +#endif + +typedef union SCQ SCQ; +/** Select/Call Qualifier */ +union SCQ { + byte_t bits; + scq_t parts; +}ALIGNPACKED; + +/** Lasted Session Qualifier */ +typedef byte_t LSQ; + +typedef struct afq_t afq_t; +/** Ack File/Session Qualifier */ +#ifdef PPC_LINUX +struct afq_t { + byte_t STATUS:4; + byte_t ACK:4; +}ALIGNPACKED; +#else +struct afq_t { + byte_t ACK:4; + byte_t STATUS:4; +}ALIGNPACKED; +#endif + +typedef union AFQ AFQ; +/** Ack File/Session Qualifier */ +union AFQ { + byte_t bits; + afq_t parts; +}ALIGNPACKED; + +/** ===========================Ϣṹ================================= */ + +/** Process information in monitor direction (station-specific parameter) */ +typedef struct M_SP_NA_1_t M_SP_NA_1_t; +/** Single-point information */ +struct M_SP_NA_1_t { + SIQ siq; +}ALIGNPACKED; + +typedef struct M_SP_TA_1_t M_SP_TA_1_t; +/** Single-point information with time tag */ +struct M_SP_TA_1_t { + SIQ siq; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_DP_NA_1_t M_DP_NA_1_t; +/** Double-point information */ +struct M_DP_NA_1_t { + DIQ diq; +}ALIGNPACKED; + +typedef struct M_DP_TA_1_t M_DP_TA_1_t; +/** Double-point information with time tag */ +struct M_DP_TA_1_t { + DIQ diq; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_ST_NA_1_t M_ST_NA_1_t; +/** Step position information */ +struct M_ST_NA_1_t { + VTI vti; + QDS qds; +}ALIGNPACKED; + +typedef struct M_ST_TA_1_t M_ST_TA_1_t; +/** Step position information with time tag */ +struct M_ST_TA_1_t { + VTI vti; + QDS qds; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_BO_NA_1_t M_BO_NA_1_t; +/** Bitstring of 32 bit */ +struct M_BO_NA_1_t { + BSI bsi; + QDS qds; +}ALIGNPACKED; + +typedef struct M_SA_NA_1_t M_SA_NA_1_t; +/** String of ASCII */ +struct M_SA_NA_1_t { + byte_t length; + char str[1]; +}ALIGNPACKED; + +typedef struct M_BO_TA_1_t M_BO_TA_1_t; +/** Bitstring of 32 bit with time tag */ +struct M_BO_TA_1_t { + BSI bsi; + QDS qds; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_ME_NA_1_t M_ME_NA_1_t; +/** Measured value, normalised value */ +struct M_ME_NA_1_t { + NVA nva; + QDS qds; +}ALIGNPACKED; + +typedef struct M_ME_TA_1_t M_ME_TA_1_t; +/** Measured value, normalised value with time tag */ +struct M_ME_TA_1_t { + NVA nva; + QDS qds; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_ME_NB_1_t M_ME_NB_1_t; +/** Measured value, scaled value */ +struct M_ME_NB_1_t { + SVA sva; + QDS qds; +}ALIGNPACKED; + +typedef struct M_ME_TB_1_t M_ME_TB_1_t; +/** Measured value, scaled value with time tag */ +struct M_ME_TB_1_t { + SVA sva; + QDS qds; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_ME_NC_1_t M_ME_NC_1_t; +/** Measured value, short floating point value */ +struct M_ME_NC_1_t { + IEEE754SP std; + QDS qds; +}ALIGNPACKED; + +typedef struct M_ME_TC_1_t M_ME_TC_1_t; +/** Measured value, short floating point value with time tag */ +struct M_ME_TC_1_t { + IEEE754SP std; + QDS qds; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_IT_NA_1_t M_IT_NA_1_t; +/** Integrated totals */ +struct M_IT_NA_1_t { + BCR bcr; +}ALIGNPACKED; + +typedef struct M_IT_TA_1_t M_IT_TA_1_t; +/** Integrated totals with time tag */ +struct M_IT_TA_1_t { + BCR bcr; + CP24Time2a tm; +}ALIGNPACKED; + +typedef struct M_EP_TA_1_t M_EP_TA_1_t; +/** Event of protection equipment with time tag */ +struct M_EP_TA_1_t { + SEP sep; + CP16Time2a tm16; + CP24Time2a tm24; +}ALIGNPACKED; + +typedef struct M_EP_TB_1_t M_EP_TB_1_t; +/** Packed start events of protection equipment with time tag */ +struct M_EP_TB_1_t { + SPE spe; + QDP qdp; + CP16Time2a tm16; + CP24Time2a tm24; +}ALIGNPACKED; + +typedef struct M_EP_TC_1_t M_EP_TC_1_t; +/** Packed output circuit information of protection equipment with time tag */ +struct M_EP_TC_1_t { + OCI oci; + QDP qdp; + CP16Time2a tm16; + CP24Time2a tm24; +}ALIGNPACKED; + +typedef struct M_PS_NA_1_t M_PS_NA_1_t; +/** Packed single point information with time tag */ +struct M_PS_NA_1_t { + SCD scd; + QDS qds; +}ALIGNPACKED; + +typedef struct M_ME_ND_1_t M_ME_ND_1_t; +/** Measured value, normalised value without quality descriptor */ +struct M_ME_ND_1_t { + NVA nva; +}ALIGNPACKED; + +typedef struct M_SP_TB_1_t M_SP_TB_1_t; +/** Single point information with time tag CP56Time2a */ +struct M_SP_TB_1_t { + SIQ siq; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_DP_TB_1_t M_DP_TB_1_t; +/** Double point information with time tag CP56Time2a */ +struct M_DP_TB_1_t { + DIQ diq; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_ST_TB_1_t M_ST_TB_1_t; +/** Step position information with time tag CP56Time2a */ +struct M_ST_TB_1_t { + VTI vti; + QDS qds; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_BO_TB_1_t M_BO_TB_1_t; +/** Bitstring of 32 bit with time tag CP56Time2a */ +struct M_BO_TB_1_t { + BSI bsi; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_ME_TD_1_t M_ME_TD_1_t; +/** Measured value, normalised value with time tag CP56Time2a */ +struct M_ME_TD_1_t { + NVA nva; + QDS qds; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_ME_TE_1_t M_ME_TE_1_t; +/** Measured value, scaled value with time tag CP56Time2a */ +struct M_ME_TE_1_t { + SVA sva; + QDS qds; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_ME_TF_1_t M_ME_TF_1_t; +/** Measured value, short floating point value with time tag CP56Time2a */ +struct M_ME_TF_1_t { + IEEE754SP std; + QDS qds; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_IT_TB_1_t M_IT_TB_1_t; +/** Integrated totals with time tag CP56Time2a */ +struct M_IT_TB_1_t { + BCR bcr; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct M_EP_TD_1_t M_EP_TD_1_t; +/** Event of protection equipment with time tag CP56Time2a */ +struct M_EP_TD_1_t { + SEP sep; + CP16Time2a tm16; + CP56Time2a tm56; +}ALIGNPACKED; + +typedef struct M_EP_TE_1_t M_EP_TE_1_t; +/** Packed start events of protection equipment with time tag CP56Time2a */ +struct M_EP_TE_1_t { + SPE spe; + QDP qdp; + CP16Time2a tm16; + CP56Time2a tm56; +}ALIGNPACKED; + +typedef struct M_EP_TF_1_t M_EP_TF_1_t; +/** Packed tripping events of protection equipment with time tag CP56Time2a */ +struct M_EP_TF_1_t { + OCI oci; + QDP qdp; + CP16Time2a tm16; + CP56Time2a tm56; +}ALIGNPACKED; + +/** ˳ִϢ͵ͽṹ */ +typedef struct es_nva_t es_nva_t; +struct es_nva_t { + byte_t step; + byte_t flag; + byte_t no; + byte_t pause_time; + byte_t rsv2; + byte_t rsv3; + byte_t rsv4; + byte_t rsv5; + byte_t rsv6; + byte_t rsv7; + byte_t rsv8; +}ALIGNPACKED; +typedef struct es_str_t es_str_t; +struct es_str_t { + byte_t strlen; + byte_t string[255]; +}ALIGNPACKED; +typedef struct M_ES_NA_1_t M_ES_NA_1_t; +struct M_ES_NA_1_t { + es_nva_t esn; + es_str_t ess; +}ALIGNPACKED; + +/** Process information in control direction (station-specific parameter) */ +typedef struct C_SC_NA_1_t C_SC_NA_1_t; +/** Single command */ +struct C_SC_NA_1_t { + SCO sco; +}ALIGNPACKED; + +typedef struct C_DC_NA_1_t C_DC_NA_1_t; +/** Double command */ +struct C_DC_NA_1_t { + DCO dco; +}ALIGNPACKED; + +typedef struct C_RC_NA_1_t C_RC_NA_1_t; +/** Regulating step command */ +struct C_RC_NA_1_t { + RCO rco; +}ALIGNPACKED; + +typedef struct C_SE_NA_1_t C_SE_NA_1_t; +/** Set point command, normalised value */ +struct C_SE_NA_1_t { + NVA nva; + QOSP qos; +}ALIGNPACKED; + +typedef struct C_SE_EX_1_t C_SE_EX_1_t; +/** Set point command, normalised value ,ֱִУ跴У +S/E λЧΪ 0 +*/ +struct C_SE_EX_1_t { + NVA nva; + QOSP qos; +}ALIGNPACKED; + +typedef struct C_SE_NB_1_t C_SE_NB_1_t; +/** Set point command, scaled value */ +struct C_SE_NB_1_t { + SVA sva; + QOSP qos; +}ALIGNPACKED; + +typedef struct C_SE_NC_1_t C_SE_NC_1_t; +/** Set point command, short floating point value */ +struct C_SE_NC_1_t { + IEEE754SP std; + QOSP qos; +}ALIGNPACKED; + +typedef struct C_BO_NA_1_t C_BO_NA_1_t; +/** Bitstring of 32 bit */ +struct C_BO_NA_1_t { + BSI bsi; +}ALIGNPACKED; + +typedef struct C_SC_TA_1_t C_SC_TA_1_t; +/** Single command with time tag CP56Time2a */ +struct C_SC_TA_1_t { + SCO sco; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_DC_TA_1_t C_DC_TA_1_t; +/** Double command with time tag CP56Time2a */ +struct C_DC_TA_1_t { + DCO dco; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_RC_TA_1_t C_RC_TA_1_t; +/** Regulating step command with time tag CP56Time2a */ +struct C_RC_TA_1_t { + RCO rco; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_SE_TA_1_t C_SE_TA_1_t; +/** Set point command, normalised value with time tag CP56Time2a */ +struct C_SE_TA_1_t { + NVA nva; + QOSP qos; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_SE_TB_1_t C_SE_TB_1_t; +/** Set point command, scaled value with time tag CP56Time2a */ +struct C_SE_TB_1_t { + SVA sva; + QOSP qos; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_SE_TC_1_t C_SE_TC_1_t; +/** Set point command, short floating point value with time tag CP56Time2a */ +struct C_SE_TC_1_t { + IEEE754SP std; + QOSP qos; + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_BO_TA_1_t C_BO_TA_1_t; +/** Bitstring of 32 bit with time tag CP56Time2a */ +struct C_BO_TA_1_t { + BSI bsi; + CP56Time2a tm; +}ALIGNPACKED; + +/** System information in monitor direction (station-specific parameter) */ +typedef struct M_EI_NA_1_t M_EI_NA_1_t; +/** End of initialisation */ +struct M_EI_NA_1_t { + COI coi; +}ALIGNPACKED; + +/** System information in control direction (station-specific parameter) */ +typedef struct C_IC_NA_1_t C_IC_NA_1_t; +/** Interrogation command */ +struct C_IC_NA_1_t { + QOI qoi; +}ALIGNPACKED; + +typedef struct C_CI_NA_1_t C_CI_NA_1_t; +/** Counter interrogation command */ +struct C_CI_NA_1_t { + QCC qcc; +}ALIGNPACKED; + +/* Read command = C_RD_NA_1 no structure body */ + +typedef struct C_CS_NA_1_t C_CS_NA_1_t; +/** Clock synchronisation command */ +struct C_CS_NA_1_t { + CP56Time2a tm; +}ALIGNPACKED; + +typedef struct C_TS_NA_1_t C_TS_NA_1_t; +/** Test command */ +struct C_TS_NA_1_t { + FBP fbp; +}ALIGNPACKED; + +typedef struct C_RP_NA_1_t C_RP_NA_1_t; +/** Reset process command */ +struct C_RP_NA_1_t { + QRP qrp; +}ALIGNPACKED; + +typedef struct C_CD_NA_1_t C_CD_NA_1_t; +/** Delay acquisition command */ +struct C_CD_NA_1_t { + CP16Time2a tm; +}ALIGNPACKED; + +typedef struct C_TS_TA_1_t C_TS_TA_1_t; +/** Test command with time tag CP56Time2a */ +struct C_TS_TA_1_t { + FBP fbp; + CP56Time2a tm; +}ALIGNPACKED; + +/** Parameter in control direction (station-specific parameter) */ +typedef struct P_ME_NA_1_t P_ME_NA_1_t; +/** Parameter of measured value, normalised value */ +struct P_ME_NA_1_t { + NVA nva; + QPM qpm; +}ALIGNPACKED; + +typedef struct P_ME_NB_1_t P_ME_NB_1_t; +/** Parameter of measured value, scaled value */ +struct P_ME_NB_1_t { + SVA sva; + QPM qpm; +}ALIGNPACKED; + +typedef struct P_ME_NC_1_t P_ME_NC_1_t; +/** Parameter of measured value, short floating point value */ +struct P_ME_NC_1_t { + IEEE754SP std; + QPM qpm; +}ALIGNPACKED; + +typedef struct P_AC_NA_1_t P_AC_NA_1_t; +/** Active parameter */ +struct P_AC_NA_1_t { + QPA qpa; +}ALIGNPACKED; + +typedef struct F_FR_NA_1_t F_FR_NA_1_t; +/** File Transfer (station-specific parameter) */ +struct F_FR_NA_1_t { + NOF nof; + LOF lof; + FRQ frq; +}ALIGNPACKED; + +typedef struct F_SR_NA_1_t F_SR_NA_1_t; +/** Section ready */ +struct F_SR_NA_1_t { + NOF nof; + NOS nos; + LOF lof; +}ALIGNPACKED; + +typedef struct F_SC_NA_1_t F_SC_NA_1_t; +/** Call directory, select file, call file, call section */ +struct F_SC_NA_1_t { + NOF nof; + NOS nos; + SCQ scq; +}ALIGNPACKED; + +typedef struct F_LS_NA_1_t F_LS_NA_1_t; +/** Last section, last segment */ +struct F_LS_NA_1_t { + NOF nof; + NOS nos; + LSQ lsq; + CHS chs; +}ALIGNPACKED; + +typedef struct F_AF_NA_1_t F_AF_NA_1_t; +/** Ack file, ack section */ +struct F_AF_NA_1_t { + NOF nof; + NOS nos; + AFQ afq; +}ALIGNPACKED; + +typedef struct F_SG_NA_1_t F_SG_NA_1_t; +/** Segment */ +struct F_SG_NA_1_t { + NOF nof; + NOS nos; + LOS los; + byte_t seg[1]; +}ALIGNPACKED; + +typedef struct F_DR_TA_1_t F_DR_TA_1_t; +/** Directory */ +struct F_DR_TA_1_t { + NOF nof; + LOF lof; + SOF nos; + CP56Time2a tm; +}ALIGNPACKED; + +/** Special type for AGC */ +typedef struct C_SE_ND_1_t C_SE_ND_1_t; +/** Set multi-point command, normalised value */ +struct C_SE_ND_1_t { + uint16_t num; /** 趨ֵĿ */ +}ALIGNPACKED; + +/** ===========================Ϣṹ================================= */ +typedef struct ACC_PARAM_RELTIME_t ACC_PARAM_RELTIME_t; +struct ACC_PARAM_RELTIME_t{ + uint16_t relativetime; +}ALIGNPACKED; + +typedef struct ACC_PARAM_FAN_t ACC_PARAM_FAN_t; +struct ACC_PARAM_FAN_t{ + uint16_t fan; +}ALIGNPACKED; + +typedef struct ACC_PARAM_NOF_t ACC_PARAM_NOF_t; +struct ACC_PARAM_NOF_t{ + uint16_t nof; +}ALIGNPACKED; + +#ifdef PPC_LINUX +struct PHASE_t{ + byte_t phaseA :1; //A + byte_t phaseB :1; //B + byte_t phaseC :1; //C + byte_t phaseI :1; //ӵع + byte_t phaseO :1; // + byte_t res :2; // + byte_t valid :1; //Чλ +}ALIGNPACKED; +#else +struct PHASE_t{ + byte_t phaseA :1; //A + byte_t phaseB :1; //B + byte_t phaseC :1; //C + byte_t phaseI :1; //ӵع + byte_t phaseO :1; // + byte_t res :2; // + byte_t valid :1; //Чλ +}ALIGNPACKED; +#endif + +typedef union ACC_PARAM_PHASE_t ACC_PARAM_PHASE_t; +union ACC_PARAM_PHASE_t{ + byte_t bit; + struct PHASE_t phase; +}ALIGNPACKED; + +typedef struct ACC_PARAM_DISTANCE_t ACC_PARAM_DISTANCE_t; +struct ACC_PARAM_DISTANCE_t{ + float distance; +}ALIGNPACKED; + +typedef struct ACC_PARAM_MAXI_t ACC_PARAM_MAXI_t; +struct ACC_PARAM_MAXI_t{ + float max_i; +}ALIGNPACKED; + +typedef struct ACC_PARAM_MINI_t ACC_PARAM_MINI_t; +struct ACC_PARAM_MINI_t{ + float min_i; +}ALIGNPACKED; + +/** ===========================EYE-LINUXϵͳṹ================================= */ +typedef struct C_MT_ND_1_t C_MT_ND_1_t; +/** Multi-point transmit command, normalised value */ +struct C_MT_ND_1_t { + uint16_t num; /** 趨ֵĿ */ + dco_t dco; /** ѡ/ִ */ + byte_t desc; /** ֵ */ + uint16_t start; /** ֵʼ */ + uint16_t end; /** ֵ */ +}ALIGNPACKED; + +typedef struct gd_t gd_t; +struct gd_t { + byte_t size; //ֽڱʾַij cַ β \0ռij + byte_t gid[255]; +}ALIGNPACKED; +/** ַͶ */ +/* ַʹʾ + byte_t value[256]; + value_t val; + + val.data = &value; + val.typid = M_GD_NA_1; + value[0] = strlen(str)+1 ; //val.dataֽ֣ڱʾַij 1 cַĽβ \0ռij + val.size = value[0] +1; //value_tsize Ӧǣ ַ + һֽ + strcpy(value+1,str); +*/ +/** Special type for eye-linux */ +typedef union M_GD_NA_1_t M_GD_NA_1_t; +/** IEC60870-5-103 GDD structure, eye-linux special */ +union M_GD_NA_1_t { + byte_t bits[256]; + gd_t parts; +}; + +typedef union C_GD_NA_1_t C_GD_NA_1_t; +/** IEC60870-5-103 GDD structure, eye-linux special */ +union C_GD_NA_1_t { + byte_t bits[256]; + gd_t parts; +}ALIGNPACKED; + +typedef struct value_t value_t; +/** 洢ضݵĻṹ */ +struct value_t { + byte_t typid; /**< ͣʹIEC60870-5-101ASDU TYP */ + uint16_t size; /**< = sizeof(typid͵) */ + void* data; /**< ָsizeСڴ滺(洢typid͵) */ +}ALIGNPACKED; + +#define REQ_TD_2 2 //ѡ¼ +#define STA_TD_4 4 //¼ + +#define ACC_ACK_OK 1 //¼(б)·ɹ +#define ACC_ACK_FALUT 2 //¼(б)·ʧ +#define ACC_ACK_BUZY 3 //װæδ· +#define ACC_ACK_NOSUPPORT 4 //װò֧¼(ֶ¼ + +typedef struct dist_record_t dist_record_t; +/** Disurbance record */ +struct dist_record_t { + uint16_t fan; + byte_t sof; + CP56Time2a glb_tm; +}ALIGNPACKED; + +typedef struct dist_table_t dist_table_t; +/** Recorded disturbance table */ +struct dist_table_t { + uint32_t ied; + uint16_t cpu; + byte_t nor; /**< Number of disturbance recorded */ + dist_record_t *rec; +}; + +typedef struct sfa_t sfa_t; +/** Status of Fault */ +#ifdef PPC_LINUX +struct sfa_t { + byte_t RES:4; + byte_t OTEV:1; /**< Other event (disturbance data recording initiated by) */ + byte_t TEST:1; /**< Type of disturbance values */ + byte_t TM:1; /**< Transmit (disturbance data) */ + byte_t TP:1; /**< Trip (Recorded fault) */ +}ALIGNPACKED; +#else +struct sfa_t { + byte_t TP:1; /**< Trip (Recorded fault) */ + byte_t TM:1; /**< Transmit (disturbance data) */ + byte_t TEST:1; /**< Type of disturbance values */ + byte_t OTEV:1; /**< Other event (disturbance data recording initiated by) */ + byte_t RES:4; +}ALIGNPACKED; +#endif + +typedef union SFA SFA; +/** Status of Fault */ +union SFA { + byte_t bits; + sfa_t parts; +}ALIGNPACKED; + +typedef struct accs_t accs_t; +/** Actual channel data */ +struct accs_t { + byte_t tov; /**< Type of disturbance values */ + byte_t acc; /**< Actual channel */ + char name[32]; /**< channel name */ + char szPhase[8]; /**< channel Phase */ + char szUnit[8]; /**< Unit */ + IEEE754SP rpv; /**< Rated primary value */ + IEEE754SP rsv; /**< Rated secondary value */ + IEEE754SP rfa; /**< Reference factor */ + byte_t maxframe; /**< max frame number */ + uint16_t *ndv; /**< Number of disturbance value */ + uint16_t *nfe; /**< The order of firsr disturbance value*/ + int16_t **sdv; /**< Single disturbance value buffer */ +}ALIGNPACKED; + +typedef struct tap_t tap_t; +/** Tag postion */ +struct tap_t { + uint16_t tap; /**< Tag postion */ + DIQ dpi; /**< Double point information */ +}ALIGNPACKED; + +typedef struct tags_t tags_t; +/** Tag postion data */ +struct tags_t { + byte_t fun; /**< Function type */ + byte_t inf; /**< Information number */ + byte_t noe; /**< number of tag */ + char name[32]; /**< tag Name */ + tap_t *tag;/**< Tag postion buffer */ +}ALIGNPACKED; + + + +typedef struct timespan_t timespan_t; +struct timespan_t { + int flag; // (0=ٷǹ¼͹¼) 1=ֻٹ¼ + CP56Time2a lowbound; //low bound of acc time + CP56Time2a highbound; //high bound of acc time +}ALIGNPACKED; + +typedef struct M_EX_TA_1_t M_EX_TA_1_t; +#define EXT_SOE_PARAMETER (100) /**< SOEչ */ +struct M_EX_TA_1_t { + byte_t typid; /**< ͨSOE */ + byte_t res_flag1; /**< ñ־Ŀǰ0 */ + byte_t data_1[16]; /**< дͨSOE (Cp56+FLOAT+QOS=7+4+1=13 16 should enough) */ + byte_t ext_typid; /**< չ */ + uint16_t len; /**< չֱij */ + byte_t res_flag2; /**< */ + char data_2[256]; /**< չ */ +}ALIGNPACKED; + +typedef struct EXT_SOE_PARAMETER_HEADER_t EXT_SOE_PARAMETER_HEADER_t; +struct EXT_SOE_PARAMETER_HEADER_t { + byte_t param_id; /**< ID */ + byte_t param_type; /**< TYPE */ + byte_t param_len; /**< */ + /*... */ +}ALIGNPACKED; + +//ָװ¼б +typedef struct D_RE_DT_1_t D_RE_DT_1_t; +struct D_RE_DT_1_t { + timespan_t timespan; +}ALIGNPACKED; +//б¼ +typedef struct D_FA_SE_1_t D_FA_SE_1_t; +struct D_FA_SE_1_t { + dist_record_t dist_record; +}ALIGNPACKED; + +typedef struct D_ACC_ACK_1_t D_ACC_ACK_1_t; +struct D_ACC_ACK_1_t{ + byte_t response; //ԼӦ(ACC_ACK_OK) +}ALIGNPACKED; + + +typedef struct M_IT_S1_1_t M_IT_S1_1_t; + +struct M_IT_S1_1_t { + int8_t s_int1; + QDS qds; +}ALIGNPACKED; + +typedef struct M_IT_U1_1_t M_IT_U1_1_t; + +struct M_IT_U1_1_t { + byte_t u_int1; + QDS qds; +}ALIGNPACKED; + + +typedef struct M_IT_S2_1_t M_IT_S2_1_t; + +struct M_IT_S2_1_t { + int16_t s_int2; + QDS qds; +}ALIGNPACKED; + +typedef struct M_IT_U2_1_t M_IT_U2_1_t; + +struct M_IT_U2_1_t { + uint16_t u_int2; + QDS qds; +}ALIGNPACKED; + +typedef struct M_IT_S4_1_t M_IT_S4_1_t; +struct M_IT_S4_1_t { + int32_t s_int4; + QDS qds; +}ALIGNPACKED; + +typedef struct M_IT_U4_1_t M_IT_U4_1_t; +struct M_IT_U4_1_t { + uint32_t u_int4; + QDS qds; +}ALIGNPACKED; + +typedef struct M_IT_F4_1_t M_IT_F4_1_t; +struct M_IT_F4_1_t { + float32_t f_4; + QDS qds; +}ALIGNPACKED; + +typedef struct M_IT_F8_1_t M_IT_F8_1_t; +struct M_IT_F8_1_t { + float64_t f_8; + QDS qds; +}ALIGNPACKED; + + + + + +#ifdef _OS_WIN32_ +#pragma pack(pop) +#endif + +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ƻIEC60870׼vlaue_tṹֵʽת */ +APR_DECLARE(int) copy_iec_data(value_t *dstval,value_t *srcval,uint32_t flags); + +/** ijһIEC60870-5-101׼Ϣṹֽڳ */ +APR_DECLARE(size_t) sizeof_typid_data(byte_t typid); + +/** ijһIEC60870-5-101׼Ϣ󻺳ֽڳ */ +APR_DECLARE(size_t) sizeof_typid_buf(byte_t typid, byte_t *buf); + +/** value_tʾֵתɱʾֵʵַ */ +APR_DECLARE(int) data_value2string(value_t *val,char *szvalue); + +APR_DECLARE(int) data_actual_val(value_t *val,void *actval); +/** õEX_TA_1 ʵչֳֽڵƫ */ +APR_DECLARE(size_t) RDB_Get_EX_TA_Len_offset(byte_t *buf); + +/** СתIEC60870׼vlaue_tṹֵ */ +APR_DECLARE(int) htolval_iec_data(value_t *dstval,value_t *srcval); + +#ifdef __cplusplus +} +#endif + +#endif /*_INC_IEC60870_5_101_TYPE_H */ diff --git a/include/apr-linux/CVS/Entries b/include/apr-linux/CVS/Entries new file mode 100644 index 0000000..0f0929e --- /dev/null +++ b/include/apr-linux/CVS/Entries @@ -0,0 +1,78 @@ +/api_version.h/1.1/Fri Nov 25 08:40:16 2005// +/apr.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_allocator.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_anylock.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_atomic.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_base64.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_buckets.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_date.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_dbd.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_dbm.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_dso.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_env.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_errno.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_file_info.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_file_io.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_fnmatch.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_general.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_getopt.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_global_mutex.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_hash.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_hooks.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_iconv.h/1.1/Fri Nov 25 08:40:30 2005// +/apr_inherit.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_ldap.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_ldap_init.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_ldap_option.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_ldap_rebind.h/1.1/Mon Mar 2 05:02:58 2015// +/apr_ldap_url.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_lib.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_md4.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_md5.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_memcache.h/1.1/Mon Mar 2 05:02:59 2015// +/apr_mmap.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_network_io.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_optional.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_optional_hooks.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_poll.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_pools.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_portable.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_proc_mutex.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_queue.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_random.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_reslist.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_ring.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_rmm.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_sdbm.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_sha1.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_shm.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_signal.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_strings.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_strmatch.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_support.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_tables.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_thread_cond.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_thread_mutex.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_thread_pool.h/1.1/Mon Mar 2 05:03:00 2015// +/apr_thread_proc.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_thread_rwlock.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_time.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_uri.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_user.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_uuid.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_version.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_want.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_xlate.h/1.1/Thu Jun 15 02:48:39 2017// +/apr_xml.h/1.1/Thu Jun 15 02:48:39 2017// +/apu.h/1.1/Thu Jun 15 02:48:39 2017// +/apu.h.in/1.1/Fri Sep 30 07:45:50 2005// +/apu.hnw/1.1/Fri Sep 30 07:45:50 2005// +/apu.hw/1.1/Fri Sep 30 07:45:50 2005// +/apu_version.h/1.1/Thu Jun 15 02:48:39 2017// +/apu_want.h/1.1/Thu Jun 15 02:48:39 2017// +/apu_want.h.in/1.1/Fri Sep 30 07:45:50 2005// +/apu_want.hnw/1.1/Fri Sep 30 07:45:50 2005// +/apu_want.hw/1.1/Fri Sep 30 07:45:50 2005// +/expat.h/1.1/Thu Jun 15 02:48:39 2017// +/expat_external.h/1.1/Mon Dec 19 07:31:20 2005// +D diff --git a/include/apr-linux/CVS/Entries.Extra b/include/apr-linux/CVS/Entries.Extra new file mode 100644 index 0000000..a834470 --- /dev/null +++ b/include/apr-linux/CVS/Entries.Extra @@ -0,0 +1,77 @@ +/api_version.h////*//// +/apr.h////*//// +/apr_allocator.h////*//// +/apr_anylock.h////*//// +/apr_atomic.h////*//// +/apr_base64.h////*//// +/apr_buckets.h////*//// +/apr_date.h////*//// +/apr_dbd.h////*//// +/apr_dbm.h////*//// +/apr_dso.h////*//// +/apr_env.h////*//// +/apr_errno.h////*//// +/apr_file_info.h////*//// +/apr_file_io.h////*//// +/apr_fnmatch.h////*//// +/apr_general.h////*//// +/apr_getopt.h////*//// +/apr_global_mutex.h////*//// +/apr_hash.h////*//// +/apr_hooks.h////*//// +/apr_iconv.h////*//// +/apr_inherit.h////*//// +/apr_ldap.h////*//// +/apr_ldap_init.h////*//// +/apr_ldap_option.h////*//// +/apr_ldap_rebind.h////*//// +/apr_ldap_url.h////*//// +/apr_lib.h////*//// +/apr_md4.h////*//// +/apr_md5.h////*//// +/apr_memcache.h////*//// +/apr_mmap.h////*//// +/apr_network_io.h////*//// +/apr_optional.h////*//// +/apr_optional_hooks.h////*//// +/apr_poll.h////*//// +/apr_pools.h////*//// +/apr_portable.h////*//// +/apr_proc_mutex.h////*//// +/apr_queue.h////*//// +/apr_random.h////*//// +/apr_reslist.h////*//// +/apr_ring.h////*//// +/apr_rmm.h////*//// +/apr_sdbm.h////*//// +/apr_sha1.h////*//// +/apr_shm.h////*//// +/apr_signal.h////*//// +/apr_strings.h////*//// +/apr_strmatch.h////*//// +/apr_support.h////*//// +/apr_tables.h////*//// +/apr_thread_cond.h////*//// +/apr_thread_mutex.h////*//// +/apr_thread_pool.h////*//// +/apr_thread_proc.h////*//// +/apr_thread_rwlock.h////*//// +/apr_time.h////*//// +/apr_uri.h////*//// +/apr_user.h////*//// +/apr_uuid.h////*//// +/apr_version.h////*//// +/apr_want.h////*//// +/apr_xlate.h////*//// +/apr_xml.h////*//// +/apu.h////*//// +/apu.h.in////*//// +/apu.hnw////*//// +/apu.hw////*//// +/apu_version.h////*//// +/apu_want.h////*//// +/apu_want.h.in////*//// +/apu_want.hnw////*//// +/apu_want.hw////*//// +/expat.h////*//// +/expat_external.h////*//// diff --git a/include/apr-linux/CVS/Entries.Extra.Old b/include/apr-linux/CVS/Entries.Extra.Old new file mode 100644 index 0000000..a834470 --- /dev/null +++ b/include/apr-linux/CVS/Entries.Extra.Old @@ -0,0 +1,77 @@ +/api_version.h////*//// +/apr.h////*//// +/apr_allocator.h////*//// +/apr_anylock.h////*//// +/apr_atomic.h////*//// +/apr_base64.h////*//// +/apr_buckets.h////*//// +/apr_date.h////*//// +/apr_dbd.h////*//// +/apr_dbm.h////*//// +/apr_dso.h////*//// +/apr_env.h////*//// +/apr_errno.h////*//// +/apr_file_info.h////*//// +/apr_file_io.h////*//// +/apr_fnmatch.h////*//// +/apr_general.h////*//// +/apr_getopt.h////*//// +/apr_global_mutex.h////*//// +/apr_hash.h////*//// +/apr_hooks.h////*//// +/apr_iconv.h////*//// +/apr_inherit.h////*//// +/apr_ldap.h////*//// +/apr_ldap_init.h////*//// +/apr_ldap_option.h////*//// +/apr_ldap_rebind.h////*//// +/apr_ldap_url.h////*//// +/apr_lib.h////*//// +/apr_md4.h////*//// +/apr_md5.h////*//// +/apr_memcache.h////*//// +/apr_mmap.h////*//// +/apr_network_io.h////*//// +/apr_optional.h////*//// +/apr_optional_hooks.h////*//// +/apr_poll.h////*//// +/apr_pools.h////*//// +/apr_portable.h////*//// +/apr_proc_mutex.h////*//// +/apr_queue.h////*//// +/apr_random.h////*//// +/apr_reslist.h////*//// +/apr_ring.h////*//// +/apr_rmm.h////*//// +/apr_sdbm.h////*//// +/apr_sha1.h////*//// +/apr_shm.h////*//// +/apr_signal.h////*//// +/apr_strings.h////*//// +/apr_strmatch.h////*//// +/apr_support.h////*//// +/apr_tables.h////*//// +/apr_thread_cond.h////*//// +/apr_thread_mutex.h////*//// +/apr_thread_pool.h////*//// +/apr_thread_proc.h////*//// +/apr_thread_rwlock.h////*//// +/apr_time.h////*//// +/apr_uri.h////*//// +/apr_user.h////*//// +/apr_uuid.h////*//// +/apr_version.h////*//// +/apr_want.h////*//// +/apr_xlate.h////*//// +/apr_xml.h////*//// +/apu.h////*//// +/apu.h.in////*//// +/apu.hnw////*//// +/apu.hw////*//// +/apu_version.h////*//// +/apu_want.h////*//// +/apu_want.h.in////*//// +/apu_want.hnw////*//// +/apu_want.hw////*//// +/expat.h////*//// +/expat_external.h////*//// diff --git a/include/apr-linux/CVS/Entries.Old b/include/apr-linux/CVS/Entries.Old new file mode 100644 index 0000000..6178581 --- /dev/null +++ b/include/apr-linux/CVS/Entries.Old @@ -0,0 +1,78 @@ +/api_version.h/0/dummy timestamp// +/apr.h/0/dummy timestamp// +/apr_allocator.h/0/dummy timestamp// +/apr_anylock.h/0/dummy timestamp// +/apr_atomic.h/0/dummy timestamp// +/apr_base64.h/0/dummy timestamp// +/apr_buckets.h/0/dummy timestamp// +/apr_date.h/0/dummy timestamp// +/apr_dbd.h/0/dummy timestamp// +/apr_dbm.h/0/dummy timestamp// +/apr_dso.h/0/dummy timestamp// +/apr_env.h/0/dummy timestamp// +/apr_errno.h/0/dummy timestamp// +/apr_file_info.h/0/dummy timestamp// +/apr_file_io.h/0/dummy timestamp// +/apr_fnmatch.h/0/dummy timestamp// +/apr_general.h/0/dummy timestamp// +/apr_getopt.h/0/dummy timestamp// +/apr_global_mutex.h/0/dummy timestamp// +/apr_hash.h/0/dummy timestamp// +/apr_hooks.h/0/dummy timestamp// +/apr_iconv.h/0/dummy timestamp// +/apr_inherit.h/0/dummy timestamp// +/apr_ldap.h/0/dummy timestamp// +/apr_ldap_init.h/0/dummy timestamp// +/apr_ldap_option.h/0/dummy timestamp// +/apr_ldap_rebind.h/0/dummy timestamp// +/apr_ldap_url.h/0/dummy timestamp// +/apr_lib.h/0/dummy timestamp// +/apr_md4.h/0/dummy timestamp// +/apr_md5.h/0/dummy timestamp// +/apr_memcache.h/0/dummy timestamp// +/apr_mmap.h/0/dummy timestamp// +/apr_network_io.h/0/dummy timestamp// +/apr_optional.h/0/dummy timestamp// +/apr_optional_hooks.h/0/dummy timestamp// +/apr_poll.h/0/dummy timestamp// +/apr_pools.h/0/dummy timestamp// +/apr_portable.h/0/dummy timestamp// +/apr_proc_mutex.h/0/dummy timestamp// +/apr_queue.h/0/dummy timestamp// +/apr_random.h/0/dummy timestamp// +/apr_reslist.h/0/dummy timestamp// +/apr_ring.h/0/dummy timestamp// +/apr_rmm.h/0/dummy timestamp// +/apr_sdbm.h/0/dummy timestamp// +/apr_sha1.h/0/dummy timestamp// +/apr_shm.h/0/dummy timestamp// +/apr_signal.h/0/dummy timestamp// +/apr_strings.h/0/dummy timestamp// +/apr_strmatch.h/0/dummy timestamp// +/apr_support.h/0/dummy timestamp// +/apr_tables.h/0/dummy timestamp// +/apr_thread_cond.h/0/dummy timestamp// +/apr_thread_mutex.h/0/dummy timestamp// +/apr_thread_pool.h/0/dummy timestamp// +/apr_thread_proc.h/0/dummy timestamp// +/apr_thread_rwlock.h/0/dummy timestamp// +/apr_time.h/0/dummy timestamp// +/apr_uri.h/0/dummy timestamp// +/apr_user.h/0/dummy timestamp// +/apr_uuid.h/0/dummy timestamp// +/apr_version.h/0/dummy timestamp// +/apr_want.h/0/dummy timestamp// +/apr_xlate.h/0/dummy timestamp// +/apr_xml.h/0/dummy timestamp// +/apu.h/0/dummy timestamp// +/apu.h.in/0/dummy timestamp// +/apu.hnw/0/dummy timestamp// +/apu.hw/0/dummy timestamp// +/apu_version.h/0/dummy timestamp// +/apu_want.h/0/dummy timestamp// +/apu_want.h.in/0/dummy timestamp// +/apu_want.hnw/0/dummy timestamp// +/apu_want.hw/0/dummy timestamp// +/expat.h/0/dummy timestamp// +/expat_external.h/0/dummy timestamp// +D diff --git a/include/apr-linux/CVS/Repository b/include/apr-linux/CVS/Repository new file mode 100644 index 0000000..c455994 --- /dev/null +++ b/include/apr-linux/CVS/Repository @@ -0,0 +1 @@ +jspqfe/src/pt61850netd_pqfe/source/include/apr-linux diff --git a/include/apr-linux/CVS/Root b/include/apr-linux/CVS/Root new file mode 100644 index 0000000..0536776 --- /dev/null +++ b/include/apr-linux/CVS/Root @@ -0,0 +1 @@ +:ext:lizhongming@10.0.0.2:/JoyProject diff --git a/include/apr-linux/CVS/Template b/include/apr-linux/CVS/Template new file mode 100644 index 0000000..e69de29 diff --git a/include/apr-linux/api_version.h b/include/apr-linux/api_version.h new file mode 100644 index 0000000..84957eb --- /dev/null +++ b/include/apr-linux/api_version.h @@ -0,0 +1,132 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +#ifndef API_VERSION_H +#define API_VERSION_H + +/** + * @file api_version.h + * @brief APR-iconv Versioning Interface + * + * APR-iconv's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of API by use of the compile-time + * constants and the use of the run-time query function. + * + * API version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for API. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define API_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading API_MAJOR_VERSION + */ +#define API_MINOR_VERSION 1 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading API_MINOR_VERSION + */ +#define API_PATCH_VERSION 1 + +/** + * The symbol API_IS_DEV_VERSION is only defined for internal, + * "development" copies of API. It is undefined for released versions + * of API. + */ +/* #define API_IS_DEV_VERSION */ + + +#if defined(API_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define API_IS_DEV_STRING "-dev" +#else +#define API_IS_DEV_STRING "" +#endif + +#ifndef API_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define API_STRINGIFY(n) API_STRINGIFY_HELPER(n) +/** Helper macro for API_STRINGIFY */ +#define API_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of API's version */ +#define API_VERSION_STRING \ + API_STRINGIFY(API_MAJOR_VERSION) "." \ + API_STRINGIFY(API_MINOR_VERSION) "." \ + API_STRINGIFY(API_PATCH_VERSION) \ + API_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define API_VERSION_STRING_CSV API_MAJOR_VERSION ##, \ + ##API_MINOR_VERSION ##, \ + ##API_PATCH_VERSION + + +#ifndef API_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. API_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr_version.h" + +#include "apr_iconv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return APR-iconv's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +API_DECLARE(void) api_version(apr_version_t *pvsn); + +/** Return API's version information as a string. */ +API_DECLARE(const char *) api_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef API_VERSION_ONLY */ + +#endif /* ndef API_VERSION_H */ diff --git a/include/apr-linux/apr.h b/include/apr-linux/apr.h new file mode 100644 index 0000000..6d01656 --- /dev/null +++ b/include/apr-linux/apr.h @@ -0,0 +1,512 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.h.in instead. + * + * And please, make an effort to stub apr.hw and apr.hnw in the process. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/** + * @defgroup APR Apache Portability Runtime library + * @{ + */ +/** + * @defgroup apr_platform Platform Definitions + * @{ + * @warning + * The actual values of macros and typedefs on this page
+ * are platform specific and should NOT be relied upon!
+ */ + +/* So that we can use inline on some critical functions, and use + * GNUC attributes (such as to get -Wall warnings for printf-like + * functions). Only do this in gcc 2.7 or later ... it may work + * on earlier stuff, but why chance it. + * + * We've since discovered that the gcc shipped with NeXT systems + * as "cc" is completely broken. It claims to be __GNUC__ and so + * on, but it doesn't implement half of the things that __GNUC__ + * means. In particular it's missing inline and the __attribute__ + * stuff. So we hack around it. PR#1613. -djg + */ +#if !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ + defined(NEXT) +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#define APR_INLINE +#define APR_HAS_INLINE 0 +#else +#define APR_INLINE __inline__ +#define APR_HAS_INLINE 1 +#endif + +#define APR_HAVE_ARPA_INET_H 1 +#define APR_HAVE_CONIO_H 0 +#define APR_HAVE_CRYPT_H 1 +#define APR_HAVE_CTYPE_H 1 +#define APR_HAVE_DIRENT_H 1 +#define APR_HAVE_ERRNO_H 1 +#define APR_HAVE_FCNTL_H 1 +#define APR_HAVE_IO_H 0 +#define APR_HAVE_LIMITS_H 1 +#define APR_HAVE_NETDB_H 1 +#define APR_HAVE_NETINET_IN_H 1 +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 1 +#define APR_HAVE_PTHREAD_H 1 +#define APR_HAVE_SEMAPHORE_H 1 +#define APR_HAVE_SIGNAL_H 1 +#define APR_HAVE_STDARG_H 1 +#define APR_HAVE_STDINT_H 1 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 1 +#define APR_HAVE_SYS_IOCTL_H 1 +#define APR_HAVE_SYS_SENDFILE_H 1 +#define APR_HAVE_SYS_SIGNAL_H 1 +#define APR_HAVE_SYS_SOCKET_H 1 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 1 +#define APR_HAVE_SYS_TYPES_H 1 +#define APR_HAVE_SYS_UIO_H 1 +#define APR_HAVE_SYS_UN_H 1 +#define APR_HAVE_SYS_WAIT_H 1 +#define APR_HAVE_TIME_H 1 +#define APR_HAVE_UNISTD_H 1 +#define APR_HAVE_WINDOWS_H 0 +#define APR_HAVE_WINSOCK2_H 0 + +/** @} */ +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +#if APR_HAVE_WINDOWS_H +#include +#endif + +#if APR_HAVE_WINSOCK2_H +#include +#endif + +#if APR_HAVE_SYS_TYPES_H +#include +#endif + +#if APR_HAVE_SYS_SOCKET_H +#include +#endif + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +/* C99 7.18.4 requires that stdint.h only exposes INT64_C + * and UINT64_C for C++ implementations if this is defined: */ +#define __STDC_CONSTANT_MACROS +#endif + +#if APR_HAVE_STDINT_H +#include +#endif + +#if APR_HAVE_SYS_WAIT_H +#include +#endif + +#ifdef OS2 +#define INCL_DOS +#define INCL_DOSERRORS +#include +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include +#endif +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +#define APR_HAVE_SHMEM_MMAP_TMP 1 +#define APR_HAVE_SHMEM_MMAP_SHM 1 +#define APR_HAVE_SHMEM_MMAP_ZERO 1 +#define APR_HAVE_SHMEM_SHMGET_ANON 1 +#define APR_HAVE_SHMEM_SHMGET 1 +#define APR_HAVE_SHMEM_MMAP_ANON 1 +#define APR_HAVE_SHMEM_BEOS 0 + +#define APR_USE_SHMEM_MMAP_TMP 0 +#define APR_USE_SHMEM_MMAP_SHM 0 +#define APR_USE_SHMEM_MMAP_ZERO 0 +#define APR_USE_SHMEM_SHMGET_ANON 0 +#define APR_USE_SHMEM_SHMGET 1 +#define APR_USE_SHMEM_MMAP_ANON 1 +#define APR_USE_SHMEM_BEOS 0 + +#define APR_USE_FLOCK_SERIALIZE 0 +#define APR_USE_SYSVSEM_SERIALIZE 1 +#define APR_USE_POSIXSEM_SERIALIZE 0 +#define APR_USE_FCNTL_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 1 + +#define APR_HAS_FLOCK_SERIALIZE 1 +#define APR_HAS_SYSVSEM_SERIALIZE 1 +#define APR_HAS_POSIXSEM_SERIALIZE 1 +#define APR_HAS_FCNTL_SERIALIZE 1 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 1 + +#define APR_PROCESS_LOCK_IS_GLOBAL 0 + +#define APR_HAVE_CORKABLE_TCP 1 +#define APR_HAVE_GETRLIMIT 1 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 1 +#define APR_HAVE_IPV6 1 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 1 +#define APR_HAVE_SIGACTION 1 +#define APR_HAVE_SIGSUSPEND 1 +#define APR_HAVE_SIGWAIT 1 +#define APR_HAVE_SA_STORAGE 1 +#define APR_HAVE_STRCASECMP 1 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRICMP 0 +#define APR_HAVE_STRNCASECMP 1 +#define APR_HAVE_STRNICMP 0 +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_STRUCT_RLIMIT 1 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 +#define APR_HAVE_IOVEC 1 + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY 1 +#define APR_HAS_THREADS 1 +#define APR_HAS_SENDFILE 1 +#define APR_HAS_MMAP 1 +#define APR_HAS_FORK 1 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 1 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 0 +#define APR_HAS_PROC_INVOKED 0 +#define APR_HAS_USER 1 +#define APR_HAS_LARGE_FILES 1 +#define APR_HAS_XTHREAD_FILES 0 +#define APR_HAS_OS_UUID 0 + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 + +/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible + * to poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 1 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* If we have a TCP implementation that can be "corked", what flag + * do we use? + */ +#define APR_TCP_NOPUSH_FLAG TCP_CORK + +/* Is the TCP_NODELAY socket option inherited from listening sockets? +*/ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? +*/ +#define APR_O_NONBLOCK_INHERITED 0 + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef long long apr_int64_t; +typedef unsigned long long apr_uint64_t; + +typedef size_t apr_size_t; +typedef ssize_t apr_ssize_t; +typedef off64_t apr_off_t; +typedef socklen_t apr_socklen_t; +typedef unsigned long apr_ino_t; + +#define APR_SIZEOF_VOIDP 4 + +#if APR_SIZEOF_VOIDP == 8 +typedef apr_uint64_t apr_uintptr_t; +#else +typedef apr_uint32_t apr_uintptr_t; +#endif + +/* Are we big endian? */ +#define APR_IS_BIGENDIAN 0 + +/* Mechanisms to properly type numeric literals */ +#define APR_INT64_C(val) INT64_C(val) +#define APR_UINT64_C(val) UINT64_C(val) + +#ifdef INT16_MIN +#define APR_INT16_MIN INT16_MIN +#else +#define APR_INT16_MIN (-0x7fff - 1) +#endif + +#ifdef INT16_MAX +#define APR_INT16_MAX INT16_MAX +#else +#define APR_INT16_MAX (0x7fff) +#endif + +#ifdef UINT16_MAX +#define APR_UINT16_MAX UINT16_MAX +#else +#define APR_UINT16_MAX (0xffff) +#endif + +#ifdef INT32_MIN +#define APR_INT32_MIN INT32_MIN +#else +#define APR_INT32_MIN (-0x7fffffff - 1) +#endif + +#ifdef INT32_MAX +#define APR_INT32_MAX INT32_MAX +#else +#define APR_INT32_MAX 0x7fffffff +#endif + +#ifdef UINT32_MAX +#define APR_UINT32_MAX UINT32_MAX +#else +#define APR_UINT32_MAX (0xffffffffU) +#endif + +#ifdef INT64_MIN +#define APR_INT64_MIN INT64_MIN +#else +#define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) +#endif + +#ifdef INT64_MAX +#define APR_INT64_MAX INT64_MAX +#else +#define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) +#endif + +#ifdef UINT64_MAX +#define APR_UINT64_MAX UINT64_MAX +#else +#define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) +#endif + +#define APR_SIZE_MAX (~((apr_size_t)0)) + + +/* Definitions that APR programs need to work properly. */ + +/** + * APR public API wrap for C++ compilers. + */ +#ifdef __cplusplus +#define APR_BEGIN_DECLS extern "C" { +#define APR_END_DECLS } +#else +#define APR_BEGIN_DECLS +#define APR_END_DECLS +#endif + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + *
+ *
+ * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data);
+ *
+ * 
+ */ +#define APR_THREAD_FUNC + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * + *
+ * APR_DECLARE(rettype) apr_func(args)
+ * 
+ * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + *
+ *
+ * APR_DECLARE_NONSTD(rettype) apr_func(args, ...);
+ *
+ * 
+ */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with AP_MODULE_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * + *
+ *
+ * extern APR_DECLARE_DATA type apr_variable;\n
+ * APR_DECLARE_DATA type apr_variable = value;
+ *
+ * 
+ */ +#define APR_DECLARE_DATA + +/* Define APR_SSIZE_T_FMT. + * If ssize_t is an integer we define it to be "d", + * if ssize_t is a long int we define it to be "ld", + * if ssize_t is neither we declare an error here. + * I looked for a better way to define this here, but couldn't find one, so + * to find the logic for this definition search for "ssize_t_fmt" in + * configure.in. + */ +#define APR_SSIZE_T_FMT "d" + +/* And APR_SIZE_T_FMT */ +#define APR_SIZE_T_FMT "u" + +/* And APR_OFF_T_FMT */ +#define APR_OFF_T_FMT APR_INT64_T_FMT + +/* And APR_PID_T_FMT */ +#define APR_PID_T_FMT "d" + +/* And APR_INT64_T_FMT */ +#define APR_INT64_T_FMT "lld" + +/* And APR_UINT64_T_FMT */ +#define APR_UINT64_T_FMT "llu" + +/* And APR_UINT64_T_HEX_FMT */ +#define APR_UINT64_T_HEX_FMT "llx" + +/* Does the proc mutex lock threads too */ +#define APR_PROC_MUTEX_IS_GLOBAL 0 + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\n" + +#if APR_HAVE_SYS_WAIT_H +#ifdef WEXITSTATUS +#define apr_wait_t int +#else +#define apr_wait_t union wait +#define WEXITSTATUS(status) (int)((status).w_retcode) +#define WTERMSIG(status) (int)((status).w_termsig) +#endif /* !WEXITSTATUS */ +#elif defined(__MINGW32__) +typedef int apr_wait_t; +#endif /* HAVE_SYS_WAIT_H */ + +#if defined(PATH_MAX) +#define APR_PATH_MAX PATH_MAX +#elif defined(_POSIX_PATH_MAX) +#define APR_PATH_MAX _POSIX_PATH_MAX +#else +#error no decision has been made on APR_PATH_MAX for your platform +#endif + +#define APR_DSOPATH "LD_LIBRARY_PATH" + +/** @} */ + +/* Definitions that only Win32 programs need to compile properly. */ + +/* XXX These simply don't belong here, perhaps in apr_portable.h + * based on some APR_HAVE_PID/GID/UID? + */ +#ifdef __MINGW32__ +#ifndef __GNUC__ +typedef int pid_t; +#endif +typedef int uid_t; +typedef int gid_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* APR_H */ diff --git a/include/apr-linux/apr_allocator.h b/include/apr-linux/apr_allocator.h new file mode 100644 index 0000000..1acfa9b --- /dev/null +++ b/include/apr-linux/apr_allocator.h @@ -0,0 +1,167 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_ALLOCATOR_H +#define APR_ALLOCATOR_H + +/** + * @file apr_allocator.h + * @brief APR Internal Memory Allocation + */ + +#include "apr.h" +#include "apr_errno.h" +#define APR_WANT_MEMFUNC /**< For no good reason? */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_allocator Internal Memory Allocation + * @ingroup APR + * @{ + */ + +/** the allocator structure */ +typedef struct apr_allocator_t apr_allocator_t; +/** the structure which holds information about the allocation */ +typedef struct apr_memnode_t apr_memnode_t; + +/** basic memory node structure + * @note The next, ref and first_avail fields are available for use by the + * caller of apr_allocator_alloc(), the remaining fields are read-only. + * The next field has to be used with caution and sensibly set when the + * memnode is passed back to apr_allocator_free(). See apr_allocator_free() + * for details. + * The ref and first_avail fields will be properly restored by + * apr_allocator_free(). + */ +struct apr_memnode_t { + apr_memnode_t *next; /**< next memnode */ + apr_memnode_t **ref; /**< reference to self */ + apr_uint32_t index; /**< size */ + apr_uint32_t free_index; /**< how much free */ + char *first_avail; /**< pointer to first free memory */ + char *endp; /**< pointer to end of free memory */ +}; + +/** The base size of a memory node - aligned. */ +#define APR_MEMNODE_T_SIZE APR_ALIGN_DEFAULT(sizeof(apr_memnode_t)) + +/** Symbolic constants */ +#define APR_ALLOCATOR_MAX_FREE_UNLIMITED 0 + +/** + * View a new allocator key status + * @param allocator The allocator we have just created. + * + */ +APR_DECLARE(apr_status_t) apr_allocator_status(); + +/** + * Create a new allocator + * @param allocator The allocator we have just created. + * + */ +APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator); + +/** + * Destroy an allocator + * @param allocator The allocator to be destroyed + * @remark Any memnodes not given back to the allocator prior to destroying + * will _not_ be free()d. + */ +APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator); + +/** + * Allocate a block of mem from the allocator + * @param allocator The allocator to allocate from + * @param size The size of the mem to allocate (excluding the + * memnode structure) + */ +APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator, + apr_size_t size); + +/** + * Free a list of blocks of mem, giving them back to the allocator. + * The list is typically terminated by a memnode with its next field + * set to NULL. + * @param allocator The allocator to give the mem back to + * @param memnode The memory node to return + */ +APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator, + apr_memnode_t *memnode); + +#include "apr_pools.h" + +/** + * Set the owner of the allocator + * @param allocator The allocator to set the owner for + * @param pool The pool that is to own the allocator + * @remark Typically pool is the highest level pool using the allocator + */ +/* + * XXX: see if we can come up with something a bit better. Currently + * you can make a pool an owner, but if the pool doesn't use the allocator + * the allocator will never be destroyed. + */ +APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator, + apr_pool_t *pool); + +/** + * Get the current owner of the allocator + * @param allocator The allocator to get the owner from + */ +APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator); + +/** + * Set the current threshold at which the allocator should start + * giving blocks back to the system. + * @param allocator The allocator the set the threshold on + * @param size The threshold. 0 == unlimited. + */ +APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator, + apr_size_t size); + +#include "apr_thread_mutex.h" + +#if APR_HAS_THREADS +/** + * Set a mutex for the allocator to use + * @param allocator The allocator to set the mutex for + * @param mutex The mutex + */ +APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator, + apr_thread_mutex_t *mutex); + +/** + * Get the mutex currently set for the allocator + * @param allocator The allocator + */ +APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get( + apr_allocator_t *allocator); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ALLOCATOR_H */ diff --git a/include/apr-linux/apr_anylock.h b/include/apr-linux/apr_anylock.h new file mode 100644 index 0000000..51e97ff --- /dev/null +++ b/include/apr-linux/apr_anylock.h @@ -0,0 +1,128 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * @file apr_anylock.h + * @brief APR-Util transparent any lock flavor wrapper + */ +#ifndef APR_ANYLOCK_H +#define APR_ANYLOCK_H + +#include "apr_proc_mutex.h" +#include "apr_thread_mutex.h" +#include "apr_thread_rwlock.h" + +/** Structure that may contain any APR lock type */ +typedef struct apr_anylock_t { + /** Indicates what type of lock is in lock */ + enum tm_lock { + apr_anylock_none, /**< None */ + apr_anylock_procmutex, /**< Process-based */ + apr_anylock_threadmutex, /**< Thread-based */ + apr_anylock_readlock, /**< Read lock */ + apr_anylock_writelock /**< Write lock */ + } type; + /** Union of all possible APR locks */ + union apr_anylock_u_t { + apr_proc_mutex_t *pm; /**< Process mutex */ +#if APR_HAS_THREADS + apr_thread_mutex_t *tm; /**< Thread mutex */ + apr_thread_rwlock_t *rw; /**< Read-write lock */ +#endif + } lock; +} apr_anylock_t; + +#if APR_HAS_THREADS + +/** Lock an apr_anylock_t structure */ +#define APR_ANYLOCK_LOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_lock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_lock((lck)->lock.pm) \ + : (((lck)->type == apr_anylock_readlock) \ + ? apr_thread_rwlock_rdlock((lck)->lock.rw) \ + : (((lck)->type == apr_anylock_writelock) \ + ? apr_thread_rwlock_wrlock((lck)->lock.rw) \ + : APR_EINVAL))))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_LOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_lock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#if APR_HAS_THREADS + +/** Try to lock an apr_anylock_t structure */ +#define APR_ANYLOCK_TRYLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_trylock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_trylock((lck)->lock.pm) \ + : (((lck)->type == apr_anylock_readlock) \ + ? apr_thread_rwlock_tryrdlock((lck)->lock.rw) \ + : (((lck)->type == apr_anylock_writelock) \ + ? apr_thread_rwlock_trywrlock((lck)->lock.rw) \ + : APR_EINVAL))))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_TRYLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_trylock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#if APR_HAS_THREADS + +/** Unlock an apr_anylock_t structure */ +#define APR_ANYLOCK_UNLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_unlock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_unlock((lck)->lock.pm) \ + : ((((lck)->type == apr_anylock_readlock) || \ + ((lck)->type == apr_anylock_writelock)) \ + ? apr_thread_rwlock_unlock((lck)->lock.rw) \ + : APR_EINVAL)))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_UNLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_unlock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#endif /* !APR_ANYLOCK_H */ diff --git a/include/apr-linux/apr_atomic.h b/include/apr-linux/apr_atomic.h new file mode 100644 index 0000000..60e4bb5 --- /dev/null +++ b/include/apr-linux/apr_atomic.h @@ -0,0 +1,140 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_ATOMIC_H +#define APR_ATOMIC_H + +/** + * @file apr_atomic.h + * @brief APR Atomic Operations + */ + +#include "apr.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_atomic Atomic Operations + * @ingroup APR + * @{ + */ + +/** + * this function is required on some platforms to initialize the + * atomic operation's internal structures + * @param p pool + * @return APR_SUCCESS on successful completion + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_initialize. + * @internal + */ +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p); + +/* + * Atomic operations on 32-bit values + * Note: Each of these functions internally implements a memory barrier + * on platforms that require it + */ + +/** + * atomically read an apr_uint32_t from memory + * @param mem the pointer + */ +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem); + +/** + * atomically set an apr_uint32_t in memory + * @param mem pointer to the object + * @param val value that the object will assume + */ +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically add 'val' to an apr_uint32_t + * @param mem pointer to the object + * @param val amount to add + * @return old value pointed to by mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically subtract 'val' from an apr_uint32_t + * @param mem pointer to the object + * @param val amount to subtract + */ +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically increment an apr_uint32_t by 1 + * @param mem pointer to the object + * @return old value pointed to by mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem); + +/** + * atomically decrement an apr_uint32_t by 1 + * @param mem pointer to the atomic value + * @return zero if the value becomes zero on decrement, otherwise non-zero + */ +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem); + +/** + * compare an apr_uint32_t's value with 'cmp'. + * If they are the same swap the value with 'with' + * @param mem pointer to the value + * @param with what to swap it with + * @param cmp the value to compare it to + * @return the old value of *mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp); + +/** + * exchange an apr_uint32_t's value with 'val'. + * @param mem pointer to the value + * @param val what to swap it with + * @return the old value of *mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * compare the pointer's value with cmp. + * If they are the same swap the value with 'with' + * @param mem pointer to the pointer + * @param with what to swap it with + * @param cmp the value to compare it to + * @return the old value of the pointer + */ +APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp); + +/** + * exchange a pair of pointer values + * @param mem pointer to the pointer + * @param with what to swap it with + * @return the old value of the pointer + */ +APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ATOMIC_H */ diff --git a/include/apr-linux/apr_base64.h b/include/apr-linux/apr_base64.h new file mode 100644 index 0000000..b4b2b88 --- /dev/null +++ b/include/apr-linux/apr_base64.h @@ -0,0 +1,112 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * The apr_vsnprintf/apr_snprintf functions are based on, and used with the + * permission of, the SIO stdio-replacement strx_* functions by Panos + * Tsirigotis for xinetd. + */ + +/** + * @file apr_base64.h + * @brief APR-UTIL Base64 Encoding + */ +#ifndef APR_BASE64_H +#define APR_BASE64_H + +#include "apu.h" +#include "apr_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Base64 Base64 Encoding + * @ingroup APR_Util + * @{ + */ + +/* Simple BASE64 encode/decode functions. + * + * As we might encode binary strings, hence we require the length of + * the incoming plain source. And return the length of what we decoded. + * + * The decoding function takes any non valid char (i.e. whitespace, \0 + * or anything non A-Z,0-9 etc as terminal. + * + * plain strings/binary sequences are not assumed '\0' terminated. Encoded + * strings are neither. But probably should. + * + */ + +/** + * Given the length of an un-encrypted string, get the length of the + * encrypted string. + * @param len the length of an unencrypted string. + * @return the length of the string after it is encrypted + */ +APU_DECLARE(int) apr_base64_encode_len(int len); + +/** + * Encode a text string using base64encoding. + * @param coded_dst The destination string for the encoded string. + * @param plain_src The original string in plain text + * @param len_plain_src The length of the plain text string + * @return the length of the encoded string + */ +APU_DECLARE(int) apr_base64_encode(char * coded_dst, const char *plain_src, + int len_plain_src); + +/** + * Encode an EBCDIC string using base64encoding. + * @param coded_dst The destination string for the encoded string. + * @param plain_src The original string in plain text + * @param len_plain_src The length of the plain text string + * @return the length of the encoded string + */ +APU_DECLARE(int) apr_base64_encode_binary(char * coded_dst, + const unsigned char *plain_src, + int len_plain_src); + +/** + * Determine the maximum buffer length required to decode the plain text + * string given the encoded string. + * @param coded_src The encoded string + * @return the maximum required buffer length for the plain text string + */ +APU_DECLARE(int) apr_base64_decode_len(const char * coded_src); + +/** + * Decode a string to plain text + * @param plain_dst The destination string for the plain text + * @param coded_src The encoded string + * @return the length of the plain text string + */ +APU_DECLARE(int) apr_base64_decode(char * plain_dst, const char *coded_src); + +/** + * Decode an EBCDIC string to plain text + * @param plain_dst The destination string for the plain text + * @param coded_src The encoded string + * @return the length of the plain text string + */ +APU_DECLARE(int) apr_base64_decode_binary(unsigned char * plain_dst, + const char *coded_src); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_BASE64_H */ diff --git a/include/apr-linux/apr_buckets.h b/include/apr-linux/apr_buckets.h new file mode 100644 index 0000000..6ee97f2 --- /dev/null +++ b/include/apr-linux/apr_buckets.h @@ -0,0 +1,1504 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +/** + * @file apr_buckets.h + * @brief APR-UTIL Buckets/Bucket Brigades + */ + +#ifndef APR_BUCKETS_H +#define APR_BUCKETS_H + +#if defined(APR_BUCKET_DEBUG) && !defined(APR_RING_DEBUG) +#define APR_RING_DEBUG +#endif + +#include "apu.h" +#include "apr_network_io.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_mmap.h" +#include "apr_errno.h" +#include "apr_ring.h" +#include "apr.h" +#if APR_HAVE_SYS_UIO_H +#include /* for struct iovec */ +#endif +#if APR_HAVE_STDARG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Bucket_Brigades Bucket Brigades + * @ingroup APR_Util + * @{ + */ + +/** default bucket buffer size - 8KB minus room for memory allocator headers */ +#define APR_BUCKET_BUFF_SIZE 8000 + +/** Determines how a bucket or brigade should be read */ +typedef enum { + APR_BLOCK_READ, /**< block until data becomes available */ + APR_NONBLOCK_READ /**< return immediately if no data is available */ +} apr_read_type_e; + +/** + * The one-sentence buzzword-laden overview: Bucket brigades represent + * a complex data stream that can be passed through a layered IO + * system without unnecessary copying. A longer overview follows... + * + * A bucket brigade is a doubly linked list (ring) of buckets, so we + * aren't limited to inserting at the front and removing at the end. + * Buckets are only passed around as members of a brigade, although + * singleton buckets can occur for short periods of time. + * + * Buckets are data stores of various types. They can refer to data in + * memory, or part of a file or mmap area, or the output of a process, + * etc. Buckets also have some type-dependent accessor functions: + * read, split, copy, setaside, and destroy. + * + * read returns the address and size of the data in the bucket. If the + * data isn't in memory then it is read in and the bucket changes type + * so that it can refer to the new location of the data. If all the + * data doesn't fit in the bucket then a new bucket is inserted into + * the brigade to hold the rest of it. + * + * split divides the data in a bucket into two regions. After a split + * the original bucket refers to the first part of the data and a new + * bucket inserted into the brigade after the original bucket refers + * to the second part of the data. Reference counts are maintained as + * necessary. + * + * setaside ensures that the data in the bucket has a long enough + * lifetime. Sometimes it is convenient to create a bucket referring + * to data on the stack in the expectation that it will be consumed + * (output to the network) before the stack is unwound. If that + * expectation turns out not to be valid, the setaside function is + * called to move the data somewhere safer. + * + * copy makes a duplicate of the bucket structure as long as it's + * possible to have multiple references to a single copy of the + * data itself. Not all bucket types can be copied. + * + * destroy maintains the reference counts on the resources used by a + * bucket and frees them if necessary. + * + * Note: all of the above functions have wrapper macros (apr_bucket_read(), + * apr_bucket_destroy(), etc), and those macros should be used rather + * than using the function pointers directly. + * + * To write a bucket brigade, they are first made into an iovec, so that we + * don't write too little data at one time. Currently we ignore compacting the + * buckets into as few buckets as possible, but if we really want good + * performance, then we need to compact the buckets before we convert to an + * iovec, or possibly while we are converting to an iovec. + */ + +/* + * Forward declaration of the main types. + */ + +/** @see apr_bucket_brigade */ +typedef struct apr_bucket_brigade apr_bucket_brigade; +/** @see apr_bucket */ +typedef struct apr_bucket apr_bucket; +/** @see apr_bucket_alloc_t */ +typedef struct apr_bucket_alloc_t apr_bucket_alloc_t; + +/** @see apr_bucket_type_t */ +typedef struct apr_bucket_type_t apr_bucket_type_t; + +/** + * Basic bucket type + */ +struct apr_bucket_type_t { + /** + * The name of the bucket type + */ + const char *name; + /** + * The number of functions this bucket understands. Can not be less than + * five. + */ + int num_func; + /** + * Whether the bucket contains metadata (ie, information that + * describes the regular contents of the brigade). The metadata + * is not returned by apr_bucket_read() and is not indicated by + * the ->length of the apr_bucket itself. In other words, an + * empty bucket is safe to arbitrarily remove if and only if it + * contains no metadata. In this sense, "data" is just raw bytes + * that are the "content" of the brigade and "metadata" describes + * that data but is not a proper part of it. + */ + enum { + /** This bucket type represents actual data to send to the client. */ + APR_BUCKET_DATA = 0, + /** This bucket type represents metadata. */ + APR_BUCKET_METADATA = 1 + } is_metadata; + /** + * Free the private data and any resources used by the bucket (if they + * aren't shared with another bucket). This function is required to be + * implemented for all bucket types, though it might be a no-op on some + * of them (namely ones that never allocate any private data structures). + * @param data The private data pointer from the bucket to be destroyed + */ + void (*destroy)(void *data); + + /** + * Read the data from the bucket. This is required to be implemented + * for all bucket types. + * @param b The bucket to read from + * @param str A place to store the data read. Allocation should only be + * done if absolutely necessary. + * @param len The amount of data read. + * @param block Should this read function block if there is more data that + * cannot be read immediately. + */ + apr_status_t (*read)(apr_bucket *b, const char **str, apr_size_t *len, + apr_read_type_e block); + + /** + * Make it possible to set aside the data for at least as long as the + * given pool. Buckets containing data that could potentially die before + * this pool (e.g. the data resides on the stack, in a child pool of + * the given pool, or in a disjoint pool) must somehow copy, shift, or + * transform the data to have the proper lifetime. + * @param e The bucket to convert + * @remark Some bucket types contain data that will always outlive the + * bucket itself. For example no data (EOS and FLUSH), or the data + * resides in global, constant memory (IMMORTAL), or the data is on + * the heap (HEAP). For these buckets, apr_bucket_setaside_noop can + * be used. + */ + apr_status_t (*setaside)(apr_bucket *e, apr_pool_t *pool); + + /** + * Split one bucket in two at the specified position by duplicating + * the bucket structure (not the data) and modifying any necessary + * start/end/offset information. If it's not possible to do this + * for the bucket type (perhaps the length of the data is indeterminate, + * as with pipe and socket buckets), then APR_ENOTIMPL is returned. + * @param e The bucket to split + * @param point The offset of the first byte in the new bucket + */ + apr_status_t (*split)(apr_bucket *e, apr_size_t point); + + /** + * Copy the bucket structure (not the data), assuming that this is + * possible for the bucket type. If it's not, APR_ENOTIMPL is returned. + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + */ + apr_status_t (*copy)(apr_bucket *e, apr_bucket **c); + +}; + +/** + * apr_bucket structures are allocated on the malloc() heap and + * their lifetime is controlled by the parent apr_bucket_brigade + * structure. Buckets can move from one brigade to another e.g. by + * calling APR_BRIGADE_CONCAT(). In general the data in a bucket has + * the same lifetime as the bucket and is freed when the bucket is + * destroyed; if the data is shared by more than one bucket (e.g. + * after a split) the data is freed when the last bucket goes away. + */ +struct apr_bucket { + /** Links to the rest of the brigade */ + APR_RING_ENTRY(apr_bucket) link; + /** The type of bucket. */ + const apr_bucket_type_t *type; + /** The length of the data in the bucket. This could have been implemented + * with a function, but this is an optimization, because the most + * common thing to do will be to get the length. If the length is unknown, + * the value of this field will be (apr_size_t)(-1). + */ + apr_size_t length; + /** The start of the data in the bucket relative to the private base + * pointer. The vast majority of bucket types allow a fixed block of + * data to be referenced by multiple buckets, each bucket pointing to + * a different segment of the data. That segment starts at base+start + * and ends at base+start+length. + * If the length == (apr_size_t)(-1), then start == -1. + */ + apr_off_t start; + /** type-dependent data hangs off this pointer */ + void *data; + /** + * Pointer to function used to free the bucket. This function should + * always be defined and it should be consistent with the memory + * function used to allocate the bucket. For example, if malloc() is + * used to allocate the bucket, this pointer should point to free(). + * @param e Pointer to the bucket being freed + */ + void (*free)(void *e); + /** The freelist from which this bucket was allocated */ + apr_bucket_alloc_t *list; +}; + +/** A list of buckets */ +struct apr_bucket_brigade { + /** The pool to associate the brigade with. The data is not allocated out + * of the pool, but a cleanup is registered with this pool. If the + * brigade is destroyed by some mechanism other than pool destruction, + * the destroying function is responsible for killing the cleanup. + */ + apr_pool_t *p; + /** The buckets in the brigade are on this list. */ + /* + * The apr_bucket_list structure doesn't actually need a name tag + * because it has no existence independent of struct apr_bucket_brigade; + * the ring macros are designed so that you can leave the name tag + * argument empty in this situation but apparently the Windows compiler + * doesn't like that. + */ + APR_RING_HEAD(apr_bucket_list, apr_bucket) list; + /** The freelist from which this bucket was allocated */ + apr_bucket_alloc_t *bucket_alloc; +}; + + +/** + * Function called when a brigade should be flushed + */ +typedef apr_status_t (*apr_brigade_flush)(apr_bucket_brigade *bb, void *ctx); + +/* + * define APR_BUCKET_DEBUG if you want your brigades to be checked for + * validity at every possible instant. this will slow your code down + * substantially but is a very useful debugging tool. + */ +#ifdef APR_BUCKET_DEBUG + +#define APR_BRIGADE_CHECK_CONSISTENCY(b) \ + APR_RING_CHECK_CONSISTENCY(&(b)->list, apr_bucket, link) + +#define APR_BUCKET_CHECK_CONSISTENCY(e) \ + APR_RING_CHECK_ELEM_CONSISTENCY((e), apr_bucket, link) + +#else +/** + * checks the ring pointers in a bucket brigade for consistency. an + * abort() will be triggered if any inconsistencies are found. + * note: this is a no-op unless APR_BUCKET_DEBUG is defined. + * @param b The brigade + */ +#define APR_BRIGADE_CHECK_CONSISTENCY(b) +/** + * checks the brigade a bucket is in for ring consistency. an + * abort() will be triggered if any inconsistencies are found. + * note: this is a no-op unless APR_BUCKET_DEBUG is defined. + * @param e The bucket + */ +#define APR_BUCKET_CHECK_CONSISTENCY(e) +#endif + + +/** + * Wrappers around the RING macros to reduce the verbosity of the code + * that handles bucket brigades. + */ +/** + * The magic pointer value that indicates the head of the brigade + * @remark This is used to find the beginning and end of the brigade, eg: + *
+ *      while (e != APR_BRIGADE_SENTINEL(b)) {
+ *          ...
+ *          e = APR_BUCKET_NEXT(e);
+ *      }
+ * 
+ * @param b The brigade + * @return The magic pointer value + */ +#define APR_BRIGADE_SENTINEL(b) APR_RING_SENTINEL(&(b)->list, apr_bucket, link) + +/** + * Determine if the bucket brigade is empty + * @param b The brigade to check + * @return true or false + */ +#define APR_BRIGADE_EMPTY(b) APR_RING_EMPTY(&(b)->list, apr_bucket, link) + +/** + * Return the first bucket in a brigade + * @param b The brigade to query + * @return The first bucket in the brigade + */ +#define APR_BRIGADE_FIRST(b) APR_RING_FIRST(&(b)->list) +/** + * Return the last bucket in a brigade + * @param b The brigade to query + * @return The last bucket in the brigade + */ +#define APR_BRIGADE_LAST(b) APR_RING_LAST(&(b)->list) + +/** + * Insert a list of buckets at the front of a brigade + * @param b The brigade to add to + * @param e The first bucket in a list of buckets to insert + */ +#define APR_BRIGADE_INSERT_HEAD(b, e) do { \ + apr_bucket *ap__b = (e); \ + APR_RING_INSERT_HEAD(&(b)->list, ap__b, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((b)); \ + } while (0) + +/** + * Insert a list of buckets at the end of a brigade + * @param b The brigade to add to + * @param e The first bucket in a list of buckets to insert + */ +#define APR_BRIGADE_INSERT_TAIL(b, e) do { \ + apr_bucket *ap__b = (e); \ + APR_RING_INSERT_TAIL(&(b)->list, ap__b, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((b)); \ + } while (0) + +/** + * Concatenate brigade b onto the end of brigade a, leaving brigade b empty + * @param a The first brigade + * @param b The second brigade + */ +#define APR_BRIGADE_CONCAT(a, b) do { \ + APR_RING_CONCAT(&(a)->list, &(b)->list, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((a)); \ + } while (0) + +/** + * Prepend brigade b onto the beginning of brigade a, leaving brigade b empty + * @param a The first brigade + * @param b The second brigade + */ +#define APR_BRIGADE_PREPEND(a, b) do { \ + APR_RING_PREPEND(&(a)->list, &(b)->list, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((a)); \ + } while (0) + +/** + * Insert a list of buckets before a specified bucket + * @param a The bucket to insert before + * @param b The buckets to insert + */ +#define APR_BUCKET_INSERT_BEFORE(a, b) do { \ + apr_bucket *ap__a = (a), *ap__b = (b); \ + APR_RING_INSERT_BEFORE(ap__a, ap__b, link); \ + APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ + } while (0) + +/** + * Insert a list of buckets after a specified bucket + * @param a The bucket to insert after + * @param b The buckets to insert + */ +#define APR_BUCKET_INSERT_AFTER(a, b) do { \ + apr_bucket *ap__a = (a), *ap__b = (b); \ + APR_RING_INSERT_AFTER(ap__a, ap__b, link); \ + APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ + } while (0) + +/** + * Get the next bucket in the list + * @param e The current bucket + * @return The next bucket + */ +#define APR_BUCKET_NEXT(e) APR_RING_NEXT((e), link) +/** + * Get the previous bucket in the list + * @param e The current bucket + * @return The previous bucket + */ +#define APR_BUCKET_PREV(e) APR_RING_PREV((e), link) + +/** + * Remove a bucket from its bucket brigade + * @param e The bucket to remove + */ +#define APR_BUCKET_REMOVE(e) APR_RING_REMOVE((e), link) + +/** + * Initialize a new bucket's prev/next pointers + * @param e The bucket to initialize + */ +#define APR_BUCKET_INIT(e) APR_RING_ELEM_INIT((e), link) + +/** + * Determine if a bucket contains metadata. An empty bucket is + * safe to arbitrarily remove if and only if this is false. + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_METADATA(e) ((e)->type->is_metadata) + +/** + * Determine if a bucket is a FLUSH bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_FLUSH(e) ((e)->type == &apr_bucket_type_flush) +/** + * Determine if a bucket is an EOS bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_EOS(e) ((e)->type == &apr_bucket_type_eos) +/** + * Determine if a bucket is a FILE bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_FILE(e) ((e)->type == &apr_bucket_type_file) +/** + * Determine if a bucket is a PIPE bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_PIPE(e) ((e)->type == &apr_bucket_type_pipe) +/** + * Determine if a bucket is a SOCKET bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_SOCKET(e) ((e)->type == &apr_bucket_type_socket) +/** + * Determine if a bucket is a HEAP bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_HEAP(e) ((e)->type == &apr_bucket_type_heap) +/** + * Determine if a bucket is a TRANSIENT bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_TRANSIENT(e) ((e)->type == &apr_bucket_type_transient) +/** + * Determine if a bucket is a IMMORTAL bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_IMMORTAL(e) ((e)->type == &apr_bucket_type_immortal) +#if APR_HAS_MMAP +/** + * Determine if a bucket is a MMAP bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_MMAP(e) ((e)->type == &apr_bucket_type_mmap) +#endif +/** + * Determine if a bucket is a POOL bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_POOL(e) ((e)->type == &apr_bucket_type_pool) + +/* + * General-purpose reference counting for the various bucket types. + * + * Any bucket type that keeps track of the resources it uses (i.e. + * most of them except for IMMORTAL, TRANSIENT, and EOS) needs to + * attach a reference count to the resource so that it can be freed + * when the last bucket that uses it goes away. Resource-sharing may + * occur because of bucket splits or buckets that refer to globally + * cached data. */ + +/** @see apr_bucket_refcount */ +typedef struct apr_bucket_refcount apr_bucket_refcount; +/** + * The structure used to manage the shared resource must start with an + * apr_bucket_refcount which is updated by the general-purpose refcount + * code. A pointer to the bucket-type-dependent private data structure + * can be cast to a pointer to an apr_bucket_refcount and vice versa. + */ +struct apr_bucket_refcount { + /** The number of references to this bucket */ + int refcount; +}; + +/* ***** Reference-counted bucket types ***** */ + +/** @see apr_bucket_heap */ +typedef struct apr_bucket_heap apr_bucket_heap; +/** + * A bucket referring to data allocated off the heap. + */ +struct apr_bucket_heap { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The start of the data actually allocated. This should never be + * modified, it is only used to free the bucket. + */ + char *base; + /** how much memory was allocated */ + apr_size_t alloc_len; + /** function to use to delete the data */ + void (*free_func)(void *data); +}; + +/** @see apr_bucket_pool */ +typedef struct apr_bucket_pool apr_bucket_pool; +/** + * A bucket referring to data allocated from a pool + */ +struct apr_bucket_pool { + /** The pool bucket must be able to be easily morphed to a heap + * bucket if the pool gets cleaned up before all references are + * destroyed. This apr_bucket_heap structure is populated automatically + * when the pool gets cleaned up, and subsequent calls to pool_read() + * will result in the apr_bucket in question being morphed into a + * regular heap bucket. (To avoid having to do many extra refcount + * manipulations and b->data manipulations, the apr_bucket_pool + * struct actually *contains* the apr_bucket_heap struct that it + * will become as its first element; the two share their + * apr_bucket_refcount members.) + */ + apr_bucket_heap heap; + /** The block of data actually allocated from the pool. + * Segments of this block are referenced by adjusting + * the start and length of the apr_bucket accordingly. + * This will be NULL after the pool gets cleaned up. + */ + const char *base; + /** The pool the data was allocated from. When the pool + * is cleaned up, this gets set to NULL as an indicator + * to pool_read() that the data is now on the heap and + * so it should morph the bucket into a regular heap + * bucket before continuing. + */ + apr_pool_t *pool; + /** The freelist this structure was allocated from, which is + * needed in the cleanup phase in order to allocate space on the heap + */ + apr_bucket_alloc_t *list; +}; + +#if APR_HAS_MMAP +/** @see apr_bucket_mmap */ +typedef struct apr_bucket_mmap apr_bucket_mmap; +/** + * A bucket referring to an mmap()ed file + */ +struct apr_bucket_mmap { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The mmap this sub_bucket refers to */ + apr_mmap_t *mmap; +}; +#endif + +/** @see apr_bucket_file */ +typedef struct apr_bucket_file apr_bucket_file; +/** + * A bucket referring to an file + */ +struct apr_bucket_file { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The file this bucket refers to */ + apr_file_t *fd; + /** The pool into which any needed structures should + * be created while reading from this file bucket */ + apr_pool_t *readpool; +#if APR_HAS_MMAP + /** Whether this bucket should be memory-mapped if + * a caller tries to read from it */ + int can_mmap; +#endif /* APR_HAS_MMAP */ +}; + +/** @see apr_bucket_structs */ +typedef union apr_bucket_structs apr_bucket_structs; +/** + * A union of all bucket structures so we know what + * the max size is. + */ +union apr_bucket_structs { + apr_bucket b; /**< Bucket */ + apr_bucket_heap heap; /**< Heap */ + apr_bucket_pool pool; /**< Pool */ +#if APR_HAS_MMAP + apr_bucket_mmap mmap; /**< MMap */ +#endif + apr_bucket_file file; /**< File */ +}; + +/** + * The amount that apr_bucket_alloc() should allocate in the common case. + * Note: this is twice as big as apr_bucket_structs to allow breathing + * room for third-party bucket types. + */ +#define APR_BUCKET_ALLOC_SIZE APR_ALIGN_DEFAULT(2*sizeof(apr_bucket_structs)) + +/* ***** Bucket Brigade Functions ***** */ +/** + * Create a new bucket brigade. The bucket brigade is originally empty. + * @param p The pool to associate with the brigade. Data is not allocated out + * of the pool, but a cleanup is registered. + * @param list The bucket allocator to use + * @return The empty bucket brigade + */ +APU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p, + apr_bucket_alloc_t *list); + +/** + * destroy an entire bucket brigade. This includes destroying all of the + * buckets within the bucket brigade's bucket list. + * @param b The bucket brigade to destroy + */ +APU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b); + +/** + * empty out an entire bucket brigade. This includes destroying all of the + * buckets within the bucket brigade's bucket list. This is similar to + * apr_brigade_destroy(), except that it does not deregister the brigade's + * pool cleanup function. + * @param data The bucket brigade to clean up + * @remark Generally, you should use apr_brigade_destroy(). This function + * can be useful in situations where you have a single brigade that + * you wish to reuse many times by destroying all of the buckets in + * the brigade and putting new buckets into it later. + */ +APU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data); + +/** + * Move the buckets from the tail end of the existing brigade @param b into + * the brigade @param a. If @param a is NULL a new brigade is created. Buckets + * from @param e to the last bucket (inclusively) of brigade @param b are moved + * from @param b to the returned brigade @param a. + * @param b The brigade to split + * @param e The first bucket to move + * @param a The brigade which should be used for the result or NULL if + * a new brigade should be created. + * @return The brigade supplied in @param a or a new one if @param a was NULL. + * @warning Note that this function allocates a new brigade if @param a is + * NULL so memory consumption should be carefully considered. + */ +APU_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b, + apr_bucket *e, + apr_bucket_brigade *a); + +/** + * Create a new bucket brigade and move the buckets from the tail end + * of an existing brigade into the new brigade. Buckets from + * @param e to the last bucket (inclusively) of brigade @param b + * are moved from @param b to the returned brigade. + * @param b The brigade to split + * @param e The first bucket to move + * @return The new brigade + * @warning Note that this function always allocates a new brigade + * so memory consumption should be carefully considered. + */ +APU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b, + apr_bucket *e); + +/** + * Partition a bucket brigade at a given offset (in bytes from the start of + * the brigade). This is useful whenever a filter wants to use known ranges + * of bytes from the brigade; the ranges can even overlap. + * @param b The brigade to partition + * @param point The offset at which to partition the brigade + * @param after_point Returns a pointer to the first bucket after the partition + * @return APR_SUCCESS on success, APR_INCOMPLETE if the contents of the + * brigade were shorter than @a point, or an error code. + * @remark if APR_INCOMPLETE is returned, @a after_point will be set to + * the brigade sentinel. + */ +APU_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b, + apr_off_t point, + apr_bucket **after_point); + +/** + * Return the total length of the brigade. + * @param bb The brigade to compute the length of + * @param read_all Read unknown-length buckets to force a size + * @param length Returns the length of the brigade (up to the end, or up + * to a bucket read error), or -1 if the brigade has buckets + * of indeterminate length and read_all is 0. + */ +APU_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb, + int read_all, + apr_off_t *length); + +/** + * Take a bucket brigade and store the data in a flat char* + * @param bb The bucket brigade to create the char* from + * @param c The char* to write into + * @param len The maximum length of the char array. On return, it is the + * actual length of the char array. + */ +APU_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb, + char *c, + apr_size_t *len); + +/** + * Creates a pool-allocated string representing a flat bucket brigade + * @param bb The bucket brigade to create the char array from + * @param c On return, the allocated char array + * @param len On return, the length of the char array. + * @param pool The pool to allocate the string from. + */ +APU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb, + char **c, + apr_size_t *len, + apr_pool_t *pool); + +/** + * Split a brigade to represent one LF line. + * @param bbOut The bucket brigade that will have the LF line appended to. + * @param bbIn The input bucket brigade to search for a LF-line. + * @param block The blocking mode to be used to split the line. + * @param maxbytes The maximum bytes to read. If this many bytes are seen + * without a LF, the brigade will contain a partial line. + */ +APU_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut, + apr_bucket_brigade *bbIn, + apr_read_type_e block, + apr_off_t maxbytes); + +/** + * create an iovec of the elements in a bucket_brigade... return number + * of elements used. This is useful for writing to a file or to the + * network efficiently. + * @param b The bucket brigade to create the iovec from + * @param vec The iovec to create + * @param nvec The number of elements in the iovec. On return, it is the + * number of iovec elements actually filled out. + */ +APU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, + struct iovec *vec, int *nvec); + +/** + * This function writes a list of strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param va A list of strings to add + * @return APR_SUCCESS or error code. + */ +APU_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + va_list va); + +/** + * This function writes a string into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param str The string to add + * @param nbyte The number of bytes to write + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char *str, apr_size_t nbyte); + +/** + * This function writes multiple strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param vec The strings to add (address plus length for each) + * @param nvec The number of entries in iovec + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const struct iovec *vec, + apr_size_t nvec); + +/** + * This function writes a string into a bucket brigade. + * @param bb The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param str The string to add + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb, + apr_brigade_flush flush, void *ctx, + const char *str); + +/** + * This function writes a character into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param c The character to add + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char c); + +/** + * This function writes an unspecified number of strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param ... The strings to add + * @return APR_SUCCESS or error code + */ +APU_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, ...); + +/** + * Evaluate a printf and put the resulting string at the end + * of the bucket brigade. + * @param b The brigade to write to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param fmt The format of the string to write + * @param ... The arguments to fill out the format + * @return APR_SUCCESS or error code + */ +APU_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, ...) + __attribute__((format(printf,4,5))); + +/** + * Evaluate a printf and put the resulting string at the end + * of the bucket brigade. + * @param b The brigade to write to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param fmt The format of the string to write + * @param va The arguments to fill out the format + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, va_list va); + +/** + * Utility function to insert a file (or a segment of a file) onto the + * end of the brigade. The file is split into multiple buckets if it + * is larger than the maximum size which can be represented by a + * single bucket. + * @param bb the brigade to insert into + * @param f the file to insert + * @param start the offset of the start of the segment + * @param len the length of the segment of the file to insert + * @param p pool from which file buckets are allocated + * @return the last bucket inserted + */ +APU_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb, + apr_file_t *f, + apr_off_t start, + apr_off_t len, + apr_pool_t *p); + + + +/* ***** Bucket freelist functions ***** */ +/** + * Create a bucket allocator. + * @param p This pool's underlying apr_allocator_t is used to allocate memory + * for the bucket allocator. When the pool is destroyed, the bucket + * allocator's cleanup routine will free all memory that has been + * allocated from it. + * @remark The reason the allocator gets its memory from the pool's + * apr_allocator_t rather than from the pool itself is because + * the bucket allocator will free large memory blocks back to the + * allocator when it's done with them, thereby preventing memory + * footprint growth that would occur if we allocated from the pool. + * @warning The allocator must never be used by more than one thread at a time. + */ +APU_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create(apr_pool_t *p); + +/** + * Create a bucket allocator. + * @param allocator This apr_allocator_t is used to allocate both the bucket + * allocator and all memory handed out by the bucket allocator. The + * caller is responsible for destroying the bucket allocator and the + * apr_allocator_t -- no automatic cleanups will happen. + * @warning The allocator must never be used by more than one thread at a time. + */ +APU_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create_ex(apr_allocator_t *allocator); + +/** + * Destroy a bucket allocator. + * @param list The allocator to be destroyed + */ +APU_DECLARE_NONSTD(void) apr_bucket_alloc_destroy(apr_bucket_alloc_t *list); + +/** + * Allocate memory for use by the buckets. + * @param size The amount to allocate. + * @param list The allocator from which to allocate the memory. + */ +APU_DECLARE_NONSTD(void *) apr_bucket_alloc(apr_size_t size, apr_bucket_alloc_t *list); + +/** + * Free memory previously allocated with apr_bucket_alloc(). + * @param block The block of memory to be freed. + */ +APU_DECLARE_NONSTD(void) apr_bucket_free(void *block); + + +/* ***** Bucket Functions ***** */ +/** + * Free the resources used by a bucket. If multiple buckets refer to + * the same resource it is freed when the last one goes away. + * @see apr_bucket_delete() + * @param e The bucket to destroy + */ +#define apr_bucket_destroy(e) do { \ + (e)->type->destroy((e)->data); \ + (e)->free(e); \ + } while (0) + +/** + * Delete a bucket by removing it from its brigade (if any) and then + * destroying it. + * @remark This mainly acts as an aid in avoiding code verbosity. It is + * the preferred exact equivalent to: + *
+ *      APR_BUCKET_REMOVE(e);
+ *      apr_bucket_destroy(e);
+ * 
+ * @param e The bucket to delete + */ +#define apr_bucket_delete(e) do { \ + APR_BUCKET_REMOVE(e); \ + apr_bucket_destroy(e); \ + } while (0) + +/** + * Read the data from the bucket. + * + * If it is not practical to return all + * the data in the bucket, the current bucket is split and replaced by + * two buckets, the first representing the data returned in this call, + * and the second representing the rest of the data as yet unread. The + * original bucket will become the first bucket after this call. + * + * (It is assumed that the bucket is a member of a brigade when this + * function is called). + * @param e The bucket to read from + * @param str The location to store the data in + * @param len The amount of data read + * @param block Whether the read function blocks + */ +#define apr_bucket_read(e,str,len,block) (e)->type->read(e, str, len, block) + +/** + * Setaside data so that stack data is not destroyed on returning from + * the function + * @param e The bucket to setaside + * @param p The pool to setaside into + */ +#define apr_bucket_setaside(e,p) (e)->type->setaside(e,p) + +/** + * Split one bucket in two at the point provided. + * + * Once split, the original bucket becomes the first of the two new buckets. + * + * (It is assumed that the bucket is a member of a brigade when this + * function is called). + * @param e The bucket to split + * @param point The offset to split the bucket at + */ +#define apr_bucket_split(e,point) (e)->type->split(e, point) + +/** + * Copy a bucket. + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + */ +#define apr_bucket_copy(e,c) (e)->type->copy(e, c) + +/* Bucket type handling */ + +/** + * This function simply returns APR_SUCCESS to denote that the bucket does + * not require anything to happen for its setaside() function. This is + * appropriate for buckets that have "immortal" data -- the data will live + * at least as long as the bucket. + * @param data The bucket to setaside + * @param pool The pool defining the desired lifetime of the bucket data + * @return APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_noop(apr_bucket *data, + apr_pool_t *pool); + +/** + * A place holder function that signifies that the setaside function was not + * implemented for this bucket + * @param data The bucket to setaside + * @param pool The pool defining the desired lifetime of the bucket data + * @return APR_ENOTIMPL + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_notimpl(apr_bucket *data, + apr_pool_t *pool); + +/** + * A place holder function that signifies that the split function was not + * implemented for this bucket + * @param data The bucket to split + * @param point The location to split the bucket + * @return APR_ENOTIMPL + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_split_notimpl(apr_bucket *data, + apr_size_t point); + +/** + * A place holder function that signifies that the copy function was not + * implemented for this bucket + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + * @return APR_ENOTIMPL + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_copy_notimpl(apr_bucket *e, + apr_bucket **c); + +/** + * A place holder function that signifies that this bucket does not need + * to do anything special to be destroyed. That's only the case for buckets + * that either have no data (metadata buckets) or buckets whose data pointer + * points to something that's not a bucket-type-specific structure, as with + * simple buckets where data points to a string and pipe buckets where data + * points directly to the apr_file_t. + * @param data The bucket data to destroy + */ +APU_DECLARE_NONSTD(void) apr_bucket_destroy_noop(void *data); + +/** + * There is no apr_bucket_destroy_notimpl, because destruction is required + * to be implemented (it could be a noop, but only if that makes sense for + * the bucket type) + */ + +/* There is no apr_bucket_read_notimpl, because it is a required function + */ + + +/* All of the bucket types implemented by the core */ +/** + * The flush bucket type. This signifies that all data should be flushed to + * the next filter. The flush bucket should be sent with the other buckets. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_flush; +/** + * The EOS bucket type. This signifies that there will be no more data, ever. + * All filters MUST send all data to the next filter when they receive a + * bucket of this type + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_eos; +/** + * The FILE bucket type. This bucket represents a file on disk + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_file; +/** + * The HEAP bucket type. This bucket represents a data allocated from the + * heap. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_heap; +#if APR_HAS_MMAP +/** + * The MMAP bucket type. This bucket represents an MMAP'ed file + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_mmap; +#endif +/** + * The POOL bucket type. This bucket represents a data that was allocated + * from a pool. IF this bucket is still available when the pool is cleared, + * the data is copied on to the heap. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pool; +/** + * The PIPE bucket type. This bucket represents a pipe to another program. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pipe; +/** + * The IMMORTAL bucket type. This bucket represents a segment of data that + * the creator is willing to take responsibility for. The core will do + * nothing with the data in an immortal bucket + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_immortal; +/** + * The TRANSIENT bucket type. This bucket represents a data allocated off + * the stack. When the setaside function is called, this data is copied on + * to the heap + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_transient; +/** + * The SOCKET bucket type. This bucket represents a socket to another machine + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_socket; + + +/* ***** Simple buckets ***** */ + +/** + * Split a simple bucket into two at the given point. Most non-reference + * counting buckets that allow multiple references to the same block of + * data (eg transient and immortal) will use this as their split function + * without any additional type-specific handling. + * @param b The bucket to be split + * @param point The offset of the first byte in the new bucket + * @return APR_EINVAL if the point is not within the bucket; + * APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_split(apr_bucket *b, + apr_size_t point); + +/** + * Copy a simple bucket. Most non-reference-counting buckets that allow + * multiple references to the same block of data (eg transient and immortal) + * will use this as their copy function without any additional type-specific + * handling. + * @param a The bucket to copy + * @param b Returns a pointer to the new bucket + * @return APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_copy(apr_bucket *a, + apr_bucket **b); + + +/* ***** Shared, reference-counted buckets ***** */ + +/** + * Initialize a bucket containing reference-counted data that may be + * shared. The caller must allocate the bucket if necessary and + * initialize its type-dependent fields, and allocate and initialize + * its own private data structure. This function should only be called + * by type-specific bucket creation functions. + * @param b The bucket to initialize + * @param data A pointer to the private data structure + * with the reference count at the start + * @param start The start of the data in the bucket + * relative to the private base pointer + * @param length The length of the data in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_shared_make(apr_bucket *b, void *data, + apr_off_t start, + apr_size_t length); + +/** + * Decrement the refcount of the data in the bucket. This function + * should only be called by type-specific bucket destruction functions. + * @param data The private data pointer from the bucket to be destroyed + * @return TRUE or FALSE; TRUE if the reference count is now + * zero, indicating that the shared resource itself can + * be destroyed by the caller. + */ +APU_DECLARE(int) apr_bucket_shared_destroy(void *data); + +/** + * Split a bucket into two at the given point, and adjust the refcount + * to the underlying data. Most reference-counting bucket types will + * be able to use this function as their split function without any + * additional type-specific handling. + * @param b The bucket to be split + * @param point The offset of the first byte in the new bucket + * @return APR_EINVAL if the point is not within the bucket; + * APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_split(apr_bucket *b, + apr_size_t point); + +/** + * Copy a refcounted bucket, incrementing the reference count. Most + * reference-counting bucket types will be able to use this function + * as their copy function without any additional type-specific handling. + * @param a The bucket to copy + * @param b Returns a pointer to the new bucket + * @return APR_ENOMEM if allocation failed; + or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_copy(apr_bucket *a, + apr_bucket **b); + + +/* ***** Functions to Create Buckets of varying types ***** */ +/* + * Each bucket type foo has two initialization functions: + * apr_bucket_foo_make which sets up some already-allocated memory as a + * bucket of type foo; and apr_bucket_foo_create which allocates memory + * for the bucket, calls apr_bucket_make_foo, and initializes the + * bucket's list pointers. The apr_bucket_foo_make functions are used + * inside the bucket code to change the type of buckets in place; + * other code should call apr_bucket_foo_create. All the initialization + * functions change nothing if they fail. + */ + +/** + * Create an End of Stream bucket. This indicates that there is no more data + * coming from down the filter stack. All filters should flush at this point. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_eos_create(apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in an EOS bucket. This indicates that there is no + * more data coming from down the filter stack. All filters should flush at + * this point. + * @param b The bucket to make into an EOS bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_eos_make(apr_bucket *b); + +/** + * Create a flush bucket. This indicates that filters should flush their + * data. There is no guarantee that they will flush it, but this is the + * best we can do. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_flush_create(apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a FLUSH bucket. This indicates that filters + * should flush their data. There is no guarantee that they will flush it, + * but this is the best we can do. + * @param b The bucket to make into a FLUSH bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_flush_make(apr_bucket *b); + +/** + * Create a bucket referring to long-lived data. + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_immortal_create(const char *buf, + apr_size_t nbyte, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to long-lived data + * @param b The bucket to make into a IMMORTAL bucket + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_immortal_make(apr_bucket *b, + const char *buf, + apr_size_t nbyte); + +/** + * Create a bucket referring to data on the stack. + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_transient_create(const char *buf, + apr_size_t nbyte, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to stack data + * @param b The bucket to make into a TRANSIENT bucket + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_transient_make(apr_bucket *b, + const char *buf, + apr_size_t nbyte); + +/** + * Create a bucket referring to memory on the heap. If the caller asks + * for the data to be copied, this function always allocates 4K of + * memory so that more data can be added to the bucket without + * requiring another allocation. Therefore not all the data may be put + * into the bucket. If copying is not requested then the bucket takes + * over responsibility for free()ing the memory. + * @param buf The buffer to insert into the bucket + * @param nbyte The size of the buffer to insert. + * @param free_func Function to use to free the data; NULL indicates that the + * bucket should make a copy of the data + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_heap_create(const char *buf, + apr_size_t nbyte, + void (*free_func)(void *data), + apr_bucket_alloc_t *list); +/** + * Make the bucket passed in a bucket refer to heap data + * @param b The bucket to make into a HEAP bucket + * @param buf The buffer to insert into the bucket + * @param nbyte The size of the buffer to insert. + * @param free_func Function to use to free the data; NULL indicates that the + * bucket should make a copy of the data + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_heap_make(apr_bucket *b, const char *buf, + apr_size_t nbyte, + void (*free_func)(void *data)); + +/** + * Create a bucket referring to memory allocated from a pool. + * + * @param buf The buffer to insert into the bucket + * @param length The number of bytes referred to by this bucket + * @param pool The pool the memory was allocated from + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf, + apr_size_t length, + apr_pool_t *pool, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to pool data + * @param b The bucket to make into a pool bucket + * @param buf The buffer to insert into the bucket + * @param length The number of bytes referred to by this bucket + * @param pool The pool the memory was allocated from + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b, const char *buf, + apr_size_t length, + apr_pool_t *pool); + +#if APR_HAS_MMAP +/** + * Create a bucket referring to mmap()ed memory. + * @param mm The mmap to insert into the bucket + * @param start The offset of the first byte in the mmap + * that this bucket refers to + * @param length The number of bytes referred to by this bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm, + apr_off_t start, + apr_size_t length, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to an MMAP'ed file + * @param b The bucket to make into a MMAP bucket + * @param mm The mmap to insert into the bucket + * @param start The offset of the first byte in the mmap + * that this bucket refers to + * @param length The number of bytes referred to by this bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm, + apr_off_t start, + apr_size_t length); +#endif + +/** + * Create a bucket referring to a socket. + * @param thissock The socket to put in the bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_socket_create(apr_socket_t *thissock, + apr_bucket_alloc_t *list); +/** + * Make the bucket passed in a bucket refer to a socket + * @param b The bucket to make into a SOCKET bucket + * @param thissock The socket to put in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_socket_make(apr_bucket *b, + apr_socket_t *thissock); + +/** + * Create a bucket referring to a pipe. + * @param thispipe The pipe to put in the bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pipe_create(apr_file_t *thispipe, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to a pipe + * @param b The bucket to make into a PIPE bucket + * @param thispipe The pipe to put in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pipe_make(apr_bucket *b, + apr_file_t *thispipe); + +/** + * Create a bucket referring to a file. + * @param fd The file to put in the bucket + * @param offset The offset where the data of interest begins in the file + * @param len The amount of data in the file we are interested in + * @param p The pool into which any needed structures should be created + * while reading from this file bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + * @remark If the file is truncated such that the segment of the file + * referenced by the bucket no longer exists, an attempt to read + * from the bucket will fail with APR_EOF. + * @remark apr_brigade_insert_file() should generally be used to + * insert files into brigades, since that function can correctly + * handle large file issues. + */ +APU_DECLARE(apr_bucket *) apr_bucket_file_create(apr_file_t *fd, + apr_off_t offset, + apr_size_t len, + apr_pool_t *p, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to a file + * @param b The bucket to make into a FILE bucket + * @param fd The file to put in the bucket + * @param offset The offset where the data of interest begins in the file + * @param len The amount of data in the file we are interested in + * @param p The pool into which any needed structures should be created + * while reading from this file bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_file_make(apr_bucket *b, apr_file_t *fd, + apr_off_t offset, + apr_size_t len, apr_pool_t *p); + +/** + * Enable or disable memory-mapping for a FILE bucket (default is enabled) + * @param b The bucket + * @param enabled Whether memory-mapping should be enabled + * @return APR_SUCCESS normally, or an error code if the operation fails + */ +APU_DECLARE(apr_status_t) apr_bucket_file_enable_mmap(apr_bucket *b, + int enabled); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_BUCKETS_H */ diff --git a/include/apr-linux/apr_date.h b/include/apr-linux/apr_date.h new file mode 100644 index 0000000..b098b54 --- /dev/null +++ b/include/apr-linux/apr_date.h @@ -0,0 +1,106 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_DATE_H +#define APR_DATE_H + +/** + * @file apr_date.h + * @brief APR-UTIL date routines + */ + +/** + * @defgroup APR_Util_Date Date routines + * @ingroup APR_Util + * @{ + */ + +/* + * apr_date.h: prototypes for date parsing utility routines + */ + +#include "apu.h" +#include "apr_time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A bad date. */ +#define APR_DATE_BAD ((apr_time_t)0) + +/** + * Compare a string to a mask + * @param data The string to compare + * @param mask Mask characters (arbitrary maximum is 256 characters): + *
+ *   '\@' - uppercase letter
+ *   '\$' - lowercase letter
+ *   '\&' - hex digit
+ *   '#' - digit
+ *   '~' - digit or space
+ *   '*' - swallow remaining characters
+ * 
+ * @remark The mask tests for an exact match for any other character + * @return 1 if the string matches, 0 otherwise + */ +APU_DECLARE(int) apr_date_checkmask(const char *data, const char *mask); + +/** + * Parses an HTTP date in one of three standard forms: + *
+ *     Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+ *     Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ *     Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+ * 
+ * @param date The date in one of the three formats above + * @return the apr_time_t number of microseconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + */ +APU_DECLARE(apr_time_t) apr_date_parse_http(const char *date); + +/** + * Parses a string resembling an RFC 822 date. This is meant to be + * leinent in its parsing of dates. Hence, this will parse a wider + * range of dates than apr_date_parse_http. + * + * The prominent mailer (or poster, if mailer is unknown) that has + * been seen in the wild is included for the unknown formats. + *
+ *     Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+ *     Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ *     Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+ *     Sun, 6 Nov 1994 08:49:37 GMT   ; RFC 822, updated by RFC 1123
+ *     Sun, 06 Nov 94 08:49:37 GMT    ; RFC 822
+ *     Sun, 6 Nov 94 08:49:37 GMT     ; RFC 822
+ *     Sun, 06 Nov 94 08:49 GMT       ; Unknown [drtr\@ast.cam.ac.uk] 
+ *     Sun, 6 Nov 94 08:49 GMT        ; Unknown [drtr\@ast.cam.ac.uk]
+ *     Sun, 06 Nov 94 8:49:37 GMT     ; Unknown [Elm 70.85]
+ *     Sun, 6 Nov 94 8:49:37 GMT      ; Unknown [Elm 70.85] 
+ * 
+ * + * @param date The date in one of the formats above + * @return the apr_time_t number of microseconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + */ +APU_DECLARE(apr_time_t) apr_date_parse_rfc(const char *date); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_DATE_H */ diff --git a/include/apr-linux/apr_dbd.h b/include/apr-linux/apr_dbd.h new file mode 100644 index 0000000..0e25d02 --- /dev/null +++ b/include/apr-linux/apr_dbd.h @@ -0,0 +1,551 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* Overview of what this is and does: + * http://www.apache.org/~niq/dbd.html + */ + +#ifndef APR_DBD_H +#define APR_DBD_H + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_dbd.h + * @brief APR-UTIL DBD library + */ +/** + * @defgroup APR_Util_DBD DBD routines + * @ingroup APR_Util + * @{ + */ + +/** + * Mapping of C to SQL types, used for prepared statements. + * @remarks + * For apr_dbd_p[v]query/select functions, in and out parameters are always + * const char * (i.e. regular nul terminated strings). LOB types are passed + * with four (4) arguments: payload, length, table and column, all as const + * char *, where table and column are reserved for future use by Oracle. + * @remarks + * For apr_dbd_p[v]bquery/select functions, in and out parameters are + * described next to each enumeration constant and are generally native binary + * types or some APR data type. LOB types are passed with four (4) arguments: + * payload (char*), length (apr_size_t*), table (char*) and column (char*). + * Table and column are reserved for future use by Oracle. + */ +typedef enum { + APR_DBD_TYPE_NONE, + APR_DBD_TYPE_TINY, /**< \%hhd : in, out: char* */ + APR_DBD_TYPE_UTINY, /**< \%hhu : in, out: unsigned char* */ + APR_DBD_TYPE_SHORT, /**< \%hd : in, out: short* */ + APR_DBD_TYPE_USHORT, /**< \%hu : in, out: unsigned short* */ + APR_DBD_TYPE_INT, /**< \%d : in, out: int* */ + APR_DBD_TYPE_UINT, /**< \%u : in, out: unsigned int* */ + APR_DBD_TYPE_LONG, /**< \%ld : in, out: long* */ + APR_DBD_TYPE_ULONG, /**< \%lu : in, out: unsigned long* */ + APR_DBD_TYPE_LONGLONG, /**< \%lld : in, out: apr_int64_t* */ + APR_DBD_TYPE_ULONGLONG, /**< \%llu : in, out: apr_uint64_t* */ + APR_DBD_TYPE_FLOAT, /**< \%f : in, out: float* */ + APR_DBD_TYPE_DOUBLE, /**< \%lf : in, out: double* */ + APR_DBD_TYPE_STRING, /**< \%s : in: char*, out: char** */ + APR_DBD_TYPE_TEXT, /**< \%pDt : in: char*, out: char** */ + APR_DBD_TYPE_TIME, /**< \%pDi : in: char*, out: char** */ + APR_DBD_TYPE_DATE, /**< \%pDd : in: char*, out: char** */ + APR_DBD_TYPE_DATETIME, /**< \%pDa : in: char*, out: char** */ + APR_DBD_TYPE_TIMESTAMP, /**< \%pDs : in: char*, out: char** */ + APR_DBD_TYPE_ZTIMESTAMP, /**< \%pDz : in: char*, out: char** */ + APR_DBD_TYPE_BLOB, /**< \%pDb : in: char* apr_size_t* char* char*, out: apr_bucket_brigade* */ + APR_DBD_TYPE_CLOB, /**< \%pDc : in: char* apr_size_t* char* char*, out: apr_bucket_brigade* */ + APR_DBD_TYPE_NULL /**< \%pDn : in: void*, out: void** */ +} apr_dbd_type_e; + +/* These are opaque structs. Instantiation is up to each backend */ +typedef struct apr_dbd_driver_t apr_dbd_driver_t; +typedef struct apr_dbd_t apr_dbd_t; +typedef struct apr_dbd_transaction_t apr_dbd_transaction_t; +typedef struct apr_dbd_results_t apr_dbd_results_t; +typedef struct apr_dbd_row_t apr_dbd_row_t; +typedef struct apr_dbd_prepared_t apr_dbd_prepared_t; + +/** apr_dbd_init: perform once-only initialisation. Call once only. + * + * @param pool - pool to register any shutdown cleanups, etc + */ +APU_DECLARE(apr_status_t) apr_dbd_init(apr_pool_t *pool); + +/** apr_dbd_get_driver: get the driver struct for a name + * + * @param pool - (process) pool to register cleanup + * @param name - driver name + * @param driver - pointer to driver struct. + * @return APR_SUCCESS for success + * @return APR_ENOTIMPL for no driver (when DSO not enabled) + * @return APR_EDSOOPEN if DSO driver file can't be opened + * @return APR_ESYMNOTFOUND if the driver file doesn't contain a driver + */ +APU_DECLARE(apr_status_t) apr_dbd_get_driver(apr_pool_t *pool, const char *name, + const apr_dbd_driver_t **driver); + +/** apr_dbd_open_ex: open a connection to a backend + * + * @param pool - working pool + * @param params - arguments to driver (implementation-dependent) + * @param handle - pointer to handle to return + * @param driver - driver struct. + * @param error - descriptive error. + * @return APR_SUCCESS for success + * @return APR_EGENERAL if driver exists but connection failed + * @remarks PostgreSQL: the params is passed directly to the PQconnectdb() + * function (check PostgreSQL documentation for more details on the syntax). + * @remarks SQLite2: the params is split on a colon, with the first part used + * as the filename and second part converted to an integer and used as file + * mode. + * @remarks SQLite3: the params is passed directly to the sqlite3_open() + * function as a filename to be opened (check SQLite3 documentation for more + * details). + * @remarks Oracle: the params can have "user", "pass", "dbname" and "server" + * keys, each followed by an equal sign and a value. Such key/value pairs can + * be delimited by space, CR, LF, tab, semicolon, vertical bar or comma. + * @remarks MySQL: the params can have "host", "port", "user", "pass", + * "dbname", "sock", "flags" "fldsz" and "group" keys, each followed by an + * equal sign and a value. Such key/value pairs can be delimited by space, + * CR, LF, tab, semicolon, vertical bar or comma. For now, "flags" can only + * recognise CLIENT_FOUND_ROWS (check MySQL manual for details). The value + * associated with "fldsz" determines maximum amount of memory (in bytes) for + * each of the fields in the result set of prepared statements. By default, + * this value is 1 MB. The value associated with "group" determines which + * group from configuration file to use (see MYSQL_READ_DEFAULT_GROUP option + * of mysql_options() in MySQL manual). + * @remarks FreeTDS: the params can have "username", "password", "appname", + * "dbname", "host", "charset", "lang" and "server" keys, each followed by an + * equal sign and a value. + */ +APU_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *params, + apr_dbd_t **handle, + const char **error); + +/** apr_dbd_open: open a connection to a backend + * + * @param pool - working pool + * @param params - arguments to driver (implementation-dependent) + * @param handle - pointer to handle to return + * @param driver - driver struct. + * @return APR_SUCCESS for success + * @return APR_EGENERAL if driver exists but connection failed + * @see apr_dbd_open_ex + */ +APU_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *params, + apr_dbd_t **handle); + +/** apr_dbd_close: close a connection to a backend + * + * @param handle - handle to close + * @param driver - driver struct. + * @return APR_SUCCESS for success or error status + */ +APU_DECLARE(apr_status_t) apr_dbd_close(const apr_dbd_driver_t *driver, + apr_dbd_t *handle); + +/* apr-function-shaped versions of things */ + +/** apr_dbd_name: get the name of the driver + * + * @param driver - the driver + * @return - name + */ +APU_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t *driver); + +/** apr_dbd_native_handle: get native database handle of the underlying db + * + * @param driver - the driver + * @param handle - apr_dbd handle + * @return - native handle + */ +APU_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t *driver, + apr_dbd_t *handle); + +/** check_conn: check status of a database connection + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection to check + * @return APR_SUCCESS or error + */ +APU_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle); + +/** apr_dbd_set_dbname: select database name. May be a no-op if not supported. + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param name - the database to select + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, const char *name); + +/** apr_dbd_transaction_start: start a transaction. May be a no-op. + * + * @param driver - the driver + * @param pool - a pool to use for error messages (if any). + * @param handle - the db connection + * @param trans - ptr to a transaction. May be null on entry + * @return 0 for success or error code + * @remarks Note that transaction modes, set by calling + * apr_dbd_transaction_mode_set(), will affect all query/select calls within + * a transaction. By default, any error in query/select during a transaction + * will cause the transaction to inherit the error code and any further + * query/select calls will fail immediately. Put transaction in "ignore + * errors" mode to avoid that. Use "rollback" mode to do explicit rollback. + */ +APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, + apr_dbd_transaction_t **trans); + +/** apr_dbd_transaction_end: end a transaction + * (commit on success, rollback on error). + * May be a no-op. + * + * @param driver - the driver + * @param handle - the db connection + * @param trans - the transaction. + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_transaction_t *trans); + +#define APR_DBD_TRANSACTION_COMMIT 0x00 /**< commit the transaction */ +#define APR_DBD_TRANSACTION_ROLLBACK 0x01 /**< rollback the transaction */ +#define APR_DBD_TRANSACTION_IGNORE_ERRORS 0x02 /**< ignore transaction errors */ + +/** apr_dbd_transaction_mode_get: get the mode of transaction + * + * @param driver - the driver + * @param trans - the transaction + * @return mode of transaction + */ +APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *driver, + apr_dbd_transaction_t *trans); + +/** apr_dbd_transaction_mode_set: set the mode of transaction + * + * @param driver - the driver + * @param trans - the transaction + * @param mode - new mode of the transaction + * @return the mode of transaction in force after the call + */ +APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *driver, + apr_dbd_transaction_t *trans, + int mode); + +/** apr_dbd_query: execute an SQL query that doesn't return a result set + * + * @param driver - the driver + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the SQL statement to execute + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t *driver, apr_dbd_t *handle, + int *nrows, const char *statement); + +/** apr_dbd_select: execute an SQL query that returns a result set + * + * @param driver - the driver + * @param pool - pool to allocate the result set + * @param handle - the connection + * @param res - pointer to result set pointer. May point to NULL on entry + * @param statement - the SQL statement to execute + * @param random - 1 to support random access to results (seek any row); + * 0 to support only looping through results in order + * (async access - faster) + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + const char *statement, int random); + +/** apr_dbd_num_cols: get the number of columns in a results set + * + * @param driver - the driver + * @param res - result set. + * @return number of columns + */ +APU_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res); + +/** apr_dbd_num_tuples: get the number of rows in a results set + * of a synchronous select + * + * @param driver - the driver + * @param res - result set. + * @return number of rows, or -1 if the results are asynchronous + */ +APU_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res); + +/** apr_dbd_get_row: get a row from a result set + * + * @param driver - the driver + * @param pool - pool to allocate the row + * @param res - result set pointer + * @param row - pointer to row pointer. May point to NULL on entry + * @param rownum - row number (counting from 1), or -1 for "next row". + * Ignored if random access is not supported. + * @return 0 for success, -1 for rownum out of range or data finished + */ +APU_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_results_t *res, apr_dbd_row_t **row, + int rownum); + +/** apr_dbd_get_entry: get an entry from a row + * + * @param driver - the driver + * @param row - row pointer + * @param col - entry number + * @return value from the row, or NULL if col is out of bounds. + */ +APU_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col); + +/** apr_dbd_get_name: get an entry name from a result set + * + * @param driver - the driver + * @param res - result set pointer + * @param col - entry number + * @return name of the entry, or NULL if col is out of bounds. + */ +APU_DECLARE(const char*) apr_dbd_get_name(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res, int col); + + +/** apr_dbd_error: get current error message (if any) + * + * @param driver - the driver + * @param handle - the connection + * @param errnum - error code from operation that returned an error + * @return the database current error message, or message for errnum + * (implementation-dependent whether errnum is ignored) + */ +APU_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t *driver, + apr_dbd_t *handle, int errnum); + +/** apr_dbd_escape: escape a string so it is safe for use in query/select + * + * @param driver - the driver + * @param pool - pool to alloc the result from + * @param string - the string to escape + * @param handle - the connection + * @return the escaped, safe string + */ +APU_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *string, + apr_dbd_t *handle); + +/** apr_dbd_prepare: prepare a statement + * + * @param driver - the driver + * @param pool - pool to alloc the result from + * @param handle - the connection + * @param query - the SQL query + * @param label - A label for the prepared statement. + * use NULL for temporary prepared statements + * (eg within a Request in httpd) + * @param statement - statement to prepare. May point to null on entry. + * @return 0 for success or error code + * @remarks To specify parameters of the prepared query, use \%s, \%d etc. + * (see below for full list) in place of database specific parameter syntax + * (e.g. for PostgreSQL, this would be $1, $2, for SQLite3 this would be ? + * etc.). For instance: "SELECT name FROM customers WHERE name=%s" would be + * a query that this function understands. + * @remarks Here is the full list of format specifiers that this function + * understands and what they map to in SQL: \%hhd (TINY INT), \%hhu (UNSIGNED + * TINY INT), \%hd (SHORT), \%hu (UNSIGNED SHORT), \%d (INT), \%u (UNSIGNED + * INT), \%ld (LONG), \%lu (UNSIGNED LONG), \%lld (LONG LONG), \%llu + * (UNSIGNED LONG LONG), \%f (FLOAT, REAL), \%lf (DOUBLE PRECISION), \%s + * (VARCHAR), \%pDt (TEXT), \%pDi (TIME), \%pDd (DATE), \%pDa (DATETIME), + * \%pDs (TIMESTAMP), \%pDz (TIMESTAMP WITH TIME ZONE), \%pDb (BLOB), \%pDc + * (CLOB) and \%pDn (NULL). Not all databases have support for all these + * types, so the underlying driver will attempt the "best match" where + * possible. A \% followed by any letter not in the above list will be + * interpreted as VARCHAR (i.e. \%s). + */ +APU_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, const char *query, + const char *label, + apr_dbd_prepared_t **statement); + + +/** apr_dbd_pquery: query using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param nargs - ignored (for backward compatibility only) + * @param args - args to prepared statement + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, int nargs, + const char **args); + +/** apr_dbd_pselect: select using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param nargs - ignored (for backward compatibility only) + * @param args - args to prepared statement + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + int nargs, const char **args); + +/** apr_dbd_pvquery: query using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param ... - varargs list + * @return 0 for success or error code + */ +APU_DECLARE_NONSTD(int) apr_dbd_pvquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...); + +/** apr_dbd_pvselect: select using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param ... - varargs list + * @return 0 for success or error code + */ +APU_DECLARE_NONSTD(int) apr_dbd_pvselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, ...); + +/** apr_dbd_pbquery: query using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + int *nrows, apr_dbd_prepared_t *statement, + const void **args); + +/** apr_dbd_pbselect: select using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const void **args); + +/** apr_dbd_pvbquery: query using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param ... - varargs list of binary args + * @return 0 for success or error code + */ +APU_DECLARE_NONSTD(int) apr_dbd_pvbquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...); + +/** apr_dbd_pvbselect: select using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param ... - varargs list of binary args + * @return 0 for success or error code + */ +APU_DECLARE_NONSTD(int) apr_dbd_pvbselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, ...); + +/** apr_dbd_datum_get: get a binary entry from a row + * + * @param driver - the driver + * @param row - row pointer + * @param col - entry number + * @param type - type of data to get + * @param data - pointer to data, allocated by the caller + * @return APR_SUCCESS on success, APR_ENOENT if data is NULL or APR_EGENERAL + */ +APU_DECLARE(apr_status_t) apr_dbd_datum_get(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col, + apr_dbd_type_e type, void *data); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/apr-linux/apr_dbm.h b/include/apr-linux/apr_dbm.h new file mode 100644 index 0000000..9f6e8b4 --- /dev/null +++ b/include/apr-linux/apr_dbm.h @@ -0,0 +1,224 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_DBM_H +#define APR_DBM_H + +#include "apu.h" +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_file_info.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_dbm.h + * @brief APR-UTIL DBM library + */ +/** + * @defgroup APR_Util_DBM DBM routines + * @ingroup APR_Util + * @{ + */ +/** + * Structure for referencing a dbm + */ +typedef struct apr_dbm_t apr_dbm_t; + +/** + * Structure for referencing the datum record within a dbm + */ +typedef struct +{ + /** pointer to the 'data' to retrieve/store in the DBM */ + char *dptr; + /** size of the 'data' to retrieve/store in the DBM */ + apr_size_t dsize; +} apr_datum_t; + +/* modes to open the DB */ +#define APR_DBM_READONLY 1 /**< open for read-only access */ +#define APR_DBM_READWRITE 2 /**< open for read-write access */ +#define APR_DBM_RWCREATE 3 /**< open for r/w, create if needed */ +#define APR_DBM_RWTRUNC 4 /**< open for r/w, truncating an existing + DB if present */ +/** + * Open a dbm file by file name and type of DBM + * @param dbm The newly opened database + * @param type The type of the DBM (not all may be available at run time) + *
+ *  GDBM for GDBM files
+ *  SDBM for SDBM files
+ *  DB   for berkeley DB files
+ *  NDBM for NDBM files
+ *  default for the default DBM type
+ *  
+ * @param name The dbm file name to open + * @param mode The flag value + *
+ *           APR_DBM_READONLY   open for read-only access
+ *           APR_DBM_READWRITE  open for read-write access
+ *           APR_DBM_RWCREATE   open for r/w, create if needed
+ *           APR_DBM_RWTRUNC    open for r/w, truncate if already there
+ * 
+ * @param perm Permissions to apply to if created + * @param cntxt The pool to use when creating the dbm + * @remark The dbm name may not be a true file name, as many dbm packages + * append suffixes for seperate data and index files. + */ + +APU_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **dbm, const char* type, + const char *name, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *cntxt); + + +/** + * Open a dbm file by file name + * @param dbm The newly opened database + * @param name The dbm file name to open + * @param mode The flag value + *
+ *           APR_DBM_READONLY   open for read-only access
+ *           APR_DBM_READWRITE  open for read-write access
+ *           APR_DBM_RWCREATE   open for r/w, create if needed
+ *           APR_DBM_RWTRUNC    open for r/w, truncate if already there
+ * 
+ * @param perm Permissions to apply to if created + * @param cntxt The pool to use when creating the dbm + * @remark The dbm name may not be a true file name, as many dbm packages + * append suffixes for seperate data and index files. + */ +APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **dbm, const char *name, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *cntxt); + +/** + * Close a dbm file previously opened by apr_dbm_open + * @param dbm The database to close + */ +APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm); + +/** + * Fetch a dbm record value by key + * @param dbm The database + * @param key The key datum to find this record + * @param pvalue The value datum retrieved for this record + */ +APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue); +/** + * Store a dbm record value by key + * @param dbm The database + * @param key The key datum to store this record by + * @param value The value datum to store in this record + */ +APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value); + +/** + * Delete a dbm record value by key + * @param dbm The database + * @param key The key datum of the record to delete + * @remark It is not an error to delete a non-existent record. + */ +APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key); + +/** + * Search for a key within the dbm + * @param dbm The database + * @param key The datum describing a key to test + */ +APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key); + +/** + * Retrieve the first record key from a dbm + * @param dbm The database + * @param pkey The key datum of the first record + */ +APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey); + +/** + * Retrieve the next record key from a dbm + * @param dbm The database + * @param pkey The key datum of the next record + */ +APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey); + +/** + * Proactively toss any memory associated with the apr_datum_t. + * @param dbm The database + * @param data The datum to free. + */ +APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data); + +/** + * Report more information when an apr_dbm function fails. + * @param dbm The database + * @param errcode A DBM-specific value for the error (for logging). If this + * isn't needed, it may be NULL. + * @param errbuf Location to store the error text + * @param errbufsize The size of the provided buffer + * @return The errbuf parameter, for convenience. + */ +APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode, + char *errbuf, apr_size_t errbufsize); +/** + * If the specified file/path were passed to apr_dbm_open(), return the + * actual file/path names which would be (created and) used. At most, two + * files may be used; used2 may be NULL if only one file is used. + * @param pool The pool for allocating used1 and used2. + * @param type The type of DBM you require info on + * @param pathname The path name to generate used-names from. + * @param used1 The first pathname used by the apr_dbm implementation. + * @param used2 The second pathname used by apr_dbm. If only one file is + * used by the specific implementation, this will be set to NULL. + * @return An error if the specified type is invalid. + * @remark The dbm file(s) don't need to exist. This function only manipulates + * the pathnames. + */ +APU_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *pool, + const char *type, + const char *pathname, + const char **used1, + const char **used2); + +/** + * If the specified file/path were passed to apr_dbm_open(), return the + * actual file/path names which would be (created and) used. At most, two + * files may be used; used2 may be NULL if only one file is used. + * @param pool The pool for allocating used1 and used2. + * @param pathname The path name to generate used-names from. + * @param used1 The first pathname used by the apr_dbm implementation. + * @param used2 The second pathname used by apr_dbm. If only one file is + * used by the specific implementation, this will be set to NULL. + * @remark The dbm file(s) don't need to exist. This function only manipulates + * the pathnames. + */ +APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *pool, + const char *pathname, + const char **used1, + const char **used2); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_DBM_H */ diff --git a/include/apr-linux/apr_dso.h b/include/apr-linux/apr_dso.h new file mode 100644 index 0000000..ac701cf --- /dev/null +++ b/include/apr-linux/apr_dso.h @@ -0,0 +1,94 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_DSO_DOT_H +#define APR_DSO_DOT_H + +/** + * @file apr_dso.h + * @brief APR Dynamic Object Handling Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_dso Dynamic Object Handling + * @ingroup APR + * @{ + */ + +#if APR_HAS_DSO || defined(DOXYGEN) + +/** + * Structure for referencing dynamic objects + */ +typedef struct apr_dso_handle_t apr_dso_handle_t; + +/** + * Structure for referencing symbols from dynamic objects + */ +typedef void * apr_dso_handle_sym_t; + +/** + * Load a DSO library. + * @param res_handle Location to store new handle for the DSO. + * @param path Path to the DSO library + * @param ctx Pool to use. + * @bug We aught to provide an alternative to RTLD_GLOBAL, which + * is the only supported method of loading DSOs today. + */ +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *ctx); + +/** + * Close a DSO library. + * @param handle handle to close. + */ +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle); + +/** + * Load a symbol from a DSO handle. + * @param ressym Location to store the loaded symbol + * @param handle handle to load the symbol from. + * @param symname Name of the symbol to load. + */ +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname); + +/** + * Report more information when a DSO function fails. + * @param dso The dso handle that has been opened + * @param buf Location to store the dso error + * @param bufsize The size of the provided buffer + */ +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buf, apr_size_t bufsize); + +#endif /* APR_HAS_DSO */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/apr-linux/apr_env.h b/include/apr-linux/apr_env.h new file mode 100644 index 0000000..05419c3 --- /dev/null +++ b/include/apr-linux/apr_env.h @@ -0,0 +1,67 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_ENV_H +#define APR_ENV_H +/** + * @file apr_env.h + * @brief APR Environment functions + */ +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_env Functions for manupulating the environment + * @ingroup APR + * @{ + */ + +/** + * Get the value of an environment variable + * @param value the returned value, allocated from @a pool + * @param envvar the name of the environment variable + * @param pool where to allocate @a value and any temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_get(char **value, const char *envvar, + apr_pool_t *pool); + +/** + * Set the value of an environment variable + * @param envvar the name of the environment variable + * @param value the value to set + * @param pool where to allocate temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_set(const char *envvar, const char *value, + apr_pool_t *pool); + +/** + * Delete a variable from the environment + * @param envvar the name of the environment variable + * @param pool where to allocate temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_ENV_H */ diff --git a/include/apr-linux/apr_errno.h b/include/apr-linux/apr_errno.h new file mode 100644 index 0000000..f34e8d9 --- /dev/null +++ b/include/apr-linux/apr_errno.h @@ -0,0 +1,1312 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_ERRNO_H +#define APR_ERRNO_H + +/** + * @file apr_errno.h + * @brief APR Error Codes + */ + +#include "apr.h" + +#if APR_HAVE_ERRNO_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_errno Error Codes + * @ingroup APR + * @{ + */ + +/** + * Type for specifying an error or status code. + */ +typedef int apr_status_t; + +/** + * Return a human readable string describing the specified error. + * @param statcode The error code the get a string for. + * @param buf A buffer to hold the error string. + * @param bufsize Size of the buffer to hold the string. + */ +APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize); + +#if defined(DOXYGEN) +/** + * @def APR_FROM_OS_ERROR(os_err_type syserr) + * Fold a platform specific error into an apr_status_t code. + * @return apr_status_t + * @param e The platform os error code. + * @warning macro implementation; the syserr argument may be evaluated + * multiple times. + */ +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) + +/** + * @def APR_TO_OS_ERROR(apr_status_t statcode) + * @return os_err_type + * Fold an apr_status_t code back to the native platform defined error. + * @param e The apr_status_t folded platform os error code. + * @warning macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. + */ +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +/** @def apr_get_os_error() + * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms + * @remark This retrieves errno, or calls a GetLastError() style function, and + * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no + * such mechanism, so this call may be unsupported. Do NOT use this + * call for socket errors from socket, send, recv etc! + */ + +/** @def apr_set_os_error(e) + * Reset the last platform error, unfolded from an apr_status_t, on some platforms + * @param e The OS error folded in a prior call to APR_FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a SetLastError() style function, unfolding statcode + * with APR_TO_OS_ERROR. Some platforms (such as OS2) have no such + * mechanism, so this call may be unsupported. + */ + +/** @def apr_get_netos_error() + * Return the last socket error, folded into apr_status_t, on all platforms + * @remark This retrieves errno or calls a GetLastSocketError() style function, + * and folds it with APR_FROM_OS_ERROR. + */ + +/** @def apr_set_netos_error(e) + * Reset the last socket error, unfolded from an apr_status_t + * @param e The socket error folded in a prior call to APR_FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a WSASetLastError() style function, unfolding + * socketcode with APR_TO_OS_ERROR. + */ + +#endif /* defined(DOXYGEN) */ + +/** + * APR_OS_START_ERROR is where the APR specific error values start. + */ +#define APR_OS_START_ERROR 20000 +/** + * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit + * into one of the error/status ranges below -- except for + * APR_OS_START_USERERR, which see. + */ +#define APR_OS_ERRSPACE_SIZE 50000 +/** + * APR_UTIL_ERRSPACE_SIZE is the size of the space that is reserved for + * use within apr-util. This space is reserved above that used by APR + * internally. + * @note This number MUST be smaller than APR_OS_ERRSPACE_SIZE by a + * large enough amount that APR has sufficient room for it's + * codes. + */ +#define APR_UTIL_ERRSPACE_SIZE 20000 +/** + * APR_OS_START_STATUS is where the APR specific status codes start. + */ +#define APR_OS_START_STATUS (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE) +/** + * APR_UTIL_START_STATUS is where APR-Util starts defining it's + * status codes. + */ +#define APR_UTIL_START_STATUS (APR_OS_START_STATUS + \ + (APR_OS_ERRSPACE_SIZE - APR_UTIL_ERRSPACE_SIZE)) +/** + * APR_OS_START_USERERR are reserved for applications that use APR that + * layer their own error codes along with APR's. Note that the + * error immediately following this one is set ten times farther + * away than usual, so that users of apr have a lot of room in + * which to declare custom error codes. + * + * In general applications should try and create unique error codes. To try + * and assist in finding suitable ranges of numbers to use, the following + * ranges are known to be used by the listed applications. If your + * application defines error codes please advise the range of numbers it + * uses to dev@apr.apache.org for inclusion in this list. + * + * Ranges shown are in relation to APR_OS_START_USERERR + * + * Subversion - Defined ranges, of less than 100, at intervals of 5000 + * starting at an offset of 5000, e.g. + * +5000 to 5100, +10000 to 10100 + */ +#define APR_OS_START_USERERR (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_USEERR is obsolete, defined for compatibility only. + * Use APR_OS_START_USERERR instead. + */ +#define APR_OS_START_USEERR APR_OS_START_USERERR +/** + * APR_OS_START_CANONERR is where APR versions of errno values are defined + * on systems which don't have the corresponding errno. + */ +#define APR_OS_START_CANONERR (APR_OS_START_USERERR \ + + (APR_OS_ERRSPACE_SIZE * 10)) +/** + * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into + * apr_status_t values. + */ +#define APR_OS_START_EAIERR (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_SYSERR folds platform-specific system error values into + * apr_status_t values. + */ +#define APR_OS_START_SYSERR (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE) + +/** + * @defgroup APR_ERROR_map APR Error Space + *
+ * The following attempts to show the relation of the various constants
+ * used for mapping APR Status codes.
+ *
+ *       0          
+ *
+ *  20,000     APR_OS_START_ERROR
+ *
+ *         + APR_OS_ERRSPACE_SIZE (50,000)
+ *
+ *  70,000      APR_OS_START_STATUS
+ *
+ *         + APR_OS_ERRSPACE_SIZE - APR_UTIL_ERRSPACE_SIZE (30,000)
+ *
+ * 100,000      APR_UTIL_START_STATUS
+ *
+ *         + APR_UTIL_ERRSPACE_SIZE (20,000)
+ *
+ * 120,000      APR_OS_START_USERERR
+ *
+ *         + 10 x APR_OS_ERRSPACE_SIZE (50,000 * 10)
+ *
+ * 620,000      APR_OS_START_CANONERR
+ *
+ *         + APR_OS_ERRSPACE_SIZE (50,000)
+ *
+ * 670,000      APR_OS_START_EAIERR
+ *
+ *         + APR_OS_ERRSPACE_SIZE (50,000)
+ *
+ * 720,000      APR_OS_START_SYSERR
+ *
+ * 
+ */ + +/** no error. */ +#define APR_SUCCESS 0 + +/** + * @defgroup APR_Error APR Error Values + *
+ * APR ERROR VALUES
+ * APR_ENOSTAT      APR was unable to perform a stat on the file 
+ * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
+ * APR_EBADDATE     APR was given an invalid date 
+ * APR_EINVALSOCK   APR was given an invalid socket
+ * APR_ENOPROC      APR was not given a process structure
+ * APR_ENOTIME      APR was not given a time structure
+ * APR_ENODIR       APR was not given a directory structure
+ * APR_ENOLOCK      APR was not given a lock structure
+ * APR_ENOPOLL      APR was not given a poll structure
+ * APR_ENOSOCKET    APR was not given a socket
+ * APR_ENOTHREAD    APR was not given a thread structure
+ * APR_ENOTHDKEY    APR was not given a thread key structure
+ * APR_ENOSHMAVAIL  There is no more shared memory available
+ * APR_EDSOOPEN     APR was unable to open the dso object.  For more 
+ *                  information call apr_dso_error().
+ * APR_EGENERAL     General failure (specific information not available)
+ * APR_EBADIP       The specified IP address is invalid
+ * APR_EBADMASK     The specified netmask is invalid
+ * APR_ESYMNOTFOUND Could not find the requested symbol
+ * APR_ENOTENOUGHENTROPY Not enough entropy to continue
+ * 
+ * + *
+ * APR STATUS VALUES
+ * APR_INCHILD        Program is currently executing in the child
+ * APR_INPARENT       Program is currently executing in the parent
+ * APR_DETACH         The thread is detached
+ * APR_NOTDETACH      The thread is not detached
+ * APR_CHILD_DONE     The child has finished executing
+ * APR_CHILD_NOTDONE  The child has not finished executing
+ * APR_TIMEUP         The operation did not finish before the timeout
+ * APR_INCOMPLETE     The operation was incomplete although some processing
+ *                    was performed and the results are partially valid
+ * APR_BADCH          Getopt found an option not in the option string
+ * APR_BADARG         Getopt found an option that is missing an argument 
+ *                    and an argument was specified in the option string
+ * APR_EOF            APR has encountered the end of the file
+ * APR_NOTFOUND       APR was unable to find the socket in the poll structure
+ * APR_ANONYMOUS      APR is using anonymous shared memory
+ * APR_FILEBASED      APR is using a file name as the key to the shared memory
+ * APR_KEYBASED       APR is using a shared key as the key to the shared memory
+ * APR_EINIT          Ininitalizer value.  If no option has been found, but 
+ *                    the status variable requires a value, this should be used
+ * APR_ENOTIMPL       The APR function has not been implemented on this 
+ *                    platform, either because nobody has gotten to it yet, 
+ *                    or the function is impossible on this platform.
+ * APR_EMISMATCH      Two passwords do not match.
+ * APR_EABSOLUTE      The given path was absolute.
+ * APR_ERELATIVE      The given path was relative.
+ * APR_EINCOMPLETE    The given path was neither relative nor absolute.
+ * APR_EABOVEROOT     The given path was above the root path.
+ * APR_EBUSY          The given lock was busy.
+ * APR_EPROC_UNKNOWN  The given process wasn't recognized by APR
+ * 
+ * @{ + */ +/** @see APR_STATUS_IS_ENOSTAT */ +#define APR_ENOSTAT (APR_OS_START_ERROR + 1) +/** @see APR_STATUS_IS_ENOPOOL */ +#define APR_ENOPOOL (APR_OS_START_ERROR + 2) +/* empty slot: +3 */ +/** @see APR_STATUS_IS_EBADDATE */ +#define APR_EBADDATE (APR_OS_START_ERROR + 4) +/** @see APR_STATUS_IS_EINVALSOCK */ +#define APR_EINVALSOCK (APR_OS_START_ERROR + 5) +/** @see APR_STATUS_IS_ENOPROC */ +#define APR_ENOPROC (APR_OS_START_ERROR + 6) +/** @see APR_STATUS_IS_ENOTIME */ +#define APR_ENOTIME (APR_OS_START_ERROR + 7) +/** @see APR_STATUS_IS_ENODIR */ +#define APR_ENODIR (APR_OS_START_ERROR + 8) +/** @see APR_STATUS_IS_ENOLOCK */ +#define APR_ENOLOCK (APR_OS_START_ERROR + 9) +/** @see APR_STATUS_IS_ENOPOLL */ +#define APR_ENOPOLL (APR_OS_START_ERROR + 10) +/** @see APR_STATUS_IS_ENOSOCKET */ +#define APR_ENOSOCKET (APR_OS_START_ERROR + 11) +/** @see APR_STATUS_IS_ENOTHREAD */ +#define APR_ENOTHREAD (APR_OS_START_ERROR + 12) +/** @see APR_STATUS_IS_ENOTHDKEY */ +#define APR_ENOTHDKEY (APR_OS_START_ERROR + 13) +/** @see APR_STATUS_IS_EGENERAL */ +#define APR_EGENERAL (APR_OS_START_ERROR + 14) +/** @see APR_STATUS_IS_ENOSHMAVAIL */ +#define APR_ENOSHMAVAIL (APR_OS_START_ERROR + 15) +/** @see APR_STATUS_IS_EBADIP */ +#define APR_EBADIP (APR_OS_START_ERROR + 16) +/** @see APR_STATUS_IS_EBADMASK */ +#define APR_EBADMASK (APR_OS_START_ERROR + 17) +/* empty slot: +18 */ +/** @see APR_STATUS_IS_EDSOPEN */ +#define APR_EDSOOPEN (APR_OS_START_ERROR + 19) +/** @see APR_STATUS_IS_EABSOLUTE */ +#define APR_EABSOLUTE (APR_OS_START_ERROR + 20) +/** @see APR_STATUS_IS_ERELATIVE */ +#define APR_ERELATIVE (APR_OS_START_ERROR + 21) +/** @see APR_STATUS_IS_EINCOMPLETE */ +#define APR_EINCOMPLETE (APR_OS_START_ERROR + 22) +/** @see APR_STATUS_IS_EABOVEROOT */ +#define APR_EABOVEROOT (APR_OS_START_ERROR + 23) +/** @see APR_STATUS_IS_EBADPATH */ +#define APR_EBADPATH (APR_OS_START_ERROR + 24) +/** @see APR_STATUS_IS_EPATHWILD */ +#define APR_EPATHWILD (APR_OS_START_ERROR + 25) +/** @see APR_STATUS_IS_ESYMNOTFOUND */ +#define APR_ESYMNOTFOUND (APR_OS_START_ERROR + 26) +/** @see APR_STATUS_IS_EPROC_UNKNOWN */ +#define APR_EPROC_UNKNOWN (APR_OS_START_ERROR + 27) +/** @see APR_STATUS_IS_ENOTENOUGHENTROPY */ +#define APR_ENOTENOUGHENTROPY (APR_OS_START_ERROR + 28) +/** @} */ + +/** + * @defgroup APR_STATUS_IS Status Value Tests + * @warning For any particular error condition, more than one of these tests + * may match. This is because platform-specific error codes may not + * always match the semantics of the POSIX codes these tests (and the + * corresponding APR error codes) are named after. A notable example + * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on + * Win32 platforms. The programmer should always be aware of this and + * adjust the order of the tests accordingly. + * @{ + */ +/** + * APR was unable to perform a stat on the file + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOSTAT(s) ((s) == APR_ENOSTAT) +/** + * APR was not provided a pool with which to allocate memory + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOPOOL(s) ((s) == APR_ENOPOOL) +/** APR was given an invalid date */ +#define APR_STATUS_IS_EBADDATE(s) ((s) == APR_EBADDATE) +/** APR was given an invalid socket */ +#define APR_STATUS_IS_EINVALSOCK(s) ((s) == APR_EINVALSOCK) +/** APR was not given a process structure */ +#define APR_STATUS_IS_ENOPROC(s) ((s) == APR_ENOPROC) +/** APR was not given a time structure */ +#define APR_STATUS_IS_ENOTIME(s) ((s) == APR_ENOTIME) +/** APR was not given a directory structure */ +#define APR_STATUS_IS_ENODIR(s) ((s) == APR_ENODIR) +/** APR was not given a lock structure */ +#define APR_STATUS_IS_ENOLOCK(s) ((s) == APR_ENOLOCK) +/** APR was not given a poll structure */ +#define APR_STATUS_IS_ENOPOLL(s) ((s) == APR_ENOPOLL) +/** APR was not given a socket */ +#define APR_STATUS_IS_ENOSOCKET(s) ((s) == APR_ENOSOCKET) +/** APR was not given a thread structure */ +#define APR_STATUS_IS_ENOTHREAD(s) ((s) == APR_ENOTHREAD) +/** APR was not given a thread key structure */ +#define APR_STATUS_IS_ENOTHDKEY(s) ((s) == APR_ENOTHDKEY) +/** Generic Error which can not be put into another spot */ +#define APR_STATUS_IS_EGENERAL(s) ((s) == APR_EGENERAL) +/** There is no more shared memory available */ +#define APR_STATUS_IS_ENOSHMAVAIL(s) ((s) == APR_ENOSHMAVAIL) +/** The specified IP address is invalid */ +#define APR_STATUS_IS_EBADIP(s) ((s) == APR_EBADIP) +/** The specified netmask is invalid */ +#define APR_STATUS_IS_EBADMASK(s) ((s) == APR_EBADMASK) +/* empty slot: +18 */ +/** + * APR was unable to open the dso object. + * For more information call apr_dso_error(). + */ +#if defined(WIN32) +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN \ + || APR_TO_OS_ERROR(s) == ERROR_MOD_NOT_FOUND) +#else +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN) +#endif +/** The given path was absolute. */ +#define APR_STATUS_IS_EABSOLUTE(s) ((s) == APR_EABSOLUTE) +/** The given path was relative. */ +#define APR_STATUS_IS_ERELATIVE(s) ((s) == APR_ERELATIVE) +/** The given path was neither relative nor absolute. */ +#define APR_STATUS_IS_EINCOMPLETE(s) ((s) == APR_EINCOMPLETE) +/** The given path was above the root path. */ +#define APR_STATUS_IS_EABOVEROOT(s) ((s) == APR_EABOVEROOT) +/** The given path was bad. */ +#define APR_STATUS_IS_EBADPATH(s) ((s) == APR_EBADPATH) +/** The given path contained wildcards. */ +#define APR_STATUS_IS_EPATHWILD(s) ((s) == APR_EPATHWILD) +/** Could not find the requested symbol. + * For more information call apr_dso_error(). + */ +#if defined(WIN32) +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND \ + || APR_TO_OS_ERROR(s) == ERROR_PROC_NOT_FOUND) +#else +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND) +#endif +/** The given process was not recognized by APR. */ +#define APR_STATUS_IS_EPROC_UNKNOWN(s) ((s) == APR_EPROC_UNKNOWN) +/** APR could not gather enough entropy to continue. */ +#define APR_STATUS_IS_ENOTENOUGHENTROPY(s) ((s) == APR_ENOTENOUGHENTROPY) + +/** @} */ + +/** + * @addtogroup APR_Error + * @{ + */ +/** @see APR_STATUS_IS_INCHILD */ +#define APR_INCHILD (APR_OS_START_STATUS + 1) +/** @see APR_STATUS_IS_INPARENT */ +#define APR_INPARENT (APR_OS_START_STATUS + 2) +/** @see APR_STATUS_IS_DETACH */ +#define APR_DETACH (APR_OS_START_STATUS + 3) +/** @see APR_STATUS_IS_NOTDETACH */ +#define APR_NOTDETACH (APR_OS_START_STATUS + 4) +/** @see APR_STATUS_IS_CHILD_DONE */ +#define APR_CHILD_DONE (APR_OS_START_STATUS + 5) +/** @see APR_STATUS_IS_CHILD_NOTDONE */ +#define APR_CHILD_NOTDONE (APR_OS_START_STATUS + 6) +/** @see APR_STATUS_IS_TIMEUP */ +#define APR_TIMEUP (APR_OS_START_STATUS + 7) +/** @see APR_STATUS_IS_INCOMPLETE */ +#define APR_INCOMPLETE (APR_OS_START_STATUS + 8) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** @see APR_STATUS_IS_BADCH */ +#define APR_BADCH (APR_OS_START_STATUS + 12) +/** @see APR_STATUS_IS_BADARG */ +#define APR_BADARG (APR_OS_START_STATUS + 13) +/** @see APR_STATUS_IS_EOF */ +#define APR_EOF (APR_OS_START_STATUS + 14) +/** @see APR_STATUS_IS_NOTFOUND */ +#define APR_NOTFOUND (APR_OS_START_STATUS + 15) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** @see APR_STATUS_IS_ANONYMOUS */ +#define APR_ANONYMOUS (APR_OS_START_STATUS + 19) +/** @see APR_STATUS_IS_FILEBASED */ +#define APR_FILEBASED (APR_OS_START_STATUS + 20) +/** @see APR_STATUS_IS_KEYBASED */ +#define APR_KEYBASED (APR_OS_START_STATUS + 21) +/** @see APR_STATUS_IS_EINIT */ +#define APR_EINIT (APR_OS_START_STATUS + 22) +/** @see APR_STATUS_IS_ENOTIMPL */ +#define APR_ENOTIMPL (APR_OS_START_STATUS + 23) +/** @see APR_STATUS_IS_EMISMATCH */ +#define APR_EMISMATCH (APR_OS_START_STATUS + 24) +/** @see APR_STATUS_IS_EBUSY */ +#define APR_EBUSY (APR_OS_START_STATUS + 25) +/** @} */ + +/** + * @addtogroup APR_STATUS_IS + * @{ + */ +/** + * Program is currently executing in the child + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code */ +#define APR_STATUS_IS_INCHILD(s) ((s) == APR_INCHILD) +/** + * Program is currently executing in the parent + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_INPARENT(s) ((s) == APR_INPARENT) +/** + * The thread is detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_DETACH(s) ((s) == APR_DETACH) +/** + * The thread is not detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_NOTDETACH(s) ((s) == APR_NOTDETACH) +/** + * The child has finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_CHILD_DONE(s) ((s) == APR_CHILD_DONE) +/** + * The child has not finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_CHILD_NOTDONE(s) ((s) == APR_CHILD_NOTDONE) +/** + * The operation did not finish before the timeout + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP) +/** + * The operation was incomplete although some processing was performed + * and the results are partially valid. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_INCOMPLETE(s) ((s) == APR_INCOMPLETE) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** + * Getopt found an option not in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_BADCH(s) ((s) == APR_BADCH) +/** + * Getopt found an option not in the option string and an argument was + * specified in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_BADARG(s) ((s) == APR_BADARG) +/** + * APR has encountered the end of the file + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EOF(s) ((s) == APR_EOF) +/** + * APR was unable to find the socket in the poll structure + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_NOTFOUND(s) ((s) == APR_NOTFOUND) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** + * APR is using anonymous shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ANONYMOUS(s) ((s) == APR_ANONYMOUS) +/** + * APR is using a file name as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_FILEBASED(s) ((s) == APR_FILEBASED) +/** + * APR is using a shared key as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_KEYBASED(s) ((s) == APR_KEYBASED) +/** + * Ininitalizer value. If no option has been found, but + * the status variable requires a value, this should be used + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EINIT(s) ((s) == APR_EINIT) +/** + * The APR function has not been implemented on this + * platform, either because nobody has gotten to it yet, + * or the function is impossible on this platform. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOTIMPL(s) ((s) == APR_ENOTIMPL) +/** + * Two passwords do not match. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EMISMATCH(s) ((s) == APR_EMISMATCH) +/** + * The given lock was busy + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EBUSY(s) ((s) == APR_EBUSY) + +/** @} */ + +/** + * @addtogroup APR_Error APR Error Values + * @{ + */ +/* APR CANONICAL ERROR VALUES */ +/** @see APR_STATUS_IS_EACCES */ +#ifdef EACCES +#define APR_EACCES EACCES +#else +#define APR_EACCES (APR_OS_START_CANONERR + 1) +#endif + +/** @see APR_STATUS_IS_EEXIST */ +#ifdef EEXIST +#define APR_EEXIST EEXIST +#else +#define APR_EEXIST (APR_OS_START_CANONERR + 2) +#endif + +/** @see APR_STATUS_IS_ENAMETOOLONG */ +#ifdef ENAMETOOLONG +#define APR_ENAMETOOLONG ENAMETOOLONG +#else +#define APR_ENAMETOOLONG (APR_OS_START_CANONERR + 3) +#endif + +/** @see APR_STATUS_IS_ENOENT */ +#ifdef ENOENT +#define APR_ENOENT ENOENT +#else +#define APR_ENOENT (APR_OS_START_CANONERR + 4) +#endif + +/** @see APR_STATUS_IS_ENOTDIR */ +#ifdef ENOTDIR +#define APR_ENOTDIR ENOTDIR +#else +#define APR_ENOTDIR (APR_OS_START_CANONERR + 5) +#endif + +/** @see APR_STATUS_IS_ENOSPC */ +#ifdef ENOSPC +#define APR_ENOSPC ENOSPC +#else +#define APR_ENOSPC (APR_OS_START_CANONERR + 6) +#endif + +/** @see APR_STATUS_IS_ENOMEM */ +#ifdef ENOMEM +#define APR_ENOMEM ENOMEM +#else +#define APR_ENOMEM (APR_OS_START_CANONERR + 7) +#endif + +/** @see APR_STATUS_IS_EMFILE */ +#ifdef EMFILE +#define APR_EMFILE EMFILE +#else +#define APR_EMFILE (APR_OS_START_CANONERR + 8) +#endif + +/** @see APR_STATUS_IS_ENFILE */ +#ifdef ENFILE +#define APR_ENFILE ENFILE +#else +#define APR_ENFILE (APR_OS_START_CANONERR + 9) +#endif + +/** @see APR_STATUS_IS_EBADF */ +#ifdef EBADF +#define APR_EBADF EBADF +#else +#define APR_EBADF (APR_OS_START_CANONERR + 10) +#endif + +/** @see APR_STATUS_IS_EINVAL */ +#ifdef EINVAL +#define APR_EINVAL EINVAL +#else +#define APR_EINVAL (APR_OS_START_CANONERR + 11) +#endif + +/** @see APR_STATUS_IS_ESPIPE */ +#ifdef ESPIPE +#define APR_ESPIPE ESPIPE +#else +#define APR_ESPIPE (APR_OS_START_CANONERR + 12) +#endif + +/** + * @see APR_STATUS_IS_EAGAIN + * @warning use APR_STATUS_IS_EAGAIN instead of just testing this value + */ +#ifdef EAGAIN +#define APR_EAGAIN EAGAIN +#elif defined(EWOULDBLOCK) +#define APR_EAGAIN EWOULDBLOCK +#else +#define APR_EAGAIN (APR_OS_START_CANONERR + 13) +#endif + +/** @see APR_STATUS_IS_EINTR */ +#ifdef EINTR +#define APR_EINTR EINTR +#else +#define APR_EINTR (APR_OS_START_CANONERR + 14) +#endif + +/** @see APR_STATUS_IS_ENOTSOCK */ +#ifdef ENOTSOCK +#define APR_ENOTSOCK ENOTSOCK +#else +#define APR_ENOTSOCK (APR_OS_START_CANONERR + 15) +#endif + +/** @see APR_STATUS_IS_ECONNREFUSED */ +#ifdef ECONNREFUSED +#define APR_ECONNREFUSED ECONNREFUSED +#else +#define APR_ECONNREFUSED (APR_OS_START_CANONERR + 16) +#endif + +/** @see APR_STATUS_IS_EINPROGRESS */ +#ifdef EINPROGRESS +#define APR_EINPROGRESS EINPROGRESS +#else +#define APR_EINPROGRESS (APR_OS_START_CANONERR + 17) +#endif + +/** + * @see APR_STATUS_IS_ECONNABORTED + * @warning use APR_STATUS_IS_ECONNABORTED instead of just testing this value + */ + +#ifdef ECONNABORTED +#define APR_ECONNABORTED ECONNABORTED +#else +#define APR_ECONNABORTED (APR_OS_START_CANONERR + 18) +#endif + +/** @see APR_STATUS_IS_ECONNRESET */ +#ifdef ECONNRESET +#define APR_ECONNRESET ECONNRESET +#else +#define APR_ECONNRESET (APR_OS_START_CANONERR + 19) +#endif + +/** @see APR_STATUS_IS_ETIMEDOUT + * @deprecated */ +#ifdef ETIMEDOUT +#define APR_ETIMEDOUT ETIMEDOUT +#else +#define APR_ETIMEDOUT (APR_OS_START_CANONERR + 20) +#endif + +/** @see APR_STATUS_IS_EHOSTUNREACH */ +#ifdef EHOSTUNREACH +#define APR_EHOSTUNREACH EHOSTUNREACH +#else +#define APR_EHOSTUNREACH (APR_OS_START_CANONERR + 21) +#endif + +/** @see APR_STATUS_IS_ENETUNREACH */ +#ifdef ENETUNREACH +#define APR_ENETUNREACH ENETUNREACH +#else +#define APR_ENETUNREACH (APR_OS_START_CANONERR + 22) +#endif + +/** @see APR_STATUS_IS_EFTYPE */ +#ifdef EFTYPE +#define APR_EFTYPE EFTYPE +#else +#define APR_EFTYPE (APR_OS_START_CANONERR + 23) +#endif + +/** @see APR_STATUS_IS_EPIPE */ +#ifdef EPIPE +#define APR_EPIPE EPIPE +#else +#define APR_EPIPE (APR_OS_START_CANONERR + 24) +#endif + +/** @see APR_STATUS_IS_EXDEV */ +#ifdef EXDEV +#define APR_EXDEV EXDEV +#else +#define APR_EXDEV (APR_OS_START_CANONERR + 25) +#endif + +/** @see APR_STATUS_IS_ENOTEMPTY */ +#ifdef ENOTEMPTY +#define APR_ENOTEMPTY ENOTEMPTY +#else +#define APR_ENOTEMPTY (APR_OS_START_CANONERR + 26) +#endif + +/** @see APR_STATUS_IS_EAFNOSUPPORT */ +#ifdef EAFNOSUPPORT +#define APR_EAFNOSUPPORT EAFNOSUPPORT +#else +#define APR_EAFNOSUPPORT (APR_OS_START_CANONERR + 27) +#endif + +/** @} */ + +#if defined(OS2) && !defined(DOXYGEN) + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define INCL_DOSERRORS +#define INCL_DOS + +/* Leave these undefined. + * OS2 doesn't rely on the errno concept. + * The API calls always return a result codes which + * should be filtered through APR_FROM_OS_ERROR(). + * + * #define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) + * #define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) + */ + +/* A special case, only socket calls require this; + */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(errno)) +#define apr_set_netos_error(e) (errno = APR_TO_OS_ERROR(e)) + +/* And this needs to be greped away for good: + */ +#define APR_OS2_STATUS(e) (APR_FROM_OS_ERROR(e)) + +/* These can't sit in a private header, so in spite of the extra size, + * they need to be made available here. + */ +#define SOCBASEERR 10000 +#define SOCEPERM (SOCBASEERR+1) /* Not owner */ +#define SOCESRCH (SOCBASEERR+3) /* No such process */ +#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ +#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ +#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ +#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ +#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ +#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ +#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ +#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ +#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ +#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ +#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ +#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ +#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ +#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ +#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ +#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ +#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ +#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ +#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ +#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ +#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ +#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ +#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ +#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ +#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ +#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ +#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ +#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ +#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ +#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ +#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ +#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ +#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ +#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ +#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ +#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ +#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ +#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ +#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ +#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ +#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ + || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == APR_OS_START_SYSERR + SOCENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ + || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == APR_OS_START_SYSERR + SOCEWOULDBLOCK \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + SOCEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + SOCENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + SOCECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + SOCEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + SOCECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + SOCECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + SOCEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + SOCENETUNREACH) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE \ + || (s) == APR_OS_START_SYSERR + SOCEPIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_AFNOSUPPORT \ + || (s) == APR_OS_START_SYSERR + SOCEAFNOSUPPORT) + +/* + Sorry, too tired to wrap this up for OS2... feel free to + fit the following into their best matches. + + { ERROR_NO_SIGNAL_SENT, ESRCH }, + { SOCEALREADY, EALREADY }, + { SOCEDESTADDRREQ, EDESTADDRREQ }, + { SOCEMSGSIZE, EMSGSIZE }, + { SOCEPROTOTYPE, EPROTOTYPE }, + { SOCENOPROTOOPT, ENOPROTOOPT }, + { SOCEPROTONOSUPPORT, EPROTONOSUPPORT }, + { SOCESOCKTNOSUPPORT, ESOCKTNOSUPPORT }, + { SOCEOPNOTSUPP, EOPNOTSUPP }, + { SOCEPFNOSUPPORT, EPFNOSUPPORT }, + { SOCEADDRINUSE, EADDRINUSE }, + { SOCEADDRNOTAVAIL, EADDRNOTAVAIL }, + { SOCENETDOWN, ENETDOWN }, + { SOCENETRESET, ENETRESET }, + { SOCENOBUFS, ENOBUFS }, + { SOCEISCONN, EISCONN }, + { SOCENOTCONN, ENOTCONN }, + { SOCESHUTDOWN, ESHUTDOWN }, + { SOCETOOMANYREFS, ETOOMANYREFS }, + { SOCELOOP, ELOOP }, + { SOCEHOSTDOWN, EHOSTDOWN }, + { SOCENOTEMPTY, ENOTEMPTY }, + { SOCEPIPE, EPIPE } +*/ + +#elif defined(WIN32) && !defined(DOXYGEN) /* !defined(OS2) */ + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) +#define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) + +/* A special case, only socket calls require this: + */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) +#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_CANNOT_MAKE \ + || (s) == APR_OS_START_SYSERR + ERROR_CURRENT_DIRECTORY \ + || (s) == APR_OS_START_SYSERR + ERROR_DRIVE_LOCKED \ + || (s) == APR_OS_START_SYSERR + ERROR_FAIL_I24 \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_LOCKED \ + || (s) == APR_OS_START_SYSERR + ERROR_NETWORK_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ + || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == APR_OS_START_SYSERR + WSAENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_NETPATH \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_NET_NAME \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_PATHNAME \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DRIVE) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM \ + || (s) == APR_OS_START_SYSERR + ERROR_ARENA_TRASHED \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_MEMORY \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_BLOCK \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_QUOTA \ + || (s) == APR_OS_START_SYSERR + ERROR_OUTOFMEMORY) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ + || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_TARGET_HANDLE) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_ACCESS \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DATA \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_SEEK_ON_DEVICE \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_PROC_SLOTS \ + || (s) == APR_OS_START_SYSERR + ERROR_NESTING_NOT_ALLOWED \ + || (s) == APR_OS_START_SYSERR + ERROR_MAX_THRDS_REACHED \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + WSAEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + ERROR_NETNAME_DELETED \ + || (s) == APR_OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE \ + || (s) == APR_OS_START_SYSERR + ERROR_EXE_MACHINE_TYPE_MISMATCH \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DLL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_MODULETYPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_EXE_FORMAT \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_EXE_SIGNATURE \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_CORRUPT \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_FORMAT) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY) +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT \ + || (s) == APR_OS_START_SYSERR + WSAEAFNOSUPPORT) + +#elif defined(NETWARE) && defined(USE_WINSOCK) && !defined(DOXYGEN) /* !defined(OS2) && !defined(WIN32) */ + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define apr_get_os_error() (errno) +#define apr_set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) +#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) + +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == EWOULDBLOCK \ + || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + WSAEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) +#define APR_STATUS_IS_ENETDOWN(s) ((s) == APR_OS_START_SYSERR + WSAENETDOWN) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY) +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT \ + || (s) == APR_OS_START_SYSERR + WSAEAFNOSUPPORT) + +#else /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/* + * os error codes are clib error codes + */ +#define APR_FROM_OS_ERROR(e) (e) +#define APR_TO_OS_ERROR(e) (e) + +#define apr_get_os_error() (errno) +#define apr_set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: + */ +#define apr_get_netos_error() (errno) +#define apr_set_netos_error(e) (errno = (e)) + +/** + * @addtogroup APR_STATUS_IS + * @{ + */ + +/** permission denied */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) +/** file exists */ +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) +/** path name is too long */ +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) +/** + * no such file or directory + * @remark + * EMVSCATLG can be returned by the automounter on z/OS for + * paths which do not exist. + */ +#ifdef EMVSCATLG +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == EMVSCATLG) +#else +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) +#endif +/** not a directory */ +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +/** no space left on device */ +#ifdef EDQUOT +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == EDQUOT) +#else +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) +#endif +/** not enough memory */ +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +/** too many open files */ +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) +/** file table overflow */ +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +/** bad file # */ +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) +/** invalid argument */ +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) +/** illegal seek */ +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) + +/** operation would block */ +#if !defined(EWOULDBLOCK) || !defined(EAGAIN) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) +#elif (EWOULDBLOCK == EAGAIN) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) +#else +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == EWOULDBLOCK) +#endif + +/** interrupted system call */ +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR) +/** socket operation on a non-socket */ +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK) +/** Connection Refused */ +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED) +/** operation now in progress */ +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS) + +/** + * Software caused connection abort + * @remark + * EPROTO on certain older kernels really means ECONNABORTED, so we need to + * ignore it for them. See discussion in new-httpd archives nh.9701 & nh.9603 + * + * There is potentially a bug in Solaris 2.x x<6, and other boxes that + * implement tcp sockets in userland (i.e. on top of STREAMS). On these + * systems, EPROTO can actually result in a fatal loop. See PR#981 for + * example. It's hard to handle both uses of EPROTO. + */ +#ifdef EPROTO +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == EPROTO) +#else +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED) +#endif + +/** Connection Reset by peer */ +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET) +/** Operation timed out + * @deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT) +/** no route to host */ +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH) +/** network is unreachable */ +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH) +/** inappropiate file type or format */ +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +/** broken pipe */ +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) +/** cross device link */ +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) +/** Directory Not Empty */ +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY || \ + (s) == APR_EEXIST) +/** Address Family not supported */ +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT) +/** @} */ + +#endif /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_ERRNO_H */ diff --git a/include/apr-linux/apr_file_info.h b/include/apr-linux/apr_file_info.h new file mode 100644 index 0000000..bbcff8a --- /dev/null +++ b/include/apr-linux/apr_file_info.h @@ -0,0 +1,427 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_FILE_INFO_H +#define APR_FILE_INFO_H + +/** + * @file apr_file_info.h + * @brief APR File Information + */ + +#include "apr.h" +#include "apr_user.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_time.h" +#include "apr_errno.h" + +#if APR_HAVE_SYS_UIO_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_file_info File Information + * @ingroup APR + * @{ + */ + +/* Many applications use the type member to determine the + * existance of a file or initialization of the file info, + * so the APR_NOFILE value must be distinct from APR_UNKFILE. + */ + +/** apr_filetype_e values for the filetype member of the + * apr_file_info_t structure + * @warning: Not all of the filetypes below can be determined. + * For example, a given platform might not correctly report + * a socket descriptor as APR_SOCK if that type isn't + * well-identified on that platform. In such cases where + * a filetype exists but cannot be described by the recognized + * flags below, the filetype will be APR_UNKFILE. If the + * filetype member is not determined, the type will be APR_NOFILE. + */ + +typedef enum { + APR_NOFILE = 0, /**< no file type determined */ + APR_REG, /**< a regular file */ + APR_DIR, /**< a directory */ + APR_CHR, /**< a character device */ + APR_BLK, /**< a block device */ + APR_PIPE, /**< a FIFO / pipe */ + APR_LNK, /**< a symbolic link */ + APR_SOCK, /**< a [unix domain] socket */ + APR_UNKFILE = 127 /**< a file of some other unknown type */ +} apr_filetype_e; + +/** + * @defgroup apr_file_permissions File Permissions flags + * @{ + */ + +#define APR_FPROT_USETID 0x8000 /**< Set user id */ +#define APR_FPROT_UREAD 0x0400 /**< Read by user */ +#define APR_FPROT_UWRITE 0x0200 /**< Write by user */ +#define APR_FPROT_UEXECUTE 0x0100 /**< Execute by user */ + +#define APR_FPROT_GSETID 0x4000 /**< Set group id */ +#define APR_FPROT_GREAD 0x0040 /**< Read by group */ +#define APR_FPROT_GWRITE 0x0020 /**< Write by group */ +#define APR_FPROT_GEXECUTE 0x0010 /**< Execute by group */ + +#define APR_FPROT_WSTICKY 0x2000 /**< Sticky bit */ +#define APR_FPROT_WREAD 0x0004 /**< Read by others */ +#define APR_FPROT_WWRITE 0x0002 /**< Write by others */ +#define APR_FPROT_WEXECUTE 0x0001 /**< Execute by others */ + +#define APR_FPROT_OS_DEFAULT 0x0FFF /**< use OS's default permissions */ + +/* additional permission flags for apr_file_copy and apr_file_append */ +#define APR_FPROT_FILE_SOURCE_PERMS 0x1000 /**< Copy source file's permissions */ + +/* backcompat */ +#define APR_USETID APR_FPROT_USETID /**< @deprecated @see APR_FPROT_USETID */ +#define APR_UREAD APR_FPROT_UREAD /**< @deprecated @see APR_FPROT_UREAD */ +#define APR_UWRITE APR_FPROT_UWRITE /**< @deprecated @see APR_FPROT_UWRITE */ +#define APR_UEXECUTE APR_FPROT_UEXECUTE /**< @deprecated @see APR_FPROT_UEXECUTE */ +#define APR_GSETID APR_FPROT_GSETID /**< @deprecated @see APR_FPROT_GSETID */ +#define APR_GREAD APR_FPROT_GREAD /**< @deprecated @see APR_FPROT_GREAD */ +#define APR_GWRITE APR_FPROT_GWRITE /**< @deprecated @see APR_FPROT_GWRITE */ +#define APR_GEXECUTE APR_FPROT_GEXECUTE /**< @deprecated @see APR_FPROT_GEXECUTE */ +#define APR_WSTICKY APR_FPROT_WSTICKY /**< @deprecated @see APR_FPROT_WSTICKY */ +#define APR_WREAD APR_FPROT_WREAD /**< @deprecated @see APR_FPROT_WREAD */ +#define APR_WWRITE APR_FPROT_WWRITE /**< @deprecated @see APR_FPROT_WWRITE */ +#define APR_WEXECUTE APR_FPROT_WEXECUTE /**< @deprecated @see APR_FPROT_WEXECUTE */ +#define APR_OS_DEFAULT APR_FPROT_OS_DEFAULT /**< @deprecated @see APR_FPROT_OS_DEFAULT */ +#define APR_FILE_SOURCE_PERMS APR_FPROT_FILE_SOURCE_PERMS /**< @deprecated @see APR_FPROT_FILE_SOURCE_PERMS */ + +/** @} */ + + +/** + * Structure for referencing directories. + */ +typedef struct apr_dir_t apr_dir_t; +/** + * Structure for determining file permissions. + */ +typedef apr_int32_t apr_fileperms_t; +#if (defined WIN32) || (defined NETWARE) +/** + * Structure for determining the device the file is on. + */ +typedef apr_uint32_t apr_dev_t; +#else +/** + * Structure for determining the device the file is on. + */ +typedef dev_t apr_dev_t; +#endif + +/** + * @defgroup apr_file_stat Stat Functions + * @{ + */ +/** file info structure */ +typedef struct apr_finfo_t apr_finfo_t; + +#define APR_FINFO_LINK 0x00000001 /**< Stat the link not the file itself if it is a link */ +#define APR_FINFO_MTIME 0x00000010 /**< Modification Time */ +#define APR_FINFO_CTIME 0x00000020 /**< Creation or inode-changed time */ +#define APR_FINFO_ATIME 0x00000040 /**< Access Time */ +#define APR_FINFO_SIZE 0x00000100 /**< Size of the file */ +#define APR_FINFO_CSIZE 0x00000200 /**< Storage size consumed by the file */ +#define APR_FINFO_DEV 0x00001000 /**< Device */ +#define APR_FINFO_INODE 0x00002000 /**< Inode */ +#define APR_FINFO_NLINK 0x00004000 /**< Number of links */ +#define APR_FINFO_TYPE 0x00008000 /**< Type */ +#define APR_FINFO_USER 0x00010000 /**< User */ +#define APR_FINFO_GROUP 0x00020000 /**< Group */ +#define APR_FINFO_UPROT 0x00100000 /**< User protection bits */ +#define APR_FINFO_GPROT 0x00200000 /**< Group protection bits */ +#define APR_FINFO_WPROT 0x00400000 /**< World protection bits */ +#define APR_FINFO_ICASE 0x01000000 /**< if dev is case insensitive */ +#define APR_FINFO_NAME 0x02000000 /**< ->name in proper case */ + +#define APR_FINFO_MIN 0x00008170 /**< type, mtime, ctime, atime, size */ +#define APR_FINFO_IDENT 0x00003000 /**< dev and inode */ +#define APR_FINFO_OWNER 0x00030000 /**< user and group */ +#define APR_FINFO_PROT 0x00700000 /**< all protections */ +#define APR_FINFO_NORM 0x0073b170 /**< an atomic unix apr_stat() */ +#define APR_FINFO_DIRENT 0x02000000 /**< an atomic unix apr_dir_read() */ + +/** + * The file information structure. This is analogous to the POSIX + * stat structure. + */ +struct apr_finfo_t { + /** Allocates memory and closes lingering handles in the specified pool */ + apr_pool_t *pool; + /** The bitmask describing valid fields of this apr_finfo_t structure + * including all available 'wanted' fields and potentially more */ + apr_int32_t valid; + /** The access permissions of the file. Mimics Unix access rights. */ + apr_fileperms_t protection; + /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, + * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. + * If the type cannot be determined, the value is APR_UNKFILE. + */ + apr_filetype_e filetype; + /** The user id that owns the file */ + apr_uid_t user; + /** The group id that owns the file */ + apr_gid_t group; + /** The inode of the file. */ + apr_ino_t inode; + /** The id of the device the file is on. */ + apr_dev_t device; + /** The number of hard links to the file. */ + apr_int32_t nlink; + /** The size of the file */ + apr_off_t size; + /** The storage size consumed by the file */ + apr_off_t csize; + /** The time the file was last accessed */ + apr_time_t atime; + /** The time the file was last modified */ + apr_time_t mtime; + /** The time the file was created, or the inode was last changed */ + apr_time_t ctime; + /** The pathname of the file (possibly unrooted) */ + const char *fname; + /** The file's name (no path) in filesystem case */ + const char *name; + /** The file's handle, if accessed (can be submitted to apr_duphandle) */ + struct apr_file_t *filehand; +}; + +/** + * get the specified file's stats. The file is specified by filename, + * instead of using a pre-opened file. + * @param finfo Where to store the information about the file, which is + * never touched if the call fails. + * @param fname The name of the file to stat. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ + values + * @param pool the pool to use to allocate the new file. + * + * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. + */ +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool); + +/** @} */ +/** + * @defgroup apr_dir Directory Manipulation Functions + * @{ + */ + +/** + * Open the specified directory. + * @param new_dir The opened directory descriptor. + * @param dirname The full path to the directory (use / on all systems) + * @param pool The pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new_dir, + const char *dirname, + apr_pool_t *pool); + +/** + * close the specified directory. + * @param thedir the directory descriptor to close. + */ +APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir); + +/** + * Read the next entry from the specified directory. + * @param finfo the file info structure and filled in by apr_dir_read + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ + values + * @param thedir the directory descriptor returned from apr_dir_open + * @remark No ordering is guaranteed for the entries read. + * + * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. + */ +APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, + apr_dir_t *thedir); + +/** + * Rewind the directory to the first entry. + * @param thedir the directory descriptor to rewind. + */ +APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir); +/** @} */ + +/** + * @defgroup apr_filepath Filepath Manipulation Functions + * @{ + */ + +/** Cause apr_filepath_merge to fail if addpath is above rootpath + * @bug in APR 0.9 and 1.x, this flag's behavior is undefined + * if the rootpath is NULL or empty. In APR 2.0 this should be + * changed to imply NOTABSOLUTE if the rootpath is NULL or empty. + */ +#define APR_FILEPATH_NOTABOVEROOT 0x01 + +/** internal: Only meaningful with APR_FILEPATH_NOTABOVEROOT */ +#define APR_FILEPATH_SECUREROOTTEST 0x02 + +/** Cause apr_filepath_merge to fail if addpath is above rootpath, + * even given a rootpath /foo/bar and an addpath ../bar/bash + */ +#define APR_FILEPATH_SECUREROOT 0x03 + +/** Fail apr_filepath_merge if the merged path is relative */ +#define APR_FILEPATH_NOTRELATIVE 0x04 + +/** Fail apr_filepath_merge if the merged path is absolute */ +#define APR_FILEPATH_NOTABSOLUTE 0x08 + +/** Return the file system's native path format (e.g. path delimiters + * of ':' on MacOS9, '\' on Win32, etc.) */ +#define APR_FILEPATH_NATIVE 0x10 + +/** Resolve the true case of existing directories and file elements + * of addpath, (resolving any aliases on Win32) and append a proper + * trailing slash if a directory + */ +#define APR_FILEPATH_TRUENAME 0x20 + +/** + * Extract the rootpath from the given filepath + * @param rootpath the root file path returned with APR_SUCCESS or APR_EINCOMPLETE + * @param filepath the pathname to parse for its root component + * @param flags the desired rules to apply, from + *
+ *      APR_FILEPATH_NATIVE    Use native path seperators (e.g. '\' on Win32)
+ *      APR_FILEPATH_TRUENAME  Tests that the root exists, and makes it proper
+ * 
+ * @param p the pool to allocate the new path string from + * @remark on return, filepath points to the first non-root character in the + * given filepath. In the simplest example, given a filepath of "/foo", + * returns the rootpath of "/" and filepath points at "foo". This is far + * more complex on other platforms, which will canonicalize the root form + * to a consistant format, given the APR_FILEPATH_TRUENAME flag, and also + * test for the validity of that root (e.g., that a drive d:/ or network + * share //machine/foovol/). + * The function returns APR_ERELATIVE if filepath isn't rooted (an + * error), APR_EINCOMPLETE if the root path is ambigious (but potentially + * legitimate, e.g. "/" on Windows is incomplete because it doesn't specify + * the drive letter), or APR_EBADPATH if the root is simply invalid. + * APR_SUCCESS is returned if filepath is an absolute path. + */ +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, + const char **filepath, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Merge additional file path onto the previously processed rootpath + * @param newpath the merged paths returned + * @param rootpath the root file path (NULL uses the current working path) + * @param addpath the path to add to the root path + * @param flags the desired APR_FILEPATH_ rules to apply when merging + * @param p the pool to allocate the new path string from + * @remark if the flag APR_FILEPATH_TRUENAME is given, and the addpath + * contains wildcard characters ('*', '?') on platforms that don't support + * such characters within filenames, the paths will be merged, but the + * result code will be APR_EPATHWILD, and all further segments will not + * reflect the true filenames including the wildcard and following segments. + */ +APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, + const char *rootpath, + const char *addpath, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Split a search path into separate components + * @param pathelts the returned components of the search path + * @param liststr the search path (e.g., getenv("PATH")) + * @param p the pool to allocate the array and path components from + * @remark empty path componenta do not become part of @a pathelts. + * @remark the path separator in @a liststr is system specific; + * e.g., ':' on Unix, ';' on Windows, etc. + */ +APR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts, + const char *liststr, + apr_pool_t *p); + +/** + * Merge a list of search path components into a single search path + * @param liststr the returned search path; may be NULL if @a pathelts is empty + * @param pathelts the components of the search path + * @param p the pool to allocate the search path from + * @remark emtpy strings in the source array are ignored. + * @remark the path separator in @a liststr is system specific; + * e.g., ':' on Unix, ';' on Windows, etc. + */ +APR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr, + apr_array_header_t *pathelts, + apr_pool_t *p); + +/** + * Return the default file path (for relative file names) + * @param path the default path string returned + * @param flags optional flag APR_FILEPATH_NATIVE to retrieve the + * default file path in os-native format. + * @param p the pool to allocate the default path string from + */ +APR_DECLARE(apr_status_t) apr_filepath_get(char **path, apr_int32_t flags, + apr_pool_t *p); + +/** + * Set the default file path (for relative file names) + * @param path the default path returned + * @param p the pool to allocate any working storage + */ +APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p); + +/** The FilePath character encoding is unknown */ +#define APR_FILEPATH_ENCODING_UNKNOWN 0 + +/** The FilePath character encoding is locale-dependent */ +#define APR_FILEPATH_ENCODING_LOCALE 1 + +/** The FilePath character encoding is UTF-8 */ +#define APR_FILEPATH_ENCODING_UTF8 2 + +/** + * Determine the encoding used internally by the FilePath functions + * @param style points to a variable which receives the encoding style flag + * @param p the pool to allocate any working storage + * @remark Use @c apr_os_locale_encoding and/or @c apr_os_default_encoding + * to get the name of the path encoding if it's not UTF-8. + */ +APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p); +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_FILE_INFO_H */ diff --git a/include/apr-linux/apr_file_io.h b/include/apr-linux/apr_file_io.h new file mode 100644 index 0000000..32a9455 --- /dev/null +++ b/include/apr-linux/apr_file_io.h @@ -0,0 +1,925 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_FILE_IO_H +#define APR_FILE_IO_H + +/** + * @file apr_file_io.h + * @brief APR File I/O Handling + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_time.h" +#include "apr_errno.h" +#include "apr_file_info.h" +#include "apr_inherit.h" + +#define APR_WANT_STDIO /**< for SEEK_* */ +#define APR_WANT_IOVEC /**< for apr_file_writev */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_file_io File I/O Handling Functions + * @ingroup APR + * @{ + */ + +/** + * @defgroup apr_file_open_flags File Open Flags/Routines + * @{ + */ + +/* Note to implementors: Values in the range 0x00100000--0x80000000 + are reserved for platform-specific values. */ + +#define APR_FOPEN_READ 0x00001 /**< Open the file for reading */ +#define APR_FOPEN_WRITE 0x00002 /**< Open the file for writing */ +#define APR_FOPEN_CREATE 0x00004 /**< Create the file if not there */ +#define APR_FOPEN_APPEND 0x00008 /**< Append to the end of the file */ +#define APR_FOPEN_TRUNCATE 0x00010 /**< Open the file and truncate + to 0 length */ +#define APR_FOPEN_BINARY 0x00020 /**< Open the file in binary mode */ +#define APR_FOPEN_EXCL 0x00040 /**< Open should fail if APR_CREATE + and file exists. */ +#define APR_FOPEN_BUFFERED 0x00080 /**< Open the file for buffered I/O */ +#define APR_FOPEN_DELONCLOSE 0x00100 /**< Delete the file after close */ +#define APR_FOPEN_XTHREAD 0x00200 /**< Platform dependent tag to open + the file for use across multiple + threads */ +#define APR_FOPEN_SHARELOCK 0x00400 /**< Platform dependent support for + higher level locked read/write + access to support writes across + process/machines */ +#define APR_FOPEN_NOCLEANUP 0x00800 /**< Do not register a cleanup + when the file is opened */ +#define APR_FOPEN_SENDFILE_ENABLED 0x01000 /**< Advisory flag that this + file should support + apr_socket_sendfile operation */ +#define APR_FOPEN_LARGEFILE 0x04000 /**< Platform dependent flag to enable + * large file support, see WARNING below + */ +#define APR_FOPEN_SPARSE 0x08000 /**< Platform dependent flag to enable + * sparse file support, see WARNING below + */ + +/* backcompat */ +#define APR_READ APR_FOPEN_READ /**< @deprecated @see APR_FOPEN_READ */ +#define APR_WRITE APR_FOPEN_WRITE /**< @deprecated @see APR_FOPEN_WRITE */ +#define APR_CREATE APR_FOPEN_CREATE /**< @deprecated @see APR_FOPEN_CREATE */ +#define APR_APPEND APR_FOPEN_APPEND /**< @deprecated @see APR_FOPEN_APPEND */ +#define APR_TRUNCATE APR_FOPEN_TRUNCATE /**< @deprecated @see APR_FOPEN_TRUNCATE */ +#define APR_BINARY APR_FOPEN_BINARY /**< @deprecated @see APR_FOPEN_BINARY */ +#define APR_EXCL APR_FOPEN_EXCL /**< @deprecated @see APR_FOPEN_EXCL */ +#define APR_BUFFERED APR_FOPEN_BUFFERED /**< @deprecated @see APR_FOPEN_BUFFERED */ +#define APR_DELONCLOSE APR_FOPEN_DELONCLOSE /**< @deprecated @see APR_FOPEN_DELONCLOSE */ +#define APR_XTHREAD APR_FOPEN_XTHREAD /**< @deprecated @see APR_FOPEN_XTHREAD */ +#define APR_SHARELOCK APR_FOPEN_SHARELOCK /**< @deprecated @see APR_FOPEN_SHARELOCK */ +#define APR_FILE_NOCLEANUP APR_FOPEN_NOCLEANUP /**< @deprecated @see APR_FOPEN_NOCLEANUP */ +#define APR_SENDFILE_ENABLED APR_FOPEN_SENDFILE_ENABLED /**< @deprecated @see APR_FOPEN_SENDFILE_ENABLED */ +#define APR_LARGEFILE APR_FOPEN_LARGEFILE /**< @deprecated @see APR_FOPEN_LARGEFILE */ + +/** @warning APR_FOPEN_LARGEFILE flag only has effect on some + * platforms where sizeof(apr_off_t) == 4. Where implemented, it + * allows opening and writing to a file which exceeds the size which + * can be represented by apr_off_t (2 gigabytes). When a file's size + * does exceed 2Gb, apr_file_info_get() will fail with an error on the + * descriptor, likewise apr_stat()/apr_lstat() will fail on the + * filename. apr_dir_read() will fail with APR_INCOMPLETE on a + * directory entry for a large file depending on the particular + * APR_FINFO_* flags. Generally, it is not recommended to use this + * flag. + * + * @warning APR_FOPEN_SPARSE may, depending on platform, convert a + * normal file to a sparse file. Some applications may be unable + * to decipher a sparse file, so it's critical that the sparse file + * flag should only be used for files accessed only by APR or other + * applications known to be able to decipher them. APR does not + * guarentee that it will compress the file into sparse segments + * if it was previously created and written without the sparse flag. + * On platforms which do not understand, or on file systems which + * cannot handle sparse files, the flag is ignored by apr_file_open(). + */ + +/** @} */ + +/** + * @defgroup apr_file_seek_flags File Seek Flags + * @{ + */ + +/* flags for apr_file_seek */ +/** Set the file position */ +#define APR_SET SEEK_SET +/** Current */ +#define APR_CUR SEEK_CUR +/** Go to end of file */ +#define APR_END SEEK_END +/** @} */ + +/** + * @defgroup apr_file_attrs_set_flags File Attribute Flags + * @{ + */ + +/* flags for apr_file_attrs_set */ +#define APR_FILE_ATTR_READONLY 0x01 /**< File is read-only */ +#define APR_FILE_ATTR_EXECUTABLE 0x02 /**< File is executable */ +#define APR_FILE_ATTR_HIDDEN 0x04 /**< File is hidden */ +/** @} */ + +/** + * @defgroup apr_file_writev{_full} max iovec size + * @{ + */ +#if defined(DOXYGEN) +#define APR_MAX_IOVEC_SIZE 1024 /**< System dependent maximum + size of an iovec array */ +#elif defined(IOV_MAX) +#define APR_MAX_IOVEC_SIZE IOV_MAX +#elif defined(MAX_IOVEC) +#define APR_MAX_IOVEC_SIZE MAX_IOVEC +#else +#define APR_MAX_IOVEC_SIZE 1024 +#endif +/** @} */ + +/** File attributes */ +typedef apr_uint32_t apr_fileattrs_t; + +/** Type to pass as whence argument to apr_file_seek. */ +typedef int apr_seek_where_t; + +/** + * Structure for referencing files. + */ +typedef struct apr_file_t apr_file_t; + +/* File lock types/flags */ +/** + * @defgroup apr_file_lock_types File Lock Types + * @{ + */ + +#define APR_FLOCK_SHARED 1 /**< Shared lock. More than one process + or thread can hold a shared lock + at any given time. Essentially, + this is a "read lock", preventing + writers from establishing an + exclusive lock. */ +#define APR_FLOCK_EXCLUSIVE 2 /**< Exclusive lock. Only one process + may hold an exclusive lock at any + given time. This is analogous to + a "write lock". */ + +#define APR_FLOCK_TYPEMASK 0x000F /**< mask to extract lock type */ +#define APR_FLOCK_NONBLOCK 0x0010 /**< do not block while acquiring the + file lock */ +/** @} */ + +/** + * Open the specified file. + * @param newf The opened file descriptor. + * @param fname The full path to the file (using / on all systems) + * @param flag Or'ed value of: + *
+ *         APR_READ              open for reading
+ *         APR_WRITE             open for writing
+ *         APR_CREATE            create the file if not there
+ *         APR_APPEND            file ptr is set to end prior to all writes
+ *         APR_TRUNCATE          set length to zero if file exists
+ *         APR_BINARY            not a text file (This flag is ignored on 
+ *                               UNIX because it has no meaning)
+ *         APR_BUFFERED          buffer the data.  Default is non-buffered
+ *         APR_EXCL              return error if APR_CREATE and file exists
+ *         APR_DELONCLOSE        delete the file after closing.
+ *         APR_XTHREAD           Platform dependent tag to open the file
+ *                               for use across multiple threads
+ *         APR_SHARELOCK         Platform dependent support for higher
+ *                               level locked read/write access to support
+ *                               writes across process/machines
+ *         APR_FILE_NOCLEANUP    Do not register a cleanup with the pool 
+ *                               passed in on the pool argument (see below).
+ *                               The apr_os_file_t handle in apr_file_t will not
+ *                               be closed when the pool is destroyed.
+ *         APR_SENDFILE_ENABLED  Open with appropriate platform semantics
+ *                               for sendfile operations.  Advisory only,
+ *                               apr_socket_sendfile does not check this flag.
+ * 
+ * @param perm Access permissions for file. + * @param pool The pool to use. + * @remark If perm is APR_OS_DEFAULT and the file is being created, + * appropriate default permissions will be used. + * @remark By default, the returned file descriptor will not be + * inherited by child processes created by apr_proc_create(). This + * can be changed using apr_file_inherit_set(). + */ +APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **newf, const char *fname, + apr_int32_t flag, apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Close the specified file. + * @param file The file descriptor to close. + */ +APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file); + +/** + * Delete the specified file. + * @param path The full path to the file (using / on all systems) + * @param pool The pool to use. + * @remark If the file is open, it won't be removed until all + * instances are closed. + */ +APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool); + +/** + * Rename the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param pool The pool to use. + * @warning If a file exists at the new location, then it will be + * overwritten. Moving files or directories across devices may not be + * possible. + */ +APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, + const char *to_path, + apr_pool_t *pool); + +/** + * Copy the specified file to another file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param perms Access permissions for the new file if it is created. + * In place of the usual or'd combination of file permissions, the + * value APR_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + * @remark The new file does not need to exist, it will be created if required. + * @warning If the new file already exists, its contents will be overwritten. + */ +APR_DECLARE(apr_status_t) apr_file_copy(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool); + +/** + * Append the specified file to another file. + * @param from_path The full path to the source file (use / on all systems) + * @param to_path The full path to the destination file (use / on all systems) + * @param perms Access permissions for the destination file if it is created. + * In place of the usual or'd combination of file permissions, the + * value APR_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + * @remark The new file does not need to exist, it will be created if required. + */ +APR_DECLARE(apr_status_t) apr_file_append(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool); + +/** + * Are we at the end of the file + * @param fptr The apr file we are testing. + * @remark Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise. + */ +APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr); + +/** + * Open standard error as an apr file pointer. + * @param thefile The apr file to use as stderr. + * @param pool The pool to allocate the file out of. + * + * @remark The only reason that the apr_file_open_std* functions exist + * is that you may not always have a stderr/out/in on Windows. This + * is generally a problem with newer versions of Windows and services. + * + * @remark The other problem is that the C library functions generally work + * differently on Windows and Unix. So, by using apr_file_open_std* + * functions, you can get a handle to an APR struct that works with + * the APR functions which are supposed to work identically on all + * platforms. + */ +APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard output as an apr file pointer. + * @param thefile The apr file to use as stdout. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr. + */ +APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard input as an apr file pointer. + * @param thefile The apr file to use as stdin. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr. + */ +APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard error as an apr file pointer, with flags. + * @param thefile The apr file to use as stderr. + * @param flags The flags to open the file with. Only the APR_EXCL, + * APR_BUFFERED, APR_XTHREAD, APR_SHARELOCK, + * APR_SENDFILE_ENABLED and APR_LARGEFILE flags should + * be used. The APR_WRITE flag will be set unconditionally. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr. + */ +APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool); + +/** + * open standard output as an apr file pointer, with flags. + * @param thefile The apr file to use as stdout. + * @param flags The flags to open the file with. Only the APR_EXCL, + * APR_BUFFERED, APR_XTHREAD, APR_SHARELOCK, + * APR_SENDFILE_ENABLED and APR_LARGEFILE flags should + * be used. The APR_WRITE flag will be set unconditionally. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr. + */ +APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool); + +/** + * open standard input as an apr file pointer, with flags. + * @param thefile The apr file to use as stdin. + * @param flags The flags to open the file with. Only the APR_EXCL, + * APR_BUFFERED, APR_XTHREAD, APR_SHARELOCK, + * APR_SENDFILE_ENABLED and APR_LARGEFILE flags should + * be used. The APR_READ flag will be set unconditionally. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr. + */ +APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool); + +/** + * Read data from the specified file. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes On entry, the number of bytes to read; on exit, the number + * of bytes read. + * + * @remark apr_file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, all of the available data is read. The third + * argument is modified to reflect the number of bytes read. If a + * char was put back into the stream via ungetc, it will be the first + * character returned. + * + * @remark It is not possible for both bytes to be read and an APR_EOF + * or other error to be returned. APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, + apr_size_t *nbytes); + +/** + * Write data to the specified file. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes On entry, the number of bytes to write; on exit, the number + * of bytes written. + * + * @remark apr_file_write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, it + * will write as many as it can. The third argument is modified to + * reflect the * number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, + apr_size_t *nbytes); + +/** + * Write data from iovec array to the specified file. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + * + * @remark apr_file_writev is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes); + +/** + * Read data from the specified file, ensuring that the buffer is filled + * before returning. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes The number of bytes to read. + * @param bytes_read If non-NULL, this will contain the number of bytes read. + * + * @remark apr_file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, then the process/thread will block until it is + * available or EOF is reached. If a char was put back into the + * stream via ungetc, it will be the first character returned. + * + * @remark It is possible for both bytes to be read and an error to be + * returned. And if *bytes_read is less than nbytes, an accompanying + * error is _always_ returned. + * + * @remark APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_read_full(apr_file_t *thefile, void *buf, + apr_size_t nbytes, + apr_size_t *bytes_read); + +/** + * Write data to the specified file, ensuring that all of the data is + * written before returning. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes The number of bytes to write. + * @param bytes_written If non-NULL, set to the number of bytes written. + * + * @remark apr_file_write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, the + * process/thread will block until they can be written. Exceptional + * error such as "out of space" or "pipe closed" will terminate with + * an error. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. And if *bytes_written is less than nbytes, an + * accompanying error is _always_ returned. + * + * @remark APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile, + const void *buf, + apr_size_t nbytes, + apr_size_t *bytes_written); + + +/** + * Write data from iovec array to the specified file, ensuring that all of the + * data is written before returning. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark apr_file_writev_full is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *nbytes); +/** + * Write a character into the specified file. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile); + +/** + * Read a character from the specified file. + * @param ch The character to read into + * @param thefile The file descriptor to read from + */ +APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile); + +/** + * Put a character back onto a specified stream. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile); + +/** + * Read a string from the specified file. + * @param str The buffer to store the string in. + * @param len The length of the string + * @param thefile The file descriptor to read from + * @remark The buffer will be NUL-terminated if any characters are stored. + */ +APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, + apr_file_t *thefile); + +/** + * Write the string into the specified file. + * @param str The string to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile); + +/** + * Flush the file's buffer. + * @param thefile The file descriptor to flush + */ +APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile); + +/** + * Duplicate the specified file descriptor. + * @param new_file The structure to duplicate into. + * @param old_file The file to duplicate. + * @param p The pool to use for the new file. + * @remark *new_file must point to a valid apr_file_t, or point to NULL. + */ +APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Duplicate the specified file descriptor and close the original + * @param new_file The old file that is to be closed and reused + * @param old_file The file to duplicate + * @param p The pool to use for the new file + * + * @remark new_file MUST point at a valid apr_file_t. It cannot be NULL. + */ +APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Move the specified file descriptor to a new pool + * @param new_file Pointer in which to return the new apr_file_t + * @param old_file The file to move + * @param p The pool to which the descriptor is to be moved + * @remark Unlike apr_file_dup2(), this function doesn't do an + * OS dup() operation on the underlying descriptor; it just + * moves the descriptor's apr_file_t wrapper to a new pool. + * @remark The new pool need not be an ancestor of old_file's pool. + * @remark After calling this function, old_file may not be used + */ +APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Give the specified apr file handle a new buffer + * @param thefile The file handle that is to be modified + * @param buffer The buffer + * @param bufsize The size of the buffer + * @remark It is possible to add a buffer to previously unbuffered + * file handles, the APR_BUFFERED flag will be added to + * the file handle's flags. Likewise, with buffer=NULL and + * bufsize=0 arguments it is possible to make a previously + * buffered file handle unbuffered. + */ +APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *thefile, + char * buffer, + apr_size_t bufsize); + +/** + * Get the size of any buffer for the specified apr file handle + * @param thefile The file handle + */ +APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *thefile); + +/** + * Move the read/write file offset to a specified byte within a file. + * @param thefile The file descriptor + * @param where How to move the pointer, one of: + *
+ *            APR_SET  --  set the offset to offset
+ *            APR_CUR  --  add the offset to the current position 
+ *            APR_END  --  add the offset to the current file size 
+ * 
+ * @param offset The offset to move the pointer to. + * @remark The third argument is modified to be the offset the pointer + was actually moved to. + */ +APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, + apr_seek_where_t where, + apr_off_t *offset); + +/** + * Create an anonymous pipe. + * @param in The newly created pipe's file for reading. + * @param out The newly created pipe's file for writing. + * @param pool The pool to operate on. + * @remark By default, the returned file descriptors will be inherited + * by child processes created using apr_proc_create(). This can be + * changed using apr_file_inherit_unset(). + * @bug Some platforms cannot toggle between blocking and nonblocking, + * and when passing a pipe as a standard handle to an application which + * does not expect it, a non-blocking stream will fluxor the client app. + * @deprecated @see apr_file_pipe_create_ex + */ +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool); + +/** + * Create an anonymous pipe which portably supports async timeout options. + * @param in The newly created pipe's file for reading. + * @param out The newly created pipe's file for writing. + * @param blocking one of these values defined in apr_thread_proc.h; + *
+ *       APR_FULL_BLOCK
+ *       APR_READ_BLOCK
+ *       APR_WRITE_BLOCK
+ *       APR_FULL_NONBLOCK
+ * 
+ * @remark By default, the returned file descriptors will be inherited + * by child processes created using apr_proc_create(). This can be + * changed using apr_file_inherit_unset(). + * @remark Some platforms cannot toggle between blocking and nonblocking, + * and when passing a pipe as a standard handle to an application which + * does not expect it, a non-blocking stream will fluxor the client app. + * Use this function rather than apr_file_pipe_create to create pipes + * where one or both ends require non-blocking semantics. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *p); + +/** + * Create a named pipe. + * @param filename The filename of the named pipe + * @param perm The permissions for the newly created pipe. + * @param pool The pool to operate on. + */ +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Get the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are getting a timeout for. + * @param timeout The current timeout value in microseconds. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, + apr_interval_time_t *timeout); + +/** + * Set the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are setting a timeout on. + * @param timeout The timeout value in microseconds. Values < 0 mean wait + * forever, 0 means do not wait at all. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, + apr_interval_time_t timeout); + +/** file (un)locking functions. */ + +/** + * Establish a lock on the specified, open file. The lock may be advisory + * or mandatory, at the discretion of the platform. The lock applies to + * the file as a whole, rather than a specific range. Locks are established + * on a per-thread/process basis; a second lock by the same thread will not + * block. + * @param thefile The file to lock. + * @param type The type of lock to establish on the file. + */ +APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type); + +/** + * Remove any outstanding locks on the file. + * @param thefile The file to unlock. + */ +APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile); + +/**accessor and general file_io functions. */ + +/** + * return the file name of the current file. + * @param new_path The path of the file. + * @param thefile The currently open file. + */ +APR_DECLARE(apr_status_t) apr_file_name_get(const char **new_path, + apr_file_t *thefile); + +/** + * Return the data associated with the current file. + * @param data The user data associated with the file. + * @param key The key to use for retreiving data associated with this file. + * @param file The currently open file. + */ +APR_DECLARE(apr_status_t) apr_file_data_get(void **data, const char *key, + apr_file_t *file); + +/** + * Set the data associated with the current file. + * @param file The currently open file. + * @param data The user data to associate with the file. + * @param key The key to use for assocaiteing data with the file. + * @param cleanup The cleanup routine to use when the file is destroyed. + */ +APR_DECLARE(apr_status_t) apr_file_data_set(apr_file_t *file, void *data, + const char *key, + apr_status_t (*cleanup)(void *)); + +/** + * Write a string to a file using a printf format. + * @param fptr The file to write to. + * @param format The format string + * @param ... The values to substitute in the format string + * @return The number of bytes written + */ +APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, + const char *format, ...) + __attribute__((format(printf,2,3))); + +/** + * set the specified file's permission bits. + * @param fname The file (name) to apply the permissions to. + * @param perms The permission bits to apply to the file. + * + * @warning Some platforms may not be able to apply all of the + * available permission bits; APR_INCOMPLETE will be returned if some + * permissions are specified which could not be set. + * + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, + apr_fileperms_t perms); + +/** + * Set attributes of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param attributes Or'd combination of + *
+ *            APR_FILE_ATTR_READONLY   - make the file readonly
+ *            APR_FILE_ATTR_EXECUTABLE - make the file executable
+ *            APR_FILE_ATTR_HIDDEN     - make the file hidden
+ * 
+ * @param attr_mask Mask of valid bits in attributes. + * @param pool the pool to use. + * @remark This function should be used in preference to explict manipulation + * of the file permissions, because the operations to provide these + * attributes are platform specific and may involve more than simply + * setting permission bits. + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *pool); + +/** + * Set the mtime of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param mtime The mtime to apply to the file. + * @param pool The pool to use. + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool); + +/** + * Create a new directory on the file system. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm, + apr_pool_t *pool); + +/** Creates a new directory on the file system, but behaves like + * 'mkdir -p'. Creates intermediate directories as required. No error + * will be reported if PATH already exists. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Remove directory from the file system. + * @param path the path for the directory to be removed. (use / on all systems) + * @param pool the pool to use. + * @remark Removing a directory which is in-use (e.g., the current working + * directory, or during apr_dir_read, or with an open file) is not portable. + */ +APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool); + +/** + * get the specified file's stats. + * @param finfo Where to store the information about the file. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values + * @param thefile The file to get information about. + */ +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_file_t *thefile); + + +/** + * Truncate the file's length to the specified offset + * @param fp The file to truncate + * @param offset The offset to truncate to. + * @remark The read/write file offset is repositioned to offset. + */ +APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *fp, apr_off_t offset); + +/** + * Retrieve the flags that were passed into apr_file_open() + * when the file was opened. + * @return apr_int32_t the flags + */ +APR_DECLARE(apr_int32_t) apr_file_flags_get(apr_file_t *f); + +/** + * Get the pool used by the file. + */ +APR_POOL_DECLARE_ACCESSOR(file); + +/** + * Set a file to be inherited by child processes. + * + */ +APR_DECLARE_INHERIT_SET(file); + +/** + * Unset a file from being inherited by child processes. + */ +APR_DECLARE_INHERIT_UNSET(file); + +/** + * Open a temporary file + * @param fp The apr file to use as a temporary file. + * @param templ The template to use when creating a temp file. + * @param flags The flags to open the file with. If this is zero, + * the file is opened with + * APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_DELONCLOSE + * @param p The pool to allocate the file out of. + * @remark + * This function generates a unique temporary file name from template. + * The last six characters of template must be XXXXXX and these are replaced + * with a string that makes the filename unique. Since it will be modified, + * template must not be a string constant, but should be declared as a character + * array. + * + */ +APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *templ, + apr_int32_t flags, apr_pool_t *p); + + +/** + * Find an existing directory suitable as a temporary storage location. + * @param temp_dir The temp directory. + * @param p The pool to use for any necessary allocations. + * @remark + * This function uses an algorithm to search for a directory that an + * an application can use for temporary storage. Once such a + * directory is found, that location is cached by the library. Thus, + * callers only pay the cost of this algorithm once if that one time + * is successful. + * + */ +APR_DECLARE(apr_status_t) apr_temp_dir_get(const char **temp_dir, + apr_pool_t *p); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_FILE_IO_H */ diff --git a/include/apr-linux/apr_fnmatch.h b/include/apr-linux/apr_fnmatch.h new file mode 100644 index 0000000..ef6d0b2 --- /dev/null +++ b/include/apr-linux/apr_fnmatch.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 + */ + +/* This file has been modified by the Apache Software Foundation. */ +#ifndef _APR_FNMATCH_H_ +#define _APR_FNMATCH_H_ + +/** + * @file apr_fnmatch.h + * @brief APR FNMatch Functions + */ + +#include "apr_errno.h" +#include "apr_tables.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_fnmatch Filename Matching Functions + * @ingroup APR + * @{ + */ + +#define APR_FNM_NOMATCH 1 /**< Match failed. */ + +#define APR_FNM_NOESCAPE 0x01 /**< Disable backslash escaping. */ +#define APR_FNM_PATHNAME 0x02 /**< Slash must be matched by slash. */ +#define APR_FNM_PERIOD 0x04 /**< Period must be matched by period. */ +#define APR_FNM_CASE_BLIND 0x08 /**< Compare characters case-insensitively. + * @remark This flag is an Apache addition + */ + +/** + * Try to match the string to the given pattern, return APR_SUCCESS if + * match, else return APR_FNM_NOMATCH. Note that there is no such thing as + * an illegal pattern. + * + * With all flags unset, a pattern is interpreted as such: + * + * PATTERN: Backslash followed by any character, including another + * backslash.
+ * MATCHES: That character exactly. + * + *

+ * PATTERN: ?
+ * MATCHES: Any single character. + *

+ * + *

+ * PATTERN: *
+ * MATCHES: Any sequence of zero or more characters. (Note that multiple + * *s in a row are equivalent to one.) + * + * PATTERN: Any character other than \?*[ or a \ at the end of the pattern
+ * MATCHES: That character exactly. (Case sensitive.) + * + * PATTERN: [ followed by a class description followed by ]
+ * MATCHES: A single character described by the class description. + * (Never matches, if the class description reaches until the + * end of the string without a ].) If the first character of + * the class description is ^ or !, the sense of the description + * is reversed. The rest of the class description is a list of + * single characters or pairs of characters separated by -. Any + * of those characters can have a backslash in front of them, + * which is ignored; this lets you use the characters ] and - + * in the character class, as well as ^ and ! at the + * beginning. The pattern matches a single character if it + * is one of the listed characters or falls into one of the + * listed ranges (inclusive, case sensitive). Ranges with + * the first character larger than the second are legal but + * never match. Edge cases: [] never matches, and [^] and [!] + * always match without consuming a character. + * + * Note that these patterns attempt to match the entire string, not + * just find a substring matching the pattern. + * + * @param pattern The pattern to match to + * @param strings The string we are trying to match + * @param flags flags to use in the match. Bitwise OR of: + *

+ *              APR_FNM_NOESCAPE       Disable backslash escaping
+ *              APR_FNM_PATHNAME       Slash must be matched by slash
+ *              APR_FNM_PERIOD         Period must be matched by period
+ *              APR_FNM_CASE_BLIND     Compare characters case-insensitively.
+ * 
+ */ + +APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, + const char *strings, int flags); + +/** + * Determine if the given pattern is a regular expression. + * @param pattern The pattern to search for glob characters. + * @return non-zero if pattern has any glob characters in it + */ +APR_DECLARE(int) apr_fnmatch_test(const char *pattern); + +/** + * Find all files that match a specified pattern. + * @param pattern The pattern to use for finding files. + * @param result Array to use when storing the results + * @param p The pool to use. + * @return non-zero if pattern has any glob characters in it + */ +APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern, + apr_array_header_t **result, + apr_pool_t *p); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_APR_FNMATCH_H_ */ diff --git a/include/apr-linux/apr_general.h b/include/apr-linux/apr_general.h new file mode 100644 index 0000000..db1f25b --- /dev/null +++ b/include/apr-linux/apr_general.h @@ -0,0 +1,241 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_GENERAL_H +#define APR_GENERAL_H + +/** + * @file apr_general.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @brief APR Miscellaneous library routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#if APR_HAVE_SIGNAL_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_general Miscellaneous library routines + * @ingroup APR + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @{ + */ + +/** FALSE */ +#ifndef FALSE +#define FALSE 0 +#endif +/** TRUE */ +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +/** a space */ +#define APR_ASCII_BLANK '\040' +/** a carrige return */ +#define APR_ASCII_CR '\015' +/** a line feed */ +#define APR_ASCII_LF '\012' +/** a tab */ +#define APR_ASCII_TAB '\011' + +/** signal numbers typedef */ +typedef int apr_signum_t; + +/** + * Finding offsets of elements within structures. + * Taken from the X code... they've sweated portability of this stuff + * so we don't have to. Sigh... + * @param p_type pointer type name + * @param field data field within the structure pointed to + * @return offset + */ + +#if defined(CRAY) || (defined(__arm) && !defined(LINUX)) +#ifdef __STDC__ +#define APR_OFFSET(p_type,field) _Offsetof(p_type,field) +#else +#ifdef CRAY2 +#define APR_OFFSET(p_type,field) \ + (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) + +#else /* !CRAY2 */ + +#define APR_OFFSET(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) + +#endif /* !CRAY2 */ +#endif /* __STDC__ */ +#else /* ! (CRAY || __arm) */ + +#define APR_OFFSET(p_type,field) \ + ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) + +#endif /* !CRAY */ + +/** + * Finding offsets of elements within structures. + * @param s_type structure type name + * @param field data field within the structure + * @return offset + */ +#if defined(offsetof) && !defined(__cplusplus) +#define APR_OFFSETOF(s_type,field) offsetof(s_type,field) +#else +#define APR_OFFSETOF(s_type,field) APR_OFFSET(s_type*,field) +#endif + +#ifndef DOXYGEN + +/* A couple of prototypes for functions in case some platform doesn't + * have it + */ +#if (!APR_HAVE_STRCASECMP) && (APR_HAVE_STRICMP) +#define strcasecmp(s1, s2) stricmp(s1, s2) +#elif (!APR_HAVE_STRCASECMP) +int strcasecmp(const char *a, const char *b); +#endif + +#if (!APR_HAVE_STRNCASECMP) && (APR_HAVE_STRNICMP) +#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n) +#elif (!APR_HAVE_STRNCASECMP) +int strncasecmp(const char *a, const char *b, size_t n); +#endif + +#endif + +/** + * Alignment macros + */ + +/* APR_ALIGN() is only to be used to align on a power of 2 boundary */ +#define APR_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) + +/** Default alignment */ +#define APR_ALIGN_DEFAULT(size) APR_ALIGN(size, 8) + + +/** + * String and memory functions + */ + +/* APR_STRINGIFY is defined here, and also in apr_release.h, so wrap it */ +#ifndef APR_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) +/** Helper macro for APR_STRINGIFY */ +#define APR_STRINGIFY_HELPER(n) #n +#endif + +#if (!APR_HAVE_MEMMOVE) +#define memmove(a,b,c) bcopy(b,a,c) +#endif + +#if (!APR_HAVE_MEMCHR) +void *memchr(const void *s, int c, size_t n); +#endif + +/** @} */ + +/** + * @defgroup apr_library Library initialization and termination + * @{ + */ + +/** + * Setup any APR internal data structures. This MUST be the first function + * called for any APR library. + * @remark See apr_app_initialize if this is an application, rather than + * a library consumer of apr. + */ +APR_DECLARE(apr_status_t) apr_initialize(void); + +/** + * Set up an application with normalized argc, argv (and optionally env) in + * order to deal with platform-specific oddities, such as Win32 services, + * code pages and signals. This must be the first function called for any + * APR program. + * @param argc Pointer to the argc that may be corrected + * @param argv Pointer to the argv that may be corrected + * @param env Pointer to the env that may be corrected, may be NULL + * @remark See apr_initialize if this is a library consumer of apr. + * Otherwise, this call is identical to apr_initialize, and must be closed + * with a call to apr_terminate at the end of program execution. + */ +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + char const * const * *argv, + char const * const * *env); + +/** + * Tear down any APR internal data structures which aren't torn down + * automatically. + * @remark An APR program must call this function at termination once it + * has stopped using APR services. The APR developers suggest using + * atexit to ensure this is called. When using APR from a language + * other than C that has problems with the calling convention, use + * apr_terminate2() instead. + */ +APR_DECLARE_NONSTD(void) apr_terminate(void); + +/** + * Tear down any APR internal data structures which aren't torn down + * automatically, same as apr_terminate + * @remark An APR program must call either the apr_terminate or apr_terminate2 + * function once it it has finished using APR services. The APR + * developers suggest using atexit(apr_terminate) to ensure this is done. + * apr_terminate2 exists to allow non-c language apps to tear down apr, + * while apr_terminate is recommended from c language applications. + */ +APR_DECLARE(void) apr_terminate2(void); + +/** @} */ + +/** + * @defgroup apr_random Random Functions + * @{ + */ + +#if APR_HAS_RANDOM || defined(DOXYGEN) + +/* TODO: I'm not sure this is the best place to put this prototype...*/ +/** + * Generate random bytes. + * @param buf Buffer to fill with random bytes + * @param length Length of buffer in bytes + */ +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf, + apr_size_t length); + +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_GENERAL_H */ diff --git a/include/apr-linux/apr_getopt.h b/include/apr-linux/apr_getopt.h new file mode 100644 index 0000000..75ad566 --- /dev/null +++ b/include/apr-linux/apr_getopt.h @@ -0,0 +1,160 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_GETOPT_H +#define APR_GETOPT_H + +/** + * @file apr_getopt.h + * @brief APR Command Arguments (getopt) + */ + +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_getopt Command Argument Parsing + * @ingroup APR + * @{ + */ + +/** + * An @c apr_getopt_t error callback function. + * + * @a arg is this @c apr_getopt_t's @c errarg member. + */ +typedef void (apr_getopt_err_fn_t)(void *arg, const char *err, ...); + +/** @see apr_getopt_t */ +typedef struct apr_getopt_t apr_getopt_t; + +/** + * Structure to store command line argument information. + */ +struct apr_getopt_t { + /** context for processing */ + apr_pool_t *cont; + /** function to print error message (NULL == no messages) */ + apr_getopt_err_fn_t *errfn; + /** user defined first arg to pass to error message */ + void *errarg; + /** index into parent argv vector */ + int ind; + /** character checked for validity */ + int opt; + /** reset getopt */ + int reset; + /** count of arguments */ + int argc; + /** array of pointers to arguments */ + const char **argv; + /** argument associated with option */ + char const* place; + /** set to nonzero to support interleaving options with regular args */ + int interleave; + /** start of non-option arguments skipped for interleaving */ + int skip_start; + /** end of non-option arguments skipped for interleaving */ + int skip_end; +}; + +/** @see apr_getopt_option_t */ +typedef struct apr_getopt_option_t apr_getopt_option_t; + +/** + * Structure used to describe options that getopt should search for. + */ +struct apr_getopt_option_t { + /** long option name, or NULL if option has no long name */ + const char *name; + /** option letter, or a value greater than 255 if option has no letter */ + int optch; + /** nonzero if option takes an argument */ + int has_arg; + /** a description of the option */ + const char *description; +}; + +/** + * Initialize the arguments for parsing by apr_getopt(). + * @param os The options structure created for apr_getopt() + * @param cont The pool to operate on + * @param argc The number of arguments to parse + * @param argv The array of arguments to parse + * @remark Arguments 3 and 4 are most commonly argc and argv from main(argc, argv) + * The (*os)->errfn is initialized to fprintf(stderr... but may be overridden. + */ +APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont, + int argc, const char * const *argv); + +/** + * Parse the options initialized by apr_getopt_init(). + * @param os The apr_opt_t structure returned by apr_getopt_init() + * @param opts A string of characters that are acceptable options to the + * program. Characters followed by ":" are required to have an + * option associated + * @param option_ch The next option character parsed + * @param option_arg The argument following the option character: + * @return There are four potential status values on exit. They are: + *
+ *             APR_EOF      --  No more options to parse
+ *             APR_BADCH    --  Found a bad option character
+ *             APR_BADARG   --  No argument followed the option flag
+ *             APR_SUCCESS  --  The next option was found.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, + char *option_ch, const char **option_arg); + +/** + * Parse the options initialized by apr_getopt_init(), accepting long + * options beginning with "--" in addition to single-character + * options beginning with "-". + * @param os The apr_getopt_t structure created by apr_getopt_init() + * @param opts A pointer to a list of apr_getopt_option_t structures, which + * can be initialized with { "name", optch, has_args }. has_args + * is nonzero if the option requires an argument. A structure + * with an optch value of 0 terminates the list. + * @param option_ch Receives the value of "optch" from the apr_getopt_option_t + * structure corresponding to the next option matched. + * @param option_arg Receives the argument following the option, if any. + * @return There are four potential status values on exit. They are: + *
+ *             APR_EOF      --  No more options to parse
+ *             APR_BADCH    --  Found a bad option character
+ *             APR_BADARG   --  No argument followed the option flag
+ *             APR_SUCCESS  --  The next option was found.
+ * 
+ * When APR_SUCCESS is returned, os->ind gives the index of the first + * non-option argument. On error, a message will be printed to stdout unless + * os->err is set to 0. If os->interleave is set to nonzero, options can come + * after arguments, and os->argv will be permuted to leave non-option arguments + * at the end (the original argv is unaffected). + */ +APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os, + const apr_getopt_option_t *opts, + int *option_ch, + const char **option_arg); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_GETOPT_H */ diff --git a/include/apr-linux/apr_global_mutex.h b/include/apr-linux/apr_global_mutex.h new file mode 100644 index 0000000..9316001 --- /dev/null +++ b/include/apr-linux/apr_global_mutex.h @@ -0,0 +1,153 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_GLOBAL_MUTEX_H +#define APR_GLOBAL_MUTEX_H + +/** + * @file apr_global_mutex.h + * @brief APR Global Locking Routines + */ + +#include "apr.h" +#include "apr_proc_mutex.h" /* only for apr_lockmech_e */ +#include "apr_pools.h" +#include "apr_errno.h" +#if APR_PROC_MUTEX_IS_GLOBAL +#include "apr_proc_mutex.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_GlobalMutex Global Locking Routines + * @ingroup APR + * @{ + */ + +#if !APR_PROC_MUTEX_IS_GLOBAL || defined(DOXYGEN) + +/** Opaque global mutex structure. */ +typedef struct apr_global_mutex_t apr_global_mutex_t; + +/* Function definitions */ + +/** + * Create and initialize a mutex that can be used to synchronize both + * processes and threads. Note: There is considerable overhead in using + * this API if only cross-process or cross-thread mutual exclusion is + * required. See apr_proc_mutex.h and apr_thread_mutex.h for more + * specialized lock routines. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + *
+ *            APR_LOCK_FCNTL
+ *            APR_LOCK_FLOCK
+ *            APR_LOCK_SYSVSEM
+ *            APR_LOCK_POSIXSEM
+ *            APR_LOCK_PROC_PTHREAD
+ *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_create(apr_global_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool); + +/** + * Re-open a mutex in a child process. + * @param mutex The newly re-opened mutex structure. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_global_mutex_create(). + * @param pool The pool to operate on. + * @remark This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_child_init( + apr_global_mutex_t **mutex, + const char *fname, + apr_pool_t *pool); + +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_lock(apr_global_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_trylock(apr_global_mutex_t *mutex); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_unlock(apr_global_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_destroy(apr_global_mutex_t *mutex); + +/** + * Get the pool used by this global_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(global_mutex); + +#else /* APR_PROC_MUTEX_IS_GLOBAL */ + +/* Some platforms [e.g. Win32] have cross process locks that are truly + * global locks, since there isn't the concept of cross-process locks. + * Define these platforms in terms of an apr_proc_mutex_t. + */ + +#define apr_global_mutex_t apr_proc_mutex_t +#define apr_global_mutex_create apr_proc_mutex_create +#define apr_global_mutex_child_init apr_proc_mutex_child_init +#define apr_global_mutex_lock apr_proc_mutex_lock +#define apr_global_mutex_trylock apr_proc_mutex_trylock +#define apr_global_mutex_unlock apr_proc_mutex_unlock +#define apr_global_mutex_destroy apr_proc_mutex_destroy +#define apr_global_mutex_pool_get apr_proc_mutex_pool_get + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APR_GLOBAL_MUTEX_H */ diff --git a/include/apr-linux/apr_hash.h b/include/apr-linux/apr_hash.h new file mode 100644 index 0000000..e2be1d8 --- /dev/null +++ b/include/apr-linux/apr_hash.h @@ -0,0 +1,257 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_HASH_H +#define APR_HASH_H + +/** + * @file apr_hash.h + * @brief APR Hash Tables + */ + +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_hash Hash Tables + * @ingroup APR + * @{ + */ + +/** + * When passing a key to apr_hash_set or apr_hash_get, this value can be + * passed to indicate a string-valued key, and have apr_hash compute the + * length automatically. + * + * @remark apr_hash will use strlen(key) for the length. The NUL terminator + * is not included in the hash value (why throw a constant in?). + * Since the hash table merely references the provided key (rather + * than copying it), apr_hash_this() will return the NUL-term'd key. + */ +#define APR_HASH_KEY_STRING (-1) + +/** + * Abstract type for hash tables. + */ +typedef struct apr_hash_t apr_hash_t; + +/** + * Abstract type for scanning hash tables. + */ +typedef struct apr_hash_index_t apr_hash_index_t; + +/** + * Callback functions for calculating hash values. + * @param key The key. + * @param klen The length of the key, or APR_HASH_KEY_STRING to use the string + * length. If APR_HASH_KEY_STRING then returns the actual key length. + */ +typedef unsigned int (*apr_hashfunc_t)(const char *key, apr_ssize_t *klen); + +/** + * The default hash function. + */ +unsigned int apr_hashfunc_default(const char *key, apr_ssize_t *klen); + +/** + * Create a hash table. + * @param pool The pool to allocate the hash table out of + * @return The hash table just created + */ +APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool); + +/** + * Create a hash table with a custom hash function + * @param pool The pool to allocate the hash table out of + * @param hash_func A custom hash function. + * @return The hash table just created + */ +APR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool, + apr_hashfunc_t hash_func); + +/** + * Make a copy of a hash table + * @param pool The pool from which to allocate the new hash table + * @param h The hash table to clone + * @return The hash table just created + * @remark Makes a shallow copy + */ +APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool, + const apr_hash_t *h); + +/** + * Associate a value with a key in a hash table. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. + * @param val Value to associate with the key + * @remark If the value is NULL the hash entry is deleted. + */ +APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, const void *key, + apr_ssize_t klen, const void *val); + +/** + * Look up the value associated with a key in a hash table. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. + * @return Returns NULL if the key is not present. + */ +APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, const void *key, + apr_ssize_t klen); + +/** + * Start iterating over the entries in a hash table. + * @param p The pool to allocate the apr_hash_index_t iterator. If this + * pool is NULL, then an internal, non-thread-safe iterator is used. + * @param ht The hash table + * @remark There is no restriction on adding or deleting hash entries during + * an iteration (although the results may be unpredictable unless all you do + * is delete the current entry) and multiple iterations can be in + * progress at the same time. + */ +/** + * @example + * + *
+ * 
+ * int sum_values(apr_pool_t *p, apr_hash_t *ht)
+ * {
+ *     apr_hash_index_t *hi;
+ *     void *val;
+ *     int sum = 0;
+ *     for (hi = apr_hash_first(p, ht); hi; hi = apr_hash_next(hi)) {
+ *         apr_hash_this(hi, NULL, NULL, &val);
+ *         sum += *(int *)val;
+ *     }
+ *     return sum;
+ * }
+ * 
+ */ +APR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht); + +/** + * Continue iterating over the entries in a hash table. + * @param hi The iteration state + * @return a pointer to the updated iteration state. NULL if there are no more + * entries. + */ +APR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi); + +/** + * Get the current entry's details from the iteration state. + * @param hi The iteration state + * @param key Return pointer for the pointer to the key. + * @param klen Return pointer for the key length. + * @param val Return pointer for the associated value. + * @remark The return pointers should point to a variable that will be set to the + * corresponding data, or they may be NULL if the data isn't interesting. + */ +APR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi, const void **key, + apr_ssize_t *klen, void **val); + +/** + * Get the number of key/value pairs in the hash table. + * @param ht The hash table + * @return The number of key/value pairs in the hash table. + */ +APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht); + +/** + * Clear any key/value pairs in the hash table. + * @param ht The hash table + */ +APR_DECLARE(void) apr_hash_clear(apr_hash_t *ht); + +/** + * Merge two hash tables into one new hash table. The values of the overlay + * hash override the values of the base if both have the same key. Both + * hash tables must use the same hash function. + * @param p The pool to use for the new hash table + * @param overlay The table to add to the initial table + * @param base The table that represents the initial values of the new table + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(apr_hash_t *) apr_hash_overlay(apr_pool_t *p, + const apr_hash_t *overlay, + const apr_hash_t *base); + +/** + * Merge two hash tables into one new hash table. If the same key + * is present in both tables, call the supplied merge function to + * produce a merged value for the key in the new table. Both + * hash tables must use the same hash function. + * @param p The pool to use for the new hash table + * @param h1 The first of the tables to merge + * @param h2 The second of the tables to merge + * @param merger A callback function to merge values, or NULL to + * make values from h1 override values from h2 (same semantics as + * apr_hash_overlay()) + * @param data Client data to pass to the merger function + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p, + const apr_hash_t *h1, + const apr_hash_t *h2, + void * (*merger)(apr_pool_t *p, + const void *key, + apr_ssize_t klen, + const void *h1_val, + const void *h2_val, + const void *data), + const void *data); + +/** + * Get the current entry's details from the table state. + * @param p The pool to allocate the apr_hash_index_t iterator. If this + * pool is NULL, then an internal, non-thread-safe iterator is used. + * @param classkey Return pointer for the pointer to the key. + * @param classtable Return pointer for the associated value. + * @remark The return pointers should point to a variable that will be set to the + * corresponding data, or they may be NULL if the data isn't interesting. + */ +APR_DECLARE(void*) apr_class_retrieve(apr_hash_t *classtable, + const char *classkey); + +/** + * Register myclass into a new hash table. The values of the overlay + * hash override the values of the base if both have the same key.. + * @param p The pool to use for the new hash table + * @param classtable The first of the tables to merge + * @param classkey The second of the tables to merge + * @param newclass The table to add to the initial table + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(void) apr_class_register(apr_hash_t **classtable, + const char *classkey, + void *newclass, + apr_pool_t *p); + +/** + * Get a pointer to the pool which the hash table was created in + */ +APR_POOL_DECLARE_ACCESSOR(hash); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_HASH_H */ diff --git a/include/apr-linux/apr_hooks.h b/include/apr-linux/apr_hooks.h new file mode 100644 index 0000000..1a52833 --- /dev/null +++ b/include/apr-linux/apr_hooks.h @@ -0,0 +1,256 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_HOOKS_H +#define APR_HOOKS_H + +#include "apu.h" +/* For apr_array_header_t */ +#include "apr_tables.h" + +/** + * @file apr_hooks.h + * @brief Apache hook functions + */ + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup APR_Util_Hook Hook Functions + * @ingroup APR_Util + * @{ + */ +/** macro to return the prototype of the hook function */ +#define APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \ +link##_DECLARE(apr_array_header_t *) ns##_hook_get_##name(void) + +/** macro to declare the hook correctly */ +#define APR_DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) \ +typedef ret ns##_HOOK_##name##_t args; \ +link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \ + const char * const *aszPre, \ + const char * const *aszSucc, int nOrder); \ +link##_DECLARE(ret) ns##_run_##name args; \ +APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name); \ +typedef struct ns##_LINK_##name##_t \ + { \ + ns##_HOOK_##name##_t *pFunc; \ + const char *szName; \ + const char * const *aszPredecessors; \ + const char * const *aszSuccessors; \ + int nOrder; \ + } ns##_LINK_##name##_t; + +/** macro to declare the hook structure */ +#define APR_HOOK_STRUCT(members) \ +static struct { members } _hooks; + +/** macro to link the hook structure */ +#define APR_HOOK_LINK(name) \ + apr_array_header_t *link_##name; + +/** macro to implement the hook */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf,const char * const *aszPre, \ + const char * const *aszSucc,int nOrder) \ + { \ + ns##_LINK_##name##_t *pHook; \ + if(!_hooks.link_##name) \ + { \ + _hooks.link_##name=apr_array_make(apr_hook_global_pool,1,sizeof(ns##_LINK_##name##_t)); \ + apr_hook_sort_register(#name,&_hooks.link_##name); \ + } \ + pHook=apr_array_push(_hooks.link_##name); \ + pHook->pFunc=pf; \ + pHook->aszPredecessors=aszPre; \ + pHook->aszSuccessors=aszSucc; \ + pHook->nOrder=nOrder; \ + pHook->szName=apr_hook_debug_current; \ + if(apr_hook_debug_enabled) \ + apr_hook_debug_show(#name,aszPre,aszSucc); \ + } \ + APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \ + { \ + return _hooks.link_##name; \ + } + +/** + * Implement a hook that has no return code, and therefore runs all of the + * registered functions + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_VOID(ns,link,name,args_decl,args_use) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(void) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ +\ + if(!_hooks.link_##name) \ + return; \ +\ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + pHook[n].pFunc args_use; \ + } + +/* FIXME: note that this returns ok when nothing is run. I suspect it should + really return decline, but that breaks Apache currently - Ben +*/ +/** + * Implement a hook that runs until one of the functions returns something + * other than OK or DECLINE + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param ret Type to return + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param ok Success value + * @param decline Decline value + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ +\ + if(!_hooks.link_##name) \ + return ok; \ +\ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + rv=pHook[n].pFunc args_use; \ +\ + if(rv != ok && rv != decline) \ + return rv; \ + } \ + return ok; \ + } + + +/** + * Implement a hook that runs until the first function returns something + * other than the value of decline + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param name The name of the hook + * @param ret Type to return + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param decline Decline value + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns,link,ret,name,args_decl,args_use,decline) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ +\ + if(!_hooks.link_##name) \ + return decline; \ +\ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + rv=pHook[n].pFunc args_use; \ +\ + if(rv != decline) \ + return rv; \ + } \ + return decline; \ + } + + /* Hook orderings */ +/** run this hook first, before ANYTHING */ +#define APR_HOOK_REALLY_FIRST (-10) +/** run this hook first */ +#define APR_HOOK_FIRST 0 +/** run this hook somewhere */ +#define APR_HOOK_MIDDLE 10 +/** run this hook after every other hook which is defined*/ +#define APR_HOOK_LAST 20 +/** run this hook last, after EVERYTHING */ +#define APR_HOOK_REALLY_LAST 30 + +/** + * The global pool used to allocate any memory needed by the hooks. + */ +APU_DECLARE_DATA extern apr_pool_t *apr_hook_global_pool; + +/** + * A global variable to determine if debugging information about the + * hooks functions should be printed + */ +APU_DECLARE_DATA extern int apr_hook_debug_enabled; + +/** + * The name of the module that is currently registering a function + */ +APU_DECLARE_DATA extern const char *apr_hook_debug_current; + +/** + * Register a hook function to be sorted + * @param szHookName The name of the Hook the function is registered for + * @param aHooks The array which stores all of the functions for this hook + */ +APU_DECLARE(void) apr_hook_sort_register(const char *szHookName, + apr_array_header_t **aHooks); +/** + * Sort all of the registerd functions for a given hook + */ +APU_DECLARE(void) apr_hook_sort_all(void); + +/** + * Print all of the information about the current hook. This is used for + * debugging purposes. + * @param szName The name of the hook + * @param aszPre All of the functions in the predecessor array + * @param aszSucc All of the functions in the successor array + */ +APU_DECLARE(void) apr_hook_debug_show(const char *szName, + const char * const *aszPre, + const char * const *aszSucc); + +/** + * Remove all currently registered functions. + */ +APU_DECLARE(void) apr_hook_deregister_all(void); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_HOOKS_H */ diff --git a/include/apr-linux/apr_iconv.h b/include/apr-linux/apr_iconv.h new file mode 100644 index 0000000..cc21dfc --- /dev/null +++ b/include/apr-linux/apr_iconv.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1999,2000 + * Konstantin Chuguev. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Konstantin Chuguev + * and its contributors. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef APR_ICONV_H +#define APR_ICONV_H + +#include "apr.h" +#include "apr_pools.h" +#include + +/** + * API_DECLARE_EXPORT is defined when building the libapriconv dynamic + * library, so that all public symbols are exported. + * + * API_DECLARE_STATIC is defined when including the apriconv public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * API_DECLARE_STATIC and API_DECLARE_EXPORT are left undefined when + * including the apr-iconv public headers, to import and link the symbols + * from the dynamic libapriconv library and assure appropriate indirection + * and calling conventions at compile time. + */ + +#if defined(DOXYGEN) || !defined(WIN32) +/** + * The public apr-iconv functions are declared with API_DECLARE(), so they + * use the most portable calling convention. Public apr-iconv functions + * with variable arguments must use API_DECLARE_NONSTD(). + * + * @deffunc API_DECLARE(rettype) apr_func(args); + */ +#define API_DECLARE(type) type +/** + * The private apr-iconv functions are declared with API_DECLARE_NONSTD(), + * so they use the most optimal C language calling conventions. + * + * @deffunc API_DECLARE(rettype) apr_func(args); + */ +#define API_DECLARE_NONSTD(type) type +/** + * All exported apr-iconv variables are declared with API_DECLARE_DATA + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc API_DECLARE_DATA type apr_variable; + * @tip extern API_DECLARE_DATA type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define API_DECLARE_DATA +#elif defined(API_DECLARE_STATIC) +#define API_DECLARE(type) type __stdcall +#define API_DECLARE_NONSTD(type) type __cdecl +#define API_DECLARE_DATA +#elif defined(API_DECLARE_EXPORT) +#define API_DECLARE(type) __declspec(dllexport) type __stdcall +#define API_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define API_DECLARE_DATA __declspec(dllexport) +#else +#define API_DECLARE(type) __declspec(dllimport) type __stdcall +#define API_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define API_DECLARE_DATA __declspec(dllimport) +#endif + +/* + * apr_iconv_t: charset conversion descriptor type + */ +typedef void *apr_iconv_t; + +/* __BEGIN_DECLS */ + +/** + * Create a conversion descriptor. + * @param to name of charset to convert to. + * @param from name of charset of the input bytes. + * @param pool pool to alloc memory. + * @param cd conversion descriptor created in pool. + */ +API_DECLARE(apr_status_t) apr_iconv_open(const char *to, const char *from, + apr_pool_t *pool, apr_iconv_t *cd); +/** + * Perform character set conversion. + * @param cd conversion descriptor created by apr_iconv_open(). + * @param inbuf input buffer. + * @param inbytesleft bytes to convert. + * @param outbuf output buffer. + * @param outbytesleft space (in bytes) available in outbuf. + * @param translated number of input bytes converted. + */ +API_DECLARE(apr_status_t) apr_iconv(apr_iconv_t cd, + const char **inbuf, apr_size_t *inbytesleft, + char **outbuf, apr_size_t *outbytesleft, + apr_size_t *translated); +/** + * Deallocate descriptor for character set conversion. + * @param cd conversion descriptor. + * @param pool pool used in the apr_iconv_open(). + */ +API_DECLARE(apr_status_t) apr_iconv_close(apr_iconv_t cd, apr_pool_t *pool); + +/* __END_DECLS */ + +#endif /* APR_ICONV_H */ diff --git a/include/apr-linux/apr_inherit.h b/include/apr-linux/apr_inherit.h new file mode 100644 index 0000000..b7f7480 --- /dev/null +++ b/include/apr-linux/apr_inherit.h @@ -0,0 +1,51 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_INHERIT_H +#define APR_INHERIT_H + +/** + * @file apr_inherit.h + * @brief APR File Handle Inheritance Helpers + * @remark This internal header includes internal declaration helpers + * for other headers to declare apr_foo_inherit_[un]set functions. + */ + +/** + * Prototype for type-specific declarations of apr_foo_inherit_set + * functions. + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurance of apr_foo_inherit_set. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_DECLARE_INHERIT_SET(type) \ + APR_DECLARE(apr_status_t) apr_##type##_inherit_set( \ + apr_##type##_t *the##type) + +/** + * Prototype for type-specific declarations of apr_foo_inherit_unset + * functions. + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurance of apr_foo_inherit_unset. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_DECLARE_INHERIT_UNSET(type) \ + APR_DECLARE(apr_status_t) apr_##type##_inherit_unset( \ + apr_##type##_t *the##type) + +#endif /* ! APR_INHERIT_H */ diff --git a/include/apr-linux/apr_ldap.h b/include/apr-linux/apr_ldap.h new file mode 100644 index 0000000..e75b8f8 --- /dev/null +++ b/include/apr-linux/apr_ldap.h @@ -0,0 +1,193 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* + * apr_ldap.h is generated from apr_ldap.h.in by configure -- do not edit apr_ldap.h + */ +/** + * @file apr_ldap.h + * @brief APR-UTIL LDAP + */ +#ifndef APU_LDAP_H +#define APU_LDAP_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +/* this will be defined if LDAP support was compiled into apr-util */ +#define APR_HAS_LDAP 0 + +/* identify the LDAP toolkit used */ +#define APR_HAS_NETSCAPE_LDAPSDK 0 +#define APR_HAS_SOLARIS_LDAPSDK 0 +#define APR_HAS_NOVELL_LDAPSDK 0 +#define APR_HAS_MOZILLA_LDAPSDK 0 +#define APR_HAS_OPENLDAP_LDAPSDK 0 +#define APR_HAS_MICROSOFT_LDAPSDK 0 +#define APR_HAS_TIVOLI_LDAPSDK 0 +#define APR_HAS_ZOS_LDAPSDK 0 +#define APR_HAS_OTHER_LDAPSDK 0 + + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/* + * The following #defines are DEPRECATED and should not be used for + * anything. They remain to maintain binary compatibility. + * The original code defined the OPENLDAP SDK as present regardless + * of what really was there, which was way bogus. In addition, the + * apr_ldap_url_parse*() functions have been rewritten specifically for + * APR, so the APR_HAS_LDAP_URL_PARSE macro is forced to zero. + */ +#if APR_HAS_TIVOLI_LDAPSDK +#define APR_HAS_LDAP_SSL 0 +#else +#define APR_HAS_LDAP_SSL 1 +#endif +#define APR_HAS_LDAP_URL_PARSE 0 + +#if APR_HAS_OPENLDAP_LDAPSDK && !defined(LDAP_DEPRECATED) +/* Ensure that the "deprecated" interfaces are still exposed + * with OpenLDAP >= 2.3; these were exposed by default in earlier + * releases. */ +#define LDAP_DEPRECATED 1 +#endif + +/* + * Include the standard LDAP header files. + */ + + + + + + +/* + * Detected standard functions + */ +#define APR_HAS_LDAPSSL_CLIENT_INIT 0 +#define APR_HAS_LDAPSSL_CLIENT_DEINIT 0 +#define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 0 +#define APR_HAS_LDAP_START_TLS_S 0 +#define APR_HAS_LDAP_SSLINIT 0 +#define APR_HAS_LDAPSSL_INIT 0 +#define APR_HAS_LDAPSSL_INSTALL_ROUTINES 0 + +/* + * Make sure the secure LDAP port is defined + */ +#ifndef LDAPS_PORT +#define LDAPS_PORT 636 /* ldaps:/// default LDAP over TLS port */ +#endif + +/* + * For ldap function calls that input a size limit on the number of returned elements + * Some SDKs do not have the define for LDAP_DEFAULT_LIMIT (-1) or LDAP_NO_LIMIT (0) + */ +#if APR_HAS_ZOS_LDAPSDK || APR_HAS_MICROSOFT_LDAPSDK +#define APR_LDAP_SIZELIMIT LDAP_NO_LIMIT +#else +#ifdef LDAP_DEFAULT_LIMIT +#define APR_LDAP_SIZELIMIT LDAP_DEFAULT_LIMIT +#else +#define APR_LDAP_SIZELIMIT -1 /* equivalent to LDAP_DEFAULT_LIMIT */ +#endif +#endif + +/* + * z/OS is missing some defines + */ +#ifndef LDAP_VERSION_MAX +#define LDAP_VERSION_MAX LDAP_VERSION +#endif +#if APR_HAS_ZOS_LDAPSDK +#define LDAP_VENDOR_NAME "IBM z/OS" +#endif + +/* Note: Macros defining const casting has been removed in APR v1.0, + * pending real support for LDAP v2.0 toolkits. + * + * In the mean time, please use an LDAP v3.0 toolkit. + */ +#if LDAP_VERSION_MAX <= 2 +#error Support for LDAP v2.0 toolkits has been removed from apr-util. Please use an LDAP v3.0 toolkit. +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * This structure allows the C LDAP API error codes to be returned + * along with plain text error messages that explain to us mere mortals + * what really happened. + */ +typedef struct apr_ldap_err_t { + const char *reason; + const char *msg; + int rc; +} apr_ldap_err_t; + +#ifdef __cplusplus +} +#endif + +/* The MS SDK returns LDAP_UNAVAILABLE when the backend has closed the connection + * between LDAP calls. Protect with APR_HAS_MICROSOFT_LDAPSDK in case someone + * manually chooses another SDK on Windows + */ +#if APR_HAS_MICROSOFT_LDAPSDK +#define APR_LDAP_IS_SERVER_DOWN(s) ((s) == LDAP_SERVER_DOWN \ + || (s) == LDAP_UNAVAILABLE) +#else +#define APR_LDAP_IS_SERVER_DOWN(s) ((s) == LDAP_SERVER_DOWN) +#endif + +/* These symbols are not actually exported in a DSO build, but mapped into + * a private exported function array for apr_ldap_stub to bind dynamically. + * Rename them appropriately to protect the global namespace. + */ +#ifdef APU_DSO_LDAP_BUILD + +#define apr_ldap_info apr__ldap_info +#define apr_ldap_init apr__ldap_init +#define apr_ldap_ssl_init apr__ldap_ssl_init +#define apr_ldap_ssl_deinit apr__ldap_ssl_deinit +#define apr_ldap_get_option apr__ldap_get_option +#define apr_ldap_set_option apr__ldap_set_option +#define apr_ldap_rebind_init apr__ldap_rebind_init +#define apr_ldap_rebind_add apr__ldap_rebind_add +#define apr_ldap_rebind_remove apr__ldap_rebind_remove + +#define APU_DECLARE_LDAP(type) type +#else +#define APU_DECLARE_LDAP(type) APU_DECLARE(type) +#endif + +#include "apr_ldap_url.h" +#include "apr_ldap_init.h" +#include "apr_ldap_option.h" +#include "apr_ldap_rebind.h" + +/** @} */ +#endif /* APR_HAS_LDAP */ +#endif /* APU_LDAP_H */ diff --git a/include/apr-linux/apr_ldap_init.h b/include/apr-linux/apr_ldap_init.h new file mode 100644 index 0000000..1736aac --- /dev/null +++ b/include/apr-linux/apr_ldap_init.h @@ -0,0 +1,166 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * @file apr_ldap_init.h + * @brief APR-UTIL LDAP ldap_init() functions + */ +#ifndef APR_LDAP_INIT_H +#define APR_LDAP_INIT_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +#include "apr_ldap.h" + +#if APR_HAS_LDAP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** + * Macro to detect security related return values. + */ +#if defined(LDAP_INSUFFICIENT_ACCESS) +#define APU_LDAP_INSUFFICIENT_ACCESS LDAP_INSUFFICIENT_ACCESS +#elif defined(LDAP_INSUFFICIENT_RIGHTS) +#define APU_LDAP_INSUFFICIENT_ACCESS LDAP_INSUFFICIENT_RIGHTS +#elif defined(APR_HAS_MICROSOFT_LDAPSDK) +/* The macros above fail to contemplate that LDAP_RETCODE values + * may be represented by an enum. autoconf tests would be much + * more robust. + */ +#define APU_LDAP_INSUFFICIENT_ACCESS LDAP_INSUFFICIENT_RIGHTS +#else +#error The security return codes must be added to support this LDAP toolkit. +#endif + +#if defined(LDAP_SECURITY_ERROR) +#define APU_LDAP_SECURITY_ERROR LDAP_SECURITY_ERROR +#else +#define APU_LDAP_SECURITY_ERROR(n) \ + (LDAP_INAPPROPRIATE_AUTH == n) ? 1 \ + : (LDAP_INVALID_CREDENTIALS == n) ? 1 \ + : (APU_LDAP_INSUFFICIENT_ACCESS == n) ? 1 \ + : 0 +#endif + + +/** + * APR LDAP SSL Initialise function + * + * This function initialises SSL on the underlying LDAP toolkit + * if this is necessary. + * + * If a CA certificate is provided, this is set, however the setting + * of certificates via this method has been deprecated and will be removed in + * APR v2.0. + * + * The apr_ldap_set_option() function with the APR_LDAP_OPT_TLS_CERT option + * should be used instead to set certificates. + * + * If SSL support is not available on this platform, or a problem + * was encountered while trying to set the certificate, the function + * will return APR_EGENERAL. Further LDAP specific error information + * can be found in result_err. + * @param pool The pool to use + * @param cert_auth_file The name of the certificate to use, can be NULL + * @param cert_file_type The type of certificate specified. See the + * apr_ldap_set_option() APR_LDAP_OPT_TLS_CERT option for details. + * @param result_err The returned result + */ +APU_DECLARE_LDAP(int) apr_ldap_ssl_init(apr_pool_t *pool, + const char *cert_auth_file, + int cert_file_type, + apr_ldap_err_t **result_err); + +/** + * APR LDAP SSL De-Initialise function + * + * This function tears down any SSL certificate setup previously + * set using apr_ldap_ssl_init(). It should be called to clean + * up if a graceful restart of a service is attempted. + * @todo currently we do not check whether apr_ldap_ssl_init() + * has been called first - we probably should. + */ +APU_DECLARE_LDAP(int) apr_ldap_ssl_deinit(void); + +/** + * APR LDAP initialise function + * + * This function is responsible for initialising an LDAP + * connection in a toolkit independant way. It does the + * job of ldap_init() from the C api. + * + * It handles both the SSL and non-SSL case, and attempts + * to hide the complexity setup from the user. This function + * assumes that any certificate setup necessary has already + * been done. + * + * If SSL or STARTTLS needs to be enabled, and the underlying + * toolkit supports it, the following values are accepted for + * secure: + * + * APR_LDAP_NONE: No encryption + * APR_LDAP_SSL: SSL encryption (ldaps://) + * APR_LDAP_STARTTLS: Force STARTTLS on ldap:// + * @remark The Novell toolkit is only able to set the SSL mode via this + * function. To work around this limitation, set the SSL mode here if no + * per connection client certificates are present, otherwise set secure + * APR_LDAP_NONE here, then set the per connection client certificates, + * followed by setting the SSL mode via apr_ldap_set_option(). As Novell + * does not support per connection client certificates, this problem is + * worked around while still being compatible with other LDAP toolkits. + * @param pool The pool to use + * @param ldap The LDAP handle + * @param hostname The name of the host to connect to. This can be either a + * DNS name, or an IP address. + * @param portno The port to connect to + * @param secure The security mode to set + * @param result_err The returned result + */ +APU_DECLARE_LDAP(int) apr_ldap_init(apr_pool_t *pool, + LDAP **ldap, + const char *hostname, + int portno, + int secure, + apr_ldap_err_t **result_err); + +/** + * APR LDAP info function + * + * This function returns a string describing the LDAP toolkit + * currently in use. The string is placed inside result_err->reason. + * @param pool The pool to use + * @param result_err The returned result + */ +APU_DECLARE_LDAP(int) apr_ldap_info(apr_pool_t *pool, + apr_ldap_err_t **result_err); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APR_LDAP_URL_H */ diff --git a/include/apr-linux/apr_ldap_option.h b/include/apr-linux/apr_ldap_option.h new file mode 100644 index 0000000..69f746c --- /dev/null +++ b/include/apr-linux/apr_ldap_option.h @@ -0,0 +1,255 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * @file apr_ldap_option.h + * @brief APR-UTIL LDAP ldap_*_option() functions + */ +#ifndef APR_LDAP_OPTION_H +#define APR_LDAP_OPTION_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +#include "apr_ldap.h" + +#if APR_HAS_LDAP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * The following defines handle the different TLS certificate + * options available. If these options are missing, APR will try and + * emulate support for this using the deprecated ldap_start_tls_s() + * function. + */ +/** + * Set SSL mode to one of APR_LDAP_NONE, APR_LDAP_SSL, APR_LDAP_STARTTLS + * or APR_LDAP_STOPTLS. + */ +#define APR_LDAP_OPT_TLS 0x6fff +/** + * Set zero or more CA certificates, client certificates or private + * keys globally, or per connection (where supported). + */ +#define APR_LDAP_OPT_TLS_CERT 0x6ffe +/** + * Set the LDAP library to no verify the server certificate. This means + * all servers are considered trusted. + */ +#define APR_LDAP_OPT_VERIFY_CERT 0x6ffd +/** + * Set the LDAP library to indicate if referrals should be chased during + * LDAP searches. + */ +#define APR_LDAP_OPT_REFERRALS 0x6ffc +/** + * Set the LDAP library to indicate a maximum number of referral hops to + * chase before giving up on the search. + */ +#define APR_LDAP_OPT_REFHOPLIMIT 0x6ffb + +/** + * Structures for the apr_set_option() cases + */ + +/** + * APR_LDAP_OPT_TLS_CERT + * + * This structure includes possible options to set certificates on + * system initialisation. Different SDKs have different certificate + * requirements, and to achieve this multiple certificates must be + * specified at once passed as an (apr_array_header_t *). + * + * Netscape: + * Needs the CA cert database (cert7.db), the client cert database (key3.db) + * and the security module file (secmod.db) set at the system initialisation + * time. Three types are supported: APR_LDAP_CERT7_DB, APR_LDAP_KEY3_DB and + * APR_LDAP_SECMOD. + * + * To specify a client cert connection, a certificate nickname needs to be + * provided with a type of APR_LDAP_CERT. + * int ldapssl_enable_clientauth( LDAP *ld, char *keynickname, + * char *keypasswd, char *certnickname ); + * keynickname is currently not used, and should be set to "" + * + * Novell: + * Needs CA certificates and client certificates set at system initialisation + * time. Three types are supported: APR_LDAP_CA*, APR_LDAP_CERT* and + * APR_LDAP_KEY*. + * + * Certificates cannot be specified per connection. + * + * The functions used are: + * ldapssl_add_trusted_cert(serverTrustedRoot, serverTrustedRootEncoding); + * Clients certs and keys are set at system initialisation time with + * int ldapssl_set_client_cert ( + * void *cert, + * int type + * void *password); + * type can be LDAPSSL_CERT_FILETYPE_B64 or LDAPSSL_CERT_FILETYPE_DER + * ldapssl_set_client_private_key(clientPrivateKey, + * clientPrivateKeyEncoding, + * clientPrivateKeyPassword); + * + * OpenSSL: + * Needs one or more CA certificates to be set at system initialisation time + * with a type of APR_LDAP_CA*. + * + * May have one or more client certificates set per connection with a type of + * APR_LDAP_CERT*, and keys with APR_LDAP_KEY*. + */ +/** CA certificate type unknown */ +#define APR_LDAP_CA_TYPE_UNKNOWN 0 +/** binary DER encoded CA certificate */ +#define APR_LDAP_CA_TYPE_DER 1 +/** PEM encoded CA certificate */ +#define APR_LDAP_CA_TYPE_BASE64 2 +/** Netscape/Mozilla cert7.db CA certificate database */ +#define APR_LDAP_CA_TYPE_CERT7_DB 3 +/** Netscape/Mozilla secmod file */ +#define APR_LDAP_CA_TYPE_SECMOD 4 +/** Client certificate type unknown */ +#define APR_LDAP_CERT_TYPE_UNKNOWN 5 +/** binary DER encoded client certificate */ +#define APR_LDAP_CERT_TYPE_DER 6 +/** PEM encoded client certificate */ +#define APR_LDAP_CERT_TYPE_BASE64 7 +/** Netscape/Mozilla key3.db client certificate database */ +#define APR_LDAP_CERT_TYPE_KEY3_DB 8 +/** Netscape/Mozilla client certificate nickname */ +#define APR_LDAP_CERT_TYPE_NICKNAME 9 +/** Private key type unknown */ +#define APR_LDAP_KEY_TYPE_UNKNOWN 10 +/** binary DER encoded private key */ +#define APR_LDAP_KEY_TYPE_DER 11 +/** PEM encoded private key */ +#define APR_LDAP_KEY_TYPE_BASE64 12 +/** PKCS#12 encoded client certificate */ +#define APR_LDAP_CERT_TYPE_PFX 13 +/** PKCS#12 encoded private key */ +#define APR_LDAP_KEY_TYPE_PFX 14 +/** Openldap directory full of base64-encoded cert + * authorities with hashes in corresponding .0 directory + */ +#define APR_LDAP_CA_TYPE_CACERTDIR_BASE64 15 + + +/** + * Certificate structure. + * + * This structure is used to store certificate details. An array of + * these structures is passed to apr_ldap_set_option() to set CA + * and client certificates. + * @param type Type of certificate APR_LDAP_*_TYPE_* + * @param path Path, file or nickname of the certificate + * @param password Optional password, can be NULL + */ +typedef struct apr_ldap_opt_tls_cert_t apr_ldap_opt_tls_cert_t; +struct apr_ldap_opt_tls_cert_t { + int type; + const char *path; + const char *password; +}; + +/** + * APR_LDAP_OPT_TLS + * + * This sets the SSL level on the LDAP handle. + * + * Netscape/Mozilla: + * Supports SSL, but not STARTTLS + * SSL is enabled by calling ldapssl_install_routines(). + * + * Novell: + * Supports SSL and STARTTLS. + * SSL is enabled by calling ldapssl_install_routines(). Note that calling + * other ldap functions before ldapssl_install_routines() may cause this + * function to fail. + * STARTTLS is enabled by calling ldapssl_start_tls_s() after calling + * ldapssl_install_routines() (check this). + * + * OpenLDAP: + * Supports SSL and supports STARTTLS, but none of this is documented: + * http://www.openldap.org/lists/openldap-software/200409/msg00618.html + * Documentation for both SSL support and STARTTLS has been deleted from + * the OpenLDAP documentation and website. + */ + +/** No encryption */ +#define APR_LDAP_NONE 0 +/** SSL encryption (ldaps://) */ +#define APR_LDAP_SSL 1 +/** TLS encryption (STARTTLS) */ +#define APR_LDAP_STARTTLS 2 +/** end TLS encryption (STOPTLS) */ +#define APR_LDAP_STOPTLS 3 + +/** + * APR LDAP get option function + * + * This function gets option values from a given LDAP session if + * one was specified. It maps to the native ldap_get_option() function. + * @param pool The pool to use + * @param ldap The LDAP handle + * @param option The LDAP_OPT_* option to return + * @param outvalue The value returned (if any) + * @param result_err The apr_ldap_err_t structure contained detailed results + * of the operation. + */ +APU_DECLARE_LDAP(int) apr_ldap_get_option(apr_pool_t *pool, + LDAP *ldap, + int option, + void *outvalue, + apr_ldap_err_t **result_err); + +/** + * APR LDAP set option function + * + * This function sets option values to a given LDAP session if + * one was specified. It maps to the native ldap_set_option() function. + * + * Where an option is not supported by an LDAP toolkit, this function + * will try and apply legacy functions to achieve the same effect, + * depending on the platform. + * @param pool The pool to use + * @param ldap The LDAP handle + * @param option The LDAP_OPT_* option to set + * @param invalue The value to set + * @param result_err The apr_ldap_err_t structure contained detailed results + * of the operation. + */ +APU_DECLARE_LDAP(int) apr_ldap_set_option(apr_pool_t *pool, + LDAP *ldap, + int option, + const void *invalue, + apr_ldap_err_t **result_err); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APR_LDAP_OPTION_H */ + diff --git a/include/apr-linux/apr_ldap_rebind.h b/include/apr-linux/apr_ldap_rebind.h new file mode 100644 index 0000000..e1ee804 --- /dev/null +++ b/include/apr-linux/apr_ldap_rebind.h @@ -0,0 +1,87 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * The APR LDAP rebind functions provide an implementation of + * a rebind procedure that can be used to allow clients to chase referrals, + * using the same credentials used to log in originally. + * + * Use of this implementation is optional. + * + * @file apu_ldap_rebind.h + * @brief Apache LDAP library + */ + +#ifndef APU_LDAP_REBIND_H +#define APU_LDAP_REBIND_H + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/** + * APR LDAP initialize rebind lock + * + * This function creates the lock for controlling access to the xref list.. + * @param pool Pool to use when creating the xref_lock. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_init(apr_pool_t *pool); + + +/** + * APR LDAP rebind_add function + * + * This function creates a cross reference entry for the specified ldap + * connection. The rebind callback function will look up this ldap + * connection so it can retrieve the bindDN and bindPW for use in any + * binds while referrals are being chased. + * + * This function will add the callback to the LDAP handle passed in. + * + * A cleanup is registered within the pool provided to remove this + * entry when the pool is removed. Alternatively apr_ldap_rebind_remove() + * can be called to explicitly remove the entry at will. + * + * @param pool The pool to use + * @param ld The LDAP connectionhandle + * @param bindDN The bind DN to be used for any binds while chasing + * referrals on this ldap connection. + * @param bindPW The bind Password to be used for any binds while + * chasing referrals on this ldap connection. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_add(apr_pool_t *pool, + LDAP *ld, + const char *bindDN, + const char *bindPW); + +/** + * APR LDAP rebind_remove function + * + * This function removes the rebind cross reference entry for the + * specified ldap connection. + * + * If not explicitly removed, this function will be called automatically + * when the pool is cleaned up. + * + * @param ld The LDAP connectionhandle + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_remove(LDAP *ld); + +#endif /* APR_HAS_LDAP */ + +#endif /* APU_LDAP_REBIND_H */ + diff --git a/include/apr-linux/apr_ldap_url.h b/include/apr-linux/apr_ldap_url.h new file mode 100644 index 0000000..6ebda83 --- /dev/null +++ b/include/apr-linux/apr_ldap_url.h @@ -0,0 +1,117 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * @file apr_ldap_url.h + * @brief APR-UTIL LDAP ldap_init() functions + */ +#ifndef APR_LDAP_URL_H +#define APR_LDAP_URL_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +#if APR_HAS_LDAP + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Structure to access an exploded LDAP URL */ +typedef struct apr_ldap_url_desc_t { + struct apr_ldap_url_desc_t *lud_next; + char *lud_scheme; + char *lud_host; + int lud_port; + char *lud_dn; + char **lud_attrs; + int lud_scope; + char *lud_filter; + char **lud_exts; + int lud_crit_exts; +} apr_ldap_url_desc_t; + +#ifndef APR_LDAP_URL_SUCCESS +#define APR_LDAP_URL_SUCCESS 0x00 /* Success */ +#define APR_LDAP_URL_ERR_MEM 0x01 /* can't allocate memory space */ +#define APR_LDAP_URL_ERR_PARAM 0x02 /* parameter is bad */ +#define APR_LDAP_URL_ERR_BADSCHEME 0x03 /* URL doesn't begin with "ldap[si]://" */ +#define APR_LDAP_URL_ERR_BADENCLOSURE 0x04 /* URL is missing trailing ">" */ +#define APR_LDAP_URL_ERR_BADURL 0x05 /* URL is bad */ +#define APR_LDAP_URL_ERR_BADHOST 0x06 /* host port is bad */ +#define APR_LDAP_URL_ERR_BADATTRS 0x07 /* bad (or missing) attributes */ +#define APR_LDAP_URL_ERR_BADSCOPE 0x08 /* scope string is invalid (or missing) */ +#define APR_LDAP_URL_ERR_BADFILTER 0x09 /* bad or missing filter */ +#define APR_LDAP_URL_ERR_BADEXTS 0x0a /* bad or missing extensions */ +#endif + +/** + * Is this URL an ldap url? ldap:// + * @param url The url to test + */ +APU_DECLARE(int) apr_ldap_is_ldap_url(const char *url); + +/** + * Is this URL an SSL ldap url? ldaps:// + * @param url The url to test + */ +APU_DECLARE(int) apr_ldap_is_ldaps_url(const char *url); + +/** + * Is this URL an ldap socket url? ldapi:// + * @param url The url to test + */ +APU_DECLARE(int) apr_ldap_is_ldapi_url(const char *url); + +/** + * Parse an LDAP URL. + * @param pool The pool to use + * @param url_in The URL to parse + * @param ludpp The structure to return the exploded URL + * @param result_err The result structure of the operation + */ +APU_DECLARE(int) apr_ldap_url_parse_ext(apr_pool_t *pool, + const char *url_in, + apr_ldap_url_desc_t **ludpp, + apr_ldap_err_t **result_err); + +/** + * Parse an LDAP URL. + * @param pool The pool to use + * @param url_in The URL to parse + * @param ludpp The structure to return the exploded URL + * @param result_err The result structure of the operation + */ +APU_DECLARE(int) apr_ldap_url_parse(apr_pool_t *pool, + const char *url_in, + apr_ldap_url_desc_t **ludpp, + apr_ldap_err_t **result_err); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APR_LDAP_URL_H */ diff --git a/include/apr-linux/apr_lib.h b/include/apr-linux/apr_lib.h new file mode 100644 index 0000000..e09122e --- /dev/null +++ b/include/apr-linux/apr_lib.h @@ -0,0 +1,240 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_LIB_H +#define APR_LIB_H + +/** + * @file apr_lib.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @brief APR general purpose library routines + */ + +#include "apr.h" +#include "apr_errno.h" + +#if APR_HAVE_CTYPE_H +#include +#endif +#if APR_HAVE_STDARG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_lib General Purpose Library Routines + * @ingroup APR + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @{ + */ + +/** A constant representing a 'large' string. */ +#define HUGE_STRING_LEN 8192 + +/* + * Define the structures used by the APR general-purpose library. + */ + +/** @see apr_vformatter_buff_t */ +typedef struct apr_vformatter_buff_t apr_vformatter_buff_t; + +/** + * Structure used by the variable-formatter routines. + */ +struct apr_vformatter_buff_t { + /** The current position */ + char *curpos; + /** The end position of the format string */ + char *endpos; +}; + +/** + * return the final element of the pathname + * @param pathname The path to get the final element of + * @return the final element of the path + * @remark + *
+ * For example:
+ *                 "/foo/bar/gum"    -> "gum"
+ *                 "/foo/bar/gum/"   -> ""
+ *                 "gum"             -> "gum"
+ *                 "bs\\path\\stuff" -> "stuff"
+ * 
+ */ +APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname); + +/** + * apr_killpg + * Small utility macros to make things easier to read. Not usually a + * goal, to be sure.. + */ + +#ifdef WIN32 +#define apr_killpg(x, y) +#else /* WIN32 */ +#ifdef NO_KILLPG +#define apr_killpg(x, y) (kill (-(x), (y))) +#else /* NO_KILLPG */ +#define apr_killpg(x, y) (killpg ((x), (y))) +#endif /* NO_KILLPG */ +#endif /* WIN32 */ + +/** + * apr_vformatter() is a generic printf-style formatting routine + * with some extensions. + * @param flush_func The function to call when the buffer is full + * @param c The buffer to write to + * @param fmt The format string + * @param ap The arguments to use to fill out the format string. + * + * @remark + *
+ * The extensions are:
+ *
+ * %%pA	takes a struct in_addr *, and prints it as a.b.c.d
+ * %%pI	takes an apr_sockaddr_t * and prints it as a.b.c.d:port or
+ *      [ipv6-address]:port
+ * %%pT takes an apr_os_thread_t * and prints it in decimal
+ *      ('0' is printed if !APR_HAS_THREADS)
+ * %%pt takes an apr_os_thread_t * and prints it in hexadecimal
+ *      ('0' is printed if !APR_HAS_THREADS)
+ * %%pm takes an apr_status_t * and prints the appropriate error
+ *      string (from apr_strerror) corresponding to that error code.
+ * %%pp takes a void * and outputs it in hex
+ * %%pB takes a apr_uint32_t * as bytes and outputs it's apr_strfsize
+ * %%pF same as above, but takes a apr_off_t *
+ * %%pS same as above, but takes a apr_size_t *
+ *
+ * %%pt is only available from APR 1.2.0 onwards.
+ * %%pm, %%pB, %%pF and %%pS are only available from APR 1.3.0 onwards.
+ * 
+ * The %%p hacks are to force gcc's printf warning code to skip
+ * over a pointer argument without complaining.  This does
+ * mean that the ANSI-style %%p (output a void * in hex format) won't
+ * work as expected at all, but that seems to be a fair trade-off
+ * for the increased robustness of having printf-warnings work.
+ *
+ * Additionally, apr_vformatter allows for arbitrary output methods
+ * using the apr_vformatter_buff and flush_func.
+ *
+ * The apr_vformatter_buff has two elements curpos and endpos.
+ * curpos is where apr_vformatter will write the next byte of output.
+ * It proceeds writing output to curpos, and updating curpos, until
+ * either the end of output is reached, or curpos == endpos (i.e. the
+ * buffer is full).
+ *
+ * If the end of output is reached, apr_vformatter returns the
+ * number of bytes written.
+ *
+ * When the buffer is full, the flush_func is called.  The flush_func
+ * can return -1 to indicate that no further output should be attempted,
+ * and apr_vformatter will return immediately with -1.  Otherwise
+ * the flush_func should flush the buffer in whatever manner is
+ * appropriate, re apr_pool_t nitialize curpos and endpos, and return 0.
+ *
+ * Note that flush_func is only invoked as a result of attempting to
+ * write another byte at curpos when curpos >= endpos.  So for
+ * example, it's possible when the output exactly matches the buffer
+ * space available that curpos == endpos will be true when
+ * apr_vformatter returns.
+ *
+ * apr_vformatter does not call out to any other code, it is entirely
+ * self-contained.  This allows the callers to do things which are
+ * otherwise "unsafe".  For example, apr_psprintf uses the "scratch"
+ * space at the unallocated end of a block, and doesn't actually
+ * complete the allocation until apr_vformatter returns.  apr_psprintf
+ * would be completely broken if apr_vformatter were to call anything
+ * that used this same pool.  Similarly http_bprintf() uses the "scratch"
+ * space at the end of its output buffer, and doesn't actually note
+ * that the space is in use until it either has to flush the buffer
+ * or until apr_vformatter returns.
+ * 
+ */ +APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *b), + apr_vformatter_buff_t *c, const char *fmt, + va_list ap); + +/** + * Display a prompt and read in the password from stdin. + * @param prompt The prompt to display + * @param pwbuf Buffer to store the password + * @param bufsize The length of the password buffer. + * @remark If the password entered must be truncated to fit in + * the provided buffer, APR_ENAMETOOLONG will be returned. + * Note that the bufsize paramater is passed by reference for no + * reason; its value will never be modified by the apr_password_get() + * function. + */ +APR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, + apr_size_t *bufsize); + +/** @} */ + +/** + * @defgroup apr_ctype ctype functions + * These macros allow correct support of 8-bit characters on systems which + * support 8-bit characters. Pretty dumb how the cast is required, but + * that's legacy libc for ya. These new macros do not support EOF like + * the standard macros do. Tough. + * @{ + */ +/** @see isalnum */ +#define apr_isalnum(c) (isalnum(((unsigned char)(c)))) +/** @see isalpha */ +#define apr_isalpha(c) (isalpha(((unsigned char)(c)))) +/** @see iscntrl */ +#define apr_iscntrl(c) (iscntrl(((unsigned char)(c)))) +/** @see isdigit */ +#define apr_isdigit(c) (isdigit(((unsigned char)(c)))) +/** @see isgraph */ +#define apr_isgraph(c) (isgraph(((unsigned char)(c)))) +/** @see islower*/ +#define apr_islower(c) (islower(((unsigned char)(c)))) +/** @see isascii */ +#ifdef isascii +#define apr_isascii(c) (isascii(((unsigned char)(c)))) +#else +#define apr_isascii(c) (((c) & ~0x7f)==0) +#endif +/** @see isprint */ +#define apr_isprint(c) (isprint(((unsigned char)(c)))) +/** @see ispunct */ +#define apr_ispunct(c) (ispunct(((unsigned char)(c)))) +/** @see isspace */ +#define apr_isspace(c) (isspace(((unsigned char)(c)))) +/** @see isupper */ +#define apr_isupper(c) (isupper(((unsigned char)(c)))) +/** @see isxdigit */ +#define apr_isxdigit(c) (isxdigit(((unsigned char)(c)))) +/** @see tolower */ +#define apr_tolower(c) (tolower(((unsigned char)(c)))) +/** @see toupper */ +#define apr_toupper(c) (toupper(((unsigned char)(c)))) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_LIB_H */ diff --git a/include/apr-linux/apr_md4.h b/include/apr-linux/apr_md4.h new file mode 100644 index 0000000..43fb33e --- /dev/null +++ b/include/apr-linux/apr_md4.h @@ -0,0 +1,135 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * 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. MD4 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. MD4 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 APR_MD4_H +#define APR_MD4_H + +#include "apu.h" +#include "apr_xlate.h" +/** + * @file apr_md4.h + * @brief APR-UTIL MD4 Library + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_MD4 MD4 Library + * @ingroup APR_Util + * @{ + */ + +/** The digestsize for MD4 */ +#define APR_MD4_DIGESTSIZE 16 + +/** @see apr_md4_ctx_t */ +typedef struct apr_md4_ctx_t apr_md4_ctx_t; + +/** MD4 context. */ +struct apr_md4_ctx_t { + /** state (ABCD) */ + apr_uint32_t state[4]; + /** number of bits, modulo 2^64 (lsb first) */ + apr_uint32_t count[2]; + /** input buffer */ + unsigned char buffer[64]; +#if APR_HAS_XLATE + /** translation handle */ + apr_xlate_t *xlate; +#endif +}; + +/** + * MD4 Initialize. Begins an MD4 operation, writing a new context. + * @param context The MD4 context to initialize. + */ +APU_DECLARE(apr_status_t) apr_md4_init(apr_md4_ctx_t *context); + +#if APR_HAS_XLATE +/** + * MDr4 translation setup. Provides the APR translation handle to be used + * for translating the content before calculating the digest. + * @param context The MD4 content to set the translation for. + * @param xlate The translation handle to use for this MD4 context + */ +APU_DECLARE(apr_status_t) apr_md4_set_xlate(apr_md4_ctx_t *context, + apr_xlate_t *xlate); +#else +#define apr_md4_set_xlate(context, xlate) APR_ENOTIMPL +#endif + +/** + * MD4 block update operation. Continue an MD4 message-digest operation, + * processing another message block, and updating the context. + * @param context The MD4 content to update. + * @param input next message block to update + * @param inputLen The length of the next message block + */ +APU_DECLARE(apr_status_t) apr_md4_update(apr_md4_ctx_t *context, + const unsigned char *input, + apr_size_t inputLen); + +/** + * MD4 finalization. Ends an MD4 message-digest operation, writing the + * message digest and zeroing the context + * @param digest The final MD4 digest + * @param context The MD4 content we are finalizing. + */ +APU_DECLARE(apr_status_t) apr_md4_final( + unsigned char digest[APR_MD4_DIGESTSIZE], + apr_md4_ctx_t *context); + +/** + * MD4 digest computation + * @param digest The MD4 digest + * @param input message block to use + * @param inputLen The length of the message block + */ +APU_DECLARE(apr_status_t) apr_md4(unsigned char digest[APR_MD4_DIGESTSIZE], + const unsigned char *input, + apr_size_t inputLen); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_MD4_H */ diff --git a/include/apr-linux/apr_md5.h b/include/apr-linux/apr_md5.h new file mode 100644 index 0000000..367324a --- /dev/null +++ b/include/apr-linux/apr_md5.h @@ -0,0 +1,162 @@ +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* 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. + */ + +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_MD5_H +#define APR_MD5_H + +#include "apu.h" +#include "apr_xlate.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @file apr_md5.h + * @brief APR MD5 Routines + */ + +/** + * @defgroup APR_MD5 MD5 Routines + * @ingroup APR + * @{ + */ + +/** The MD5 digest size */ +#define APR_MD5_DIGESTSIZE 16 + +/** @see apr_md5_ctx_t */ +typedef struct apr_md5_ctx_t apr_md5_ctx_t; + +/** MD5 context. */ +struct apr_md5_ctx_t { + /** state (ABCD) */ + apr_uint32_t state[4]; + /** number of bits, modulo 2^64 (lsb first) */ + apr_uint32_t count[2]; + /** input buffer */ + unsigned char buffer[64]; + /** translation handle + * ignored if xlate is unsupported + */ + apr_xlate_t *xlate; +}; + +/** + * MD5 Initialize. Begins an MD5 operation, writing a new context. + * @param context The MD5 context to initialize. + */ +APU_DECLARE(apr_status_t) apr_md5_init(apr_md5_ctx_t *context); + +/** + * MD5 translation setup. Provides the APR translation handle to be used + * for translating the content before calculating the digest. + * @param context The MD5 content to set the translation for. + * @param xlate The translation handle to use for this MD5 context + */ +APU_DECLARE(apr_status_t) apr_md5_set_xlate(apr_md5_ctx_t *context, + apr_xlate_t *xlate); + +/** + * MD5 block update operation. Continue an MD5 message-digest operation, + * processing another message block, and updating the context. + * @param context The MD5 content to update. + * @param input next message block to update + * @param inputLen The length of the next message block + */ +APU_DECLARE(apr_status_t) apr_md5_update(apr_md5_ctx_t *context, + const void *input, + apr_size_t inputLen); + +/** + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * message digest and zeroing the context + * @param digest The final MD5 digest + * @param context The MD5 content we are finalizing. + */ +APU_DECLARE(apr_status_t) apr_md5_final(unsigned char digest[APR_MD5_DIGESTSIZE], + apr_md5_ctx_t *context); + +/** + * MD5 in one step + * @param digest The final MD5 digest + * @param input The message block to use + * @param inputLen The length of the message block + */ +APU_DECLARE(apr_status_t) apr_md5(unsigned char digest[APR_MD5_DIGESTSIZE], + const void *input, + apr_size_t inputLen); + +/** + * Encode a password using an MD5 algorithm + * @param password The password to encode + * @param salt The salt to use for the encoding + * @param result The string to store the encoded password in + * @param nbytes The size of the result buffer + */ +APU_DECLARE(apr_status_t) apr_md5_encode(const char *password, const char *salt, + char *result, apr_size_t nbytes); + + +/** + * Validate hashes created by APR-supported algorithms: md5 and sha1. + * hashes created by crypt are supported only on platforms that provide + * crypt(3), so don't rely on that function unless you know that your + * application will be run only on platforms that support it. On platforms + * that don't support crypt(3), this falls back to a clear text string + * comparison. + * @param passwd The password to validate + * @param hash The password to validate against + */ +APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, + const char *hash); + + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_MD5_H */ diff --git a/include/apr-linux/apr_memcache.h b/include/apr-linux/apr_memcache.h new file mode 100644 index 0000000..499d280 --- /dev/null +++ b/include/apr-linux/apr_memcache.h @@ -0,0 +1,446 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_MEMCACHE_H +#define APR_MEMCACHE_H + +/** + * @file apr_memcache.h + * @brief Client interface for memcached + * @remark To use this interface you must have a separate memcached + * server running. See the memcached website at http://www.danga.com/memcached/ + * for more information. + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_time.h" +#include "apr_strings.h" +#include "apr_network_io.h" +#include "apr_ring.h" +#include "apr_buckets.h" +#include "apr_reslist.h" +#include "apr_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_MC Memcached Client Routines + * @ingroup APR_Util + * @{ + */ + +/** Specifies the status of a memcached server */ +typedef enum +{ + APR_MC_SERVER_LIVE, /**< Server is alive and responding to requests */ + APR_MC_SERVER_DEAD /**< Server is not responding to requests */ +} apr_memcache_server_status_t; + +/** Opaque memcache client connection object */ +typedef struct apr_memcache_conn_t apr_memcache_conn_t; + +/** Memcache Server Info Object */ +typedef struct apr_memcache_server_t apr_memcache_server_t; +struct apr_memcache_server_t +{ + const char *host; /**< Hostname of this Server */ + apr_port_t port; /**< Port of this Server */ + apr_memcache_server_status_t status; /**< @see apr_memcache_server_status_t */ +#if APR_HAS_THREADS || defined(DOXYGEN) + apr_reslist_t *conns; /**< Resource list of actual client connections */ +#else + apr_memcache_conn_t *conn; +#endif + apr_pool_t *p; /** Pool to use for private allocations */ +#if APR_HAS_THREADS + apr_thread_mutex_t *lock; +#endif + apr_time_t btime; +}; + +/* Custom hash callback function prototype, user for server selection. +* @param baton user selected baton +* @param data data to hash +* @param data_len length of data +*/ +typedef apr_uint32_t (*apr_memcache_hash_func)(void *baton, + const char *data, + const apr_size_t data_len); + +typedef struct apr_memcache_t apr_memcache_t; + +/* Custom Server Select callback function prototype. +* @param baton user selected baton +* @param mc memcache instance, use mc->live_servers to select a node +* @param hash hash of the selected key. +*/ +typedef apr_memcache_server_t* (*apr_memcache_server_func)(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash); + +/** Container for a set of memcached servers */ +struct apr_memcache_t +{ + apr_uint32_t flags; /**< Flags, Not currently used */ + apr_uint16_t nalloc; /**< Number of Servers Allocated */ + apr_uint16_t ntotal; /**< Number of Servers Added */ + apr_memcache_server_t **live_servers; /**< Array of Servers */ + apr_pool_t *p; /** Pool to use for allocations */ + void *hash_baton; + apr_memcache_hash_func hash_func; + void *server_baton; + apr_memcache_server_func server_func; +}; + +/** Returned Data from a multiple get */ +typedef struct +{ + apr_status_t status; + const char* key; + apr_size_t len; + char *data; + apr_uint16_t flags; +} apr_memcache_value_t; + +/** + * Creates a crc32 hash used to split keys between servers + * @param data Data to be hashed + * @param data_len Length of the data to use + * @return crc32 hash of data + * @remark The crc32 hash is not compatible with old memcached clients. + */ +APU_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc, + const char *data, + const apr_size_t data_len); + +/** + * Pure CRC32 Hash. Used by some clients. + */ +APU_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * hash compatible with the standard Perl Client. + */ +APU_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * Picks a server based on a hash + * @param mc The memcache client object to use + * @param hash Hashed value of a Key + * @return server that controls specified hash + * @see apr_memcache_hash + */ +APU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server_hash(apr_memcache_t *mc, + const apr_uint32_t hash); + +/** + * server selection compatible with the standard Perl Client. + */ +APU_DECLARE(apr_memcache_server_t *) +apr_memcache_find_server_hash_default(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash); + +/** + * Adds a server to a client object + * @param mc The memcache client object to use + * @param ms Server to add + * @remark Adding servers is not thread safe, and should be done once at startup. + * @warning Changing servers after startup may cause keys to go to + * different servers. + */ +APU_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, + apr_memcache_server_t *server); + + +/** + * Finds a Server object based on a hostname/port pair + * @param mc The memcache client object to use + * @param host Hostname of the server + * @param port Port of the server + * @return Server with matching Hostname and Port, or NULL if none was found. + */ +APU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, + const char *host, + apr_port_t port); + +/** + * Enables a Server for use again + * @param mc The memcache client object to use + * @param ms Server to Activate + */ +APU_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, + apr_memcache_server_t *ms); + + +/** + * Disable a Server + * @param mc The memcache client object to use + * @param ms Server to Disable + */ +APU_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, + apr_memcache_server_t *ms); + +/** + * Creates a new Server Object + * @param p Pool to use + * @param host hostname of the server + * @param port port of the server + * @param min minimum number of client sockets to open + * @param smax soft maximum number of client connections to open + * @param max hard maximum number of client connections + * @param ttl time to live in seconds of a client connection + * @param ns location of the new server object + * @see apr_reslist_create + * @remark min, smax, and max are only used when APR_HAS_THREADS + */ +APU_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p, + const char *host, + apr_port_t port, + apr_uint32_t min, + apr_uint32_t smax, + apr_uint32_t max, + apr_uint32_t ttl, + apr_memcache_server_t **ns); +/** + * Creates a new memcached client object + * @param p Pool to use + * @param max_servers maximum number of servers + * @param flags Not currently used + * @param mc location of the new memcache client object + */ +APU_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p, + apr_uint16_t max_servers, + apr_uint32_t flags, + apr_memcache_t **mc); + +/** + * Gets a value from the server, allocating the value out of p + * @param mc client to use + * @param p Pool to use + * @param key null terminated string containing the key + * @param baton location of the allocated value + * @param len length of data at baton + * @param flags any flags set by the client for this key + * @return + */ +APU_DECLARE(apr_status_t) apr_memcache_getp(apr_memcache_t *mc, + apr_pool_t *p, + const char* key, + char **baton, + apr_size_t *len, + apr_uint16_t *flags); + + +/** + * Add a key to a hash for a multiget query + * if the hash (*value) is NULL it will be created + * @param data_pool pool from where the hash and their items are created from + * @param key null terminated string containing the key + * @param values hash of keys and values that this key will be added to + * @return + */ +APU_DECLARE(void) +apr_memcache_add_multget_key(apr_pool_t *data_pool, + const char* key, + apr_hash_t **values); + +/** + * Gets multiple values from the server, allocating the values out of p + * @param mc client to use + * @param temp_pool Pool used for tempoary allocations. May be cleared inside this + * call. + * @param data_pool Pool used to allocate data for the returned values. + * @param values hash of apr_memcache_value_t keyed by strings, contains the + * result of the multiget call. + * @return + */ +APU_DECLARE(apr_status_t) +apr_memcache_multgetp(apr_memcache_t *mc, + apr_pool_t *temp_pool, + apr_pool_t *data_pool, + apr_hash_t *values); + +/** + * Sets a value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param len length of data at baton + * @param timeout time in seconds for the data to live on the server + * @param flags any flags set by the client for this key + */ +APU_DECLARE(apr_status_t) apr_memcache_set(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Adds value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param len length of data at baton + * @param timeout time for the data to live on the server + * @param flags any flags set by the client for this key + * @return APR_SUCCESS if the key was added, APR_EEXIST if the key + * already exists on the server. + */ +APU_DECLARE(apr_status_t) apr_memcache_add(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Replaces value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param len length of data at baton + * @param timeout time for the data to live on the server + * @param flags any flags set by the client for this key + * @return APR_SUCCESS if the key was added, APR_EEXIST if the key + * did not exist on the server. + */ +APU_DECLARE(apr_status_t) apr_memcache_replace(apr_memcache_t *mc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); +/** + * Deletes a key from a server + * @param mc client to use + * @param key null terminated string containing the key + * @param timeout time for the delete to stop other clients from adding + */ +APU_DECLARE(apr_status_t) apr_memcache_delete(apr_memcache_t *mc, + const char *key, + apr_uint32_t timeout); + +/** + * Increments a value + * @param mc client to use + * @param key null terminated string containing the key + * @param n number to increment by + * @param nv new value after incrmenting + */ +APU_DECLARE(apr_status_t) apr_memcache_incr(apr_memcache_t *mc, + const char *key, + apr_int32_t n, + apr_uint32_t *nv); + +/** + * Decrements a value + * @param mc client to use + * @param key null terminated string containing the key + * @param n number to decrement by + * @param nv new value after decrementing + */ +APU_DECLARE(apr_status_t) apr_memcache_decr(apr_memcache_t *mc, + const char *key, + apr_int32_t n, + apr_uint32_t *new_value); + +/** + * Query a server's version + * @param ms server to query + * @param p Pool to allocate answer from + * @param baton location to store server version string + * @param len length of the server version string + */ +APU_DECLARE(apr_status_t) apr_memcache_version(apr_memcache_server_t *ms, + apr_pool_t *p, + char **baton); + +typedef struct +{ + /** Version string of this server */ + const char *version; + /** Process id of this server process */ + apr_uint32_t pid; + /** Number of seconds this server has been running */ + apr_uint32_t uptime; + /** current UNIX time according to the server */ + apr_time_t time; + /** The size of a pointer on the current machine */ + apr_uint32_t pointer_size; + /** Accumulated user time for this process */ + apr_time_t rusage_user; + /** Accumulated system time for this process */ + apr_time_t rusage_system; + /** Current number of items stored by the server */ + apr_uint32_t curr_items; + /** Total number of items stored by this server */ + apr_uint32_t total_items; + /** Current number of bytes used by this server to store items */ + apr_uint64_t bytes; + /** Number of open connections */ + apr_uint32_t curr_connections; + /** Total number of connections opened since the server started running */ + apr_uint32_t total_connections; + /** Number of connection structures allocated by the server */ + apr_uint32_t connection_structures; + /** Cumulative number of retrieval requests */ + apr_uint32_t cmd_get; + /** Cumulative number of storage requests */ + apr_uint32_t cmd_set; + /** Number of keys that have been requested and found present */ + apr_uint32_t get_hits; + /** Number of items that have been requested and not found */ + apr_uint32_t get_misses; + /** Number of items removed from cache because they passed their + expiration time */ + apr_uint64_t evictions; + /** Total number of bytes read by this server */ + apr_uint64_t bytes_read; + /** Total number of bytes sent by this server */ + apr_uint64_t bytes_written; + /** Number of bytes this server is allowed to use for storage. */ + apr_uint32_t limit_maxbytes; + /** Number of threads the server is running (if built with threading) */ + apr_uint32_t threads; +} apr_memcache_stats_t; + +/** + * Query a server for statistics + * @param ms server to query + * @param p Pool to allocate answer from + * @param stats location of the new statistics structure + */ +APU_DECLARE(apr_status_t) apr_memcache_stats(apr_memcache_server_t *ms, + apr_pool_t *p, + apr_memcache_stats_t **stats); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_MEMCACHE_H */ diff --git a/include/apr-linux/apr_mmap.h b/include/apr-linux/apr_mmap.h new file mode 100644 index 0000000..77d697f --- /dev/null +++ b/include/apr-linux/apr_mmap.h @@ -0,0 +1,171 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_MMAP_H +#define APR_MMAP_H + +/** + * @file apr_mmap.h + * @brief APR MMAP routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_ring.h" +#include "apr_file_io.h" /* for apr_file_t */ + +#ifdef BEOS +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_mmap MMAP (Memory Map) Routines + * @ingroup APR + * @{ + */ + +/** MMap opened for reading */ +#define APR_MMAP_READ 1 +/** MMap opened for writing */ +#define APR_MMAP_WRITE 2 + +/** @see apr_mmap_t */ +typedef struct apr_mmap_t apr_mmap_t; + +/** + * @remark + * As far as I can tell the only really sane way to store an MMAP is as a + * void * and a length. BeOS requires this area_id, but that's just a little + * something extra. I am exposing this type, because it doesn't make much + * sense to keep it private, and opening it up makes some stuff easier in + * Apache. + */ +/** The MMAP structure */ +struct apr_mmap_t { + /** The pool the mmap structure was allocated out of. */ + apr_pool_t *cntxt; +#ifdef BEOS + /** An area ID. Only valid on BeOS */ + area_id area; +#endif +#ifdef WIN32 + /** The handle of the file mapping */ + HANDLE mhandle; + /** The start of the real memory page area (mapped view) */ + void *mv; + /** The physical start, size and offset */ + apr_off_t pstart; + apr_size_t psize; + apr_off_t poffset; +#endif + /** The start of the memory mapped area */ + void *mm; + /** The amount of data in the mmap */ + apr_size_t size; + /** ring of apr_mmap_t's that reference the same + * mmap'ed region; acts in place of a reference count */ + APR_RING_ENTRY(apr_mmap_t) link; +}; + +#if APR_HAS_MMAP || defined(DOXYGEN) + +/** @def APR_MMAP_THRESHOLD + * Files have to be at least this big before they're mmap()d. This is to deal + * with systems where the expense of doing an mmap() and an munmap() outweighs + * the benefit for small files. It shouldn't be set lower than 1. + */ +#ifdef MMAP_THRESHOLD +# define APR_MMAP_THRESHOLD MMAP_THRESHOLD +#else +# ifdef SUNOS4 +# define APR_MMAP_THRESHOLD (8*1024) +# else +# define APR_MMAP_THRESHOLD 1 +# endif /* SUNOS4 */ +#endif /* MMAP_THRESHOLD */ + +/** @def APR_MMAP_LIMIT + * Maximum size of MMap region + */ +#ifdef MMAP_LIMIT +# define APR_MMAP_LIMIT MMAP_LIMIT +#else +# define APR_MMAP_LIMIT (4*1024*1024) +#endif /* MMAP_LIMIT */ + +/** Can this file be MMaped */ +#define APR_MMAP_CANDIDATE(filelength) \ + ((filelength >= APR_MMAP_THRESHOLD) && (filelength < APR_MMAP_LIMIT)) + +/* Function definitions */ + +/** + * Create a new mmap'ed file out of an existing APR file. + * @param newmmap The newly created mmap'ed file. + * @param file The file turn into an mmap. + * @param offset The offset into the file to start the data pointer at. + * @param size The size of the file + * @param flag bit-wise or of: + *
+ *          APR_MMAP_READ       MMap opened for reading
+ *          APR_MMAP_WRITE      MMap opened for writing
+ * 
+ * @param cntxt The pool to use when creating the mmap. + */ +APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **newmmap, + apr_file_t *file, apr_off_t offset, + apr_size_t size, apr_int32_t flag, + apr_pool_t *cntxt); + +/** + * Duplicate the specified MMAP. + * @param new_mmap The structure to duplicate into. + * @param old_mmap The mmap to duplicate. + * @param p The pool to use for new_mmap. + */ +APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, + apr_mmap_t *old_mmap, + apr_pool_t *p); + +/** + * Remove a mmap'ed. + * @param mm The mmap'ed file. + */ +APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm); + +/** + * Move the pointer into the mmap'ed file to the specified offset. + * @param addr The pointer to the offset specified. + * @param mm The mmap'ed file. + * @param offset The offset to move to. + */ +APR_DECLARE(apr_status_t) apr_mmap_offset(void **addr, apr_mmap_t *mm, + apr_off_t offset); + +#endif /* APR_HAS_MMAP */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_MMAP_H */ diff --git a/include/apr-linux/apr_network_io.h b/include/apr-linux/apr_network_io.h new file mode 100644 index 0000000..a852c93 --- /dev/null +++ b/include/apr-linux/apr_network_io.h @@ -0,0 +1,842 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_NETWORK_IO_H +#define APR_NETWORK_IO_H +/** + * @file apr_network_io.h + * @brief APR Network library + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_errno.h" +#include "apr_inherit.h" + +#if APR_HAVE_NETINET_IN_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_network_io Network Routines + * @ingroup APR + * @{ + */ + +#ifndef APR_MAX_SECS_TO_LINGER +/** Maximum seconds to linger */ +#define APR_MAX_SECS_TO_LINGER 30 +#endif + +#ifndef APRMAXHOSTLEN +/** Maximum hostname length */ +#define APRMAXHOSTLEN 256 +#endif + +#ifndef APR_ANYADDR +/** Default 'any' address */ +#define APR_ANYADDR "0.0.0.0" +#endif + +/** + * @defgroup apr_sockopt Socket option definitions + * @{ + */ +#define APR_SO_LINGER 1 /**< Linger */ +#define APR_SO_KEEPALIVE 2 /**< Keepalive */ +#define APR_SO_DEBUG 4 /**< Debug */ +#define APR_SO_NONBLOCK 8 /**< Non-blocking IO */ +#define APR_SO_REUSEADDR 16 /**< Reuse addresses */ +#define APR_SO_BROADCAST 32 /**< Permit sending of broadcast msgs */ +#define APR_SO_SNDBUF 64 /**< Send buffer */ +#define APR_SO_RCVBUF 128 /**< Receive buffer */ +#define APR_SO_DISCONNECTED 256 /**< Disconnected */ +#define APR_TCP_NODELAY 512 /**< For SCTP sockets, this is mapped + * to STCP_NODELAY internally. + */ +#define APR_TCP_NOPUSH 1024 /**< No push */ +#define APR_RESET_NODELAY 2048 /**< This flag is ONLY set internally + * when we set APR_TCP_NOPUSH with + * APR_TCP_NODELAY set to tell us that + * APR_TCP_NODELAY should be turned on + * again when NOPUSH is turned off + */ +#define APR_INCOMPLETE_READ 4096 /**< Set on non-blocking sockets + * (timeout != 0) on which the + * previous read() did not fill a buffer + * completely. the next apr_socket_recv() + * will first call select()/poll() rather than + * going straight into read(). (Can also + * be set by an application to force a + * select()/poll() call before the next + * read, in cases where the app expects + * that an immediate read would fail.) + */ +#define APR_INCOMPLETE_WRITE 8192 /**< like APR_INCOMPLETE_READ, but for write + * @see APR_INCOMPLETE_READ + */ +#define APR_IPV6_V6ONLY 16384 /**< Don't accept IPv4 connections on an + * IPv6 listening socket. + */ +#define APR_TCP_DEFER_ACCEPT 32768 /**< Delay accepting of new connections + * until data is available. + * @see apr_socket_accept_filter + */ + +/** @} */ + +/** Define what type of socket shutdown should occur. */ +typedef enum { + APR_SHUTDOWN_READ, /**< no longer allow read request */ + APR_SHUTDOWN_WRITE, /**< no longer allow write requests */ + APR_SHUTDOWN_READWRITE /**< no longer allow read or write requests */ +} apr_shutdown_how_e; + +#define APR_IPV4_ADDR_OK 0x01 /**< @see apr_sockaddr_info_get() */ +#define APR_IPV6_ADDR_OK 0x02 /**< @see apr_sockaddr_info_get() */ + +#if (!APR_HAVE_IN_ADDR) +/** + * We need to make sure we always have an in_addr type, so APR will just + * define it ourselves, if the platform doesn't provide it. + */ +struct in_addr { + apr_uint32_t s_addr; /**< storage to hold the IP# */ +}; +#endif + +/** @def APR_INADDR_NONE + * Not all platforms have a real INADDR_NONE. This macro replaces + * INADDR_NONE on all platforms. + */ +#ifdef INADDR_NONE +#define APR_INADDR_NONE INADDR_NONE +#else +#define APR_INADDR_NONE ((unsigned int) 0xffffffff) +#endif + +/** + * @def APR_INET + * Not all platforms have these defined, so we'll define them here + * The default values come from FreeBSD 4.1.1 + */ +#define APR_INET AF_INET +/** @def APR_UNSPEC + * Let the system decide which address family to use + */ +#ifdef AF_UNSPEC +#define APR_UNSPEC AF_UNSPEC +#else +#define APR_UNSPEC 0 +#endif +#if APR_HAVE_IPV6 +/** @def APR_INET6 +* IPv6 Address Family. Not all platforms may have this defined. +*/ + +#define APR_INET6 AF_INET6 +#endif + +/** + * @defgroup IP_Proto IP Protocol Definitions for use when creating sockets + * @{ + */ +#define APR_PROTO_TCP 6 /**< TCP */ +#define APR_PROTO_UDP 17 /**< UDP */ +#define APR_PROTO_SCTP 132 /**< SCTP */ +/** @} */ + +/** + * Enum used to denote either the local and remote endpoint of a + * connection. + */ +typedef enum { + APR_LOCAL, /**< Socket information for local end of connection */ + APR_REMOTE /**< Socket information for remote end of connection */ +} apr_interface_e; + +/** + * The specific declaration of inet_addr's ... some platforms fall back + * inet_network (this is not good, but necessary) + */ + +#if APR_HAVE_INET_ADDR +#define apr_inet_addr inet_addr +#elif APR_HAVE_INET_NETWORK /* only DGUX, as far as I know */ +/** + * @warning + * not generally safe... inet_network() and inet_addr() perform + * different functions */ +#define apr_inet_addr inet_network +#endif + +/** A structure to represent sockets */ +typedef struct apr_socket_t apr_socket_t; +/** + * A structure to encapsulate headers and trailers for apr_socket_sendfile + */ +typedef struct apr_hdtr_t apr_hdtr_t; +/** A structure to represent in_addr */ +typedef struct in_addr apr_in_addr_t; +/** A structure to represent an IP subnet */ +typedef struct apr_ipsubnet_t apr_ipsubnet_t; + +/** @remark use apr_uint16_t just in case some system has a short that isn't 16 bits... */ +typedef apr_uint16_t apr_port_t; + +/** @remark It's defined here as I think it should all be platform safe... + * @see apr_sockaddr_t + */ +typedef struct apr_sockaddr_t apr_sockaddr_t; +/** + * APRs socket address type, used to ensure protocol independence + */ +struct apr_sockaddr_t { + /** The pool to use... */ + apr_pool_t *pool; + /** The hostname */ + char *hostname; + /** Either a string of the port number or the service name for the port */ + char *servname; + /** The numeric port */ + apr_port_t port; + /** The family */ + apr_int32_t family; + /** How big is the sockaddr we're using? */ + apr_socklen_t salen; + /** How big is the ip address structure we're using? */ + int ipaddr_len; + /** How big should the address buffer be? 16 for v4 or 46 for v6 + * used in inet_ntop... */ + int addr_str_len; + /** This points to the IP address structure within the appropriate + * sockaddr structure. */ + void *ipaddr_ptr; + /** If multiple addresses were found by apr_sockaddr_info_get(), this + * points to a representation of the next address. */ + apr_sockaddr_t *next; + /** Union of either IPv4 or IPv6 sockaddr. */ + union { + /** IPv4 sockaddr structure */ + struct sockaddr_in sin; +#if APR_HAVE_IPV6 + /** IPv6 sockaddr structure */ + struct sockaddr_in6 sin6; +#endif +#if APR_HAVE_SA_STORAGE + /** Placeholder to ensure that the size of this union is not + * dependent on whether APR_HAVE_IPV6 is defined. */ + struct sockaddr_storage sas; +#endif + } sa; +}; + +#if APR_HAS_SENDFILE +/** + * Support reusing the socket on platforms which support it (from disconnect, + * specifically Win32. + * @remark Optional flag passed into apr_socket_sendfile() + */ +#define APR_SENDFILE_DISCONNECT_SOCKET 1 +#endif + +/** A structure to encapsulate headers and trailers for apr_socket_sendfile */ +struct apr_hdtr_t { + /** An iovec to store the headers sent before the file. */ + struct iovec* headers; + /** number of headers in the iovec */ + int numheaders; + /** An iovec to store the trailers sent after the file. */ + struct iovec* trailers; + /** number of trailers in the iovec */ + int numtrailers; +}; + +/* function definitions */ + +/** + * Create a socket. + * @param new_sock The new socket that has been set up. + * @param family The address family of the socket (e.g., APR_INET). + * @param type The type of the socket (e.g., SOCK_STREAM). + * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP). + * @param cont The pool for the apr_socket_t and associated storage. + */ +APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new_sock, + int family, int type, + int protocol, + apr_pool_t *cont); + +/** + * Shutdown either reading, writing, or both sides of a socket. + * @param thesocket The socket to close + * @param how How to shutdown the socket. One of: + *
+ *            APR_SHUTDOWN_READ         no longer allow read requests
+ *            APR_SHUTDOWN_WRITE        no longer allow write requests
+ *            APR_SHUTDOWN_READWRITE    no longer allow read or write requests 
+ * 
+ * @see apr_shutdown_how_e + * @remark This does not actually close the socket descriptor, it just + * controls which calls are still valid on the socket. + */ +APR_DECLARE(apr_status_t) apr_socket_shutdown(apr_socket_t *thesocket, + apr_shutdown_how_e how); + +/** + * Close a socket. + * @param thesocket The socket to close + */ +APR_DECLARE(apr_status_t) apr_socket_close(apr_socket_t *thesocket); + +/** + * Bind the socket to its associated port + * @param sock The socket to bind + * @param sa The socket address to bind to + * @remark This may be where we will find out if there is any other process + * using the selected port. + */ +APR_DECLARE(apr_status_t) apr_socket_bind(apr_socket_t *sock, + apr_sockaddr_t *sa); + +/** + * Listen to a bound socket for connections. + * @param sock The socket to listen on + * @param backlog The number of outstanding connections allowed in the sockets + * listen queue. If this value is less than zero, the listen + * queue size is set to zero. + */ +APR_DECLARE(apr_status_t) apr_socket_listen(apr_socket_t *sock, + apr_int32_t backlog); + +/** + * Accept a new connection request + * @param new_sock A copy of the socket that is connected to the socket that + * made the connection request. This is the socket which should + * be used for all future communication. + * @param sock The socket we are listening on. + * @param connection_pool The pool for the new socket. + */ +APR_DECLARE(apr_status_t) apr_socket_accept(apr_socket_t **new_sock, + apr_socket_t *sock, + apr_pool_t *connection_pool); + +/** + * Issue a connection request to a socket either on the same machine + * or a different one. + * @param sock The socket we wish to use for our side of the connection + * @param sa The address of the machine we wish to connect to. + */ +APR_DECLARE(apr_status_t) apr_socket_connect(apr_socket_t *sock, + apr_sockaddr_t *sa); + +/** + * Create apr_sockaddr_t from hostname, address family, and port. + * @param sa The new apr_sockaddr_t. + * @param hostname The hostname or numeric address string to resolve/parse, or + * NULL to build an address that corresponds to 0.0.0.0 or :: + * @param family The address family to use, or APR_UNSPEC if the system should + * decide. + * @param port The port number. + * @param flags Special processing flags: + *
+ *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
+ *                                 for IPv6 addresses if the first query failed;
+ *                                 only valid if family is APR_UNSPEC and hostname
+ *                                 isn't NULL; mutually exclusive with
+ *                                 APR_IPV6_ADDR_OK
+ *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
+ *                                 for IPv4 addresses if the first query failed;
+ *                                 only valid if family is APR_UNSPEC and hostname
+ *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
+ *                                 with APR_IPV4_ADDR_OK
+ * 
+ * @param p The pool for the apr_sockaddr_t and associated storage. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, + const char *hostname, + apr_int32_t family, + apr_port_t port, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Look up the host name from an apr_sockaddr_t. + * @param hostname The hostname. + * @param sa The apr_sockaddr_t. + * @param flags Special processing flags. + */ +APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, + apr_sockaddr_t *sa, + apr_int32_t flags); + +/** + * Parse hostname/IP address with scope id and port. + * + * Any of the following strings are accepted: + * 8080 (just the port number) + * www.apache.org (just the hostname) + * www.apache.org:8080 (hostname and port number) + * [fe80::1]:80 (IPv6 numeric address string only) + * [fe80::1%eth0] (IPv6 numeric address string and scope id) + * + * Invalid strings: + * (empty string) + * [abc] (not valid IPv6 numeric address string) + * abc:65536 (invalid port number) + * + * @param addr The new buffer containing just the hostname. On output, *addr + * will be NULL if no hostname/IP address was specfied. + * @param scope_id The new buffer containing just the scope id. On output, + * *scope_id will be NULL if no scope id was specified. + * @param port The port number. On output, *port will be 0 if no port was + * specified. + * ### FIXME: 0 is a legal port (per RFC 1700). this should + * ### return something besides zero if the port is missing. + * @param str The input string to be parsed. + * @param p The pool from which *addr and *scope_id are allocated. + * @remark If scope id shouldn't be allowed, check for scope_id != NULL in + * addition to checking the return code. If addr/hostname should be + * required, check for addr == NULL in addition to checking the + * return code. + */ +APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, + char **scope_id, + apr_port_t *port, + const char *str, + apr_pool_t *p); + +/** + * Get name of the current machine + * @param buf A buffer to store the hostname in. + * @param len The maximum length of the hostname that can be stored in the + * buffer provided. The suggested length is APRMAXHOSTLEN + 1. + * @param cont The pool to use. + * @remark If the buffer was not large enough, an error will be returned. + */ +APR_DECLARE(apr_status_t) apr_gethostname(char *buf, int len, apr_pool_t *cont); + +/** + * Return the data associated with the current socket + * @param data The user data associated with the socket. + * @param key The key to associate with the user data. + * @param sock The currently open socket. + */ +APR_DECLARE(apr_status_t) apr_socket_data_get(void **data, const char *key, + apr_socket_t *sock); + +/** + * Set the data associated with the current socket. + * @param sock The currently open socket. + * @param data The user data to associate with the socket. + * @param key The key to associate with the data. + * @param cleanup The cleanup to call when the socket is destroyed. + */ +APR_DECLARE(apr_status_t) apr_socket_data_set(apr_socket_t *sock, void *data, + const char *key, + apr_status_t (*cleanup)(void*)); + +/** + * Send data over a network. + * @param sock The socket to send the data over. + * @param buf The buffer which contains the data to be sent. + * @param len On entry, the number of bytes to send; on exit, the number + * of bytes sent. + * @remark + *
+ * This functions acts like a blocking write by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ *
+ * It is possible for both bytes to be sent and an error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len); + +/** + * Send multiple packets of data over a network. + * @param sock The socket to send the data over. + * @param vec The array of iovec structs containing the data to send + * @param nvec The number of iovec structs in the array + * @param len Receives the number of bytes actually written + * @remark + *
+ * This functions acts like a blocking write by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ * The number of bytes actually sent is stored in argument 3.
+ *
+ * It is possible for both bytes to be sent and an error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock, + const struct iovec *vec, + apr_int32_t nvec, apr_size_t *len); + +/** + * @param sock The socket to send from + * @param where The apr_sockaddr_t describing where to send the data + * @param flags The flags to use + * @param buf The data to send + * @param len The length of the data to send + */ +APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, + apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len); + +/** + * Read data from a socket. On success, the address of the peer from + * which the data was sent is copied into the @param from parameter, + * and the @param len parameter is updated to give the number of bytes + * written to @param buf. + * @param from Updated with the address from which the data was received + * @param sock The socket to use + * @param flags The flags to use + * @param buf The buffer to use + * @param len The length of the available buffer + */ + +APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, + apr_socket_t *sock, + apr_int32_t flags, char *buf, + apr_size_t *len); + +#if APR_HAS_SENDFILE || defined(DOXYGEN) + +/** + * Send a file from an open file descriptor to a socket, along with + * optional headers and trailers + * @param sock The socket to which we're writing + * @param file The open file from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * The offset parameter is passed by reference for no reason; its + * value will never be modified by the apr_socket_sendfile() function. + */ +APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock, + apr_file_t *file, + apr_hdtr_t *hdtr, + apr_off_t *offset, + apr_size_t *len, + apr_int32_t flags); + +#endif /* APR_HAS_SENDFILE */ + +/** + * Read data from a network. + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param len On entry, the number of bytes to receive; on exit, the number + * of bytes received. + * @remark + *
+ * This functions acts like a blocking read by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ * The number of bytes actually received is stored in argument 3.
+ *
+ * It is possible for both bytes to be received and an APR_EOF or
+ * other error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, + char *buf, apr_size_t *len); + +/** + * Setup socket options for the specified socket + * @param sock The socket to set up. + * @param opt The option we would like to configure. One of: + *
+ *            APR_SO_DEBUG      --  turn on debugging information 
+ *            APR_SO_KEEPALIVE  --  keep connections active
+ *            APR_SO_LINGER     --  lingers on close if data is present
+ *            APR_SO_NONBLOCK   --  Turns blocking on/off for socket
+ *                                  When this option is enabled, use
+ *                                  the APR_STATUS_IS_EAGAIN() macro to
+ *                                  see if a send or receive function
+ *                                  could not transfer data without
+ *                                  blocking.
+ *            APR_SO_REUSEADDR  --  The rules used in validating addresses
+ *                                  supplied to bind should allow reuse
+ *                                  of local addresses.
+ *            APR_SO_SNDBUF     --  Set the SendBufferSize
+ *            APR_SO_RCVBUF     --  Set the ReceiveBufferSize
+ * 
+ * @param on Value for the option. + */ +APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t on); + +/** + * Setup socket timeout for the specified socket + * @param sock The socket to set up. + * @param t Value for the timeout. + *
+ *   t > 0  -- read and write calls return APR_TIMEUP if specified time
+ *             elapsess with no data read or written
+ *   t == 0 -- read and write calls never block
+ *   t < 0  -- read and write calls block
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, + apr_interval_time_t t); + +/** + * Query socket options for the specified socket + * @param sock The socket to query + * @param opt The option we would like to query. One of: + *
+ *            APR_SO_DEBUG      --  turn on debugging information 
+ *            APR_SO_KEEPALIVE  --  keep connections active
+ *            APR_SO_LINGER     --  lingers on close if data is present
+ *            APR_SO_NONBLOCK   --  Turns blocking on/off for socket
+ *            APR_SO_REUSEADDR  --  The rules used in validating addresses
+ *                                  supplied to bind should allow reuse
+ *                                  of local addresses.
+ *            APR_SO_SNDBUF     --  Set the SendBufferSize
+ *            APR_SO_RCVBUF     --  Set the ReceiveBufferSize
+ *            APR_SO_DISCONNECTED -- Query the disconnected state of the socket.
+ *                                  (Currently only used on Windows)
+ * 
+ * @param on Socket option returned on the call. + */ +APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t *on); + +/** + * Query socket timeout for the specified socket + * @param sock The socket to query + * @param t Socket timeout returned from the query. + */ +APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, + apr_interval_time_t *t); + +/** + * Query the specified socket if at the OOB/Urgent data mark + * @param sock The socket to query + * @param atmark Is set to true if socket is at the OOB/urgent mark, + * otherwise is set to false. + */ +APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, + int *atmark); + +/** + * Return an address associated with a socket; either the address to + * which the socket is bound locally or the the address of the peer + * to which the socket is connected. + * @param sa The returned apr_sockaddr_t. + * @param which Whether to retrieve the local or remote address + * @param sock The socket to use + */ +APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, + apr_interface_e which, + apr_socket_t *sock); + +/** + * Return the IP address (in numeric address string format) in + * an APR socket address. APR will allocate storage for the IP address + * string from the pool of the apr_sockaddr_t. + * @param addr The IP address. + * @param sockaddr The socket address to reference. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, + apr_sockaddr_t *sockaddr); + +/** + * Write the IP address (in numeric address string format) of the APR + * socket address @a sockaddr into the buffer @a buf (of size @a buflen). + * @param sockaddr The socket address to reference. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen, + apr_sockaddr_t *sockaddr); + +/** + * See if the IP addresses in two APR socket addresses are + * equivalent. Appropriate logic is present for comparing + * IPv4-mapped IPv6 addresses with IPv4 addresses. + * + * @param addr1 One of the APR socket addresses. + * @param addr2 The other APR socket address. + * @remark The return value will be non-zero if the addresses + * are equivalent. + */ +APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, + const apr_sockaddr_t *addr2); + +/** +* Return the type of the socket. +* @param sock The socket to query. +* @param type The returned type (e.g., SOCK_STREAM). +*/ +APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock, + int *type); + +/** + * Given an apr_sockaddr_t and a service name, set the port for the service + * @param sockaddr The apr_sockaddr_t that will have its port set + * @param servname The name of the service you wish to use + */ +APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, + const char *servname); +/** + * Build an ip-subnet representation from an IP address and optional netmask or + * number-of-bits. + * @param ipsub The new ip-subnet representation + * @param ipstr The input IP address string + * @param mask_or_numbits The input netmask or number-of-bits string, or NULL + * @param p The pool to allocate from + */ +APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, + const char *ipstr, + const char *mask_or_numbits, + apr_pool_t *p); + +/** + * Test the IP address in an apr_sockaddr_t against a pre-built ip-subnet + * representation. + * @param ipsub The ip-subnet representation + * @param sa The socket address to test + * @return non-zero if the socket address is within the subnet, 0 otherwise + */ +APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa); + +#if APR_HAS_SO_ACCEPTFILTER || defined(DOXYGEN) +/** + * Set an OS level accept filter. + * @param sock The socket to put the accept filter on. + * @param name The accept filter + * @param args Any extra args to the accept filter. Passing NULL here removes + * the accept filter. + */ +apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *name, + char *args); +#endif + +/** + * Return the protocol of the socket. + * @param sock The socket to query. + * @param protocol The returned protocol (e.g., APR_PROTO_TCP). + */ +APR_DECLARE(apr_status_t) apr_socket_protocol_get(apr_socket_t *sock, + int *protocol); + +/** + * Get the pool used by the socket. + */ +APR_POOL_DECLARE_ACCESSOR(socket); + +/** + * Set a socket to be inherited by child processes. + */ +APR_DECLARE_INHERIT_SET(socket); + +/** + * Unset a socket from being inherited by child processes. + */ +APR_DECLARE_INHERIT_UNSET(socket); + +/** + * @defgroup apr_mcast IP Multicast + * @{ + */ + +/** + * Join a Multicast Group + * @param sock The socket to join a multicast group + * @param join The address of the multicast group to join + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) + */ +APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock, + apr_sockaddr_t *join, + apr_sockaddr_t *iface, + apr_sockaddr_t *source); + +/** + * Leave a Multicast Group. All arguments must be the same as + * apr_mcast_join. + * @param sock The socket to leave a multicast group + * @param addr The address of the multicast group to leave + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) + */ +APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock, + apr_sockaddr_t *addr, + apr_sockaddr_t *iface, + apr_sockaddr_t *source); + +/** + * Set the Multicast Time to Live (ttl) for a multicast transmission. + * @param sock The socket to set the multicast ttl + * @param ttl Time to live to Assign. 0-255, default=1 + * @remark If the TTL is 0, packets will only be seen by sockets on + * the local machine, and only when multicast loopback is enabled. + */ +APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock, + apr_byte_t ttl); + +/** + * Toggle IP Multicast Loopback + * @param sock The socket to set multicast loopback + * @param opt 0=disable, 1=enable + */ +APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock, + apr_byte_t opt); + + +/** + * Set the Interface to be used for outgoing Multicast Transmissions. + * @param sock The socket to set the multicast interface on + * @param iface Address of the interface to use for Multicast + */ +APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock, + apr_sockaddr_t *iface); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_NETWORK_IO_H */ + diff --git a/include/apr-linux/apr_optional.h b/include/apr-linux/apr_optional.h new file mode 100644 index 0000000..3301d66 --- /dev/null +++ b/include/apr-linux/apr_optional.h @@ -0,0 +1,92 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_OPTIONAL_H +#define APR_OPTIONAL_H + +#include "apu.h" +/** + * @file apr_optional.h + * @brief APR-UTIL registration of functions exported by modules + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Opt Optional Functions + * @ingroup APR_Util + * + * Typesafe registration and retrieval of functions that may not be present + * (i.e. functions exported by optional modules) + * @{ + */ + +/** + * The type of an optional function. + * @param name The name of the function + */ +#define APR_OPTIONAL_FN_TYPE(name) apr_OFN_##name##_t + +/** + * Declare an optional function. + * @param ret The return type of the function + * @param name The name of the function + * @param args The function arguments (including brackets) + */ +#define APR_DECLARE_OPTIONAL_FN(ret,name,args) \ +typedef ret (APR_OPTIONAL_FN_TYPE(name)) args + +/** + * XXX: This doesn't belong here, then! + * Private function! DO NOT USE! + * @internal + */ + +typedef void (apr_opt_fn_t)(void); +/** @internal */ +APU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName, + apr_opt_fn_t *pfn); + +/** + * Register an optional function. This can be later retrieved, type-safely, by + * name. Like all global functions, the name must be unique. Note that, + * confusingly but correctly, the function itself can be static! + * @param name The name of the function + */ +#define APR_REGISTER_OPTIONAL_FN(name) do { \ + APR_OPTIONAL_FN_TYPE(name) *apu__opt = name; \ + apr_dynamic_fn_register(#name,(apr_opt_fn_t *)apu__opt); \ +} while (0) + +/** @internal + * Private function! DO NOT USE! + */ +APU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName); + +/** + * Retrieve an optional function. Returns NULL if the function is not present. + * @param name The name of the function + */ +#define APR_RETRIEVE_OPTIONAL_FN(name) \ + (APR_OPTIONAL_FN_TYPE(name) *)apr_dynamic_fn_retrieve(#name) + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_OPTIONAL_H */ diff --git a/include/apr-linux/apr_optional_hooks.h b/include/apr-linux/apr_optional_hooks.h new file mode 100644 index 0000000..54bf65e --- /dev/null +++ b/include/apr-linux/apr_optional_hooks.h @@ -0,0 +1,117 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +/** + * @file apr_optional_hooks.h + * @brief Apache optional hook functions + */ + + +#ifndef APR_OPTIONAL_HOOK_H +#define APR_OPTIONAL_HOOK_H + +#include "apr_tables.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup APR_Util_OPT_HOOK Optional Hook Functions + * @ingroup APR_Util_Hook + * @{ + */ +/** + * Function to implemnt the APR_OPTIONAL_HOOK Macro + * @internal + * @see APR_OPTIONAL_HOOK + * + * @param name The name of the hook + * @param pfn A pointer to a function that will be called + * @param aszPre a NULL-terminated array of strings that name modules whose hooks should precede this one + * @param aszSucc a NULL-terminated array of strings that name modules whose hooks should succeed this one + * @param nOrder an integer determining order before honouring aszPre and aszSucc (for example HOOK_MIDDLE) + */ + + +APU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void), + const char * const *aszPre, + const char * const *aszSucc, + int nOrder); + +/** + * Hook to an optional hook. + * + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param pfn A pointer to a function that will be called + * @param aszPre a NULL-terminated array of strings that name modules whose hooks should precede this one + * @param aszSucc a NULL-terminated array of strings that name modules whose hooks should succeed this one + * @param nOrder an integer determining order before honouring aszPre and aszSucc (for example HOOK_MIDDLE) + */ + +#define APR_OPTIONAL_HOOK(ns,name,pfn,aszPre,aszSucc,nOrder) do { \ + ns##_HOOK_##name##_t *apu__hook = pfn; \ + apr_optional_hook_add(#name,(void (*)(void))apu__hook,aszPre, aszSucc, nOrder); \ +} while (0) + +/** + * @internal + * @param szName - the name of the function + * @return the hook structure for a given hook + */ +APU_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName); + +/** + * Implement an optional hook that runs until one of the functions + * returns something other than OK or DECLINE. + * + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param ret The type of the return value of the hook + * @param ret The type of the return value of the hook + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param ok Success value + * @param decline Decline value + */ +#define APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ + apr_array_header_t *pHookArray=apr_optional_hook_get(#name); \ +\ + if(!pHookArray) \ + return ok; \ +\ + pHook=(ns##_LINK_##name##_t *)pHookArray->elts; \ + for(n=0 ; n < pHookArray->nelts ; ++n) \ + { \ + rv=(pHook[n].pFunc)args_use; \ +\ + if(rv != ok && rv != decline) \ + return rv; \ + } \ + return ok; \ + } + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_OPTIONAL_HOOK_H */ diff --git a/include/apr-linux/apr_poll.h b/include/apr-linux/apr_poll.h new file mode 100644 index 0000000..92a540a --- /dev/null +++ b/include/apr-linux/apr_poll.h @@ -0,0 +1,255 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_POLL_H +#define APR_POLL_H +/** + * @file apr_poll.h + * @brief APR Poll interface + */ +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_inherit.h" +#include "apr_file_io.h" +#include "apr_network_io.h" + +#if APR_HAVE_NETINET_IN_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_poll Poll Routines + * @ingroup APR + * @{ + */ + +/** + * Poll options + */ +#define APR_POLLIN 0x001 /**< Can read without blocking */ +#define APR_POLLPRI 0x002 /**< Priority data available */ +#define APR_POLLOUT 0x004 /**< Can write without blocking */ +#define APR_POLLERR 0x010 /**< Pending error */ +#define APR_POLLHUP 0x020 /**< Hangup occurred */ +#define APR_POLLNVAL 0x040 /**< Descriptior invalid */ + +/** + * Pollset Flags + */ +#define APR_POLLSET_THREADSAFE 0x001 /**< Adding or Removing a Descriptor is thread safe */ +#define APR_POLLSET_NOCOPY 0x002 /**< Descriptors passed to apr_pollset_create() are not copied */ + +/** Used in apr_pollfd_t to determine what the apr_descriptor is */ +typedef enum { + APR_NO_DESC, /**< nothing here */ + APR_POLL_SOCKET, /**< descriptor refers to a socket */ + APR_POLL_FILE, /**< descriptor refers to a file */ + APR_POLL_LASTDESC /**< @deprecated descriptor is the last one in the list */ +} apr_datatype_e ; + +/** Union of either an APR file or socket. */ +typedef union { + apr_file_t *f; /**< file */ + apr_socket_t *s; /**< socket */ +} apr_descriptor; + +/** @see apr_pollfd_t */ +typedef struct apr_pollfd_t apr_pollfd_t; + +/** Poll descriptor set. */ +struct apr_pollfd_t { + apr_pool_t *p; /**< associated pool */ + apr_datatype_e desc_type; /**< descriptor type */ + apr_int16_t reqevents; /**< requested events */ + apr_int16_t rtnevents; /**< returned events */ + apr_descriptor desc; /**< @see apr_descriptor */ + void *client_data; /**< allows app to associate context */ +}; + + +/* General-purpose poll API for arbitrarily large numbers of + * file descriptors + */ + +/** Opaque structure used for pollset API */ +typedef struct apr_pollset_t apr_pollset_t; + +/** + * Setup a pollset object + * @param pollset The pointer in which to return the newly created object + * @param size The maximum number of descriptors that this pollset can hold + * @param p The pool from which to allocate the pollset + * @param flags Optional flags to modify the operation of the pollset. + * + * @remark If flags equals APR_POLLSET_THREADSAFE, then a pollset is + * created on which it is safe to make concurrent calls to + * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() from + * separate threads. This feature is only supported on some + * platforms; the apr_pollset_create() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + */ +APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags); + +/** + * Destroy a pollset object + * @param pollset The pollset to destroy + */ +APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset); + +/** + * Add a socket or file descriptor to a pollset + * @param pollset The pollset to which to add the descriptor + * @param descriptor The descriptor to add + * @remark If you set client_data in the descriptor, that value + * will be returned in the client_data field whenever this + * descriptor is signalled in apr_pollset_poll(). + * @remark If the pollset has been created with APR_POLLSET_THREADSAFE + * and thread T1 is blocked in a call to apr_pollset_poll() for + * this same pollset that is being modified via apr_pollset_add() + * in thread T2, the currently executing apr_pollset_poll() call in + * T1 will either: (1) automatically include the newly added descriptor + * in the set of descriptors it is watching or (2) return immediately + * with APR_EINTR. Option (1) is recommended, but option (2) is + * allowed for implementations where option (1) is impossible + * or impractical. + */ +APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor); + +/** + * Remove a descriptor from a pollset + * @param pollset The pollset from which to remove the descriptor + * @param descriptor The descriptor to remove + * @remark If the pollset has been created with APR_POLLSET_THREADSAFE + * and thread T1 is blocked in a call to apr_pollset_poll() for + * this same pollset that is being modified via apr_pollset_remove() + * in thread T2, the currently executing apr_pollset_poll() call in + * T1 will either: (1) automatically exclude the newly added descriptor + * in the set of descriptors it is watching or (2) return immediately + * with APR_EINTR. Option (1) is recommended, but option (2) is + * allowed for implementations where option (1) is impossible + * or impractical. + */ +APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor); + +/** + * Block for activity on the descriptor(s) in a pollset + * @param pollset The pollset to use + * @param timeout Timeout in microseconds + * @param num Number of signalled descriptors (output parameter) + * @param descriptors Array of signalled descriptors (output parameter) + */ +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors); + + +/** + * Poll the descriptors in the poll structure + * @param aprset The poll structure we will be using. + * @param numsock The number of descriptors we are polling + * @param nsds The number of descriptors signalled (output parameter) + * @param timeout The amount of time in microseconds to wait. This is + * a maximum, not a minimum. If a descriptor is signalled, we + * will wake up before this time. A negative number means + * wait until a descriptor is signalled. + * @remark The number of descriptors signalled is returned in the third argument. + * This is a blocking call, and it will not return until either a + * descriptor has been signalled, or the timeout has expired. + * @remark The rtnevents field in the apr_pollfd_t array will only be filled- + * in if the return value is APR_SUCCESS. + */ +APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t numsock, + apr_int32_t *nsds, + apr_interval_time_t timeout); + +/** Opaque structure used for pollset API */ +typedef struct apr_pollcb_t apr_pollcb_t; + +/** + * Setup a pollcb object + * @param pollcb The pointer in which to return the newly created object + * @param size The maximum number of descriptors that a single _poll can return. + * @param p The pool from which to allocate the pollcb + * @param flags Optional flags to modify the operation of the pollcb. + * + * @remark Pollcb is only supported on some platforms; the apr_pollcb_create() + * call will fail with APR_ENOTIMPL on platforms where it is not supported. + */ +APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb, + apr_uint32_t size, + apr_pool_t *pool, + apr_uint32_t flags); + +/** + * Add a socket or file descriptor to a pollcb + * @param pollcb The pollcb to which to add the descriptor + * @param descriptor The descriptor to add + * @remark If you set client_data in the descriptor, that value + * will be returned in the client_data field whenever this + * descriptor is signalled in apr_pollcb_poll(). + * @remark Unlike the apr_pollset API, the descriptor is not copied, and users + * must retain the memory used by descriptor, as the same pointer will be + * returned to them from apr_pollcb_poll. + */ +APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor); +/** + * Remove a descriptor from a pollcb + * @param pollcb The pollcb from which to remove the descriptor + * @param descriptor The descriptor to remove + */ +APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor); + +/** Function prototype for pollcb handlers + * @param baton Opaque baton passed into apr_pollcb_poll + * @param descriptor Contains the notification for an active descriptor, + * the rtnevents member contains what events were triggered + * for this descriptor. + */ +typedef apr_status_t (*apr_pollcb_cb_t)(void *baton, apr_pollfd_t *descriptor); + +/** + * Block for activity on the descriptor(s) in a pollcb + * @param pollcb The pollcb to use + * @param timeout Timeout in microseconds + * @param func Callback function to call for each active socket + * @param baton Opaque baton passed to the callback function. + */ +APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_POLL_H */ + diff --git a/include/apr-linux/apr_pools.h b/include/apr-linux/apr_pools.h new file mode 100644 index 0000000..eb7c6e5 --- /dev/null +++ b/include/apr-linux/apr_pools.h @@ -0,0 +1,741 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_POOLS_H +#define APR_POOLS_H + +/** + * @file apr_pools.h + * @brief APR memory allocation + * + * Resource allocation routines... + * + * designed so that we don't have to keep track of EVERYTHING so that + * it can be explicitly freed later (a fundamentally unsound strategy --- + * particularly in the presence of die()). + * + * Instead, we maintain pools, and allocate items (both memory and I/O + * handlers) from the pools --- currently there are two, one for per + * transaction info, and one for config info. When a transaction is over, + * we can delete everything in the per-transaction apr_pool_t without fear, + * and without thinking too hard about it either. + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_general.h" /* for APR_STRINGIFY */ +#define APR_WANT_MEMFUNC /**< for no good reason? */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_pools Memory Pool Functions + * @ingroup APR + * @{ + */ + +/** The fundamental pool type */ +typedef struct apr_pool_t apr_pool_t; + + +/** + * Declaration helper macro to construct apr_foo_pool_get()s. + * + * This standardized macro is used by opaque (APR) data types to return + * the apr_pool_t that is associated with the data type. + * + * APR_POOL_DECLARE_ACCESSOR() is used in a header file to declare the + * accessor function. A typical usage and result would be: + *
+ *    APR_POOL_DECLARE_ACCESSOR(file);
+ * becomes:
+ *    APR_DECLARE(apr_pool_t *) apr_file_pool_get(apr_file_t *ob);
+ * 
+ * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurance of apr_foo_pool_get. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_POOL_DECLARE_ACCESSOR(type) \ + APR_DECLARE(apr_pool_t *) apr_##type##_pool_get \ + (const apr_##type##_t *the##type) + +/** + * Implementation helper macro to provide apr_foo_pool_get()s. + * + * In the implementation, the APR_POOL_IMPLEMENT_ACCESSOR() is used to + * actually define the function. It assumes the field is named "pool". + */ +#define APR_POOL_IMPLEMENT_ACCESSOR(type) \ + APR_DECLARE(apr_pool_t *) apr_##type##_pool_get \ + (const apr_##type##_t *the##type) \ + { return the##type->pool; } + + +/** + * Pool debug levels + * + *
+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ * ---------------------------------
+ * |   |   |   |   |   |   |   | x |  General debug code enabled (useful in
+ *                                    combination with --with-efence).
+ *
+ * |   |   |   |   |   |   | x |   |  Verbose output on stderr (report
+ *                                    CREATE, CLEAR, DESTROY).
+ *
+ * |   |   |   | x |   |   |   |   |  Verbose output on stderr (report
+ *                                    PALLOC, PCALLOC).
+ *
+ * |   |   |   |   |   | x |   |   |  Lifetime checking. On each use of a
+ *                                    pool, check its lifetime.  If the pool
+ *                                    is out of scope, abort().
+ *                                    In combination with the verbose flag
+ *                                    above, it will output LIFE in such an
+ *                                    event prior to aborting.
+ *
+ * |   |   |   |   | x |   |   |   |  Pool owner checking.  On each use of a
+ *                                    pool, check if the current thread is the
+ *                                    pools owner.  If not, abort().  In
+ *                                    combination with the verbose flag above,
+ *                                    it will output OWNER in such an event
+ *                                    prior to aborting.  Use the debug
+ *                                    function apr_pool_owner_set() to switch
+ *                                    a pools ownership.
+ *
+ * When no debug level was specified, assume general debug mode.
+ * If level 0 was specified, debugging is switched off
+ * 
+ */ +#if defined(APR_POOL_DEBUG) +/* If APR_POOL_DEBUG is blank, we get 1; if it is a number, we get -1. */ +#if (APR_POOL_DEBUG - APR_POOL_DEBUG -1 == 1) +#undef APR_POOL_DEBUG +#define APR_POOL_DEBUG 1 +#endif +#else +#define APR_POOL_DEBUG 0 +#endif + +/** the place in the code where the particular function was called */ +#define APR_POOL__FILE_LINE__ __FILE__ ":" APR_STRINGIFY(__LINE__) + + + +/** A function that is called when allocation fails. */ +typedef int (*apr_abortfunc_t)(int retcode); + +/* + * APR memory structure manipulators (pools, tables, and arrays). + */ + +/* + * Initialization + */ + +/** + * Setup all of the internal structures required to use pools + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_initialize. + * @internal + */ +APR_DECLARE(apr_status_t) apr_pool_initialize(void); + +/** + * Tear down all of the internal structures required to use pools + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_terminate. + * @internal + */ +APR_DECLARE(void) apr_pool_terminate(void); + + +/* + * Pool creation/destruction + */ + +#include "apr_allocator.h" + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @param abort_fn A function to use if the pool cannot allocate more memory. + * @param allocator The allocator to use with the new pool. If NULL the + * allocator of the parent pool will be used. + */ +APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param abort_fn A function to use if the pool cannot allocate more memory. + * @param allocator The allocator to use with the new pool. If NULL the + * new allocator will be crated with newpool as owner. + */ +APR_DECLARE(apr_status_t) apr_pool_create_core_ex(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +/** + * Debug version of apr_pool_create_ex. + * @param newpool @see apr_pool_create. + * @param parent @see apr_pool_create. + * @param abort_fn @see apr_pool_create. + * @param allocator @see apr_pool_create. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_create_ex + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_create_ex in a wrapper, trust the macro + * and don't call apr_pool_create_ex_debug directly. + */ +APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_create_ex(newpool, parent, abort_fn, allocator) \ + apr_pool_create_ex_debug(newpool, parent, abort_fn, allocator, \ + APR_POOL__FILE_LINE__) +#endif + +/** + * Debug version of apr_pool_create_core_ex. + * @param newpool @see apr_pool_create. + * @param abort_fn @see apr_pool_create. + * @param allocator @see apr_pool_create. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_create_core_ex + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_create_core_ex in a wrapper, trust the macro + * and don't call apr_pool_create_core_ex_debug directly. + */ +APR_DECLARE(apr_status_t) apr_pool_create_core_ex_debug(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_create_core_ex(newpool, abort_fn, allocator) \ + apr_pool_create_core_ex_debug(newpool, abort_fn, allocator, \ + APR_POOL__FILE_LINE__) +#endif + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + */ +#if defined(DOXYGEN) +APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, + apr_pool_t *parent); +#else +#if APR_POOL_DEBUG +#define apr_pool_create(newpool, parent) \ + apr_pool_create_ex_debug(newpool, parent, NULL, NULL, \ + APR_POOL__FILE_LINE__) +#else +#define apr_pool_create(newpool, parent) \ + apr_pool_create_ex(newpool, parent, NULL, NULL) +#endif +#endif + +/** + * Create a new pool. + * @param newpool The pool we have just created. + */ +#if defined(DOXYGEN) +APR_DECLARE(apr_status_t) apr_pool_create_core(apr_pool_t **newpool); +#else +#if APR_POOL_DEBUG +#define apr_pool_create_core(newpool) \ + apr_pool_create_core_ex_debug(newpool, NULL, NULL, \ + APR_POOL__FILE_LINE__) +#else +#define apr_pool_create_core(newpool) \ + apr_pool_create_core_ex(newpool, NULL, NULL) +#endif +#endif + +/** + * Find the pools allocator + * @param pool The pool to get the allocator from. + */ +APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool); + +/** + * Clear all memory in the pool and run all the cleanups. This also destroys all + * subpools. + * @param p The pool to clear + * @remark This does not actually free the memory, it just allows the pool + * to re-use this memory for the next allocation. + * @see apr_pool_destroy() + */ +APR_DECLARE(void) apr_pool_clear(apr_pool_t *p); + +/** + * Debug version of apr_pool_clear. + * @param p See: apr_pool_clear. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_clear + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_clear in a wrapper, trust the macro + * and don't call apr_pool_destroy_clear directly. + */ +APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *p, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_clear(p) \ + apr_pool_clear_debug(p, APR_POOL__FILE_LINE__) +#endif + +/** + * Destroy the pool. This takes similar action as apr_pool_clear() and then + * frees all the memory. + * @param p The pool to destroy + * @remark This will actually free the memory + */ +APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p); + +/** + * Debug version of apr_pool_destroy. + * @param p See: apr_pool_destroy. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_destroy + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_destroy in a wrapper, trust the macro + * and don't call apr_pool_destroy_debug directly. + */ +APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *p, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_destroy(p) \ + apr_pool_destroy_debug(p, APR_POOL__FILE_LINE__) +#endif + + +/* + * Memory allocation + */ + +/** + * Allocate a block of memory from a pool + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The allocated memory + */ +APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size); + +/** + * Debug version of apr_palloc + * @param p See: apr_palloc + * @param size See: apr_palloc + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @return See: apr_palloc + */ +APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *p, apr_size_t size, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_palloc(p, size) \ + apr_palloc_debug(p, size, APR_POOL__FILE_LINE__) +#endif + +/** + * Allocate a block of memory from a pool and set all of the memory to 0 + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The allocated memory + */ +#if defined(DOXYGEN) +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *p, apr_size_t size); +#elif !APR_POOL_DEBUG +#define apr_pcalloc(p, size) memset(apr_palloc(p, size), 0, size) +#endif + +/** + * Debug version of apr_pcalloc + * @param p See: apr_pcalloc + * @param size See: apr_pcalloc + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @return See: apr_pcalloc + */ +APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *p, apr_size_t size, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pcalloc(p, size) \ + apr_pcalloc_debug(p, size, APR_POOL__FILE_LINE__) +#endif + + +/* + * Pool Properties + */ + +/** + * Set the function to be called when an allocation failure occurs. + * @remark If the program wants APR to exit on a memory allocation error, + * then this function can be called to set the callback to use (for + * performing cleanup and then exiting). If this function is not called, + * then APR will return an error and expect the calling program to + * deal with the error accordingly. + */ +APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abortfunc, + apr_pool_t *pool); + +/** + * Get the abort function associated with the specified pool. + * @param pool The pool for retrieving the abort function. + * @return The abort function for the given pool. + */ +APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool); + +/** + * Get the parent pool of the specified pool. + * @param pool The pool for retrieving the parent pool. + * @return The parent of the given pool. + */ +APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool); + +/** + * Determine if pool a is an ancestor of pool b. + * @param a The pool to search + * @param b The pool to search for + * @return True if a is an ancestor of b, NULL is considered an ancestor + * of all pools. + * @remark if compiled with APR_POOL_DEBUG, this function will also + * return true if A is a pool which has been guaranteed by the caller + * (using apr_pool_join) to have a lifetime at least as long as some + * ancestor of pool B. + */ +APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b); + +/** + * Tag a pool (give it a name) + * @param pool The pool to tag + * @param tag The tag + */ +APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag); + + +/* + * User data management + */ + +/** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param cleanup The cleanup program to use to cleanup the data (NULL if none) + * @param pool The current pool + * @warning The data to be attached to the pool should have a life span + * at least as long as the pool it is being attached to. + * + * Users of APR must take EXTREME care when choosing a key to + * use for their data. It is possible to accidentally overwrite + * data by choosing a key that another part of the program is using. + * Therefore it is advised that steps are taken to ensure that unique + * keys are used for all of the userdata objects in a particular pool + * (the same key in two different pools or a pool and one of its + * subpools is okay) at all times. Careful namespace prefixing of + * key names is a typical way to help ensure this uniqueness. + * + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_set( + const void *data, + const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool); + +/** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param cleanup The cleanup program to use to cleanup the data (NULL if none) + * @param pool The current pool + * @note same as apr_pool_userdata_set(), except that this version doesn't + * make a copy of the key (this function is useful, for example, when + * the key is a string literal) + * @warning This should NOT be used if the key could change addresses by + * any means between the apr_pool_userdata_setn() call and a + * subsequent apr_pool_userdata_get() on that key, such as if a + * static string is used as a userdata key in a DSO and the DSO could + * be unloaded and reloaded between the _setn() and the _get(). You + * MUST use apr_pool_userdata_set() in such cases. + * @warning More generally, the key and the data to be attached to the + * pool should have a life span at least as long as the pool itself. + * + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_setn( + const void *data, + const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool); + +/** + * Return the data associated with the current pool. + * @param data The user data associated with the pool. + * @param key The key for the data to retrieve + * @param pool The current pool. + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, + apr_pool_t *pool); + + +/** + * @defgroup PoolCleanup Pool Cleanup Functions + * + * Cleanups are performed in the reverse order they were registered. That is: + * Last In, First Out. A cleanup function can safely allocate memory from + * the pool that is being cleaned up. It can also safely register additional + * cleanups which will be run LIFO, directly after the current cleanup + * terminates. Cleanups have to take caution in calling functions that + * create subpools. Subpools, created during cleanup will NOT automatically + * be cleaned up. In other words, cleanups are to clean up after themselves. + * + * @{ + */ + +/** + * Register a function to be called when a pool is cleared or destroyed + * @param p The pool register the cleanup with + * @param data The data to pass to the cleanup function. + * @param plain_cleanup The function to call when the pool is cleared + * or destroyed + * @param child_cleanup The function to call when a child process is about + * to exec - this function is called in the child, obviously! + */ +APR_DECLARE(void) apr_pool_cleanup_register( + apr_pool_t *p, + const void *data, + apr_status_t (*plain_cleanup)(void *), + apr_status_t (*child_cleanup)(void *)); + +/** + * Register a function to be called when a pool is cleared or destroyed. + * + * Unlike apr_pool_cleanup_register which register a cleanup + * that is called AFTER all subpools are destroyed this function register + * a function that will be called before any of the subpool is destoryed. + * + * @param p The pool register the cleanup with + * @param data The data to pass to the cleanup function. + * @param plain_cleanup The function to call when the pool is cleared + * or destroyed + */ +APR_DECLARE(void) apr_pool_pre_cleanup_register( + apr_pool_t *p, + const void *data, + apr_status_t (*plain_cleanup)(void *)); + +/** + * Remove a previously registered cleanup function. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a cleanup will be removed. + * + * @param p The pool to remove the cleanup from + * @param data The data of the registered cleanup + * @param cleanup The function to remove from cleanup + * @remarks For some strange reason only the plain_cleanup is handled by this + * function + */ +APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data, + apr_status_t (*cleanup)(void *)); + +/** + * Replace the child cleanup function of a previously registered cleanup. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a plain_cleanup will have the registered child cleanup + * function replaced with @a child_cleanup. + * + * @param p The pool of the registered cleanup + * @param data The data of the registered cleanup + * @param plain_cleanup The plain cleanup function of the registered cleanup + * @param child_cleanup The function to register as the child cleanup + */ +APR_DECLARE(void) apr_pool_child_cleanup_set( + apr_pool_t *p, + const void *data, + apr_status_t (*plain_cleanup)(void *), + apr_status_t (*child_cleanup)(void *)); + +/** + * Run the specified cleanup function immediately and unregister it. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a cleanup will be removed and @a cleanup will be called + * with @a data as the argument. + * + * @param p The pool to remove the cleanup from + * @param data The data to remove from cleanup + * @param cleanup The function to remove from cleanup + */ +APR_DECLARE(apr_status_t) apr_pool_cleanup_run( + apr_pool_t *p, + void *data, + apr_status_t (*cleanup)(void *)); + +/** + * An empty cleanup function. + * + * Passed to apr_pool_cleanup_register() when no cleanup is required. + * + * @param data The data to cleanup, will not be used by this function. + */ +APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data); + +/** + * Run all registered child cleanups, in preparation for an exec() + * call in a forked child -- close files, etc., but *don't* flush I/O + * buffers, *don't* wait for subprocesses, and *don't* free any + * memory. + */ +APR_DECLARE(void) apr_pool_cleanup_for_exec(void); + +/** @} */ + +/** + * @defgroup PoolDebug Pool Debugging functions. + * + * pools have nested lifetimes -- sub_pools are destroyed when the + * parent pool is cleared. We allow certain liberties with operations + * on things such as tables (and on other structures in a more general + * sense) where we allow the caller to insert values into a table which + * were not allocated from the table's pool. The table's data will + * remain valid as long as all the pools from which its values are + * allocated remain valid. + * + * For example, if B is a sub pool of A, and you build a table T in + * pool B, then it's safe to insert data allocated in A or B into T + * (because B lives at most as long as A does, and T is destroyed when + * B is cleared/destroyed). On the other hand, if S is a table in + * pool A, it is safe to insert data allocated in A into S, but it + * is *not safe* to insert data allocated from B into S... because + * B can be cleared/destroyed before A is (which would leave dangling + * pointers in T's data structures). + * + * In general we say that it is safe to insert data into a table T + * if the data is allocated in any ancestor of T's pool. This is the + * basis on which the APR_POOL_DEBUG code works -- it tests these ancestor + * relationships for all data inserted into tables. APR_POOL_DEBUG also + * provides tools (apr_pool_find, and apr_pool_is_ancestor) for other + * folks to implement similar restrictions for their own data + * structures. + * + * However, sometimes this ancestor requirement is inconvenient -- + * sometimes it's necessary to create a sub pool where the sub pool is + * guaranteed to have the same lifetime as the parent pool. This is a + * guarantee implemented by the *caller*, not by the pool code. That + * is, the caller guarantees they won't destroy the sub pool + * individually prior to destroying the parent pool. + * + * In this case the caller must call apr_pool_join() to indicate this + * guarantee to the APR_POOL_DEBUG code. + * + * These functions are only implemented when #APR_POOL_DEBUG is set. + * + * @{ + */ +#if APR_POOL_DEBUG || defined(DOXYGEN) +/** + * Guarantee that a subpool has the same lifetime as the parent. + * @param p The parent pool + * @param sub The subpool + */ +APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub); + +/** + * Find a pool from something allocated in it. + * @param mem The thing allocated in the pool + * @return The pool it is allocated in + */ +APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem); + +/** + * Report the number of bytes currently in the pool + * @param p The pool to inspect + * @param recurse Recurse/include the subpools' sizes + * @return The number of bytes + */ +APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *p, int recurse); + +/** + * Lock a pool + * @param pool The pool to lock + * @param flag The flag + */ +APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag); + +/* @} */ + +#else /* APR_POOL_DEBUG or DOXYGEN */ + +#ifdef apr_pool_join +#undef apr_pool_join +#endif +#define apr_pool_join(a,b) + +#ifdef apr_pool_lock +#undef apr_pool_lock +#endif +#define apr_pool_lock(pool, lock) + +#endif /* APR_POOL_DEBUG or DOXYGEN */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_POOLS_H */ diff --git a/include/apr-linux/apr_portable.h b/include/apr-linux/apr_portable.h new file mode 100644 index 0000000..b1b21e3 --- /dev/null +++ b/include/apr-linux/apr_portable.h @@ -0,0 +1,506 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 header file is where you should put ANY platform specific information. + * This should be the only header file that programs need to include that + * actually has platform dependant code which refers to the . + */ +#ifndef APR_PORTABLE_H +#define APR_PORTABLE_H +/** + * @file apr_portable.h + * @brief APR Portability Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_network_io.h" +#include "apr_errno.h" +#include "apr_global_mutex.h" +#include "apr_proc_mutex.h" +#include "apr_time.h" +#include "apr_dso.h" +#include "apr_shm.h" + +#if APR_HAVE_DIRENT_H +#include +#endif +#if APR_HAVE_FCNTL_H +#include +#endif +#if APR_HAVE_PTHREAD_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_portabile Portability Routines + * @ingroup APR + * @{ + */ + +#ifdef WIN32 +/* The primitives for Windows types */ +typedef HANDLE apr_os_file_t; +typedef HANDLE apr_os_dir_t; +typedef SOCKET apr_os_sock_t; +typedef HANDLE apr_os_proc_mutex_t; +typedef HANDLE apr_os_thread_t; +typedef HANDLE apr_os_proc_t; +typedef DWORD apr_os_threadkey_t; +typedef FILETIME apr_os_imp_time_t; +typedef SYSTEMTIME apr_os_exp_time_t; +typedef HANDLE apr_os_dso_handle_t; +typedef HANDLE apr_os_shm_t; + +#elif defined(OS2) +typedef HFILE apr_os_file_t; +typedef HDIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef HMTX apr_os_proc_mutex_t; +typedef TID apr_os_thread_t; +typedef PID apr_os_proc_t; +typedef PULONG apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef HMODULE apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#elif defined(__BEOS__) +#include +#include + +struct apr_os_proc_mutex_t { + sem_id sem; + int32 ben; +}; + +typedef int apr_os_file_t; +typedef DIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef struct apr_os_proc_mutex_t apr_os_proc_mutex_t; +typedef thread_id apr_os_thread_t; +typedef thread_id apr_os_proc_t; +typedef int apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef image_id apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#elif defined(NETWARE) +typedef int apr_os_file_t; +typedef DIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef NXMutex_t apr_os_proc_mutex_t; +typedef NXThreadId_t apr_os_thread_t; +typedef long apr_os_proc_t; +typedef NXKey_t apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef void * apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#else +/* Any other OS should go above this one. This is the lowest common + * denominator typedefs for all UNIX-like systems. :) + */ + +/** Basic OS process mutex structure. */ +struct apr_os_proc_mutex_t { +#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + /** Value used for SYS V Semaphore, FCNTL and FLOCK serialization */ + int crossproc; +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + /** Value used for PTHREAD serialization */ + pthread_mutex_t *pthread_interproc; +#endif +#if APR_HAS_THREADS + /* If no threads, no need for thread locks */ +#if APR_USE_PTHREAD_SERIALIZE + /** This value is currently unused within APR and Apache */ + pthread_mutex_t *intraproc; +#endif +#endif +}; + +typedef int apr_os_file_t; /**< native file */ +typedef DIR apr_os_dir_t; /**< native dir */ +typedef int apr_os_sock_t; /**< native dir */ +typedef struct apr_os_proc_mutex_t apr_os_proc_mutex_t; /**< native proces + * mutex + */ +#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H +typedef pthread_t apr_os_thread_t; /**< native thread */ +typedef pthread_key_t apr_os_threadkey_t; /**< native thread address + * space */ +#endif +typedef pid_t apr_os_proc_t; /**< native pid */ +typedef struct timeval apr_os_imp_time_t; /**< native timeval */ +typedef struct tm apr_os_exp_time_t; /**< native tm */ +/** @var apr_os_dso_handle_t + * native dso types + */ +#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) +#include +typedef shl_t apr_os_dso_handle_t; +#elif defined(DARWIN) +#include +typedef NSModule apr_os_dso_handle_t; +#else +typedef void * apr_os_dso_handle_t; +#endif +typedef void* apr_os_shm_t; /**< native SHM */ + +#endif + +/** + * @typedef apr_os_sock_info_t + * @brief alias for local OS socket + */ +/** + * everything APR needs to know about an active socket to construct + * an APR socket from it; currently, this is platform-independent + */ +struct apr_os_sock_info_t { + apr_os_sock_t *os_sock; /**< always required */ + struct sockaddr *local; /**< NULL if not yet bound */ + struct sockaddr *remote; /**< NULL if not connected */ + int family; /**< always required (APR_INET, APR_INET6, etc.) */ + int type; /**< always required (SOCK_STREAM, SOCK_DGRAM, etc.) */ + int protocol; /**< 0 or actual protocol (APR_PROTO_SCTP, APR_PROTO_TCP, etc.) */ +}; + +typedef struct apr_os_sock_info_t apr_os_sock_info_t; + +#if APR_PROC_MUTEX_IS_GLOBAL || defined(DOXYGEN) +/** Opaque global mutex type */ +#define apr_os_global_mutex_t apr_os_proc_mutex_t +/** @return apr_os_global_mutex */ +#define apr_os_global_mutex_get apr_os_proc_mutex_get +#else + /** Thread and process mutex for those platforms where process mutexes + * are not held in threads. + */ + struct apr_os_global_mutex_t { + apr_pool_t *pool; + apr_proc_mutex_t *proc_mutex; +#if APR_HAS_THREADS + apr_thread_mutex_t *thread_mutex; +#endif /* APR_HAS_THREADS */ + }; + typedef struct apr_os_global_mutex_t apr_os_global_mutex_t; + +APR_DECLARE(apr_status_t) apr_os_global_mutex_get(apr_os_global_mutex_t *ospmutex, + apr_global_mutex_t *pmutex); +#endif + + +/** + * convert the file from apr type to os specific type. + * @param thefile The os specific file we are converting to + * @param file The apr file to convert. + * @remark On Unix, it is only possible to get a file descriptor from + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, + apr_file_t *file); + +/** + * convert the dir from apr type to os specific type. + * @param thedir The os specific dir we are converting to + * @param dir The apr dir to convert. + */ +APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir, + apr_dir_t *dir); + +/** + * Convert the socket from an apr type to an OS specific socket + * @param thesock The socket to convert. + * @param sock The os specifc equivelant of the apr socket.. + */ +APR_DECLARE(apr_status_t) apr_os_sock_get(apr_os_sock_t *thesock, + apr_socket_t *sock); + +/** + * Convert the proc mutex from os specific type to apr type + * @param ospmutex The os specific proc mutex we are converting to. + * @param pmutex The apr proc mutex to convert. + */ +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex); + +/** + * Get the exploded time in the platforms native format. + * @param ostime the native time format + * @param aprtime the time to convert + */ +APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, + apr_time_exp_t *aprtime); + +/** + * Get the imploded time in the platforms native format. + * @param ostime the native time format + * @param aprtime the time to convert + */ +APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, + apr_time_t *aprtime); + +/** + * convert the shm from apr type to os specific type. + * @param osshm The os specific shm representation + * @param shm The apr shm to convert. + */ +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm); + +#if APR_HAS_THREADS || defined(DOXYGEN) +/** + * @defgroup apr_os_thread Thread portability Routines + * @{ + */ +/** + * convert the thread to os specific type from apr type. + * @param thethd The apr thread to convert + * @param thd The os specific thread we are converting to + */ +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, + apr_thread_t *thd); + +/** + * convert the thread private memory key to os specific type from an apr type. + * @param thekey The apr handle we are converting from. + * @param key The os specific handle we are converting to. + */ +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, + apr_threadkey_t *key); + +/** + * convert the thread from os specific type to apr type. + * @param thd The apr thread we are converting to. + * @param thethd The os specific thread to convert + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, + apr_os_thread_t *thethd, + apr_pool_t *cont); + +/** + * convert the thread private memory key from os specific type to apr type. + * @param key The apr handle we are converting to. + * @param thekey The os specific handle to convert + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, + apr_pool_t *cont); +/** + * Get the thread ID + */ +APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void); + +/** + * Compare two thread id's + * @param tid1 1st Thread ID to compare + * @param tid2 2nd Thread ID to compare + */ +APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, + apr_os_thread_t tid2); + +/** @} */ +#endif /* APR_HAS_THREADS */ + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific file to convert + * @param flags The flags that were used to open this file. + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_int32_t flags, apr_pool_t *cont); + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific pipe to convert + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *cont); + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific pipe to convert + * @param register_cleanup A cleanup will be registered on the apr_file_t + * to issue apr_file_close(). + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *cont); + +/** + * convert the dir from os specific type to apr type. + * @param dir The apr dir we are converting to. + * @param thedir The os specific dir to convert + * @param cont The pool to use when creating to apr directory. + */ +APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir, + apr_os_dir_t *thedir, + apr_pool_t *cont); + +/** + * Convert a socket from the os specific type to the apr type + * @param sock The pool to use. + * @param thesock The socket to convert to. + * @param cont The socket we are converting to an apr type. + * @remark If it is a true socket, it is best to call apr_os_sock_make() + * and provide APR with more information about the socket. + */ +APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, + apr_os_sock_t *thesock, + apr_pool_t *cont); + +/** + * Create a socket from an existing descriptor and local and remote + * socket addresses. + * @param apr_sock The new socket that has been set up + * @param os_sock_info The os representation of the socket handle and + * other characteristics of the socket + * @param cont The pool to use + * @remark If you only know the descriptor/handle or if it isn't really + * a true socket, use apr_os_sock_put() instead. + */ +APR_DECLARE(apr_status_t) apr_os_sock_make(apr_socket_t **apr_sock, + apr_os_sock_info_t *os_sock_info, + apr_pool_t *cont); + +/** + * Convert the proc mutex from os specific type to apr type + * @param pmutex The apr proc mutex we are converting to. + * @param ospmutex The os specific proc mutex to convert. + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *cont); + +/** + * Put the imploded time in the APR format. + * @param aprtime the APR time format + * @param ostime the time to convert + * @param cont the pool to use if necessary + */ +APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, + apr_os_imp_time_t **ostime, + apr_pool_t *cont); + +/** + * Put the exploded time in the APR format. + * @param aprtime the APR time format + * @param ostime the time to convert + * @param cont the pool to use if necessary + */ +APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, + apr_os_exp_time_t **ostime, + apr_pool_t *cont); + +/** + * convert the shared memory from os specific type to apr type. + * @param shm The apr shm representation of osshm + * @param osshm The os specific shm identity + * @param cont The pool to use if it is needed. + * @remark On fork()ed architectures, this is typically nothing more than + * the memory block mapped. On non-fork architectures, this is typically + * some internal handle to pass the mapping from process to process. + */ +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **shm, + apr_os_shm_t *osshm, + apr_pool_t *cont); + + +#if APR_HAS_DSO || defined(DOXYGEN) +/** + * @defgroup apr_os_dso DSO (Dynamic Loading) Portabiliity Routines + * @{ + */ +/** + * convert the dso handle from os specific to apr + * @param dso The apr handle we are converting to + * @param thedso the os specific handle to convert + * @param pool the pool to use if it is needed + */ +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **dso, + apr_os_dso_handle_t thedso, + apr_pool_t *pool); + +/** + * convert the apr dso handle into an os specific one + * @param aprdso The apr dso handle to convert + * @param dso The os specific dso to return + */ +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *dso, + apr_dso_handle_t *aprdso); + +#if APR_HAS_OS_UUID +/** + * Private: apr-util's apr_uuid module when supported by the platform + */ +APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data); +#endif + +/** @} */ +#endif /* APR_HAS_DSO */ + + +/** + * Get the name of the system default characer set. + * @param pool the pool to allocate the name from, if needed + */ +APR_DECLARE(const char*) apr_os_default_encoding(apr_pool_t *pool); + + +/** + * Get the name of the current locale character set. + * @param pool the pool to allocate the name from, if needed + * @remark Defers to apr_os_default_encoding if the current locale's + * data can't be retreved on this system. + */ +APR_DECLARE(const char*) apr_os_locale_encoding(apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_PORTABLE_H */ diff --git a/include/apr-linux/apr_proc_mutex.h b/include/apr-linux/apr_proc_mutex.h new file mode 100644 index 0000000..ceb9c82 --- /dev/null +++ b/include/apr-linux/apr_proc_mutex.h @@ -0,0 +1,166 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_PROC_MUTEX_H +#define APR_PROC_MUTEX_H + +/** + * @file apr_proc_mutex.h + * @brief APR Process Locking Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_proc_mutex Process Locking Routines + * @ingroup APR + * @{ + */ + +/** + * Enumerated potential types for APR process locking methods + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +typedef enum { + APR_LOCK_FCNTL, /**< fcntl() */ + APR_LOCK_FLOCK, /**< flock() */ + APR_LOCK_SYSVSEM, /**< System V Semaphores */ + APR_LOCK_PROC_PTHREAD, /**< POSIX pthread process-based locking */ + APR_LOCK_POSIXSEM, /**< POSIX semaphore process-based locking */ + APR_LOCK_DEFAULT /**< Use the default process lock */ +} apr_lockmech_e; + +/** Opaque structure representing a process mutex. */ +typedef struct apr_proc_mutex_t apr_proc_mutex_t; + +/* Function definitions */ + +/** + * Create and initialize a mutex that can be used to synchronize processes. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + *
+ *            APR_LOCK_FCNTL
+ *            APR_LOCK_FLOCK
+ *            APR_LOCK_SYSVSEM
+ *            APR_LOCK_POSIXSEM
+ *            APR_LOCK_PROC_PTHREAD
+ *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @see apr_lockmech_e + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool); + +/** + * Re-open a mutex in a child process. + * @param mutex The newly re-opened mutex structure. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_proc_mutex_create(). + * @param pool The pool to operate on. + * @remark This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool); + +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + * @note This function is generally used to kill a cleanup on an already + * created mutex + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex); + +/** + * Return the name of the lockfile for the mutex, or NULL + * if the mutex doesn't use a lock file + */ + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex); + +/** + * Display the name of the mutex, as it relates to the actual method used. + * This matches the valid options for Apache's AcceptMutex directive + * @param mutex the name of the mutex + */ +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex); + +/** + * Display the name of the default mutex: APR_LOCK_DEFAULT + */ +APR_DECLARE(const char *) apr_proc_mutex_defname(void); + +/** + * Get the pool used by this proc_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(proc_mutex); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_PROC_MUTEX_H */ diff --git a/include/apr-linux/apr_queue.h b/include/apr-linux/apr_queue.h new file mode 100644 index 0000000..5d24c67 --- /dev/null +++ b/include/apr-linux/apr_queue.h @@ -0,0 +1,138 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_QUEUE_H +#define APR_QUEUE_H + +/** + * @file apr_queue.h + * @brief Thread Safe FIFO bounded queue + * @note Since most implementations of the queue are backed by a condition + * variable implementation, it isn't available on systems without threads. + * Although condition variables are some times available without threads. + */ + +#include "apu.h" +#include "apr_errno.h" +#include "apr_pools.h" + +#if APR_HAS_THREADS + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_FIFO Thread Safe FIFO bounded queue + * @ingroup APR_Util + * @{ + */ + +/** + * opaque structure + */ +typedef struct apr_queue_t apr_queue_t; + +/** + * create a FIFO queue + * @param queue The new queue + * @param queue_capacity maximum size of the queue + * @param a pool to allocate queue from + */ +APU_DECLARE(apr_status_t) apr_queue_create(apr_queue_t **queue, + unsigned int queue_capacity, + apr_pool_t *a); + +/** + * push/add a object to the queue, blocking if the queue is already full + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking was interrupted (try again) + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successfull push + */ +APU_DECLARE(apr_status_t) apr_queue_push(apr_queue_t *queue, void *data); + +/** + * pop/get an object from the queue, blocking if the queue is already empty + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking was interrupted (try again) + * @returns APR_EOF if the queue has been terminated + * @returns APR_SUCCESS on a successfull pop + */ +APU_DECLARE(apr_status_t) apr_queue_pop(apr_queue_t *queue, void **data); + +/** + * push/add a object to the queue, returning immediatly if the queue is full + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is full + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successfull push + */ +APU_DECLARE(apr_status_t) apr_queue_trypush(apr_queue_t *queue, void *data); + +/** + * pop/get an object to the queue, returning immediatly if the queue is empty + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is empty + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successfull push + */ +APU_DECLARE(apr_status_t) apr_queue_trypop(apr_queue_t *queue, void **data); + +/** + * returns the size of the queue. + * + * @warning this is not threadsafe, and is intended for reporting/monitoring + * of the queue. + * @param queue the queue + * @returns the size of the queue + */ +APU_DECLARE(unsigned int) apr_queue_size(apr_queue_t *queue); + +/** + * interrupt all the threads blocking on this queue. + * + * @param queue the queue + */ +APU_DECLARE(apr_status_t) apr_queue_interrupt_all(apr_queue_t *queue); + +/** + * terminate all queue, sendinging a interupt to all the + * blocking threads + * + * @param queue the queue + */ +APU_DECLARE(apr_status_t) apr_queue_term(apr_queue_t *queue); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* APR_HAS_THREADS */ + +#endif /* APRQUEUE_H */ diff --git a/include/apr-linux/apr_random.h b/include/apr-linux/apr_random.h new file mode 100644 index 0000000..2915435 --- /dev/null +++ b/include/apr-linux/apr_random.h @@ -0,0 +1,153 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_RANDOM_H +#define APR_RANDOM_H + +/** + * @file apr_random.h + * @brief APR PRNG routines + */ + +#include "apr_pools.h" +#include "apr_thread_proc.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_random PRNG Routines + * @ingroup APR + * @{ + */ + +typedef struct apr_crypto_hash_t apr_crypto_hash_t; + +typedef void apr_crypto_hash_init_t(apr_crypto_hash_t *hash); +typedef void apr_crypto_hash_add_t(apr_crypto_hash_t *hash, const void *data, + apr_size_t bytes); +typedef void apr_crypto_hash_finish_t(apr_crypto_hash_t *hash, + unsigned char *result); + + +/* FIXME: make this opaque */ +struct apr_crypto_hash_t { + apr_crypto_hash_init_t *init; + apr_crypto_hash_add_t *add; + apr_crypto_hash_finish_t *finish; + apr_size_t size; + void *data; +}; + +/** + * Allocate and initialize the SHA-256 context + * @param p The pool to allocate from + */ +APR_DECLARE(apr_crypto_hash_t *) apr_crypto_sha256_new(apr_pool_t *p); + +/** Opaque PRNG structure. */ +typedef struct apr_random_t apr_random_t; + +/** + * Initialize a PRNG state + * @param g The PRNG state + * @param p The pool to allocate from + * @param pool_hash Pool hash functions + * @param key_hash Key hash functions + * @param prng_hash PRNG hash functions + */ +APR_DECLARE(void) apr_random_init(apr_random_t *g, apr_pool_t *p, + apr_crypto_hash_t *pool_hash, + apr_crypto_hash_t *key_hash, + apr_crypto_hash_t *prng_hash); +/** + * Allocate and initialize (apr_crypto_sha256_new) a new PRNG state. + * @param p The pool to allocate from + */ +APR_DECLARE(apr_random_t *) apr_random_standard_new(apr_pool_t *p); + +/** + * Mix the randomness pools. + * @param g The PRNG state + * @param entropy_ Entropy buffer + * @param bytes Length of entropy_ in bytes + */ +APR_DECLARE(void) apr_random_add_entropy(apr_random_t *g, + const void *entropy_, + apr_size_t bytes); +/** + * Generate cryptographically insecure random bytes. + * @param g The RNG state + * @param random Buffer to fill with random bytes + * @param bytes Length of buffer in bytes + */ +APR_DECLARE(apr_status_t) apr_random_insecure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes); + +/** + * Generate cryptographically secure random bytes. + * @param g The RNG state + * @param random Buffer to fill with random bytes + * @param bytes Length of buffer in bytes + */ +APR_DECLARE(apr_status_t) apr_random_secure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes); +/** + * Ensures that E bits of conditional entropy are mixed into the PRNG + * before any further randomness is extracted. + * @param g The RNG state + */ +APR_DECLARE(void) apr_random_barrier(apr_random_t *g); + +/** + * Return APR_SUCCESS if the cryptographic PRNG has been seeded with + * enough data, APR_ENOTENOUGHENTROPY otherwise. + * @param r The RNG state + */ +APR_DECLARE(apr_status_t) apr_random_secure_ready(apr_random_t *r); + +/** + * Return APR_SUCCESS if the PRNG has been seeded with enough data, + * APR_ENOTENOUGHENTROPY otherwise. + * @param r The PRNG state + */ +APR_DECLARE(apr_status_t) apr_random_insecure_ready(apr_random_t *r); + +/** + * Mix the randomness pools after forking. + * @param proc The resulting process handle from apr_proc_fork() + * @remark Call this in the child after forking to mix the randomness + * pools. Note that its generally a bad idea to fork a process with a + * real PRNG in it - better to have the PRNG externally and get the + * randomness from there. However, if you really must do it, then you + * should supply all your entropy to all the PRNGs - don't worry, they + * won't produce the same output. + * @remark Note that apr_proc_fork() calls this for you, so only weird + * applications need ever call it themselves. + * @internal + */ +APR_DECLARE(void) apr_random_after_fork(apr_proc_t *proc); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_RANDOM_H */ diff --git a/include/apr-linux/apr_reslist.h b/include/apr-linux/apr_reslist.h new file mode 100644 index 0000000..39e8398 --- /dev/null +++ b/include/apr-linux/apr_reslist.h @@ -0,0 +1,150 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_RESLIST_H +#define APR_RESLIST_H + +/** + * @file apr_reslist.h + * @brief APR-UTIL Resource List Routines + */ + +#include "apr.h" +#include "apu.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_time.h" + +#if APR_HAS_THREADS + +/** + * @defgroup APR_Util_RL Resource List Routines + * @ingroup APR_Util + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Opaque resource list object */ +typedef struct apr_reslist_t apr_reslist_t; + +/* Generic constructor called by resource list when it needs to create a + * resource. + * @param resource opaque resource + * @param param flags + * @param pool Pool + */ +typedef apr_status_t (*apr_reslist_constructor)(void **resource, void *params, + apr_pool_t *pool); + +/* Generic destructor called by resource list when it needs to destroy a + * resource. + * @param resource opaque resource + * @param param flags + * @param pool Pool + */ +typedef apr_status_t (*apr_reslist_destructor)(void *resource, void *params, + apr_pool_t *pool); + +/** + * Create a new resource list with the following parameters: + * @param reslist An address where the pointer to the new resource + * list will be stored. + * @param pool The pool to use for local storage and management + * @param min Allowed minimum number of available resources. Zero + * creates new resources only when needed. + * @param smax Resources will be destroyed to meet this maximum + * restriction as they expire. + * @param hmax Absolute maximum limit on the number of total resources. + * @param ttl If non-zero, sets the maximum amount of time a resource + * may be available while exceeding the soft limit. + * @param con Constructor routine that is called to create a new resource. + * @param de Destructor routine that is called to destroy an expired resource. + * @param params Passed to constructor and deconstructor + * @param pool The pool from which to create this resoure list. Also the + * same pool that is passed to the constructor and destructor + * routines. + */ +APU_DECLARE(apr_status_t) apr_reslist_create(apr_reslist_t **reslist, + int min, int smax, int hmax, + apr_interval_time_t ttl, + apr_reslist_constructor con, + apr_reslist_destructor de, + void *params, + apr_pool_t *pool); + +/** + * Destroy the given resource list and all resources controlled by + * this list. + * FIXME: Should this block until all resources become available, + * or maybe just destroy all the free ones, or maybe destroy + * them even though they might be in use by something else? + * Currently it will abort if there are resources that haven't + * been released, so there is an assumption that all resources + * have been released to the list before calling this function. + * @param reslist The reslist to destroy + */ +APU_DECLARE(apr_status_t) apr_reslist_destroy(apr_reslist_t *reslist); + +/** + * Retrieve a resource from the list, creating a new one if necessary. + * If we have met our maximum number of resources, we will block + * until one becomes available. + */ +APU_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist, + void **resource); + +/** + * Return a resource back to the list of available resources. + */ +APU_DECLARE(apr_status_t) apr_reslist_release(apr_reslist_t *reslist, + void *resource); + +/** + * Set the timeout the acquire will wait for a free resource + * when the maximum number of resources is exceeded. + * @param reslist The resource list. + * @param timeout Timeout to wait. The zero waits forewer. + */ +APU_DECLARE(void) apr_reslist_timeout_set(apr_reslist_t *reslist, + apr_interval_time_t timeout); + +/** + * Return the number of outstanding resources. + * @param reslist The resource list. + */ +APU_DECLARE(apr_uint32_t) apr_reslist_acquired_count(apr_reslist_t *reslist); + +/** + * Invalidate a resource in the pool - e.g. a database connection + * that returns a "lost connection" error and can't be restored. + * Use this instead of apr_reslist_release if the resource is bad. + */ +APU_DECLARE(apr_status_t) apr_reslist_invalidate(apr_reslist_t *reslist, + void *resource); + + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* APR_HAS_THREADS */ + +#endif /* ! APR_RESLIST_H */ diff --git a/include/apr-linux/apr_ring.h b/include/apr-linux/apr_ring.h new file mode 100644 index 0000000..935b07f --- /dev/null +++ b/include/apr-linux/apr_ring.h @@ -0,0 +1,513 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 code draws heavily from the 4.4BSD macros + * and Dean Gaudet's "splim/ring.h". + * + * + * + * We'd use Dean's code directly if we could guarantee the + * availability of inline functions. + */ + +#ifndef APR_RING_H +#define APR_RING_H + +/** + * @file apr_ring.h + * @brief APR Rings + */ + +/* + * for offsetof() + */ +#include "apr_general.h" + +/** + * @defgroup apr_ring Ring Macro Implementations + * @ingroup APR + * A ring is a kind of doubly-linked list that can be manipulated + * without knowing where its head is. + * @{ + */ + +/** + * The Ring Element + * + * A ring element struct is linked to the other elements in the ring + * through its ring entry field, e.g. + *
+ *      struct my_element_t {
+ *          APR_RING_ENTRY(my_element_t) link;
+ *          int foo;
+ *          char *bar;
+ *      };
+ * 
+ * + * An element struct may be put on more than one ring if it has more + * than one APR_RING_ENTRY field. Each APR_RING_ENTRY has a corresponding + * APR_RING_HEAD declaration. + * + * @warning For strict C standards compliance you should put the APR_RING_ENTRY + * first in the element struct unless the head is always part of a larger + * object with enough earlier fields to accommodate the offsetof() used + * to compute the ring sentinel below. You can usually ignore this caveat. + */ +#define APR_RING_ENTRY(elem) \ + struct { \ + struct elem * volatile next; \ + struct elem * volatile prev; \ + } + +/** + * The Ring Head + * + * Each ring is managed via its head, which is a struct declared like this: + *
+ *      APR_RING_HEAD(my_ring_t, my_element_t);
+ *      struct my_ring_t ring, *ringp;
+ * 
+ * + * This struct looks just like the element link struct so that we can + * be sure that the typecasting games will work as expected. + * + * The first element in the ring is next after the head, and the last + * element is just before the head. + */ +#define APR_RING_HEAD(head, elem) \ + struct head { \ + struct elem *next; \ + struct elem *prev; \ + } + +/** + * The Ring Sentinel + * + * This is the magic pointer value that occurs before the first and + * after the last elements in the ring, computed from the address of + * the ring's head. The head itself isn't an element, but in order to + * get rid of all the special cases when dealing with the ends of the + * ring, we play typecasting games to make it look like one. + * + * Here is a diagram to illustrate the arrangements of the next and + * prev pointers of each element in a single ring. Note that they point + * to the start of each element, not to the APR_RING_ENTRY structure. + * + *
+ *     +->+------+<-+  +->+------+<-+  +->+------+<-+
+ *     |  |struct|  |  |  |struct|  |  |  |struct|  |
+ *    /   | elem |   \/   | elem |   \/   | elem |  \
+ * ...    |      |   /\   |      |   /\   |      |   ...
+ *        +------+  |  |  +------+  |  |  +------+
+ *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
+ *        |  next|--+     | entry|--+     |  next|--...
+ *        +------+        +------+        +------+
+ *        | etc. |        | etc. |        | etc. |
+ *        :      :        :      :        :      :
+ * 
+ * + * The APR_RING_HEAD is nothing but a bare APR_RING_ENTRY. The prev + * and next pointers in the first and last elements don't actually + * point to the head, they point to a phantom place called the + * sentinel. Its value is such that last->next->next == first because + * the offset from the sentinel to the head's next pointer is the same + * as the offset from the start of an element to its next pointer. + * This also works in the opposite direction. + * + *
+ *        last                            first
+ *     +->+------+<-+  +->sentinel<-+  +->+------+<-+
+ *     |  |struct|  |  |            |  |  |struct|  |
+ *    /   | elem |   \/              \/   | elem |  \
+ * ...    |      |   /\              /\   |      |   ...
+ *        +------+  |  |  +------+  |  |  +------+
+ *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
+ *        |  next|--+     |  head|--+     |  next|--...
+ *        +------+        +------+        +------+
+ *        | etc. |                        | etc. |
+ *        :      :                        :      :
+ * 
+ * + * Note that the offset mentioned above is different for each kind of + * ring that the element may be on, and each kind of ring has a unique + * name for its APR_RING_ENTRY in each element, and has its own type + * for its APR_RING_HEAD. + * + * Note also that if the offset is non-zero (which is required if an + * element has more than one APR_RING_ENTRY), the unreality of the + * sentinel may have bad implications on very perverse implementations + * of C -- see the warning in APR_RING_ENTRY. + * + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SENTINEL(hp, elem, link) \ + (struct elem *)((char *)(&(hp)->next) - APR_OFFSETOF(struct elem, link)) + +/** + * The first element of the ring + * @param hp The head of the ring + */ +#define APR_RING_FIRST(hp) (hp)->next +/** + * The last element of the ring + * @param hp The head of the ring + */ +#define APR_RING_LAST(hp) (hp)->prev +/** + * The next element in the ring + * @param ep The current element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_NEXT(ep, link) (ep)->link.next +/** + * The previous element in the ring + * @param ep The current element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_PREV(ep, link) (ep)->link.prev + + +/** + * Initialize a ring + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INIT(hp, elem, link) do { \ + APR_RING_FIRST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ + APR_RING_LAST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ + } while (0) + +/** + * Determine if a ring is empty + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @return true or false + */ +#define APR_RING_EMPTY(hp, elem, link) \ + (APR_RING_FIRST((hp)) == APR_RING_SENTINEL((hp), elem, link)) + +/** + * Initialize a singleton element + * @param ep The element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_ELEM_INIT(ep, link) do { \ + APR_RING_NEXT((ep), link) = (ep); \ + APR_RING_PREV((ep), link) = (ep); \ + } while (0) + + +/** + * Splice the sequence ep1..epN into the ring before element lep + * (..lep.. becomes ..ep1..epN..lep..) + * @warning This doesn't work for splicing before the first element or on + * empty rings... see APR_RING_SPLICE_HEAD for one that does + * @param lep Element in the ring to splice before + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do { \ + APR_RING_NEXT((epN), link) = (lep); \ + APR_RING_PREV((ep1), link) = APR_RING_PREV((lep), link); \ + APR_RING_NEXT(APR_RING_PREV((lep), link), link) = (ep1); \ + APR_RING_PREV((lep), link) = (epN); \ + } while (0) + +/** + * Splice the sequence ep1..epN into the ring after element lep + * (..lep.. becomes ..lep..ep1..epN..) + * @warning This doesn't work for splicing after the last element or on + * empty rings... see APR_RING_SPLICE_TAIL for one that does + * @param lep Element in the ring to splice after + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_AFTER(lep, ep1, epN, link) do { \ + APR_RING_PREV((ep1), link) = (lep); \ + APR_RING_NEXT((epN), link) = APR_RING_NEXT((lep), link); \ + APR_RING_PREV(APR_RING_NEXT((lep), link), link) = (epN); \ + APR_RING_NEXT((lep), link) = (ep1); \ + } while (0) + +/** + * Insert the element nep into the ring before element lep + * (..lep.. becomes ..nep..lep..) + * @warning This doesn't work for inserting before the first element or on + * empty rings... see APR_RING_INSERT_HEAD for one that does + * @param lep Element in the ring to insert before + * @param nep Element to insert + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_BEFORE(lep, nep, link) \ + APR_RING_SPLICE_BEFORE((lep), (nep), (nep), link) + +/** + * Insert the element nep into the ring after element lep + * (..lep.. becomes ..lep..nep..) + * @warning This doesn't work for inserting after the last element or on + * empty rings... see APR_RING_INSERT_TAIL for one that does + * @param lep Element in the ring to insert after + * @param nep Element to insert + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_AFTER(lep, nep, link) \ + APR_RING_SPLICE_AFTER((lep), (nep), (nep), link) + + +/** + * Splice the sequence ep1..epN into the ring before the first element + * (..hp.. becomes ..hp..ep1..epN..) + * @param hp Head of the ring + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link) \ + APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((hp), elem, link), \ + (ep1), (epN), link) + +/** + * Splice the sequence ep1..epN into the ring after the last element + * (..hp.. becomes ..ep1..epN..hp..) + * @param hp Head of the ring + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link) \ + APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((hp), elem, link), \ + (ep1), (epN), link) + +/** + * Insert the element nep into the ring before the first element + * (..hp.. becomes ..hp..nep..) + * @param hp Head of the ring + * @param nep Element to insert + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_HEAD(hp, nep, elem, link) \ + APR_RING_SPLICE_HEAD((hp), (nep), (nep), elem, link) + +/** + * Insert the element nep into the ring after the last element + * (..hp.. becomes ..nep..hp..) + * @param hp Head of the ring + * @param nep Element to insert + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_TAIL(hp, nep, elem, link) \ + APR_RING_SPLICE_TAIL((hp), (nep), (nep), elem, link) + +/** + * Concatenate ring h2 onto the end of ring h1, leaving h2 empty. + * @param h1 Head of the ring to concatenate onto + * @param h2 Head of the ring to concatenate + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CONCAT(h1, h2, elem, link) do { \ + if (!APR_RING_EMPTY((h2), elem, link)) { \ + APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((h1), elem, link), \ + APR_RING_FIRST((h2)), \ + APR_RING_LAST((h2)), link); \ + APR_RING_INIT((h2), elem, link); \ + } \ + } while (0) + +/** + * Prepend ring h2 onto the beginning of ring h1, leaving h2 empty. + * @param h1 Head of the ring to prepend onto + * @param h2 Head of the ring to prepend + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_PREPEND(h1, h2, elem, link) do { \ + if (!APR_RING_EMPTY((h2), elem, link)) { \ + APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((h1), elem, link), \ + APR_RING_FIRST((h2)), \ + APR_RING_LAST((h2)), link); \ + APR_RING_INIT((h2), elem, link); \ + } \ + } while (0) + +/** + * Unsplice a sequence of elements from a ring + * @warning The unspliced sequence is left with dangling pointers at either end + * @param ep1 First element in the sequence to unsplice + * @param epN Last element in the sequence to unsplice + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_UNSPLICE(ep1, epN, link) do { \ + APR_RING_NEXT(APR_RING_PREV((ep1), link), link) = \ + APR_RING_NEXT((epN), link); \ + APR_RING_PREV(APR_RING_NEXT((epN), link), link) = \ + APR_RING_PREV((ep1), link); \ + } while (0) + +/** + * Remove a single element from a ring + * @warning The unspliced element is left with dangling pointers at either end + * @param ep Element to remove + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_REMOVE(ep, link) \ + APR_RING_UNSPLICE((ep), (ep), link) + +/** + * Iterate over a ring + * @param ep The current element + * @param head The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_FOREACH(ep, head, elem, link) \ + for (ep = APR_RING_FIRST(head); \ + ep != APR_RING_SENTINEL(head, elem, link); \ + ep = APR_RING_NEXT(ep, link)) + +/** + * Iterate over a ring safe against removal of the current element + * @param ep1 The current element + * @param ep2 Iteration cursor + * @param head The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_FOREACH_SAFE(ep1, ep2, head, elem, link) \ + for (ep1 = APR_RING_FIRST(head), ep2 = APR_RING_NEXT(ep1, link); \ + ep1 != APR_RING_SENTINEL(head, elem, link); \ + ep1 = ep2, ep2 = APR_RING_NEXT(ep1, link)) + +/* Debugging tools: */ + +#ifdef APR_RING_DEBUG +#include +#include + +#define APR_RING_CHECK_ONE(msg, ptr) \ + fprintf(stderr, "*** %s %p\n", msg, ptr) + +#define APR_RING_CHECK(hp, elem, link, msg) \ + APR_RING_CHECK_ELEM(APR_RING_SENTINEL(hp, elem, link), elem, link, msg) + +#define APR_RING_CHECK_ELEM(ep, elem, link, msg) do { \ + struct elem *start = (ep); \ + struct elem *here = start; \ + fprintf(stderr, "*** ring check start -- %s\n", msg); \ + do { \ + fprintf(stderr, "\telem %p\n", here); \ + fprintf(stderr, "\telem->next %p\n", \ + APR_RING_NEXT(here, link)); \ + fprintf(stderr, "\telem->prev %p\n", \ + APR_RING_PREV(here, link)); \ + fprintf(stderr, "\telem->next->prev %p\n", \ + APR_RING_PREV(APR_RING_NEXT(here, link), link)); \ + fprintf(stderr, "\telem->prev->next %p\n", \ + APR_RING_NEXT(APR_RING_PREV(here, link), link)); \ + if (APR_RING_PREV(APR_RING_NEXT(here, link), link) != here) { \ + fprintf(stderr, "\t*** elem->next->prev != elem\n"); \ + break; \ + } \ + if (APR_RING_NEXT(APR_RING_PREV(here, link), link) != here) { \ + fprintf(stderr, "\t*** elem->prev->next != elem\n"); \ + break; \ + } \ + here = APR_RING_NEXT(here, link); \ + } while (here != start); \ + fprintf(stderr, "*** ring check end\n"); \ + } while (0) + +#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) \ + APR_RING_CHECK_ELEM_CONSISTENCY(APR_RING_SENTINEL(hp, elem, link),\ + elem, link) + +#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) do { \ + struct elem *start = (ep); \ + struct elem *here = start; \ + do { \ + assert(APR_RING_PREV(APR_RING_NEXT(here, link), link) == here); \ + assert(APR_RING_NEXT(APR_RING_PREV(here, link), link) == here); \ + here = APR_RING_NEXT(here, link); \ + } while (here != start); \ + } while (0) + +#else +/** + * Print a single pointer value to STDERR + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param msg Descriptive message + * @param ptr Pointer value to print + */ +#define APR_RING_CHECK_ONE(msg, ptr) +/** + * Dump all ring pointers to STDERR, starting with the head and looping all + * the way around the ring back to the head. Aborts if an inconsistency + * is found. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param hp Head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @param msg Descriptive message + */ +#define APR_RING_CHECK(hp, elem, link, msg) +/** + * Loops around a ring and checks all the pointers for consistency. Pops + * an assertion if any inconsistency is found. Same idea as APR_RING_CHECK() + * except that it's silent if all is well. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param hp Head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) +/** + * Dump all ring pointers to STDERR, starting with the given element and + * looping all the way around the ring back to that element. Aborts if + * an inconsistency is found. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param ep The element + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @param msg Descriptive message + */ +#define APR_RING_CHECK_ELEM(ep, elem, link, msg) +/** + * Loops around a ring, starting with the given element, and checks all + * the pointers for consistency. Pops an assertion if any inconsistency + * is found. Same idea as APR_RING_CHECK_ELEM() except that it's silent + * if all is well. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param ep The element + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) +#endif + +/** @} */ + +#endif /* !APR_RING_H */ diff --git a/include/apr-linux/apr_rmm.h b/include/apr-linux/apr_rmm.h new file mode 100644 index 0000000..976fe9c --- /dev/null +++ b/include/apr-linux/apr_rmm.h @@ -0,0 +1,137 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_RMM_H +#define APR_RMM_H +/** + * @file apr_rmm.h + * @brief APR-UTIL Relocatable Memory Management Routines + */ +/** + * @defgroup APR_Util_RMM Relocatable Memory Management Routines + * @ingroup APR_Util + * @{ + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apu.h" +#include "apr_anylock.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Structure to access Relocatable, Managed Memory */ +typedef struct apr_rmm_t apr_rmm_t; + +/** Fundamental allocation unit, within a specific apr_rmm_t */ +typedef apr_size_t apr_rmm_off_t; + +/** + * Initialize a relocatable memory block to be managed by the apr_rmm API. + * @param rmm The relocatable memory block + * @param lock An apr_anylock_t of the appropriate type of lock, or NULL + * if no locking is required. + * @param membuf The block of relocatable memory to be managed + * @param memsize The size of relocatable memory block to be managed + * @param cont The pool to use for local storage and management + * @remark Both @param membuf and @param memsize must be aligned + * (for instance using APR_ALIGN_DEFAULT). + */ +APU_DECLARE(apr_status_t) apr_rmm_init(apr_rmm_t **rmm, apr_anylock_t *lock, + void *membuf, apr_size_t memsize, + apr_pool_t *cont); + +/** + * Destroy a managed memory block. + * @param rmm The relocatable memory block to destroy + */ +APU_DECLARE(apr_status_t) apr_rmm_destroy(apr_rmm_t *rmm); + +/** + * Attach to a relocatable memory block already managed by the apr_rmm API. + * @param rmm The relocatable memory block + * @param lock An apr_anylock_t of the appropriate type of lock + * @param membuf The block of relocatable memory already under management + * @param cont The pool to use for local storage and management + */ +APU_DECLARE(apr_status_t) apr_rmm_attach(apr_rmm_t **rmm, apr_anylock_t *lock, + void *membuf, apr_pool_t *cont); + +/** + * Detach from the managed block of memory. + * @param rmm The relocatable memory block to detach from + */ +APU_DECLARE(apr_status_t) apr_rmm_detach(apr_rmm_t *rmm); + +/** + * Allocate memory from the block of relocatable memory. + * @param rmm The relocatable memory block + * @param reqsize How much memory to allocate + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_malloc(apr_rmm_t *rmm, apr_size_t reqsize); + +/** + * Realloc memory from the block of relocatable memory. + * @param rmm The relocatable memory block + * @param entity The memory allocation to realloc + * @param reqsize The new size + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_realloc(apr_rmm_t *rmm, void *entity, apr_size_t reqsize); + +/** + * Allocate memory from the block of relocatable memory and initialize it to zero. + * @param rmm The relocatable memory block + * @param reqsize How much memory to allocate + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_calloc(apr_rmm_t *rmm, apr_size_t reqsize); + +/** + * Free allocation returned by apr_rmm_malloc or apr_rmm_calloc. + * @param rmm The relocatable memory block + * @param entity The memory allocation to free + */ +APU_DECLARE(apr_status_t) apr_rmm_free(apr_rmm_t *rmm, apr_rmm_off_t entity); + +/** + * Retrieve the physical address of a relocatable allocation of memory + * @param rmm The relocatable memory block + * @param entity The memory allocation to free + * @return address The address, aligned with APR_ALIGN_DEFAULT. + */ +APU_DECLARE(void *) apr_rmm_addr_get(apr_rmm_t *rmm, apr_rmm_off_t entity); + +/** + * Compute the offset of a relocatable allocation of memory + * @param rmm The relocatable memory block + * @param entity The physical address to convert to an offset + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_offset_get(apr_rmm_t *rmm, void *entity); + +/** + * Compute the required overallocation of memory needed to fit n allocs + * @param n The number of alloc/calloc regions desired + */ +APU_DECLARE(apr_size_t) apr_rmm_overhead_get(int n); + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* ! APR_RMM_H */ + diff --git a/include/apr-linux/apr_sdbm.h b/include/apr-linux/apr_sdbm.h new file mode 100644 index 0000000..5759508 --- /dev/null +++ b/include/apr-linux/apr_sdbm.h @@ -0,0 +1,176 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: ex-public domain + */ + +#ifndef APR_SDBM_H +#define APR_SDBM_H + +#include "apu.h" +#include "apr_errno.h" +#include "apr_file_io.h" /* for apr_fileperms_t */ + +/** + * @file apr_sdbm.h + * @brief apr-util SDBM library + */ +/** + * @defgroup APR_Util_DBM_SDBM SDBM library + * @ingroup APR_Util_DBM + * @{ + */ + +/** + * Structure for referencing an sdbm + */ +typedef struct apr_sdbm_t apr_sdbm_t; + +/** + * Structure for referencing the datum record within an sdbm + */ +typedef struct { + /** pointer to the data stored/retrieved */ + char *dptr; + /** size of data */ + /* apr_ssize_t for release 2.0??? */ + int dsize; +} apr_sdbm_datum_t; + +/* The extensions used for the database files */ +/** SDBM Directory file extension */ +#define APR_SDBM_DIRFEXT ".dir" +/** SDBM page file extension */ +#define APR_SDBM_PAGFEXT ".pag" + +/* flags to sdbm_store */ +#define APR_SDBM_INSERT 0 /**< Insert */ +#define APR_SDBM_REPLACE 1 /**< Replace */ +#define APR_SDBM_INSERTDUP 2 /**< Insert with duplicates */ + +/** + * Open an sdbm database by file name + * @param db The newly opened database + * @param name The sdbm file to open + * @param mode The flag values (APR_READ and APR_BINARY flags are implicit) + *
+ *           APR_WRITE          open for read-write access
+ *           APR_CREATE         create the sdbm if it does not exist
+ *           APR_TRUNCATE       empty the contents of the sdbm
+ *           APR_EXCL           fail for APR_CREATE if the file exists
+ *           APR_DELONCLOSE     delete the sdbm when closed
+ *           APR_SHARELOCK      support locking across process/machines
+ * 
+ * @param perms Permissions to apply to if created + * @param p The pool to use when creating the sdbm + * @remark The sdbm name is not a true file name, as sdbm appends suffixes + * for seperate data and index files. + */ +APU_DECLARE(apr_status_t) apr_sdbm_open(apr_sdbm_t **db, const char *name, + apr_int32_t mode, + apr_fileperms_t perms, apr_pool_t *p); + +/** + * Close an sdbm file previously opened by apr_sdbm_open + * @param db The database to close + */ +APU_DECLARE(apr_status_t) apr_sdbm_close(apr_sdbm_t *db); + +/** + * Lock an sdbm database for concurency of multiple operations + * @param db The database to lock + * @param type The lock type + *
+ *           APR_FLOCK_SHARED
+ *           APR_FLOCK_EXCLUSIVE
+ * 
+ * @remark Calls to apr_sdbm_lock may be nested. All apr_sdbm functions + * perform implicit locking. Since an APR_FLOCK_SHARED lock cannot be + * portably promoted to an APR_FLOCK_EXCLUSIVE lock, apr_sdbm_store and + * apr_sdbm_delete calls will fail if an APR_FLOCK_SHARED lock is held. + * The apr_sdbm_lock call requires the database to be opened with the + * APR_SHARELOCK mode value. + */ +APU_DECLARE(apr_status_t) apr_sdbm_lock(apr_sdbm_t *db, int type); + +/** + * Release an sdbm lock previously aquired by apr_sdbm_lock + * @param db The database to unlock + */ +APU_DECLARE(apr_status_t) apr_sdbm_unlock(apr_sdbm_t *db); + +/** + * Fetch an sdbm record value by key + * @param db The database + * @param value The value datum retrieved for this record + * @param key The key datum to find this record + */ +APU_DECLARE(apr_status_t) apr_sdbm_fetch(apr_sdbm_t *db, + apr_sdbm_datum_t *value, + apr_sdbm_datum_t key); + +/** + * Store an sdbm record value by key + * @param db The database + * @param key The key datum to store this record by + * @param value The value datum to store in this record + * @param opt The method used to store the record + *
+ *           APR_SDBM_INSERT     return an error if the record exists
+ *           APR_SDBM_REPLACE    overwrite any existing record for key
+ * 
+ */ +APU_DECLARE(apr_status_t) apr_sdbm_store(apr_sdbm_t *db, apr_sdbm_datum_t key, + apr_sdbm_datum_t value, int opt); + +/** + * Delete an sdbm record value by key + * @param db The database + * @param key The key datum of the record to delete + * @remark It is not an error to delete a non-existent record. + */ +APU_DECLARE(apr_status_t) apr_sdbm_delete(apr_sdbm_t *db, + const apr_sdbm_datum_t key); + +/** + * Retrieve the first record key from a dbm + * @param db The database + * @param key The key datum of the first record + * @remark The keys returned are not ordered. To traverse the list of keys + * for an sdbm opened with APR_SHARELOCK, the caller must use apr_sdbm_lock + * prior to retrieving the first record, and hold the lock until after the + * last call to apr_sdbm_nextkey. + */ +APU_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, apr_sdbm_datum_t *key); + +/** + * Retrieve the next record key from an sdbm + * @param db The database + * @param key The key datum of the next record + */ +APU_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, apr_sdbm_datum_t *key); + +/** + * Returns true if the sdbm database opened for read-only access + * @param db The database to test + */ +APU_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db); +/** @} */ +#endif /* APR_SDBM_H */ diff --git a/include/apr-linux/apr_sha1.h b/include/apr-linux/apr_sha1.h new file mode 100644 index 0000000..2a4edf3 --- /dev/null +++ b/include/apr-linux/apr_sha1.h @@ -0,0 +1,121 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +/* NIST Secure Hash Algorithm + * heavily modified by Uwe Hollerbach uh@alumni.caltech edu + * from Peter C. Gutmann's implementation as found in + * Applied Cryptography by Bruce Schneier + * This code is hereby placed in the public domain + */ + +#ifndef APR_SHA1_H +#define APR_SHA1_H + +#include "apu.h" +#include "apr_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_sha1.h + * @brief APR-UTIL SHA1 library + */ + +/** size of the SHA1 DIGEST */ +#define APR_SHA1_DIGESTSIZE 20 + +/** + * Define the Magic String prefix that identifies a password as being + * hashed using our algorithm. + */ +#define APR_SHA1PW_ID "{SHA}" + +/** length of the SHA Password */ +#define APR_SHA1PW_IDLEN 5 + +/** @see apr_sha1_ctx_t */ +typedef struct apr_sha1_ctx_t apr_sha1_ctx_t; + +/** + * SHA1 context structure + */ +struct apr_sha1_ctx_t { + /** message digest */ + apr_uint32_t digest[5]; + /** 64-bit bit counts */ + apr_uint32_t count_lo, count_hi; + /** SHA data buffer */ + apr_uint32_t data[16]; + /** unprocessed amount in data */ + int local; +}; + +/** + * Provide a means to SHA1 crypt/encode a plaintext password in a way which + * makes password file compatible with those commonly use in netscape web + * and ldap installations. + * @param clear The plaintext password + * @param len The length of the plaintext password + * @param out The encrypted/encoded password + * @note SHA1 support is useful for migration purposes, but is less + * secure than Apache's password format, since Apache's (MD5) + * password format uses a random eight character salt to generate + * one of many possible hashes for the same password. Netscape + * uses plain SHA1 without a salt, so the same password + * will always generate the same hash, making it easier + * to break since the search space is smaller. + */ +APU_DECLARE(void) apr_sha1_base64(const char *clear, int len, char *out); + +/** + * Initialize the SHA digest + * @param context The SHA context to initialize + */ +APU_DECLARE(void) apr_sha1_init(apr_sha1_ctx_t *context); + +/** + * Update the SHA digest + * @param context The SHA1 context to update + * @param input The buffer to add to the SHA digest + * @param inputLen The length of the input buffer + */ +APU_DECLARE(void) apr_sha1_update(apr_sha1_ctx_t *context, const char *input, + unsigned int inputLen); + +/** + * Update the SHA digest with binary data + * @param context The SHA1 context to update + * @param input The buffer to add to the SHA digest + * @param inputLen The length of the input buffer + */ +APU_DECLARE(void) apr_sha1_update_binary(apr_sha1_ctx_t *context, + const unsigned char *input, + unsigned int inputLen); + +/** + * Finish computing the SHA digest + * @param digest the output buffer in which to store the digest + * @param context The context to finalize + */ +APU_DECLARE(void) apr_sha1_final(unsigned char digest[APR_SHA1_DIGESTSIZE], + apr_sha1_ctx_t *context); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SHA1_H */ diff --git a/include/apr-linux/apr_shm.h b/include/apr-linux/apr_shm.h new file mode 100644 index 0000000..2b1d50f --- /dev/null +++ b/include/apr-linux/apr_shm.h @@ -0,0 +1,146 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_SHM_H +#define APR_SHM_H + +/** + * @file apr_shm.h + * @brief APR Shared Memory Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_shm Shared Memory Routines + * @ingroup APR + * @{ + */ + +/** + * Private, platform-specific data struture representing a shared memory + * segment. + */ +typedef struct apr_shm_t apr_shm_t; + +/** + * Create and make accessable a shared memory segment. + * @param m The shared memory structure to create. + * @param reqsize The desired size of the segment. + * @param filename The file to use for shared memory on platforms that + * require it. + * @param pool the pool from which to allocate the shared memory + * structure. + * @remark A note about Anonymous vs. Named shared memory segments: + * Not all plaforms support anonymous shared memory segments, but in + * some cases it is prefered over other types of shared memory + * implementations. Passing a NULL 'file' parameter to this function + * will cause the subsystem to use anonymous shared memory segments. + * If such a system is not available, APR_ENOTIMPL is returned. + * @remark A note about allocation sizes: + * On some platforms it is necessary to store some metainformation + * about the segment within the actual segment. In order to supply + * the caller with the requested size it may be necessary for the + * implementation to request a slightly greater segment length + * from the subsystem. In all cases, the apr_shm_baseaddr_get() + * function will return the first usable byte of memory. + * + */ +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *pool); + +/** + * Remove named resource associated with a shared memory segment, + * preventing attachments to the resource, but not destroying it. + * @param filename The filename associated with shared-memory segment which + * needs to be removed + * @param pool The pool used for file operations + * @remark This function is only supported on platforms which support + * name-based shared memory segments, and will return APR_ENOTIMPL on + * platforms without such support. Removing the file while the shm + * is in use is not entirely portable, caller may use this to enhance + * obscurity of the resource, but be prepared for the the call to fail, + * and for concurrent attempts to create a resource of the same name + * to also fail. The pool cleanup of apr_shm_create (apr_shm_destroy) + * also removes the named resource. + */ +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool); + +/** + * Destroy a shared memory segment and associated memory. + * @param m The shared memory segment structure to destroy. + */ +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m); + +/** + * Attach to a shared memory segment that was created + * by another process. + * @param m The shared memory structure to create. + * @param filename The file used to create the original segment. + * (This MUST match the original filename.) + * @param pool the pool from which to allocate the shared memory + * structure for this process. + */ +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *filename, + apr_pool_t *pool); + +/** + * Detach from a shared memory segment without destroying it. + * @param m The shared memory structure representing the segment + * to detach from. + */ +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m); + +/** + * Retrieve the base address of the shared memory segment. + * NOTE: This address is only usable within the callers address + * space, since this API does not guarantee that other attaching + * processes will maintain the same address mapping. + * @param m The shared memory segment from which to retrieve + * the base address. + * @return address, aligned by APR_ALIGN_DEFAULT. + */ +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m); + +/** + * Retrieve the length of a shared memory segment in bytes. + * @param m The shared memory segment from which to retrieve + * the segment length. + */ +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m); + +/** + * Get the pool used by this shared memory segment. + */ +APR_POOL_DECLARE_ACCESSOR(shm); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SHM_T */ diff --git a/include/apr-linux/apr_signal.h b/include/apr-linux/apr_signal.h new file mode 100644 index 0000000..2063133 --- /dev/null +++ b/include/apr-linux/apr_signal.h @@ -0,0 +1,109 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_SIGNAL_H +#define APR_SIGNAL_H + +/** + * @file apr_signal.h + * @brief APR Signal Handling + */ + +#include "apr.h" +#include "apr_pools.h" + +#if APR_HAVE_SIGNAL_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_signal Signal Handling + * @ingroup APR + * @{ + */ + +#if APR_HAVE_SIGACTION || defined(DOXYGEN) + +#if defined(DARWIN) && !defined(__cplusplus) && !defined(_ANSI_SOURCE) +/* work around Darwin header file bugs + * http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2657228.html + */ +#undef SIG_DFL +#undef SIG_IGN +#undef SIG_ERR +#define SIG_DFL (void (*)(int))0 +#define SIG_IGN (void (*)(int))1 +#define SIG_ERR (void (*)(int))-1 +#endif + +/** Function prototype for signal handlers */ +typedef void apr_sigfunc_t(int); + +/** + * Set the signal handler function for a given signal + * @param signo The signal (eg... SIGWINCH) + * @param func the function to get called + */ +APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func); + +#if defined(SIG_IGN) && !defined(SIG_ERR) +#define SIG_ERR ((apr_sigfunc_t *) -1) +#endif + +#else /* !APR_HAVE_SIGACTION */ +#define apr_signal(a, b) signal(a, b) +#endif + + +/** + * Get the description for a specific signal number + * @param signum The signal number + * @return The description of the signal + */ +APR_DECLARE(const char *) apr_signal_description_get(int signum); + +/** + * APR-private function for initializing the signal package + * @internal + * @param pglobal The internal, global pool + */ +void apr_signal_init(apr_pool_t *pglobal); + +/** + * Block the delivery of a particular signal + * @param signum The signal number + * @return status + */ +APR_DECLARE(apr_status_t) apr_signal_block(int signum); + +/** + * Enable the delivery of a particular signal + * @param signum The signal number + * @return status + */ +APR_DECLARE(apr_status_t) apr_signal_unblock(int signum); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* APR_SIGNAL_H */ diff --git a/include/apr-linux/apr_strings.h b/include/apr-linux/apr_strings.h new file mode 100644 index 0000000..996f8ce --- /dev/null +++ b/include/apr-linux/apr_strings.h @@ -0,0 +1,361 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* Portions of this file are covered by */ +/* -*- mode: c; c-file-style: "k&r" -*- + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef APR_STRINGS_H +#define APR_STRINGS_H + +/** + * @file apr_strings.h + * @brief APR Strings library + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#define APR_WANT_IOVEC +#include "apr_want.h" + +#if APR_HAVE_STDARG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_strings String routines + * @ingroup APR + * @{ + */ + +/** + * Do a natural order comparison of two strings. + * @param a The first string to compare + * @param b The second string to compare + * @return Either <0, 0, or >0. If the first string is less than the second + * this returns <0, if they are equivalent it returns 0, and if the + * first string is greater than second string it retuns >0. + */ +APR_DECLARE(int) apr_strnatcmp(char const *a, char const *b); + +/** + * Do a natural order comparison of two strings ignoring the case of the + * strings. + * @param a The first string to compare + * @param b The second string to compare + * @return Either <0, 0, or >0. If the first string is less than the second + * this returns <0, if they are equivalent it returns 0, and if the + * first string is greater than second string it retuns >0. + */ +APR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b); + +/** + * duplicate a string into memory allocated out of a pool + * @param p The pool to allocate out of + * @param s The string to duplicate + * @return The new string + */ +APR_DECLARE(char *) apr_pstrdup(apr_pool_t *p, const char *s); + +/** + * Create a null-terminated string by making a copy of a sequence + * of characters and appending a null byte + * @param p The pool to allocate out of + * @param s The block of characters to duplicate + * @param n The number of characters to duplicate + * @return The new string + * @remark This is a faster alternative to apr_pstrndup, for use + * when you know that the string being duplicated really + * has 'n' or more characters. If the string might contain + * fewer characters, use apr_pstrndup. + */ +APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *p, const char *s, apr_size_t n); + +/** + * Duplicate at most n characters of a string into memory allocated + * out of a pool; the new string will be NUL-terminated + * @param p The pool to allocate out of + * @param s The string to duplicate + * @param n The maximum number of characters to duplicate + * @return The new string + * @remark The amount of memory allocated from the pool is the length + * of the returned string including the NUL terminator + */ +APR_DECLARE(char *) apr_pstrndup(apr_pool_t *p, const char *s, apr_size_t n); + +/** + * Duplicate a block of memory. + * + * @param p The pool to allocate from + * @param m The memory to duplicate + * @param n The number of bytes to duplicate + * @return The new block of memory + */ +APR_DECLARE(void *) apr_pmemdup(apr_pool_t *p, const void *m, apr_size_t n); + +/** + * Concatenate multiple strings, allocating memory out a pool + * @param p The pool to allocate out of + * @param ... The strings to concatenate. The final string must be NULL + * @return The new string + */ +APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *p, ...); + +/** + * Concatenate multiple strings specified in a writev-style vector + * @param p The pool from which to allocate + * @param vec The strings to concatenate + * @param nvec The number of strings to concatenate + * @param nbytes (output) strlen of new string (pass in NULL to omit) + * @return The new string + */ +APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *p, const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes); + +/** + * printf-style style printing routine. The data is output to a string + * allocated from a pool + * @param p The pool to allocate out of + * @param fmt The format of the string + * @param ap The arguments to use while printing the data + * @return The new string + */ +APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *p, const char *fmt, va_list ap); + +/** + * printf-style style printing routine. The data is output to a string + * allocated from a pool + * @param p The pool to allocate out of + * @param fmt The format of the string + * @param ... The arguments to use while printing the data + * @return The new string + */ +APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) + __attribute__((format(printf,2,3))); + +/** + * Copy up to dst_size characters from src to dst; does not copy + * past a NUL terminator in src, but always terminates dst with a NUL + * regardless. + * @param dst The destination string + * @param src The source string + * @param dst_size The space available in dst; dst always receives + * NUL termination, so if src is longer than + * dst_size, the actual number of characters copied is + * dst_size - 1. + * @return Pointer to the NUL terminator of the destination string, dst + * @remark + *
+ * Note the differences between this function and strncpy():
+ *  1) strncpy() doesn't always NUL terminate; apr_cpystrn() does.
+ *  2) strncpy() pads the destination string with NULs, which is often 
+ *     unnecessary; apr_cpystrn() does not.
+ *  3) strncpy() returns a pointer to the beginning of the dst string;
+ *     apr_cpystrn() returns a pointer to the NUL terminator of dst, 
+ *     to allow a check for truncation.
+ * 
+ */ +APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, + apr_size_t dst_size); + +/** + * Strip spaces from a string + * @param dest The destination string. It is okay to modify the string + * in place. Namely dest == src + * @param src The string to rid the spaces from. + * @return The destination string, dest. + */ +APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src); + +/** + * Convert the arguments to a program from one string to an array of + * strings terminated by a NULL pointer + * @param arg_str The arguments to convert + * @param argv_out Output location. This is a pointer to an array of strings. + * @param token_context Pool to use. + */ +APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, + char ***argv_out, + apr_pool_t *token_context); + +/** + * Split a string into separate null-terminated tokens. The tokens are + * delimited in the string by one or more characters from the sep + * argument. + * @param str The string to separate; this should be specified on the + * first call to apr_strtok() for a given string, and NULL + * on subsequent calls. + * @param sep The set of delimiters + * @param last Internal state saved by apr_strtok() between calls. + * @return The next token from the string + */ +APR_DECLARE(char *) apr_strtok(char *str, const char *sep, char **last); + +/** + * @defgroup APR_Strings_Snprintf snprintf implementations + * @warning + * These are snprintf implementations based on apr_vformatter(). + * + * Note that various standards and implementations disagree on the return + * value of snprintf, and side-effects due to %n in the formatting string. + * apr_snprintf (and apr_vsnprintf) behaves as follows: + * + * Process the format string until the entire string is exhausted, or + * the buffer fills. If the buffer fills then stop processing immediately + * (so no further %n arguments are processed), and return the buffer + * length. In all cases the buffer is NUL terminated. It will return the + * number of characters inserted into the buffer, not including the + * terminating NUL. As a special case, if len is 0, apr_snprintf will + * return the number of characters that would have been inserted if + * the buffer had been infinite (in this case, *buffer can be NULL) + * + * In no event does apr_snprintf return a negative number. + * @{ + */ + +/** + * snprintf routine based on apr_vformatter. This means it understands the + * same extensions. + * @param buf The buffer to write to + * @param len The size of the buffer + * @param format The format string + * @param ... The arguments to use to fill out the format string. + */ +APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, + const char *format, ...) + __attribute__((format(printf,3,4))); + +/** + * vsnprintf routine based on apr_vformatter. This means it understands the + * same extensions. + * @param buf The buffer to write to + * @param len The size of the buffer + * @param format The format string + * @param ap The arguments to use to fill out the format string. + */ +APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, + va_list ap); +/** @} */ + +/** + * create a string representation of an int, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n); + +/** + * create a string representation of a long, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n); + +/** + * create a string representation of an apr_off_t, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n); + +/** + * Convert a numeric string into an apr_off_t numeric value. + * @param offset The value of the parsed string. + * @param buf The string to parse. It may contain optional whitespace, + * followed by an optional '+' (positive, default) or '-' (negative) + * character, followed by an optional '0x' prefix if base is 0 or 16, + * followed by numeric digits appropriate for base. + * @param end A pointer to the end of the valid character in buf. If + * not NULL, it is set to the first invalid character in buf. + * @param base A numeric base in the range between 2 and 36 inclusive, + * or 0. If base is zero, buf will be treated as base ten unless its + * digits are prefixed with '0x', in which case it will be treated as + * base 16. + * @bug *end breaks type safety; where *buf is const, *end needs to be + * declared as const in APR 2.0 + */ +APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *buf, + char **end, int base); + +/** + * parse a numeric string into a 64-bit numeric value + * @param buf The string to parse. It may contain optional whitespace, + * followed by an optional '+' (positive, default) or '-' (negative) + * character, followed by an optional '0x' prefix if base is 0 or 16, + * followed by numeric digits appropriate for base. + * @param end A pointer to the end of the valid character in buf. If + * not NULL, it is set to the first invalid character in buf. + * @param base A numeric base in the range between 2 and 36 inclusive, + * or 0. If base is zero, buf will be treated as base ten unless its + * digits are prefixed with '0x', in which case it will be treated as + * base 16. + * @return The numeric value of the string. On overflow, errno is set + * to ERANGE. + */ +APR_DECLARE(apr_int64_t) apr_strtoi64(const char *buf, char **end, int base); + +/** + * parse a base-10 numeric string into a 64-bit numeric value. + * Equivalent to apr_strtoi64(buf, (char**)NULL, 10). + * @param buf The string to parse + * @return The numeric value of the string + */ +APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf); + +/** + * Format a binary size (magnitiudes are 2^10 rather than 10^3) from an apr_off_t, + * as bytes, K, M, T, etc, to a four character compacted human readable string. + * @param size The size to format + * @param buf The 5 byte text buffer (counting the trailing null) + * @return The buf passed to apr_strfsize() + * @remark All negative sizes report ' - ', apr_strfsize only formats positive values. + */ +APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_STRINGS_H */ diff --git a/include/apr-linux/apr_strmatch.h b/include/apr-linux/apr_strmatch.h new file mode 100644 index 0000000..53fadad --- /dev/null +++ b/include/apr-linux/apr_strmatch.h @@ -0,0 +1,81 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_STRMATCH_H +#define APR_STRMATCH_H +/** + * @file apr_strmatch.h + * @brief APR-UTIL string matching routines + */ + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_StrMatch String matching routines + * @ingroup APR_Util + * @{ + */ + +/** @see apr_strmatch_pattern */ +typedef struct apr_strmatch_pattern apr_strmatch_pattern; + +/** + * Precompiled search pattern + */ +struct apr_strmatch_pattern { + /** Function called to compare */ + const char *(*compare)(const apr_strmatch_pattern *this_pattern, + const char *s, apr_size_t slen); + const char *pattern; /**< Current pattern */ + apr_size_t length; /**< Current length */ + void *context; /**< hook to add precomputed metadata */ +}; + +#if defined(DOXYGEN) +/** + * Search for a precompiled pattern within a string + * @param pattern The pattern + * @param s The string in which to search for the pattern + * @param slen The length of s (excluding null terminator) + * @return A pointer to the first instance of the pattern in s, or + * NULL if not found + */ +APU_DECLARE(const char *) apr_strmatch(const apr_strmatch_pattern *pattern, + const char *s, apr_size_t slen); +#else +#define apr_strmatch(pattern, s, slen) (*((pattern)->compare))((pattern), (s), (slen)) +#endif + +/** + * Precompile a pattern for matching using the Boyer-Moore-Horspool algorithm + * @param p The pool from which to allocate the pattern + * @param s The pattern string + * @param case_sensitive Whether the matching should be case-sensitive + * @return a pointer to the compiled pattern, or NULL if compilation fails + */ +APU_DECLARE(const apr_strmatch_pattern *) apr_strmatch_precompile(apr_pool_t *p, const char *s, int case_sensitive); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_STRMATCH_H */ diff --git a/include/apr-linux/apr_support.h b/include/apr-linux/apr_support.h new file mode 100644 index 0000000..79c8cb4 --- /dev/null +++ b/include/apr-linux/apr_support.h @@ -0,0 +1,57 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_SUPPORT_H +#define APR_SUPPORT_H + +/** + * @file apr_support.h + * @brief APR Support functions + */ + +#include "apr.h" +#include "apr_network_io.h" +#include "apr_file_io.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_support Internal APR support functions + * @ingroup APR + * @{ + */ + +/** + * Wait for IO to occur or timeout. + * + * @param f The file to wait on. + * @param s The socket to wait on if @a f is @c NULL. + * @param for_read If non-zero wait for data to be available to read, + * otherwise wait for data to be able to be written. + * @return APR_TIMEUP if we run out of time. + */ +apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, + int for_read); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_SUPPORT_H */ diff --git a/include/apr-linux/apr_tables.h b/include/apr-linux/apr_tables.h new file mode 100644 index 0000000..c2cd741 --- /dev/null +++ b/include/apr-linux/apr_tables.h @@ -0,0 +1,467 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_TABLES_H +#define APR_TABLES_H + +/** + * @file apr_tables.h + * @brief APR Table library + */ + +#include "apr.h" +#include "apr_pools.h" + +#if APR_HAVE_STDARG_H +#include /* for va_list */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_tables Table and Array Functions + * @ingroup APR + * Tables are used to store entirely opaque structures + * for applications, while Arrays are usually used to + * deal with string lists. + * @{ + */ + +/** the table abstract data type */ +typedef struct apr_table_t apr_table_t; + +/** @see apr_array_header_t */ +typedef struct apr_array_header_t apr_array_header_t; + +/** An opaque array type */ +struct apr_array_header_t { + /** The pool the array is allocated out of */ + apr_pool_t *pool; + /** The amount of memory allocated for each element of the array */ + int elt_size; + /** The number of active elements in the array */ + int nelts; + /** The number of elements allocated in the array */ + int nalloc; + /** The elements in the array */ + char *elts; +}; + +/** + * The (opaque) structure for string-content tables. + */ +typedef struct apr_table_entry_t apr_table_entry_t; + +/** The type for each entry in a string-content table */ +struct apr_table_entry_t { + /** The key for the current table entry */ + char *key; /* maybe NULL in future; + * check when iterating thru table_elts + */ + /** The value for the current table entry */ + char *val; + + /** A checksum for the key, for use by the apr_table internals */ + apr_uint32_t key_checksum; +}; + +/** + * Get the elements from a table + * @param t The table + * @return An array containing the contents of the table + */ +APR_DECLARE(const apr_array_header_t *) apr_table_elts(const apr_table_t *t); + +/** + * Determine if the table is empty (either NULL or having no elements) + * @param t The table to check + * @return True if empty, False otherwise + */ +APR_DECLARE(int) apr_is_empty_table(const apr_table_t *t); + +/** + * Determine if the array is empty (either NULL or having no elements) + * @param a The array to check + * @return True if empty, False otherwise + */ +APR_DECLARE(int) apr_is_empty_array(const apr_array_header_t *a); + +/** + * Create an array + * @param p The pool to allocate the memory out of + * @param nelts the number of elements in the initial array + * @param elt_size The size of each element in the array. + * @return The new array + */ +APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, + int nelts, int elt_size); + +/** + * Add a new element to an array (as a first-in, last-out stack) + * @param arr The array to add an element to. + * @return Location for the new element in the array. + * @remark If there are no free spots in the array, then this function will + * allocate new space for the new element. + */ +APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr); + +/** A helper macro for accessing a member of an APR array. + * + * @param ary the array + * @param i the index into the array to return + * @param type the type of the objects stored in the array + * + * @return the item at index i + */ +#define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i]) + +/** A helper macro for pushing elements into an APR array. + * + * @param ary the array + * @param type the type of the objects stored in the array + * + * @return the location where the new object should be placed + */ +#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary))) + +/** + * Remove an element from an array (as a first-in, last-out stack) + * @param arr The array to remove an element from. + * @return Location of the element in the array. + * @remark If there are no elements in the array, NULL is returned. + */ +APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr); + +/** + * Remove all elements from an array. + * @param arr The array to remove all elements from. + * @remark As the underlying storage is allocated from a pool, no + * memory is freed by this operation, but is available for reuse. + */ +APR_DECLARE(void) apr_array_clear(apr_array_header_t *arr); + +/** + * Concatenate two arrays together + * @param dst The destination array, and the one to go first in the combined + * array + * @param src The source array to add to the destination array + */ +APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst, + const apr_array_header_t *src); + +/** + * Copy the entire array + * @param p The pool to allocate the copy of the array out of + * @param arr The array to copy + * @return An exact copy of the array passed in + * @remark The alternate apr_array_copy_hdr copies only the header, and arranges + * for the elements to be copied if (and only if) the code subsequently + * does a push or arraycat. + */ +APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p, + const apr_array_header_t *arr); +/** + * Copy the headers of the array, and arrange for the elements to be copied if + * and only if the code subsequently does a push or arraycat. + * @param p The pool to allocate the copy of the array out of + * @param arr The array to copy + * @return An exact copy of the array passed in + * @remark The alternate apr_array_copy copies the *entire* array. + */ +APR_DECLARE(apr_array_header_t *) apr_array_copy_hdr(apr_pool_t *p, + const apr_array_header_t *arr); + +/** + * Append one array to the end of another, creating a new array in the process. + * @param p The pool to allocate the new array out of + * @param first The array to put first in the new array. + * @param second The array to put second in the new array. + * @return A new array containing the data from the two arrays passed in. +*/ +APR_DECLARE(apr_array_header_t *) apr_array_append(apr_pool_t *p, + const apr_array_header_t *first, + const apr_array_header_t *second); + +/** + * Generates a new string from the apr_pool_t containing the concatenated + * sequence of substrings referenced as elements within the array. The string + * will be empty if all substrings are empty or null, or if there are no + * elements in the array. If sep is non-NUL, it will be inserted between + * elements as a separator. + * @param p The pool to allocate the string out of + * @param arr The array to generate the string from + * @param sep The separator to use + * @return A string containing all of the data in the array. + */ +APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t *p, + const apr_array_header_t *arr, + const char sep); + +/** + * Make a new table + * @param p The pool to allocate the pool out of + * @param nelts The number of elements in the initial table. + * @return The new table. + * @warning This table can only store text data + */ +APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts); + +/** + * Create a new table and copy another table into it + * @param p The pool to allocate the new table out of + * @param t The table to copy + * @return A copy of the table passed in + * @warning The table keys and respective values are not copied + */ +APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, + const apr_table_t *t); + +/** + * Create a new table whose contents are deep copied from the given + * table. A deep copy operation copies all fields, and makes copies + * of dynamically allocated memory pointed to by the fields. + * @param p The pool to allocate the new table out of + * @param t The table to clone + * @return A deep copy of the table passed in + */ +APR_DECLARE(apr_table_t *) apr_table_clone(apr_pool_t *p, + const apr_table_t *t); + +/** + * Delete all of the elements from a table + * @param t The table to clear + */ +APR_DECLARE(void) apr_table_clear(apr_table_t *t); + +/** + * Get the value associated with a given key from the table. After this call, + * The data is still in the table + * @param t The table to search for the key + * @param key The key to search for + * @return The value associated with the key, or NULL if the key does not exist. + */ +APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key); + +/** + * Add a key/value pair to a table, if another element already exists with the + * same key, this will over-write the old data. + * @param t The table to add the data to. + * @param key The key fo use + * @param val The value to add + * @remark When adding data, this function makes a copy of both the key and the + * value. + */ +APR_DECLARE(void) apr_table_set(apr_table_t *t, const char *key, + const char *val); + +/** + * Add a key/value pair to a table, if another element already exists with the + * same key, this will over-write the old data. + * @param t The table to add the data to. + * @param key The key to use + * @param val The value to add + * @warning When adding data, this function does not make a copy of the key or + * the value, so care should be taken to ensure that the values will + * not change after they have been added.. + */ +APR_DECLARE(void) apr_table_setn(apr_table_t *t, const char *key, + const char *val); + +/** + * Remove data from the table + * @param t The table to remove data from + * @param key The key of the data being removed + */ +APR_DECLARE(void) apr_table_unset(apr_table_t *t, const char *key); + +/** + * Add data to a table by merging the value with data that has already been + * stored + * @param t The table to search for the data + * @param key The key to merge data for + * @param val The data to add + * @remark If the key is not found, then this function acts like apr_table_add + */ +APR_DECLARE(void) apr_table_merge(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table by merging the value with data that has already been + * stored + * @param t The table to search for the data + * @param key The key to merge data for + * @param val The data to add + * @remark If the key is not found, then this function acts like apr_table_addn + */ +APR_DECLARE(void) apr_table_mergen(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table, regardless of whether there is another element with the + * same key. + * @param t The table to add to + * @param key The key to use + * @param val The value to add. + * @remark When adding data, this function makes a copy of both the key and the + * value. + */ +APR_DECLARE(void) apr_table_add(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table, regardless of whether there is another element with the + * same key. + * @param t The table to add to + * @param key The key to use + * @param val The value to add. + * @remark When adding data, this function does not make a copy of the key or the + * value, so care should be taken to ensure that the values will not + * change after they have been added.. + */ +APR_DECLARE(void) apr_table_addn(apr_table_t *t, const char *key, + const char *val); + +/** + * Merge two tables into one new table + * @param p The pool to use for the new table + * @param overlay The first table to put in the new table + * @param base The table to add at the end of the new table + * @return A new table containing all of the data from the two passed in + */ +APR_DECLARE(apr_table_t *) apr_table_overlay(apr_pool_t *p, + const apr_table_t *overlay, + const apr_table_t *base); + +/** + * Declaration prototype for the iterator callback function of apr_table_do() + * and apr_table_vdo(). + * @param rec The data passed as the first argument to apr_table_[v]do() + * @param key The key from this iteration of the table + * @param value The value from this iteration of the table + * @remark Iteration continues while this callback function returns non-zero. + * To export the callback function for apr_table_[v]do() it must be declared + * in the _NONSTD convention. + */ +typedef int (apr_table_do_callback_fn_t)(void *rec, const char *key, + const char *value); + +/** + * Iterate over a table running the provided function once for every + * element in the table. The varargs array must be a list of zero or + * more (char *) keys followed by a NULL pointer. If zero keys are + * given, the @param comp function will be invoked for every element + * in the table. Otherwise, the function is invoked only for those + * elements matching the keys specified. + * + * If an invocation of the @param comp function returns zero, + * iteration will continue using the next specified key, if any. + * + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param t The table to iterate over + * @param ... A varargs array of zero or more (char *) keys followed by NULL + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t + */ +APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, ...); + +/** + * Iterate over a table running the provided function once for every + * element in the table. The @param vp varargs paramater must be a + * list of zero or more (char *) keys followed by a NULL pointer. If + * zero keys are given, the @param comp function will be invoked for + * every element in the table. Otherwise, the function is invoked + * only for those elements matching the keys specified. + * + * If an invocation of the @param comp function returns zero, + * iteration will continue using the next specified key, if any. + * + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param t The table to iterate over + * @param vp List of zero or more (char *) keys followed by NULL + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t + */ +APR_DECLARE(int) apr_table_vdo(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, va_list vp); + +/** flag for overlap to use apr_table_setn */ +#define APR_OVERLAP_TABLES_SET (0) +/** flag for overlap to use apr_table_mergen */ +#define APR_OVERLAP_TABLES_MERGE (1) +/** + * For each element in table b, either use setn or mergen to add the data + * to table a. Which method is used is determined by the flags passed in. + * @param a The table to add the data to. + * @param b The table to iterate over, adding its data to table a + * @param flags How to add the table to table a. One of: + * APR_OVERLAP_TABLES_SET Use apr_table_setn + * APR_OVERLAP_TABLES_MERGE Use apr_table_mergen + * @remark This function is highly optimized, and uses less memory and CPU cycles + * than a function that just loops through table b calling other functions. + */ +/** + * Conceptually, apr_table_overlap does this: + * + *
+ *  apr_array_header_t *barr = apr_table_elts(b);
+ *  apr_table_entry_t *belt = (apr_table_entry_t *)barr->elts;
+ *  int i;
+ *
+ *  for (i = 0; i < barr->nelts; ++i) {
+ *      if (flags & APR_OVERLAP_TABLES_MERGE) {
+ *          apr_table_mergen(a, belt[i].key, belt[i].val);
+ *      }
+ *      else {
+ *          apr_table_setn(a, belt[i].key, belt[i].val);
+ *      }
+ *  }
+ * 
+ * + * Except that it is more efficient (less space and cpu-time) especially + * when b has many elements. + * + * Notice the assumptions on the keys and values in b -- they must be + * in an ancestor of a's pool. In practice b and a are usually from + * the same pool. + */ + +APR_DECLARE(void) apr_table_overlap(apr_table_t *a, const apr_table_t *b, + unsigned flags); + +/** + * Eliminate redundant entries in a table by either overwriting + * or merging duplicates + * + * @param t Table. + * @param flags APR_OVERLAP_TABLES_MERGE to merge, or + * APR_OVERLAP_TABLES_SET to overwrite + */ +APR_DECLARE(void) apr_table_compress(apr_table_t *t, unsigned flags); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_TABLES_H */ diff --git a/include/apr-linux/apr_thread_cond.h b/include/apr-linux/apr_thread_cond.h new file mode 100644 index 0000000..199f1de --- /dev/null +++ b/include/apr-linux/apr_thread_cond.h @@ -0,0 +1,139 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_THREAD_COND_H +#define APR_THREAD_COND_H + +/** + * @file apr_thread_cond.h + * @brief APR Condition Variable Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_time.h" +#include "apr_thread_mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS || defined(DOXYGEN) + +/** + * @defgroup apr_thread_cond Condition Variable Routines + * @ingroup APR + * @{ + */ + +/** Opaque structure for thread condition variables */ +typedef struct apr_thread_cond_t apr_thread_cond_t; + +/** + * Note: destroying a condition variable (or likewise, destroying or + * clearing the pool from which a condition variable was allocated) if + * any threads are blocked waiting on it gives undefined results. + */ + +/** + * Create and initialize a condition variable that can be used to signal + * and schedule threads in a single process. + * @param cond the memory address where the newly created condition variable + * will be stored. + * @param pool the pool from which to allocate the condition. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool); + +/** + * Put the active calling thread to sleep until signaled to wake up. Each + * condition variable must be associated with a mutex, and that mutex must + * be locked before calling this function, or the behavior will be + * undefined. As the calling thread is put to sleep, the given mutex + * will be simultaneously released; and as this thread wakes up the lock + * is again simultaneously acquired. + * @param cond the condition variable on which to block. + * @param mutex the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @remark Spurious wakeups may occur. Before and after every call to wait on + * a condition variable, the caller should test whether the condition is already + * met. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex); + +/** + * Put the active calling thread to sleep until signaled to wake up or + * the timeout is reached. Each condition variable must be associated + * with a mutex, and that mutex must be locked before calling this + * function, or the behavior will be undefined. As the calling thread + * is put to sleep, the given mutex will be simultaneously released; + * and as this thread wakes up the lock is again simultaneously acquired. + * @param cond the condition variable on which to block. + * @param mutex the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @param timeout The amount of time in microseconds to wait. This is + * a maximum, not a minimum. If the condition is signaled, we + * will wake up before this time, otherwise the error APR_TIMEUP + * is returned. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout); + +/** + * Signals a single thread, if one exists, that is blocking on the given + * condition variable. That thread is then scheduled to wake up and acquire + * the associated mutex. Although it is not required, if predictable scheduling + * is desired, that mutex must be locked while calling this function. + * @param cond the condition variable on which to produce the signal. + * @remark If no threads are waiting on the condition variable, nothing happens. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond); + +/** + * Signals all threads blocking on the given condition variable. + * Each thread that was signaled is then scheduled to wake up and acquire + * the associated mutex. This will happen in a serialized manner. + * @param cond the condition variable on which to produce the broadcast. + * @remark If no threads are waiting on the condition variable, nothing happens. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond); + +/** + * Destroy the condition variable and free the associated memory. + * @param cond the condition variable to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond); + +/** + * Get the pool used by this thread_cond. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_cond); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_COND_H */ diff --git a/include/apr-linux/apr_thread_mutex.h b/include/apr-linux/apr_thread_mutex.h new file mode 100644 index 0000000..4596dce --- /dev/null +++ b/include/apr-linux/apr_thread_mutex.h @@ -0,0 +1,110 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_THREAD_MUTEX_H +#define APR_THREAD_MUTEX_H + +/** + * @file apr_thread_mutex.h + * @brief APR Thread Mutex Routines + */ + +#include "apr.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS || defined(DOXYGEN) + +/** + * @defgroup apr_thread_mutex Thread Mutex Routines + * @ingroup APR + * @{ + */ + +/** Opaque thread-local mutex structure */ +typedef struct apr_thread_mutex_t apr_thread_mutex_t; + +#define APR_THREAD_MUTEX_DEFAULT 0x0 /**< platform-optimal lock behavior */ +#define APR_THREAD_MUTEX_NESTED 0x1 /**< enable nested (recursive) locks */ +#define APR_THREAD_MUTEX_UNNESTED 0x2 /**< disable nested locks */ + +/* Delayed the include to avoid a circular reference */ +#include "apr_pools.h" + +/** + * Create and initialize a mutex that can be used to synchronize threads. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param flags Or'ed value of: + *
+ *           APR_THREAD_MUTEX_DEFAULT   platform-optimal lock behavior.
+ *           APR_THREAD_MUTEX_NESTED    enable nested (recursive) locks.
+ *           APR_THREAD_MUTEX_UNNESTED  disable nested locks (non-recursive).
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @warning Be cautious in using APR_THREAD_MUTEX_DEFAULT. While this is the + * most optimial mutex based on a given platform's performance charateristics, + * it will behave as either a nested or an unnested lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool); +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex); + +/** + * Get the pool used by this thread_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_mutex); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_MUTEX_H */ diff --git a/include/apr-linux/apr_thread_pool.h b/include/apr-linux/apr_thread_pool.h new file mode 100644 index 0000000..cbf382b --- /dev/null +++ b/include/apr-linux/apr_thread_pool.h @@ -0,0 +1,299 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you 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. + */ + +#ifndef APU_THREAD_POOL_H +#define APU_THREAD_POOL_H + +#include "apu.h" +#include "apr_thread_proc.h" + +/** + * @file apr_thread_pool.h + * @brief APR Thread Pool Library + + * @remarks This library implements a thread pool using apr_thread_t. A thread + * pool is a set of threads that can be created in advance or on demand until a + * maximum number. When a task is scheduled, the thread pool will find an idle + * thread to handle the task. In case all existing threads are busy and the + * number of tasks in the queue is higher than the adjustable threshold, the + * pool will try to create a new thread to serve the task if the maximum number + * has not been reached. Otherwise, the task will be put into a queue based on + * priority, which can be valued from 0 to 255, with higher values being served + * first. If there are tasks with the same priority, the new task might be put at + * the top or at the bottom - it depends on which function is used to put the task. + * + * @remarks There may be the case where the thread pool can use up to the maximum + * number of threads at peak load, but having those threads idle afterwards. A + * maximum number of idle threads can be set so that the extra idling threads will + * be terminated to save system resources. + */ +#if APR_HAS_THREADS + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_TP Thread Pool routines + * @ingroup APR_Util + * @{ + */ + +/** Opaque Thread Pool structure. */ +typedef struct apr_thread_pool apr_thread_pool_t; + +#define APR_THREAD_TASK_PRIORITY_LOWEST 0 +#define APR_THREAD_TASK_PRIORITY_LOW 63 +#define APR_THREAD_TASK_PRIORITY_NORMAL 127 +#define APR_THREAD_TASK_PRIORITY_HIGH 191 +#define APR_THREAD_TASK_PRIORITY_HIGHEST 255 + +/** + * Create a thread pool + * @param me The pointer in which to return the newly created apr_thread_pool + * object, or NULL if thread pool creation fails. + * @param init_threads The number of threads to be created initially, this number + * will also be used as the initial value for the maximum number of idle threads. + * @param max_threads The maximum number of threads that can be created + * @param pool The pool to use + * @return APR_SUCCESS if the thread pool was created successfully. Otherwise, + * the error code. + */ +APU_DECLARE(apr_status_t) apr_thread_pool_create(apr_thread_pool_t **me, + apr_size_t init_threads, + apr_size_t max_threads, + apr_pool_t *pool); + +/** + * Destroy the thread pool and stop all the threads + * @return APR_SUCCESS if all threads are stopped. + */ +APU_DECLARE(apr_status_t) apr_thread_pool_destroy(apr_thread_pool_t *me); + +/** + * Schedule a task to the bottom of the tasks of same priority. + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param priority The priority of the task. + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_push(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner); +/** + * Schedule a task to be run after a delay + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param time Time in microseconds + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_schedule(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_interval_time_t time, + void *owner); + +/** + * Schedule a task to the top of the tasks of same priority. + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param priority The priority of the task. + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_top(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner); + +/** + * Cancel tasks submitted by the owner. If there is any task from the owner that + * is currently running, the function will spin until the task finished. + * @param me The thread pool + * @param owner Owner of the task + * @return APR_SUCCESS if the task has been cancelled successfully + * @note The task function should not be calling cancel, otherwise the function + * may get stuck forever. The function assert if it detect such a case. + */ +APU_DECLARE(apr_status_t) apr_thread_pool_tasks_cancel(apr_thread_pool_t *me, + void *owner); + +/** + * Get the current number of tasks waiting in the queue + * @param me The thread pool + * @return Number of tasks in the queue + */ +APU_DECLARE(apr_size_t) apr_thread_pool_tasks_count(apr_thread_pool_t *me); + +/** + * Get the current number of scheduled tasks waiting in the queue + * @param me The thread pool + * @return Number of scheduled tasks in the queue + */ +APU_DECLARE(apr_size_t) apr_thread_pool_scheduled_tasks_count(apr_thread_pool_t *me); + +/** + * Get the current number of threads + * @param me The thread pool + * @return Total number of threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_threads_count(apr_thread_pool_t *me); + +/** + * Get the current number of busy threads + * @param me The thread pool + * @return Number of busy threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_busy_count(apr_thread_pool_t *me); + +/** + * Get the current number of idle threads + * @param me The thread pool + * @return Number of idle threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_idle_count(apr_thread_pool_t *me); + +/** + * Access function for the maximum number of idle threads. Number of current + * idle threads will be reduced to the new limit. + * @param me The thread pool + * @param cnt The number + * @return The number of threads that were stopped. + */ +APU_DECLARE(apr_size_t) apr_thread_pool_idle_max_set(apr_thread_pool_t *me, + apr_size_t cnt); + +/** + * Get number of tasks that have run + * @param me The thread pool + * @return Number of tasks that have run + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_tasks_run_count(apr_thread_pool_t * me); + +/** + * Get high water mark of the number of tasks waiting to run + * @param me The thread pool + * @return High water mark of tasks waiting to run + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_tasks_high_count(apr_thread_pool_t * me); + +/** + * Get high water mark of the number of threads + * @param me The thread pool + * @return High water mark of threads in thread pool + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_threads_high_count(apr_thread_pool_t * me); + +/** + * Get the number of idle threads that were destroyed after timing out + * @param me The thread pool + * @return Number of idle threads that timed out + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_threads_idle_timeout_count(apr_thread_pool_t * me); + +/** + * Access function for the maximum number of idle threads + * @param me The thread pool + * @return The current maximum number + */ +APU_DECLARE(apr_size_t) apr_thread_pool_idle_max_get(apr_thread_pool_t *me); + +/** + * Access function for the maximum number of threads. + * @param me The thread pool + * @param cnt Number of threads + * @return The original maximum number of threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_thread_max_set(apr_thread_pool_t *me, + apr_size_t cnt); + +/** + * Access function for the maximum wait time (in microseconds) of an + * idling thread that exceeds the maximum number of idling threads. + * A non-zero value allows for the reaping of idling threads to shrink + * over time. Which helps reduce thrashing. + * @param me The thread pool + * @param timeout The number of microseconds an idle thread should wait + * till it reaps itself + * @return The original maximum wait time + */ +APU_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_set(apr_thread_pool_t * me, + apr_interval_time_t timeout); + +/** + * Access function for the maximum wait time (in microseconds) of an + * idling thread that exceeds the maximum number of idling threads + * @param me The thread pool + * @return The current maximum wait time + */ +APU_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_get(apr_thread_pool_t * me); + +/** + * Access function for the maximum number of threads + * @param me The thread pool + * @return The current maximum number + */ +APU_DECLARE(apr_size_t) apr_thread_pool_thread_max_get(apr_thread_pool_t *me); + +/** + * Access function for the threshold of tasks in queue to trigger a new thread. + * @param me The thread pool + * @param cnt The new threshold + * @return The original threshold + */ +APU_DECLARE(apr_size_t) apr_thread_pool_threshold_set(apr_thread_pool_t *me, + apr_size_t val); + +/** + * Access function for the threshold of tasks in queue to trigger a new thread. + * @param me The thread pool + * @return The current threshold + */ +APU_DECLARE(apr_size_t) apr_thread_pool_threshold_get(apr_thread_pool_t * me); + +/** + * Get owner of the task currently been executed by the thread. + * @param thd The thread is executing a task + * @param owner Pointer to receive owner of the task. + * @return APR_SUCCESS if the owner is retrieved successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_task_owner_get(apr_thread_t *thd, + void **owner); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_THREADS */ +#endif /* !APR_THREAD_POOL_H */ diff --git a/include/apr-linux/apr_thread_proc.h b/include/apr-linux/apr_thread_proc.h new file mode 100644 index 0000000..4bcc4ee --- /dev/null +++ b/include/apr-linux/apr_thread_proc.h @@ -0,0 +1,824 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_THREAD_PROC_H +#define APR_THREAD_PROC_H + +/** + * @file apr_thread_proc.h + * @brief APR Thread and Process Library + */ + +#include "apr.h" +#include "apr_file_io.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#if APR_HAVE_STRUCT_RLIMIT +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_thread_proc Threads and Process Functions + * @ingroup APR + * @{ + */ + +typedef enum { + APR_SHELLCMD, /**< use the shell to invoke the program */ + APR_PROGRAM, /**< invoke the program directly, no copied env */ + APR_PROGRAM_ENV, /**< invoke the program, replicating our environment */ + APR_PROGRAM_PATH, /**< find program on PATH, use our environment */ + APR_SHELLCMD_ENV /**< use the shell to invoke the program, + * replicating our environment + */ +} apr_cmdtype_e; + +typedef enum { + APR_WAIT, /**< wait for the specified process to finish */ + APR_NOWAIT /**< do not wait -- just see if it has finished */ +} apr_wait_how_e; + +/* I am specifically calling out the values so that the macros below make + * more sense. Yes, I know I don't need to, but I am hoping this makes what + * I am doing more clear. If you want to add more reasons to exit, continue + * to use bitmasks. + */ +typedef enum { + APR_PROC_EXIT = 1, /**< process exited normally */ + APR_PROC_SIGNAL = 2, /**< process exited due to a signal */ + APR_PROC_SIGNAL_CORE = 4 /**< process exited and dumped a core file */ +} apr_exit_why_e; + +/** did we exit the process */ +#define APR_PROC_CHECK_EXIT(x) (x & APR_PROC_EXIT) +/** did we get a signal */ +#define APR_PROC_CHECK_SIGNALED(x) (x & APR_PROC_SIGNAL) +/** did we get core */ +#define APR_PROC_CHECK_CORE_DUMP(x) (x & APR_PROC_SIGNAL_CORE) + +/** @see apr_procattr_io_set */ +#define APR_NO_PIPE 0 +/** @see apr_procattr_io_set and apr_file_pipe_create_ex */ +#define APR_FULL_BLOCK 1 +/** @see apr_procattr_io_set and apr_file_pipe_create_ex */ +#define APR_FULL_NONBLOCK 2 +/** @see apr_procattr_io_set */ +#define APR_PARENT_BLOCK 3 +/** @see apr_procattr_io_set */ +#define APR_CHILD_BLOCK 4 +/** @see apr_procattr_io_set */ +#define APR_NO_FILE 8 + +/** @see apr_file_pipe_create_ex */ +#define APR_READ_BLOCK 3 +/** @see apr_file_pipe_create_ex */ +#define APR_WRITE_BLOCK 4 + +/** @see apr_procattr_io_set + * @note Win32 only effective with version 1.2.12, portably introduced in 1.3.0 + */ +#define APR_NO_FILE 8 + +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_CPU 0 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_MEM 1 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_NPROC 2 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_NOFILE 3 + +/** + * @defgroup APR_OC Other Child Flags + * @{ + */ +#define APR_OC_REASON_DEATH 0 /**< child has died, caller must call + * unregister still */ +#define APR_OC_REASON_UNWRITABLE 1 /**< write_fd is unwritable */ +#define APR_OC_REASON_RESTART 2 /**< a restart is occuring, perform + * any necessary cleanup (including + * sending a special signal to child) + */ +#define APR_OC_REASON_UNREGISTER 3 /**< unregister has been called, do + * whatever is necessary (including + * kill the child) */ +#define APR_OC_REASON_LOST 4 /**< somehow the child exited without + * us knowing ... buggy os? */ +#define APR_OC_REASON_RUNNING 5 /**< a health check is occuring, + * for most maintainence functions + * this is a no-op. + */ +/** @} */ + +/** The APR process type */ +typedef struct apr_proc_t { + /** The process ID */ + pid_t pid; + /** Parent's side of pipe to child's stdin */ + apr_file_t *in; + /** Parent's side of pipe to child's stdout */ + apr_file_t *out; + /** Parent's side of pipe to child's stdouterr */ + apr_file_t *err; +#if APR_HAS_PROC_INVOKED || defined(DOXYGEN) + /** Diagnositics/debugging string of the command invoked for + * this process [only present if APR_HAS_PROC_INVOKED is true] + * @remark Only enabled on Win32 by default. + * @bug This should either always or never be present in release + * builds - since it breaks binary compatibility. We may enable + * it always in APR 1.0 yet leave it undefined in most cases. + */ + char *invoked; +#endif +#if defined(WIN32) || defined(DOXYGEN) + /** (Win32 only) Creator's handle granting access to the process + * @remark This handle is closed and reset to NULL in every case + * corresponding to a waitpid() on Unix which returns the exit status. + * Therefore Win32 correspond's to Unix's zombie reaping characteristics + * and avoids potential handle leaks. + */ + HANDLE hproc; +#endif +} apr_proc_t; + +/** + * The prototype for APR child errfn functions. (See the description + * of apr_procattr_child_errfn_set() for more information.) + * It is passed the following parameters: + * @param pool Pool associated with the apr_proc_t. If your child + * error function needs user data, associate it with this + * pool. + * @param err APR error code describing the error + * @param description Text description of type of processing which failed + */ +typedef void (apr_child_errfn_t)(apr_pool_t *proc, apr_status_t err, + const char *description); + +/** Opaque Thread structure. */ +typedef struct apr_thread_t apr_thread_t; + +/** Opaque Thread attributes structure. */ +typedef struct apr_threadattr_t apr_threadattr_t; + +/** Opaque Process attributes structure. */ +typedef struct apr_procattr_t apr_procattr_t; + +/** Opaque control variable for one-time atomic variables. */ +typedef struct apr_thread_once_t apr_thread_once_t; + +/** Opaque thread private address space. */ +typedef struct apr_threadkey_t apr_threadkey_t; + +/** Opaque record of child process. */ +typedef struct apr_other_child_rec_t apr_other_child_rec_t; + +/** + * The prototype for any APR thread worker functions. + */ +typedef void *(APR_THREAD_FUNC *apr_thread_start_t)(apr_thread_t*, void*); + +typedef enum { + APR_KILL_NEVER, /**< process is never sent any signals */ + APR_KILL_ALWAYS, /**< process is sent SIGKILL on apr_pool_t cleanup */ + APR_KILL_AFTER_TIMEOUT, /**< SIGTERM, wait 3 seconds, SIGKILL */ + APR_JUST_WAIT, /**< wait forever for the process to complete */ + APR_KILL_ONLY_ONCE /**< send SIGTERM and then wait */ +} apr_kill_conditions_e; + +/* Thread Function definitions */ + +#if APR_HAS_THREADS + +/** + * Create and initialize a new threadattr variable + * @param new_attr The newly created threadattr. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new_attr, + apr_pool_t *cont); + +/** + * Set if newly created threads should be created in detached state. + * @param attr The threadattr to affect + * @param on Non-zero if detached threads should be created. + */ +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, + apr_int32_t on); + +/** + * Get the detach state for this threadattr. + * @param attr The threadattr to reference + * @return APR_DETACH if threads are to be detached, or APR_NOTDETACH + * if threads are to be joinable. + */ +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr); + +/** + * Set the stack size of newly created threads. + * @param attr The threadattr to affect + * @param stacksize The stack size in bytes + */ +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize); + +/** + * Set the stack guard area size of newly created threads. + * @param attr The threadattr to affect + * @param guardsize The stack guard area size in bytes + * @note Thread library implementations commonly use a "guard area" + * after each thread's stack which is not readable or writable such that + * stack overflows cause a segfault; this consumes e.g. 4K of memory + * and increases memory management overhead. Setting the guard area + * size to zero hence trades off reliable behaviour on stack overflow + * for performance. */ +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t guardsize); + +/** + * Create a new thread of execution + * @param new_thread The newly created thread handle. + * @param attr The threadattr to use to determine how to create the thread + * @param func The function to start the new thread in + * @param data Any data to be passed to the starting function + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new_thread, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, apr_pool_t *cont); + +/** + * stop the current thread + * @param thd The thread to stop + * @param retval The return value to pass back to any thread that cares + */ +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, + apr_status_t retval); + +/** + * block until the desired thread stops executing. + * @param retval The return value from the dead thread. + * @param thd The thread to join + */ +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, + apr_thread_t *thd); + +/** + * force the current thread to yield the processor + */ +APR_DECLARE(void) apr_thread_yield(void); + +/** + * Initialize the control variable for apr_thread_once. If this isn't + * called, apr_initialize won't work. + * @param control The control variable to initialize + * @param p The pool to allocate data from. + */ +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p); + +/** + * Run the specified function one time, regardless of how many threads + * call it. + * @param control The control variable. The same variable should + * be passed in each time the function is tried to be + * called. This is how the underlying functions determine + * if the function has ever been called before. + * @param func The function to call. + */ +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)); + +/** + * detach a thread + * @param thd The thread to detach + */ +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd); + +/** + * Return the pool associated with the current thread. + * @param data The user data associated with the thread. + * @param key The key to associate with the data + * @param thread The currently open thread. + */ +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, + apr_thread_t *thread); + +/** + * Return the pool associated with the current thread. + * @param data The user data to associate with the thread. + * @param key The key to use for associating the data with the thread + * @param cleanup The cleanup routine to use when the thread is destroyed. + * @param thread The currently open thread. + */ +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread); + +/** + * Create and initialize a new thread private address space + * @param key The thread private handle. + * @param dest The destructor to use when freeing the private memory. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), + apr_pool_t *cont); + +/** + * Get a pointer to the thread private memory + * @param new_mem The data stored in private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new_mem, + apr_threadkey_t *key); + +/** + * Set the data to be stored in thread private memory + * @param priv The data to be stored in private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, + apr_threadkey_t *key); + +/** + * Free the thread private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key); + +/** + * Return the pool associated with the current threadkey. + * @param data The user data associated with the threadkey. + * @param key The key associated with the data + * @param threadkey The currently open threadkey. + */ +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey); + +/** + * Return the pool associated with the current threadkey. + * @param data The data to set. + * @param key The key to associate with the data. + * @param cleanup The cleanup routine to use when the file is destroyed. + * @param threadkey The currently open threadkey. + */ +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_threadkey_t *threadkey); + +#endif + +/** + * Create and initialize a new procattr variable + * @param new_attr The newly created procattr. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new_attr, + apr_pool_t *cont); + +/** + * Determine if any of stdin, stdout, or stderr should be linked to pipes + * when starting a child process. + * @param attr The procattr we care about. + * @param in Should stdin be a pipe back to the parent? + * @param out Should stdout be a pipe back to the parent? + * @param err Should stderr be a pipe back to the parent? + * @note If APR_NO_PIPE, there will be no special channel, the child + * inherits the parent's corresponding stdio stream. If APR_NO_FILE is + * specified, that corresponding stream is closed in the child (and will + * be INVALID_HANDLE_VALUE when inspected on Win32). This can have ugly + * side effects, as the next file opened in the child on Unix will fall + * into the stdio stream fd slot! + */ +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, apr_int32_t out, + apr_int32_t err); + +/** + * Set the child_in and/or parent_in values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_in apr_file_t value to use as child_in. Must be a valid file. + * @param parent_in apr_file_t value to use as parent_in. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. You can save some + * extra function calls by not creating your own pipe since this + * creates one in the process space for you. + * @bug Note that calling this function with two NULL files on some platforms + * creates an APR_FULL_BLOCK pipe, but this behavior is neither portable nor + * is it supported. @see apr_procattr_io_set instead for simple pipes. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(struct apr_procattr_t *attr, + apr_file_t *child_in, + apr_file_t *parent_in); + +/** + * Set the child_out and parent_out values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_out apr_file_t value to use as child_out. Must be a valid file. + * @param parent_out apr_file_t value to use as parent_out. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + * @bug Note that calling this function with two NULL files on some platforms + * creates an APR_FULL_BLOCK pipe, but this behavior is neither portable nor + * is it supported. @see apr_procattr_io_set instead for simple pipes. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(struct apr_procattr_t *attr, + apr_file_t *child_out, + apr_file_t *parent_out); + +/** + * Set the child_err and parent_err values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_err apr_file_t value to use as child_err. Must be a valid file. + * @param parent_err apr_file_t value to use as parent_err. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + * @bug Note that calling this function with two NULL files on some platforms + * creates an APR_FULL_BLOCK pipe, but this behavior is neither portable nor + * is it supported. @see apr_procattr_io_set instead for simple pipes. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(struct apr_procattr_t *attr, + apr_file_t *child_err, + apr_file_t *parent_err); + +/** + * Set which directory the child process should start executing in. + * @param attr The procattr we care about. + * @param dir Which dir to start in. By default, this is the same dir as + * the parent currently resides in, when the createprocess call + * is made. + */ +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir); + +/** + * Set what type of command the child process will call. + * @param attr The procattr we care about. + * @param cmd The type of command. One of: + *
+ *            APR_SHELLCMD     --  Anything that the shell can handle
+ *            APR_PROGRAM      --  Executable program   (default) 
+ *            APR_PROGRAM_ENV  --  Executable program, copy environment
+ *            APR_PROGRAM_PATH --  Executable program on PATH, copy env
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd); + +/** + * Determine if the child should start in detached state. + * @param attr The procattr we care about. + * @param detach Should the child start in detached state? Default is no. + */ +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + apr_int32_t detach); + +#if APR_HAVE_STRUCT_RLIMIT +/** + * Set the Resource Utilization limits when starting a new process. + * @param attr The procattr we care about. + * @param what Which limit to set, one of: + *
+ *                 APR_LIMIT_CPU
+ *                 APR_LIMIT_MEM
+ *                 APR_LIMIT_NPROC
+ *                 APR_LIMIT_NOFILE
+ * 
+ * @param limit Value to set the limit to. + */ +APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, + apr_int32_t what, + struct rlimit *limit); +#endif + +/** + * Specify an error function to be called in the child process if APR + * encounters an error in the child prior to running the specified program. + * @param attr The procattr describing the child process to be created. + * @param errfn The function to call in the child process. + * @remark At the present time, it will only be called from apr_proc_create() + * on platforms where fork() is used. It will never be called on other + * platforms, on those platforms apr_proc_create() will return the error + * in the parent process rather than invoke the callback in the now-forked + * child process. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn); + +/** + * Specify that apr_proc_create() should do whatever it can to report + * failures to the caller of apr_proc_create(), rather than find out in + * the child. + * @param attr The procattr describing the child process to be created. + * @param chk Flag to indicate whether or not extra work should be done + * to try to report failures to the caller. + * @remark This flag only affects apr_proc_create() on platforms where + * fork() is used. This leads to extra overhead in the calling + * process, but that may help the application handle such + * errors more gracefully. + */ +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk); + +/** + * Determine if the child should start in its own address space or using the + * current one from its parent + * @param attr The procattr we care about. + * @param addrspace Should the child start in its own address space? Default + * is no on NetWare and yes on other platforms. + */ +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace); + +/** + * Set the username used for running process + * @param attr The procattr we care about. + * @param username The username used + * @param password User password if needed. Password is needed on WIN32 + * or any other platform having + * APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set. + */ +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password); + +/** + * Set the group used for running process + * @param attr The procattr we care about. + * @param groupname The group name used + */ +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname); + + +#if APR_HAS_FORK +/** + * This is currently the only non-portable call in APR. This executes + * a standard unix fork. + * @param proc The resulting process handle. + * @param cont The pool to use. + * @remark returns APR_INCHILD for the child, and APR_INPARENT for the parent + * or an error. + */ +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *cont); +#endif + +/** + * Create a new process and execute a new program within that process. + * @param new_proc The resulting process handle. + * @param progname The program to run + * @param args the arguments to pass to the new program. The first + * one should be the program name. + * @param env The new environment table for the new process. This + * should be a list of NULL-terminated strings. This argument + * is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and + * APR_SHELLCMD_ENV types of commands. + * @param attr the procattr we should use to determine how to create the new + * process + * @param pool The pool to use. + * @note This function returns without waiting for the new process to terminate; + * use apr_proc_wait for that. + */ +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new_proc, + const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool); + +/** + * Wait for a child process to die + * @param proc The process handle that corresponds to the desired child process + * @param exitcode The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * @param exitwhy Why the child died, the bitwise or of: + *
+ *            APR_PROC_EXIT         -- process terminated normally
+ *            APR_PROC_SIGNAL       -- process was killed by a signal
+ *            APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
+ *                                     generated a core dump.
+ * 
+ * @param waithow How should we wait. One of: + *
+ *            APR_WAIT   -- block until the child process dies.
+ *            APR_NOWAIT -- return immediately regardless of if the 
+ *                          child is dead or not.
+ * 
+ * @remark The childs status is in the return code to this process. It is one of: + *
+ *            APR_CHILD_DONE     -- child is no longer running.
+ *            APR_CHILD_NOTDONE  -- child is still running.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow); + +/** + * Wait for any current child process to die and return information + * about that child. + * @param proc Pointer to NULL on entry, will be filled out with child's + * information + * @param exitcode The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * @param exitwhy Why the child died, the bitwise or of: + *
+ *            APR_PROC_EXIT         -- process terminated normally
+ *            APR_PROC_SIGNAL       -- process was killed by a signal
+ *            APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
+ *                                     generated a core dump.
+ * 
+ * @param waithow How should we wait. One of: + *
+ *            APR_WAIT   -- block until the child process dies.
+ *            APR_NOWAIT -- return immediately regardless of if the 
+ *                          child is dead or not.
+ * 
+ * @param p Pool to allocate child information out of. + * @bug Passing proc as a *proc rather than **proc was an odd choice + * for some platforms... this should be revisited in 1.0 + */ +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p); + +#define APR_PROC_DETACH_FOREGROUND 0 /**< Do not detach */ +#define APR_PROC_DETACH_DAEMONIZE 1 /**< Detach */ + +/** + * Detach the process from the controlling terminal. + * @param daemonize set to non-zero if the process should daemonize + * and become a background process, else it will + * stay in the foreground. + */ +APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize); + +/** + * Register an other_child -- a child associated to its registered + * maintence callback. This callback is invoked when the process + * dies, is disconnected or disappears. + * @param proc The child process to register. + * @param maintenance maintenance is a function that is invoked with a + * reason and the data pointer passed here. + * @param data Opaque context data passed to the maintenance function. + * @param write_fd An fd that is probed for writing. If it is ever unwritable + * then the maintenance is invoked with reason + * OC_REASON_UNWRITABLE. + * @param p The pool to use for allocating memory. + * @bug write_fd duplicates the proc->out stream, it's really redundant + * and should be replaced in the APR 1.0 API with a bitflag of which + * proc->in/out/err handles should be health checked. + * @bug no platform currently tests the pipes health. + */ +APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc, + void (*maintenance) (int reason, + void *, + int status), + void *data, apr_file_t *write_fd, + apr_pool_t *p); + +/** + * Stop watching the specified other child. + * @param data The data to pass to the maintenance function. This is + * used to find the process to unregister. + * @warning Since this can be called by a maintenance function while we're + * scanning the other_children list, all scanners should protect + * themself by loading ocr->next before calling any maintenance + * function. + */ +APR_DECLARE(void) apr_proc_other_child_unregister(void *data); + +/** + * Notify the maintenance callback of a registered other child process + * that application has detected an event, such as death. + * @param proc The process to check + * @param reason The reason code to pass to the maintenance function + * @param status The status to pass to the maintenance function + * @remark An example of code using this behavior; + *
+ * rv = apr_proc_wait_all_procs(&proc, &exitcode, &status, APR_WAIT, p);
+ * if (APR_STATUS_IS_CHILD_DONE(rv)) {
+ * #if APR_HAS_OTHER_CHILD
+ *     if (apr_proc_other_child_alert(&proc, APR_OC_REASON_DEATH, status)
+ *             == APR_SUCCESS) {
+ *         ;  (already handled)
+ *     }
+ *     else
+ * #endif
+ *         [... handling non-otherchild processes death ...]
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, + int reason, + int status); + +/** + * Test one specific other child processes and invoke the maintenance callback + * with the appropriate reason code, if still running, or the appropriate reason + * code if the process is no longer healthy. + * @param ocr The registered other child + * @param reason The reason code (e.g. APR_OC_REASON_RESTART) if still running + */ +APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, + int reason); + +/** + * Test all registered other child processes and invoke the maintenance callback + * with the appropriate reason code, if still running, or the appropriate reason + * code if the process is no longer healthy. + * @param reason The reason code (e.g. APR_OC_REASON_RESTART) to running processes + */ +APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason); + +/** + * Terminate a process. + * @param proc The process to terminate. + * @param sig How to kill the process. + */ +APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int sig); + +/** + * Register a process to be killed when a pool dies. + * @param a The pool to use to define the processes lifetime + * @param proc The process to register + * @param how How to kill the process, one of: + *
+ *         APR_KILL_NEVER         -- process is never sent any signals
+ *         APR_KILL_ALWAYS        -- process is sent SIGKILL on apr_pool_t cleanup
+ *         APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL
+ *         APR_JUST_WAIT          -- wait forever for the process to complete
+ *         APR_KILL_ONLY_ONCE     -- send SIGTERM and then wait
+ * 
+ */ +APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *a, apr_proc_t *proc, + apr_kill_conditions_e how); + +#if APR_HAS_THREADS + +#if (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) && !defined(OS2) + +/** + * Setup the process for a single thread to be used for all signal handling. + * @warning This must be called before any threads are created + */ +APR_DECLARE(apr_status_t) apr_setup_signal_thread(void); + +/** + * Make the current thread listen for signals. This thread will loop + * forever, calling a provided function whenever it receives a signal. That + * functions should return 1 if the signal has been handled, 0 otherwise. + * @param signal_handler The function to call when a signal is received + * apr_status_t apr_signal_thread((int)(*signal_handler)(int signum)) + */ +APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)); + +#endif /* (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) && !defined(OS2) */ + +/** + * Get the child-pool used by the thread from the thread info. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_PROC_H */ + diff --git a/include/apr-linux/apr_thread_rwlock.h b/include/apr-linux/apr_thread_rwlock.h new file mode 100644 index 0000000..5090959 --- /dev/null +++ b/include/apr-linux/apr_thread_rwlock.h @@ -0,0 +1,180 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_THREAD_RWLOCK_H +#define APR_THREAD_RWLOCK_H + +/** + * @file apr_thread_rwlock.h + * @brief APR Reader/Writer Lock Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS + +/** + * @defgroup apr_thread_rwlock Reader/Writer Lock Routines + * @ingroup APR + * @{ + */ + +/** Opaque read-write thread-safe lock. */ +typedef struct apr_thread_rwlock_t apr_thread_rwlock_t; + +/** + * Note: The following operations have undefined results: unlocking a + * read-write lock which is not locked in the calling thread; write + * locking a read-write lock which is already locked by the calling + * thread; destroying a read-write lock more than once; clearing or + * destroying the pool from which a locked read-write lock is + * allocated. + */ + +/** + * Create and initialize a read-write lock that can be used to synchronize + * threads. + * @param rwlock the memory address where the newly created readwrite lock + * will be stored. + * @param pool the pool from which to allocate the mutex. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool); +/** + * Acquire a shared-read lock on the given read-write lock. This will allow + * multiple threads to enter the same critical section while they have acquired + * the read lock. + * @param rwlock the read-write lock on which to acquire the shared read. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock); + +/** + * Attempt to acquire the shared-read lock on the given read-write lock. This + * is the same as apr_thread_rwlock_rdlock(), only that the function fails + * if there is another thread holding the write lock, or if there are any + * write threads blocking on the lock. If the function fails for this case, + * APR_EBUSY will be returned. Note: it is important that the + * APR_STATUS_IS_EBUSY(s) macro be used to determine if the return value was + * APR_EBUSY, for portability reasons. + * @param rwlock the rwlock on which to attempt the shared read. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock); + +/** + * Acquire an exclusive-write lock on the given read-write lock. This will + * allow only one single thread to enter the critical sections. If there + * are any threads currently holding the read-lock, this thread is put to + * sleep until it can have exclusive access to the lock. + * @param rwlock the read-write lock on which to acquire the exclusive write. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock); + +/** + * Attempt to acquire the exclusive-write lock on the given read-write lock. + * This is the same as apr_thread_rwlock_wrlock(), only that the function fails + * if there is any other thread holding the lock (for reading or writing), + * in which case the function will return APR_EBUSY. Note: it is important + * that the APR_STATUS_IS_EBUSY(s) macro be used to determine if the return + * value was APR_EBUSY, for portability reasons. + * @param rwlock the rwlock on which to attempt the exclusive write. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock); + +/** + * Release either the read or write lock currently held by the calling thread + * associated with the given read-write lock. + * @param rwlock the read-write lock to be released (unlocked). + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock); + +/** + * Destroy the read-write lock and free the associated memory. + * @param rwlock the rwlock to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock); + +/** + * Get the pool used by this thread_rwlock. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_rwlock); + +#endif /* APR_HAS_THREADS */ + +/** Notify event data, events count less than 32. */ +typedef apr_uint32_t apr_event_t; + +/** System default notify event */ +#define DRVS_MSG_BADHANDLE 0x40000000 /**< Driver handle error */ +#define DRVS_MSG_TIMEOUT 0x80000000 /**< Driver accept event timeout */ + +/** + * Opaque thread-safe notify events group. Only apply in multi producer and single + * customer pattern. + */ +typedef struct apr_thread_event_t apr_thread_event_t; + +/** + * Create and initialize a thread event that can be used to synchronize + * threads. + * @param ev the memory address where the newly created thread event + * will be stored. + * @param pool the pool from which to allocate the thread event. + */ +APR_DECLARE(apr_status_t) apr_thread_event_create(apr_thread_event_t **ev, + apr_pool_t *pool); + +/** + * Destroy the thread event and free the associated memory. + * @param ev the thread event to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_event_destroy(apr_thread_event_t *ev); + +/** + * Put the active calling thread to sleep until thread event to wake up or + * the timeout is reached. Each event variable must be associated with event + * mask. + * @param ev the thread event variable on which to block. + * @param mask the thread events mask that can be singled in this function, + * @param timeout The amount of time in microseconds to wait. This is a maximum, + * not a minimum. If the event is signaled, we will wake up before this + * time, otherwise the error DRVS_MSG_TIMEOUT is returned. + */ +APR_DECLARE(apr_event_t) apr_thread_event_read(apr_thread_event_t *ev, + apr_event_t mask, + apr_uint32_t timeout); + +/** + * Notify the thread which is blocking on the thread events. + * That thread is then scheduled to wake up. + * @param ev the thread event handle on which to produce the events. + */ +APR_DECLARE(apr_status_t) apr_thread_event_write(apr_thread_event_t *ev, + apr_event_t event); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_RWLOCK_H */ diff --git a/include/apr-linux/apr_time.h b/include/apr-linux/apr_time.h new file mode 100644 index 0000000..253aa72 --- /dev/null +++ b/include/apr-linux/apr_time.h @@ -0,0 +1,232 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_TIME_H +#define APR_TIME_H + +/** + * @file apr_time.h + * @brief APR Time Library + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_time Time Routines + * @ingroup APR + * @{ + */ + +/** month names */ +APR_DECLARE_DATA extern const char apr_month_snames[12][4]; +/** day names */ +APR_DECLARE_DATA extern const char apr_day_snames[7][4]; + + +/** number of microseconds since 00:00:00 january 1, 1970 UTC */ +typedef apr_int64_t apr_time_t; + + +/** mechanism to properly type apr_time_t literals */ +#define APR_TIME_C(val) APR_INT64_C(val) + +/** mechanism to properly print apr_time_t values */ +#define APR_TIME_T_FMT APR_INT64_T_FMT + +/** intervals for I/O timeouts, in microseconds */ +typedef apr_int64_t apr_interval_time_t; +/** short interval for I/O timeouts, in microseconds */ +typedef apr_int32_t apr_short_interval_time_t; + +/** number of microseconds per second */ +#define APR_USEC_PER_SEC APR_TIME_C(1000000) + +/** @return apr_time_t as a second */ +#define apr_time_sec(time) ((time) / APR_USEC_PER_SEC) + +/** @return apr_time_t as a usec */ +#define apr_time_usec(time) ((time) % APR_USEC_PER_SEC) + +/** @return apr_time_t as a msec */ +#define apr_time_msec(time) (((time) / 1000) % 1000) + +/** @return apr_time_t as a msec */ +#define apr_time_as_msec(time) ((time) / 1000) + +/** @return a second as an apr_time_t */ +#define apr_time_from_sec(sec) ((apr_time_t)(sec) * APR_USEC_PER_SEC) + +/** @return a second and usec combination as an apr_time_t */ +#define apr_time_make(sec, usec) ((apr_time_t)(sec) * APR_USEC_PER_SEC \ + + (apr_time_t)(usec)) + +/** + * @return the current time + */ +APR_DECLARE(apr_time_t) apr_time_now(void); + +/** @see apr_time_exp_t */ +typedef struct apr_time_exp_t apr_time_exp_t; + +/** + * a structure similar to ANSI struct tm with the following differences: + * - tm_usec isn't an ANSI field + * - tm_gmtoff isn't an ANSI field (it's a bsdism) + */ +struct apr_time_exp_t { + /** microseconds past tm_sec */ + apr_int32_t tm_usec; + /** (0-61) seconds past tm_min */ + apr_int32_t tm_sec; + /** (0-59) minutes past tm_hour */ + apr_int32_t tm_min; + /** (0-23) hours past midnight */ + apr_int32_t tm_hour; + /** (1-31) day of the month */ + apr_int32_t tm_mday; + /** (0-11) month of the year */ + apr_int32_t tm_mon; + /** year since 1900 */ + apr_int32_t tm_year; + /** (0-6) days since sunday */ + apr_int32_t tm_wday; + /** (0-365) days since jan 1 */ + apr_int32_t tm_yday; + /** daylight saving time */ + apr_int32_t tm_isdst; + /** seconds east of UTC */ + apr_int32_t tm_gmtoff; +}; + +/** + * convert an ansi time_t to an apr_time_t + * @param result the resulting apr_time_t + * @param input the time_t to convert + */ +APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, + time_t input); + +/** + * convert a time to its human readable components using an offset + * from GMT + * @param result the exploded time + * @param input the time to explode + * @param offs the number of seconds offset to apply + */ +APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, + apr_time_t input, + apr_int32_t offs); + +/** + * convert a time to its human readable components in GMT timezone + * @param result the exploded time + * @param input the time to explode + */ +APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, + apr_time_t input); + +/** + * convert a time to its human readable components in local timezone + * @param result the exploded time + * @param input the time to explode + */ +APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, + apr_time_t input); + +/** + * Convert time value from human readable format to a numeric apr_time_t + * e.g. elapsed usec since epoch + * @param result the resulting imploded time + * @param input the input exploded time + */ +APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *result, + apr_time_exp_t *input); + +/** + * Convert time value from human readable format to a numeric apr_time_t that + * always represents GMT + * @param result the resulting imploded time + * @param input the input exploded time + */ +APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *result, + apr_time_exp_t *input); + +/** + * Sleep for the specified number of micro-seconds. + * @param t desired amount of time to sleep. + * @warning May sleep for longer than the specified time. + */ +APR_DECLARE(void) apr_sleep(apr_interval_time_t t); + +/** length of a RFC822 Date */ +#define APR_RFC822_DATE_LEN (30) +/** + * apr_rfc822_date formats dates in the RFC822 + * format in an efficient manner. It is a fixed length + * format which requires the indicated amount of storage, + * including the trailing NUL terminator. + * @param date_str String to write to. + * @param t the time to convert + */ +APR_DECLARE(apr_status_t) apr_rfc822_date(char *date_str, apr_time_t t); + +/** length of a CTIME date */ +#define APR_CTIME_LEN (25) +/** + * apr_ctime formats dates in the ctime() format + * in an efficient manner. it is a fixed length format + * and requires the indicated amount of storage including + * the trailing NUL terminator. + * Unlike ANSI/ISO C ctime(), apr_ctime() does not include + * a \n at the end of the string. + * @param date_str String to write to. + * @param t the time to convert + */ +APR_DECLARE(apr_status_t) apr_ctime(char *date_str, apr_time_t t); + +/** + * formats the exploded time according to the format specified + * @param s string to write to + * @param retsize The length of the returned string + * @param max The maximum length of the string + * @param format The format for the time string + * @param tm The time to convert + */ +APR_DECLARE(apr_status_t) apr_strftime(char *s, apr_size_t *retsize, + apr_size_t max, const char *format, + apr_time_exp_t *tm); + +/** + * Improve the clock resolution for the lifetime of the given pool. + * Generally this is only desireable on benchmarking and other very + * time-sensitive applications, and has no impact on most platforms. + * @param p The pool to associate the finer clock resolution + */ +APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_TIME_H */ diff --git a/include/apr-linux/apr_uri.h b/include/apr-linux/apr_uri.h new file mode 100644 index 0000000..99db4d9 --- /dev/null +++ b/include/apr-linux/apr_uri.h @@ -0,0 +1,178 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* + * apr_uri.h: External Interface of apr_uri.c + */ + +/** + * @file apr_uri.h + * @brief APR-UTIL URI Routines + */ + +#ifndef APR_URI_H +#define APR_URI_H + +#include "apu.h" + +#include "apr_network_io.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_URI URI + * @ingroup APR_Util + * @{ + */ + +#define APR_URI_FTP_DEFAULT_PORT 21 /**< default FTP port */ +#define APR_URI_SSH_DEFAULT_PORT 22 /**< default SSH port */ +#define APR_URI_TELNET_DEFAULT_PORT 23 /**< default telnet port */ +#define APR_URI_GOPHER_DEFAULT_PORT 70 /**< default Gopher port */ +#define APR_URI_HTTP_DEFAULT_PORT 80 /**< default HTTP port */ +#define APR_URI_POP_DEFAULT_PORT 110 /**< default POP port */ +#define APR_URI_NNTP_DEFAULT_PORT 119 /**< default NNTP port */ +#define APR_URI_IMAP_DEFAULT_PORT 143 /**< default IMAP port */ +#define APR_URI_PROSPERO_DEFAULT_PORT 191 /**< default Prospero port */ +#define APR_URI_WAIS_DEFAULT_PORT 210 /**< default WAIS port */ +#define APR_URI_LDAP_DEFAULT_PORT 389 /**< default LDAP port */ +#define APR_URI_HTTPS_DEFAULT_PORT 443 /**< default HTTPS port */ +#define APR_URI_RTSP_DEFAULT_PORT 554 /**< default RTSP port */ +#define APR_URI_SNEWS_DEFAULT_PORT 563 /**< default SNEWS port */ +#define APR_URI_ACAP_DEFAULT_PORT 674 /**< default ACAP port */ +#define APR_URI_NFS_DEFAULT_PORT 2049 /**< default NFS port */ +#define APR_URI_TIP_DEFAULT_PORT 3372 /**< default TIP port */ +#define APR_URI_SIP_DEFAULT_PORT 5060 /**< default SIP port */ + +/** Flags passed to unparse_uri_components(): */ +/** suppress "scheme://user\@site:port" */ +#define APR_URI_UNP_OMITSITEPART (1U<<0) +/** Just omit user */ +#define APR_URI_UNP_OMITUSER (1U<<1) +/** Just omit password */ +#define APR_URI_UNP_OMITPASSWORD (1U<<2) +/** omit "user:password\@" part */ +#define APR_URI_UNP_OMITUSERINFO (APR_URI_UNP_OMITUSER | \ + APR_URI_UNP_OMITPASSWORD) +/** Show plain text password (default: show XXXXXXXX) */ +#define APR_URI_UNP_REVEALPASSWORD (1U<<3) +/** Show "scheme://user\@site:port" only */ +#define APR_URI_UNP_OMITPATHINFO (1U<<4) +/** Omit the "?queryarg" from the path */ +#define APR_URI_UNP_OMITQUERY (1U<<5) + +/** @see apr_uri_t */ +typedef struct apr_uri_t apr_uri_t; + +/** + * A structure to encompass all of the fields in a uri + */ +struct apr_uri_t { + /** scheme ("http"/"ftp"/...) */ + char *scheme; + /** combined [user[:password]\@]host[:port] */ + char *hostinfo; + /** user name, as in http://user:passwd\@host:port/ */ + char *user; + /** password, as in http://user:passwd\@host:port/ */ + char *password; + /** hostname from URI (or from Host: header) */ + char *hostname; + /** port string (integer representation is in "port") */ + char *port_str; + /** the request path (or "/" if only scheme://host was given) */ + char *path; + /** Everything after a '?' in the path, if present */ + char *query; + /** Trailing "#fragment" string, if present */ + char *fragment; + + /** structure returned from gethostbyname() */ + struct hostent *hostent; + + /** The port number, numeric, valid only if port_str != NULL */ + apr_port_t port; + + /** has the structure been initialized */ + unsigned is_initialized:1; + + /** has the DNS been looked up yet */ + unsigned dns_looked_up:1; + /** has the dns been resolved yet */ + unsigned dns_resolved:1; +}; + +/* apr_uri.c */ +/** + * Return the default port for a given scheme. The schemes recognized are + * http, ftp, https, gopher, wais, nntp, snews, and prospero + * @param scheme_str The string that contains the current scheme + * @return The default port for this scheme + */ +APU_DECLARE(apr_port_t) apr_uri_port_of_scheme(const char *scheme_str); + +/** + * Unparse a apr_uri_t structure to an URI string. Optionally + * suppress the password for security reasons. + * @param p The pool to allocate out of + * @param uptr All of the parts of the uri + * @param flags How to unparse the uri. One of: + *
+ *    APR_URI_UNP_OMITSITEPART        Suppress "scheme://user\@site:port" 
+ *    APR_URI_UNP_OMITUSER            Just omit user 
+ *    APR_URI_UNP_OMITPASSWORD        Just omit password 
+ *    APR_URI_UNP_OMITUSERINFO        Omit "user:password\@" part
+ *    APR_URI_UNP_REVEALPASSWORD      Show plain text password (default: show XXXXXXXX)
+ *    APR_URI_UNP_OMITPATHINFO        Show "scheme://user\@site:port" only 
+ *    APR_URI_UNP_OMITQUERY           Omit "?queryarg" or "#fragment" 
+ * 
+ * @return The uri as a string + */ +APU_DECLARE(char *) apr_uri_unparse(apr_pool_t *p, + const apr_uri_t *uptr, + unsigned flags); + +/** + * Parse a given URI, fill in all supplied fields of a apr_uri_t + * structure. This eliminates the necessity of extracting host, port, + * path, query info repeatedly in the modules. + * @param p The pool to allocate out of + * @param uri The uri to parse + * @param uptr The apr_uri_t to fill out + * @return APR_SUCCESS for success or error code + */ +APU_DECLARE(apr_status_t) apr_uri_parse(apr_pool_t *p, const char *uri, + apr_uri_t *uptr); + +/** + * Special case for CONNECT parsing: it comes with the hostinfo part only + * @param p The pool to allocate out of + * @param hostinfo The hostinfo string to parse + * @param uptr The apr_uri_t to fill out + * @return APR_SUCCESS for success or error code + */ +APU_DECLARE(apr_status_t) apr_uri_parse_hostinfo(apr_pool_t *p, + const char *hostinfo, + apr_uri_t *uptr); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_URI_H */ diff --git a/include/apr-linux/apr_user.h b/include/apr-linux/apr_user.h new file mode 100644 index 0000000..0179e22 --- /dev/null +++ b/include/apr-linux/apr_user.h @@ -0,0 +1,158 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_USER_H +#define APR_USER_H + +/** + * @file apr_user.h + * @brief APR User ID Services + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_user User and Group ID Services + * @ingroup APR + * @{ + */ + +/** + * Structure for determining user ownership. + */ +#ifdef WIN32 +typedef PSID apr_uid_t; +#else +typedef uid_t apr_uid_t; +#endif + +/** + * Structure for determining group ownership. + */ +#ifdef WIN32 +typedef PSID apr_gid_t; +#else +typedef gid_t apr_gid_t; +#endif + +#if APR_HAS_USER + +/** + * Get the userid (and groupid) of the calling process + * @param userid Returns the user id + * @param groupid Returns the user's group id + * @param p The pool from which to allocate working space + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *userid, + apr_gid_t *groupid, + apr_pool_t *p); + +/** + * Get the user name for a specified userid + * @param username Pointer to new string containing user name (on output) + * @param userid The userid + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + apr_pool_t *p); + +/** + * Get the userid (and groupid) for the specified username + * @param userid Returns the user id + * @param groupid Returns the user's group id + * @param username The username to lookup + * @param p The pool from which to allocate working space + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *userid, apr_gid_t *groupid, + const char *username, apr_pool_t *p); + +/** + * Get the home directory for the named user + * @param dirname Pointer to new string containing directory name (on output) + * @param username The named user + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + const char *username, + apr_pool_t *p); + +/** + * Compare two user identifiers for equality. + * @param left One uid to test + * @param right Another uid to test + * @return APR_SUCCESS if the apr_uid_t strutures identify the same user, + * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid. + * @remark This function is available only if APR_HAS_USER is defined. + */ +#if defined(WIN32) +APR_DECLARE(apr_status_t) apr_uid_compare(apr_uid_t left, apr_uid_t right); +#else +#define apr_uid_compare(left,right) (((left) == (right)) ? APR_SUCCESS : APR_EMISMATCH) +#endif + +/** + * Get the group name for a specified groupid + * @param groupname Pointer to new string containing group name (on output) + * @param groupid The groupid + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, + apr_gid_t groupid, apr_pool_t *p); + +/** + * Get the groupid for a specified group name + * @param groupid Pointer to the group id (on output) + * @param groupname The group name to look up + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *groupid, + const char *groupname, apr_pool_t *p); + +/** + * Compare two group identifiers for equality. + * @param left One gid to test + * @param right Another gid to test + * @return APR_SUCCESS if the apr_gid_t strutures identify the same group, + * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid. + * @remark This function is available only if APR_HAS_USER is defined. + */ +#if defined(WIN32) +APR_DECLARE(apr_status_t) apr_gid_compare(apr_gid_t left, apr_gid_t right); +#else +#define apr_gid_compare(left,right) (((left) == (right)) ? APR_SUCCESS : APR_EMISMATCH) +#endif + +#endif /* ! APR_HAS_USER */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_USER_H */ diff --git a/include/apr-linux/apr_uuid.h b/include/apr-linux/apr_uuid.h new file mode 100644 index 0000000..5312a9f --- /dev/null +++ b/include/apr-linux/apr_uuid.h @@ -0,0 +1,76 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * @file apr_uuid.h + * @brief APR UUID library + */ +#ifndef APR_UUID_H +#define APR_UUID_H + +#include "apu.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_UUID UUID Handling + * @ingroup APR + * @{ + */ + +/** + * we represent a UUID as a block of 16 bytes. + */ + +typedef struct { + unsigned char data[16]; /**< the actual UUID */ +} apr_uuid_t; + +/** UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF */ +#define APR_UUID_FORMATTED_LENGTH 36 + + +/** + * Generate and return a (new) UUID + * @param uuid The resulting UUID + */ +APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid); + +/** + * Format a UUID into a string, following the standard format + * @param buffer The buffer to place the formatted UUID string into. It must + * be at least APR_UUID_FORMATTED_LENGTH + 1 bytes long to hold + * the formatted UUID and a null terminator + * @param uuid The UUID to format + */ +APU_DECLARE(void) apr_uuid_format(char *buffer, const apr_uuid_t *uuid); + +/** + * Parse a standard-format string into a UUID + * @param uuid The resulting UUID + * @param uuid_str The formatted UUID + */ +APU_DECLARE(apr_status_t) apr_uuid_parse(apr_uuid_t *uuid, const char *uuid_str); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_UUID_H */ diff --git a/include/apr-linux/apr_version.h b/include/apr-linux/apr_version.h new file mode 100644 index 0000000..aec7c73 --- /dev/null +++ b/include/apr-linux/apr_version.h @@ -0,0 +1,159 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_VERSION_H +#define APR_VERSION_H + +/** + * @file apr_version.h + * @brief APR Versioning Interface + * + * APR's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of APR by use of the compile-time + * constants and the use of the run-time query function. + * + * APR version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for APR. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define APR_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading APR_MAJOR_VERSION + */ +#define APR_MINOR_VERSION 3 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading APR_MINOR_VERSION + */ +#define APR_PATCH_VERSION 2 + +/** + * The symbol APR_IS_DEV_VERSION is only defined for internal, + * "development" copies of APR. It is undefined for released versions + * of APR. + */ +/* #undef APR_IS_DEV_VERSION */ + +/** + * Check at compile time if the APR version is at least a certain + * level. + * @param major The major version component of the version checked + * for (e.g., the "1" of "1.3.0"). + * @param minor The minor version component of the version checked + * for (e.g., the "3" of "1.3.0"). + * @param patch The patch level component of the version checked + * for (e.g., the "0" of "1.3.0"). + * @remark This macro is available with APR versions starting with + * 1.3.0. + */ +#define APR_VERSION_AT_LEAST(major,minor,patch) \ +(((major) < APR_MAJOR_VERSION) \ + || ((major) == APR_MAJOR_VERSION && (minor) < APR_MINOR_VERSION) \ + || ((major) == APR_MAJOR_VERSION && (minor) == APR_MINOR_VERSION && (patch) <= APR_PATCH_VERSION)) + +#if defined(APR_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define APR_IS_DEV_STRING "-dev" +#else +#define APR_IS_DEV_STRING "" +#endif + +/* APR_STRINGIFY is defined here, and also in apr_general.h, so wrap it */ +#ifndef APR_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) +/** Helper macro for APR_STRINGIFY */ +#define APR_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of APR's version */ +#define APR_VERSION_STRING \ + APR_STRINGIFY(APR_MAJOR_VERSION) "." \ + APR_STRINGIFY(APR_MINOR_VERSION) "." \ + APR_STRINGIFY(APR_PATCH_VERSION) \ + APR_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define APR_VERSION_STRING_CSV APR_MAJOR_VERSION ##, \ + ##APR_MINOR_VERSION ##, \ + ##APR_PATCH_VERSION + + +#ifndef APR_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. APR_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The numeric version information is broken out into fields within this + * structure. + */ +typedef struct { + int major; /**< major number */ + int minor; /**< minor number */ + int patch; /**< patch number */ + int is_dev; /**< is development (1 or 0) */ +} apr_version_t; + +/** + * Return APR's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +APR_DECLARE(void) apr_version(apr_version_t *pvsn); + +/** Return APR's version information as a string. */ +APR_DECLARE(const char *) apr_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APR_VERSION_ONLY */ + +#endif /* ndef APR_VERSION_H */ diff --git a/include/apr-linux/apr_want.h b/include/apr-linux/apr_want.h new file mode 100644 index 0000000..454257a --- /dev/null +++ b/include/apr-linux/apr_want.h @@ -0,0 +1,129 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#include "apr.h" /* configuration data */ +/** + * @file apr_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APR_WANT_STRFUNC:  strcmp, strcat, strcpy, etc
+ *   APR_WANT_MEMFUNC:  memcmp, memcpy, etc
+ *   APR_WANT_STDIO:     and related bits
+ *   APR_WANT_IOVEC:    struct iovec
+ *   APR_WANT_BYTEFUNC: htons, htonl, ntohl, ntohs
+ *
+ * Typical usage:
+ *
+ *   #define APR_WANT_STRFUNC
+ *   #define APR_WANT_MEMFUNC
+ *   #include "apr_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apr_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STRFUNC + +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_STRINGS_H +#include +#endif + +#undef APR_WANT_STRFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_MEMFUNC + +#if APR_HAVE_STRING_H +#include +#endif + +#undef APR_WANT_MEMFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STDIO + +#if APR_HAVE_STDIO_H +#include +#endif + +#undef APR_WANT_STDIO +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_IOVEC + +#if APR_HAVE_IOVEC + +#if APR_HAVE_SYS_UIO_H +#include +#endif + +#else + +#if 0 +struct iovec +{ + char *iov_base; + size_t iov_len; +}; +#endif + +#endif + +/* apr_want is included at several layers; redefining APR_HAVE_IOVEC + * now to ensure that our struct is not introduced several times. + */ +#undef APR_HAVE_IOVEC +#define APR_HAVE_IOVEC 1 + +#undef APR_WANT_IOVEC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_BYTEFUNC + +/* Single Unix says they are in arpa/inet.h. Linux has them in + * netinet/in.h. FreeBSD has them in arpa/inet.h but requires that + * netinet/in.h be included first. + */ +#if APR_HAVE_NETINET_IN_H +#include +#endif +#if APR_HAVE_ARPA_INET_H +#include +#endif + +#undef APR_WANT_BYTEFUNC +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr-linux/apr_xlate.h b/include/apr-linux/apr_xlate.h new file mode 100644 index 0000000..3263668 --- /dev/null +++ b/include/apr-linux/apr_xlate.h @@ -0,0 +1,163 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_XLATE_H +#define APR_XLATE_H + +#include "apu.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file apr_xlate.h + * @brief APR I18N translation library + */ + +/** + * @defgroup APR_XLATE I18N translation library + * @ingroup APR + * @{ + */ +/** Opaque translation buffer */ +typedef struct apr_xlate_t apr_xlate_t; + +/** + * Set up for converting text from one charset to another. + * @param convset The handle to be filled in by this function + * @param topage The name of the target charset + * @param frompage The name of the source charset + * @param pool The pool to use + * @remark + * Specify APR_DEFAULT_CHARSET for one of the charset + * names to indicate the charset of the source code at + * compile time. This is useful if there are literal + * strings in the source code which must be translated + * according to the charset of the source code. + * APR_DEFAULT_CHARSET is not useful if the source code + * of the caller was not encoded in the same charset as + * APR at compile time. + * + * @remark + * Specify APR_LOCALE_CHARSET for one of the charset + * names to indicate the charset of the current locale. + * + * @remark + * Return APR_EINVAL if unable to procure a convset, or APR_ENOTIMPL + * if charset transcoding is not available in this instance of + * apr-util at all (i.e., APR_HAS_XLATE is undefined). + */ +APU_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset, + const char *topage, + const char *frompage, + apr_pool_t *pool); + +/** + * This is to indicate the charset of the sourcecode at compile time + * names to indicate the charset of the source code at + * compile time. This is useful if there are literal + * strings in the source code which must be translated + * according to the charset of the source code. + */ +#define APR_DEFAULT_CHARSET (const char *)0 +/** + * To indicate charset names of the current locale + */ +#define APR_LOCALE_CHARSET (const char *)1 + +/** + * Find out whether or not the specified conversion is single-byte-only. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param onoff Output: whether or not the conversion is single-byte-only + * @remark + * Return APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + */ +APU_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff); + +/** + * Convert a buffer of text from one codepage to another. + * @param convset The handle allocated by apr_xlate_open, specifying + * the parameters of conversion + * @param inbuf The address of the source buffer + * @param inbytes_left Input: the amount of input data to be translated + * Output: the amount of input data not yet translated + * @param outbuf The address of the destination buffer + * @param outbytes_left Input: the size of the output buffer + * Output: the amount of the output buffer not yet used + * @remark + * Returns APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + * Returns APR_INCOMPLETE if the input buffer ends in an incomplete + * multi-byte character. + * + * To correctly terminate the output buffer for some multi-byte + * character set encodings, a final call must be made to this function + * after the complete input string has been converted, passing + * the inbuf and inbytes_left parameters as NULL. (Note that this + * mode only works from version 1.1.0 onwards) + */ +APU_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset, + const char *inbuf, + apr_size_t *inbytes_left, + char *outbuf, + apr_size_t *outbytes_left); + +/* @see apr_file_io.h the comment in apr_file_io.h about this hack */ +#ifdef APR_NOT_DONE_YET +/** + * The purpose of apr_xlate_conv_char is to translate one character + * at a time. This needs to be written carefully so that it works + * with double-byte character sets. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param inchar The character to convert + * @param outchar The converted character + */ +APU_DECLARE(apr_status_t) apr_xlate_conv_char(apr_xlate_t *convset, + char inchar, char outchar); +#endif + +/** + * Convert a single-byte character from one charset to another. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param inchar The single-byte character to convert. + * @warning This only works when converting between single-byte character sets. + * -1 will be returned if the conversion can't be performed. + */ +APU_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset, + unsigned char inchar); + +/** + * Close a codepage translation handle. + * @param convset The codepage translation handle to close + * @remark + * Return APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + */ +APU_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_XLATE_H */ diff --git a/include/apr-linux/apr_xml.h b/include/apr-linux/apr_xml.h new file mode 100644 index 0000000..2a43b28 --- /dev/null +++ b/include/apr-linux/apr_xml.h @@ -0,0 +1,356 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +/** + * @file apr_xml.h + * @brief APR-UTIL XML Library + */ +#ifndef APR_XML_H +#define APR_XML_H + +/** + * @defgroup APR_Util_XML XML + * @ingroup APR_Util + * @{ + */ +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_file_io.h" + +#include "apu.h" +#if APR_CHARSET_EBCDIC +#include "apr_xlate.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @package Apache XML library + */ + +/* -------------------------------------------------------------------- */ + +/* ### these will need to move at some point to a more logical spot */ + +/** @see apr_text */ +typedef struct apr_text apr_text; + +/** Structure to keep a linked list of pieces of text */ +struct apr_text { + /** The current piece of text */ + const char *text; + /** a pointer to the next piece of text */ + struct apr_text *next; +}; + +/** @see apr_text_header */ +typedef struct apr_text_header apr_text_header; + +/** A list of pieces of text */ +struct apr_text_header { + /** The first piece of text in the list */ + apr_text *first; + /** The last piece of text in the list */ + apr_text *last; +}; + +/** + * Append a piece of text to the end of a list + * @param p The pool to allocate out of + * @param hdr The text header to append to + * @param text The new text to append + */ +APU_DECLARE(void) apr_text_append(apr_pool_t *p, apr_text_header *hdr, + const char *text); + + +/* -------------------------------------------------------------------- +** +** XML PARSING +*/ + +/* +** Qualified namespace values +** +** APR_XML_NS_DAV_ID +** We always insert the "DAV:" namespace URI at the head of the +** namespace array. This means that it will always be at ID==0, +** making it much easier to test for. +** +** APR_XML_NS_NONE +** This special ID is used for two situations: +** +** 1) The namespace prefix begins with "xml" (and we do not know +** what it means). Namespace prefixes with "xml" (any case) as +** their first three characters are reserved by the XML Namespaces +** specification for future use. mod_dav will pass these through +** unchanged. When this identifier is used, the prefix is LEFT in +** the element/attribute name. Downstream processing should not +** prepend another prefix. +** +** 2) The element/attribute does not have a namespace. +** +** a) No prefix was used, and a default namespace has not been +** defined. +** b) No prefix was used, and the default namespace was specified +** to mean "no namespace". This is done with a namespace +** declaration of: xmlns="" +** (this declaration is typically used to override a previous +** specification for the default namespace) +** +** In these cases, we need to record that the elem/attr has no +** namespace so that we will not attempt to prepend a prefix. +** All namespaces that are used will have a prefix assigned to +** them -- mod_dav will never set or use the default namespace +** when generating XML. This means that "no prefix" will always +** mean "no namespace". +** +** In both cases, the XML generation will avoid prepending a prefix. +** For the first case, this means the original prefix/name will be +** inserted into the output stream. For the latter case, it means +** the name will have no prefix, and since we never define a default +** namespace, this means it will have no namespace. +** +** Note: currently, mod_dav understands the "xmlns" prefix and the +** "xml:lang" attribute. These are handled specially (they aren't +** left within the XML tree), so the APR_XML_NS_NONE value won't ever +** really apply to these values. +*/ +#define APR_XML_NS_DAV_ID 0 /**< namespace ID for "DAV:" */ +#define APR_XML_NS_NONE -10 /**< no namespace for this elem/attr */ + +#define APR_XML_NS_ERROR_BASE -100 /**< used only during processing */ +/** Is this namespace an error? */ +#define APR_XML_NS_IS_ERROR(e) ((e) <= APR_XML_NS_ERROR_BASE) + +/** @see apr_xml_attr */ +typedef struct apr_xml_attr apr_xml_attr; +/** @see apr_xml_elem */ +typedef struct apr_xml_elem apr_xml_elem; +/** @see apr_xml_doc */ +typedef struct apr_xml_doc apr_xml_doc; + +/** apr_xml_attr: holds a parsed XML attribute */ +struct apr_xml_attr { + /** attribute name */ + const char *name; + /** index into namespace array */ + int ns; + + /** attribute value */ + const char *value; + + /** next attribute */ + struct apr_xml_attr *next; +}; + +/** apr_xml_elem: holds a parsed XML element */ +struct apr_xml_elem { + /** element name */ + const char *name; + /** index into namespace array */ + int ns; + /** xml:lang for attrs/contents */ + const char *lang; + + /** cdata right after start tag */ + apr_text_header first_cdata; + /** cdata after MY end tag */ + apr_text_header following_cdata; + + /** parent element */ + struct apr_xml_elem *parent; + /** next (sibling) element */ + struct apr_xml_elem *next; + /** first child element */ + struct apr_xml_elem *first_child; + /** first attribute */ + struct apr_xml_attr *attr; + + /* used only during parsing */ + /** last child element */ + struct apr_xml_elem *last_child; + /** namespaces scoped by this elem */ + struct apr_xml_ns_scope *ns_scope; + + /* used by modules during request processing */ + /** Place for modules to store private data */ + void *priv; +}; + +/** Is this XML element empty? */ +#define APR_XML_ELEM_IS_EMPTY(e) ((e)->first_child == NULL && \ + (e)->first_cdata.first == NULL) + +/** apr_xml_doc: holds a parsed XML document */ +struct apr_xml_doc { + /** root element */ + apr_xml_elem *root; + /** array of namespaces used */ + apr_array_header_t *namespaces; +}; + +/** Opaque XML parser structure */ +typedef struct apr_xml_parser apr_xml_parser; + +/** + * Create an XML parser + * @param pool The pool for allocating the parser and the parse results. + * @return The new parser. + */ +APU_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool); + +/** + * Parse a File, producing a xml_doc + * @param p The pool for allocating the parse results. + * @param parser A pointer to *parser (needed so calling function can get + * errors), will be set to NULL on successfull completion. + * @param ppdoc A pointer to *apr_xml_doc (which has the parsed results in it) + * @param xmlfd A file to read from. + * @param buffer_length Buffer length which would be suitable + * @return Any errors found during parsing. + */ +APU_DECLARE(apr_status_t) apr_xml_parse_file(apr_pool_t *p, + apr_xml_parser **parser, + apr_xml_doc **ppdoc, + apr_file_t *xmlfd, + apr_size_t buffer_length); + + +/** + * Feed input into the parser + * @param parser The XML parser for parsing this data. + * @param data The data to parse. + * @param len The length of the data. + * @return Any errors found during parsing. + * @remark Use apr_xml_parser_geterror() to get more error information. + */ +APU_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser, + const char *data, + apr_size_t len); + +/** + * Terminate the parsing and return the result + * @param parser The XML parser for parsing this data. + * @param pdoc The resulting parse information. May be NULL to simply + * terminate the parsing without fetching the info. + * @return Any errors found during the final stage of parsing. + * @remark Use apr_xml_parser_geterror() to get more error information. + */ +APU_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser, + apr_xml_doc **pdoc); + +/** + * Fetch additional error information from the parser. + * @param parser The XML parser to query for errors. + * @param errbuf A buffer for storing error text. + * @param errbufsize The length of the error text buffer. + * @return The error buffer + */ +APU_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser, + char *errbuf, + apr_size_t errbufsize); + + +/** + * Converts an XML element tree to flat text + * @param p The pool to allocate out of + * @param elem The XML element to convert + * @param style How to covert the XML. One of: + *
+ *     APR_XML_X2T_FULL                start tag, contents, end tag 
+ *     APR_XML_X2T_INNER               contents only 
+ *     APR_XML_X2T_LANG_INNER          xml:lang + inner contents 
+ *     APR_XML_X2T_FULL_NS_LANG        FULL + ns defns + xml:lang 
+ * 
+ * @param namespaces The namespace of the current XML element + * @param ns_map Namespace mapping + * @param pbuf Buffer to put the converted text into + * @param psize Size of the converted text + */ +APU_DECLARE(void) apr_xml_to_text(apr_pool_t *p, const apr_xml_elem *elem, + int style, apr_array_header_t *namespaces, + int *ns_map, const char **pbuf, + apr_size_t *psize); + +/* style argument values: */ +#define APR_XML_X2T_FULL 0 /**< start tag, contents, end tag */ +#define APR_XML_X2T_INNER 1 /**< contents only */ +#define APR_XML_X2T_LANG_INNER 2 /**< xml:lang + inner contents */ +#define APR_XML_X2T_FULL_NS_LANG 3 /**< FULL + ns defns + xml:lang */ + +/** + * empty XML element + * @param p The pool to allocate out of + * @param elem The XML element to empty + * @return the string that was stored in the XML element + */ +APU_DECLARE(const char *) apr_xml_empty_elem(apr_pool_t *p, + const apr_xml_elem *elem); + +/** + * quote an XML string + * Replace '<', '>', and '&' with '<', '>', and '&'. + * @param p The pool to allocate out of + * @param s The string to quote + * @param quotes If quotes is true, then replace '"' with '"'. + * @return The quoted string + * @note If the string does not contain special characters, it is not + * duplicated into the pool and the original string is returned. + */ +APU_DECLARE(const char *) apr_xml_quote_string(apr_pool_t *p, const char *s, + int quotes); + +/** + * Quote an XML element + * @param p The pool to allocate out of + * @param elem The element to quote + */ +APU_DECLARE(void) apr_xml_quote_elem(apr_pool_t *p, apr_xml_elem *elem); + +/* manage an array of unique URIs: apr_xml_insert_uri() and APR_XML_URI_ITEM() */ + +/** + * return the URI's (existing) index, or insert it and return a new index + * @param uri_array array to insert into + * @param uri The uri to insert + * @return int The uri's index + */ +APU_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array, + const char *uri); + +/** Get the URI item for this XML element */ +#define APR_XML_GET_URI_ITEM(ary, i) (((const char * const *)(ary)->elts)[i]) + +#if APR_CHARSET_EBCDIC +/** + * Convert parsed tree in EBCDIC + * @param p The pool to allocate out of + * @param pdoc The apr_xml_doc to convert. + * @param xlate The translation handle to use. + * @return Any errors found during conversion. + */ +APU_DECLARE(apr_status_t) apr_xml_parser_convert_doc(apr_pool_t *p, + apr_xml_doc *pdoc, + apr_xlate_t *convset); +#endif + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* APR_XML_H */ diff --git a/include/apr-linux/apu.h b/include/apr-linux/apu.h new file mode 100644 index 0000000..04934c8 --- /dev/null +++ b/include/apr-linux/apu.h @@ -0,0 +1,110 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* + * apu.h is generated from apu.h.in by configure -- do not edit apu.h + */ +/* @file apu.h + * @brief APR-Utility main file + */ +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +#ifndef APU_H +#define APU_H + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @fn APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @fn APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @fn APU_DECLARE_DATA type apr_variable; + * @note APU_DECLARE_DATA extern type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA + +#if !defined(WIN32) || defined(APU_MODULE_DECLARE_STATIC) +/** + * Declare a dso module's exported module structure as APU_MODULE_DECLARE_DATA. + * + * Unless APU_MODULE_DECLARE_STATIC is defined at compile time, symbols + * declared with APU_MODULE_DECLARE_DATA are always exported. + * @code + * module APU_MODULE_DECLARE_DATA mod_tag + * @endcode + */ +#define APU_MODULE_DECLARE_DATA +#else +#define APU_MODULE_DECLARE_DATA __declspec(dllexport) +#endif + +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 +#define APU_HAVE_GDBM 0 +#define APU_HAVE_NDBM 0 +#define APU_HAVE_DB 0 + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION 0 +#endif + +#define APU_HAVE_PGSQL 0 +#define APU_HAVE_MYSQL 0 +#define APU_HAVE_SQLITE3 0 +#define APU_HAVE_SQLITE2 0 +#define APU_HAVE_ORACLE 0 +#define APU_HAVE_FREETDS 0 +#define APU_HAVE_ODBC 0 + +#define APU_HAVE_APR_ICONV 0 +#define APU_HAVE_ICONV 1 +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#endif /* APU_H */ +/** @} */ diff --git a/include/apr-linux/apu.h.in b/include/apr-linux/apu.h.in new file mode 100644 index 0000000..ac4001e --- /dev/null +++ b/include/apr-linux/apu.h.in @@ -0,0 +1,85 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +/* + * apu.h is generated from apu.h.in by configure -- do not edit apu.h + */ +/* @file apu.h + * @brief APR-Utility main file + */ +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +#ifndef APU_H +#define APU_H + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip APU_DECLARE_DATA extern type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM @apu_have_sdbm@ +#define APU_HAVE_GDBM @apu_have_gdbm@ +#define APU_HAVE_NDBM @apu_have_ndbm@ +#define APU_HAVE_DB @apu_have_db@ + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION @apu_db_version@ +#endif /* APU_HAVE_DB */ + +#define APU_HAVE_APR_ICONV @have_apr_iconv@ +#define APU_HAVE_ICONV @have_iconv@ +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#endif /* APU_H */ +/** @} */ diff --git a/include/apr-linux/apu.hnw b/include/apr-linux/apu.hnw new file mode 100644 index 0000000..d09b8ec --- /dev/null +++ b/include/apr-linux/apu.hnw @@ -0,0 +1,83 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +/* + * Note: This is a NetWare specific version of apu.h. It is renamed to + * apu.h at the start of a NetWare build. + */ +/* @file apu.h + * @brief APR-Utility main file + */ +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +#ifndef APU_H +#define APU_H + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip APU_DECLARE_DATA extern type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 +#define APU_HAVE_GDBM 0 +#define APU_HAVE_DB 0 + + +#define HAVE_ICONV_H 1 +#define APU_HAVE_APR_ICONV 0 +#define APU_HAVE_ICONV 1 +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#endif /* APU_H */ +/** @} */ diff --git a/include/apr-linux/apu.hw b/include/apr-linux/apu.hw new file mode 100644 index 0000000..4e5810f --- /dev/null +++ b/include/apr-linux/apu.hw @@ -0,0 +1,102 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +/* + * Note: This is a Windows specific version of apu.h. It is renamed to + * apu.h at the start of a Windows build. + */ +/* @file apu.h + * @brief APR-Utility main file + */ + +#ifdef WIN32 +#ifndef APU_H +#define APU_H +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +#if defined(DOXYGEN) || !defined(WIN32) +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip extern APU_DECLARE_DATA type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +#elif defined(APU_DECLARE_STATIC) +#define APU_DECLARE(type) type __stdcall +#define APU_DECLARE_NONSTD(type) type __cdecl +#define APU_DECLARE_DATA +#elif defined(APU_DECLARE_EXPORT) +#define APU_DECLARE(type) __declspec(dllexport) type __stdcall +#define APU_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APU_DECLARE_DATA __declspec(dllexport) +#else +#define APU_DECLARE(type) __declspec(dllimport) type __stdcall +#define APU_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APU_DECLARE_DATA __declspec(dllimport) +#endif +/** @} */ +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 +#define APU_HAVE_GDBM 0 + +/* Allow external override */ +#if !defined(APU_HAVE_DB) +#define APU_HAVE_DB 0 +#endif + + +#define APU_HAVE_APR_ICONV 1 +#define APU_HAVE_ICONV 0 +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#endif /* APU_H */ +#endif /* WIN32 */ diff --git a/include/apr-linux/apu_version.h b/include/apr-linux/apu_version.h new file mode 100644 index 0000000..d0bd2f6 --- /dev/null +++ b/include/apr-linux/apu_version.h @@ -0,0 +1,134 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APU_VERSION_H +#define APU_VERSION_H + +/** + * @file apu_version.h + * @brief APR-util Versioning Interface + * + * APR-util's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of APU by use of the compile-time + * constants and the use of the run-time query function. + * + * APU version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for APU. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define APU_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading APU_MAJOR_VERSION + */ +#define APU_MINOR_VERSION 3 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading APR_MINOR_VERSION + */ +#define APU_PATCH_VERSION 2 + +/** + * The symbol APU_IS_DEV_VERSION is only defined for internal, + * "development" copies of APU. It is undefined for released versions + * of APU. + */ +/* #undef APU_IS_DEV_VERSION */ + + +#if defined(APU_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define APU_IS_DEV_STRING "-dev" +#else +#define APU_IS_DEV_STRING "" +#endif + + +#ifndef APU_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APU_STRINGIFY(n) APU_STRINGIFY_HELPER(n) +/** Helper macro for APU_STRINGIFY */ +#define APU_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of APU's version */ +#define APU_VERSION_STRING \ + APU_STRINGIFY(APU_MAJOR_VERSION) "." \ + APU_STRINGIFY(APU_MINOR_VERSION) "." \ + APU_STRINGIFY(APU_PATCH_VERSION) \ + APU_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define APU_VERSION_STRING_CSV APU_MAJOR_VERSION ##, \ + ##APU_MINOR_VERSION ##, \ + ##APU_PATCH_VERSION + + +#ifndef APU_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. APU_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr_version.h" + +#include "apu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return APR-util's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +APU_DECLARE(void) apu_version(apr_version_t *pvsn); + +/** Return APU's version information as a string. */ +APU_DECLARE(const char *) apu_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APU_VERSION_ONLY */ + +#endif /* ndef APU_VERSION_H */ diff --git a/include/apr-linux/apu_want.h b/include/apr-linux/apu_want.h new file mode 100644 index 0000000..25f1100 --- /dev/null +++ b/include/apr-linux/apu_want.h @@ -0,0 +1,51 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +#include +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr-linux/apu_want.h.in b/include/apr-linux/apu_want.h.in new file mode 100644 index 0000000..2888d59 --- /dev/null +++ b/include/apr-linux/apu_want.h.in @@ -0,0 +1,50 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header@>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +#include <@apu_db_header@> +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr-linux/apu_want.hnw b/include/apr-linux/apu_want.hnw new file mode 100644 index 0000000..5063afe --- /dev/null +++ b/include/apr-linux/apu_want.hnw @@ -0,0 +1,51 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr-linux/apu_want.hw b/include/apr-linux/apu_want.hw new file mode 100644 index 0000000..5063afe --- /dev/null +++ b/include/apr-linux/apu_want.hw @@ -0,0 +1,51 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr-linux/expat.h b/include/apr-linux/expat.h new file mode 100644 index 0000000..9e440e2 --- /dev/null +++ b/include/apr-linux/expat.h @@ -0,0 +1,742 @@ +/* +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#include + +#ifndef XMLPARSEAPI +# if defined(__declspec) && !defined(__CYGWIN__) +# define XMLPARSEAPI __declspec(dllimport) +# else +# define XMLPARSEAPI /* nothing */ +# endif +#endif /* not defined XMLPARSEAPI */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *XML_Parser; + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ + +typedef void (*XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +void XMLPARSEAPI +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* + The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" keyword. + The "isrequired" parameter will be true and the default value will + be NULL in the case of "#REQUIRED". If "isrequired" is true and + default is non-NULL, then this is a "#FIXED" default. + */ + +typedef void (*XML_AttlistDeclHandler) (void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +void XMLPARSEAPI +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + + + /* The XML declaration handler is called for *both* XML declarations and + text declarations. The way to distinguish is that the version parameter + will be null for text declarations. The encoding parameter may be null + for XML declarations. The standalone parameter will be -1, 0, or 1 + indicating respectively that there was no standalone parameter in + the declaration, that it was given as no, or that it was given as yes. + */ + +typedef void (*XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +void XMLPARSEAPI +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the +external protocol or null if there is none specified. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type +names and attribute names that belong to a namespace will be expanded; +unprefixed attribute names are never expanded; unprefixed element type +names are expanded only if there is a default namespace. The expanded +name is the concatenation of the namespace URI, the namespace +separator character, and the local part of the name. If the namespace +separator is '\0' then the namespace URI and the local part will be +concatenated without any separator. When a namespace is not declared, +the name and prefix will be passed through without expansion. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suit referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ + +XML_Parser XMLPARSEAPI +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. */ + +typedef void (*XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (*XML_EndElementHandler)(void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (*XML_CharacterDataHandler)(void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (*XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void (*XML_StartCdataSectionHandler)(void *userData); +typedef void (*XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for +which there is no applicable handler. This includes both +characters that are part of markup which is of a kind that is +not reported (comments, markup declarations), or characters +that are part of a construct which could be reported but +for which no handler has been supplied. The characters are passed +exactly as they were in the XML document except that +they will be encoded in UTF-8. Line boundaries are not normalized. +Note that a byte order mark character is not passed to the default handler. +There are no guarantees about how characters are divided between calls +to the default handler: for example, a comment might be split between +multiple calls. */ + +typedef void (*XML_DefaultHandler)(void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. */ + +typedef void (*XML_StartDoctypeDeclHandler)(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset + ); + +/* This is called for the start of the DOCTYPE declaration when the +closing > is encountered, but after processing any external subset. */ +typedef void (*XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-null and systemId, publicID, and notationName will be null. + The value string is NOT null terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be null and systemId will be non-null. + The publicId argument will be null unless a public identifier was + provided. The notationName argument will have a non-null value only + for unparsed entity declarations. +*/ + +typedef void (*XML_EntityDeclHandler) (void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +void XMLPARSEAPI +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. +This is called for a declaration of an unparsed (NDATA) +entity. The base argument is whatever was set by XML_SetBase. +The entityName, systemId and notationName arguments will never be null. +The other arguments may be. */ + +typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. +The base argument is whatever was set by XML_SetBase. +The notationName will never be null. The other arguments can be. */ + +typedef void (*XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for +each namespace declaration. The call to the start and end element +handlers occur between the calls to the start and end namespace +declaration handlers. For an xmlns attribute, prefix will be null. +For an xmlns="" attribute, uri will be null. */ + +typedef void (*XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (*XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone (it has an +external subset or a reference to a parameter entity, but does not +have standalone="yes"). If this handler returns 0, then processing +will not continue, and the parser will return a +XML_ERROR_NOT_STANDALONE error. */ + +typedef int (*XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general entity. +The referenced entity is not automatically parsed. +The application can parse it immediately or later using +XML_ExternalEntityParserCreate. +The parser argument is the parser parsing the entity containing the reference; +it can be passed as the parser argument to XML_ExternalEntityParserCreate. +The systemId argument is the system identifier as specified in the entity +declaration; it will not be null. +The base argument is the system identifier that should be used as the base for +resolving systemId if systemId was relative; this is set by XML_SetBase; +it may be null. +The publicId argument is the public identifier as specified in the entity +declaration, or null if none was specified; the whitespace in the public +identifier will have been normalized as required by the XML spec. +The context argument specifies the parsing context in the format +expected by the context argument to +XML_ExternalEntityParserCreate; context is valid only until the handler +returns, so if the referenced entity is to be parsed later, it must be copied. +The handler should return 0 if processing should not continue because of +a fatal error in the handling of the external entity. +In this case the calling parser will return an +XML_ERROR_EXTERNAL_ENTITY_HANDLING error. +Note that unlike other handlers the first argument is the parser, not +userData. */ + +typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This structure is filled in by the XML_UnknownEncodingHandler +to provide information to the parser about encodings that are unknown +to the parser. +The map[b] member gives information about byte sequences +whose first byte is b. +If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar +value c. +If map[b] is -1, then the byte sequence is malformed. +If map[b] is -n, where n >= 2, then b is the first byte of an n-byte +sequence that encodes a single Unicode scalar value. +The data member will be passed as the first argument to the convert function. +The convert function is used to convert multibyte sequences; +s will point to a n-byte sequence where map[(unsigned char)*s] == -n. +The convert function must return the Unicode scalar value +represented by this byte sequence or -1 if the byte sequence is malformed. +The convert function may be null if the encoding is a single-byte encoding, +that is if map[b] >= -1 for all bytes b. +When the parser is finished with the encoding, then if release is not null, +it will call release passing it the data member; +once release has been called, the convert function will not be called again. + +Expat places certain restrictions on the encodings that are supported +using this mechanism. + +1. Every ASCII character that can appear in a well-formed XML document, +other than the characters + + $@\^`{}~ + +must be represented by a single byte, and that byte must be the +same byte that represents that character in ASCII. + +2. No character may require more than 4 bytes to encode. + +3. All characters encoded must have Unicode scalar values <= 0xFFFF, +(ie characters that would be encoded by surrogates in UTF-16 +are not allowed). Note that this restriction doesn't apply to +the built-in support for UTF-8 and UTF-16. + +4. No Unicode character may be encoded by more than one distinct sequence +of bytes. */ + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. +The encodingHandlerData argument is that which was passed as the +second argument to XML_SetUnknownEncodingHandler. +The name argument gives the name of the encoding as specified in +the encoding declaration. +If the callback can provide information about the encoding, +it must fill in the XML_Encoding structure, and return 1. +Otherwise it must return 0. +If info does not describe a suitable encoding, +then the parser will return an XML_UNKNOWN_ENCODING error. */ + +typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +void XMLPARSEAPI +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +void XMLPARSEAPI +XML_SetStartElementHandler(XML_Parser, XML_StartElementHandler); + +void XMLPARSEAPI +XML_SetEndElementHandler(XML_Parser, XML_EndElementHandler); + +void XMLPARSEAPI +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +void XMLPARSEAPI +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +void XMLPARSEAPI +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +void XMLPARSEAPI +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +void XMLPARSEAPI +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +void XMLPARSEAPI +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of +internal entities. The entity reference will be passed to the default +handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of +internal entities. The entity reference will not be passed to the +default handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +void XMLPARSEAPI +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +void XMLPARSEAPI +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +void XMLPARSEAPI +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +void XMLPARSEAPI +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +void XMLPARSEAPI +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +void XMLPARSEAPI +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-null value for arg is specified here, then it will be passed +as the first argument to the external entity ref handler instead +of the parser object. */ +void XMLPARSEAPI +XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +void XMLPARSEAPI +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end element, +processing instruction or character data. It causes the corresponding +markup to be passed to the default handler. */ +void XMLPARSEAPI +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single + string separated by the separator character specified when the parser + was created: URI + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the names + has a prefix. +*/ + +void XMLPARSEAPI +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +void XMLPARSEAPI +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or null. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument +to XML_ParserCreate. It must not be called after XML_Parse +or XML_ParseBuffer. */ + +int XMLPARSEAPI +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed +as the first argument to callbacks instead of userData. +The userData will still be accessible using XML_GetUserData. */ + +void XMLPARSEAPI +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* Sets the base to be used for resolving relative URIs in system +identifiers in declarations. Resolving relative identifiers is left +to the application: this value will be passed through as the base +argument to the XML_ExternalEntityRefHandler, XML_NotationDeclHandler +and XML_UnparsedEntityDeclHandler. The base argument will be copied. +Returns zero if out of memory, non-zero otherwise. */ + +int XMLPARSEAPI +XML_SetBase(XML_Parser parser, const XML_Char *base); + +const XML_Char XMLPARSEAPI * +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call +to the XML_StartElementHandler that were specified in the start-tag +rather than defaulted. Each attribute/value pair counts as 2; thus +this correspondds to an index into the atts array passed to the +XML_StartElementHandler. */ + +int XMLPARSEAPI +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to +XML_StartElementHandler, or -1 if there is no ID attribute. Each +attribute/value pair counts as 2; thus this correspondds to an index +into the atts array passed to the XML_StartElementHandler. */ + +int XMLPARSEAPI +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns 0 if a fatal error is detected. +The last call to XML_Parse must have isFinal true; +len may be zero for this call (or any other). */ +int XMLPARSEAPI +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +void XMLPARSEAPI * +XML_GetBuffer(XML_Parser parser, int len); + +int XMLPARSEAPI +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general +entity; context is a '\0'-terminated string specifying the parse +context; encoding is a '\0'-terminated string giving the name of the +externally specified encoding, or null if there is no externally +specified encoding. The context string consists of a sequence of +tokens separated by formfeeds (\f); a token consisting of a name +specifies that the general entity of the name is open; a token of the +form prefix=uri specifies the namespace for a particular prefix; a +token of the form =uri specifies the default namespace. This can be +called at any point after the first call to an +ExternalEntityRefHandler so longer as the parser has not yet been +freed. The new parser is completely independent and may safely be +used in a separate thread. The handlers and userData are initialized +from the parser argument. Returns 0 if out of memory. Otherwise +returns a new XML_Parser object. */ +XML_Parser XMLPARSEAPI +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD +subset). If parsing of parameter entities is enabled, then references +to external parameter entities (including the external DTD subset) +will be passed to the handler set with +XML_SetExternalEntityRefHandler. The context passed will be 0. +Unlike external general entities, external parameter entities can only +be parsed synchronously. If the external parameter entity is to be +parsed, it must be parsed during the call to the external entity ref +handler: the complete sequence of XML_ExternalEntityParserCreate, +XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during +this call. After XML_ExternalEntityParserCreate has been called to +create the parser for the external parameter entity (context must be 0 +for this call), it is illegal to make any calls on the old parser +until XML_ParserFree has been called on the newly created parser. If +the library has been compiled without support for parameter entity +parsing (ie without XML_DTD being defined), then +XML_SetParamEntityParsing will return 0 if parsing of parameter +entities is requested; otherwise it will return non-zero. */ + +int XMLPARSEAPI +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE +}; + +/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode +returns information about the error. */ + +enum XML_Error XMLPARSEAPI +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse location. +They may be called when XML_Parse or XML_ParseBuffer return 0; +in this case the location is the location of the character at which +the error was detected. +They may also be called from any other callback called to report +some parse event; in this the location is the location of the first +of the sequence of characters that generated the event. */ + +int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser); +int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser); +long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. +Returns 0 if the event is in an internal entity. */ + +int XMLPARSEAPI +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a null pointer. Also returns a null pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. */ + +const char XMLPARSEAPI * +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees memory used by the parser. */ +void XMLPARSEAPI +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +const XML_LChar XMLPARSEAPI * +XML_ErrorString(int code); + +/* Return a string containing the version number of this expat */ +const XML_LChar XMLPARSEAPI * +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat */ + +XML_Expat_Version XMLPARSEAPI +XML_ExpatVersionInfo(void); + +#ifndef XML_MAJOR_VERSION +#define XML_MAJOR_VERSION 1 +#endif +#ifndef XML_MINOR_VERSION +#define XML_MINOR_VERSION 95 +#endif +#ifndef XML_MICRO_VERSION +#define XML_MICRO_VERSION 2 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/include/apr-linux/expat_external.h b/include/apr-linux/expat_external.h new file mode 100644 index 0000000..4145cac --- /dev/null +++ b/include/apr-linux/expat_external.h @@ -0,0 +1,92 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* External API definitions */ + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ diff --git a/include/apr/CVS/Entries b/include/apr/CVS/Entries new file mode 100644 index 0000000..4a752b3 --- /dev/null +++ b/include/apr/CVS/Entries @@ -0,0 +1,84 @@ +/api_version.h/1.1/Fri Nov 25 08:39:54 2005// +/apr.h/1.1/Fri Sep 30 06:39:34 2005// +/apr.h.in/1.1/Fri Sep 30 06:39:34 2005// +/apr.hnw/1.1/Fri Sep 30 06:39:34 2005// +/apr.hw/1.1/Tue May 30 11:03:54 2006// +/apr_allocator.h/1.1/Wed Dec 21 10:57:50 2005// +/apr_anylock.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_atomic.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_base64.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_buckets.h/1.1/Wed Nov 9 06:56:32 2005// +/apr_compat.h/1.1/Thu Sep 30 00:45:10 2004// +/apr_date.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_dbd.h/1.1/Tue May 30 11:03:54 2006// +/apr_dbm.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_dso.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_env.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_errno.h/1.1/Tue May 30 11:03:54 2006// +/apr_file_info.h/1.1/Tue May 30 11:03:54 2006// +/apr_file_io.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_fnmatch.h/1.1/Thu Sep 30 00:45:10 2004// +/apr_general.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_getopt.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_global_mutex.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_hash.h/1.1/Tue May 30 11:03:54 2006// +/apr_hooks.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_iconv.h/1.1/Fri Nov 25 08:40:00 2005// +/apr_inherit.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap.h.in/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap.hnw/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap.hw/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap_init.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap_option.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_ldap_rebind.h/1.1/Mon Mar 2 05:02:54 2015// +/apr_ldap_url.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_lib.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_md4.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_md5.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_memcache.h/1.1/Mon Mar 2 05:02:55 2015// +/apr_mmap.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_network_io.h/1.1/Tue May 30 11:03:54 2006// +/apr_optional.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_optional_hooks.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_poll.h/1.1/Tue May 30 11:03:54 2006// +/apr_pools.h/1.1/Wed Nov 9 06:56:04 2005// +/apr_portable.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_proc_mutex.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_queue.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_random.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_reslist.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_ring.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_rmm.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_sdbm.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_sha1.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_shm.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_signal.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_strings.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_strmatch.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_support.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_tables.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_thread_cond.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_thread_mutex.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_thread_pool.h/1.1/Mon Mar 2 05:02:56 2015// +/apr_thread_proc.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_thread_rwlock.h/1.1/Tue Dec 27 10:48:44 2005// +/apr_time.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_uri.h/1.1/Tue May 30 11:03:54 2006// +/apr_user.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_uuid.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_version.h/1.1/Tue May 30 11:03:54 2006// +/apr_want.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_xlate.h/1.1/Fri Sep 30 06:39:34 2005// +/apr_xml.h/1.1/Fri Sep 30 06:39:34 2005// +/apu.h/1.1/Fri Sep 30 06:39:34 2005// +/apu.h.in/1.1/Fri Sep 30 06:39:34 2005// +/apu.hnw/1.1/Fri Sep 30 06:39:34 2005// +/apu.hw/1.1/Fri Sep 30 06:39:34 2005// +/apu_version.h/1.1/Tue May 30 11:03:54 2006// +/apu_want.h/1.1/Fri Sep 30 06:39:34 2005// +/apu_want.h.in/1.1/Fri Sep 30 06:39:34 2005// +/apu_want.hnw/1.1/Fri Sep 30 06:39:34 2005// +/apu_want.hw/1.1/Fri Sep 30 06:39:34 2005// +/expat.h/1.1/Mon Mar 2 05:02:57 2015// +D diff --git a/include/apr/CVS/Entries.Extra b/include/apr/CVS/Entries.Extra new file mode 100644 index 0000000..91adda9 --- /dev/null +++ b/include/apr/CVS/Entries.Extra @@ -0,0 +1,83 @@ +/api_version.h////*//// +/apr.h////*//// +/apr.h.in////*//// +/apr.hnw////*//// +/apr.hw////*//// +/apr_allocator.h////*//// +/apr_anylock.h////*//// +/apr_atomic.h////*//// +/apr_base64.h////*//// +/apr_buckets.h////*//// +/apr_compat.h////*//// +/apr_date.h////*//// +/apr_dbd.h////*//// +/apr_dbm.h////*//// +/apr_dso.h////*//// +/apr_env.h////*//// +/apr_errno.h////*//// +/apr_file_info.h////*//// +/apr_file_io.h////*//// +/apr_fnmatch.h////*//// +/apr_general.h////*//// +/apr_getopt.h////*//// +/apr_global_mutex.h////*//// +/apr_hash.h////*//// +/apr_hooks.h////*//// +/apr_iconv.h////*//// +/apr_inherit.h////*//// +/apr_ldap.h////*//// +/apr_ldap.h.in////*//// +/apr_ldap.hnw////*//// +/apr_ldap.hw////*//// +/apr_ldap_init.h////*//// +/apr_ldap_option.h////*//// +/apr_ldap_rebind.h////*//// +/apr_ldap_url.h////*//// +/apr_lib.h////*//// +/apr_md4.h////*//// +/apr_md5.h////*//// +/apr_memcache.h////*//// +/apr_mmap.h////*//// +/apr_network_io.h////*//// +/apr_optional.h////*//// +/apr_optional_hooks.h////*//// +/apr_poll.h////*//// +/apr_pools.h////*//// +/apr_portable.h////*//// +/apr_proc_mutex.h////*//// +/apr_queue.h////*//// +/apr_random.h////*//// +/apr_reslist.h////*//// +/apr_ring.h////*//// +/apr_rmm.h////*//// +/apr_sdbm.h////*//// +/apr_sha1.h////*//// +/apr_shm.h////*//// +/apr_signal.h////*//// +/apr_strings.h////*//// +/apr_strmatch.h////*//// +/apr_support.h////*//// +/apr_tables.h////*//// +/apr_thread_cond.h////*//// +/apr_thread_mutex.h////*//// +/apr_thread_pool.h////*//// +/apr_thread_proc.h////*//// +/apr_thread_rwlock.h////*//// +/apr_time.h////*//// +/apr_uri.h////*//// +/apr_user.h////*//// +/apr_uuid.h////*//// +/apr_version.h////*//// +/apr_want.h////*//// +/apr_xlate.h////*//// +/apr_xml.h////*//// +/apu.h////*//// +/apu.h.in////*//// +/apu.hnw////*//// +/apu.hw////*//// +/apu_version.h////*//// +/apu_want.h////*//// +/apu_want.h.in////*//// +/apu_want.hnw////*//// +/apu_want.hw////*//// +/expat.h////*//// diff --git a/include/apr/CVS/Entries.Extra.Old b/include/apr/CVS/Entries.Extra.Old new file mode 100644 index 0000000..91adda9 --- /dev/null +++ b/include/apr/CVS/Entries.Extra.Old @@ -0,0 +1,83 @@ +/api_version.h////*//// +/apr.h////*//// +/apr.h.in////*//// +/apr.hnw////*//// +/apr.hw////*//// +/apr_allocator.h////*//// +/apr_anylock.h////*//// +/apr_atomic.h////*//// +/apr_base64.h////*//// +/apr_buckets.h////*//// +/apr_compat.h////*//// +/apr_date.h////*//// +/apr_dbd.h////*//// +/apr_dbm.h////*//// +/apr_dso.h////*//// +/apr_env.h////*//// +/apr_errno.h////*//// +/apr_file_info.h////*//// +/apr_file_io.h////*//// +/apr_fnmatch.h////*//// +/apr_general.h////*//// +/apr_getopt.h////*//// +/apr_global_mutex.h////*//// +/apr_hash.h////*//// +/apr_hooks.h////*//// +/apr_iconv.h////*//// +/apr_inherit.h////*//// +/apr_ldap.h////*//// +/apr_ldap.h.in////*//// +/apr_ldap.hnw////*//// +/apr_ldap.hw////*//// +/apr_ldap_init.h////*//// +/apr_ldap_option.h////*//// +/apr_ldap_rebind.h////*//// +/apr_ldap_url.h////*//// +/apr_lib.h////*//// +/apr_md4.h////*//// +/apr_md5.h////*//// +/apr_memcache.h////*//// +/apr_mmap.h////*//// +/apr_network_io.h////*//// +/apr_optional.h////*//// +/apr_optional_hooks.h////*//// +/apr_poll.h////*//// +/apr_pools.h////*//// +/apr_portable.h////*//// +/apr_proc_mutex.h////*//// +/apr_queue.h////*//// +/apr_random.h////*//// +/apr_reslist.h////*//// +/apr_ring.h////*//// +/apr_rmm.h////*//// +/apr_sdbm.h////*//// +/apr_sha1.h////*//// +/apr_shm.h////*//// +/apr_signal.h////*//// +/apr_strings.h////*//// +/apr_strmatch.h////*//// +/apr_support.h////*//// +/apr_tables.h////*//// +/apr_thread_cond.h////*//// +/apr_thread_mutex.h////*//// +/apr_thread_pool.h////*//// +/apr_thread_proc.h////*//// +/apr_thread_rwlock.h////*//// +/apr_time.h////*//// +/apr_uri.h////*//// +/apr_user.h////*//// +/apr_uuid.h////*//// +/apr_version.h////*//// +/apr_want.h////*//// +/apr_xlate.h////*//// +/apr_xml.h////*//// +/apu.h////*//// +/apu.h.in////*//// +/apu.hnw////*//// +/apu.hw////*//// +/apu_version.h////*//// +/apu_want.h////*//// +/apu_want.h.in////*//// +/apu_want.hnw////*//// +/apu_want.hw////*//// +/expat.h////*//// diff --git a/include/apr/CVS/Entries.Old b/include/apr/CVS/Entries.Old new file mode 100644 index 0000000..07e00d6 --- /dev/null +++ b/include/apr/CVS/Entries.Old @@ -0,0 +1,84 @@ +/api_version.h/0/dummy timestamp// +/apr.h/0/dummy timestamp// +/apr.h.in/0/dummy timestamp// +/apr.hnw/0/dummy timestamp// +/apr.hw/0/dummy timestamp// +/apr_allocator.h/0/dummy timestamp// +/apr_anylock.h/0/dummy timestamp// +/apr_atomic.h/0/dummy timestamp// +/apr_base64.h/0/dummy timestamp// +/apr_buckets.h/0/dummy timestamp// +/apr_compat.h/0/dummy timestamp// +/apr_date.h/0/dummy timestamp// +/apr_dbd.h/0/dummy timestamp// +/apr_dbm.h/0/dummy timestamp// +/apr_dso.h/0/dummy timestamp// +/apr_env.h/0/dummy timestamp// +/apr_errno.h/0/dummy timestamp// +/apr_file_info.h/0/dummy timestamp// +/apr_file_io.h/0/dummy timestamp// +/apr_fnmatch.h/0/dummy timestamp// +/apr_general.h/0/dummy timestamp// +/apr_getopt.h/0/dummy timestamp// +/apr_global_mutex.h/0/dummy timestamp// +/apr_hash.h/0/dummy timestamp// +/apr_hooks.h/0/dummy timestamp// +/apr_iconv.h/0/dummy timestamp// +/apr_inherit.h/0/dummy timestamp// +/apr_ldap.h/0/dummy timestamp// +/apr_ldap.h.in/0/dummy timestamp// +/apr_ldap.hnw/0/dummy timestamp// +/apr_ldap.hw/0/dummy timestamp// +/apr_ldap_init.h/0/dummy timestamp// +/apr_ldap_option.h/0/dummy timestamp// +/apr_ldap_rebind.h/0/dummy timestamp// +/apr_ldap_url.h/0/dummy timestamp// +/apr_lib.h/0/dummy timestamp// +/apr_md4.h/0/dummy timestamp// +/apr_md5.h/0/dummy timestamp// +/apr_memcache.h/0/dummy timestamp// +/apr_mmap.h/0/dummy timestamp// +/apr_network_io.h/0/dummy timestamp// +/apr_optional.h/0/dummy timestamp// +/apr_optional_hooks.h/0/dummy timestamp// +/apr_poll.h/0/dummy timestamp// +/apr_pools.h/0/dummy timestamp// +/apr_portable.h/0/dummy timestamp// +/apr_proc_mutex.h/0/dummy timestamp// +/apr_queue.h/0/dummy timestamp// +/apr_random.h/0/dummy timestamp// +/apr_reslist.h/0/dummy timestamp// +/apr_ring.h/0/dummy timestamp// +/apr_rmm.h/0/dummy timestamp// +/apr_sdbm.h/0/dummy timestamp// +/apr_sha1.h/0/dummy timestamp// +/apr_shm.h/0/dummy timestamp// +/apr_signal.h/0/dummy timestamp// +/apr_strings.h/0/dummy timestamp// +/apr_strmatch.h/0/dummy timestamp// +/apr_support.h/0/dummy timestamp// +/apr_tables.h/0/dummy timestamp// +/apr_thread_cond.h/0/dummy timestamp// +/apr_thread_mutex.h/0/dummy timestamp// +/apr_thread_pool.h/0/dummy timestamp// +/apr_thread_proc.h/0/dummy timestamp// +/apr_thread_rwlock.h/0/dummy timestamp// +/apr_time.h/0/dummy timestamp// +/apr_uri.h/0/dummy timestamp// +/apr_user.h/0/dummy timestamp// +/apr_uuid.h/0/dummy timestamp// +/apr_version.h/0/dummy timestamp// +/apr_want.h/0/dummy timestamp// +/apr_xlate.h/0/dummy timestamp// +/apr_xml.h/0/dummy timestamp// +/apu.h/0/dummy timestamp// +/apu.h.in/0/dummy timestamp// +/apu.hnw/0/dummy timestamp// +/apu.hw/0/dummy timestamp// +/apu_version.h/0/dummy timestamp// +/apu_want.h/0/dummy timestamp// +/apu_want.h.in/0/dummy timestamp// +/apu_want.hnw/0/dummy timestamp// +/apu_want.hw/0/dummy timestamp// +/expat.h/0/dummy timestamp// +D diff --git a/include/apr/CVS/Repository b/include/apr/CVS/Repository new file mode 100644 index 0000000..4c865c8 --- /dev/null +++ b/include/apr/CVS/Repository @@ -0,0 +1 @@ +jspqfe/src/pt61850netd_pqfe/source/include/apr diff --git a/include/apr/CVS/Root b/include/apr/CVS/Root new file mode 100644 index 0000000..0536776 --- /dev/null +++ b/include/apr/CVS/Root @@ -0,0 +1 @@ +:ext:lizhongming@10.0.0.2:/JoyProject diff --git a/include/apr/CVS/Template b/include/apr/CVS/Template new file mode 100644 index 0000000..e69de29 diff --git a/include/apr/api_version.h b/include/apr/api_version.h new file mode 100644 index 0000000..84957eb --- /dev/null +++ b/include/apr/api_version.h @@ -0,0 +1,132 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +#ifndef API_VERSION_H +#define API_VERSION_H + +/** + * @file api_version.h + * @brief APR-iconv Versioning Interface + * + * APR-iconv's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of API by use of the compile-time + * constants and the use of the run-time query function. + * + * API version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for API. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define API_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading API_MAJOR_VERSION + */ +#define API_MINOR_VERSION 1 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading API_MINOR_VERSION + */ +#define API_PATCH_VERSION 1 + +/** + * The symbol API_IS_DEV_VERSION is only defined for internal, + * "development" copies of API. It is undefined for released versions + * of API. + */ +/* #define API_IS_DEV_VERSION */ + + +#if defined(API_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define API_IS_DEV_STRING "-dev" +#else +#define API_IS_DEV_STRING "" +#endif + +#ifndef API_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define API_STRINGIFY(n) API_STRINGIFY_HELPER(n) +/** Helper macro for API_STRINGIFY */ +#define API_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of API's version */ +#define API_VERSION_STRING \ + API_STRINGIFY(API_MAJOR_VERSION) "." \ + API_STRINGIFY(API_MINOR_VERSION) "." \ + API_STRINGIFY(API_PATCH_VERSION) \ + API_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define API_VERSION_STRING_CSV API_MAJOR_VERSION ##, \ + ##API_MINOR_VERSION ##, \ + ##API_PATCH_VERSION + + +#ifndef API_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. API_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr_version.h" + +#include "apr_iconv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return APR-iconv's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +API_DECLARE(void) api_version(apr_version_t *pvsn); + +/** Return API's version information as a string. */ +API_DECLARE(const char *) api_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef API_VERSION_ONLY */ + +#endif /* ndef API_VERSION_H */ diff --git a/include/apr/apr.h b/include/apr/apr.h new file mode 100644 index 0000000..1a3c674 --- /dev/null +++ b/include/apr/apr.h @@ -0,0 +1,511 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.hw instead. + * + * And please, make an effort to stub apr.hnw and apr.h.in in the process. + * + * This is the Win32 specific version of apr.h. It is copied from + * apr.hw by the apr.dsp and libapr.dsp projects. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +#if defined(WIN32) || defined(DOXYGEN) + +/* Ignore most warnings (back down to /W3) for poorly constructed headers + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(push, 3) +#endif + +/* disable or reduce the frequency of... + * C4057: indirection to slightly different base types + * C4075: slight indirection changes (unsigned short* vs short[]) + * C4100: unreferenced formal parameter + * C4127: conditional expression is constant + * C4163: '_rotl64' : not available as an intrinsic function + * C4201: nonstandard extension nameless struct/unions + * C4244: int to char/short - precision loss + * C4514: unreferenced inline function removed + */ +#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) + +/* Has windows.h already been included? If so, our preferences don't matter, + * but we will still need the winsock things no matter what was included. + * If not, include a restricted set of windows headers to our tastes. + */ +#ifndef _WINDOWS_ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef _WIN32_WINNT + +/* Restrict the server to a subset of Windows NT 4.0 header files by default + */ +#define _WIN32_WINNT 0x0400 +#endif +#ifndef NOUSER +#define NOUSER +#endif +#ifndef NOMCX +#define NOMCX +#endif +#ifndef NOIME +#define NOIME +#endif +#include +/* + * Add a _very_few_ declarations missing from the restricted set of headers + * (If this list becomes extensive, re-enable the required headers above!) + * winsock headers were excluded by WIN32_LEAN_AND_MEAN, so include them now + */ +#define SW_HIDE 0 +#ifndef _WIN32_WCE +#include +#include +#include +#else +#include +#endif +#endif /* !_WINDOWS_ */ + +/** + * @defgroup apr_platform Platform Definitions + * @ingroup APR + * @{ + */ + +#define APR_INLINE __inline +#define APR_HAS_INLINE 1 +#ifndef __attribute__ +#define __attribute__(__x) +#endif + +#ifndef _WIN32_WCE +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H 1 +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H 1 +#define APR_HAVE_DIRENT_H 0 +#define APR_HAVE_ERRNO_H 1 +#define APR_HAVE_FCNTL_H 1 +#define APR_HAVE_IO_H 1 +#define APR_HAVE_LIMITS_H 1 +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SIGNAL_H 1 +#define APR_HAVE_STDARG_H 1 +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SIGNAL_H 0 +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#define APR_HAVE_SYS_TYPES_H 1 +#define APR_HAVE_SYS_UIO_H 0 +#define APR_HAVE_SYS_WAIT_H 0 +#define APR_HAVE_UNISTD_H 0 +#define APR_HAVE_STDDEF_H 1 +#define APR_HAVE_PROCESS_H 1 +#define APR_HAVE_TIME_H 1 +#else +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H 0 +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H 0 +#define APR_HAVE_DIRENT_H 0 +#define APR_HAVE_ERRNO_H 0 +#define APR_HAVE_FCNTL_H 0 +#define APR_HAVE_IO_H 0 +#define APR_HAVE_LIMITS_H 0 +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SIGNAL_H 0 +#define APR_HAVE_STDARG_H 0 +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SIGNAL_H 0 +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#define APR_HAVE_SYS_TYPES_H 0 +#define APR_HAVE_SYS_UIO_H 0 +#define APR_HAVE_SYS_WAIT_H 0 +#define APR_HAVE_UNISTD_H 0 +#define APR_HAVE_STDDEF_H 0 +#define APR_HAVE_PROCESS_H 0 +#define APR_HAVE_TIME_H 0 +#endif + +#define APR_USE_FLOCK_SERIALIZE 0 +#define APR_USE_SYSVSEM_SERIALIZE 0 +#define APR_USE_FCNTL_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 0 + +#define APR_HAS_FLOCK_SERIALIZE 0 +#define APR_HAS_SYSVSEM_SERIALIZE 0 +#define APR_HAS_FCNTL_SERIALIZE 0 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 +#define APR_HAS_RWLOCK_SERIALIZE 0 + +#define APR_HAS_LOCK_CREATE_NP 0 + +#define APR_PROCESS_LOCK_IS_GLOBAL 0 + +#define APR_USES_ANONYMOUS_SHM 0 +#define APR_USES_FILEBASED_SHM 0 +#define APR_USES_KEYBASED_SHM 0 + +#define APR_FILE_BASED_SHM 0 +#define APR_MEM_BASED_SHM 0 + +#define APR_HAVE_CORKABLE_TCP 0 +#define APR_HAVE_GETRLIMIT 0 +#define APR_HAVE_ICONV 0 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 0 +#define APR_HAVE_IPV6 0 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 0 +#define APR_HAVE_SIGACTION 0 +#define APR_HAVE_SIGSUSPEND 0 +#define APR_HAVE_SIGWAIT 0 +#define APR_HAVE_STRCASECMP 0 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRNCASECMP 0 +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_STRUCT_RLIMIT 0 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 + +#ifndef _WIN32_WCE +#define APR_HAVE_STRICMP 1 +#define APR_HAVE_STRNICMP 1 +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 1 +#else +#define APR_HAVE_STRICMP 0 +#define APR_HAVE_STRNICMP 0 +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 +#endif + +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_STDIO_H +#include +#endif +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#if APR_HAVE_STDDEF_H +#include +#endif +#if APR_HAVE_TIME_H +#include +#endif +#if APR_HAVE_PROCESS_H +#include +#endif +#if APR_HAVE_IPV6 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY 1 +#define APR_HAS_THREADS 1 +#define APR_HAS_MMAP 1 +#define APR_HAS_FORK 0 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 1 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 1 +#define APR_HAS_PROC_INVOKED 1 +#ifndef _WIN32_WCE +#define APR_HAS_SENDFILE 1 +#define APR_HAS_USER 1 +#define APR_HAS_LARGE_FILES 1 +#define APR_HAS_XTHREAD_FILES 1 +#else +#define APR_HAS_SENDFILE 0 +#define APR_HAS_USER 0 +#define APR_HAS_LARGE_FILES 0 +#define APR_HAS_XTHREAD_FILES 0 +#endif +#define APR_HAS_OS_UUID 1 + +/* Win32 cannot poll [just yet] on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 0 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* Is the TCP_NODELAY socket option inherited from listening sockets? + */ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? + */ +#define APR_O_NONBLOCK_INHERITED 1 + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef __int64 apr_int64_t; +typedef unsigned __int64 apr_uint64_t; + +typedef size_t apr_size_t; +#if APR_HAVE_STDDEF_H +typedef ptrdiff_t apr_ssize_t; +#else +typedef int apr_ssize_t; +#endif +#if APR_HAS_LARGE_FILES +typedef __int64 apr_off_t; +#else +typedef int apr_off_t; +#endif +typedef int apr_socklen_t; + +/* Are we big endian? */ +/* XXX: Fatal assumption on Alpha platforms */ +#define APR_IS_BIGENDIAN 0 + +#ifdef WIN64 +#define APR_SIZEOF_VOIDP 8 +#else +#define APR_SIZEOF_VOIDP 4 +#endif + +/* XXX These simply don't belong here, perhaps in apr_portable.h + * based on some APR_HAVE_PID/GID/UID? + */ +typedef int pid_t; +typedef int uid_t; +typedef int gid_t; + +/* Mechanisms to properly type numeric literals */ + +#define APR_INT64_C(val) (val##i64) +#define APR_UINT64_C(val) (val##Ui64) + + +#if APR_HAVE_IPV6 + +/* Appears in later flavors, not the originals. */ +#ifndef in_addr6 +#define in6_addr in_addr6 +#endif + +#ifndef WS2TCPIP_INLINE +#define IN6_IS_ADDR_V4MAPPED(a) \ + ( (*(const apr_uint64_t *)(const void *)(&(a)->s6_addr[0]) == 0) \ + && (*(const apr_uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) +#endif + +#endif /* APR_HAS_IPV6 */ + +/* Definitions that APR programs need to work properly. */ + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * @example + */ +/** void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + */ +#define APR_THREAD_FUNC __stdcall + + +#if defined(DOXYGEN) || !defined(WIN32) + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE(rettype) apr_func(args) + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with AP_MODULE_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * @example + */ +/** extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + */ +#define APR_DECLARE_DATA + +#elif defined(APR_DECLARE_STATIC) +#define APR_DECLARE(type) type __stdcall +#define APR_DECLARE_NONSTD(type) type __cdecl +#define APR_DECLARE_DATA +#elif defined(APR_DECLARE_EXPORT) +#define APR_DECLARE(type) __declspec(dllexport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllexport) +#else +#define APR_DECLARE(type) __declspec(dllimport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllimport) +#endif + +#ifdef WIN64 +#define APR_SSIZE_T_FMT "I64d" +#define APR_SIZE_T_FMT "I64d" +#else +#define APR_SSIZE_T_FMT "d" +#define APR_SIZE_T_FMT "d" +#endif + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_FMT "I64d" +#else +#define APR_OFF_T_FMT "d" +#endif + +#define APR_PID_T_FMT "d" + +#define APR_INT64_T_FMT "I64d" +#define APR_UINT64_T_FMT "I64u" +#define APR_UINT64_T_HEX_FMT "I64x" + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\r\n" + +/* No difference between PROC and GLOBAL mutex */ +#define APR_PROC_MUTEX_IS_GLOBAL 1 + +typedef int apr_wait_t; + +/* struct iovec is needed to emulate Unix writev */ +struct iovec { + char* iov_base; + apr_size_t iov_len; +}; + +/* Nasty Win32 .h ommissions we really need */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#if APR_HAS_UNICODE_FS +/* An arbitrary size that is digestable. True max is a bit less than 32000 */ +#define APR_PATH_MAX 8192 +#else /* !APR_HAS_UNICODE_FS */ +#define APR_PATH_MAX MAX_PATH +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/* Done with badly written headers + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(pop) +#endif + +#endif /* WIN32 */ + +#endif /* APR_H */ diff --git a/include/apr/apr.h.in b/include/apr/apr.h.in new file mode 100644 index 0000000..87869b8 --- /dev/null +++ b/include/apr/apr.h.in @@ -0,0 +1,398 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.h.in instead. + * + * And please, make an effort to stub apr.hw and apr.hnw in the process. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/** + * @defgroup APR Apache Portability Runtime library + * @{ + */ +/** + * @defgroup apr_platform Platform Definitions + * @{ + */ + +/* So that we can use inline on some critical functions, and use + * GNUC attributes (such as to get -Wall warnings for printf-like + * functions). Only do this in gcc 2.7 or later ... it may work + * on earlier stuff, but why chance it. + * + * We've since discovered that the gcc shipped with NeXT systems + * as "cc" is completely broken. It claims to be __GNUC__ and so + * on, but it doesn't implement half of the things that __GNUC__ + * means. In particular it's missing inline and the __attribute__ + * stuff. So we hack around it. PR#1613. -djg + */ +#if !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ + defined(NEXT) +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#define APR_INLINE +#define APR_HAS_INLINE 0 +#else +#define APR_INLINE __inline__ +#define APR_HAS_INLINE 1 +#endif + +#define APR_HAVE_ARPA_INET_H @arpa_ineth@ +#define APR_HAVE_CONIO_H @conioh@ +#define APR_HAVE_CRYPT_H @crypth@ +#define APR_HAVE_CTYPE_H @ctypeh@ +#define APR_HAVE_DIRENT_H @direnth@ +#define APR_HAVE_ERRNO_H @errnoh@ +#define APR_HAVE_FCNTL_H @fcntlh@ +#define APR_HAVE_IO_H @ioh@ +#define APR_HAVE_LIMITS_H @limitsh@ +#define APR_HAVE_NETDB_H @netdbh@ +#define APR_HAVE_NETINET_IN_H @netinet_inh@ +#define APR_HAVE_NETINET_SCTP_H @netinet_sctph@ +#define APR_HAVE_NETINET_SCTP_UIO_H @netinet_sctp_uioh@ +#define APR_HAVE_NETINET_TCP_H @netinet_tcph@ +#define APR_HAVE_PTHREAD_H @pthreadh@ +#define APR_HAVE_SEMAPHORE_H @semaphoreh@ +#define APR_HAVE_SIGNAL_H @signalh@ +#define APR_HAVE_STDARG_H @stdargh@ +#define APR_HAVE_STDINT_H @stdint@ +#define APR_HAVE_STDIO_H @stdioh@ +#define APR_HAVE_STDLIB_H @stdlibh@ +#define APR_HAVE_STRING_H @stringh@ +#define APR_HAVE_STRINGS_H @stringsh@ +#define APR_HAVE_SYS_IOCTL_H @sys_ioctlh@ +#define APR_HAVE_SYS_SENDFILE_H @sys_sendfileh@ +#define APR_HAVE_SYS_SIGNAL_H @sys_signalh@ +#define APR_HAVE_SYS_SOCKET_H @sys_socketh@ +#define APR_HAVE_SYS_SOCKIO_H @sys_sockioh@ +#define APR_HAVE_SYS_SYSLIMITS_H @sys_syslimitsh@ +#define APR_HAVE_SYS_TIME_H @sys_timeh@ +#define APR_HAVE_SYS_TYPES_H @sys_typesh@ +#define APR_HAVE_SYS_UIO_H @sys_uioh@ +#define APR_HAVE_SYS_UN_H @sys_unh@ +#define APR_HAVE_SYS_WAIT_H @sys_waith@ +#define APR_HAVE_TIME_H @timeh@ +#define APR_HAVE_UNISTD_H @unistdh@ + +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +#if APR_HAVE_SYS_TYPES_H +#include +#endif + +#if APR_HAVE_SYS_SOCKET_H +#include +#endif + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +/* C99 7.18.4 requires that stdint.h only exposes INT64_C + * and UINT64_C for C++ implementations if this is defined: */ +#define __STDC_CONSTANT_MACROS +#endif + +#if APR_HAVE_STDINT_H +#include +#endif + +#if APR_HAVE_SYS_WAIT_H +#include +#endif + +#ifdef OS2 +#define INCL_DOS +#define INCL_DOSERRORS +#include +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include +#endif +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +#define APR_HAVE_SHMEM_MMAP_TMP @havemmaptmp@ +#define APR_HAVE_SHMEM_MMAP_SHM @havemmapshm@ +#define APR_HAVE_SHMEM_MMAP_ZERO @havemmapzero@ +#define APR_HAVE_SHMEM_SHMGET_ANON @haveshmgetanon@ +#define APR_HAVE_SHMEM_SHMGET @haveshmget@ +#define APR_HAVE_SHMEM_MMAP_ANON @havemmapanon@ +#define APR_HAVE_SHMEM_BEOS @havebeosarea@ + +#define APR_USE_SHMEM_MMAP_TMP @usemmaptmp@ +#define APR_USE_SHMEM_MMAP_SHM @usemmapshm@ +#define APR_USE_SHMEM_MMAP_ZERO @usemmapzero@ +#define APR_USE_SHMEM_SHMGET_ANON @useshmgetanon@ +#define APR_USE_SHMEM_SHMGET @useshmget@ +#define APR_USE_SHMEM_MMAP_ANON @usemmapanon@ +#define APR_USE_SHMEM_BEOS @usebeosarea@ + +#define APR_USE_FLOCK_SERIALIZE @flockser@ +#define APR_USE_SYSVSEM_SERIALIZE @sysvser@ +#define APR_USE_POSIXSEM_SERIALIZE @posixser@ +#define APR_USE_FCNTL_SERIALIZE @fcntlser@ +#define APR_USE_PROC_PTHREAD_SERIALIZE @procpthreadser@ +#define APR_USE_PTHREAD_SERIALIZE @pthreadser@ + +#define APR_HAS_FLOCK_SERIALIZE @hasflockser@ +#define APR_HAS_SYSVSEM_SERIALIZE @hassysvser@ +#define APR_HAS_POSIXSEM_SERIALIZE @hasposixser@ +#define APR_HAS_FCNTL_SERIALIZE @hasfcntlser@ +#define APR_HAS_PROC_PTHREAD_SERIALIZE @hasprocpthreadser@ + +#define APR_PROCESS_LOCK_IS_GLOBAL @proclockglobal@ + +#define APR_HAVE_CORKABLE_TCP @have_corkable_tcp@ +#define APR_HAVE_GETRLIMIT @have_getrlimit@ +#define APR_HAVE_IN_ADDR @have_in_addr@ +#define APR_HAVE_INET_ADDR @have_inet_addr@ +#define APR_HAVE_INET_NETWORK @have_inet_network@ +#define APR_HAVE_IPV6 @have_ipv6@ +#define APR_HAVE_MEMMOVE @have_memmove@ +#define APR_HAVE_SETRLIMIT @have_setrlimit@ +#define APR_HAVE_SIGACTION @have_sigaction@ +#define APR_HAVE_SIGSUSPEND @have_sigsuspend@ +#define APR_HAVE_SIGWAIT @have_sigwait@ +#define APR_HAVE_SA_STORAGE @have_sa_storage@ +#define APR_HAVE_STRCASECMP @have_strcasecmp@ +#define APR_HAVE_STRDUP @have_strdup@ +#define APR_HAVE_STRICMP @have_stricmp@ +#define APR_HAVE_STRNCASECMP @have_strncasecmp@ +#define APR_HAVE_STRNICMP @have_strnicmp@ +#define APR_HAVE_STRSTR @have_strstr@ +#define APR_HAVE_MEMCHR @have_memchr@ +#define APR_HAVE_STRUCT_RLIMIT @struct_rlimit@ +#define APR_HAVE_UNION_SEMUN @have_union_semun@ +#define APR_HAVE_SCTP @have_sctp@ + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY @sharedmem@ +#define APR_HAS_THREADS @threads@ +#define APR_HAS_SENDFILE @sendfile@ +#define APR_HAS_MMAP @mmap@ +#define APR_HAS_FORK @fork@ +#define APR_HAS_RANDOM @rand@ +#define APR_HAS_OTHER_CHILD @oc@ +#define APR_HAS_DSO @aprdso@ +#define APR_HAS_SO_ACCEPTFILTER @acceptfilter@ +#define APR_HAS_UNICODE_FS 0 +#define APR_HAS_PROC_INVOKED 0 +#define APR_HAS_USER 1 +#define APR_HAS_LARGE_FILES @aprlfs@ +#define APR_HAS_XTHREAD_FILES 0 +#define APR_HAS_OS_UUID @osuuid@ + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 + +/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible + * to poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS @file_as_socket@ + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC @apr_charset_ebcdic@ + +/* If we have a TCP implementation that can be "corked", what flag + * do we use? + */ +#define APR_TCP_NOPUSH_FLAG @apr_tcp_nopush_flag@ + +/* Is the TCP_NODELAY socket option inherited from listening sockets? +*/ +#define APR_TCP_NODELAY_INHERITED @tcp_nodelay_inherited@ + +/* Is the O_NONBLOCK flag inherited from listening sockets? +*/ +#define APR_O_NONBLOCK_INHERITED @o_nonblock_inherited@ + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef @short_value@ apr_int16_t; +typedef unsigned @short_value@ apr_uint16_t; + +typedef @int_value@ apr_int32_t; +typedef unsigned @int_value@ apr_uint32_t; + +typedef @long_value@ apr_int64_t; +typedef unsigned @long_value@ apr_uint64_t; + +typedef @size_t_value@ apr_size_t; +typedef @ssize_t_value@ apr_ssize_t; +typedef @off_t_value@ apr_off_t; +typedef @socklen_t_value@ apr_socklen_t; + +#define APR_SIZEOF_VOIDP @voidp_size@ + +/* Are we big endian? */ +#define APR_IS_BIGENDIAN @bigendian@ + +/* Mechanisms to properly type numeric literals */ +@int64_literal@ +@uint64_literal@ + +/* Definitions that APR programs need to work properly. */ + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * @example + */ +/** void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + */ +#define APR_THREAD_FUNC + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE(rettype) apr_func(args) + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with AP_MODULE_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * @example + */ +/** extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + */ +#define APR_DECLARE_DATA + +/* Define APR_SSIZE_T_FMT. + * If ssize_t is an integer we define it to be "d", + * if ssize_t is a long int we define it to be "ld", + * if ssize_t is neither we declare an error here. + * I looked for a better way to define this here, but couldn't find one, so + * to find the logic for this definition search for "ssize_t_fmt" in + * configure.in. + */ +@ssize_t_fmt@ + +/* And APR_SIZE_T_FMT */ +@size_t_fmt@ + +/* And APR_OFF_T_FMT */ +@off_t_fmt@ + +/* And APR_PID_T_FMT */ +@pid_t_fmt@ + +/* And APR_INT64_T_FMT */ +@int64_t_fmt@ + +/* And APR_UINT64_T_FMT */ +@uint64_t_fmt@ + +/* And APR_UINT64_T_HEX_FMT */ +@uint64_t_hex_fmt@ + +/* Does the proc mutex lock threads too */ +#define APR_PROC_MUTEX_IS_GLOBAL @proc_mutex_is_global@ + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "@eolstr@" + + +#if APR_HAVE_SYS_WAIT_H +#ifdef WEXITSTATUS +#define apr_wait_t int +#else +#define apr_wait_t union wait +#define WEXITSTATUS(status) (int)((status).w_retcode) +#define WTERMSIG(status) (int)((status).w_termsig) +#endif /* !WEXITSTATUS */ +#endif /* HAVE_SYS_WAIT_H */ + +#if defined(PATH_MAX) +#define APR_PATH_MAX PATH_MAX +#elif defined(_POSIX_PATH_MAX) +#define APR_PATH_MAX _POSIX_PATH_MAX +#else +#error no decision has been made on APR_PATH_MAX for your platform +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_H */ diff --git a/include/apr/apr.hnw b/include/apr/apr.hnw new file mode 100644 index 0000000..a907a87 --- /dev/null +++ b/include/apr/apr.hnw @@ -0,0 +1,365 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.hnw instead. + * + * And please, make an effort to stub apr.hw and apr.h.in in the process. + * + * This is the NetWare specific version of apr.h. It is copied from + * apr.hnw at the start of a NetWare build by prebuildNW.bat. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +#if defined(NETWARE) || defined(DOXYGEN) + +#define FD_SETSIZE 1024 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_WINSOCK +#include +#else +#include +#endif +#include + +#ifdef NW_BUILD_IPV6 +#include +#endif + +#define _POSIX_THREAD_SAFE_FUNCTIONS 1 +#define READDIR_IS_THREAD_SAFE 1 + +/* Keep #include'd headers from within the __cplusplus or doxyblocks */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_platform Platform Definitions + * @ingroup APR + * @{ + */ + +#define APR_INLINE +#define APR_HAS_INLINE 0 +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#define ENUM_BITFIELD(e,n,w) signed int n : w + +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H 0 +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H 1 +#define APR_HAVE_DIRENT_H 1 +#define APR_HAVE_ERRNO_H 1 +#define APR_HAVE_FCNTL_H 1 +#define APR_HAVE_IO_H 0 +#define APR_HAVE_LIMITS_H 1 +#ifdef USE_WINSOCK +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#else +#define APR_HAVE_ARPA_INET_H 1 +#define APR_HAVE_NETDB_H 1 +#define APR_HAVE_NETINET_IN_H 1 +#endif +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SIGNAL_H 1 +#define APR_HAVE_STDARG_H 1 +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_STRTOLL 1 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#ifdef USE_WINSOCK +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#else +#define APR_HAVE_SYS_SOCKET_H 1 +#define APR_HAVE_SYS_SOCKIO_H 1 +#define APR_HAVE_SYS_TIME_H 1 +#endif +#define APR_HAVE_SYS_SIGNAL_H 1 +#define APR_HAVE_SYS_TYPES_H 1 +#define APR_HAVE_SYS_UIO_H 1 +#define APR_HAVE_SYS_UN_H 1 +#define APR_HAVE_SYS_WAIT_H 1 +#define APR_HAVE_TIME_H 1 +#define APR_HAVE_UNISTD_H 1 + +#define APR_HAVE_SHMEM_MMAP_TMP 0 +#define APR_HAVE_SHMEM_MMAP_SHM 0 +#define APR_HAVE_SHMEM_MMAP_ZERO 0 +#define APR_HAVE_SHMEM_SHMGET_ANON 0 +#define APR_HAVE_SHMEM_SHMGET 0 +#define APR_HAVE_SHMEM_MMAP_ANON 0 +#define APR_HAVE_SHMEM_BEOS 0 + +#define APR_USE_SHMEM_MMAP_TMP 0 +#define APR_USE_SHMEM_MMAP_SHM 0 +#define APR_USE_SHMEM_MMAP_ZERO 0 +#define APR_USE_SHMEM_SHMGET_ANON 0 +#define APR_USE_SHMEM_SHMGET 0 +#define APR_USE_SHMEM_MMAP_ANON 0 +#define APR_USE_SHMEM_BEOS 0 + +#define APR_USE_FLOCK_SERIALIZE 0 +#define APR_USE_SYSVSEM_SERIALIZE 0 +#define APR_USE_FCNTL_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 0 + +#define APR_HAS_FLOCK_SERIALIZE 0 +#define APR_HAS_SYSVSEM_SERIALIZE 0 +#define APR_HAS_FCNTL_SERIALIZE 0 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 +#define APR_HAS_RWLOCK_SERIALIZE 0 + +#define APR_HAS_LOCK_CREATE_NP 0 + +#define APR_PROCESS_LOCK_IS_GLOBAL 1 + +#define APR_FILE_BASED_SHM 0 + +#define APR_HAVE_CORKABLE_TCP 0 +#define APR_HAVE_GETRLIMIT 0 +#define APR_HAVE_ICONV 0 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 0 +#ifdef NW_BUILD_IPV6 +#define APR_HAVE_IPV6 1 +#else +#define APR_HAVE_IPV6 0 +#endif +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 0 +#define APR_HAVE_SIGACTION 0 +#define APR_HAVE_SIGSUSPEND 0 +#define APR_HAVE_SIGWAIT 0 +#define APR_HAVE_STRCASECMP 1 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRICMP 1 +#define APR_HAVE_STRNCASECMP 1 +#define APR_HAVE_STRNICMP 1 +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_STRUCT_RLIMIT 0 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY 0 +#define APR_HAS_THREADS 1 +#define APR_HAS_SENDFILE 0 +#define APR_HAS_MMAP 0 +#define APR_HAS_FORK 0 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 0 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 0 +#define APR_HAS_PROC_INVOKED 0 +#define APR_HAS_USER 1 +#define APR_HAS_LARGE_FILES 1 +#define APR_HAS_XTHREAD_FILES 0 +#define APR_HAS_OS_UUID 0 + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 + +/* Netware can poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 1 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* Is the TCP_NODELAY socket option inherited from listening sockets? +*/ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? +*/ +#define APR_O_NONBLOCK_INHERITED 1 + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef long long apr_int64_t; +typedef unsigned long long apr_uint64_t; + +typedef size_t apr_size_t; +typedef ssize_t apr_ssize_t; +#if APR_HAS_LARGE_FILES +typedef off64_t apr_off_t; +#else +typedef off_t apr_off_t; +#endif +#ifdef USE_WINSOCK +typedef int apr_socklen_t; +#else +typedef size_t apr_socklen_t; +#endif + +/* Are we big endian? */ +/* XXX: Fatal assumption on Alpha platforms */ +#define APR_IS_BIGENDIAN 0 + +#ifdef UNKNOWN_NETWARE_64BIT_FLAG_NEEDED +#define APR_SIZEOF_VOIDP 8 +#else +#define APR_SIZEOF_VOIDP 4 +#endif + +/* Mechanisms to properly type numeric literals */ +#define APR_INT64_C(val) (val##LL) +#define APR_UINT64_C(val) (val##ULL) + +/* PROC mutex is a GLOBAL mutex on Netware */ +#define APR_PROC_MUTEX_IS_GLOBAL 1 + +/* Definitions that APR programs need to work properly. */ + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * @example + */ +/** void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + */ +#define APR_THREAD_FUNC + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE(rettype) apr_func(args) + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with AP_MODULE_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * @example + */ +/** extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + */ +#define APR_DECLARE_DATA + +#define APR_SSIZE_T_FMT "d" + +#define APR_SIZE_T_FMT "d" + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_FMT "lld" +#else +#define APR_OFF_T_FMT "ld" +#endif + +#define APR_PID_T_FMT "d" + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\r\n" + +typedef int apr_wait_t; + +#define APR_PATH_MAX PATH_MAX + +#define APR_INT64_T_FMT "lld" +#define APR_UINT64_T_FMT "llu" +#define APR_UINT64_T_HEX_FMT "llx" +#define APR_TIME_T_FMT APR_INT64_T_FMT + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NETWARE */ + +#endif /* APR_H */ diff --git a/include/apr/apr.hw b/include/apr/apr.hw new file mode 100644 index 0000000..0fd7bc9 --- /dev/null +++ b/include/apr/apr.hw @@ -0,0 +1,527 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.hw instead. + * + * And please, make an effort to stub apr.hnw and apr.h.in in the process. + * + * This is the Win32 specific version of apr.h. It is copied from + * apr.hw by the apr.dsp and libapr.dsp projects. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +#if defined(WIN32) || defined(DOXYGEN) + +/* Ignore most warnings (back down to /W3) for poorly constructed headers + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(push, 3) +#endif + +/* disable or reduce the frequency of... + * C4057: indirection to slightly different base types + * C4075: slight indirection changes (unsigned short* vs short[]) + * C4100: unreferenced formal parameter + * C4127: conditional expression is constant + * C4163: '_rotl64' : not available as an intrinsic function + * C4201: nonstandard extension nameless struct/unions + * C4244: int to char/short - precision loss + * C4514: unreferenced inline function removed + */ +#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) + +/* Ignore Microsoft's interpretation of secure development + * and the POSIX string handling API + */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define _CRT_SECURE_NO_DEPRECATE +#pragma warning(disable: 4996) +#endif + +/* Has windows.h already been included? If so, our preferences don't matter, + * but we will still need the winsock things no matter what was included. + * If not, include a restricted set of windows headers to our tastes. + */ +#ifndef _WINDOWS_ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef _WIN32_WINNT + +/* Restrict the server to a subset of Windows NT 4.0 header files by default + */ +#define _WIN32_WINNT 0x0400 +#endif +#ifndef NOUSER +#define NOUSER +#endif +#ifndef NOMCX +#define NOMCX +#endif +#ifndef NOIME +#define NOIME +#endif +#include +/* + * Add a _very_few_ declarations missing from the restricted set of headers + * (If this list becomes extensive, re-enable the required headers above!) + * winsock headers were excluded by WIN32_LEAN_AND_MEAN, so include them now + */ +#define SW_HIDE 0 +#ifndef _WIN32_WCE +#include +#include +#include +#else +#include +#endif +#endif /* !_WINDOWS_ */ + +/** + * @defgroup apr_platform Platform Definitions + * @ingroup APR + * @{ + */ + +#define APR_INLINE __inline +#define APR_HAS_INLINE 1 +#ifndef __attribute__ +#define __attribute__(__x) +#endif + +#ifndef _WIN32_WCE +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H 1 +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H 1 +#define APR_HAVE_DIRENT_H 0 +#define APR_HAVE_ERRNO_H 1 +#define APR_HAVE_FCNTL_H 1 +#define APR_HAVE_IO_H 1 +#define APR_HAVE_LIMITS_H 1 +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SIGNAL_H 1 +#define APR_HAVE_STDARG_H 1 +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SIGNAL_H 0 +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#define APR_HAVE_SYS_TYPES_H 1 +#define APR_HAVE_SYS_UIO_H 0 +#define APR_HAVE_SYS_WAIT_H 0 +#define APR_HAVE_UNISTD_H 0 +#define APR_HAVE_STDDEF_H 1 +#define APR_HAVE_PROCESS_H 1 +#define APR_HAVE_TIME_H 1 +#else +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H 0 +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H 0 +#define APR_HAVE_DIRENT_H 0 +#define APR_HAVE_ERRNO_H 0 +#define APR_HAVE_FCNTL_H 0 +#define APR_HAVE_IO_H 0 +#define APR_HAVE_LIMITS_H 0 +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SIGNAL_H 0 +#define APR_HAVE_STDARG_H 0 +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SIGNAL_H 0 +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#define APR_HAVE_SYS_TYPES_H 0 +#define APR_HAVE_SYS_UIO_H 0 +#define APR_HAVE_SYS_WAIT_H 0 +#define APR_HAVE_UNISTD_H 0 +#define APR_HAVE_STDDEF_H 0 +#define APR_HAVE_PROCESS_H 0 +#define APR_HAVE_TIME_H 0 +#endif + +#define APR_USE_FLOCK_SERIALIZE 0 +#define APR_USE_SYSVSEM_SERIALIZE 0 +#define APR_USE_FCNTL_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 0 + +#define APR_HAS_FLOCK_SERIALIZE 0 +#define APR_HAS_SYSVSEM_SERIALIZE 0 +#define APR_HAS_FCNTL_SERIALIZE 0 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 +#define APR_HAS_RWLOCK_SERIALIZE 0 + +#define APR_HAS_LOCK_CREATE_NP 0 + +#define APR_PROCESS_LOCK_IS_GLOBAL 0 + +#define APR_USES_ANONYMOUS_SHM 0 +#define APR_USES_FILEBASED_SHM 0 +#define APR_USES_KEYBASED_SHM 0 + +#define APR_FILE_BASED_SHM 0 +#define APR_MEM_BASED_SHM 0 + +#define APR_HAVE_CORKABLE_TCP 0 +#define APR_HAVE_GETRLIMIT 0 +#define APR_HAVE_ICONV 0 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 0 +#define APR_HAVE_IPV6 0 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 0 +#define APR_HAVE_SIGACTION 0 +#define APR_HAVE_SIGSUSPEND 0 +#define APR_HAVE_SIGWAIT 0 +#define APR_HAVE_STRCASECMP 0 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRNCASECMP 0 +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_STRUCT_RLIMIT 0 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 + +#ifndef _WIN32_WCE +#define APR_HAVE_STRICMP 1 +#define APR_HAVE_STRNICMP 1 +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 1 +#else +#define APR_HAVE_STRICMP 0 +#define APR_HAVE_STRNICMP 0 +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 +#endif + +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_STDIO_H +#include +#endif +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#if APR_HAVE_STDDEF_H +#include +#endif +#if APR_HAVE_TIME_H +#include +#endif +#if APR_HAVE_PROCESS_H +#include +#endif +#if APR_HAVE_IPV6 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY 1 +#define APR_HAS_THREADS 1 +#define APR_HAS_MMAP 1 +#define APR_HAS_FORK 0 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 1 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 1 +#define APR_HAS_PROC_INVOKED 1 +#ifndef _WIN32_WCE +#define APR_HAS_SENDFILE 1 +#define APR_HAS_USER 1 +#define APR_HAS_LARGE_FILES 1 +#define APR_HAS_XTHREAD_FILES 1 +#else +#define APR_HAS_SENDFILE 0 +#define APR_HAS_USER 0 +#define APR_HAS_LARGE_FILES 0 +#define APR_HAS_XTHREAD_FILES 0 +#endif +#define APR_HAS_OS_UUID 1 + +/* Win32 cannot poll [just yet] on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 0 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* Is the TCP_NODELAY socket option inherited from listening sockets? + */ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? + */ +#define APR_O_NONBLOCK_INHERITED 1 + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef __int64 apr_int64_t; +typedef unsigned __int64 apr_uint64_t; + +typedef size_t apr_size_t; +#if APR_HAVE_STDDEF_H +typedef ptrdiff_t apr_ssize_t; +#else +typedef int apr_ssize_t; +#endif +#if APR_HAS_LARGE_FILES +typedef __int64 apr_off_t; +#else +typedef int apr_off_t; +#endif +typedef int apr_socklen_t; + +/* Are we big endian? */ +/* XXX: Fatal assumption on Alpha platforms */ +#define APR_IS_BIGENDIAN 0 + +#ifdef WIN64 +#define APR_SIZEOF_VOIDP 8 +#else +#define APR_SIZEOF_VOIDP 4 +#endif + +/* XXX These simply don't belong here, perhaps in apr_portable.h + * based on some APR_HAVE_PID/GID/UID? + */ +typedef int pid_t; +typedef int uid_t; +typedef int gid_t; + +/* Mechanisms to properly type numeric literals */ + +#define APR_INT64_C(val) (val##i64) +#define APR_UINT64_C(val) (val##Ui64) + + +#if APR_HAVE_IPV6 + +/* Appears in later flavors, not the originals. */ +#ifndef in_addr6 +#define in6_addr in_addr6 +#endif + +#ifndef WS2TCPIP_INLINE +#define IN6_IS_ADDR_V4MAPPED(a) \ + ( (*(const apr_uint64_t *)(const void *)(&(a)->s6_addr[0]) == 0) \ + && (*(const apr_uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) +#endif + +#endif /* APR_HAS_IPV6 */ + +/* Definitions that APR programs need to work properly. */ + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * @example + */ +/** void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + */ +#define APR_THREAD_FUNC __stdcall + + +#if defined(DOXYGEN) || !defined(WIN32) + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE(rettype) apr_func(args) + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with AP_MODULE_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * @example + */ +/** extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + */ +#define APR_DECLARE_DATA + +#elif defined(APR_DECLARE_STATIC) +#define APR_DECLARE(type) type __stdcall +#define APR_DECLARE_NONSTD(type) type __cdecl +#define APR_DECLARE_DATA +#elif defined(APR_DECLARE_EXPORT) +#define APR_DECLARE(type) __declspec(dllexport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllexport) +#else +#define APR_DECLARE(type) __declspec(dllimport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllimport) +#endif + +#ifdef WIN64 +#define APR_SSIZE_T_FMT "I64d" +#define APR_SIZE_T_FMT "I64d" +#else +#define APR_SSIZE_T_FMT "d" +#define APR_SIZE_T_FMT "d" +#endif + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_FMT "I64d" +#else +#define APR_OFF_T_FMT "d" +#endif + +#define APR_PID_T_FMT "d" + +#define APR_INT64_T_FMT "I64d" +#define APR_UINT64_T_FMT "I64u" +#define APR_UINT64_T_HEX_FMT "I64x" + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\r\n" + +/* No difference between PROC and GLOBAL mutex */ +#define APR_PROC_MUTEX_IS_GLOBAL 1 + +typedef int apr_wait_t; + +/* struct iovec is needed to emulate Unix writev */ +struct iovec { + char* iov_base; + apr_size_t iov_len; +}; + +/* Nasty Win32 .h ommissions we really need */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#if APR_HAS_UNICODE_FS +/* An arbitrary size that is digestable. True max is a bit less than 32000 */ +#define APR_PATH_MAX 8192 +#else /* !APR_HAS_UNICODE_FS */ +#define APR_PATH_MAX MAX_PATH +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/* Done with badly written headers + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(pop) +#endif + +/* Ignore Microsoft's interpretation of secure development + * and their opinion of the POSIX standard string handling API + */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define _CRT_SECURE_NO_DEPRECATE +#pragma warning(disable: 4996) +#endif + +#endif /* WIN32 */ + +#endif /* APR_H */ diff --git a/include/apr/apr_allocator.h b/include/apr/apr_allocator.h new file mode 100644 index 0000000..6dcc3d7 --- /dev/null +++ b/include/apr/apr_allocator.h @@ -0,0 +1,167 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_ALLOCATOR_H +#define APR_ALLOCATOR_H + +/** + * @file apr_allocator.h + * @brief APR Internal Memory Allocation + */ + +#include "apr.h" +#include "apr_errno.h" +#define APR_WANT_MEMFUNC /**< For no good reason? */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_allocator Internal Memory Allocation + * @ingroup APR + * @{ + */ + +/** the allocator structure */ +typedef struct apr_allocator_t apr_allocator_t; +/** the structure which holds information about the allocation */ +typedef struct apr_memnode_t apr_memnode_t; + +/** basic memory node structure + * @note The next, ref and first_avail fields are available for use by the + * caller of apr_allocator_alloc(), the remaining fields are read-only. + * The next field has to be used with caution and sensibly set when the + * memnode is passed back to apr_allocator_free(). See apr_allocator_free() + * for details. + * The ref and first_avail fields will be properly restored by + * apr_allocator_free(). + */ +struct apr_memnode_t { + apr_memnode_t *next; /**< next memnode */ + apr_memnode_t **ref; /**< reference to self */ + apr_uint32_t index; /**< size */ + apr_uint32_t free_index; /**< how much free */ + char *first_avail; /**< pointer to first free memory */ + char *endp; /**< pointer to end of free memory */ +}; + +/** The base size of a memory node - aligned. */ +#define APR_MEMNODE_T_SIZE APR_ALIGN_DEFAULT(sizeof(apr_memnode_t)) + +/** Symbolic constants */ +#define APR_ALLOCATOR_MAX_FREE_UNLIMITED 0 + +/** + * View a new allocator key status + * @param allocator The allocator we have just created. + * + */ +APR_DECLARE(apr_status_t) apr_allocator_status(); + +/** + * Create a new allocator + * @param allocator The allocator we have just created. + * + */ +APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator); + +/** + * Destroy an allocator + * @param allocator The allocator to be destroyed + * @remark Any memnodes not given back to the allocator prior to destroying + * will _not_ be free()d. + */ +APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator); + +/** + * Allocate a block of mem from the allocator + * @param allocator The allocator to allocate from + * @param size The size of the mem to allocate (excluding the + * memnode structure) + */ +APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator, + apr_size_t size); + +/** + * Free a list of blocks of mem, giving them back to the allocator. + * The list is typically terminated by a memnode with its next field + * set to NULL. + * @param allocator The allocator to give the mem back to + * @param memnode The memory node to return + */ +APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator, + apr_memnode_t *memnode); + +#include "apr_pools.h" + +/** + * Set the owner of the allocator + * @param allocator The allocator to set the owner for + * @param pool The pool that is to own the allocator + * @remark Typically pool is the highest level pool using the allocator + */ +/* + * XXX: see if we can come up with something a bit better. Currently + * you can make a pool an owner, but if the pool doesn't use the allocator + * the allocator will never be destroyed. + */ +APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator, + apr_pool_t *pool); + +/** + * Get the current owner of the allocator + * @param allocator The allocator to get the owner from + */ +APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator); + +/** + * Set the current threshold at which the allocator should start + * giving blocks back to the system. + * @param allocator The allocator the set the threshold on + * @param size The threshold. 0 == unlimited. + */ +APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator, + apr_size_t size); + +#include "apr_thread_mutex.h" + +#if APR_HAS_THREADS +/** + * Set a mutex for the allocator to use + * @param allocator The allocator to set the mutex for + * @param mutex The mutex + */ +APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator, + apr_thread_mutex_t *mutex); + +/** + * Get the mutex currently set for the allocator + * @param allocator The allocator + */ +APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get( + apr_allocator_t *allocator); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ALLOCATOR_H */ diff --git a/include/apr/apr_anylock.h b/include/apr/apr_anylock.h new file mode 100644 index 0000000..6b724de --- /dev/null +++ b/include/apr/apr_anylock.h @@ -0,0 +1,128 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/** + * @file apr_anylock.h + * @brief APR-Util transparent any lock flavor wrapper + */ +#ifndef APR_ANYLOCK_H +#define APR_ANYLOCK_H + +#include "apr_proc_mutex.h" +#include "apr_thread_mutex.h" +#include "apr_thread_rwlock.h" + +/** Structure that may contain any APR lock type */ +typedef struct apr_anylock_t { + /** Indicates what type of lock is in lock */ + enum tm_lock { + apr_anylock_none, /**< None */ + apr_anylock_procmutex, /**< Process-based */ + apr_anylock_threadmutex, /**< Thread-based */ + apr_anylock_readlock, /**< Read lock */ + apr_anylock_writelock /**< Write lock */ + } type; + /** Union of all possible APR locks */ + union apr_anylock_u_t { + apr_proc_mutex_t *pm; /**< Process mutex */ +#if APR_HAS_THREADS + apr_thread_mutex_t *tm; /**< Thread mutex */ + apr_thread_rwlock_t *rw; /**< Read-write lock */ +#endif + } lock; +} apr_anylock_t; + +#if APR_HAS_THREADS + +/** Lock an apr_anylock_t structure */ +#define APR_ANYLOCK_LOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_lock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_lock((lck)->lock.pm) \ + : (((lck)->type == apr_anylock_readlock) \ + ? apr_thread_rwlock_rdlock((lck)->lock.rw) \ + : (((lck)->type == apr_anylock_writelock) \ + ? apr_thread_rwlock_wrlock((lck)->lock.rw) \ + : APR_EINVAL))))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_LOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_lock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#if APR_HAS_THREADS + +/** Try to lock an apr_anylock_t structure */ +#define APR_ANYLOCK_TRYLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_trylock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_trylock((lck)->lock.pm) \ + : (((lck)->type == apr_anylock_readlock) \ + ? apr_thread_rwlock_tryrdlock((lck)->lock.rw) \ + : (((lck)->type == apr_anylock_writelock) \ + ? apr_thread_rwlock_trywrlock((lck)->lock.rw) \ + : APR_EINVAL))))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_TRYLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_trylock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#if APR_HAS_THREADS + +/** Unlock an apr_anylock_t structure */ +#define APR_ANYLOCK_UNLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_unlock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_unlock((lck)->lock.pm) \ + : ((((lck)->type == apr_anylock_readlock) || \ + ((lck)->type == apr_anylock_writelock)) \ + ? apr_thread_rwlock_unlock((lck)->lock.rw) \ + : APR_EINVAL)))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_UNLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_unlock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#endif /* !APR_ANYLOCK_H */ diff --git a/include/apr/apr_atomic.h b/include/apr/apr_atomic.h new file mode 100644 index 0000000..d701069 --- /dev/null +++ b/include/apr/apr_atomic.h @@ -0,0 +1,129 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_ATOMIC_H +#define APR_ATOMIC_H + +/** + * @file apr_atomic.h + * @brief APR Atomic Operations + */ + +#include "apr.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_atomic Atomic Operations + * @ingroup APR + * @{ + */ + +/** + * this function is required on some platforms to initialize the + * atomic operation's internal structures + * @param p pool + * @return APR_SUCCESS on successful completion + */ +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p); + +/* + * Atomic operations on 32-bit values + * Note: Each of these functions internally implements a memory barrier + * on platforms that require it + */ + +/** + * atomically read an apr_uint32_t from memory + * @param mem the pointer + */ +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem); + +/** + * atomically set an apr_uint32_t in memory + * @param mem pointer to the object + * @param val value that the object will assume + */ +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically add 'val' to an apr_uint32_t + * @param mem pointer to the object + * @param val amount to add + * @return old value pointed to by mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically subtract 'val' from an apr_uint32_t + * @param mem pointer to the object + * @param val amount to subtract + */ +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically increment an apr_uint32_t by 1 + * @param mem pointer to the object + * @return old value pointed to by mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem); + +/** + * atomically decrement an apr_uint32_t by 1 + * @param mem pointer to the atomic value + * @return zero if the value becomes zero on decrement, otherwise non-zero + */ +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem); + +/** + * compare an apr_uint32_t's value with 'cmp'. + * If they are the same swap the value with 'with' + * @param mem pointer to the value + * @param with what to swap it with + * @param cmp the value to compare it to + * @return the old value of *mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp); + +/** + * exchange an apr_uint32_t's value with 'val'. + * @param mem pointer to the value + * @param val what to swap it with + * @return the old value of *mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * compare the pointer's value with cmp. + * If they are the same swap the value with 'with' + * @param mem pointer to the pointer + * @param with what to swap it with + * @param cmp the value to compare it to + * @return the old value of the pointer + */ +APR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ATOMIC_H */ diff --git a/include/apr/apr_base64.h b/include/apr/apr_base64.h new file mode 100644 index 0000000..d26aeb2 --- /dev/null +++ b/include/apr/apr_base64.h @@ -0,0 +1,111 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + * The apr_vsnprintf/apr_snprintf functions are based on, and used with the + * permission of, the SIO stdio-replacement strx_* functions by Panos + * Tsirigotis for xinetd. + */ + +/** + * @file apr_base64.h + * @brief APR-UTIL Base64 Encoding + */ +#ifndef APR_BASE64_H +#define APR_BASE64_H + +#include "apu.h" +#include "apr_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Base64 Base64 Encoding + * @ingroup APR_Util + * @{ + */ + +/* Simple BASE64 encode/decode functions. + * + * As we might encode binary strings, hence we require the length of + * the incoming plain source. And return the length of what we decoded. + * + * The decoding function takes any non valid char (i.e. whitespace, \0 + * or anything non A-Z,0-9 etc as terminal. + * + * plain strings/binary sequences are not assumed '\0' terminated. Encoded + * strings are neither. But probably should. + * + */ + +/** + * Given the length of an un-encrypted string, get the length of the + * encrypted string. + * @param len the length of an unencrypted string. + * @return the length of the string after it is encrypted + */ +APU_DECLARE(int) apr_base64_encode_len(int len); + +/** + * Encode a text string using base64encoding. + * @param coded_dst The destination string for the encoded string. + * @param plain_src The original string in plain text + * @param len_plain_src The length of the plain text string + * @return the length of the encoded string + */ +APU_DECLARE(int) apr_base64_encode(char * coded_dst, const char *plain_src, + int len_plain_src); + +/** + * Encode an EBCDIC string using base64encoding. + * @param coded_dst The destination string for the encoded string. + * @param plain_src The original string in plain text + * @param len_plain_src The length of the plain text string + * @return the length of the encoded string + */ +APU_DECLARE(int) apr_base64_encode_binary(char * coded_dst, + const unsigned char *plain_src, + int len_plain_src); + +/** + * Determine the length of a plain text string given the encoded version + * @param coded_src The encoded string + * @return the length of the plain text string + */ +APU_DECLARE(int) apr_base64_decode_len(const char * coded_src); + +/** + * Decode a string to plain text + * @param plain_dst The destination string for the plain text + * @param coded_src The encoded string + * @return the length of the plain text string + */ +APU_DECLARE(int) apr_base64_decode(char * plain_dst, const char *coded_src); + +/** + * Decode an EBCDIC string to plain text + * @param plain_dst The destination string for the plain text + * @param coded_src The encoded string + * @return the length of the plain text string + */ +APU_DECLARE(int) apr_base64_decode_binary(unsigned char * plain_dst, + const char *coded_src); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_BASE64_H */ diff --git a/include/apr/apr_buckets.h b/include/apr/apr_buckets.h new file mode 100644 index 0000000..01f6743 --- /dev/null +++ b/include/apr/apr_buckets.h @@ -0,0 +1,1464 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ +/** + * @file apr_buckets.h + * @brief APR-UTIL Buckets/Bucket Brigades + */ + +#ifndef APR_BUCKETS_H +#define APR_BUCKETS_H + +#if defined(APR_BUCKET_DEBUG) && !defined(APR_RING_DEBUG) +#define APR_RING_DEBUG +#endif + +#include "apu.h" +#include "apr_network_io.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_mmap.h" +#include "apr_errno.h" +#include "apr_ring.h" +#include "apr.h" +#if APR_HAVE_SYS_UIO_H +#include /* for struct iovec */ +#endif +#if APR_HAVE_STDARG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Bucket_Brigades Bucket Brigades + * @ingroup APR_Util + * @{ + */ + +/** default bucket buffer size - 8KB minus room for memory allocator headers */ +#define APR_BUCKET_BUFF_SIZE 8000 + +/** Determines how a bucket or brigade should be read */ +typedef enum { + APR_BLOCK_READ, /**< block until data becomes available */ + APR_NONBLOCK_READ /**< return immediately if no data is available */ +} apr_read_type_e; + +/** + * The one-sentence buzzword-laden overview: Bucket brigades represent + * a complex data stream that can be passed through a layered IO + * system without unnecessary copying. A longer overview follows... + * + * A bucket brigade is a doubly linked list (ring) of buckets, so we + * aren't limited to inserting at the front and removing at the end. + * Buckets are only passed around as members of a brigade, although + * singleton buckets can occur for short periods of time. + * + * Buckets are data stores of various types. They can refer to data in + * memory, or part of a file or mmap area, or the output of a process, + * etc. Buckets also have some type-dependent accessor functions: + * read, split, copy, setaside, and destroy. + * + * read returns the address and size of the data in the bucket. If the + * data isn't in memory then it is read in and the bucket changes type + * so that it can refer to the new location of the data. If all the + * data doesn't fit in the bucket then a new bucket is inserted into + * the brigade to hold the rest of it. + * + * split divides the data in a bucket into two regions. After a split + * the original bucket refers to the first part of the data and a new + * bucket inserted into the brigade after the original bucket refers + * to the second part of the data. Reference counts are maintained as + * necessary. + * + * setaside ensures that the data in the bucket has a long enough + * lifetime. Sometimes it is convenient to create a bucket referring + * to data on the stack in the expectation that it will be consumed + * (output to the network) before the stack is unwound. If that + * expectation turns out not to be valid, the setaside function is + * called to move the data somewhere safer. + * + * copy makes a duplicate of the bucket structure as long as it's + * possible to have multiple references to a single copy of the + * data itself. Not all bucket types can be copied. + * + * destroy maintains the reference counts on the resources used by a + * bucket and frees them if necessary. + * + * Note: all of the above functions have wrapper macros (apr_bucket_read(), + * apr_bucket_destroy(), etc), and those macros should be used rather + * than using the function pointers directly. + * + * To write a bucket brigade, they are first made into an iovec, so that we + * don't write too little data at one time. Currently we ignore compacting the + * buckets into as few buckets as possible, but if we really want good + * performance, then we need to compact the buckets before we convert to an + * iovec, or possibly while we are converting to an iovec. + */ + +/* + * Forward declaration of the main types. + */ + +/** @see apr_bucket_brigade */ +typedef struct apr_bucket_brigade apr_bucket_brigade; +/** @see apr_bucket */ +typedef struct apr_bucket apr_bucket; +/** @see apr_bucket_alloc_t */ +typedef struct apr_bucket_alloc_t apr_bucket_alloc_t; + +/** @see apr_bucket_type_t */ +typedef struct apr_bucket_type_t apr_bucket_type_t; + +/** + * Basic bucket type + */ +struct apr_bucket_type_t { + /** + * The name of the bucket type + */ + const char *name; + /** + * The number of functions this bucket understands. Can not be less than + * five. + */ + int num_func; + /** + * Whether the bucket contains metadata (ie, information that + * describes the regular contents of the brigade). The metadata + * is not returned by apr_bucket_read() and is not indicated by + * the ->length of the apr_bucket itself. In other words, an + * empty bucket is safe to arbitrarily remove if and only if it + * contains no metadata. In this sense, "data" is just raw bytes + * that are the "content" of the brigade and "metadata" describes + * that data but is not a proper part of it. + */ + enum { + /** This bucket type represents actual data to send to the client. */ + APR_BUCKET_DATA = 0, + /** This bucket type represents metadata. */ + APR_BUCKET_METADATA = 1 + } is_metadata; + /** + * Free the private data and any resources used by the bucket (if they + * aren't shared with another bucket). This function is required to be + * implemented for all bucket types, though it might be a no-op on some + * of them (namely ones that never allocate any private data structures). + * @param data The private data pointer from the bucket to be destroyed + */ + void (*destroy)(void *data); + + /** + * Read the data from the bucket. This is required to be implemented + * for all bucket types. + * @param b The bucket to read from + * @param str A place to store the data read. Allocation should only be + * done if absolutely necessary. + * @param len The amount of data read. + * @param block Should this read function block if there is more data that + * cannot be read immediately. + */ + apr_status_t (*read)(apr_bucket *b, const char **str, apr_size_t *len, + apr_read_type_e block); + + /** + * Make it possible to set aside the data for at least as long as the + * given pool. Buckets containing data that could potentially die before + * this pool (e.g. the data resides on the stack, in a child pool of + * the given pool, or in a disjoint pool) must somehow copy, shift, or + * transform the data to have the proper lifetime. + * @param e The bucket to convert + * @remark Some bucket types contain data that will always outlive the + * bucket itself. For example no data (EOS and FLUSH), or the data + * resides in global, constant memory (IMMORTAL), or the data is on + * the heap (HEAP). For these buckets, apr_bucket_setaside_noop can + * be used. + */ + apr_status_t (*setaside)(apr_bucket *e, apr_pool_t *pool); + + /** + * Split one bucket in two at the specified position by duplicating + * the bucket structure (not the data) and modifying any necessary + * start/end/offset information. If it's not possible to do this + * for the bucket type (perhaps the length of the data is indeterminate, + * as with pipe and socket buckets), then APR_ENOTIMPL is returned. + * @param e The bucket to split + * @param point The offset of the first byte in the new bucket + */ + apr_status_t (*split)(apr_bucket *e, apr_size_t point); + + /** + * Copy the bucket structure (not the data), assuming that this is + * possible for the bucket type. If it's not, APR_ENOTIMPL is returned. + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + */ + apr_status_t (*copy)(apr_bucket *e, apr_bucket **c); + +}; + +/** + * apr_bucket structures are allocated on the malloc() heap and + * their lifetime is controlled by the parent apr_bucket_brigade + * structure. Buckets can move from one brigade to another e.g. by + * calling APR_BRIGADE_CONCAT(). In general the data in a bucket has + * the same lifetime as the bucket and is freed when the bucket is + * destroyed; if the data is shared by more than one bucket (e.g. + * after a split) the data is freed when the last bucket goes away. + */ +struct apr_bucket { + /** Links to the rest of the brigade */ + APR_RING_ENTRY(apr_bucket) link; + /** The type of bucket. */ + const apr_bucket_type_t *type; + /** The length of the data in the bucket. This could have been implemented + * with a function, but this is an optimization, because the most + * common thing to do will be to get the length. If the length is unknown, + * the value of this field will be (apr_size_t)(-1). + */ + apr_size_t length; + /** The start of the data in the bucket relative to the private base + * pointer. The vast majority of bucket types allow a fixed block of + * data to be referenced by multiple buckets, each bucket pointing to + * a different segment of the data. That segment starts at base+start + * and ends at base+start+length. + * If the length == (apr_size_t)(-1), then start == -1. + */ + apr_off_t start; + /** type-dependent data hangs off this pointer */ + void *data; + /** + * Pointer to function used to free the bucket. This function should + * always be defined and it should be consistent with the memory + * function used to allocate the bucket. For example, if malloc() is + * used to allocate the bucket, this pointer should point to free(). + * @param e Pointer to the bucket being freed + */ + void (*free)(void *e); + /** The freelist from which this bucket was allocated */ + apr_bucket_alloc_t *list; +}; + +/** A list of buckets */ +struct apr_bucket_brigade { + /** The pool to associate the brigade with. The data is not allocated out + * of the pool, but a cleanup is registered with this pool. If the + * brigade is destroyed by some mechanism other than pool destruction, + * the destroying function is responsible for killing the cleanup. + */ + apr_pool_t *p; + /** The buckets in the brigade are on this list. */ + /* + * The apr_bucket_list structure doesn't actually need a name tag + * because it has no existence independent of struct apr_bucket_brigade; + * the ring macros are designed so that you can leave the name tag + * argument empty in this situation but apparently the Windows compiler + * doesn't like that. + */ + APR_RING_HEAD(apr_bucket_list, apr_bucket) list; + /** The freelist from which this bucket was allocated */ + apr_bucket_alloc_t *bucket_alloc; +}; + + +/** + * Function called when a brigade should be flushed + */ +typedef apr_status_t (*apr_brigade_flush)(apr_bucket_brigade *bb, void *ctx); + +/* + * define APR_BUCKET_DEBUG if you want your brigades to be checked for + * validity at every possible instant. this will slow your code down + * substantially but is a very useful debugging tool. + */ +#ifdef APR_BUCKET_DEBUG + +#define APR_BRIGADE_CHECK_CONSISTENCY(b) \ + APR_RING_CHECK_CONSISTENCY(&(b)->list, apr_bucket, link) + +#define APR_BUCKET_CHECK_CONSISTENCY(e) \ + APR_RING_CHECK_ELEM_CONSISTENCY((e), apr_bucket, link) + +#else +/** + * checks the ring pointers in a bucket brigade for consistency. an + * abort() will be triggered if any inconsistencies are found. + * note: this is a no-op unless APR_BUCKET_DEBUG is defined. + * @param b The brigade + */ +#define APR_BRIGADE_CHECK_CONSISTENCY(b) +/** + * checks the brigade a bucket is in for ring consistency. an + * abort() will be triggered if any inconsistencies are found. + * note: this is a no-op unless APR_BUCKET_DEBUG is defined. + * @param e The bucket + */ +#define APR_BUCKET_CHECK_CONSISTENCY(e) +#endif + + +/** + * Wrappers around the RING macros to reduce the verbosity of the code + * that handles bucket brigades. + */ +/** + * The magic pointer value that indicates the head of the brigade + * @remark This is used to find the beginning and end of the brigade, eg: + *
+ *      while (e != APR_BRIGADE_SENTINEL(b)) {
+ *          ...
+ *          e = APR_BUCKET_NEXT(e);
+ *      }
+ * 
+ * @param b The brigade + * @return The magic pointer value + */ +#define APR_BRIGADE_SENTINEL(b) APR_RING_SENTINEL(&(b)->list, apr_bucket, link) + +/** + * Determine if the bucket brigade is empty + * @param b The brigade to check + * @return true or false + */ +#define APR_BRIGADE_EMPTY(b) APR_RING_EMPTY(&(b)->list, apr_bucket, link) + +/** + * Return the first bucket in a brigade + * @param b The brigade to query + * @return The first bucket in the brigade + */ +#define APR_BRIGADE_FIRST(b) APR_RING_FIRST(&(b)->list) +/** + * Return the last bucket in a brigade + * @param b The brigade to query + * @return The last bucket in the brigade + */ +#define APR_BRIGADE_LAST(b) APR_RING_LAST(&(b)->list) + +/** + * Insert a list of buckets at the front of a brigade + * @param b The brigade to add to + * @param e The first bucket in a list of buckets to insert + */ +#define APR_BRIGADE_INSERT_HEAD(b, e) do { \ + apr_bucket *ap__b = (e); \ + APR_RING_INSERT_HEAD(&(b)->list, ap__b, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((b)); \ + } while (0) + +/** + * Insert a list of buckets at the end of a brigade + * @param b The brigade to add to + * @param e The first bucket in a list of buckets to insert + */ +#define APR_BRIGADE_INSERT_TAIL(b, e) do { \ + apr_bucket *ap__b = (e); \ + APR_RING_INSERT_TAIL(&(b)->list, ap__b, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((b)); \ + } while (0) + +/** + * Concatenate brigade b onto the end of brigade a, leaving brigade b empty + * @param a The first brigade + * @param b The second brigade + */ +#define APR_BRIGADE_CONCAT(a, b) do { \ + APR_RING_CONCAT(&(a)->list, &(b)->list, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((a)); \ + } while (0) + +/** + * Prepend brigade b onto the beginning of brigade a, leaving brigade b empty + * @param a The first brigade + * @param b The second brigade + */ +#define APR_BRIGADE_PREPEND(a, b) do { \ + APR_RING_PREPEND(&(a)->list, &(b)->list, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((a)); \ + } while (0) + +/** + * Insert a list of buckets before a specified bucket + * @param a The bucket to insert before + * @param b The buckets to insert + */ +#define APR_BUCKET_INSERT_BEFORE(a, b) do { \ + apr_bucket *ap__a = (a), *ap__b = (b); \ + APR_RING_INSERT_BEFORE(ap__a, ap__b, link); \ + APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ + } while (0) + +/** + * Insert a list of buckets after a specified bucket + * @param a The bucket to insert after + * @param b The buckets to insert + */ +#define APR_BUCKET_INSERT_AFTER(a, b) do { \ + apr_bucket *ap__a = (a), *ap__b = (b); \ + APR_RING_INSERT_AFTER(ap__a, ap__b, link); \ + APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ + } while (0) + +/** + * Get the next bucket in the list + * @param e The current bucket + * @return The next bucket + */ +#define APR_BUCKET_NEXT(e) APR_RING_NEXT((e), link) +/** + * Get the previous bucket in the list + * @param e The current bucket + * @return The previous bucket + */ +#define APR_BUCKET_PREV(e) APR_RING_PREV((e), link) + +/** + * Remove a bucket from its bucket brigade + * @param e The bucket to remove + */ +#define APR_BUCKET_REMOVE(e) APR_RING_REMOVE((e), link) + +/** + * Initialize a new bucket's prev/next pointers + * @param e The bucket to initialize + */ +#define APR_BUCKET_INIT(e) APR_RING_ELEM_INIT((e), link) + +/** + * Determine if a bucket contains metadata. An empty bucket is + * safe to arbitrarily remove if and only if this is false. + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_METADATA(e) ((e)->type->is_metadata) + +/** + * Determine if a bucket is a FLUSH bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_FLUSH(e) ((e)->type == &apr_bucket_type_flush) +/** + * Determine if a bucket is an EOS bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_EOS(e) ((e)->type == &apr_bucket_type_eos) +/** + * Determine if a bucket is a FILE bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_FILE(e) ((e)->type == &apr_bucket_type_file) +/** + * Determine if a bucket is a PIPE bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_PIPE(e) ((e)->type == &apr_bucket_type_pipe) +/** + * Determine if a bucket is a SOCKET bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_SOCKET(e) ((e)->type == &apr_bucket_type_socket) +/** + * Determine if a bucket is a HEAP bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_HEAP(e) ((e)->type == &apr_bucket_type_heap) +/** + * Determine if a bucket is a TRANSIENT bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_TRANSIENT(e) ((e)->type == &apr_bucket_type_transient) +/** + * Determine if a bucket is a IMMORTAL bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_IMMORTAL(e) ((e)->type == &apr_bucket_type_immortal) +#if APR_HAS_MMAP +/** + * Determine if a bucket is a MMAP bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_MMAP(e) ((e)->type == &apr_bucket_type_mmap) +#endif +/** + * Determine if a bucket is a POOL bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_POOL(e) ((e)->type == &apr_bucket_type_pool) + +/* + * General-purpose reference counting for the various bucket types. + * + * Any bucket type that keeps track of the resources it uses (i.e. + * most of them except for IMMORTAL, TRANSIENT, and EOS) needs to + * attach a reference count to the resource so that it can be freed + * when the last bucket that uses it goes away. Resource-sharing may + * occur because of bucket splits or buckets that refer to globally + * cached data. */ + +/** @see apr_bucket_refcount */ +typedef struct apr_bucket_refcount apr_bucket_refcount; +/** + * The structure used to manage the shared resource must start with an + * apr_bucket_refcount which is updated by the general-purpose refcount + * code. A pointer to the bucket-type-dependent private data structure + * can be cast to a pointer to an apr_bucket_refcount and vice versa. + */ +struct apr_bucket_refcount { + /** The number of references to this bucket */ + int refcount; +}; + +/* ***** Reference-counted bucket types ***** */ + +/** @see apr_bucket_heap */ +typedef struct apr_bucket_heap apr_bucket_heap; +/** + * A bucket referring to data allocated off the heap. + */ +struct apr_bucket_heap { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The start of the data actually allocated. This should never be + * modified, it is only used to free the bucket. + */ + char *base; + /** how much memory was allocated */ + apr_size_t alloc_len; + /** function to use to delete the data */ + void (*free_func)(void *data); +}; + +/** @see apr_bucket_pool */ +typedef struct apr_bucket_pool apr_bucket_pool; +/** + * A bucket referring to data allocated from a pool + */ +struct apr_bucket_pool { + /** The pool bucket must be able to be easily morphed to a heap + * bucket if the pool gets cleaned up before all references are + * destroyed. This apr_bucket_heap structure is populated automatically + * when the pool gets cleaned up, and subsequent calls to pool_read() + * will result in the apr_bucket in question being morphed into a + * regular heap bucket. (To avoid having to do many extra refcount + * manipulations and b->data manipulations, the apr_bucket_pool + * struct actually *contains* the apr_bucket_heap struct that it + * will become as its first element; the two share their + * apr_bucket_refcount members.) + */ + apr_bucket_heap heap; + /** The block of data actually allocated from the pool. + * Segments of this block are referenced by adjusting + * the start and length of the apr_bucket accordingly. + * This will be NULL after the pool gets cleaned up. + */ + const char *base; + /** The pool the data was allocated from. When the pool + * is cleaned up, this gets set to NULL as an indicator + * to pool_read() that the data is now on the heap and + * so it should morph the bucket into a regular heap + * bucket before continuing. + */ + apr_pool_t *pool; + /** The freelist this structure was allocated from, which is + * needed in the cleanup phase in order to allocate space on the heap + */ + apr_bucket_alloc_t *list; +}; + +#if APR_HAS_MMAP +/** @see apr_bucket_mmap */ +typedef struct apr_bucket_mmap apr_bucket_mmap; +/** + * A bucket referring to an mmap()ed file + */ +struct apr_bucket_mmap { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The mmap this sub_bucket refers to */ + apr_mmap_t *mmap; +}; +#endif + +/** @see apr_bucket_file */ +typedef struct apr_bucket_file apr_bucket_file; +/** + * A bucket referring to an file + */ +struct apr_bucket_file { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The file this bucket refers to */ + apr_file_t *fd; + /** The pool into which any needed structures should + * be created while reading from this file bucket */ + apr_pool_t *readpool; +#if APR_HAS_MMAP + /** Whether this bucket should be memory-mapped if + * a caller tries to read from it */ + int can_mmap; +#endif /* APR_HAS_MMAP */ +}; + +/** @see apr_bucket_structs */ +typedef union apr_bucket_structs apr_bucket_structs; +/** + * A union of all bucket structures so we know what + * the max size is. + */ +union apr_bucket_structs { + apr_bucket b; /**< Bucket */ + apr_bucket_heap heap; /**< Heap */ + apr_bucket_pool pool; /**< Pool */ +#if APR_HAS_MMAP + apr_bucket_mmap mmap; /**< MMap */ +#endif + apr_bucket_file file; /**< File */ +}; + +/** + * The amount that apr_bucket_alloc() should allocate in the common case. + * Note: this is twice as big as apr_bucket_structs to allow breathing + * room for third-party bucket types. + */ +#define APR_BUCKET_ALLOC_SIZE APR_ALIGN_DEFAULT(2*sizeof(apr_bucket_structs)) + +/* ***** Bucket Brigade Functions ***** */ +/** + * Create a new bucket brigade. The bucket brigade is originally empty. + * @param p The pool to associate with the brigade. Data is not allocated out + * of the pool, but a cleanup is registered. + * @param list The bucket allocator to use + * @return The empty bucket brigade + */ +APU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p, + apr_bucket_alloc_t *list); + +/** + * destroy an entire bucket brigade. This includes destroying all of the + * buckets within the bucket brigade's bucket list. + * @param b The bucket brigade to destroy + */ +APU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b); + +/** + * empty out an entire bucket brigade. This includes destroying all of the + * buckets within the bucket brigade's bucket list. This is similar to + * apr_brigade_destroy(), except that it does not deregister the brigade's + * pool cleanup function. + * @param data The bucket brigade to clean up + * @remark Generally, you should use apr_brigade_destroy(). This function + * can be useful in situations where you have a single brigade that + * you wish to reuse many times by destroying all of the buckets in + * the brigade and putting new buckets into it later. + */ +APU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data); + +/** + * Split a bucket brigade into two, such that the given bucket is the + * first in the new bucket brigade. This function is useful when a + * filter wants to pass only the initial part of a brigade to the next + * filter. + * @param b The brigade to split + * @param e The first element of the new brigade + * @return The new brigade + */ +APU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b, + apr_bucket *e); + +/** + * Partition a bucket brigade at a given offset (in bytes from the start of + * the brigade). This is useful whenever a filter wants to use known ranges + * of bytes from the brigade; the ranges can even overlap. + * @param b The brigade to partition + * @param point The offset at which to partition the brigade + * @param after_point Returns a pointer to the first bucket after the partition + * @return APR_SUCCESS on success, APR_INCOMPLETE if the contents of the + * brigade were shorter than @a point, or an error code. + * @remark if APR_INCOMPLETE is returned, @a after_point will be set to + * the brigade sentinel. + */ +APU_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b, + apr_off_t point, + apr_bucket **after_point); + +/** + * Return the total length of the brigade. + * @param bb The brigade to compute the length of + * @param read_all Read unknown-length buckets to force a size + * @param length Returns the length of the brigade, or -1 if the brigade has + * buckets of indeterminate length and read_all is 0. + */ +APU_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb, + int read_all, + apr_off_t *length); + +/** + * Take a bucket brigade and store the data in a flat char* + * @param bb The bucket brigade to create the char* from + * @param c The char* to write into + * @param len The maximum length of the char array. On return, it is the + * actual length of the char array. + */ +APU_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb, + char *c, + apr_size_t *len); + +/** + * Creates a pool-allocated string representing a flat bucket brigade + * @param bb The bucket brigade to create the char array from + * @param c On return, the allocated char array + * @param len On return, the length of the char array. + * @param pool The pool to allocate the string from. + */ +APU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb, + char **c, + apr_size_t *len, + apr_pool_t *pool); + +/** + * Split a brigade to represent one LF line. + * @param bbOut The bucket brigade that will have the LF line appended to. + * @param bbIn The input bucket brigade to search for a LF-line. + * @param block The blocking mode to be used to split the line. + * @param maxbytes The maximum bytes to read. If this many bytes are seen + * without a LF, the brigade will contain a partial line. + */ +APU_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut, + apr_bucket_brigade *bbIn, + apr_read_type_e block, + apr_off_t maxbytes); + +/** + * create an iovec of the elements in a bucket_brigade... return number + * of elements used. This is useful for writing to a file or to the + * network efficiently. + * @param b The bucket brigade to create the iovec from + * @param vec The iovec to create + * @param nvec The number of elements in the iovec. On return, it is the + * number of iovec elements actually filled out. + */ +APU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, + struct iovec *vec, int *nvec); + +/** + * This function writes a list of strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param va A list of strings to add + * @return APR_SUCCESS or error code. + */ +APU_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + va_list va); + +/** + * This function writes a string into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param str The string to add + * @param nbyte The number of bytes to write + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char *str, apr_size_t nbyte); + +/** + * This function writes multiple strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param vec The strings to add (address plus length for each) + * @param nvec The number of entries in iovec + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const struct iovec *vec, + apr_size_t nvec); + +/** + * This function writes a string into a bucket brigade. + * @param bb The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param str The string to add + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb, + apr_brigade_flush flush, void *ctx, + const char *str); + +/** + * This function writes a character into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param c The character to add + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char c); + +/** + * This function writes an unspecified number of strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param ... The strings to add + * @return APR_SUCCESS or error code + */ +APU_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, ...); + +/** + * Evaluate a printf and put the resulting string at the end + * of the bucket brigade. + * @param b The brigade to write to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param fmt The format of the string to write + * @param ... The arguments to fill out the format + * @return APR_SUCCESS or error code + */ +APU_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, ...) + __attribute__((format(printf,4,5))); + +/** + * Evaluate a printf and put the resulting string at the end + * of the bucket brigade. + * @param b The brigade to write to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param fmt The format of the string to write + * @param va The arguments to fill out the format + * @return APR_SUCCESS or error code + */ +APU_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, va_list va); + +/** + * Utility function to insert a file (or a segment of a file) onto the + * end of the brigade. The file is split into multiple buckets if it + * is larger than the maximum size which can be represented by a + * single bucket. + * @param bb the brigade to insert into + * @param f the file to insert + * @param start the offset of the start of the segment + * @param len the length of the segment of the file to insert + * @param p pool from which file buckets are allocated + * @return the last bucket inserted + */ +APU_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb, + apr_file_t *f, + apr_off_t start, + apr_off_t len, + apr_pool_t *p); + + + +/* ***** Bucket freelist functions ***** */ +/** + * Create a bucket allocator. + * @param p This pool's underlying apr_allocator_t is used to allocate memory + * for the bucket allocator. When the pool is destroyed, the bucket + * allocator's cleanup routine will free all memory that has been + * allocated from it. + * @remark The reason the allocator gets its memory from the pool's + * apr_allocator_t rather than from the pool itself is because + * the bucket allocator will free large memory blocks back to the + * allocator when it's done with them, thereby preventing memory + * footprint growth that would occur if we allocated from the pool. + * @warning The allocator must never be used by more than one thread at a time. + */ +APU_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create(apr_pool_t *p); + +/** + * Create a bucket allocator. + * @param allocator This apr_allocator_t is used to allocate both the bucket + * allocator and all memory handed out by the bucket allocator. The + * caller is responsible for destroying the bucket allocator and the + * apr_allocator_t -- no automatic cleanups will happen. + * @warning The allocator must never be used by more than one thread at a time. + */ +APU_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create_ex(apr_allocator_t *allocator); + +/** + * Destroy a bucket allocator. + * @param list The allocator to be destroyed + */ +APU_DECLARE_NONSTD(void) apr_bucket_alloc_destroy(apr_bucket_alloc_t *list); + +/** + * Allocate memory for use by the buckets. + * @param size The amount to allocate. + * @param list The allocator from which to allocate the memory. + */ +APU_DECLARE_NONSTD(void *) apr_bucket_alloc(apr_size_t size, apr_bucket_alloc_t *list); + +/** + * Free memory previously allocated with apr_bucket_alloc(). + * @param block The block of memory to be freed. + */ +APU_DECLARE_NONSTD(void) apr_bucket_free(void *block); + + +/* ***** Bucket Functions ***** */ +/** + * Free the resources used by a bucket. If multiple buckets refer to + * the same resource it is freed when the last one goes away. + * @see apr_bucket_delete() + * @param e The bucket to destroy + */ +#define apr_bucket_destroy(e) do { \ + (e)->type->destroy((e)->data); \ + (e)->free(e); \ + } while (0) + +/** + * Delete a bucket by removing it from its brigade (if any) and then + * destroying it. + * @remark This mainly acts as an aid in avoiding code verbosity. It is + * the preferred exact equivalent to: + *
+ *      APR_BUCKET_REMOVE(e);
+ *      apr_bucket_destroy(e);
+ * 
+ * @param e The bucket to delete + */ +#define apr_bucket_delete(e) do { \ + APR_BUCKET_REMOVE(e); \ + apr_bucket_destroy(e); \ + } while (0) + +/** + * read the data from the bucket + * @param e The bucket to read from + * @param str The location to store the data in + * @param len The amount of data read + * @param block Whether the read function blocks + */ +#define apr_bucket_read(e,str,len,block) (e)->type->read(e, str, len, block) + +/** + * Setaside data so that stack data is not destroyed on returning from + * the function + * @param e The bucket to setaside + * @param p The pool to setaside into + */ +#define apr_bucket_setaside(e,p) (e)->type->setaside(e,p) + +/** + * Split one bucket in two. + * @param e The bucket to split + * @param point The offset to split the bucket at + */ +#define apr_bucket_split(e,point) (e)->type->split(e, point) + +/** + * Copy a bucket. + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + */ +#define apr_bucket_copy(e,c) (e)->type->copy(e, c) + +/* Bucket type handling */ + +/** + * This function simply returns APR_SUCCESS to denote that the bucket does + * not require anything to happen for its setaside() function. This is + * appropriate for buckets that have "immortal" data -- the data will live + * at least as long as the bucket. + * @param data The bucket to setaside + * @param pool The pool defining the desired lifetime of the bucket data + * @return APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_noop(apr_bucket *data, + apr_pool_t *pool); + +/** + * A place holder function that signifies that the setaside function was not + * implemented for this bucket + * @param data The bucket to setaside + * @param pool The pool defining the desired lifetime of the bucket data + * @return APR_ENOTIMPL + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_notimpl(apr_bucket *data, + apr_pool_t *pool); + +/** + * A place holder function that signifies that the split function was not + * implemented for this bucket + * @param data The bucket to split + * @param point The location to split the bucket + * @return APR_ENOTIMPL + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_split_notimpl(apr_bucket *data, + apr_size_t point); + +/** + * A place holder function that signifies that the copy function was not + * implemented for this bucket + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + * @return APR_ENOTIMPL + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_copy_notimpl(apr_bucket *e, + apr_bucket **c); + +/** + * A place holder function that signifies that this bucket does not need + * to do anything special to be destroyed. That's only the case for buckets + * that either have no data (metadata buckets) or buckets whose data pointer + * points to something that's not a bucket-type-specific structure, as with + * simple buckets where data points to a string and pipe buckets where data + * points directly to the apr_file_t. + * @param data The bucket data to destroy + */ +APU_DECLARE_NONSTD(void) apr_bucket_destroy_noop(void *data); + +/** + * There is no apr_bucket_destroy_notimpl, because destruction is required + * to be implemented (it could be a noop, but only if that makes sense for + * the bucket type) + */ + +/* There is no apr_bucket_read_notimpl, because it is a required function + */ + + +/* All of the bucket types implemented by the core */ +/** + * The flush bucket type. This signifies that all data should be flushed to + * the next filter. The flush bucket should be sent with the other buckets. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_flush; +/** + * The EOS bucket type. This signifies that there will be no more data, ever. + * All filters MUST send all data to the next filter when they receive a + * bucket of this type + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_eos; +/** + * The FILE bucket type. This bucket represents a file on disk + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_file; +/** + * The HEAP bucket type. This bucket represents a data allocated from the + * heap. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_heap; +#if APR_HAS_MMAP +/** + * The MMAP bucket type. This bucket represents an MMAP'ed file + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_mmap; +#endif +/** + * The POOL bucket type. This bucket represents a data that was allocated + * from a pool. IF this bucket is still available when the pool is cleared, + * the data is copied on to the heap. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pool; +/** + * The PIPE bucket type. This bucket represents a pipe to another program. + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pipe; +/** + * The IMMORTAL bucket type. This bucket represents a segment of data that + * the creator is willing to take responsibility for. The core will do + * nothing with the data in an immortal bucket + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_immortal; +/** + * The TRANSIENT bucket type. This bucket represents a data allocated off + * the stack. When the setaside function is called, this data is copied on + * to the heap + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_transient; +/** + * The SOCKET bucket type. This bucket represents a socket to another machine + */ +APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_socket; + + +/* ***** Simple buckets ***** */ + +/** + * Split a simple bucket into two at the given point. Most non-reference + * counting buckets that allow multiple references to the same block of + * data (eg transient and immortal) will use this as their split function + * without any additional type-specific handling. + * @param b The bucket to be split + * @param point The offset of the first byte in the new bucket + * @return APR_EINVAL if the point is not within the bucket; + * APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_split(apr_bucket *b, + apr_size_t point); + +/** + * Copy a simple bucket. Most non-reference-counting buckets that allow + * multiple references to the same block of data (eg transient and immortal) + * will use this as their copy function without any additional type-specific + * handling. + * @param a The bucket to copy + * @param b Returns a pointer to the new bucket + * @return APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_copy(apr_bucket *a, + apr_bucket **b); + + +/* ***** Shared, reference-counted buckets ***** */ + +/** + * Initialize a bucket containing reference-counted data that may be + * shared. The caller must allocate the bucket if necessary and + * initialize its type-dependent fields, and allocate and initialize + * its own private data structure. This function should only be called + * by type-specific bucket creation functions. + * @param b The bucket to initialize + * @param data A pointer to the private data structure + * with the reference count at the start + * @param start The start of the data in the bucket + * relative to the private base pointer + * @param length The length of the data in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_shared_make(apr_bucket *b, void *data, + apr_off_t start, + apr_size_t length); + +/** + * Decrement the refcount of the data in the bucket. This function + * should only be called by type-specific bucket destruction functions. + * @param data The private data pointer from the bucket to be destroyed + * @return TRUE or FALSE; TRUE if the reference count is now + * zero, indicating that the shared resource itself can + * be destroyed by the caller. + */ +APU_DECLARE(int) apr_bucket_shared_destroy(void *data); + +/** + * Split a bucket into two at the given point, and adjust the refcount + * to the underlying data. Most reference-counting bucket types will + * be able to use this function as their split function without any + * additional type-specific handling. + * @param b The bucket to be split + * @param point The offset of the first byte in the new bucket + * @return APR_EINVAL if the point is not within the bucket; + * APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_split(apr_bucket *b, + apr_size_t point); + +/** + * Copy a refcounted bucket, incrementing the reference count. Most + * reference-counting bucket types will be able to use this function + * as their copy function without any additional type-specific handling. + * @param a The bucket to copy + * @param b Returns a pointer to the new bucket + * @return APR_ENOMEM if allocation failed; + or APR_SUCCESS + */ +APU_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_copy(apr_bucket *a, + apr_bucket **b); + + +/* ***** Functions to Create Buckets of varying types ***** */ +/* + * Each bucket type foo has two initialization functions: + * apr_bucket_foo_make which sets up some already-allocated memory as a + * bucket of type foo; and apr_bucket_foo_create which allocates memory + * for the bucket, calls apr_bucket_make_foo, and initializes the + * bucket's list pointers. The apr_bucket_foo_make functions are used + * inside the bucket code to change the type of buckets in place; + * other code should call apr_bucket_foo_create. All the initialization + * functions change nothing if they fail. + */ + +/** + * Create an End of Stream bucket. This indicates that there is no more data + * coming from down the filter stack. All filters should flush at this point. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_eos_create(apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in an EOS bucket. This indicates that there is no + * more data coming from down the filter stack. All filters should flush at + * this point. + * @param b The bucket to make into an EOS bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_eos_make(apr_bucket *b); + +/** + * Create a flush bucket. This indicates that filters should flush their + * data. There is no guarantee that they will flush it, but this is the + * best we can do. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_flush_create(apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a FLUSH bucket. This indicates that filters + * should flush their data. There is no guarantee that they will flush it, + * but this is the best we can do. + * @param b The bucket to make into a FLUSH bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_flush_make(apr_bucket *b); + +/** + * Create a bucket referring to long-lived data. + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_immortal_create(const char *buf, + apr_size_t nbyte, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to long-lived data + * @param b The bucket to make into a IMMORTAL bucket + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_immortal_make(apr_bucket *b, + const char *buf, + apr_size_t nbyte); + +/** + * Create a bucket referring to data on the stack. + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_transient_create(const char *buf, + apr_size_t nbyte, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to stack data + * @param b The bucket to make into a TRANSIENT bucket + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_transient_make(apr_bucket *b, + const char *buf, + apr_size_t nbyte); + +/** + * Create a bucket referring to memory on the heap. If the caller asks + * for the data to be copied, this function always allocates 4K of + * memory so that more data can be added to the bucket without + * requiring another allocation. Therefore not all the data may be put + * into the bucket. If copying is not requested then the bucket takes + * over responsibility for free()ing the memory. + * @param buf The buffer to insert into the bucket + * @param nbyte The size of the buffer to insert. + * @param free_func Function to use to free the data; NULL indicates that the + * bucket should make a copy of the data + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_heap_create(const char *buf, + apr_size_t nbyte, + void (*free_func)(void *data), + apr_bucket_alloc_t *list); +/** + * Make the bucket passed in a bucket refer to heap data + * @param b The bucket to make into a HEAP bucket + * @param buf The buffer to insert into the bucket + * @param nbyte The size of the buffer to insert. + * @param free_func Function to use to free the data; NULL indicates that the + * bucket should make a copy of the data + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_heap_make(apr_bucket *b, const char *buf, + apr_size_t nbyte, + void (*free_func)(void *data)); + +/** + * Create a bucket referring to memory allocated from a pool. + * + * @param buf The buffer to insert into the bucket + * @param length The number of bytes referred to by this bucket + * @param pool The pool the memory was allocated from + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf, + apr_size_t length, + apr_pool_t *pool, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to pool data + * @param b The bucket to make into a pool bucket + * @param buf The buffer to insert into the bucket + * @param length The number of bytes referred to by this bucket + * @param pool The pool the memory was allocated from + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b, const char *buf, + apr_size_t length, + apr_pool_t *pool); + +#if APR_HAS_MMAP +/** + * Create a bucket referring to mmap()ed memory. + * @param mm The mmap to insert into the bucket + * @param start The offset of the first byte in the mmap + * that this bucket refers to + * @param length The number of bytes referred to by this bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm, + apr_off_t start, + apr_size_t length, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to an MMAP'ed file + * @param b The bucket to make into a MMAP bucket + * @param mm The mmap to insert into the bucket + * @param start The offset of the first byte in the mmap + * that this bucket refers to + * @param length The number of bytes referred to by this bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm, + apr_off_t start, + apr_size_t length); +#endif + +/** + * Create a bucket referring to a socket. + * @param thissock The socket to put in the bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_socket_create(apr_socket_t *thissock, + apr_bucket_alloc_t *list); +/** + * Make the bucket passed in a bucket refer to a socket + * @param b The bucket to make into a SOCKET bucket + * @param thissock The socket to put in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_socket_make(apr_bucket *b, + apr_socket_t *thissock); + +/** + * Create a bucket referring to a pipe. + * @param thispipe The pipe to put in the bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pipe_create(apr_file_t *thispipe, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to a pipe + * @param b The bucket to make into a PIPE bucket + * @param thispipe The pipe to put in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_pipe_make(apr_bucket *b, + apr_file_t *thispipe); + +/** + * Create a bucket referring to a file. + * @param fd The file to put in the bucket + * @param offset The offset where the data of interest begins in the file + * @param len The amount of data in the file we are interested in + * @param p The pool into which any needed structures should be created + * while reading from this file bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_file_create(apr_file_t *fd, + apr_off_t offset, + apr_size_t len, + apr_pool_t *p, + apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in a bucket refer to a file + * @param b The bucket to make into a FILE bucket + * @param fd The file to put in the bucket + * @param offset The offset where the data of interest begins in the file + * @param len The amount of data in the file we are interested in + * @param p The pool into which any needed structures should be created + * while reading from this file bucket + * @return The new bucket, or NULL if allocation failed + */ +APU_DECLARE(apr_bucket *) apr_bucket_file_make(apr_bucket *b, apr_file_t *fd, + apr_off_t offset, + apr_size_t len, apr_pool_t *p); + +/** + * Enable or disable memory-mapping for a FILE bucket (default is enabled) + * @param b The bucket + * @param enabled Whether memory-mapping should be enabled + * @return APR_SUCCESS normally, or an error code if the operation fails + */ +APU_DECLARE(apr_status_t) apr_bucket_file_enable_mmap(apr_bucket *b, + int enabled); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_BUCKETS_H */ diff --git a/include/apr/apr_compat.h b/include/apr/apr_compat.h new file mode 100644 index 0000000..4720072 --- /dev/null +++ b/include/apr/apr_compat.h @@ -0,0 +1,230 @@ +/* Copyright 2000-2004 The Apache Software Foundation + * + * 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. + */ + +#ifndef APR_COMPAT_H +#define APR_COMPAT_H + + /** + * @file apr_compat.h + * @brief APR Legacy Apache 1.3 Compatibility + * @deprecated These defines are only present for historical purposes + */ + +/** + * @defgroup apr_compat APR Legacy Apache 1.3 Compatibility + * @ingroup APR + * @{ + */ + +/* redefine 1.3.x symbols to those that now live in libapr */ + +/** @see APR_INLINE */ +#define ap_inline APR_INLINE + +/** @deprecated @see apr_md5_ctx_t */ +#define ap_md5_ctx_t apr_md5_ctx_t +/** @deprecated @see apr_md5_encode */ +#define ap_MD5Encode apr_md5_encode +/** @deprecated @see apr_md5_final */ +#define ap_MD5Final apr_md5_final +/** @deprecated @see apr_md5_init */ +#define ap_MD5Init apr_md5_init +/** @deprecated @see apr_md5_update */ +#define ap_MD5Update apr_md5_update +/** @deprecated @see apr_array_append */ +#define ap_append_arrays apr_array_append +/** @deprecated @see apr_array_cat */ +#define ap_array_cat apr_array_cat +/** @deprecated @see apr_array_header_t */ +#define ap_array_header_t apr_array_header_t +/** @deprecated @see apr_array_pstrcat */ +#define ap_array_pstrcat apr_array_pstrcat +/** @deprecated @see apr_pool_free_blocks_num_bytes */ +#define ap_bytes_in_free_blocks apr_pool_free_blocks_num_bytes +/** @deprecated @see apr_pool_num_bytes */ +#define ap_bytes_in_pool apr_pool_num_bytes +/** @deprecated @see apr_check_file_time */ +#define ap_check_file_time apr_check_file_time +/** @deprecated @see apr_filetype_e */ +#define ap_filetype_e apr_filetype_e +/** @deprecated @see apr_pool_cleanup_for_exec */ +#define ap_cleanup_for_exec apr_pool_cleanup_for_exec +/** @deprecated @see apr_pool_clear */ +#define ap_clear_pool apr_pool_clear +/** @deprecated @see apr_table_clear */ +#define ap_clear_table apr_table_clear +/** @deprecated @see apr_array_copy */ +#define ap_copy_array apr_array_copy +/** @deprecated @see apr_array_copy_hdr */ +#define ap_copy_array_hdr apr_array_copy_hdr +/** @deprecated @see apr_table_copy */ +#define ap_copy_table apr_table_copy +/** @deprecated @see apr_cpystrn */ +#define ap_cpystrn apr_cpystrn +/** @deprecated @see apr_day_snames */ +#define ap_day_snames apr_day_snames +/** @deprecated @see apr_pool_destroy */ +#define ap_destroy_pool apr_pool_destroy +/** @deprecated @see apr_time_exp_t */ +#define ap_exploded_time_t apr_time_exp_t +/** @deprecated @see apr_fnmatch */ +#define ap_fnmatch apr_fnmatch +/** @deprecated @see apr_getopt */ +#define ap_getopt apr_getopt +/** @deprecated @see apr_inet_addr */ +#define ap_inet_addr apr_inet_addr +/** @deprecated @see apr_pool_alloc_init */ +#define ap_init_alloc apr_pool_alloc_init +/** @deprecated @see apr_is_empty_table */ +#define ap_is_empty_table apr_is_empty_table +/** @deprecated @see apr_fnmatch_test */ +#define ap_is_fnmatch apr_fnmatch_test +/** @deprecated @see apr_pool_cleanup_kill */ +#define ap_kill_cleanup apr_pool_cleanup_kill +/** @deprecated @see apr_array_make */ +#define ap_make_array apr_array_make +/** @deprecated @see apr_pool_sub_make */ +#define ap_make_sub_pool apr_pool_sub_make +/** @deprecated @see apr_table_make */ +#define ap_make_table apr_table_make +/** @deprecated @see apr_month_snames */ +#define ap_month_snames apr_month_snames +/** @deprecated @see apr_pool_note_subprocess*/ +#define ap_note_subprocess apr_pool_note_subprocess +/** @deprecated @see apr_pool_cleanup_null */ +#define ap_null_cleanup apr_pool_cleanup_null +/** @deprecated @see apr_filepath_merge */ +#define ap_os_canonical_filename apr_filepath_merge +/** @deprecated @see apr_filepath_merge */ +#define ap_os_case_canonical_filename apr_filepath_merge +/** @deprecated @see apr_dso_load */ +#define ap_os_dso_load apr_dso_load +/** @deprecated @see apr_dso_unload */ +#define ap_os_dso_unload apr_dso_unload +/** @deprecated @see apr_dso_sym */ +#define ap_os_dso_sym apr_dso_sym +/** @deprecated @see apr_dso_error */ +#define ap_os_dso_error apr_dso_error +/** @deprecated @see apr_filepath_merge + * @warning apr_filepath_merge rejects invalid filenames */ +#define ap_os_is_filename_valid apr_filepath_merge +/** @deprecated @see apr_proc_kill */ +#define ap_os_kill apr_proc_kill +/** @deprecated @see apr_filepath_merge */ +#define ap_os_systemcase_canonical_filename apr_filepath_merge +/** @deprecated @see apr_table_overlap */ +#define ap_overlap_tables apr_table_overlap +/** @deprecated @see apr_table_overlay */ +#define ap_overlay_tables apr_table_overlay +/** @deprecated @see apr_palloc */ +#define ap_palloc apr_palloc +/** @deprecated @see apr_pcalloc */ +#define ap_pcalloc apr_pcalloc +/** @deprecated @see apr_pool_join */ +#define ap_pool_join apr_pool_join +/** @deprecated @see apr_psprintf */ +#define ap_psprintf apr_psprintf +/** @deprecated @see apr_pstrcat */ +#define ap_pstrcat apr_pstrcat +/** @deprecated @see apr_pstrdup */ +#define ap_pstrdup apr_pstrdup +/** @deprecated @see apr_pstrndup */ +#define ap_pstrndup apr_pstrndup +/** @deprecated @see apr_array_push */ +#define ap_push_array apr_array_push +/** @deprecated @see apr_pvsprintf */ +#define ap_pvsprintf apr_pvsprintf +/** @deprecated @see apr_pool_cleanup_register */ +#define ap_register_cleanup apr_pool_cleanup_register +/** @deprecated @see apr_proc_other_child_register */ +#define ap_register_other_child apr_proc_other_child_register +/** @deprecated @see apr_pool_cleanup_run */ +#define ap_run_cleanup apr_pool_cleanup_run +/** @deprecated @see apr_signal */ +#define ap_signal apr_signal +/** @deprecated @see apr_snprintf */ +#define ap_snprintf apr_snprintf +/** @deprecated @see apr_table_add */ +#define ap_table_add apr_table_add +/** @deprecated @see apr_table_addn */ +#define ap_table_addn apr_table_addn +/** @deprecated @see apr_table_do */ +#define ap_table_do apr_table_do +/** @deprecated @see apr_table_elts */ +#define ap_table_elts apr_table_elts +/** @deprecated @see apr_table_get */ +#define ap_table_get apr_table_get +/** @deprecated @see apr_table_merge */ +#define ap_table_merge apr_table_merge +/** @deprecated @see apr_table_mergen */ +#define ap_table_mergen apr_table_mergen +/** @deprecated @see apr_table_set */ +#define ap_table_set apr_table_set +/** @deprecated @see apr_table_setn */ +#define ap_table_setn apr_table_setn +/** @deprecated @see apr_table_unset */ +#define ap_table_unset apr_table_unset +/** @deprecated @see apr_proc_other_child_unregister */ +#define ap_unregister_other_child apr_proc_other_child_unregister +/** @deprecated @see apr_password_validate */ +#define ap_validate_password apr_password_validate +/** @deprecated @see apr_vformatter */ +#define ap_vformatter apr_vformatter +/** @deprecated @see apr_vsnprintf */ +#define ap_vsnprintf apr_vsnprintf +/** @deprecated @see apr_wait_t */ +#define ap_wait_t apr_wait_t + +/** @deprecated @see apr_isalnum */ +#define ap_isalnum apr_isalnum +/** @deprecated @see apr_isalpha*/ +#define ap_isalpha apr_isalpha +/** @deprecated @see apr_iscntrl */ +#define ap_iscntrl apr_iscntrl +/** @deprecated @see apr_isdigit */ +#define ap_isdigit apr_isdigit +/** @deprecated @see apr_isgraph */ +#define ap_isgraph apr_isgraph +/** @deprecated @see apr_islower */ +#define ap_islower apr_islower +/** @deprecated @see apr_isascii */ +#define ap_isascii apr_isascii +/** @deprecated @see apr_isprint */ +#define ap_isprint apr_isprint +/** @deprecated @see apr_ispunct */ +#define ap_ispunct apr_ispunct +/** @deprecated @see apr_isspace */ +#define ap_isspace apr_isspace +/** @deprecated @see apr_isupper */ +#define ap_isupper apr_isupper +/** @deprecated @see apr_isxdigit */ +#define ap_isxdigit apr_isxdigit +/** @deprecated @see apr_tolower */ +#define ap_tolower apr_tolower +/** @deprecated @see apr_toupper */ +#define ap_toupper apr_toupper + +/** @deprecated @see APR_USEC_PER_SEC */ +#define AP_USEC_PER_SEC APR_USEC_PER_SEC +/** @deprecated @see APR_RFC822_DATE_LEN */ +#define AP_RFC822_DATE_LEN APR_RFC822_DATE_LEN +/** @deprecated @see APR_OVERLAP_TABLES_MERGE */ +#define AP_OVERLAP_TABLES_MERGE APR_OVERLAP_TABLES_MERGE +/** @deprecated @see APR_OVERLAP_TABLES_SET */ +#define AP_OVERLAP_TABLES_SET APR_OVERLAP_TABLES_SET + +/** @} */ + +#endif /* APR_COMPAT_H */ diff --git a/include/apr/apr_date.h b/include/apr/apr_date.h new file mode 100644 index 0000000..87500a3 --- /dev/null +++ b/include/apr/apr_date.h @@ -0,0 +1,106 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_DATE_H +#define APR_DATE_H + +/** + * @file apr_date.h + * @brief APR-UTIL date routines + */ + +/** + * @defgroup APR_Util_Date Date routines + * @ingroup APR_Util + * @{ + */ + +/* + * apr_date.h: prototypes for date parsing utility routines + */ + +#include "apu.h" +#include "apr_time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A bad date. */ +#define APR_DATE_BAD ((apr_time_t)0) + +/** + * Compare a string to a mask + * @param data The string to compare + * @param mask Mask characters (arbitrary maximum is 256 characters): + *
+ *   '\@' - uppercase letter
+ *   '\$' - lowercase letter
+ *   '\&' - hex digit
+ *   '#' - digit
+ *   '~' - digit or space
+ *   '*' - swallow remaining characters
+ * 
+ * @remark The mask tests for an exact match for any other character + * @return 1 if the string matches, 0 otherwise + */ +APU_DECLARE(int) apr_date_checkmask(const char *data, const char *mask); + +/** + * Parses an HTTP date in one of three standard forms: + *
+ *     Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+ *     Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ *     Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+ * 
+ * @param date The date in one of the three formats above + * @return the apr_time_t number of microseconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + */ +APU_DECLARE(apr_time_t) apr_date_parse_http(const char *date); + +/** + * Parses a string resembling an RFC 822 date. This is meant to be + * leinent in its parsing of dates. Hence, this will parse a wider + * range of dates than apr_date_parse_http. + * + * The prominent mailer (or poster, if mailer is unknown) that has + * been seen in the wild is included for the unknown formats. + *
+ *     Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+ *     Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ *     Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+ *     Sun, 6 Nov 1994 08:49:37 GMT   ; RFC 822, updated by RFC 1123
+ *     Sun, 06 Nov 94 08:49:37 GMT    ; RFC 822
+ *     Sun, 6 Nov 94 08:49:37 GMT     ; RFC 822
+ *     Sun, 06 Nov 94 08:49 GMT       ; Unknown [drtr\@ast.cam.ac.uk] 
+ *     Sun, 6 Nov 94 08:49 GMT        ; Unknown [drtr\@ast.cam.ac.uk]
+ *     Sun, 06 Nov 94 8:49:37 GMT     ; Unknown [Elm 70.85]
+ *     Sun, 6 Nov 94 8:49:37 GMT      ; Unknown [Elm 70.85] 
+ * 
+ * + * @param date The date in one of the formats above + * @return the apr_time_t number of microseconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + */ +APU_DECLARE(apr_time_t) apr_date_parse_rfc(const char *date); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_DATE_H */ diff --git a/include/apr/apr_dbd.h b/include/apr/apr_dbd.h new file mode 100644 index 0000000..7bdaaea --- /dev/null +++ b/include/apr/apr_dbd.h @@ -0,0 +1,333 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* Overview of what this is and does: + * http://www.apache.org/~niq/dbd.html + */ + +#ifndef APR_DBD_H +#define APR_DBD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_dbd.h + * @brief APR-UTIL DBD library + */ +/** + * @defgroup APR_Util_DBD DBD routines + * @ingroup APR_Util + * @{ + */ + +/* These are opaque structs. Instantiation is up to each backend */ +typedef struct apr_dbd_driver_t apr_dbd_driver_t; +typedef struct apr_dbd_t apr_dbd_t; +typedef struct apr_dbd_transaction_t apr_dbd_transaction_t; +typedef struct apr_dbd_results_t apr_dbd_results_t; +typedef struct apr_dbd_row_t apr_dbd_row_t; +typedef struct apr_dbd_prepared_t apr_dbd_prepared_t; + +/** apr_dbd_init: perform once-only initialisation. Call once only. + * + * @param pool - pool to register any shutdown cleanups, etc + */ +APU_DECLARE(apr_status_t) apr_dbd_init(apr_pool_t *pool); + +/** apr_dbd_get_driver: get the driver struct for a name + * + * @param pool - (process) pool to register cleanup + * @param name - driver name + * @param driver - pointer to driver struct. + * @return APR_SUCCESS for success + * @return APR_ENOTIMPL for no driver (when DSO not enabled) + * @return APR_EDSOOPEN if DSO driver file can't be opened + * @return APR_ESYMNOTFOUND if the driver file doesn't contain a driver + */ +APU_DECLARE(apr_status_t) apr_dbd_get_driver(apr_pool_t *pool, const char *name, + const apr_dbd_driver_t **driver); + +/** apr_dbd_open: open a connection to a backend + * + * @param ptmp - working pool + * @param params - arguments to driver (implementation-dependent) + * @param handle - pointer to handle to return + * @param driver - driver struct. + * @return APR_SUCCESS for success + * @return APR_EGENERAL if driver exists but connection failed + */ +APU_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver, + apr_pool_t *ptmp, const char *params, + apr_dbd_t **handle); + +/** apr_dbd_close: close a connection to a backend. + * Only required for explicit close or + * + * @param handle - handle to close + * @param driver - driver struct. + * @return APR_SUCCESS for success or error status + */ +APU_DECLARE(apr_status_t) apr_dbd_close(const apr_dbd_driver_t *driver, + apr_dbd_t *handle); + +/* apr-function-shaped versions of things */ + +/** apr_dbd_name: get the name of the driver + * + * @param driver - the driver + * @return - name + */ +APU_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t *driver); + +/** apr_dbd_native_handle: get native database handle of the underlying db + * + * @param driver - the driver + * @param handle - apr_dbd handle + * @return - native handle + */ +APU_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t *driver, + apr_dbd_t *handle); + +/** check_conn: check status of a database connection + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection to check + * @return APR_SUCCESS or error + */ +APU_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle); + +/** apr_dbd_set_dbname: select database name. May be a no-op if not supported. + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param name - the database to select + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, const char *name); + +/** apr_dbd_transaction_start: start a transaction. May be a no-op. + * + * @param driver - the driver + * @param pool - a pool to use for error messages (if any). + * @param handle - the db connection + * @param transaction - ptr to a transaction. May be null on entry + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, + apr_dbd_transaction_t **trans); + +/** apr_dbd_transaction_end: end a transaction + * (commit on success, rollback on error). + * May be a no-op. + * + * @param driver - the driver + * @param handle - the db connection + * @param transaction - the transaction. + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_transaction_t *trans); + +/** apr_dbd_query: execute an SQL query that doesn't return a result set + * + * @param driver - the driver + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the SQL statement to execute + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t *driver, apr_dbd_t *handle, + int *nrows, const char *statement); + +/** apr_dbd_select: execute an SQL query that returns a result set + * + * @param driver - the driver + * @param pool - pool to allocate the result set + * @param handle - the connection + * @param res - pointer to result set pointer. May point to NULL on entry + * @param statement - the SQL statement to execute + * @param random - 1 to support random access to results (seek any row); + * 0 to support only looping through results in order + * (async access - faster) + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + const char *statement, int random); + +/** apr_dbd_num_cols: get the number of columns in a results set + * + * @param driver - the driver + * @param res - result set. + * @return number of columns + */ +APU_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res); + +/** apr_dbd_num_tuples: get the number of rows in a results set + * of a synchronous select + * + * @param driver - the driver + * @param res - result set. + * @return number of rows, or -1 if the results are asynchronous + */ +APU_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res); + +/** apr_dbd_get_row: get a row from a result set + * + * @param driver - the driver + * @param pool - pool to allocate the row + * @param res - result set pointer + * @param row - pointer to row pointer. May point to NULL on entry + * @param rownum - row number, or -1 for "next row". Ignored if random + * access is not supported. + * @return 0 for success, -1 for rownum out of range or data finished + */ +APU_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_results_t *res, apr_dbd_row_t **row, + int rownum); + +/** apr_dbd_get_entry: get an entry from a row + * + * @param driver - the driver + * @param row - row pointer + * @param col - entry number + * @return value from the row, or NULL if col is out of bounds. + */ +APU_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col); + +/** apr_dbd_error: get current error message (if any) + * + * @param driver - the driver + * @param handle - the connection + * @param errnum - error code from operation that returned an error + * @return the database current error message, or message for errnum + * (implementation-dependent whether errnum is ignored) + */ +APU_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t *driver, + apr_dbd_t *handle, int errnum); + +/** apr_dbd_escape: escape a string so it is safe for use in query/select + * + * @param driver - the driver + * @param pool - pool to alloc the result from + * @param string - the string to escape + * @param handle - the connection + * @return the escaped, safe string + */ +APU_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *string, + apr_dbd_t *handle); + +/** apr_dbd_prepare: prepare a statement + * + * @param driver - the driver + * @param pool - pool to alloc the result from + * @param handle - the connection + * @param query - the SQL query + * @param label - A label for the prepared statement. + * use NULL for temporary prepared statements + * (eg within a Request in httpd) + * @param statement - statement to prepare. May point to null on entry. + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, const char *query, + const char *label, + apr_dbd_prepared_t **statement); + + +/** apr_dbd_pquery: query using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param nargs - number of args to prepared statement + * @param args - args to prepared statement + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, int nargs, + const char **args); + +/** apr_dbd_pselect: select using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param nargs - number of args to prepared statement + * @param args - args to prepared statement + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + int nargs, const char **args); + +/** apr_dbd_pvquery: query using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param ... - varargs list + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pvquery(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...); + +/** apr_dbd_pvselect: select using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param ... - varargs list + * @return 0 for success or error code + */ +APU_DECLARE(int) apr_dbd_pvselect(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + ...); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/apr/apr_dbm.h b/include/apr/apr_dbm.h new file mode 100644 index 0000000..d34f9ad --- /dev/null +++ b/include/apr/apr_dbm.h @@ -0,0 +1,224 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_DBM_H +#define APR_DBM_H + +#include "apu.h" +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_file_info.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_dbm.h + * @brief APR-UTIL DBM library + */ +/** + * @defgroup APR_Util_DBM DBM routines + * @ingroup APR_Util + * @{ + */ +/** + * Structure for referencing a dbm + */ +typedef struct apr_dbm_t apr_dbm_t; + +/** + * Structure for referencing the datum record within a dbm + */ +typedef struct +{ + /** pointer to the 'data' to retrieve/store in the DBM */ + char *dptr; + /** size of the 'data' to retrieve/store in the DBM */ + apr_size_t dsize; +} apr_datum_t; + +/* modes to open the DB */ +#define APR_DBM_READONLY 1 /**< open for read-only access */ +#define APR_DBM_READWRITE 2 /**< open for read-write access */ +#define APR_DBM_RWCREATE 3 /**< open for r/w, create if needed */ +#define APR_DBM_RWTRUNC 4 /**< open for r/w, truncating an existing + DB if present */ +/** + * Open a dbm file by file name and type of DBM + * @param dbm The newly opened database + * @param type The type of the DBM (not all may be available at run time) + *
+ *  GDBM for GDBM files
+ *  SDBM for SDBM files
+ *  DB   for berkeley DB files
+ *  NDBM for NDBM files
+ *  default for the default DBM type
+ *  
+ * @param name The dbm file name to open + * @param mode The flag value + *
+ *           APR_DBM_READONLY   open for read-only access
+ *           APR_DBM_READWRITE  open for read-write access
+ *           APR_DBM_RWCREATE   open for r/w, create if needed
+ *           APR_DBM_RWTRUNC    open for r/w, truncate if already there
+ * 
+ * @param perm Permissions to apply to if created + * @param cntxt The pool to use when creating the dbm + * @remark The dbm name may not be a true file name, as many dbm packages + * append suffixes for seperate data and index files. + */ + +APU_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **dbm, const char* type, + const char *name, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *cntxt); + + +/** + * Open a dbm file by file name + * @param dbm The newly opened database + * @param name The dbm file name to open + * @param mode The flag value + *
+ *           APR_DBM_READONLY   open for read-only access
+ *           APR_DBM_READWRITE  open for read-write access
+ *           APR_DBM_RWCREATE   open for r/w, create if needed
+ *           APR_DBM_RWTRUNC    open for r/w, truncate if already there
+ * 
+ * @param perm Permissions to apply to if created + * @param cntxt The pool to use when creating the dbm + * @remark The dbm name may not be a true file name, as many dbm packages + * append suffixes for seperate data and index files. + */ +APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **dbm, const char *name, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *cntxt); + +/** + * Close a dbm file previously opened by apr_dbm_open + * @param dbm The database to close + */ +APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm); + +/** + * Fetch a dbm record value by key + * @param dbm The database + * @param key The key datum to find this record + * @param pvalue The value datum retrieved for this record + */ +APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue); +/** + * Store a dbm record value by key + * @param dbm The database + * @param key The key datum to store this record by + * @param value The value datum to store in this record + */ +APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value); + +/** + * Delete a dbm record value by key + * @param dbm The database + * @param key The key datum of the record to delete + * @remark It is not an error to delete a non-existent record. + */ +APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key); + +/** + * Search for a key within the dbm + * @param dbm The database + * @param key The datum describing a key to test + */ +APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key); + +/** + * Retrieve the first record key from a dbm + * @param dbm The database + * @param pkey The key datum of the first record + */ +APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey); + +/** + * Retrieve the next record key from a dbm + * @param dbm The database + * @param pkey The key datum of the next record + */ +APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey); + +/** + * Proactively toss any memory associated with the apr_datum_t. + * @param dbm The database + * @param data The datum to free. + */ +APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data); + +/** + * Report more information when an apr_dbm function fails. + * @param dbm The database + * @param errcode A DBM-specific value for the error (for logging). If this + * isn't needed, it may be NULL. + * @param errbuf Location to store the error text + * @param errbufsize The size of the provided buffer + * @return The errbuf parameter, for convenience. + */ +APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode, + char *errbuf, apr_size_t errbufsize); +/** + * If the specified file/path were passed to apr_dbm_open(), return the + * actual file/path names which would be (created and) used. At most, two + * files may be used; used2 may be NULL if only one file is used. + * @param pool The pool for allocating used1 and used2. + * @param type The type of DBM you require info on + * @param pathname The path name to generate used-names from. + * @param used1 The first pathname used by the apr_dbm implementation. + * @param used2 The second pathname used by apr_dbm. If only one file is + * used by the specific implementation, this will be set to NULL. + * @return An error if the specified type is invalid. + * @remark The dbm file(s) don't need to exist. This function only manipulates + * the pathnames. + */ +APU_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *pool, + const char *type, + const char *pathname, + const char **used1, + const char **used2); + +/** + * If the specified file/path were passed to apr_dbm_open(), return the + * actual file/path names which would be (created and) used. At most, two + * files may be used; used2 may be NULL if only one file is used. + * @param pool The pool for allocating used1 and used2. + * @param pathname The path name to generate used-names from. + * @param used1 The first pathname used by the apr_dbm implementation. + * @param used2 The second pathname used by apr_dbm. If only one file is + * used by the specific implementation, this will be set to NULL. + * @remark The dbm file(s) don't need to exist. This function only manipulates + * the pathnames. + */ +APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *pool, + const char *pathname, + const char **used1, + const char **used2); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_DBM_H */ diff --git a/include/apr/apr_dso.h b/include/apr/apr_dso.h new file mode 100644 index 0000000..91c6d5b --- /dev/null +++ b/include/apr/apr_dso.h @@ -0,0 +1,94 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_DSO_DOT_H +#define APR_DSO_DOT_H + +/** + * @file apr_dso.h + * @brief APR Dynamic Object Handling Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_dso Dynamic Object Handling + * @ingroup APR + * @{ + */ + +#if APR_HAS_DSO || defined(DOXYGEN) + +/** + * Structure for referencing dynamic objects + */ +typedef struct apr_dso_handle_t apr_dso_handle_t; + +/** + * Structure for referencing symbols from dynamic objects + */ +typedef void * apr_dso_handle_sym_t; + +/** + * Load a DSO library. + * @param res_handle Location to store new handle for the DSO. + * @param path Path to the DSO library + * @param ctx Pool to use. + * @bug We aught to provide an alternative to RTLD_GLOBAL, which + * is the only supported method of loading DSOs today. + */ +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *ctx); + +/** + * Close a DSO library. + * @param handle handle to close. + */ +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle); + +/** + * Load a symbol from a DSO handle. + * @param ressym Location to store the loaded symbol + * @param handle handle to load the symbol from. + * @param symname Name of the symbol to load. + */ +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname); + +/** + * Report more information when a DSO function fails. + * @param dso The dso handle that has been opened + * @param buf Location to store the dso error + * @param bufsize The size of the provided buffer + */ +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buf, apr_size_t bufsize); + +#endif /* APR_HAS_DSO */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/apr/apr_env.h b/include/apr/apr_env.h new file mode 100644 index 0000000..9e3d2a7 --- /dev/null +++ b/include/apr/apr_env.h @@ -0,0 +1,67 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_ENV_H +#define APR_ENV_H +/** + * @file apr_env.h + * @brief APR Environment functions + */ +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_env Functions for manupulating the environment + * @ingroup APR + * @{ + */ + +/** + * Get the value of an environment variable + * @param value the returned value, allocated from @a pool + * @param envvar the name of the environment variable + * @param pool where to allocate @a value and any temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_get(char **value, const char *envvar, + apr_pool_t *pool); + +/** + * Set the value of an environment variable + * @param envvar the name of the environment variable + * @param value the value to set + * @param pool where to allocate temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_set(const char *envvar, const char *value, + apr_pool_t *pool); + +/** + * Delete a variable from the environment + * @param envvar the name of the environment variable + * @param pool where to allocate temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_ENV_H */ diff --git a/include/apr/apr_errno.h b/include/apr/apr_errno.h new file mode 100644 index 0000000..9f4e569 --- /dev/null +++ b/include/apr/apr_errno.h @@ -0,0 +1,1234 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_ERRNO_H +#define APR_ERRNO_H + +/** + * @file apr_errno.h + * @brief APR Error Codes + */ + +#include "apr.h" + +#if APR_HAVE_ERRNO_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_errno Error Codes + * @ingroup APR + * @{ + */ + +/** + * Type for specifying an error or status code. + */ +typedef int apr_status_t; + +/** + * Return a human readable string describing the specified error. + * @param statcode The error code the get a string for. + * @param buf A buffer to hold the error string. + * @param bufsize Size of the buffer to hold the string. + */ +APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize); + +#if defined(DOXYGEN) +/** + * @def APR_FROM_OS_ERROR(os_err_type syserr) + * Fold a platform specific error into an apr_status_t code. + * @return apr_status_t + * @param e The platform os error code. + * @warning macro implementation; the syserr argument may be evaluated + * multiple times. + */ +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) + +/** + * @def APR_TO_OS_ERROR(apr_status_t statcode) + * @return os_err_type + * Fold an apr_status_t code back to the native platform defined error. + * @param e The apr_status_t folded platform os error code. + * @warning macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. + */ +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +/** @def apr_get_os_error() + * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms + * @remark This retrieves errno, or calls a GetLastError() style function, and + * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no + * such mechanism, so this call may be unsupported. Do NOT use this + * call for socket errors from socket, send, recv etc! + */ + +/** @def apr_set_os_error(e) + * Reset the last platform error, unfolded from an apr_status_t, on some platforms + * @param e The OS error folded in a prior call to APR_FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a SetLastError() style function, unfolding statcode + * with APR_TO_OS_ERROR. Some platforms (such as OS2) have no such + * mechanism, so this call may be unsupported. + */ + +/** @def apr_get_netos_error() + * Return the last socket error, folded into apr_status_t, on all platforms + * @remark This retrieves errno or calls a GetLastSocketError() style function, + * and folds it with APR_FROM_OS_ERROR. + */ + +/** @def apr_set_netos_error(e) + * Reset the last socket error, unfolded from an apr_status_t + * @param e The socket error folded in a prior call to APR_FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a WSASetLastError() style function, unfolding + * socketcode with APR_TO_OS_ERROR. + */ + +#endif /* defined(DOXYGEN) */ + +/** + * APR_OS_START_ERROR is where the APR specific error values start. + */ +#define APR_OS_START_ERROR 20000 +/** + * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit + * into one of the error/status ranges below -- except for + * APR_OS_START_USERERR, which see. + */ +#define APR_OS_ERRSPACE_SIZE 50000 +/** + * APR_OS_START_STATUS is where the APR specific status codes start. + */ +#define APR_OS_START_STATUS (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_USERERR are reserved for applications that use APR that + * layer their own error codes along with APR's. Note that the + * error immediately following this one is set ten times farther + * away than usual, so that users of apr have a lot of room in + * which to declare custom error codes. + */ +#define APR_OS_START_USERERR (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_USEERR is obsolete, defined for compatibility only. + * Use APR_OS_START_USERERR instead. + */ +#define APR_OS_START_USEERR APR_OS_START_USERERR +/** + * APR_OS_START_CANONERR is where APR versions of errno values are defined + * on systems which don't have the corresponding errno. + */ +#define APR_OS_START_CANONERR (APR_OS_START_USERERR \ + + (APR_OS_ERRSPACE_SIZE * 10)) +/** + * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into + * apr_status_t values. + */ +#define APR_OS_START_EAIERR (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_SYSERR folds platform-specific system error values into + * apr_status_t values. + */ +#define APR_OS_START_SYSERR (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE) + +/** no error. */ +#define APR_SUCCESS 0 + +/** + * @defgroup APR_Error APR Error Values + *
+ * APR ERROR VALUES
+ * APR_ENOSTAT      APR was unable to perform a stat on the file 
+ * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
+ * APR_EBADDATE     APR was given an invalid date 
+ * APR_EINVALSOCK   APR was given an invalid socket
+ * APR_ENOPROC      APR was not given a process structure
+ * APR_ENOTIME      APR was not given a time structure
+ * APR_ENODIR       APR was not given a directory structure
+ * APR_ENOLOCK      APR was not given a lock structure
+ * APR_ENOPOLL      APR was not given a poll structure
+ * APR_ENOSOCKET    APR was not given a socket
+ * APR_ENOTHREAD    APR was not given a thread structure
+ * APR_ENOTHDKEY    APR was not given a thread key structure
+ * APR_ENOSHMAVAIL  There is no more shared memory available
+ * APR_EDSOOPEN     APR was unable to open the dso object.  For more 
+ *                  information call apr_dso_error().
+ * APR_EGENERAL     General failure (specific information not available)
+ * APR_EBADIP       The specified IP address is invalid
+ * APR_EBADMASK     The specified netmask is invalid
+ * APR_ESYMNOTFOUND Could not find the requested symbol
+ * 
+ * + *
+ * APR STATUS VALUES
+ * APR_INCHILD        Program is currently executing in the child
+ * APR_INPARENT       Program is currently executing in the parent
+ * APR_DETACH         The thread is detached
+ * APR_NOTDETACH      The thread is not detached
+ * APR_CHILD_DONE     The child has finished executing
+ * APR_CHILD_NOTDONE  The child has not finished executing
+ * APR_TIMEUP         The operation did not finish before the timeout
+ * APR_INCOMPLETE     The operation was incomplete although some processing
+ *                    was performed and the results are partially valid
+ * APR_BADCH          Getopt found an option not in the option string
+ * APR_BADARG         Getopt found an option that is missing an argument 
+ *                    and an argument was specified in the option string
+ * APR_EOF            APR has encountered the end of the file
+ * APR_NOTFOUND       APR was unable to find the socket in the poll structure
+ * APR_ANONYMOUS      APR is using anonymous shared memory
+ * APR_FILEBASED      APR is using a file name as the key to the shared memory
+ * APR_KEYBASED       APR is using a shared key as the key to the shared memory
+ * APR_EINIT          Ininitalizer value.  If no option has been found, but 
+ *                    the status variable requires a value, this should be used
+ * APR_ENOTIMPL       The APR function has not been implemented on this 
+ *                    platform, either because nobody has gotten to it yet, 
+ *                    or the function is impossible on this platform.
+ * APR_EMISMATCH      Two passwords do not match.
+ * APR_EABSOLUTE      The given path was absolute.
+ * APR_ERELATIVE      The given path was relative.
+ * APR_EINCOMPLETE    The given path was neither relative nor absolute.
+ * APR_EABOVEROOT     The given path was above the root path.
+ * APR_EBUSY          The given lock was busy.
+ * APR_EPROC_UNKNOWN  The given process wasn't recognized by APR
+ * 
+ * @{ + */ +/** @see APR_STATUS_IS_ENOSTAT */ +#define APR_ENOSTAT (APR_OS_START_ERROR + 1) +/** @see APR_STATUS_IS_ENOPOOL */ +#define APR_ENOPOOL (APR_OS_START_ERROR + 2) +/* empty slot: +3 */ +/** @see APR_STATUS_IS_EBADDATE */ +#define APR_EBADDATE (APR_OS_START_ERROR + 4) +/** @see APR_STATUS_IS_EINVALSOCK */ +#define APR_EINVALSOCK (APR_OS_START_ERROR + 5) +/** @see APR_STATUS_IS_ENOPROC */ +#define APR_ENOPROC (APR_OS_START_ERROR + 6) +/** @see APR_STATUS_IS_ENOTIME */ +#define APR_ENOTIME (APR_OS_START_ERROR + 7) +/** @see APR_STATUS_IS_ENODIR */ +#define APR_ENODIR (APR_OS_START_ERROR + 8) +/** @see APR_STATUS_IS_ENOLOCK */ +#define APR_ENOLOCK (APR_OS_START_ERROR + 9) +/** @see APR_STATUS_IS_ENOPOLL */ +#define APR_ENOPOLL (APR_OS_START_ERROR + 10) +/** @see APR_STATUS_IS_ENOSOCKET */ +#define APR_ENOSOCKET (APR_OS_START_ERROR + 11) +/** @see APR_STATUS_IS_ENOTHREAD */ +#define APR_ENOTHREAD (APR_OS_START_ERROR + 12) +/** @see APR_STATUS_IS_ENOTHDKEY */ +#define APR_ENOTHDKEY (APR_OS_START_ERROR + 13) +/** @see APR_STATUS_IS_EGENERAL */ +#define APR_EGENERAL (APR_OS_START_ERROR + 14) +/** @see APR_STATUS_IS_ENOSHMAVAIL */ +#define APR_ENOSHMAVAIL (APR_OS_START_ERROR + 15) +/** @see APR_STATUS_IS_EBADIP */ +#define APR_EBADIP (APR_OS_START_ERROR + 16) +/** @see APR_STATUS_IS_EBADMASK */ +#define APR_EBADMASK (APR_OS_START_ERROR + 17) +/* empty slot: +18 */ +/** @see APR_STATUS_IS_EDSOPEN */ +#define APR_EDSOOPEN (APR_OS_START_ERROR + 19) +/** @see APR_STATUS_IS_EABSOLUTE */ +#define APR_EABSOLUTE (APR_OS_START_ERROR + 20) +/** @see APR_STATUS_IS_ERELATIVE */ +#define APR_ERELATIVE (APR_OS_START_ERROR + 21) +/** @see APR_STATUS_IS_EINCOMPLETE */ +#define APR_EINCOMPLETE (APR_OS_START_ERROR + 22) +/** @see APR_STATUS_IS_EABOVEROOT */ +#define APR_EABOVEROOT (APR_OS_START_ERROR + 23) +/** @see APR_STATUS_IS_EBADPATH */ +#define APR_EBADPATH (APR_OS_START_ERROR + 24) +/** @see APR_STATUS_IS_EPATHWILD */ +#define APR_EPATHWILD (APR_OS_START_ERROR + 25) +/** @see APR_STATUS_IS_ESYMNOTFOUND */ +#define APR_ESYMNOTFOUND (APR_OS_START_ERROR + 26) +/** @see APR_STATUS_IS_EPROC_UNKNOWN */ +#define APR_EPROC_UNKNOWN (APR_OS_START_ERROR + 27) +/** @see APR_STATUS_IS_ENOTENOUGHENTROPY */ +#define APR_ENOTENOUGHENTROPY (APR_OS_START_ERROR + 28) +/** @} */ + +/** + * @defgroup APR_STATUS_IS Status Value Tests + * @warning For any particular error condition, more than one of these tests + * may match. This is because platform-specific error codes may not + * always match the semantics of the POSIX codes these tests (and the + * corresponding APR error codes) are named after. A notable example + * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on + * Win32 platforms. The programmer should always be aware of this and + * adjust the order of the tests accordingly. + * @{ + */ +/** + * APR was unable to perform a stat on the file + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOSTAT(s) ((s) == APR_ENOSTAT) +/** + * APR was not provided a pool with which to allocate memory + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOPOOL(s) ((s) == APR_ENOPOOL) +/** APR was given an invalid date */ +#define APR_STATUS_IS_EBADDATE(s) ((s) == APR_EBADDATE) +/** APR was given an invalid socket */ +#define APR_STATUS_IS_EINVALSOCK(s) ((s) == APR_EINVALSOCK) +/** APR was not given a process structure */ +#define APR_STATUS_IS_ENOPROC(s) ((s) == APR_ENOPROC) +/** APR was not given a time structure */ +#define APR_STATUS_IS_ENOTIME(s) ((s) == APR_ENOTIME) +/** APR was not given a directory structure */ +#define APR_STATUS_IS_ENODIR(s) ((s) == APR_ENODIR) +/** APR was not given a lock structure */ +#define APR_STATUS_IS_ENOLOCK(s) ((s) == APR_ENOLOCK) +/** APR was not given a poll structure */ +#define APR_STATUS_IS_ENOPOLL(s) ((s) == APR_ENOPOLL) +/** APR was not given a socket */ +#define APR_STATUS_IS_ENOSOCKET(s) ((s) == APR_ENOSOCKET) +/** APR was not given a thread structure */ +#define APR_STATUS_IS_ENOTHREAD(s) ((s) == APR_ENOTHREAD) +/** APR was not given a thread key structure */ +#define APR_STATUS_IS_ENOTHDKEY(s) ((s) == APR_ENOTHDKEY) +/** Generic Error which can not be put into another spot */ +#define APR_STATUS_IS_EGENERAL(s) ((s) == APR_EGENERAL) +/** There is no more shared memory available */ +#define APR_STATUS_IS_ENOSHMAVAIL(s) ((s) == APR_ENOSHMAVAIL) +/** The specified IP address is invalid */ +#define APR_STATUS_IS_EBADIP(s) ((s) == APR_EBADIP) +/** The specified netmask is invalid */ +#define APR_STATUS_IS_EBADMASK(s) ((s) == APR_EBADMASK) +/* empty slot: +18 */ +/** + * APR was unable to open the dso object. + * For more information call apr_dso_error(). + */ +#if defined(WIN32) +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN \ + || APR_TO_OS_ERROR(s) == ERROR_MOD_NOT_FOUND) +#else +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN) +#endif +/** The given path was absolute. */ +#define APR_STATUS_IS_EABSOLUTE(s) ((s) == APR_EABSOLUTE) +/** The given path was relative. */ +#define APR_STATUS_IS_ERELATIVE(s) ((s) == APR_ERELATIVE) +/** The given path was neither relative nor absolute. */ +#define APR_STATUS_IS_EINCOMPLETE(s) ((s) == APR_EINCOMPLETE) +/** The given path was above the root path. */ +#define APR_STATUS_IS_EABOVEROOT(s) ((s) == APR_EABOVEROOT) +/** The given path was bad. */ +#define APR_STATUS_IS_EBADPATH(s) ((s) == APR_EBADPATH) +/** The given path contained wildcards. */ +#define APR_STATUS_IS_EPATHWILD(s) ((s) == APR_EPATHWILD) +/** Could not find the requested symbol. + * For more information call apr_dso_error(). + */ +#if defined(WIN32) +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND \ + || APR_TO_OS_ERROR(s) == ERROR_PROC_NOT_FOUND) +#else +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND) +#endif +/** The given process was not recognized by APR. */ +#define APR_STATUS_IS_EPROC_UNKNOWN(s) ((s) == APR_EPROC_UNKNOWN) + +/** APR could not gather enough entropy to continue. */ +#define APR_STATUS_IS_ENOTENOUGHENTROPY(s) ((s) == APR_ENOTENOUGHENTROPY) + +/** @} */ + +/** + * @addtogroup APR_Error + * @{ + */ +/** @see APR_STATUS_IS_INCHILD */ +#define APR_INCHILD (APR_OS_START_STATUS + 1) +/** @see APR_STATUS_IS_INPARENT */ +#define APR_INPARENT (APR_OS_START_STATUS + 2) +/** @see APR_STATUS_IS_DETACH */ +#define APR_DETACH (APR_OS_START_STATUS + 3) +/** @see APR_STATUS_IS_NOTDETACH */ +#define APR_NOTDETACH (APR_OS_START_STATUS + 4) +/** @see APR_STATUS_IS_CHILD_DONE */ +#define APR_CHILD_DONE (APR_OS_START_STATUS + 5) +/** @see APR_STATUS_IS_CHILD_NOTDONE */ +#define APR_CHILD_NOTDONE (APR_OS_START_STATUS + 6) +/** @see APR_STATUS_IS_TIMEUP */ +#define APR_TIMEUP (APR_OS_START_STATUS + 7) +/** @see APR_STATUS_IS_INCOMPLETE */ +#define APR_INCOMPLETE (APR_OS_START_STATUS + 8) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** @see APR_STATUS_IS_BADCH */ +#define APR_BADCH (APR_OS_START_STATUS + 12) +/** @see APR_STATUS_IS_BADARG */ +#define APR_BADARG (APR_OS_START_STATUS + 13) +/** @see APR_STATUS_IS_EOF */ +#define APR_EOF (APR_OS_START_STATUS + 14) +/** @see APR_STATUS_IS_NOTFOUND */ +#define APR_NOTFOUND (APR_OS_START_STATUS + 15) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** @see APR_STATUS_IS_ANONYMOUS */ +#define APR_ANONYMOUS (APR_OS_START_STATUS + 19) +/** @see APR_STATUS_IS_FILEBASED */ +#define APR_FILEBASED (APR_OS_START_STATUS + 20) +/** @see APR_STATUS_IS_KEYBASED */ +#define APR_KEYBASED (APR_OS_START_STATUS + 21) +/** @see APR_STATUS_IS_EINIT */ +#define APR_EINIT (APR_OS_START_STATUS + 22) +/** @see APR_STATUS_IS_ENOTIMPL */ +#define APR_ENOTIMPL (APR_OS_START_STATUS + 23) +/** @see APR_STATUS_IS_EMISMATCH */ +#define APR_EMISMATCH (APR_OS_START_STATUS + 24) +/** @see APR_STATUS_IS_EBUSY */ +#define APR_EBUSY (APR_OS_START_STATUS + 25) +/** @} */ + +/** + * @addtogroup APR_STATUS_IS + * @{ + */ +/** + * Program is currently executing in the child + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code */ +#define APR_STATUS_IS_INCHILD(s) ((s) == APR_INCHILD) +/** + * Program is currently executing in the parent + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_INPARENT(s) ((s) == APR_INPARENT) +/** + * The thread is detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_DETACH(s) ((s) == APR_DETACH) +/** + * The thread is not detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_NOTDETACH(s) ((s) == APR_NOTDETACH) +/** + * The child has finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_CHILD_DONE(s) ((s) == APR_CHILD_DONE) +/** + * The child has not finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_CHILD_NOTDONE(s) ((s) == APR_CHILD_NOTDONE) +/** + * The operation did not finish before the timeout + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP) +/** + * The operation was incomplete although some processing was performed + * and the results are partially valid. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_INCOMPLETE(s) ((s) == APR_INCOMPLETE) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** + * Getopt found an option not in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_BADCH(s) ((s) == APR_BADCH) +/** + * Getopt found an option not in the option string and an argument was + * specified in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_BADARG(s) ((s) == APR_BADARG) +/** + * APR has encountered the end of the file + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EOF(s) ((s) == APR_EOF) +/** + * APR was unable to find the socket in the poll structure + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_NOTFOUND(s) ((s) == APR_NOTFOUND) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** + * APR is using anonymous shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ANONYMOUS(s) ((s) == APR_ANONYMOUS) +/** + * APR is using a file name as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_FILEBASED(s) ((s) == APR_FILEBASED) +/** + * APR is using a shared key as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_KEYBASED(s) ((s) == APR_KEYBASED) +/** + * Ininitalizer value. If no option has been found, but + * the status variable requires a value, this should be used + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EINIT(s) ((s) == APR_EINIT) +/** + * The APR function has not been implemented on this + * platform, either because nobody has gotten to it yet, + * or the function is impossible on this platform. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOTIMPL(s) ((s) == APR_ENOTIMPL) +/** + * Two passwords do not match. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EMISMATCH(s) ((s) == APR_EMISMATCH) +/** + * The given lock was busy + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EBUSY(s) ((s) == APR_EBUSY) + +/** @} */ + +/** + * @addtogroup APR_Error APR Error Values + * @{ + */ +/* APR CANONICAL ERROR VALUES */ +/** @see APR_STATUS_IS_EACCES */ +#ifdef EACCES +#define APR_EACCES EACCES +#else +#define APR_EACCES (APR_OS_START_CANONERR + 1) +#endif + +/** @see APR_STATUS_IS_EXIST */ +#ifdef EEXIST +#define APR_EEXIST EEXIST +#else +#define APR_EEXIST (APR_OS_START_CANONERR + 2) +#endif + +/** @see APR_STATUS_IS_ENAMETOOLONG */ +#ifdef ENAMETOOLONG +#define APR_ENAMETOOLONG ENAMETOOLONG +#else +#define APR_ENAMETOOLONG (APR_OS_START_CANONERR + 3) +#endif + +/** @see APR_STATUS_IS_ENOENT */ +#ifdef ENOENT +#define APR_ENOENT ENOENT +#else +#define APR_ENOENT (APR_OS_START_CANONERR + 4) +#endif + +/** @see APR_STATUS_IS_ENOTDIR */ +#ifdef ENOTDIR +#define APR_ENOTDIR ENOTDIR +#else +#define APR_ENOTDIR (APR_OS_START_CANONERR + 5) +#endif + +/** @see APR_STATUS_IS_ENOSPC */ +#ifdef ENOSPC +#define APR_ENOSPC ENOSPC +#else +#define APR_ENOSPC (APR_OS_START_CANONERR + 6) +#endif + +/** @see APR_STATUS_IS_ENOMEM */ +#ifdef ENOMEM +#define APR_ENOMEM ENOMEM +#else +#define APR_ENOMEM (APR_OS_START_CANONERR + 7) +#endif + +/** @see APR_STATUS_IS_EMFILE */ +#ifdef EMFILE +#define APR_EMFILE EMFILE +#else +#define APR_EMFILE (APR_OS_START_CANONERR + 8) +#endif + +/** @see APR_STATUS_IS_ENFILE */ +#ifdef ENFILE +#define APR_ENFILE ENFILE +#else +#define APR_ENFILE (APR_OS_START_CANONERR + 9) +#endif + +/** @see APR_STATUS_IS_EBADF */ +#ifdef EBADF +#define APR_EBADF EBADF +#else +#define APR_EBADF (APR_OS_START_CANONERR + 10) +#endif + +/** @see APR_STATUS_IS_EINVAL */ +#ifdef EINVAL +#define APR_EINVAL EINVAL +#else +#define APR_EINVAL (APR_OS_START_CANONERR + 11) +#endif + +/** @see APR_STATUS_IS_ESPIPE */ +#ifdef ESPIPE +#define APR_ESPIPE ESPIPE +#else +#define APR_ESPIPE (APR_OS_START_CANONERR + 12) +#endif + +/** + * @see APR_STATUS_IS_EAGAIN + * @warning use APR_STATUS_IS_EAGAIN instead of just testing this value + */ +#ifdef EAGAIN +#define APR_EAGAIN EAGAIN +#elif defined(EWOULDBLOCK) +#define APR_EAGAIN EWOULDBLOCK +#else +#define APR_EAGAIN (APR_OS_START_CANONERR + 13) +#endif + +/** @see APR_STATUS_IS_EINTR */ +#ifdef EINTR +#define APR_EINTR EINTR +#else +#define APR_EINTR (APR_OS_START_CANONERR + 14) +#endif + +/** @see APR_STATUS_IS_ENOTSOCK */ +#ifdef ENOTSOCK +#define APR_ENOTSOCK ENOTSOCK +#else +#define APR_ENOTSOCK (APR_OS_START_CANONERR + 15) +#endif + +/** @see APR_STATUS_IS_ECONNREFUSED */ +#ifdef ECONNREFUSED +#define APR_ECONNREFUSED ECONNREFUSED +#else +#define APR_ECONNREFUSED (APR_OS_START_CANONERR + 16) +#endif + +/** @see APR_STATUS_IS_EINPROGRESS */ +#ifdef EINPROGRESS +#define APR_EINPROGRESS EINPROGRESS +#else +#define APR_EINPROGRESS (APR_OS_START_CANONERR + 17) +#endif + +/** + * @see APR_STATUS_IS_ECONNABORTED + * @warning use APR_STATUS_IS_ECONNABORTED instead of just testing this value + */ + +#ifdef ECONNABORTED +#define APR_ECONNABORTED ECONNABORTED +#else +#define APR_ECONNABORTED (APR_OS_START_CANONERR + 18) +#endif + +/** @see APR_STATUS_IS_ECONNRESET */ +#ifdef ECONNRESET +#define APR_ECONNRESET ECONNRESET +#else +#define APR_ECONNRESET (APR_OS_START_CANONERR + 19) +#endif + +/** @see APR_STATUS_IS_ETIMEDOUT + * @deprecated */ +#ifdef ETIMEDOUT +#define APR_ETIMEDOUT ETIMEDOUT +#else +#define APR_ETIMEDOUT (APR_OS_START_CANONERR + 20) +#endif + +/** @see APR_STATUS_IS_EHOSTUNREACH */ +#ifdef EHOSTUNREACH +#define APR_EHOSTUNREACH EHOSTUNREACH +#else +#define APR_EHOSTUNREACH (APR_OS_START_CANONERR + 21) +#endif + +/** @see APR_STATUS_IS_ENETUNREACH */ +#ifdef ENETUNREACH +#define APR_ENETUNREACH ENETUNREACH +#else +#define APR_ENETUNREACH (APR_OS_START_CANONERR + 22) +#endif + +/** @see APR_STATUS_IS_EFTYPE */ +#ifdef EFTYPE +#define APR_EFTYPE EFTYPE +#else +#define APR_EFTYPE (APR_OS_START_CANONERR + 23) +#endif + +/** @see APR_STATUS_IS_EPIPE */ +#ifdef EPIPE +#define APR_EPIPE EPIPE +#else +#define APR_EPIPE (APR_OS_START_CANONERR + 24) +#endif + +/** @see APR_STATUS_IS_EXDEV */ +#ifdef EXDEV +#define APR_EXDEV EXDEV +#else +#define APR_EXDEV (APR_OS_START_CANONERR + 25) +#endif + +/** @see APR_STATUS_IS_ENOTEMPTY */ +#ifdef ENOTEMPTY +#define APR_ENOTEMPTY ENOTEMPTY +#else +#define APR_ENOTEMPTY (APR_OS_START_CANONERR + 26) +#endif + +/** @} */ + +#if defined(OS2) && !defined(DOXYGEN) + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define INCL_DOSERRORS +#define INCL_DOS + +/* Leave these undefined. + * OS2 doesn't rely on the errno concept. + * The API calls always return a result codes which + * should be filtered through APR_FROM_OS_ERROR(). + * + * #define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) + * #define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) + */ + +/* A special case, only socket calls require this; + */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(errno)) +#define apr_set_netos_error(e) (errno = APR_TO_OS_ERROR(e)) + +/* And this needs to be greped away for good: + */ +#define APR_OS2_STATUS(e) (APR_FROM_OS_ERROR(e)) + +/* These can't sit in a private header, so in spite of the extra size, + * they need to be made available here. + */ +#define SOCBASEERR 10000 +#define SOCEPERM (SOCBASEERR+1) /* Not owner */ +#define SOCESRCH (SOCBASEERR+3) /* No such process */ +#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ +#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ +#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ +#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ +#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ +#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ +#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ +#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ +#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ +#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ +#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ +#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ +#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ +#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ +#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ +#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ +#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ +#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ +#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ +#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ +#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ +#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ +#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ +#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ +#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ +#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ +#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ +#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ +#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ +#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ +#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ +#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ +#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ +#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ +#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ +#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ +#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ +#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ +#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ +#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ +#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ + || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == APR_OS_START_SYSERR + SOCENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ + || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == APR_OS_START_SYSERR + SOCEWOULDBLOCK \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + SOCEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + SOCENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + SOCECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + SOCEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + SOCECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + SOCECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + SOCEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + SOCENETUNREACH) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE \ + || (s) == APR_OS_START_SYSERR + SOCEPIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) + +/* + Sorry, too tired to wrap this up for OS2... feel free to + fit the following into their best matches. + + { ERROR_NO_SIGNAL_SENT, ESRCH }, + { SOCEALREADY, EALREADY }, + { SOCEDESTADDRREQ, EDESTADDRREQ }, + { SOCEMSGSIZE, EMSGSIZE }, + { SOCEPROTOTYPE, EPROTOTYPE }, + { SOCENOPROTOOPT, ENOPROTOOPT }, + { SOCEPROTONOSUPPORT, EPROTONOSUPPORT }, + { SOCESOCKTNOSUPPORT, ESOCKTNOSUPPORT }, + { SOCEOPNOTSUPP, EOPNOTSUPP }, + { SOCEPFNOSUPPORT, EPFNOSUPPORT }, + { SOCEAFNOSUPPORT, EAFNOSUPPORT }, + { SOCEADDRINUSE, EADDRINUSE }, + { SOCEADDRNOTAVAIL, EADDRNOTAVAIL }, + { SOCENETDOWN, ENETDOWN }, + { SOCENETRESET, ENETRESET }, + { SOCENOBUFS, ENOBUFS }, + { SOCEISCONN, EISCONN }, + { SOCENOTCONN, ENOTCONN }, + { SOCESHUTDOWN, ESHUTDOWN }, + { SOCETOOMANYREFS, ETOOMANYREFS }, + { SOCELOOP, ELOOP }, + { SOCEHOSTDOWN, EHOSTDOWN }, + { SOCENOTEMPTY, ENOTEMPTY }, + { SOCEPIPE, EPIPE } +*/ + +#elif defined(WIN32) && !defined(DOXYGEN) /* !defined(OS2) */ + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) +#define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) + +/* A special case, only socket calls require this: + */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) +#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_CANNOT_MAKE \ + || (s) == APR_OS_START_SYSERR + ERROR_CURRENT_DIRECTORY \ + || (s) == APR_OS_START_SYSERR + ERROR_DRIVE_LOCKED \ + || (s) == APR_OS_START_SYSERR + ERROR_FAIL_I24 \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_LOCKED \ + || (s) == APR_OS_START_SYSERR + ERROR_NETWORK_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ + || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == APR_OS_START_SYSERR + WSAENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_NETPATH \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_NET_NAME \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_PATHNAME \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DRIVE) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM \ + || (s) == APR_OS_START_SYSERR + ERROR_ARENA_TRASHED \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_MEMORY \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_BLOCK \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_QUOTA \ + || (s) == APR_OS_START_SYSERR + ERROR_OUTOFMEMORY) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ + || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_TARGET_HANDLE) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_ACCESS \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DATA \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_SEEK_ON_DEVICE \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_PROC_SLOTS \ + || (s) == APR_OS_START_SYSERR + ERROR_NESTING_NOT_ALLOWED \ + || (s) == APR_OS_START_SYSERR + ERROR_MAX_THRDS_REACHED \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + WSAEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + ERROR_NETNAME_DELETED \ + || (s) == APR_OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE \ + || (s) == APR_OS_START_SYSERR + ERROR_EXE_MACHINE_TYPE_MISMATCH \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DLL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_MODULETYPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_EXE_FORMAT \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_EXE_SIGNATURE \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_CORRUPT \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_FORMAT) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY) + +#elif defined(NETWARE) && defined(USE_WINSOCK) && !defined(DOXYGEN) /* !defined(OS2) && !defined(WIN32) */ + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define apr_get_os_error() (errno) +#define apr_set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) +#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) + +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == EWOULDBLOCK \ + || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + WSAEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) +#define APR_STATUS_IS_ENETDOWN(s) ((s) == APR_OS_START_SYSERR + WSAENETDOWN) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY) + +#else /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/* + * os error codes are clib error codes + */ +#define APR_FROM_OS_ERROR(e) (e) +#define APR_TO_OS_ERROR(e) (e) + +#define apr_get_os_error() (errno) +#define apr_set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: + */ +#define apr_get_netos_error() (errno) +#define apr_set_netos_error(e) (errno = (e)) + +/** + * @addtogroup APR_STATUS_IS + * @{ + */ + +/** permission denied */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) +/** file exists */ +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) +/** path name is too long */ +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) +/** + * no such file or directory + * @remark + * EMVSCATLG can be returned by the automounter on z/OS for + * paths which do not exist. + */ +#ifdef EMVSCATLG +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == EMVSCATLG) +#else +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) +#endif +/** not a directory */ +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +/** no space left on device */ +#ifdef EDQUOT +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == EDQUOT) +#else +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) +#endif +/** not enough memory */ +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +/** too many open files */ +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) +/** file table overflow */ +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +/** bad file # */ +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) +/** invalid argument */ +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) +/** illegal seek */ +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) + +/** operation would block */ +#if !defined(EWOULDBLOCK) || !defined(EAGAIN) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) +#elif (EWOULDBLOCK == EAGAIN) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) +#else +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == EWOULDBLOCK) +#endif + +/** interrupted system call */ +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR) +/** socket operation on a non-socket */ +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK) +/** Connection Refused */ +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED) +/** operation now in progress */ +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS) + +/** + * Software caused connection abort + * @remark + * EPROTO on certain older kernels really means ECONNABORTED, so we need to + * ignore it for them. See discussion in new-httpd archives nh.9701 & nh.9603 + * + * There is potentially a bug in Solaris 2.x x<6, and other boxes that + * implement tcp sockets in userland (i.e. on top of STREAMS). On these + * systems, EPROTO can actually result in a fatal loop. See PR#981 for + * example. It's hard to handle both uses of EPROTO. + */ +#ifdef EPROTO +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == EPROTO) +#else +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED) +#endif + +/** Connection Reset by peer */ +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET) +/** Operation timed out + * @deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT) +/** no route to host */ +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH) +/** network is unreachable */ +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH) +/** inappropiate file type or format */ +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +/** broken pipe */ +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) +/** cross device link */ +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) +/** Directory Not Empty */ +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY || \ + (s) == APR_EEXIST) +/** @} */ + +#endif /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_ERRNO_H */ diff --git a/include/apr/apr_file_info.h b/include/apr/apr_file_info.h new file mode 100644 index 0000000..bb41704 --- /dev/null +++ b/include/apr/apr_file_info.h @@ -0,0 +1,429 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_FILE_INFO_H +#define APR_FILE_INFO_H + +/** + * @file apr_file_info.h + * @brief APR File Information + */ + +#include "apr.h" +#include "apr_user.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_time.h" +#include "apr_errno.h" + +#if APR_HAVE_SYS_UIO_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_file_info File Information + * @ingroup APR + * @{ + */ + +/* Many applications use the type member to determine the + * existance of a file or initialization of the file info, + * so the APR_NOFILE value must be distinct from APR_UNKFILE. + */ + +/** apr_filetype_e values for the filetype member of the + * apr_file_info_t structure + * @warning: Not all of the filetypes below can be determined. + * For example, a given platform might not correctly report + * a socket descriptor as APR_SOCK if that type isn't + * well-identified on that platform. In such cases where + * a filetype exists but cannot be described by the recognized + * flags below, the filetype will be APR_UNKFILE. If the + * filetype member is not determined, the type will be APR_NOFILE. + */ + +typedef enum { + APR_NOFILE = 0, /**< no file type determined */ + APR_REG, /**< a regular file */ + APR_DIR, /**< a directory */ + APR_CHR, /**< a character device */ + APR_BLK, /**< a block device */ + APR_PIPE, /**< a FIFO / pipe */ + APR_LNK, /**< a symbolic link */ + APR_SOCK, /**< a [unix domain] socket */ + APR_UNKFILE = 127 /**< a file of some other unknown type */ +} apr_filetype_e; + +/** + * @defgroup apr_file_permissions File Permissions flags + * @{ + */ + +#define APR_FPROT_USETID 0x8000 /**< Set user id */ +#define APR_FPROT_UREAD 0x0400 /**< Read by user */ +#define APR_FPROT_UWRITE 0x0200 /**< Write by user */ +#define APR_FPROT_UEXECUTE 0x0100 /**< Execute by user */ + +#define APR_FPROT_GSETID 0x4000 /**< Set group id */ +#define APR_FPROT_GREAD 0x0040 /**< Read by group */ +#define APR_FPROT_GWRITE 0x0020 /**< Write by group */ +#define APR_FPROT_GEXECUTE 0x0010 /**< Execute by group */ + +#define APR_FPROT_WSTICKY 0x2000 /**< Sticky bit */ +#define APR_FPROT_WREAD 0x0004 /**< Read by others */ +#define APR_FPROT_WWRITE 0x0002 /**< Write by others */ +#define APR_FPROT_WEXECUTE 0x0001 /**< Execute by others */ + +#define APR_FPROT_OS_DEFAULT 0x0FFF /**< use OS's default permissions */ + +/* additional permission flags for apr_file_copy and apr_file_append */ +#define APR_FPROT_FILE_SOURCE_PERMS 0x1000 /**< Copy source file's permissions */ + +/* backcompat */ +#define APR_USETID APR_FPROT_USETID /**< @deprecated @see APR_FPROT_USETID */ +#define APR_UREAD APR_FPROT_UREAD /**< @deprecated @see APR_FPROT_UREAD */ +#define APR_UWRITE APR_FPROT_UWRITE /**< @deprecated @see APR_FPROT_UWRITE */ +#define APR_UEXECUTE APR_FPROT_UEXECUTE /**< @deprecated @see APR_FPROT_UEXECUTE */ +#define APR_GSETID APR_FPROT_GSETID /**< @deprecated @see APR_FPROT_GSETID */ +#define APR_GREAD APR_FPROT_GREAD /**< @deprecated @see APR_FPROT_GREAD */ +#define APR_GWRITE APR_FPROT_GWRITE /**< @deprecated @see APR_FPROT_GWRITE */ +#define APR_GEXECUTE APR_FPROT_GEXECUTE /**< @deprecated @see APR_FPROT_GEXECUTE */ +#define APR_WSTICKY APR_FPROT_WSTICKY /**< @deprecated @see APR_FPROT_WSTICKY */ +#define APR_WREAD APR_FPROT_WREAD /**< @deprecated @see APR_FPROT_WREAD */ +#define APR_WWRITE APR_FPROT_WWRITE /**< @deprecated @see APR_FPROT_WWRITE */ +#define APR_WEXECUTE APR_FPROT_WEXECUTE /**< @deprecated @see APR_FPROT_WEXECUTE */ +#define APR_OS_DEFAULT APR_FPROT_OS_DEFAULT /**< @deprecated @see APR_FPROT_OS_DEFAULT */ +#define APR_FILE_SOURCE_PERMS APR_FPROT_FILE_SOURCE_PERMS /**< @deprecated @see APR_FPROT_FILE_SOURCE_PERMS */ + +/** @} */ + + +/** + * Structure for referencing directories. + */ +typedef struct apr_dir_t apr_dir_t; +/** + * Structure for determining file permissions. + */ +typedef apr_int32_t apr_fileperms_t; +#if (defined WIN32) || (defined NETWARE) +/** + * Structure for determining the inode of the file. + */ +typedef apr_uint64_t apr_ino_t; +/** + * Structure for determining the device the file is on. + */ +typedef apr_uint32_t apr_dev_t; +#else +/** The inode of the file. */ +typedef ino_t apr_ino_t; +/** + * Structure for determining the device the file is on. + */ +typedef dev_t apr_dev_t; +#endif + +/** + * @defgroup apr_file_stat Stat Functions + * @{ + */ +/** file info structure */ +typedef struct apr_finfo_t apr_finfo_t; + +#define APR_FINFO_LINK 0x00000001 /**< Stat the link not the file itself if it is a link */ +#define APR_FINFO_MTIME 0x00000010 /**< Modification Time */ +#define APR_FINFO_CTIME 0x00000020 /**< Creation or inode-changed time */ +#define APR_FINFO_ATIME 0x00000040 /**< Access Time */ +#define APR_FINFO_SIZE 0x00000100 /**< Size of the file */ +#define APR_FINFO_CSIZE 0x00000200 /**< Storage size consumed by the file */ +#define APR_FINFO_DEV 0x00001000 /**< Device */ +#define APR_FINFO_INODE 0x00002000 /**< Inode */ +#define APR_FINFO_NLINK 0x00004000 /**< Number of links */ +#define APR_FINFO_TYPE 0x00008000 /**< Type */ +#define APR_FINFO_USER 0x00010000 /**< User */ +#define APR_FINFO_GROUP 0x00020000 /**< Group */ +#define APR_FINFO_UPROT 0x00100000 /**< User protection bits */ +#define APR_FINFO_GPROT 0x00200000 /**< Group protection bits */ +#define APR_FINFO_WPROT 0x00400000 /**< World protection bits */ +#define APR_FINFO_ICASE 0x01000000 /**< if dev is case insensitive */ +#define APR_FINFO_NAME 0x02000000 /**< ->name in proper case */ + +#define APR_FINFO_MIN 0x00008170 /**< type, mtime, ctime, atime, size */ +#define APR_FINFO_IDENT 0x00003000 /**< dev and inode */ +#define APR_FINFO_OWNER 0x00030000 /**< user and group */ +#define APR_FINFO_PROT 0x00700000 /**< all protections */ +#define APR_FINFO_NORM 0x0073b170 /**< an atomic unix apr_stat() */ +#define APR_FINFO_DIRENT 0x02000000 /**< an atomic unix apr_dir_read() */ + +/** + * The file information structure. This is analogous to the POSIX + * stat structure. + */ +struct apr_finfo_t { + /** Allocates memory and closes lingering handles in the specified pool */ + apr_pool_t *pool; + /** The bitmask describing valid fields of this apr_finfo_t structure + * including all available 'wanted' fields and potentially more */ + apr_int32_t valid; + /** The access permissions of the file. Mimics Unix access rights. */ + apr_fileperms_t protection; + /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, + * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. + * If the type cannot be determined, the value is APR_UNKFILE. + */ + apr_filetype_e filetype; + /** The user id that owns the file */ + apr_uid_t user; + /** The group id that owns the file */ + apr_gid_t group; + /** The inode of the file. */ + apr_ino_t inode; + /** The id of the device the file is on. */ + apr_dev_t device; + /** The number of hard links to the file. */ + apr_int32_t nlink; + /** The size of the file */ + apr_off_t size; + /** The storage size consumed by the file */ + apr_off_t csize; + /** The time the file was last accessed */ + apr_time_t atime; + /** The time the file was last modified */ + apr_time_t mtime; + /** The time the file was created, or the inode was last changed */ + apr_time_t ctime; + /** The pathname of the file (possibly unrooted) */ + const char *fname; + /** The file's name (no path) in filesystem case */ + const char *name; + /** The file's handle, if accessed (can be submitted to apr_duphandle) */ + struct apr_file_t *filehand; +}; + +/** + * get the specified file's stats. The file is specified by filename, + * instead of using a pre-opened file. + * @param finfo Where to store the information about the file, which is + * never touched if the call fails. + * @param fname The name of the file to stat. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ + values + * @param pool the pool to use to allocate the new file. + * + * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. + */ +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool); + +/** @} */ +/** + * @defgroup apr_dir Directory Manipulation Functions + * @{ + */ + +/** + * Open the specified directory. + * @param new_dir The opened directory descriptor. + * @param dirname The full path to the directory (use / on all systems) + * @param pool The pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new_dir, + const char *dirname, + apr_pool_t *pool); + +/** + * close the specified directory. + * @param thedir the directory descriptor to close. + */ +APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir); + +/** + * Read the next entry from the specified directory. + * @param finfo the file info structure and filled in by apr_dir_read + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ + values + * @param thedir the directory descriptor returned from apr_dir_open + * @remark No ordering is guaranteed for the entries read. + * + * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. + */ +APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, + apr_dir_t *thedir); + +/** + * Rewind the directory to the first entry. + * @param thedir the directory descriptor to rewind. + */ +APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir); +/** @} */ + +/** + * @defgroup apr_filepath Filepath Manipulation Functions + * @{ + */ + +/** Cause apr_filepath_merge to fail if addpath is above rootpath */ +#define APR_FILEPATH_NOTABOVEROOT 0x01 + +/** internal: Only meaningful with APR_FILEPATH_NOTABOVEROOT */ +#define APR_FILEPATH_SECUREROOTTEST 0x02 + +/** Cause apr_filepath_merge to fail if addpath is above rootpath, + * even given a rootpath /foo/bar and an addpath ../bar/bash + */ +#define APR_FILEPATH_SECUREROOT 0x03 + +/** Fail apr_filepath_merge if the merged path is relative */ +#define APR_FILEPATH_NOTRELATIVE 0x04 + +/** Fail apr_filepath_merge if the merged path is absolute */ +#define APR_FILEPATH_NOTABSOLUTE 0x08 + +/** Return the file system's native path format (e.g. path delimiters + * of ':' on MacOS9, '\' on Win32, etc.) */ +#define APR_FILEPATH_NATIVE 0x10 + +/** Resolve the true case of existing directories and file elements + * of addpath, (resolving any aliases on Win32) and append a proper + * trailing slash if a directory + */ +#define APR_FILEPATH_TRUENAME 0x20 + +/** + * Extract the rootpath from the given filepath + * @param rootpath the root file path returned with APR_SUCCESS or APR_EINCOMPLETE + * @param filepath the pathname to parse for its root component + * @param flags the desired rules to apply, from + *
+ *      APR_FILEPATH_NATIVE    Use native path seperators (e.g. '\' on Win32)
+ *      APR_FILEPATH_TRUENAME  Tests that the root exists, and makes it proper
+ * 
+ * @param p the pool to allocate the new path string from + * @remark on return, filepath points to the first non-root character in the + * given filepath. In the simplest example, given a filepath of "/foo", + * returns the rootpath of "/" and filepath points at "foo". This is far + * more complex on other platforms, which will canonicalize the root form + * to a consistant format, given the APR_FILEPATH_TRUENAME flag, and also + * test for the validity of that root (e.g., that a drive d:/ or network + * share //machine/foovol/). + * The function returns APR_ERELATIVE if filepath isn't rooted (an + * error), APR_EINCOMPLETE if the root path is ambigious (but potentially + * legitimate, e.g. "/" on Windows is incomplete because it doesn't specify + * the drive letter), or APR_EBADPATH if the root is simply invalid. + * APR_SUCCESS is returned if filepath is an absolute path. + */ +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, + const char **filepath, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Merge additional file path onto the previously processed rootpath + * @param newpath the merged paths returned + * @param rootpath the root file path (NULL uses the current working path) + * @param addpath the path to add to the root path + * @param flags the desired APR_FILEPATH_ rules to apply when merging + * @param p the pool to allocate the new path string from + * @remark if the flag APR_FILEPATH_TRUENAME is given, and the addpath + * contains wildcard characters ('*', '?') on platforms that don't support + * such characters within filenames, the paths will be merged, but the + * result code will be APR_EPATHWILD, and all further segments will not + * reflect the true filenames including the wildcard and following segments. + */ +APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, + const char *rootpath, + const char *addpath, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Split a search path into separate components + * @param pathelts the returned components of the search path + * @param liststr the search path (e.g., getenv("PATH")) + * @param p the pool to allocate the array and path components from + * @remark empty path componenta do not become part of @a pathelts. + * @remark the path separator in @a liststr is system specific; + * e.g., ':' on Unix, ';' on Windows, etc. + */ +APR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts, + const char *liststr, + apr_pool_t *p); + +/** + * Merge a list of search path components into a single search path + * @param liststr the returned search path; may be NULL if @a pathelts is empty + * @param pathelts the components of the search path + * @param p the pool to allocate the search path from + * @remark emtpy strings in the source array are ignored. + * @remark the path separator in @a liststr is system specific; + * e.g., ':' on Unix, ';' on Windows, etc. + */ +APR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr, + apr_array_header_t *pathelts, + apr_pool_t *p); + +/** + * Return the default file path (for relative file names) + * @param path the default path string returned + * @param flags optional flag APR_FILEPATH_NATIVE to retrieve the + * default file path in os-native format. + * @param p the pool to allocate the default path string from + */ +APR_DECLARE(apr_status_t) apr_filepath_get(char **path, apr_int32_t flags, + apr_pool_t *p); + +/** + * Set the default file path (for relative file names) + * @param path the default path returned + * @param p the pool to allocate any working storage + */ +APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p); + +/** The FilePath character encoding is unknown */ +#define APR_FILEPATH_ENCODING_UNKNOWN 0 + +/** The FilePath character encoding is locale-dependent */ +#define APR_FILEPATH_ENCODING_LOCALE 1 + +/** The FilePath character encoding is UTF-8 */ +#define APR_FILEPATH_ENCODING_UTF8 2 + +/** + * Determine the encoding used internally by the FilePath functions + * @param style points to a variable which receives the encoding style flag + * @param p the pool to allocate any working storage + * @remark Use @c apr_os_locale_encoding and/or @c apr_os_default_encoding + * to get the name of the path encoding if it's not UTF-8. + */ +APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p); +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_FILE_INFO_H */ diff --git a/include/apr/apr_file_io.h b/include/apr/apr_file_io.h new file mode 100644 index 0000000..847ecb0 --- /dev/null +++ b/include/apr/apr_file_io.h @@ -0,0 +1,806 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_FILE_IO_H +#define APR_FILE_IO_H + +/** + * @file apr_file_io.h + * @brief APR File I/O Handling + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_time.h" +#include "apr_errno.h" +#include "apr_file_info.h" +#include "apr_inherit.h" + +#define APR_WANT_STDIO /**< for SEEK_* */ +#define APR_WANT_IOVEC /**< for apr_file_writev */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_file_io File I/O Handling Functions + * @ingroup APR + * @{ + */ + +/** + * @defgroup apr_file_open_flags File Open Flags/Routines + * @{ + */ + +/* Note to implementors: Values in the range 0x00100000--0x80000000 + are reserved for platform-specific values. */ + +#define APR_FOPEN_READ 0x00001 /**< Open the file for reading */ +#define APR_FOPEN_WRITE 0x00002 /**< Open the file for writing */ +#define APR_FOPEN_CREATE 0x00004 /**< Create the file if not there */ +#define APR_FOPEN_APPEND 0x00008 /**< Append to the end of the file */ +#define APR_FOPEN_TRUNCATE 0x00010 /**< Open the file and truncate + to 0 length */ +#define APR_FOPEN_BINARY 0x00020 /**< Open the file in binary mode */ +#define APR_FOPEN_EXCL 0x00040 /**< Open should fail if APR_CREATE + and file exists. */ +#define APR_FOPEN_BUFFERED 0x00080 /**< Open the file for buffered I/O */ +#define APR_FOPEN_DELONCLOSE 0x00100 /**< Delete the file after close */ +#define APR_FOPEN_XTHREAD 0x00200 /**< Platform dependent tag to open + the file for use across multiple + threads */ +#define APR_FOPEN_SHARELOCK 0x00400 /**< Platform dependent support for + higher level locked read/write + access to support writes across + process/machines */ +#define APR_FOPEN_NOCLEANUP 0x00800 /**< Do not register a cleanup + when the file is opened */ +#define APR_FOPEN_SENDFILE_ENABLED 0x01000 /**< Advisory flag that this + file should support + apr_socket_sendfile operation */ +#define APR_FOPEN_LARGEFILE 0x04000 /**< Platform dependent flag to enable + large file support; WARNING see + below. */ +/* backcompat */ +#define APR_READ APR_FOPEN_READ /**< @deprecated @see APR_FOPEN_READ */ +#define APR_WRITE APR_FOPEN_WRITE /**< @deprecated @see APR_FOPEN_WRITE */ +#define APR_CREATE APR_FOPEN_CREATE /**< @deprecated @see APR_FOPEN_CREATE */ +#define APR_APPEND APR_FOPEN_APPEND /**< @deprecated @see APR_FOPEN_APPEND */ +#define APR_TRUNCATE APR_FOPEN_TRUNCATE /**< @deprecated @see APR_FOPEN_TRUNCATE */ +#define APR_BINARY APR_FOPEN_BINARY /**< @deprecated @see APR_FOPEN_BINARY */ +#define APR_EXCL APR_FOPEN_EXCL /**< @deprecated @see APR_FOPEN_EXCL */ +#define APR_BUFFERED APR_FOPEN_BUFFERED /**< @deprecated @see APR_FOPEN_BUFFERED */ +#define APR_DELONCLOSE APR_FOPEN_DELONCLOSE /**< @deprecated @see APR_FOPEN_DELONCLOSE */ +#define APR_XTHREAD APR_FOPEN_XTHREAD /**< @deprecated @see APR_FOPEN_XTHREAD */ +#define APR_SHARELOCK APR_FOPEN_SHARELOCK /**< @deprecated @see APR_FOPEN_SHARELOCK */ +#define APR_FILE_NOCLEANUP APR_FOPEN_NOCLEANUP /**< @deprecated @see APR_FOPEN_NOCLEANUP */ +#define APR_SENDFILE_ENABLED APR_FOPEN_SENDFILE_ENABLED /**< @deprecated @see APR_FOPEN_SENDFILE_ENABLED */ +#define APR_LARGEFILE APR_FOPEN_LARGEFILE /**< @deprecated @see APR_FOPEN_LARGEFILE */ + +/** @warning The APR_LARGEFILE flag only has effect on some platforms + * where sizeof(apr_off_t) == 4. Where implemented, it allows opening + * and writing to a file which exceeds the size which can be + * represented by apr_off_t (2 gigabytes). When a file's size does + * exceed 2Gb, apr_file_info_get() will fail with an error on the + * descriptor, likewise apr_stat()/apr_lstat() will fail on the + * filename. apr_dir_read() will fail with APR_INCOMPLETE on a + * directory entry for a large file depending on the particular + * APR_FINFO_* flags. Generally, it is not recommended to use this + * flag. */ + +/** @} */ + +/** + * @defgroup apr_file_seek_flags File Seek Flags + * @{ + */ + +/* flags for apr_file_seek */ +/** Set the file position */ +#define APR_SET SEEK_SET +/** Current */ +#define APR_CUR SEEK_CUR +/** Go to end of file */ +#define APR_END SEEK_END +/** @} */ + +/** + * @defgroup apr_file_attrs_set_flags File Attribute Flags + * @{ + */ + +/* flags for apr_file_attrs_set */ +#define APR_FILE_ATTR_READONLY 0x01 /**< File is read-only */ +#define APR_FILE_ATTR_EXECUTABLE 0x02 /**< File is executable */ +#define APR_FILE_ATTR_HIDDEN 0x04 /**< File is hidden */ +/** @} */ + +/** + * @defgroup apr_file_writev{_full} max iovec size + * @{ + */ +#if defined(DOXYGEN) +#define APR_MAX_IOVEC_SIZE 1024 /**< System dependent maximum + size of an iovec array */ +#elif defined(IOV_MAX) +#define APR_MAX_IOVEC_SIZE IOV_MAX +#elif defined(MAX_IOVEC) +#define APR_MAX_IOVEC_SIZE MAX_IOVEC +#else +#define APR_MAX_IOVEC_SIZE 1024 +#endif +/** @} */ + +/** File attributes */ +typedef apr_uint32_t apr_fileattrs_t; + +/** Type to pass as whence argument to apr_file_seek. */ +typedef int apr_seek_where_t; + +/** + * Structure for referencing files. + */ +typedef struct apr_file_t apr_file_t; + +/* File lock types/flags */ +/** + * @defgroup apr_file_lock_types File Lock Types + * @{ + */ + +#define APR_FLOCK_SHARED 1 /**< Shared lock. More than one process + or thread can hold a shared lock + at any given time. Essentially, + this is a "read lock", preventing + writers from establishing an + exclusive lock. */ +#define APR_FLOCK_EXCLUSIVE 2 /**< Exclusive lock. Only one process + may hold an exclusive lock at any + given time. This is analogous to + a "write lock". */ + +#define APR_FLOCK_TYPEMASK 0x000F /**< mask to extract lock type */ +#define APR_FLOCK_NONBLOCK 0x0010 /**< do not block while acquiring the + file lock */ +/** @} */ + +/** + * Open the specified file. + * @param newf The opened file descriptor. + * @param fname The full path to the file (using / on all systems) + * @param flag Or'ed value of: + *
+ *         APR_READ              open for reading
+ *         APR_WRITE             open for writing
+ *         APR_CREATE            create the file if not there
+ *         APR_APPEND            file ptr is set to end prior to all writes
+ *         APR_TRUNCATE          set length to zero if file exists
+ *         APR_BINARY            not a text file (This flag is ignored on 
+ *                               UNIX because it has no meaning)
+ *         APR_BUFFERED          buffer the data.  Default is non-buffered
+ *         APR_EXCL              return error if APR_CREATE and file exists
+ *         APR_DELONCLOSE        delete the file after closing.
+ *         APR_XTHREAD           Platform dependent tag to open the file
+ *                               for use across multiple threads
+ *         APR_SHARELOCK         Platform dependent support for higher
+ *                               level locked read/write access to support
+ *                               writes across process/machines
+ *         APR_FILE_NOCLEANUP    Do not register a cleanup with the pool 
+ *                               passed in on the pool argument (see below).
+ *                               The apr_os_file_t handle in apr_file_t will not
+ *                               be closed when the pool is destroyed.
+ *         APR_SENDFILE_ENABLED  Open with appropriate platform semantics
+ *                               for sendfile operations.  Advisory only,
+ *                               apr_socket_sendfile does not check this flag.
+ * 
+ * @param perm Access permissions for file. + * @param pool The pool to use. + * @remark If perm is APR_OS_DEFAULT and the file is being created, + * appropriate default permissions will be used. + */ +APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **newf, const char *fname, + apr_int32_t flag, apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Close the specified file. + * @param file The file descriptor to close. + */ +APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file); + +/** + * Delete the specified file. + * @param path The full path to the file (using / on all systems) + * @param pool The pool to use. + * @remark If the file is open, it won't be removed until all + * instances are closed. + */ +APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool); + +/** + * Rename the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param pool The pool to use. + * @warning If a file exists at the new location, then it will be + * overwritten. Moving files or directories across devices may not be + * possible. + */ +APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, + const char *to_path, + apr_pool_t *pool); + +/** + * Copy the specified file to another file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param perms Access permissions for the new file if it is created. + * In place of the usual or'd combination of file permissions, the + * value APR_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + * @remark The new file does not need to exist, it will be created if required. + * @warning If the new file already exists, its contents will be overwritten. + */ +APR_DECLARE(apr_status_t) apr_file_copy(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool); + +/** + * Append the specified file to another file. + * @param from_path The full path to the source file (use / on all systems) + * @param to_path The full path to the destination file (use / on all systems) + * @param perms Access permissions for the destination file if it is created. + * In place of the usual or'd combination of file permissions, the + * value APR_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + * @remark The new file does not need to exist, it will be created if required. + */ +APR_DECLARE(apr_status_t) apr_file_append(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool); + +/** + * Are we at the end of the file + * @param fptr The apr file we are testing. + * @remark Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise. + */ +APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr); + +/** + * Open standard error as an apr file pointer. + * @param thefile The apr file to use as stderr. + * @param pool The pool to allocate the file out of. + * + * @remark The only reason that the apr_file_open_std* functions exist + * is that you may not always have a stderr/out/in on Windows. This + * is generally a problem with newer versions of Windows and services. + * + * @remark The other problem is that the C library functions generally work + * differently on Windows and Unix. So, by using apr_file_open_std* + * functions, you can get a handle to an APR struct that works with + * the APR functions which are supposed to work identically on all + * platforms. + */ +APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard output as an apr file pointer. + * @param thefile The apr file to use as stdout. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stdout. + */ +APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard input as an apr file pointer. + * @param thefile The apr file to use as stdin. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stdout. + */ +APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * Read data from the specified file. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes On entry, the number of bytes to read; on exit, the number + * of bytes read. + * + * @remark apr_file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, all of the available data is read. The third + * argument is modified to reflect the number of bytes read. If a + * char was put back into the stream via ungetc, it will be the first + * character returned. + * + * @remark It is not possible for both bytes to be read and an APR_EOF + * or other error to be returned. APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, + apr_size_t *nbytes); + +/** + * Write data to the specified file. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes On entry, the number of bytes to write; on exit, the number + * of bytes written. + * + * @remark apr_file_write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, it + * will write as many as it can. The third argument is modified to + * reflect the * number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, + apr_size_t *nbytes); + +/** + * Write data from iovec array to the specified file. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + * + * @remark apr_file_writev is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes); + +/** + * Read data from the specified file, ensuring that the buffer is filled + * before returning. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes The number of bytes to read. + * @param bytes_read If non-NULL, this will contain the number of bytes read. + * + * @remark apr_file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, then the process/thread will block until it is + * available or EOF is reached. If a char was put back into the + * stream via ungetc, it will be the first character returned. + * + * @remark It is possible for both bytes to be read and an error to be + * returned. And if *bytes_read is less than nbytes, an accompanying + * error is _always_ returned. + * + * @remark APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_read_full(apr_file_t *thefile, void *buf, + apr_size_t nbytes, + apr_size_t *bytes_read); + +/** + * Write data to the specified file, ensuring that all of the data is + * written before returning. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes The number of bytes to write. + * @param bytes_written If non-NULL, set to the number of bytes written. + * + * @remark apr_file_write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, the + * process/thread will block until they can be written. Exceptional + * error such as "out of space" or "pipe closed" will terminate with + * an error. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. And if *bytes_written is less than nbytes, an + * accompanying error is _always_ returned. + * + * @remark APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile, + const void *buf, + apr_size_t nbytes, + apr_size_t *bytes_written); + + +/** + * Write data from iovec array to the specified file, ensuring that all of the + * data is written before returning. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark apr_file_writev_full is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *nbytes); +/** + * Write a character into the specified file. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile); + +/** + * Read a character from the specified file. + * @param ch The character to read into + * @param thefile The file descriptor to read from + */ +APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile); + +/** + * Put a character back onto a specified stream. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile); + +/** + * Read a string from the specified file. + * @param str The buffer to store the string in. + * @param len The length of the string + * @param thefile The file descriptor to read from + * @remark The buffer will be NUL-terminated if any characters are stored. + */ +APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, + apr_file_t *thefile); + +/** + * Write the string into the specified file. + * @param str The string to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile); + +/** + * Flush the file's buffer. + * @param thefile The file descriptor to flush + */ +APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile); + +/** + * Duplicate the specified file descriptor. + * @param new_file The structure to duplicate into. + * @param old_file The file to duplicate. + * @param p The pool to use for the new file. + * @remark *new_file must point to a valid apr_file_t, or point to NULL. + */ +APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Duplicate the specified file descriptor and close the original + * @param new_file The old file that is to be closed and reused + * @param old_file The file to duplicate + * @param p The pool to use for the new file + * + * @remark new_file MUST point at a valid apr_file_t. It cannot be NULL. + */ +APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Move the specified file descriptor to a new pool + * @param new_file Pointer in which to return the new apr_file_t + * @param old_file The file to move + * @param p The pool to which the descriptor is to be moved + * @remark Unlike apr_file_dup2(), this function doesn't do an + * OS dup() operation on the underlying descriptor; it just + * moves the descriptor's apr_file_t wrapper to a new pool. + * @remark The new pool need not be an ancestor of old_file's pool. + * @remark After calling this function, old_file may not be used + */ +APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Move the read/write file offset to a specified byte within a file. + * @param thefile The file descriptor + * @param where How to move the pointer, one of: + *
+ *            APR_SET  --  set the offset to offset
+ *            APR_CUR  --  add the offset to the current position 
+ *            APR_END  --  add the offset to the current file size 
+ * 
+ * @param offset The offset to move the pointer to. + * @remark The third argument is modified to be the offset the pointer + was actually moved to. + */ +APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, + apr_seek_where_t where, + apr_off_t *offset); + +/** + * Create an anonymous pipe. + * @param in The file descriptor to use as input to the pipe. + * @param out The file descriptor to use as output from the pipe. + * @param pool The pool to operate on. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool); + +/** + * Create a named pipe. + * @param filename The filename of the named pipe + * @param perm The permissions for the newly created pipe. + * @param pool The pool to operate on. + */ +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Get the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are getting a timeout for. + * @param timeout The current timeout value in microseconds. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, + apr_interval_time_t *timeout); + +/** + * Set the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are setting a timeout on. + * @param timeout The timeout value in microseconds. Values < 0 mean wait + * forever, 0 means do not wait at all. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, + apr_interval_time_t timeout); + +/** file (un)locking functions. */ + +/** + * Establish a lock on the specified, open file. The lock may be advisory + * or mandatory, at the discretion of the platform. The lock applies to + * the file as a whole, rather than a specific range. Locks are established + * on a per-thread/process basis; a second lock by the same thread will not + * block. + * @param thefile The file to lock. + * @param type The type of lock to establish on the file. + */ +APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type); + +/** + * Remove any outstanding locks on the file. + * @param thefile The file to unlock. + */ +APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile); + +/**accessor and general file_io functions. */ + +/** + * return the file name of the current file. + * @param new_path The path of the file. + * @param thefile The currently open file. + */ +APR_DECLARE(apr_status_t) apr_file_name_get(const char **new_path, + apr_file_t *thefile); + +/** + * Return the data associated with the current file. + * @param data The user data associated with the file. + * @param key The key to use for retreiving data associated with this file. + * @param file The currently open file. + */ +APR_DECLARE(apr_status_t) apr_file_data_get(void **data, const char *key, + apr_file_t *file); + +/** + * Set the data associated with the current file. + * @param file The currently open file. + * @param data The user data to associate with the file. + * @param key The key to use for assocaiteing data with the file. + * @param cleanup The cleanup routine to use when the file is destroyed. + */ +APR_DECLARE(apr_status_t) apr_file_data_set(apr_file_t *file, void *data, + const char *key, + apr_status_t (*cleanup)(void *)); + +/** + * Write a string to a file using a printf format. + * @param fptr The file to write to. + * @param format The format string + * @param ... The values to substitute in the format string + * @return The number of bytes written + */ +APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, + const char *format, ...) + __attribute__((format(printf,2,3))); + +/** + * set the specified file's permission bits. + * @param fname The file (name) to apply the permissions to. + * @param perms The permission bits to apply to the file. + * + * @warning Some platforms may not be able to apply all of the + * available permission bits; APR_INCOMPLETE will be returned if some + * permissions are specified which could not be set. + * + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, + apr_fileperms_t perms); + +/** + * Set attributes of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param attributes Or'd combination of + *
+ *            APR_FILE_ATTR_READONLY   - make the file readonly
+ *            APR_FILE_ATTR_EXECUTABLE - make the file executable
+ *            APR_FILE_ATTR_HIDDEN     - make the file hidden
+ * 
+ * @param attr_mask Mask of valid bits in attributes. + * @param pool the pool to use. + * @remark This function should be used in preference to explict manipulation + * of the file permissions, because the operations to provide these + * attributes are platform specific and may involve more than simply + * setting permission bits. + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *pool); + +/** + * Set the mtime of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param mtime The mtime to apply to the file. + * @param pool The pool to use. + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool); + +/** + * Create a new directory on the file system. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm, + apr_pool_t *pool); + +/** Creates a new directory on the file system, but behaves like + * 'mkdir -p'. Creates intermediate directories as required. No error + * will be reported if PATH already exists. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Remove directory from the file system. + * @param path the path for the directory to be removed. (use / on all systems) + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool); + +/** + * get the specified file's stats. + * @param finfo Where to store the information about the file. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values + * @param thefile The file to get information about. + */ +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_file_t *thefile); + + +/** + * Truncate the file's length to the specified offset + * @param fp The file to truncate + * @param offset The offset to truncate to. + */ +APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *fp, apr_off_t offset); + +/** + * Retrieve the flags that were passed into apr_file_open() + * when the file was opened. + * @return apr_int32_t the flags + */ +APR_DECLARE(apr_int32_t) apr_file_flags_get(apr_file_t *f); + +/** + * Get the pool used by the file. + */ +APR_POOL_DECLARE_ACCESSOR(file); + +/** + * Set a file to be inherited by child processes. + * + */ +APR_DECLARE_INHERIT_SET(file); + +/** + * Unset a file from being inherited by child processes. + */ +APR_DECLARE_INHERIT_UNSET(file); + +/** + * Open a temporary file + * @param fp The apr file to use as a temporary file. + * @param templ The template to use when creating a temp file. + * @param flags The flags to open the file with. If this is zero, + * the file is opened with + * APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_DELONCLOSE + * @param p The pool to allocate the file out of. + * @remark + * This function generates a unique temporary file name from template. + * The last six characters of template must be XXXXXX and these are replaced + * with a string that makes the filename unique. Since it will be modified, + * template must not be a string constant, but should be declared as a character + * array. + * + */ +APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *templ, + apr_int32_t flags, apr_pool_t *p); + + +/** + * Find an existing directory suitable as a temporary storage location. + * @param temp_dir The temp directory. + * @param p The pool to use for any necessary allocations. + * @remark + * This function uses an algorithm to search for a directory that an + * an application can use for temporary storage. Once such a + * directory is found, that location is cached by the library. Thus, + * callers only pay the cost of this algorithm once if that one time + * is successful. + * + */ +APR_DECLARE(apr_status_t) apr_temp_dir_get(const char **temp_dir, + apr_pool_t *p); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_FILE_IO_H */ diff --git a/include/apr/apr_fnmatch.h b/include/apr/apr_fnmatch.h new file mode 100644 index 0000000..7a2811a --- /dev/null +++ b/include/apr/apr_fnmatch.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 + */ + +/* This file has been modified by the Apache Software Foundation. */ +#ifndef _APR_FNMATCH_H_ +#define _APR_FNMATCH_H_ + +/** + * @file apr_fnmatch.h + * @brief APR FNMatch Functions + */ + +#include "apr_errno.h" +#include "apr_tables.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_fnmatch Filename Matching Functions + * @ingroup APR + * @{ + */ + +#define APR_FNM_NOMATCH 1 /**< Match failed. */ + +#define APR_FNM_NOESCAPE 0x01 /**< Disable backslash escaping. */ +#define APR_FNM_PATHNAME 0x02 /**< Slash must be matched by slash. */ +#define APR_FNM_PERIOD 0x04 /**< Period must be matched by period. */ +#define APR_FNM_CASE_BLIND 0x08 /**< Compare characters case-insensitively. + * @remark This flag is an Apache addition + */ + +/** + * Try to match the string to the given pattern, return APR_SUCCESS if + * match, else return APR_FNM_NOMATCH. + * @param pattern The pattern to match to + * @param strings The string we are trying to match + * @param flags flags to use in the match. Bitwise OR of: + *
+ *              APR_FNM_NOESCAPE       Disable backslash escaping
+ *              APR_FNM_PATHNAME       Slash must be matched by slash
+ *              APR_FNM_PERIOD         Period must be matched by period
+ *              APR_FNM_CASE_BLIND     Compare characters case-insensitively.
+ * 
+ */ + +APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, + const char *strings, int flags); + +/** + * Determine if the given pattern is a regular expression. + * @param pattern The pattern to search for glob characters. + * @return non-zero if pattern has any glob characters in it + */ +APR_DECLARE(int) apr_fnmatch_test(const char *pattern); + +/** + * Find all files that match a specified pattern. + * @param pattern The pattern to use for finding files. + * @param result Array to use when storing the results + * @param p The pool to use. + * @return non-zero if pattern has any glob characters in it + */ +APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern, + apr_array_header_t **result, + apr_pool_t *p); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_APR_FNMATCH_H_ */ diff --git a/include/apr/apr_general.h b/include/apr/apr_general.h new file mode 100644 index 0000000..5973a98 --- /dev/null +++ b/include/apr/apr_general.h @@ -0,0 +1,241 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_GENERAL_H +#define APR_GENERAL_H + +/** + * @file apr_general.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @brief APR Miscellaneous library routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#if APR_HAVE_SIGNAL_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_general Miscellaneous library routines + * @ingroup APR + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @{ + */ + +/** FALSE */ +#ifndef FALSE +#define FALSE 0 +#endif +/** TRUE */ +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +/** a space */ +#define APR_ASCII_BLANK '\040' +/** a carrige return */ +#define APR_ASCII_CR '\015' +/** a line feed */ +#define APR_ASCII_LF '\012' +/** a tab */ +#define APR_ASCII_TAB '\011' + +/** signal numbers typedef */ +typedef int apr_signum_t; + +/** + * Finding offsets of elements within structures. + * Taken from the X code... they've sweated portability of this stuff + * so we don't have to. Sigh... + * @param p_type pointer type name + * @param field data field within the structure pointed to + * @return offset + */ + +#if defined(CRAY) || (defined(__arm) && !defined(LINUX)) +#ifdef __STDC__ +#define APR_OFFSET(p_type,field) _Offsetof(p_type,field) +#else +#ifdef CRAY2 +#define APR_OFFSET(p_type,field) \ + (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) + +#else /* !CRAY2 */ + +#define APR_OFFSET(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) + +#endif /* !CRAY2 */ +#endif /* __STDC__ */ +#else /* ! (CRAY || __arm) */ + +#define APR_OFFSET(p_type,field) \ + ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) + +#endif /* !CRAY */ + +/** + * Finding offsets of elements within structures. + * @param s_type structure type name + * @param field data field within the structure + * @return offset + */ +#if defined(offsetof) && !defined(__cplusplus) +#define APR_OFFSETOF(s_type,field) offsetof(s_type,field) +#else +#define APR_OFFSETOF(s_type,field) APR_OFFSET(s_type*,field) +#endif + +#ifndef DOXYGEN + +/* A couple of prototypes for functions in case some platform doesn't + * have it + */ +#if (!APR_HAVE_STRCASECMP) && (APR_HAVE_STRICMP) +#define strcasecmp(s1, s2) stricmp(s1, s2) +#elif (!APR_HAVE_STRCASECMP) +int strcasecmp(const char *a, const char *b); +#endif + +#if (!APR_HAVE_STRNCASECMP) && (APR_HAVE_STRNICMP) +#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n) +#elif (!APR_HAVE_STRNCASECMP) +int strncasecmp(const char *a, const char *b, size_t n); +#endif + +#endif + +/** + * Alignment macros + */ + +/* APR_ALIGN() is only to be used to align on a power of 2 boundary */ +#define APR_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) + +/** Default alignment */ +#define APR_ALIGN_DEFAULT(size) APR_ALIGN(size, 8) + + +/** + * String and memory functions + */ + +/* APR_STRINGIFY is defined here, and also in apr_release.h, so wrap it */ +#ifndef APR_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) +/** Helper macro for APR_STRINGIFY */ +#define APR_STRINGIFY_HELPER(n) #n +#endif + +#if (!APR_HAVE_MEMMOVE) +#define memmove(a,b,c) bcopy(b,a,c) +#endif + +#if (!APR_HAVE_MEMCHR) +void *memchr(const void *s, int c, size_t n); +#endif + +/** @} */ + +/** + * @defgroup apr_library Library initialization and termination + * @{ + */ + +/** + * Setup any APR internal data structures. This MUST be the first function + * called for any APR library. + * @remark See apr_app_initialize if this is an application, rather than + * a library consumer of apr. + */ +APR_DECLARE(apr_status_t) apr_initialize(void); + +/** + * Set up an application with normalized argc, argv (and optionally env) in + * order to deal with platform-specific oddities, such as Win32 services, + * code pages and signals. This must be the first function called for any + * APR program. + * @param argc Pointer to the argc that may be corrected + * @param argv Pointer to the argv that may be corrected + * @param env Pointer to the env that may be corrected, may be NULL + * @remark See apr_initialize if this is a library consumer of apr. + * Otherwise, this call is identical to apr_initialize, and must be closed + * with a call to apr_terminate at the end of program execution. + */ +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + char const * const * *argv, + char const * const * *env); + +/** + * Tear down any APR internal data structures which aren't torn down + * automatically. + * @remark An APR program must call this function at termination once it + * has stopped using APR services. The APR developers suggest using + * atexit to ensure this is called. When using APR from a language + * other than C that has problems with the calling convention, use + * apr_terminate2() instead. + */ +APR_DECLARE_NONSTD(void) apr_terminate(void); + +/** + * Tear down any APR internal data structures which aren't torn down + * automatically, same as apr_terminate + * @remark An APR program must call either the apr_terminate or apr_terminate2 + * function once it it has finished using APR services. The APR + * developers suggest using atexit(apr_terminate) to ensure this is done. + * apr_terminate2 exists to allow non-c language apps to tear down apr, + * while apr_terminate is recommended from c language applications. + */ +APR_DECLARE(void) apr_terminate2(void); + +/** @} */ + +/** + * @defgroup apr_random Random Functions + * @{ + */ + +#if APR_HAS_RANDOM || defined(DOXYGEN) + +/* TODO: I'm not sure this is the best place to put this prototype...*/ +/** + * Generate random bytes. + * @param buf Buffer to fill with random bytes + * @param length Length of buffer in bytes + */ +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf, + apr_size_t length); + +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_GENERAL_H */ diff --git a/include/apr/apr_getopt.h b/include/apr/apr_getopt.h new file mode 100644 index 0000000..972e14e --- /dev/null +++ b/include/apr/apr_getopt.h @@ -0,0 +1,158 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_GETOPT_H +#define APR_GETOPT_H + +/** + * @file apr_getopt.h + * @brief APR Command Arguments (getopt) + */ + +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_getopt Command Argument Parsing + * @ingroup APR + * @{ + */ + +/** + * defintion of a error function + */ +typedef void (apr_getopt_err_fn_t)(void *arg, const char *err, ...); + +/** @see apr_getopt_t */ +typedef struct apr_getopt_t apr_getopt_t; + +/** + * Structure to store command line argument information. + */ +struct apr_getopt_t { + /** context for processing */ + apr_pool_t *cont; + /** function to print error message (NULL == no messages) */ + apr_getopt_err_fn_t *errfn; + /** user defined first arg to pass to error message */ + void *errarg; + /** index into parent argv vector */ + int ind; + /** character checked for validity */ + int opt; + /** reset getopt */ + int reset; + /** count of arguments */ + int argc; + /** array of pointers to arguments */ + const char **argv; + /** argument associated with option */ + char const* place; + /** set to nonzero to support interleaving options with regular args */ + int interleave; + /** start of non-option arguments skipped for interleaving */ + int skip_start; + /** end of non-option arguments skipped for interleaving */ + int skip_end; +}; + +/** @see apr_getopt_option_t */ +typedef struct apr_getopt_option_t apr_getopt_option_t; + +/** + * Structure used to describe options that getopt should search for. + */ +struct apr_getopt_option_t { + /** long option name, or NULL if option has no long name */ + const char *name; + /** option letter, or a value greater than 255 if option has no letter */ + int optch; + /** nonzero if option takes an argument */ + int has_arg; + /** a description of the option */ + const char *description; +}; + +/** + * Initialize the arguments for parsing by apr_getopt(). + * @param os The options structure created for apr_getopt() + * @param cont The pool to operate on + * @param argc The number of arguments to parse + * @param argv The array of arguments to parse + * @remark Arguments 2 and 3 are most commonly argc and argv from main(argc, argv) + * The errfn is initialized to fprintf(stderr... but may be overridden. + */ +APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont, + int argc, const char * const *argv); + +/** + * Parse the options initialized by apr_getopt_init(). + * @param os The apr_opt_t structure returned by apr_getopt_init() + * @param opts A string of characters that are acceptable options to the + * program. Characters followed by ":" are required to have an + * option associated + * @param option_ch The next option character parsed + * @param option_arg The argument following the option character: + * @return There are four potential status values on exit. They are: + *
+ *             APR_EOF      --  No more options to parse
+ *             APR_BADCH    --  Found a bad option character
+ *             APR_BADARG   --  No argument followed the option flag
+ *             APR_SUCCESS  --  The next option was found.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, + char *option_ch, const char **option_arg); + +/** + * Parse the options initialized by apr_getopt_init(), accepting long + * options beginning with "--" in addition to single-character + * options beginning with "-". + * @param os The apr_getopt_t structure created by apr_getopt_init() + * @param opts A pointer to a list of apr_getopt_option_t structures, which + * can be initialized with { "name", optch, has_args }. has_args + * is nonzero if the option requires an argument. A structure + * with an optch value of 0 terminates the list. + * @param option_ch Receives the value of "optch" from the apr_getopt_option_t + * structure corresponding to the next option matched. + * @param option_arg Receives the argument following the option, if any. + * @return There are four potential status values on exit. They are: + *
+ *             APR_EOF      --  No more options to parse
+ *             APR_BADCH    --  Found a bad option character
+ *             APR_BADARG   --  No argument followed the option flag
+ *             APR_SUCCESS  --  The next option was found.
+ * 
+ * When APR_SUCCESS is returned, os->ind gives the index of the first + * non-option argument. On error, a message will be printed to stdout unless + * os->err is set to 0. If os->interleave is set to nonzero, options can come + * after arguments, and os->argv will be permuted to leave non-option arguments + * at the end (the original argv is unaffected). + */ +APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os, + const apr_getopt_option_t *opts, + int *option_ch, + const char **option_arg); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_GETOPT_H */ diff --git a/include/apr/apr_global_mutex.h b/include/apr/apr_global_mutex.h new file mode 100644 index 0000000..7decb28 --- /dev/null +++ b/include/apr/apr_global_mutex.h @@ -0,0 +1,153 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_GLOBAL_MUTEX_H +#define APR_GLOBAL_MUTEX_H + +/** + * @file apr_global_mutex.h + * @brief APR Global Locking Routines + */ + +#include "apr.h" +#include "apr_proc_mutex.h" /* only for apr_lockmech_e */ +#include "apr_pools.h" +#include "apr_errno.h" +#if APR_PROC_MUTEX_IS_GLOBAL +#include "apr_proc_mutex.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_GlobalMutex Global Locking Routines + * @ingroup APR + * @{ + */ + +#if !APR_PROC_MUTEX_IS_GLOBAL || defined(DOXYGEN) + +/** Opaque global mutex structure. */ +typedef struct apr_global_mutex_t apr_global_mutex_t; + +/* Function definitions */ + +/** + * Create and initialize a mutex that can be used to synchronize both + * processes and threads. Note: There is considerable overhead in using + * this API if only cross-process or cross-thread mutual exclusion is + * required. See apr_proc_mutex.h and apr_thread_mutex.h for more + * specialized lock routines. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + *
+ *            APR_LOCK_FCNTL
+ *            APR_LOCK_FLOCK
+ *            APR_LOCK_SYSVSEM
+ *            APR_LOCK_POSIXSEM
+ *            APR_LOCK_PROC_PTHREAD
+ *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_create(apr_global_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool); + +/** + * Re-open a mutex in a child process. + * @param mutex The newly re-opened mutex structure. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_global_mutex_create(). + * @param pool The pool to operate on. + * @remark This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_child_init( + apr_global_mutex_t **mutex, + const char *fname, + apr_pool_t *pool); + +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_lock(apr_global_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_trylock(apr_global_mutex_t *mutex); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_unlock(apr_global_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_destroy(apr_global_mutex_t *mutex); + +/** + * Get the pool used by this global_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(global_mutex); + +#else /* APR_PROC_MUTEX_IS_GLOBAL */ + +/* Some platforms [e.g. Win32] have cross process locks that are truly + * global locks, since there isn't the concept of cross-process locks. + * Define these platforms in terms of an apr_proc_mutex_t. + */ + +#define apr_global_mutex_t apr_proc_mutex_t +#define apr_global_mutex_create apr_proc_mutex_create +#define apr_global_mutex_child_init apr_proc_mutex_child_init +#define apr_global_mutex_lock apr_proc_mutex_lock +#define apr_global_mutex_trylock apr_proc_mutex_trylock +#define apr_global_mutex_unlock apr_proc_mutex_unlock +#define apr_global_mutex_destroy apr_proc_mutex_destroy +#define apr_global_mutex_pool_get apr_proc_mutex_pool_get + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APR_GLOBAL_MUTEX_H */ diff --git a/include/apr/apr_hash.h b/include/apr/apr_hash.h new file mode 100644 index 0000000..8a6236a --- /dev/null +++ b/include/apr/apr_hash.h @@ -0,0 +1,252 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_HASH_H +#define APR_HASH_H + +/** + * @file apr_hash.h + * @brief APR Hash Tables + */ + +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_hash Hash Tables + * @ingroup APR + * @{ + */ + +/** + * When passing a key to apr_hash_set or apr_hash_get, this value can be + * passed to indicate a string-valued key, and have apr_hash compute the + * length automatically. + * + * @remark apr_hash will use strlen(key) for the length. The NUL terminator + * is not included in the hash value (why throw a constant in?). + * Since the hash table merely references the provided key (rather + * than copying it), apr_hash_this() will return the NUL-term'd key. + */ +#define APR_HASH_KEY_STRING (-1) + +/** + * Abstract type for hash tables. + */ +typedef struct apr_hash_t apr_hash_t; + +/** + * Abstract type for scanning hash tables. + */ +typedef struct apr_hash_index_t apr_hash_index_t; + +/** + * Callback functions for calculating hash values. + * @param key The key. + * @param klen The length of the key, or APR_HASH_KEY_STRING to use the string + * length. If APR_HASH_KEY_STRING then returns the actual key length. + */ +typedef unsigned int (*apr_hashfunc_t)(const char *key, apr_ssize_t *klen); + +/** + * The default hash function. + */ +APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *key, + apr_ssize_t *klen); + +/** + * Create a hash table. + * @param pool The pool to allocate the hash table out of + * @return The hash table just created + */ +APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool); + +/** + * Create a hash table with a custom hash function + * @param pool The pool to allocate the hash table out of + * @param hash_func A custom hash function. + * @return The hash table just created + */ +APR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool, + apr_hashfunc_t hash_func); + +/** + * Make a copy of a hash table + * @param pool The pool from which to allocate the new hash table + * @param h The hash table to clone + * @return The hash table just created + * @remark Makes a shallow copy + */ +APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool, + const apr_hash_t *h); + +/** + * Associate a value with a key in a hash table. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. + * @param val Value to associate with the key + * @remark If the value is NULL the hash entry is deleted. + */ +APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, const void *key, + apr_ssize_t klen, const void *val); + +/** + * Look up the value associated with a key in a hash table. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. + * @return Returns NULL if the key is not present. + */ +APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, const void *key, + apr_ssize_t klen); + +/** + * Start iterating over the entries in a hash table. + * @param p The pool to allocate the apr_hash_index_t iterator. If this + * pool is NULL, then an internal, non-thread-safe iterator is used. + * @param ht The hash table + * @remark There is no restriction on adding or deleting hash entries during + * an iteration (although the results may be unpredictable unless all you do + * is delete the current entry) and multiple iterations can be in + * progress at the same time. + + * @example + */ +/** + *
+ * 
+ * int sum_values(apr_pool_t *p, apr_hash_t *ht)
+ * {
+ *     apr_hash_index_t *hi;
+ *     void *val;
+ *     int sum = 0;
+ *     for (hi = apr_hash_first(p, ht); hi; hi = apr_hash_next(hi)) {
+ *         apr_hash_this(hi, NULL, NULL, &val);
+ *         sum += *(int *)val;
+ *     }
+ *     return sum;
+ * }
+ * 
+ */ +APR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht); + +/** + * Continue iterating over the entries in a hash table. + * @param hi The iteration state + * @return a pointer to the updated iteration state. NULL if there are no more + * entries. + */ +APR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi); + +/** + * Get the current entry's details from the iteration state. + * @param hi The iteration state + * @param key Return pointer for the pointer to the key. + * @param klen Return pointer for the key length. + * @param val Return pointer for the associated value. + * @remark The return pointers should point to a variable that will be set to the + * corresponding data, or they may be NULL if the data isn't interesting. + */ +APR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi, const void **key, + apr_ssize_t *klen, void **val); + +/** + * Get the number of key/value pairs in the hash table. + * @param ht The hash table + * @return The number of key/value pairs in the hash table. + */ +APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht); + +/** + * Merge two hash tables into one new hash table. The values of the overlay + * hash override the values of the base if both have the same key. Both + * hash tables must use the same hash function. + * @param p The pool to use for the new hash table + * @param overlay The table to add to the initial table + * @param base The table that represents the initial values of the new table + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(apr_hash_t *) apr_hash_overlay(apr_pool_t *p, + const apr_hash_t *overlay, + const apr_hash_t *base); + +/** + * Merge two hash tables into one new hash table. If the same key + * is present in both tables, call the supplied merge function to + * produce a merged value for the key in the new table. Both + * hash tables must use the same hash function. + * @param p The pool to use for the new hash table + * @param h1 The first of the tables to merge + * @param h2 The second of the tables to merge + * @param merger A callback function to merge values, or NULL to + * make values from h1 override values from h2 (same semantics as + * apr_hash_overlay()) + * @param data Client data to pass to the merger function + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p, + const apr_hash_t *h1, + const apr_hash_t *h2, + void * (*merger)(apr_pool_t *p, + const void *key, + apr_ssize_t klen, + const void *h1_val, + const void *h2_val, + const void *data), + const void *data); + +/** + * Get the current entry's details from the table state. + * @param p The pool to allocate the apr_hash_index_t iterator. If this + * pool is NULL, then an internal, non-thread-safe iterator is used. + * @param classkey Return pointer for the pointer to the key. + * @param classtable Return pointer for the associated value. + * @remark The return pointers should point to a variable that will be set to the + * corresponding data, or they may be NULL if the data isn't interesting. + */ +APR_DECLARE(void*) apr_class_retrieve(apr_hash_t *classtable, + const char *classkey); + +/** + * Register myclass into a new hash table. The values of the overlay + * hash override the values of the base if both have the same key.. + * @param p The pool to use for the new hash table + * @param classtable The first of the tables to merge + * @param classkey The second of the tables to merge + * @param newclass The table to add to the initial table + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(void) apr_class_register(apr_hash_t **classtable, + const char *classkey, + void *newclass, + apr_pool_t *p); + +/** + * Get a pointer to the pool which the hash table was created in + */ +APR_POOL_DECLARE_ACCESSOR(hash); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_HASH_H */ diff --git a/include/apr/apr_hooks.h b/include/apr/apr_hooks.h new file mode 100644 index 0000000..287fb8c --- /dev/null +++ b/include/apr/apr_hooks.h @@ -0,0 +1,256 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_HOOKS_H +#define APR_HOOKS_H + +#include "apu.h" +/* For apr_array_header_t */ +#include "apr_tables.h" + +/** + * @file apr_hooks.h + * @brief Apache hook functions + */ + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup APR_Util_Hook Hook Functions + * @ingroup APR_Util + * @{ + */ +/** macro to return the prototype of the hook function */ +#define APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \ +link##_DECLARE(apr_array_header_t *) ns##_hook_get_##name(void) + +/** macro to declare the hook correctly */ +#define APR_DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) \ +typedef ret ns##_HOOK_##name##_t args; \ +link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \ + const char * const *aszPre, \ + const char * const *aszSucc, int nOrder); \ +link##_DECLARE(ret) ns##_run_##name args; \ +APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name); \ +typedef struct ns##_LINK_##name##_t \ + { \ + ns##_HOOK_##name##_t *pFunc; \ + const char *szName; \ + const char * const *aszPredecessors; \ + const char * const *aszSuccessors; \ + int nOrder; \ + } ns##_LINK_##name##_t; + +/** macro to declare the hook structure */ +#define APR_HOOK_STRUCT(members) \ +static struct { members } _hooks; + +/** macro to link the hook structure */ +#define APR_HOOK_LINK(name) \ + apr_array_header_t *link_##name; + +/** macro to implement the hook */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf,const char * const *aszPre, \ + const char * const *aszSucc,int nOrder) \ + { \ + ns##_LINK_##name##_t *pHook; \ + if(!_hooks.link_##name) \ + { \ + _hooks.link_##name=apr_array_make(apr_hook_global_pool,1,sizeof(ns##_LINK_##name##_t)); \ + apr_hook_sort_register(#name,&_hooks.link_##name); \ + } \ + pHook=apr_array_push(_hooks.link_##name); \ + pHook->pFunc=pf; \ + pHook->aszPredecessors=aszPre; \ + pHook->aszSuccessors=aszSucc; \ + pHook->nOrder=nOrder; \ + pHook->szName=apr_hook_debug_current; \ + if(apr_hook_debug_enabled) \ + apr_hook_debug_show(#name,aszPre,aszSucc); \ + } \ + APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \ + { \ + return _hooks.link_##name; \ + } + +/** + * Implement a hook that has no return code, and therefore runs all of the + * registered functions + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_VOID(ns,link,name,args_decl,args_use) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(void) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ +\ + if(!_hooks.link_##name) \ + return; \ +\ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + pHook[n].pFunc args_use; \ + } + +/* FIXME: note that this returns ok when nothing is run. I suspect it should + really return decline, but that breaks Apache currently - Ben +*/ +/** + * Implement a hook that runs until one of the functions returns something + * other than OK or DECLINE + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param ret Type to return + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param ok Success value + * @param decline Decline value + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ +\ + if(!_hooks.link_##name) \ + return ok; \ +\ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + rv=pHook[n].pFunc args_use; \ +\ + if(rv != ok && rv != decline) \ + return rv; \ + } \ + return ok; \ + } + + +/** + * Implement a hook that runs until the first function returns something + * other than the value of decline + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param name The name of the hook + * @param ret Type to return + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param decline Decline value + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns,link,ret,name,args_decl,args_use,decline) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ +\ + if(!_hooks.link_##name) \ + return decline; \ +\ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + rv=pHook[n].pFunc args_use; \ +\ + if(rv != decline) \ + return rv; \ + } \ + return decline; \ + } + + /* Hook orderings */ +/** run this hook first, before ANYTHING */ +#define APR_HOOK_REALLY_FIRST (-10) +/** run this hook first */ +#define APR_HOOK_FIRST 0 +/** run this hook somewhere */ +#define APR_HOOK_MIDDLE 10 +/** run this hook after every other hook which is defined*/ +#define APR_HOOK_LAST 20 +/** run this hook last, after EVERYTHING */ +#define APR_HOOK_REALLY_LAST 30 + +/** + * The global pool used to allocate any memory needed by the hooks. + */ +APU_DECLARE_DATA extern apr_pool_t *apr_hook_global_pool; + +/** + * A global variable to determine if debugging information about the + * hooks functions should be printed + */ +APU_DECLARE_DATA extern int apr_hook_debug_enabled; + +/** + * The name of the module that is currently registering a function + */ +APU_DECLARE_DATA extern const char *apr_hook_debug_current; + +/** + * Register a hook function to be sorted + * @param szHookName The name of the Hook the function is registered for + * @param aHooks The array which stores all of the functions for this hook + */ +APU_DECLARE(void) apr_hook_sort_register(const char *szHookName, + apr_array_header_t **aHooks); +/** + * Sort all of the registerd functions for a given hook + */ +APU_DECLARE(void) apr_hook_sort_all(void); + +/** + * Print all of the information about the current hook. This is used for + * debugging purposes. + * @param szName The name of the hook + * @param aszPre All of the functions in the predecessor array + * @param aszSucc All of the functions in the successor array + */ +APU_DECLARE(void) apr_hook_debug_show(const char *szName, + const char * const *aszPre, + const char * const *aszSucc); + +/** + * Remove all currently registered functions. + */ +APU_DECLARE(void) apr_hook_deregister_all(void); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_HOOKS_H */ diff --git a/include/apr/apr_iconv.h b/include/apr/apr_iconv.h new file mode 100644 index 0000000..cc21dfc --- /dev/null +++ b/include/apr/apr_iconv.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1999,2000 + * Konstantin Chuguev. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Konstantin Chuguev + * and its contributors. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef APR_ICONV_H +#define APR_ICONV_H + +#include "apr.h" +#include "apr_pools.h" +#include + +/** + * API_DECLARE_EXPORT is defined when building the libapriconv dynamic + * library, so that all public symbols are exported. + * + * API_DECLARE_STATIC is defined when including the apriconv public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * API_DECLARE_STATIC and API_DECLARE_EXPORT are left undefined when + * including the apr-iconv public headers, to import and link the symbols + * from the dynamic libapriconv library and assure appropriate indirection + * and calling conventions at compile time. + */ + +#if defined(DOXYGEN) || !defined(WIN32) +/** + * The public apr-iconv functions are declared with API_DECLARE(), so they + * use the most portable calling convention. Public apr-iconv functions + * with variable arguments must use API_DECLARE_NONSTD(). + * + * @deffunc API_DECLARE(rettype) apr_func(args); + */ +#define API_DECLARE(type) type +/** + * The private apr-iconv functions are declared with API_DECLARE_NONSTD(), + * so they use the most optimal C language calling conventions. + * + * @deffunc API_DECLARE(rettype) apr_func(args); + */ +#define API_DECLARE_NONSTD(type) type +/** + * All exported apr-iconv variables are declared with API_DECLARE_DATA + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc API_DECLARE_DATA type apr_variable; + * @tip extern API_DECLARE_DATA type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define API_DECLARE_DATA +#elif defined(API_DECLARE_STATIC) +#define API_DECLARE(type) type __stdcall +#define API_DECLARE_NONSTD(type) type __cdecl +#define API_DECLARE_DATA +#elif defined(API_DECLARE_EXPORT) +#define API_DECLARE(type) __declspec(dllexport) type __stdcall +#define API_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define API_DECLARE_DATA __declspec(dllexport) +#else +#define API_DECLARE(type) __declspec(dllimport) type __stdcall +#define API_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define API_DECLARE_DATA __declspec(dllimport) +#endif + +/* + * apr_iconv_t: charset conversion descriptor type + */ +typedef void *apr_iconv_t; + +/* __BEGIN_DECLS */ + +/** + * Create a conversion descriptor. + * @param to name of charset to convert to. + * @param from name of charset of the input bytes. + * @param pool pool to alloc memory. + * @param cd conversion descriptor created in pool. + */ +API_DECLARE(apr_status_t) apr_iconv_open(const char *to, const char *from, + apr_pool_t *pool, apr_iconv_t *cd); +/** + * Perform character set conversion. + * @param cd conversion descriptor created by apr_iconv_open(). + * @param inbuf input buffer. + * @param inbytesleft bytes to convert. + * @param outbuf output buffer. + * @param outbytesleft space (in bytes) available in outbuf. + * @param translated number of input bytes converted. + */ +API_DECLARE(apr_status_t) apr_iconv(apr_iconv_t cd, + const char **inbuf, apr_size_t *inbytesleft, + char **outbuf, apr_size_t *outbytesleft, + apr_size_t *translated); +/** + * Deallocate descriptor for character set conversion. + * @param cd conversion descriptor. + * @param pool pool used in the apr_iconv_open(). + */ +API_DECLARE(apr_status_t) apr_iconv_close(apr_iconv_t cd, apr_pool_t *pool); + +/* __END_DECLS */ + +#endif /* APR_ICONV_H */ diff --git a/include/apr/apr_inherit.h b/include/apr/apr_inherit.h new file mode 100644 index 0000000..4042c90 --- /dev/null +++ b/include/apr/apr_inherit.h @@ -0,0 +1,51 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_INHERIT_H +#define APR_INHERIT_H + +/** + * @file apr_inherit.h + * @brief APR File Handle Inheritance Helpers + * @remark This internal header includes internal declaration helpers + * for other headers to declare apr_foo_inherit_[un]set functions. + */ + +/** + * Prototype for type-specific declarations of apr_foo_inherit_set + * functions. + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurance of apr_foo_inherit_set. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_DECLARE_INHERIT_SET(type) \ + APR_DECLARE(apr_status_t) apr_##type##_inherit_set( \ + apr_##type##_t *the##type) + +/** + * Prototype for type-specific declarations of apr_foo_inherit_unset + * functions. + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurance of apr_foo_inherit_unset. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_DECLARE_INHERIT_UNSET(type) \ + APR_DECLARE(apr_status_t) apr_##type##_inherit_unset( \ + apr_##type##_t *the##type) + +#endif /* ! APR_INHERIT_H */ diff --git a/include/apr/apr_ldap.h b/include/apr/apr_ldap.h new file mode 100644 index 0000000..7a4d67f --- /dev/null +++ b/include/apr/apr_ldap.h @@ -0,0 +1,124 @@ +/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * apr_ldap.h is generated from apr_ldap.h.in by configure -- do not edit apr_ldap.h + */ +/** + * @file apr_ldap.h + * @brief APR-UTIL LDAP + */ +#ifndef APU_LDAP_H +#define APU_LDAP_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +/* this will be defined if LDAP support was compiled into apr-util */ +#define APR_HAS_LDAP 1 + +/* identify the LDAP toolkit used */ +#define APR_HAS_NETSCAPE_LDAPSDK 0 +#define APR_HAS_SOLARIS_LDAPSDK 0 +#define APR_HAS_NOVELL_LDAPSDK 0 +#define APR_HAS_MOZILLA_LDAPSDK 0 +#define APR_HAS_OPENLDAP_LDAPSDK 0 +#define APR_HAS_MICROSOFT_LDAPSDK 1 +#define APR_HAS_OTHER_LDAPSDK 0 + + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/* + * The following #defines are DEPRECATED and should not be used for + * anything. They remain to maintain binary compatibility. + * The original code defined the OPENLDAP SDK as present regardless + * of what really was there, which was way bogus. In addition, the + * apr_ldap_url_parse*() functions have been rewritten specifically for + * APR, so the APR_HAS_LDAP_URL_PARSE macro is forced to zero. + */ +#define APR_HAS_LDAP_SSL 1 +#define APR_HAS_LDAP_URL_PARSE 0 + + +/* + * Include the standard LDAP header files. + */ + +#include + + +/* + * Detected standard functions + */ +#define APR_HAS_LDAPSSL_CLIENT_INIT 0 +#define APR_HAS_LDAPSSL_CLIENT_DEINIT 0 +#define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 0 +#define APR_HAS_LDAP_START_TLS_S 0 +#define APR_HAS_LDAP_SSLINIT 1 +#define APR_HAS_LDAPSSL_INIT 0 +#define APR_HAS_LDAPSSL_INSTALL_ROUTINES 0 + + +/* + * Make sure the secure LDAP port is defined + */ +#ifndef LDAPS_PORT +#define LDAPS_PORT 636 /* ldaps:/// default LDAP over TLS port */ +#endif + + +/* Note: Macros defining const casting has been removed in APR v1.0, + * pending real support for LDAP v2.0 toolkits. + * + * In the mean time, please use an LDAP v3.0 toolkit. + */ +#if LDAP_VERSION_MAX <= 2 +#error Support for LDAP v2.0 toolkits has been removed from apr-util. Please use an LDAP v3.0 toolkit. +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * This structure allows the C LDAP API error codes to be returned + * along with plain text error messages that explain to us mere mortals + * what really happened. + */ +typedef struct apr_ldap_err_t { + const char *reason; + const char *msg; + int rc; +} apr_ldap_err_t; + +#ifdef __cplusplus +} +#endif + +#include "apr_ldap_url.h" +#include "apr_ldap_init.h" +#include "apr_ldap_option.h" + +/** @} */ +#endif /* APR_HAS_LDAP */ +#endif /* APU_LDAP_H */ diff --git a/include/apr/apr_ldap.h.in b/include/apr/apr_ldap.h.in new file mode 100644 index 0000000..44ceb6f --- /dev/null +++ b/include/apr/apr_ldap.h.in @@ -0,0 +1,125 @@ +/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * apr_ldap.h is generated from apr_ldap.h.in by configure -- do not edit apr_ldap.h + */ +/** + * @file apr_ldap.h + * @brief APR-UTIL LDAP + */ +#ifndef APU_LDAP_H +#define APU_LDAP_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +/* this will be defined if LDAP support was compiled into apr-util */ +#define APR_HAS_LDAP @apu_has_ldap@ + +/* identify the LDAP toolkit used */ +#define APR_HAS_NETSCAPE_LDAPSDK @apu_has_ldap_netscape@ +#define APR_HAS_SOLARIS_LDAPSDK @apu_has_ldap_solaris@ +#define APR_HAS_NOVELL_LDAPSDK @apu_has_ldap_novell@ +#define APR_HAS_MOZILLA_LDAPSDK @apu_has_ldap_mozilla@ +#define APR_HAS_OPENLDAP_LDAPSDK @apu_has_ldap_openldap@ +#define APR_HAS_MICROSOFT_LDAPSDK @apu_has_ldap_microsoft@ +#define APR_HAS_OTHER_LDAPSDK @apu_has_ldap_other@ + + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/* + * The following #defines are DEPRECATED and should not be used for + * anything. They remain to maintain binary compatibility. + * The original code defined the OPENLDAP SDK as present regardless + * of what really was there, which was way bogus. In addition, the + * apr_ldap_url_parse*() functions have been rewritten specifically for + * APR, so the APR_HAS_LDAP_URL_PARSE macro is forced to zero. + */ +#define APR_HAS_LDAP_SSL 1 +#define APR_HAS_LDAP_URL_PARSE 0 + + +/* + * Include the standard LDAP header files. + */ + +@lber_h@ +@ldap_h@ +@ldap_ssl_h@ + + +/* + * Detected standard functions + */ +#define APR_HAS_LDAPSSL_CLIENT_INIT @apu_has_ldapssl_client_init@ +#define APR_HAS_LDAPSSL_CLIENT_DEINIT @apu_has_ldapssl_client_deinit@ +#define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT @apu_has_ldapssl_add_trusted_cert@ +#define APR_HAS_LDAP_START_TLS_S @apu_has_ldap_start_tls_s@ +#define APR_HAS_LDAP_SSLINIT @apu_has_ldap_sslinit@ +#define APR_HAS_LDAPSSL_INIT @apu_has_ldapssl_init@ +#define APR_HAS_LDAPSSL_INSTALL_ROUTINES @apu_has_ldapssl_install_routines@ + +/* + * Make sure the secure LDAP port is defined + */ +#ifndef LDAPS_PORT +#define LDAPS_PORT 636 /* ldaps:/// default LDAP over TLS port */ +#endif + + +/* Note: Macros defining const casting has been removed in APR v1.0, + * pending real support for LDAP v2.0 toolkits. + * + * In the mean time, please use an LDAP v3.0 toolkit. + */ +#if LDAP_VERSION_MAX <= 2 +#error Support for LDAP v2.0 toolkits has been removed from apr-util. Please use an LDAP v3.0 toolkit. +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * This structure allows the C LDAP API error codes to be returned + * along with plain text error messages that explain to us mere mortals + * what really happened. + */ +typedef struct apr_ldap_err_t { + const char *reason; + const char *msg; + int rc; +} apr_ldap_err_t; + +#ifdef __cplusplus +} +#endif + +#include "apr_ldap_url.h" +#include "apr_ldap_init.h" +#include "apr_ldap_option.h" + +/** @} */ +#endif /* APR_HAS_LDAP */ +#endif /* APU_LDAP_H */ diff --git a/include/apr/apr_ldap.hnw b/include/apr/apr_ldap.hnw new file mode 100644 index 0000000..947eaac --- /dev/null +++ b/include/apr/apr_ldap.hnw @@ -0,0 +1,133 @@ +/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * apr_ldap.h is generated from apr_ldap.h.in by configure -- do not edit apr_ldap.h + */ +/** + * @file apr_ldap.h + * @brief APR-UTIL LDAP + */ +#ifndef APU_LDAP_H +#define APU_LDAP_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +/* this will be defined if LDAP support was compiled into apr-util */ +#define APR_HAS_LDAP 1 + +/* identify the LDAP toolkit used */ +#define APR_HAS_NETSCAPE_LDAPSDK 0 +#define APR_HAS_SOLARIS_LDAPSDK 0 +#define APR_HAS_NOVELL_LDAPSDK 1 +#define APR_HAS_MOZILLA_LDAPSDK 0 +#define APR_HAS_OPENLDAP_LDAPSDK 0 +#define APR_HAS_MICROSOFT_LDAPSDK 0 +#define APR_HAS_OTHER_LDAPSDK 0 + + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/* + * The following #defines are DEPRECATED and should not be used for + * anything. They remain to maintain binary compatibility. + * The original code defined the OPENLDAP SDK as present regardless + * of what really was there, which was way bogus. In addition, the + * apr_ldap_url_parse*() functions have been rewritten specifically for + * APR, so the APR_HAS_LDAP_URL_PARSE macro is forced to zero. + */ +#define APR_HAS_LDAP_SSL 1 +#define APR_HAS_LDAP_URL_PARSE 0 + + +/* + * Include the standard LDAP header files. + */ + +#ifdef GENEXPORTS +#define LDAP_VERSION_MAX 3 +#else +#include +#include +#if APR_HAS_LDAP_SSL +#include +#endif +#endif + + +/* + * Detected standard functions + */ +#define APR_HAS_LDAPSSL_CLIENT_INIT 1 +#define APR_HAS_LDAPSSL_CLIENT_DEINIT 1 +#define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 1 +#define APR_HAS_LDAP_START_TLS_S 0 +#define APR_HAS_LDAP_SSLINIT 0 +#define APR_HAS_LDAPSSL_INIT 1 +#define APR_HAS_LDAPSSL_INSTALL_ROUTINES 0 + + +/* + * Make sure the secure LDAP port is defined + */ +#ifndef LDAPS_PORT +#define LDAPS_PORT 636 /* ldaps:/// default LDAP over TLS port */ +#endif + + +/* Note: Macros defining const casting has been removed in APR v1.0, + * pending real support for LDAP v2.0 toolkits. + * + * In the mean time, please use an LDAP v3.0 toolkit. + */ +#if LDAP_VERSION_MAX <= 2 +#error Support for LDAP v2.0 toolkits has been removed from apr-util. Please use an LDAP v3.0 toolkit. +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * This structure allows the C LDAP API error codes to be returned + * along with plain text error messages that explain to us mere mortals + * what really happened. + */ +typedef struct apr_ldap_err_t { + const char *reason; + const char *msg; + int rc; +} apr_ldap_err_t; + +#ifdef __cplusplus +} +#endif + +#include "apr_ldap_url.h" +#include "apr_ldap_init.h" +#include "apr_ldap_option.h" + +/** @} */ +#endif /* APR_HAS_LDAP */ +#endif /* APU_LDAP_H */ + diff --git a/include/apr/apr_ldap.hw b/include/apr/apr_ldap.hw new file mode 100644 index 0000000..7a4d67f --- /dev/null +++ b/include/apr/apr_ldap.hw @@ -0,0 +1,124 @@ +/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * apr_ldap.h is generated from apr_ldap.h.in by configure -- do not edit apr_ldap.h + */ +/** + * @file apr_ldap.h + * @brief APR-UTIL LDAP + */ +#ifndef APU_LDAP_H +#define APU_LDAP_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +/* this will be defined if LDAP support was compiled into apr-util */ +#define APR_HAS_LDAP 1 + +/* identify the LDAP toolkit used */ +#define APR_HAS_NETSCAPE_LDAPSDK 0 +#define APR_HAS_SOLARIS_LDAPSDK 0 +#define APR_HAS_NOVELL_LDAPSDK 0 +#define APR_HAS_MOZILLA_LDAPSDK 0 +#define APR_HAS_OPENLDAP_LDAPSDK 0 +#define APR_HAS_MICROSOFT_LDAPSDK 1 +#define APR_HAS_OTHER_LDAPSDK 0 + + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/* + * The following #defines are DEPRECATED and should not be used for + * anything. They remain to maintain binary compatibility. + * The original code defined the OPENLDAP SDK as present regardless + * of what really was there, which was way bogus. In addition, the + * apr_ldap_url_parse*() functions have been rewritten specifically for + * APR, so the APR_HAS_LDAP_URL_PARSE macro is forced to zero. + */ +#define APR_HAS_LDAP_SSL 1 +#define APR_HAS_LDAP_URL_PARSE 0 + + +/* + * Include the standard LDAP header files. + */ + +#include + + +/* + * Detected standard functions + */ +#define APR_HAS_LDAPSSL_CLIENT_INIT 0 +#define APR_HAS_LDAPSSL_CLIENT_DEINIT 0 +#define APR_HAS_LDAPSSL_ADD_TRUSTED_CERT 0 +#define APR_HAS_LDAP_START_TLS_S 0 +#define APR_HAS_LDAP_SSLINIT 1 +#define APR_HAS_LDAPSSL_INIT 0 +#define APR_HAS_LDAPSSL_INSTALL_ROUTINES 0 + + +/* + * Make sure the secure LDAP port is defined + */ +#ifndef LDAPS_PORT +#define LDAPS_PORT 636 /* ldaps:/// default LDAP over TLS port */ +#endif + + +/* Note: Macros defining const casting has been removed in APR v1.0, + * pending real support for LDAP v2.0 toolkits. + * + * In the mean time, please use an LDAP v3.0 toolkit. + */ +#if LDAP_VERSION_MAX <= 2 +#error Support for LDAP v2.0 toolkits has been removed from apr-util. Please use an LDAP v3.0 toolkit. +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * This structure allows the C LDAP API error codes to be returned + * along with plain text error messages that explain to us mere mortals + * what really happened. + */ +typedef struct apr_ldap_err_t { + const char *reason; + const char *msg; + int rc; +} apr_ldap_err_t; + +#ifdef __cplusplus +} +#endif + +#include "apr_ldap_url.h" +#include "apr_ldap_init.h" +#include "apr_ldap_option.h" + +/** @} */ +#endif /* APR_HAS_LDAP */ +#endif /* APU_LDAP_H */ diff --git a/include/apr/apr_ldap_init.h b/include/apr/apr_ldap_init.h new file mode 100644 index 0000000..bd13d07 --- /dev/null +++ b/include/apr/apr_ldap_init.h @@ -0,0 +1,137 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/** + * @file apr_ldap_init.h + * @brief APR-UTIL LDAP ldap_init() functions + */ +#ifndef APR_LDAP_INIT_H +#define APR_LDAP_INIT_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +#include "apr_ldap.h" + +#if APR_HAS_LDAP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * APR LDAP SSL Initialise function + * + * This function initialises SSL on the underlying LDAP toolkit + * if this is necessary. + * + * If a CA certificate is provided, this is set, however the setting + * of certificates via this method has been deprecated and will be removed in + * APR v2.0. + * + * The apr_ldap_set_option() function with the APR_LDAP_OPT_TLS_CERT option + * should be used instead to set certificates. + * + * If SSL support is not available on this platform, or a problem + * was encountered while trying to set the certificate, the function + * will return APR_EGENERAL. Further LDAP specific error information + * can be found in result_err. + * @param pool The pool to use + * @param cert_auth_file The name of the certificate to use, can be NULL + * @param cert_file_type The type of certificate specified. See the + * apr_ldap_set_option() APR_LDAP_OPT_TLS_CERT option for details. + * @param result_err The returned result + */ +APU_DECLARE(int) apr_ldap_ssl_init(apr_pool_t *pool, + const char *cert_auth_file, + int cert_file_type, + apr_ldap_err_t **result_err); + +/** + * APR LDAP SSL De-Initialise function + * + * This function tears down any SSL certificate setup previously + * set using apr_ldap_ssl_init(). It should be called to clean + * up if a graceful restart of a service is attempted. + * @todo currently we do not check whether apr_ldap_ssl_init() + * has been called first - we probably should. + */ +APU_DECLARE(int) apr_ldap_ssl_deinit(void); + +/** + * APR LDAP initialise function + * + * This function is responsible for initialising an LDAP + * connection in a toolkit independant way. It does the + * job of ldap_init() from the C api. + * + * It handles both the SSL and non-SSL case, and attempts + * to hide the complexity setup from the user. This function + * assumes that any certificate setup necessary has already + * been done. + * + * If SSL or STARTTLS needs to be enabled, and the underlying + * toolkit supports it, the following values are accepted for + * secure: + * + * APR_LDAP_NONE: No encryption + * APR_LDAP_SSL: SSL encryption (ldaps://) + * APR_LDAP_STARTTLS: Force STARTTLS on ldap:// + * @remark The Novell toolkit is only able to set the SSL mode via this + * function. To work around this limitation, set the SSL mode here if no + * per connection client certificates are present, otherwise set secure + * APR_LDAP_NONE here, then set the per connection client certificates, + * followed by setting the SSL mode via apr_ldap_set_option(). As Novell + * does not support per connection client certificates, this problem is + * worked around while still being compatible with other LDAP toolkits. + * @param pool The pool to use + * @param ldap The LDAP handle + * @param hostname The name of the host to connect to. This can be either a + * DNS name, or an IP address. + * @param portno The port to connect to + * @param secure The security mode to set + * @param result_err The returned result + */ +APU_DECLARE(int) apr_ldap_init(apr_pool_t *pool, + LDAP **ldap, + const char *hostname, + int portno, + int secure, + apr_ldap_err_t **result_err); + +/** + * APR LDAP info function + * + * This function returns a string describing the LDAP toolkit + * currently in use. The string is placed inside result_err->reason. + * @param pool The pool to use + * @param result_err The returned result + */ +APU_DECLARE(int) apr_ldap_info(apr_pool_t *pool, + apr_ldap_err_t **result_err); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APR_LDAP_URL_H */ diff --git a/include/apr/apr_ldap_option.h b/include/apr/apr_ldap_option.h new file mode 100644 index 0000000..489dc0c --- /dev/null +++ b/include/apr/apr_ldap_option.h @@ -0,0 +1,240 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/** + * @file apr_ldap_option.h + * @brief APR-UTIL LDAP ldap_*_option() functions + */ +#ifndef APR_LDAP_OPTION_H +#define APR_LDAP_OPTION_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +#include "apr_ldap.h" + +#if APR_HAS_LDAP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * The following defines handle the different TLS certificate + * options available. If these options are missing, APR will try and + * emulate support for this using the deprecated ldap_start_tls_s() + * function. + */ +/** + * Set SSL mode to one of APR_LDAP_NONE, APR_LDAP_SSL, APR_LDAP_STARTTLS + * or APR_LDAP_STOPTLS. + */ +#define APR_LDAP_OPT_TLS 0x6fff +/** + * Set zero or more CA certificates, client certificates or private + * keys globally, or per connection (where supported). + */ +#define APR_LDAP_OPT_TLS_CERT 0x6ffe +/** + * Set the LDAP library to no verify the server certificate. This means + * all servers are considered trusted. + */ +#define APR_LDAP_OPT_VERIFY_CERT 0x6ffd + +/** + * Structures for the apr_set_option() cases + */ + +/** + * APR_LDAP_OPT_TLS_CERT + * + * This structure includes possible options to set certificates on + * system initialisation. Different SDKs have different certificate + * requirements, and to achieve this multiple certificates must be + * specified at once passed as an (apr_array_header_t *). + * + * Netscape: + * Needs the CA cert database (cert7.db), the client cert database (key3.db) + * and the security module file (secmod.db) set at the system initialisation + * time. Three types are supported: APR_LDAP_CERT7_DB, APR_LDAP_KEY3_DB and + * APR_LDAP_SECMOD. + * + * To specify a client cert connection, a certificate nickname needs to be + * provided with a type of APR_LDAP_CERT. + * int ldapssl_enable_clientauth( LDAP *ld, char *keynickname, + * char *keypasswd, char *certnickname ); + * keynickname is currently not used, and should be set to "" + * + * Novell: + * Needs CA certificates and client certificates set at system initialisation + * time. Three types are supported: APR_LDAP_CA*, APR_LDAP_CERT* and + * APR_LDAP_KEY*. + * + * Certificates cannot be specified per connection. + * + * The functions used are: + * ldapssl_add_trusted_cert(serverTrustedRoot, serverTrustedRootEncoding); + * Clients certs and keys are set at system initialisation time with + * int ldapssl_set_client_cert ( + * void *cert, + * int type + * void *password); + * type can be LDAPSSL_CERT_FILETYPE_B64 or LDAPSSL_CERT_FILETYPE_DER + * ldapssl_set_client_private_key(clientPrivateKey, + * clientPrivateKeyEncoding, + * clientPrivateKeyPassword); + * + * OpenSSL: + * Needs one or more CA certificates to be set at system initialisation time + * with a type of APR_LDAP_CA*. + * + * May have one or more client certificates set per connection with a type of + * APR_LDAP_CERT*, and keys with APR_LDAP_KEY*. + */ +/** CA certificate type unknown */ +#define APR_LDAP_CA_TYPE_UNKNOWN 0 +/** binary DER encoded CA certificate */ +#define APR_LDAP_CA_TYPE_DER 1 +/** PEM encoded CA certificate */ +#define APR_LDAP_CA_TYPE_BASE64 2 +/** Netscape/Mozilla cert7.db CA certificate database */ +#define APR_LDAP_CA_TYPE_CERT7_DB 3 +/** Netscape/Mozilla secmod file */ +#define APR_LDAP_CA_TYPE_SECMOD 4 +/** Client certificate type unknown */ +#define APR_LDAP_CERT_TYPE_UNKNOWN 5 +/** binary DER encoded client certificate */ +#define APR_LDAP_CERT_TYPE_DER 6 +/** PEM encoded client certificate */ +#define APR_LDAP_CERT_TYPE_BASE64 7 +/** Netscape/Mozilla key3.db client certificate database */ +#define APR_LDAP_CERT_TYPE_KEY3_DB 8 +/** Netscape/Mozilla client certificate nickname */ +#define APR_LDAP_CERT_TYPE_NICKNAME 9 +/** Private key type unknown */ +#define APR_LDAP_KEY_TYPE_UNKNOWN 10 +/** binary DER encoded private key */ +#define APR_LDAP_KEY_TYPE_DER 11 +/** PEM encoded private key */ +#define APR_LDAP_KEY_TYPE_BASE64 12 +/** PKCS#12 encoded client certificate */ +#define APR_LDAP_CERT_TYPE_PFX 13 +/** PKCS#12 encoded private key */ +#define APR_LDAP_KEY_TYPE_PFX 14 + +/** + * Certificate structure. + * + * This structure is used to store certificate details. An array of + * these structures is passed to apr_ldap_set_option() to set CA + * and client certificates. + * @param type Type of certificate APR_LDAP_*_TYPE_* + * @param path Path, file or nickname of the certificate + * @param password Optional password, can be NULL + */ +typedef struct apr_ldap_opt_tls_cert_t apr_ldap_opt_tls_cert_t; +struct apr_ldap_opt_tls_cert_t { + int type; + const char *path; + const char *password; +}; + +/** + * APR_LDAP_OPT_TLS + * + * This sets the SSL level on the LDAP handle. + * + * Netscape/Mozilla: + * Supports SSL, but not STARTTLS + * SSL is enabled by calling ldapssl_install_routines(). + * + * Novell: + * Supports SSL and STARTTLS. + * SSL is enabled by calling ldapssl_install_routines(). Note that calling + * other ldap functions before ldapssl_install_routines() may cause this + * function to fail. + * STARTTLS is enabled by calling ldapssl_start_tls_s() after calling + * ldapssl_install_routines() (check this). + * + * OpenLDAP: + * Supports SSL and supports STARTTLS, but none of this is documented: + * http://www.openldap.org/lists/openldap-software/200409/msg00618.html + * Documentation for both SSL support and STARTTLS has been deleted from + * the OpenLDAP documentation and website. + */ + +/** No encryption */ +#define APR_LDAP_NONE 0 +/** SSL encryption (ldaps://) */ +#define APR_LDAP_SSL 1 +/** TLS encryption (STARTTLS) */ +#define APR_LDAP_STARTTLS 2 +/** end TLS encryption (STOPTLS) */ +#define APR_LDAP_STOPTLS 3 + +/** + * APR LDAP get option function + * + * This function gets option values from a given LDAP session if + * one was specified. It maps to the native ldap_get_option() function. + * @param pool The pool to use + * @param ldap The LDAP handle + * @param option The LDAP_OPT_* option to return + * @param outvalue The value returned (if any) + * @param result_err The apr_ldap_err_t structure contained detailed results + * of the operation. + */ +APU_DECLARE(int) apr_ldap_get_option(apr_pool_t *pool, + LDAP *ldap, + int option, + void *outvalue, + apr_ldap_err_t **result_err); + +/** + * APR LDAP set option function + * + * This function sets option values to a given LDAP session if + * one was specified. It maps to the native ldap_set_option() function. + * + * Where an option is not supported by an LDAP toolkit, this function + * will try and apply legacy functions to achieve the same effect, + * depending on the platform. + * @param pool The pool to use + * @param ldap The LDAP handle + * @param option The LDAP_OPT_* option to set + * @param invalue The value to set + * @param result_err The apr_ldap_err_t structure contained detailed results + * of the operation. + */ +APU_DECLARE(int) apr_ldap_set_option(apr_pool_t *pool, + LDAP *ldap, + int option, + const void *invalue, + apr_ldap_err_t **result_err); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APR_LDAP_OPTION_H */ + diff --git a/include/apr/apr_ldap_rebind.h b/include/apr/apr_ldap_rebind.h new file mode 100644 index 0000000..e1ee804 --- /dev/null +++ b/include/apr/apr_ldap_rebind.h @@ -0,0 +1,87 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/** + * The APR LDAP rebind functions provide an implementation of + * a rebind procedure that can be used to allow clients to chase referrals, + * using the same credentials used to log in originally. + * + * Use of this implementation is optional. + * + * @file apu_ldap_rebind.h + * @brief Apache LDAP library + */ + +#ifndef APU_LDAP_REBIND_H +#define APU_LDAP_REBIND_H + +/* + * Handle the case when LDAP is enabled + */ +#if APR_HAS_LDAP + +/** + * APR LDAP initialize rebind lock + * + * This function creates the lock for controlling access to the xref list.. + * @param pool Pool to use when creating the xref_lock. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_init(apr_pool_t *pool); + + +/** + * APR LDAP rebind_add function + * + * This function creates a cross reference entry for the specified ldap + * connection. The rebind callback function will look up this ldap + * connection so it can retrieve the bindDN and bindPW for use in any + * binds while referrals are being chased. + * + * This function will add the callback to the LDAP handle passed in. + * + * A cleanup is registered within the pool provided to remove this + * entry when the pool is removed. Alternatively apr_ldap_rebind_remove() + * can be called to explicitly remove the entry at will. + * + * @param pool The pool to use + * @param ld The LDAP connectionhandle + * @param bindDN The bind DN to be used for any binds while chasing + * referrals on this ldap connection. + * @param bindPW The bind Password to be used for any binds while + * chasing referrals on this ldap connection. + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_add(apr_pool_t *pool, + LDAP *ld, + const char *bindDN, + const char *bindPW); + +/** + * APR LDAP rebind_remove function + * + * This function removes the rebind cross reference entry for the + * specified ldap connection. + * + * If not explicitly removed, this function will be called automatically + * when the pool is cleaned up. + * + * @param ld The LDAP connectionhandle + */ +APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_remove(LDAP *ld); + +#endif /* APR_HAS_LDAP */ + +#endif /* APU_LDAP_REBIND_H */ + diff --git a/include/apr/apr_ldap_url.h b/include/apr/apr_ldap_url.h new file mode 100644 index 0000000..de59161 --- /dev/null +++ b/include/apr/apr_ldap_url.h @@ -0,0 +1,117 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/** + * @file apr_ldap_url.h + * @brief APR-UTIL LDAP ldap_init() functions + */ +#ifndef APR_LDAP_URL_H +#define APR_LDAP_URL_H + +/** + * @defgroup APR_Util_LDAP LDAP + * @ingroup APR_Util + * @{ + */ + +#if APR_HAS_LDAP + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Structure to access an exploded LDAP URL */ +typedef struct apr_ldap_url_desc_t { + struct apr_ldap_url_desc_t *lud_next; + char *lud_scheme; + char *lud_host; + int lud_port; + char *lud_dn; + char **lud_attrs; + int lud_scope; + char *lud_filter; + char **lud_exts; + int lud_crit_exts; +} apr_ldap_url_desc_t; + +#ifndef APR_LDAP_URL_SUCCESS +#define APR_LDAP_URL_SUCCESS 0x00 /* Success */ +#define APR_LDAP_URL_ERR_MEM 0x01 /* can't allocate memory space */ +#define APR_LDAP_URL_ERR_PARAM 0x02 /* parameter is bad */ +#define APR_LDAP_URL_ERR_BADSCHEME 0x03 /* URL doesn't begin with "ldap[si]://" */ +#define APR_LDAP_URL_ERR_BADENCLOSURE 0x04 /* URL is missing trailing ">" */ +#define APR_LDAP_URL_ERR_BADURL 0x05 /* URL is bad */ +#define APR_LDAP_URL_ERR_BADHOST 0x06 /* host port is bad */ +#define APR_LDAP_URL_ERR_BADATTRS 0x07 /* bad (or missing) attributes */ +#define APR_LDAP_URL_ERR_BADSCOPE 0x08 /* scope string is invalid (or missing) */ +#define APR_LDAP_URL_ERR_BADFILTER 0x09 /* bad or missing filter */ +#define APR_LDAP_URL_ERR_BADEXTS 0x0a /* bad or missing extensions */ +#endif + +/** + * Is this URL an ldap url? ldap:// + * @param url The url to test + */ +APU_DECLARE(int) apr_ldap_is_ldap_url(const char *url); + +/** + * Is this URL an SSL ldap url? ldaps:// + * @param url The url to test + */ +APU_DECLARE(int) apr_ldap_is_ldaps_url(const char *url); + +/** + * Is this URL an ldap socket url? ldapi:// + * @param url The url to test + */ +APU_DECLARE(int) apr_ldap_is_ldapi_url(const char *url); + +/** + * Parse an LDAP URL. + * @param pool The pool to use + * @param url_in The URL to parse + * @param ludpp The structure to return the exploded URL + * @param result_err The result structure of the operation + */ +APU_DECLARE(int) apr_ldap_url_parse_ext(apr_pool_t *pool, + const char *url_in, + apr_ldap_url_desc_t **ludpp, + apr_ldap_err_t **result_err); + +/** + * Parse an LDAP URL. + * @param pool The pool to use + * @param url_in The URL to parse + * @param ludpp The structure to return the exploded URL + * @param result_err The result structure of the operation + */ +APU_DECLARE(int) apr_ldap_url_parse(apr_pool_t *pool, + const char *url_in, + apr_ldap_url_desc_t **ludpp, + apr_ldap_err_t **result_err); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_LDAP */ + +/** @} */ + +#endif /* APR_LDAP_URL_H */ diff --git a/include/apr/apr_lib.h b/include/apr/apr_lib.h new file mode 100644 index 0000000..738df7a --- /dev/null +++ b/include/apr/apr_lib.h @@ -0,0 +1,232 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_LIB_H +#define APR_LIB_H + +/** + * @file apr_lib.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @brief APR general purpose library routines + */ + +#include "apr.h" +#include "apr_errno.h" + +#if APR_HAVE_CTYPE_H +#include +#endif +#if APR_HAVE_STDARG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_lib General Purpose Library Routines + * @ingroup APR + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @{ + */ + +/** A constant representing a 'large' string. */ +#define HUGE_STRING_LEN 8192 + +/* + * Define the structures used by the APR general-purpose library. + */ + +/** @see apr_vformatter_buff_t */ +typedef struct apr_vformatter_buff_t apr_vformatter_buff_t; + +/** + * Structure used by the variable-formatter routines. + */ +struct apr_vformatter_buff_t { + /** The current position */ + char *curpos; + /** The end position of the format string */ + char *endpos; +}; + +/** + * return the final element of the pathname + * @param pathname The path to get the final element of + * @return the final element of the path + * @remark + *
+ * For example:
+ *                 "/foo/bar/gum"    -> "gum"
+ *                 "/foo/bar/gum/"   -> ""
+ *                 "gum"             -> "gum"
+ *                 "bs\\path\\stuff" -> "stuff"
+ * 
+ */ +APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname); + +/** + * apr_killpg + * Small utility macros to make things easier to read. Not usually a + * goal, to be sure.. + */ + +#ifdef WIN32 +#define apr_killpg(x, y) +#else /* WIN32 */ +#ifdef NO_KILLPG +#define apr_killpg(x, y) (kill (-(x), (y))) +#else /* NO_KILLPG */ +#define apr_killpg(x, y) (killpg ((x), (y))) +#endif /* NO_KILLPG */ +#endif /* WIN32 */ + +/** + * apr_vformatter() is a generic printf-style formatting routine + * with some extensions. + * @param flush_func The function to call when the buffer is full + * @param c The buffer to write to + * @param fmt The format string + * @param ap The arguments to use to fill out the format string. + * + * @remark + *
+ * The extensions are:
+ *
+ * %%pA	takes a struct in_addr *, and prints it as a.b.c.d
+ * %%pI	takes an apr_sockaddr_t * and prints it as a.b.c.d:port or
+ *      [ipv6-address]:port
+ * %%pT takes an apr_os_thread_t * and prints it in decimal
+ *      ('0' is printed if !APR_HAS_THREADS)
+ * %%pt takes an apr_os_thread_t * and prints it in hexadecimal
+ *      ('0' is printed if !APR_HAS_THREADS)
+ * %%pp takes a void * and outputs it in hex
+ *
+ * The %%p hacks are to force gcc's printf warning code to skip
+ * over a pointer argument without complaining.  This does
+ * mean that the ANSI-style %%p (output a void * in hex format) won't
+ * work as expected at all, but that seems to be a fair trade-off
+ * for the increased robustness of having printf-warnings work.
+ *
+ * Additionally, apr_vformatter allows for arbitrary output methods
+ * using the apr_vformatter_buff and flush_func.
+ *
+ * The apr_vformatter_buff has two elements curpos and endpos.
+ * curpos is where apr_vformatter will write the next byte of output.
+ * It proceeds writing output to curpos, and updating curpos, until
+ * either the end of output is reached, or curpos == endpos (i.e. the
+ * buffer is full).
+ *
+ * If the end of output is reached, apr_vformatter returns the
+ * number of bytes written.
+ *
+ * When the buffer is full, the flush_func is called.  The flush_func
+ * can return -1 to indicate that no further output should be attempted,
+ * and apr_vformatter will return immediately with -1.  Otherwise
+ * the flush_func should flush the buffer in whatever manner is
+ * appropriate, re apr_pool_t nitialize curpos and endpos, and return 0.
+ *
+ * Note that flush_func is only invoked as a result of attempting to
+ * write another byte at curpos when curpos >= endpos.  So for
+ * example, it's possible when the output exactly matches the buffer
+ * space available that curpos == endpos will be true when
+ * apr_vformatter returns.
+ *
+ * apr_vformatter does not call out to any other code, it is entirely
+ * self-contained.  This allows the callers to do things which are
+ * otherwise "unsafe".  For example, apr_psprintf uses the "scratch"
+ * space at the unallocated end of a block, and doesn't actually
+ * complete the allocation until apr_vformatter returns.  apr_psprintf
+ * would be completely broken if apr_vformatter were to call anything
+ * that used this same pool.  Similarly http_bprintf() uses the "scratch"
+ * space at the end of its output buffer, and doesn't actually note
+ * that the space is in use until it either has to flush the buffer
+ * or until apr_vformatter returns.
+ * 
+ */ +APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *b), + apr_vformatter_buff_t *c, const char *fmt, + va_list ap); + +/** + * Display a prompt and read in the password from stdin. + * @param prompt The prompt to display + * @param pwbuf Buffer to store the password + * @param bufsize The length of the password buffer. + * @remark If the password entered must be truncated to fit in + * the provided buffer, APR_ENAMETOOLONG will be returned. + * Note that the bufsize paramater is passed by reference for no + * reason; its value will never be modified by the apr_password_get() + * function. + */ +APR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, + apr_size_t *bufsize); + +/** @} */ + +/** + * @defgroup apr_ctype ctype functions + * These macros allow correct support of 8-bit characters on systems which + * support 8-bit characters. Pretty dumb how the cast is required, but + * that's legacy libc for ya. These new macros do not support EOF like + * the standard macros do. Tough. + * @{ + */ +/** @see isalnum */ +#define apr_isalnum(c) (isalnum(((unsigned char)(c)))) +/** @see isalpha */ +#define apr_isalpha(c) (isalpha(((unsigned char)(c)))) +/** @see iscntrl */ +#define apr_iscntrl(c) (iscntrl(((unsigned char)(c)))) +/** @see isdigit */ +#define apr_isdigit(c) (isdigit(((unsigned char)(c)))) +/** @see isgraph */ +#define apr_isgraph(c) (isgraph(((unsigned char)(c)))) +/** @see islower*/ +#define apr_islower(c) (islower(((unsigned char)(c)))) +/** @see isascii */ +#ifdef isascii +#define apr_isascii(c) (isascii(((unsigned char)(c)))) +#else +#define apr_isascii(c) (((c) & ~0x7f)==0) +#endif +/** @see isprint */ +#define apr_isprint(c) (isprint(((unsigned char)(c)))) +/** @see ispunct */ +#define apr_ispunct(c) (ispunct(((unsigned char)(c)))) +/** @see isspace */ +#define apr_isspace(c) (isspace(((unsigned char)(c)))) +/** @see isupper */ +#define apr_isupper(c) (isupper(((unsigned char)(c)))) +/** @see isxdigit */ +#define apr_isxdigit(c) (isxdigit(((unsigned char)(c)))) +/** @see tolower */ +#define apr_tolower(c) (tolower(((unsigned char)(c)))) +/** @see toupper */ +#define apr_toupper(c) (toupper(((unsigned char)(c)))) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_LIB_H */ diff --git a/include/apr/apr_md4.h b/include/apr/apr_md4.h new file mode 100644 index 0000000..42d108d --- /dev/null +++ b/include/apr/apr_md4.h @@ -0,0 +1,135 @@ +/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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 is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * 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. MD4 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. MD4 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 APR_MD4_H +#define APR_MD4_H + +#include "apu.h" +#include "apr_xlate.h" +/** + * @file apr_md4.h + * @brief APR-UTIL MD4 Library + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_MD4 MD4 Library + * @ingroup APR_Util + * @{ + */ + +/** The digestsize for MD4 */ +#define APR_MD4_DIGESTSIZE 16 + +/** @see apr_md4_ctx_t */ +typedef struct apr_md4_ctx_t apr_md4_ctx_t; + +/** MD4 context. */ +struct apr_md4_ctx_t { + /** state (ABCD) */ + apr_uint32_t state[4]; + /** number of bits, modulo 2^64 (lsb first) */ + apr_uint32_t count[2]; + /** input buffer */ + unsigned char buffer[64]; +#if APR_HAS_XLATE + /** translation handle */ + apr_xlate_t *xlate; +#endif +}; + +/** + * MD4 Initialize. Begins an MD4 operation, writing a new context. + * @param context The MD4 context to initialize. + */ +APU_DECLARE(apr_status_t) apr_md4_init(apr_md4_ctx_t *context); + +#if APR_HAS_XLATE +/** + * MDr4 translation setup. Provides the APR translation handle to be used + * for translating the content before calculating the digest. + * @param context The MD4 content to set the translation for. + * @param xlate The translation handle to use for this MD4 context + */ +APU_DECLARE(apr_status_t) apr_md4_set_xlate(apr_md4_ctx_t *context, + apr_xlate_t *xlate); +#else +#define apr_md4_set_xlate(context, xlate) APR_ENOTIMPL +#endif + +/** + * MD4 block update operation. Continue an MD4 message-digest operation, + * processing another message block, and updating the context. + * @param context The MD4 content to update. + * @param input next message block to update + * @param inputLen The length of the next message block + */ +APU_DECLARE(apr_status_t) apr_md4_update(apr_md4_ctx_t *context, + const unsigned char *input, + apr_size_t inputLen); + +/** + * MD4 finalization. Ends an MD4 message-digest operation, writing the + * message digest and zeroing the context + * @param digest The final MD4 digest + * @param context The MD4 content we are finalizing. + */ +APU_DECLARE(apr_status_t) apr_md4_final( + unsigned char digest[APR_MD4_DIGESTSIZE], + apr_md4_ctx_t *context); + +/** + * MD4 digest computation + * @param digest The MD4 digest + * @param input message block to use + * @param inputLen The length of the message block + */ +APU_DECLARE(apr_status_t) apr_md4(unsigned char digest[APR_MD4_DIGESTSIZE], + const unsigned char *input, + apr_size_t inputLen); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_MD4_H */ diff --git a/include/apr/apr_md5.h b/include/apr/apr_md5.h new file mode 100644 index 0000000..c6a306e --- /dev/null +++ b/include/apr/apr_md5.h @@ -0,0 +1,162 @@ +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* 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. + */ + +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_MD5_H +#define APR_MD5_H + +#include "apu.h" +#include "apr_xlate.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @file apr_md5.h + * @brief APR MD5 Routines + */ + +/** + * @defgroup APR_MD5 MD5 Routines + * @ingroup APR + * @{ + */ + +/** The MD5 digest size */ +#define APR_MD5_DIGESTSIZE 16 + +/** @see apr_md5_ctx_t */ +typedef struct apr_md5_ctx_t apr_md5_ctx_t; + +/** MD5 context. */ +struct apr_md5_ctx_t { + /** state (ABCD) */ + apr_uint32_t state[4]; + /** number of bits, modulo 2^64 (lsb first) */ + apr_uint32_t count[2]; + /** input buffer */ + unsigned char buffer[64]; + /** translation handle + * ignored if xlate is unsupported + */ + apr_xlate_t *xlate; +}; + +/** + * MD5 Initialize. Begins an MD5 operation, writing a new context. + * @param context The MD5 context to initialize. + */ +APU_DECLARE(apr_status_t) apr_md5_init(apr_md5_ctx_t *context); + +/** + * MD5 translation setup. Provides the APR translation handle to be used + * for translating the content before calculating the digest. + * @param context The MD5 content to set the translation for. + * @param xlate The translation handle to use for this MD5 context + */ +APU_DECLARE(apr_status_t) apr_md5_set_xlate(apr_md5_ctx_t *context, + apr_xlate_t *xlate); + +/** + * MD5 block update operation. Continue an MD5 message-digest operation, + * processing another message block, and updating the context. + * @param context The MD5 content to update. + * @param input next message block to update + * @param inputLen The length of the next message block + */ +APU_DECLARE(apr_status_t) apr_md5_update(apr_md5_ctx_t *context, + const void *input, + apr_size_t inputLen); + +/** + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * message digest and zeroing the context + * @param digest The final MD5 digest + * @param context The MD5 content we are finalizing. + */ +APU_DECLARE(apr_status_t) apr_md5_final(unsigned char digest[APR_MD5_DIGESTSIZE], + apr_md5_ctx_t *context); + +/** + * MD5 in one step + * @param digest The final MD5 digest + * @param input The message block to use + * @param inputLen The length of the message block + */ +APU_DECLARE(apr_status_t) apr_md5(unsigned char digest[APR_MD5_DIGESTSIZE], + const void *input, + apr_size_t inputLen); + +/** + * Encode a password using an MD5 algorithm + * @param password The password to encode + * @param salt The salt to use for the encoding + * @param result The string to store the encoded password in + * @param nbytes The size of the result buffer + */ +APU_DECLARE(apr_status_t) apr_md5_encode(const char *password, const char *salt, + char *result, apr_size_t nbytes); + + +/** + * Validate hashes created by APR-supported algorithms: md5 and sha1. + * hashes created by crypt are supported only on platforms that provide + * crypt(3), so don't rely on that function unless you know that your + * application will be run only on platforms that support it. On platforms + * that don't support crypt(3), this falls back to a clear text string + * comparison. + * @param passwd The password to validate + * @param hash The password to validate against + */ +APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, + const char *hash); + + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_MD5_H */ diff --git a/include/apr/apr_memcache.h b/include/apr/apr_memcache.h new file mode 100644 index 0000000..499d280 --- /dev/null +++ b/include/apr/apr_memcache.h @@ -0,0 +1,446 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef APR_MEMCACHE_H +#define APR_MEMCACHE_H + +/** + * @file apr_memcache.h + * @brief Client interface for memcached + * @remark To use this interface you must have a separate memcached + * server running. See the memcached website at http://www.danga.com/memcached/ + * for more information. + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_time.h" +#include "apr_strings.h" +#include "apr_network_io.h" +#include "apr_ring.h" +#include "apr_buckets.h" +#include "apr_reslist.h" +#include "apr_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_MC Memcached Client Routines + * @ingroup APR_Util + * @{ + */ + +/** Specifies the status of a memcached server */ +typedef enum +{ + APR_MC_SERVER_LIVE, /**< Server is alive and responding to requests */ + APR_MC_SERVER_DEAD /**< Server is not responding to requests */ +} apr_memcache_server_status_t; + +/** Opaque memcache client connection object */ +typedef struct apr_memcache_conn_t apr_memcache_conn_t; + +/** Memcache Server Info Object */ +typedef struct apr_memcache_server_t apr_memcache_server_t; +struct apr_memcache_server_t +{ + const char *host; /**< Hostname of this Server */ + apr_port_t port; /**< Port of this Server */ + apr_memcache_server_status_t status; /**< @see apr_memcache_server_status_t */ +#if APR_HAS_THREADS || defined(DOXYGEN) + apr_reslist_t *conns; /**< Resource list of actual client connections */ +#else + apr_memcache_conn_t *conn; +#endif + apr_pool_t *p; /** Pool to use for private allocations */ +#if APR_HAS_THREADS + apr_thread_mutex_t *lock; +#endif + apr_time_t btime; +}; + +/* Custom hash callback function prototype, user for server selection. +* @param baton user selected baton +* @param data data to hash +* @param data_len length of data +*/ +typedef apr_uint32_t (*apr_memcache_hash_func)(void *baton, + const char *data, + const apr_size_t data_len); + +typedef struct apr_memcache_t apr_memcache_t; + +/* Custom Server Select callback function prototype. +* @param baton user selected baton +* @param mc memcache instance, use mc->live_servers to select a node +* @param hash hash of the selected key. +*/ +typedef apr_memcache_server_t* (*apr_memcache_server_func)(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash); + +/** Container for a set of memcached servers */ +struct apr_memcache_t +{ + apr_uint32_t flags; /**< Flags, Not currently used */ + apr_uint16_t nalloc; /**< Number of Servers Allocated */ + apr_uint16_t ntotal; /**< Number of Servers Added */ + apr_memcache_server_t **live_servers; /**< Array of Servers */ + apr_pool_t *p; /** Pool to use for allocations */ + void *hash_baton; + apr_memcache_hash_func hash_func; + void *server_baton; + apr_memcache_server_func server_func; +}; + +/** Returned Data from a multiple get */ +typedef struct +{ + apr_status_t status; + const char* key; + apr_size_t len; + char *data; + apr_uint16_t flags; +} apr_memcache_value_t; + +/** + * Creates a crc32 hash used to split keys between servers + * @param data Data to be hashed + * @param data_len Length of the data to use + * @return crc32 hash of data + * @remark The crc32 hash is not compatible with old memcached clients. + */ +APU_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc, + const char *data, + const apr_size_t data_len); + +/** + * Pure CRC32 Hash. Used by some clients. + */ +APU_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * hash compatible with the standard Perl Client. + */ +APU_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * Picks a server based on a hash + * @param mc The memcache client object to use + * @param hash Hashed value of a Key + * @return server that controls specified hash + * @see apr_memcache_hash + */ +APU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server_hash(apr_memcache_t *mc, + const apr_uint32_t hash); + +/** + * server selection compatible with the standard Perl Client. + */ +APU_DECLARE(apr_memcache_server_t *) +apr_memcache_find_server_hash_default(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash); + +/** + * Adds a server to a client object + * @param mc The memcache client object to use + * @param ms Server to add + * @remark Adding servers is not thread safe, and should be done once at startup. + * @warning Changing servers after startup may cause keys to go to + * different servers. + */ +APU_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, + apr_memcache_server_t *server); + + +/** + * Finds a Server object based on a hostname/port pair + * @param mc The memcache client object to use + * @param host Hostname of the server + * @param port Port of the server + * @return Server with matching Hostname and Port, or NULL if none was found. + */ +APU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, + const char *host, + apr_port_t port); + +/** + * Enables a Server for use again + * @param mc The memcache client object to use + * @param ms Server to Activate + */ +APU_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, + apr_memcache_server_t *ms); + + +/** + * Disable a Server + * @param mc The memcache client object to use + * @param ms Server to Disable + */ +APU_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, + apr_memcache_server_t *ms); + +/** + * Creates a new Server Object + * @param p Pool to use + * @param host hostname of the server + * @param port port of the server + * @param min minimum number of client sockets to open + * @param smax soft maximum number of client connections to open + * @param max hard maximum number of client connections + * @param ttl time to live in seconds of a client connection + * @param ns location of the new server object + * @see apr_reslist_create + * @remark min, smax, and max are only used when APR_HAS_THREADS + */ +APU_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p, + const char *host, + apr_port_t port, + apr_uint32_t min, + apr_uint32_t smax, + apr_uint32_t max, + apr_uint32_t ttl, + apr_memcache_server_t **ns); +/** + * Creates a new memcached client object + * @param p Pool to use + * @param max_servers maximum number of servers + * @param flags Not currently used + * @param mc location of the new memcache client object + */ +APU_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p, + apr_uint16_t max_servers, + apr_uint32_t flags, + apr_memcache_t **mc); + +/** + * Gets a value from the server, allocating the value out of p + * @param mc client to use + * @param p Pool to use + * @param key null terminated string containing the key + * @param baton location of the allocated value + * @param len length of data at baton + * @param flags any flags set by the client for this key + * @return + */ +APU_DECLARE(apr_status_t) apr_memcache_getp(apr_memcache_t *mc, + apr_pool_t *p, + const char* key, + char **baton, + apr_size_t *len, + apr_uint16_t *flags); + + +/** + * Add a key to a hash for a multiget query + * if the hash (*value) is NULL it will be created + * @param data_pool pool from where the hash and their items are created from + * @param key null terminated string containing the key + * @param values hash of keys and values that this key will be added to + * @return + */ +APU_DECLARE(void) +apr_memcache_add_multget_key(apr_pool_t *data_pool, + const char* key, + apr_hash_t **values); + +/** + * Gets multiple values from the server, allocating the values out of p + * @param mc client to use + * @param temp_pool Pool used for tempoary allocations. May be cleared inside this + * call. + * @param data_pool Pool used to allocate data for the returned values. + * @param values hash of apr_memcache_value_t keyed by strings, contains the + * result of the multiget call. + * @return + */ +APU_DECLARE(apr_status_t) +apr_memcache_multgetp(apr_memcache_t *mc, + apr_pool_t *temp_pool, + apr_pool_t *data_pool, + apr_hash_t *values); + +/** + * Sets a value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param len length of data at baton + * @param timeout time in seconds for the data to live on the server + * @param flags any flags set by the client for this key + */ +APU_DECLARE(apr_status_t) apr_memcache_set(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Adds value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param len length of data at baton + * @param timeout time for the data to live on the server + * @param flags any flags set by the client for this key + * @return APR_SUCCESS if the key was added, APR_EEXIST if the key + * already exists on the server. + */ +APU_DECLARE(apr_status_t) apr_memcache_add(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Replaces value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param len length of data at baton + * @param timeout time for the data to live on the server + * @param flags any flags set by the client for this key + * @return APR_SUCCESS if the key was added, APR_EEXIST if the key + * did not exist on the server. + */ +APU_DECLARE(apr_status_t) apr_memcache_replace(apr_memcache_t *mc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); +/** + * Deletes a key from a server + * @param mc client to use + * @param key null terminated string containing the key + * @param timeout time for the delete to stop other clients from adding + */ +APU_DECLARE(apr_status_t) apr_memcache_delete(apr_memcache_t *mc, + const char *key, + apr_uint32_t timeout); + +/** + * Increments a value + * @param mc client to use + * @param key null terminated string containing the key + * @param n number to increment by + * @param nv new value after incrmenting + */ +APU_DECLARE(apr_status_t) apr_memcache_incr(apr_memcache_t *mc, + const char *key, + apr_int32_t n, + apr_uint32_t *nv); + +/** + * Decrements a value + * @param mc client to use + * @param key null terminated string containing the key + * @param n number to decrement by + * @param nv new value after decrementing + */ +APU_DECLARE(apr_status_t) apr_memcache_decr(apr_memcache_t *mc, + const char *key, + apr_int32_t n, + apr_uint32_t *new_value); + +/** + * Query a server's version + * @param ms server to query + * @param p Pool to allocate answer from + * @param baton location to store server version string + * @param len length of the server version string + */ +APU_DECLARE(apr_status_t) apr_memcache_version(apr_memcache_server_t *ms, + apr_pool_t *p, + char **baton); + +typedef struct +{ + /** Version string of this server */ + const char *version; + /** Process id of this server process */ + apr_uint32_t pid; + /** Number of seconds this server has been running */ + apr_uint32_t uptime; + /** current UNIX time according to the server */ + apr_time_t time; + /** The size of a pointer on the current machine */ + apr_uint32_t pointer_size; + /** Accumulated user time for this process */ + apr_time_t rusage_user; + /** Accumulated system time for this process */ + apr_time_t rusage_system; + /** Current number of items stored by the server */ + apr_uint32_t curr_items; + /** Total number of items stored by this server */ + apr_uint32_t total_items; + /** Current number of bytes used by this server to store items */ + apr_uint64_t bytes; + /** Number of open connections */ + apr_uint32_t curr_connections; + /** Total number of connections opened since the server started running */ + apr_uint32_t total_connections; + /** Number of connection structures allocated by the server */ + apr_uint32_t connection_structures; + /** Cumulative number of retrieval requests */ + apr_uint32_t cmd_get; + /** Cumulative number of storage requests */ + apr_uint32_t cmd_set; + /** Number of keys that have been requested and found present */ + apr_uint32_t get_hits; + /** Number of items that have been requested and not found */ + apr_uint32_t get_misses; + /** Number of items removed from cache because they passed their + expiration time */ + apr_uint64_t evictions; + /** Total number of bytes read by this server */ + apr_uint64_t bytes_read; + /** Total number of bytes sent by this server */ + apr_uint64_t bytes_written; + /** Number of bytes this server is allowed to use for storage. */ + apr_uint32_t limit_maxbytes; + /** Number of threads the server is running (if built with threading) */ + apr_uint32_t threads; +} apr_memcache_stats_t; + +/** + * Query a server for statistics + * @param ms server to query + * @param p Pool to allocate answer from + * @param stats location of the new statistics structure + */ +APU_DECLARE(apr_status_t) apr_memcache_stats(apr_memcache_server_t *ms, + apr_pool_t *p, + apr_memcache_stats_t **stats); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_MEMCACHE_H */ diff --git a/include/apr/apr_mmap.h b/include/apr/apr_mmap.h new file mode 100644 index 0000000..f1b45e3 --- /dev/null +++ b/include/apr/apr_mmap.h @@ -0,0 +1,171 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_MMAP_H +#define APR_MMAP_H + +/** + * @file apr_mmap.h + * @brief APR MMAP routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_ring.h" +#include "apr_file_io.h" /* for apr_file_t */ + +#ifdef BEOS +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_mmap MMAP (Memory Map) Routines + * @ingroup APR + * @{ + */ + +/** MMap opened for reading */ +#define APR_MMAP_READ 1 +/** MMap opened for writing */ +#define APR_MMAP_WRITE 2 + +/** @see apr_mmap_t */ +typedef struct apr_mmap_t apr_mmap_t; + +/** + * @remark + * As far as I can tell the only really sane way to store an MMAP is as a + * void * and a length. BeOS requires this area_id, but that's just a little + * something extra. I am exposing this type, because it doesn't make much + * sense to keep it private, and opening it up makes some stuff easier in + * Apache. + */ +/** The MMAP structure */ +struct apr_mmap_t { + /** The pool the mmap structure was allocated out of. */ + apr_pool_t *cntxt; +#ifdef BEOS + /** An area ID. Only valid on BeOS */ + area_id area; +#endif +#ifdef WIN32 + /** The handle of the file mapping */ + HANDLE mhandle; + /** The start of the real memory page area (mapped view) */ + void *mv; + /** The physical start, size and offset */ + apr_off_t pstart; + apr_size_t psize; + apr_off_t poffset; +#endif + /** The start of the memory mapped area */ + void *mm; + /** The amount of data in the mmap */ + apr_size_t size; + /** ring of apr_mmap_t's that reference the same + * mmap'ed region; acts in place of a reference count */ + APR_RING_ENTRY(apr_mmap_t) link; +}; + +#if APR_HAS_MMAP || defined(DOXYGEN) + +/** @def APR_MMAP_THRESHOLD + * Files have to be at least this big before they're mmap()d. This is to deal + * with systems where the expense of doing an mmap() and an munmap() outweighs + * the benefit for small files. It shouldn't be set lower than 1. + */ +#ifdef MMAP_THRESHOLD +# define APR_MMAP_THRESHOLD MMAP_THRESHOLD +#else +# ifdef SUNOS4 +# define APR_MMAP_THRESHOLD (8*1024) +# else +# define APR_MMAP_THRESHOLD 1 +# endif /* SUNOS4 */ +#endif /* MMAP_THRESHOLD */ + +/** @def APR_MMAP_LIMIT + * Maximum size of MMap region + */ +#ifdef MMAP_LIMIT +# define APR_MMAP_LIMIT MMAP_LIMIT +#else +# define APR_MMAP_LIMIT (4*1024*1024) +#endif /* MMAP_LIMIT */ + +/** Can this file be MMaped */ +#define APR_MMAP_CANDIDATE(filelength) \ + ((filelength >= APR_MMAP_THRESHOLD) && (filelength < APR_MMAP_LIMIT)) + +/* Function definitions */ + +/** + * Create a new mmap'ed file out of an existing APR file. + * @param newmmap The newly created mmap'ed file. + * @param file The file turn into an mmap. + * @param offset The offset into the file to start the data pointer at. + * @param size The size of the file + * @param flag bit-wise or of: + *
+ *          APR_MMAP_READ       MMap opened for reading
+ *          APR_MMAP_WRITE      MMap opened for writing
+ * 
+ * @param cntxt The pool to use when creating the mmap. + */ +APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **newmmap, + apr_file_t *file, apr_off_t offset, + apr_size_t size, apr_int32_t flag, + apr_pool_t *cntxt); + +/** + * Duplicate the specified MMAP. + * @param new_mmap The structure to duplicate into. + * @param old_mmap The mmap to duplicate. + * @param p The pool to use for new_mmap. + */ +APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, + apr_mmap_t *old_mmap, + apr_pool_t *p); + +/** + * Remove a mmap'ed. + * @param mm The mmap'ed file. + */ +APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm); + +/** + * Move the pointer into the mmap'ed file to the specified offset. + * @param addr The pointer to the offset specified. + * @param mm The mmap'ed file. + * @param offset The offset to move to. + */ +APR_DECLARE(apr_status_t) apr_mmap_offset(void **addr, apr_mmap_t *mm, + apr_off_t offset); + +#endif /* APR_HAS_MMAP */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_MMAP_H */ diff --git a/include/apr/apr_network_io.h b/include/apr/apr_network_io.h new file mode 100644 index 0000000..3d5d045 --- /dev/null +++ b/include/apr/apr_network_io.h @@ -0,0 +1,842 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_NETWORK_IO_H +#define APR_NETWORK_IO_H +/** + * @file apr_network_io.h + * @brief APR Network library + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_errno.h" +#include "apr_inherit.h" + +#if APR_HAVE_NETINET_IN_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_network_io Network Routines + * @ingroup APR + * @{ + */ + +#ifndef APR_MAX_SECS_TO_LINGER +/** Maximum seconds to linger */ +#define APR_MAX_SECS_TO_LINGER 30 +#endif + +#ifndef APRMAXHOSTLEN +/** Maximum hostname length */ +#define APRMAXHOSTLEN 256 +#endif + +#ifndef APR_ANYADDR +/** Default 'any' address */ +#define APR_ANYADDR "0.0.0.0" +#endif + +/** + * @defgroup apr_sockopt Socket option definitions + * @{ + */ +#define APR_SO_LINGER 1 /**< Linger */ +#define APR_SO_KEEPALIVE 2 /**< Keepalive */ +#define APR_SO_DEBUG 4 /**< Debug */ +#define APR_SO_NONBLOCK 8 /**< Non-blocking IO */ +#define APR_SO_REUSEADDR 16 /**< Reuse addresses */ +#define APR_SO_BROADCAST 32 /**< Permit sending of broadcast msgs */ +#define APR_SO_SNDBUF 64 /**< Send buffer */ +#define APR_SO_RCVBUF 128 /**< Receive buffer */ +#define APR_SO_DISCONNECTED 256 /**< Disconnected */ +#define APR_TCP_NODELAY 512 /**< For SCTP sockets, this is mapped + * to STCP_NODELAY internally. + */ +#define APR_TCP_NOPUSH 1024 /**< No push */ +#define APR_RESET_NODELAY 2048 /**< This flag is ONLY set internally + * when we set APR_TCP_NOPUSH with + * APR_TCP_NODELAY set to tell us that + * APR_TCP_NODELAY should be turned on + * again when NOPUSH is turned off + */ +#define APR_INCOMPLETE_READ 4096 /**< Set on non-blocking sockets + * (timeout != 0) on which the + * previous read() did not fill a buffer + * completely. the next apr_socket_recv() + * will first call select()/poll() rather than + * going straight into read(). (Can also + * be set by an application to force a + * select()/poll() call before the next + * read, in cases where the app expects + * that an immediate read would fail.) + */ +#define APR_INCOMPLETE_WRITE 8192 /**< like APR_INCOMPLETE_READ, but for write + * @see APR_INCOMPLETE_READ + */ +#define APR_IPV6_V6ONLY 16384 /**< Don't accept IPv4 connections on an + * IPv6 listening socket. + */ +#define APR_TCP_DEFER_ACCEPT 32768 /**< Delay accepting of new connections + * until data is available. + * @see apr_socket_accept_filter + */ + +#define APR_TCP_SERVER_ACCEPT 65536 /**< Delay accepting of new connections + * until server data is available. + * @see apr_socket_accept_filter + */ + +/** @} */ + +/** Define what type of socket shutdown should occur. */ +typedef enum { + APR_SHUTDOWN_READ, /**< no longer allow read request */ + APR_SHUTDOWN_WRITE, /**< no longer allow write requests */ + APR_SHUTDOWN_READWRITE /**< no longer allow read or write requests */ +} apr_shutdown_how_e; + +#define APR_IPV4_ADDR_OK 0x01 /**< @see apr_sockaddr_info_get() */ +#define APR_IPV6_ADDR_OK 0x02 /**< @see apr_sockaddr_info_get() */ + +#if (!APR_HAVE_IN_ADDR) +/** + * We need to make sure we always have an in_addr type, so APR will just + * define it ourselves, if the platform doesn't provide it. + */ +struct in_addr { + apr_uint32_t s_addr; /**< storage to hold the IP# */ +}; +#endif + +/** @def APR_INADDR_NONE + * Not all platforms have a real INADDR_NONE. This macro replaces + * INADDR_NONE on all platforms. + */ +#ifdef INADDR_NONE +#define APR_INADDR_NONE INADDR_NONE +#else +#define APR_INADDR_NONE ((unsigned int) 0xffffffff) +#endif + +/** + * @def APR_UNIX + * Not all platforms have these defined, so we'll define them here + * The default values come from FreeBSD 4.1.1 + */ +#define APR_UNIX AF_UNIX /**< local to host (pipes, portals) */ +/** + * @def APR_INET + * Not all platforms have these defined, so we'll define them here + * The default values come from FreeBSD 4.1.1 + */ +#define APR_INET AF_INET +/** @def APR_UNSPEC + * Let the system decide which address family to use + */ +#ifdef AF_UNSPEC +#define APR_UNSPEC AF_UNSPEC +#else +#define APR_UNSPEC 0 +#endif +#if APR_HAVE_IPV6 +/** @def APR_INET6 +* IPv6 Address Family. Not all platforms may have this defined. +*/ + +#define APR_INET6 AF_INET6 +#endif + +/** + * @defgroup IP_Proto IP Protocol Definitions for use when creating sockets + * @{ + */ +#define APR_PROTO_IP 0 /**< dummy for IP */ +#define APR_PROTO_ICMP 1 /**< control message protocol */ +#define APR_PROTO_IGMP 2 /**< internet group management protocol */ +#define APR_PROTO_TCP 6 /**< TCP */ +#define APR_PROTO_UDP 17 /**< UDP */ +#define APR_PROTO_SCTP 132 /**< SCTP */ +#define APR_PROTO_RAW 255 /**< raw IP packet */ +/** @} */ + +/** + * Enum to tell us if we're interested in remote or local socket + */ +typedef enum { + APR_LOCAL, + APR_REMOTE +} apr_interface_e; + +/** + * The specific declaration of inet_addr's ... some platforms fall back + * inet_network (this is not good, but necessary) + */ + +#if APR_HAVE_INET_ADDR +#define apr_inet_addr inet_addr +#elif APR_HAVE_INET_NETWORK /* only DGUX, as far as I know */ +/** + * @warning + * not generally safe... inet_network() and inet_addr() perform + * different functions */ +#define apr_inet_addr inet_network +#endif + +/** A structure to represent sockets */ +typedef struct apr_socket_t apr_socket_t; +/** + * A structure to encapsulate headers and trailers for apr_socket_sendfile + */ +typedef struct apr_hdtr_t apr_hdtr_t; +/** A structure to represent in_addr */ +typedef struct in_addr apr_in_addr_t; +/** A structure to represent an IP subnet */ +typedef struct apr_ipsubnet_t apr_ipsubnet_t; + +/** @remark use apr_uint16_t just in case some system has a short that isn't 16 bits... */ +typedef apr_uint16_t apr_port_t; + +/** @remark It's defined here as I think it should all be platform safe... + * @see apr_sockaddr_t + */ +typedef struct apr_sockaddr_t apr_sockaddr_t; +/** + * APRs socket address type, used to ensure protocol independence + */ +struct apr_sockaddr_t { + /** The pool to use... */ + apr_pool_t *pool; + /** The hostname */ + char *hostname; + /** Either a string of the port number or the service name for the port */ + char *servname; + /** The numeric port */ + apr_port_t port; + /** The family */ + apr_int32_t family; + /** How big is the sockaddr we're using? */ + apr_socklen_t salen; + /** How big is the ip address structure we're using? */ + int ipaddr_len; + /** How big should the address buffer be? 16 for v4 or 46 for v6 + * used in inet_ntop... */ + int addr_str_len; + /** This points to the IP address structure within the appropriate + * sockaddr structure. */ + void *ipaddr_ptr; + /** If multiple addresses were found by apr_sockaddr_info_get(), this + * points to a representation of the next address. */ + apr_sockaddr_t *next; + /** Union of either IPv4 or IPv6 sockaddr. */ + union { + /** IPv4 sockaddr structure */ + struct sockaddr_in sin; +#if APR_HAVE_IPV6 + /** IPv6 sockaddr structure */ + struct sockaddr_in6 sin6; +#endif +#if APR_HAVE_SA_STORAGE + /** Placeholder to ensure that the size of this union is not + * dependent on whether APR_HAVE_IPV6 is defined. */ + struct sockaddr_storage sas; +#endif + } sa; +}; + +#if APR_HAS_SENDFILE +/** + * Support reusing the socket on platforms which support it (from disconnect, + * specifically Win32. + * @remark Optional flag passed into apr_socket_sendfile() + */ +#define APR_SENDFILE_DISCONNECT_SOCKET 1 +#endif + +/** A structure to encapsulate headers and trailers for apr_socket_sendfile */ +struct apr_hdtr_t { + /** An iovec to store the headers sent before the file. */ + struct iovec* headers; + /** number of headers in the iovec */ + int numheaders; + /** An iovec to store the trailers sent after the file. */ + struct iovec* trailers; + /** number of trailers in the iovec */ + int numtrailers; +}; + +/* function definitions */ + +/** + * Create a socket. + * @param new_sock The new socket that has been set up. + * @param family The address family of the socket (e.g., APR_INET). + * @param type The type of the socket (e.g., SOCK_STREAM). + * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP). + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new_sock, + int family, int type, + int protocol, + apr_pool_t *cont); + +/** + * Shutdown either reading, writing, or both sides of a socket. + * @param thesocket The socket to close + * @param how How to shutdown the socket. One of: + *
+ *            APR_SHUTDOWN_READ         no longer allow read requests
+ *            APR_SHUTDOWN_WRITE        no longer allow write requests
+ *            APR_SHUTDOWN_READWRITE    no longer allow read or write requests 
+ * 
+ * @see apr_shutdown_how_e + * @remark This does not actually close the socket descriptor, it just + * controls which calls are still valid on the socket. + */ +APR_DECLARE(apr_status_t) apr_socket_shutdown(apr_socket_t *thesocket, + apr_shutdown_how_e how); + +/** + * Close a socket. + * @param thesocket The socket to close + */ +APR_DECLARE(apr_status_t) apr_socket_close(apr_socket_t *thesocket); + +/** + * Bind the socket to its associated port + * @param sock The socket to bind + * @param sa The socket address to bind to + * @remark This may be where we will find out if there is any other process + * using the selected port. + */ +APR_DECLARE(apr_status_t) apr_socket_bind(apr_socket_t *sock, + apr_sockaddr_t *sa); + +/** + * Listen to a bound socket for connections. + * @param sock The socket to listen on + * @param backlog The number of outstanding connections allowed in the sockets + * listen queue. If this value is less than zero, the listen + * queue size is set to zero. + */ +APR_DECLARE(apr_status_t) apr_socket_listen(apr_socket_t *sock, + apr_int32_t backlog); + +/** + * Accept a new connection request + * @param new_sock A copy of the socket that is connected to the socket that + * made the connection request. This is the socket which should + * be used for all future communication. + * @param sock The socket we are listening on. + * @param connection_pool The pool for the new socket. + */ +APR_DECLARE(apr_status_t) apr_socket_accept(apr_socket_t **new_sock, + apr_socket_t *sock, + apr_pool_t *connection_pool); + +/** + * Issue a connection request to a socket either on the same machine + * or a different one. + * @param sock The socket we wish to use for our side of the connection + * @param sa The address of the machine we wish to connect to. + */ +APR_DECLARE(apr_status_t) apr_socket_connect(apr_socket_t *sock, + apr_sockaddr_t *sa); + +/** + * Create apr_sockaddr_t from hostname, address family, and port. + * @param sa The new apr_sockaddr_t. + * @param hostname The hostname or numeric address string to resolve/parse, or + * NULL to build an address that corresponds to 0.0.0.0 or :: + * @param family The address family to use, or APR_UNSPEC if the system should + * decide. + * @param port The port number. + * @param flags Special processing flags: + *
+ *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
+ *                                 for IPv6 addresses if the first query failed;
+ *                                 only valid if family is APR_UNSPEC and hostname
+ *                                 isn't NULL; mutually exclusive with
+ *                                 APR_IPV6_ADDR_OK
+ *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
+ *                                 for IPv4 addresses if the first query failed;
+ *                                 only valid if family is APR_UNSPEC and hostname
+ *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
+ *                                 with APR_IPV4_ADDR_OK
+ * 
+ * @param p The pool for the apr_sockaddr_t and associated storage. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, + const char *hostname, + apr_int32_t family, + apr_port_t port, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Look up the host name from an apr_sockaddr_t. + * @param hostname The hostname. + * @param sa The apr_sockaddr_t. + * @param flags Special processing flags. + */ +APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, + apr_sockaddr_t *sa, + apr_int32_t flags); + +/** + * Parse hostname/IP address with scope id and port. + * + * Any of the following strings are accepted: + * 8080 (just the port number) + * www.apache.org (just the hostname) + * www.apache.org:8080 (hostname and port number) + * [fe80::1]:80 (IPv6 numeric address string only) + * [fe80::1%eth0] (IPv6 numeric address string and scope id) + * + * Invalid strings: + * (empty string) + * [abc] (not valid IPv6 numeric address string) + * abc:65536 (invalid port number) + * + * @param addr The new buffer containing just the hostname. On output, *addr + * will be NULL if no hostname/IP address was specfied. + * @param scope_id The new buffer containing just the scope id. On output, + * *scope_id will be NULL if no scope id was specified. + * @param port The port number. On output, *port will be 0 if no port was + * specified. + * ### FIXME: 0 is a legal port (per RFC 1700). this should + * ### return something besides zero if the port is missing. + * @param str The input string to be parsed. + * @param p The pool from which *addr and *scope_id are allocated. + * @remark If scope id shouldn't be allowed, check for scope_id != NULL in + * addition to checking the return code. If addr/hostname should be + * required, check for addr == NULL in addition to checking the + * return code. + */ +APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, + char **scope_id, + apr_port_t *port, + const char *str, + apr_pool_t *p); + +/** + * Get name of the current machine + * @param buf A buffer to store the hostname in. + * @param len The maximum length of the hostname that can be stored in the + * buffer provided. The suggested length is APRMAXHOSTLEN + 1. + * @param cont The pool to use. + * @remark If the buffer was not large enough, an error will be returned. + */ +APR_DECLARE(apr_status_t) apr_gethostname(char *buf, int len, apr_pool_t *cont); + +/** + * Return the data associated with the current socket + * @param data The user data associated with the socket. + * @param key The key to associate with the user data. + * @param sock The currently open socket. + */ +APR_DECLARE(apr_status_t) apr_socket_data_get(void **data, const char *key, + apr_socket_t *sock); + +/** + * Set the data associated with the current socket. + * @param sock The currently open socket. + * @param data The user data to associate with the socket. + * @param key The key to associate with the data. + * @param cleanup The cleanup to call when the socket is destroyed. + */ +APR_DECLARE(apr_status_t) apr_socket_data_set(apr_socket_t *sock, void *data, + const char *key, + apr_status_t (*cleanup)(void*)); + +/** + * Send data over a network. + * @param sock The socket to send the data over. + * @param buf The buffer which contains the data to be sent. + * @param len On entry, the number of bytes to send; on exit, the number + * of bytes sent. + * @remark + *
+ * This functions acts like a blocking write by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ *
+ * It is possible for both bytes to be sent and an error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len); + +/** + * Send multiple packets of data over a network. + * @param sock The socket to send the data over. + * @param vec The array of iovec structs containing the data to send + * @param nvec The number of iovec structs in the array + * @param len Receives the number of bytes actually written + * @remark + *
+ * This functions acts like a blocking write by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ * The number of bytes actually sent is stored in argument 3.
+ *
+ * It is possible for both bytes to be sent and an error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock, + const struct iovec *vec, + apr_int32_t nvec, apr_size_t *len); + +/** + * @param sock The socket to send from + * @param where The apr_sockaddr_t describing where to send the data + * @param flags The flags to use + * @param buf The data to send + * @param len The length of the data to send + */ +APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, + apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len); + +/** + * @param from The apr_sockaddr_t to fill in the recipient info + * @param sock The socket to use + * @param flags The flags to use + * @param buf The buffer to use + * @param len The length of the available buffer + */ + +APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, + apr_socket_t *sock, + apr_int32_t flags, char *buf, + apr_size_t *len); + +#if APR_HAS_SENDFILE || defined(DOXYGEN) + +/** + * Send a file from an open file descriptor to a socket, along with + * optional headers and trailers + * @param sock The socket to which we're writing + * @param file The open file from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * The offset parameter is passed by reference for no reason; its + * value will never be modified by the apr_socket_sendfile() function. + */ +APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock, + apr_file_t *file, + apr_hdtr_t *hdtr, + apr_off_t *offset, + apr_size_t *len, + apr_int32_t flags); + +#endif /* APR_HAS_SENDFILE */ + +/** + * Read data from a network. + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param len On entry, the number of bytes to receive; on exit, the number + * of bytes received. + * @remark + *
+ * This functions acts like a blocking read by default.  To change 
+ * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+ * socket option.
+ * The number of bytes actually received is stored in argument 3.
+ *
+ * It is possible for both bytes to be received and an APR_EOF or
+ * other error to be returned.
+ *
+ * APR_EINTR is never returned.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, + char *buf, apr_size_t *len); + +/** + * Setup socket options for the specified socket + * @param sock The socket to set up. + * @param opt The option we would like to configure. One of: + *
+ *            APR_SO_DEBUG      --  turn on debugging information 
+ *            APR_SO_KEEPALIVE  --  keep connections active
+ *            APR_SO_LINGER     --  lingers on close if data is present
+ *            APR_SO_NONBLOCK   --  Turns blocking on/off for socket
+ *                                  When this option is enabled, use
+ *                                  the APR_STATUS_IS_EAGAIN() macro to
+ *                                  see if a send or receive function
+ *                                  could not transfer data without
+ *                                  blocking.
+ *            APR_SO_REUSEADDR  --  The rules used in validating addresses
+ *                                  supplied to bind should allow reuse
+ *                                  of local addresses.
+ *            APR_SO_SNDBUF     --  Set the SendBufferSize
+ *            APR_SO_RCVBUF     --  Set the ReceiveBufferSize
+ * 
+ * @param on Value for the option. + */ +APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t on); + +/** + * Setup socket timeout for the specified socket + * @param sock The socket to set up. + * @param t Value for the timeout. + *
+ *   t > 0  -- read and write calls return APR_TIMEUP if specified time
+ *             elapsess with no data read or written
+ *   t == 0 -- read and write calls never block
+ *   t < 0  -- read and write calls block
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, + apr_interval_time_t t); + +/** + * Query socket options for the specified socket + * @param sock The socket to query + * @param opt The option we would like to query. One of: + *
+ *            APR_SO_DEBUG      --  turn on debugging information 
+ *            APR_SO_KEEPALIVE  --  keep connections active
+ *            APR_SO_LINGER     --  lingers on close if data is present
+ *            APR_SO_NONBLOCK   --  Turns blocking on/off for socket
+ *            APR_SO_REUSEADDR  --  The rules used in validating addresses
+ *                                  supplied to bind should allow reuse
+ *                                  of local addresses.
+ *            APR_SO_SNDBUF     --  Set the SendBufferSize
+ *            APR_SO_RCVBUF     --  Set the ReceiveBufferSize
+ *            APR_SO_DISCONNECTED -- Query the disconnected state of the socket.
+ *                                  (Currently only used on Windows)
+ * 
+ * @param on Socket option returned on the call. + */ +APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t *on); + +/** + * Query socket timeout for the specified socket + * @param sock The socket to query + * @param t Socket timeout returned from the query. + */ +APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, + apr_interval_time_t *t); + +/** + * Query the specified socket if at the OOB/Urgent data mark + * @param sock The socket to query + * @param atmark Is set to true if socket is at the OOB/urgent mark, + * otherwise is set to false. + */ +APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, + int *atmark); + +/** + * Return an apr_sockaddr_t from an apr_socket_t + * @param sa The returned apr_sockaddr_t. + * @param which Which interface do we want the apr_sockaddr_t for? + * @param sock The socket to use + */ +APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, + apr_interface_e which, + apr_socket_t *sock); + +/** + * Return the IP address (in numeric address string format) in + * an APR socket address. APR will allocate storage for the IP address + * string from the pool of the apr_sockaddr_t. + * @param addr The IP address. + * @param sockaddr The socket address to reference. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, + apr_sockaddr_t *sockaddr); + +/** + * See if the IP addresses in two APR socket addresses are + * equivalent. Appropriate logic is present for comparing + * IPv4-mapped IPv6 addresses with IPv4 addresses. + * + * @param addr1 One of the APR socket addresses. + * @param addr2 The other APR socket address. + * @remark The return value will be non-zero if the addresses + * are equivalent. + */ +APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, + const apr_sockaddr_t *addr2); + +/** +* Return the type of the socket. +* @param sock The socket to query. +* @param type The returned type (e.g., SOCK_STREAM). +*/ +APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock, + int *type); + +/** + * Given an apr_sockaddr_t and a service name, set the port for the service + * @param sockaddr The apr_sockaddr_t that will have its port set + * @param servname The name of the service you wish to use + */ +APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, + const char *servname); +/** + * Build an ip-subnet representation from an IP address and optional netmask or + * number-of-bits. + * @param ipsub The new ip-subnet representation + * @param ipstr The input IP address string + * @param mask_or_numbits The input netmask or number-of-bits string, or NULL + * @param p The pool to allocate from + */ +APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, + const char *ipstr, + const char *mask_or_numbits, + apr_pool_t *p); + +/** + * Test the IP address in an apr_sockaddr_t against a pre-built ip-subnet + * representation. + * @param ipsub The ip-subnet representation + * @param sa The socket address to test + * @return non-zero if the socket address is within the subnet, 0 otherwise + */ +APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa); + +#if APR_HAS_SO_ACCEPTFILTER || defined(DOXYGEN) +/** + * Set an OS level accept filter. + * @param sock The socket to put the accept filter on. + * @param name The accept filter + * @param args Any extra args to the accept filter. Passing NULL here removes + * the accept filter. + */ +apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *name, + char *args); +#endif + +/** + * Return the protocol of the socket. + * @param sock The socket to query. + * @param protocol The returned protocol (e.g., APR_PROTO_TCP). + */ +APR_DECLARE(apr_status_t) apr_socket_protocol_get(apr_socket_t *sock, + int *protocol); + +/** + * Get the pool used by the socket. + */ +APR_POOL_DECLARE_ACCESSOR(socket); + +/** + * Set a socket to be inherited by child processes. + */ +APR_DECLARE_INHERIT_SET(socket); + +/** + * Unset a socket from being inherited by child processes. + */ +APR_DECLARE_INHERIT_UNSET(socket); + +/** + * @defgroup apr_mcast IP Multicast + * @{ + */ + +/** + * Join a Multicast Group + * @param sock The socket to join a multicast group + * @param join The address of the multicast group to join + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) + */ +APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock, + apr_sockaddr_t *join, + apr_sockaddr_t *iface, + apr_sockaddr_t *source); + +/** + * Leave a Multicast Group. All arguments must be the same as + * apr_mcast_join. + * @param sock The socket to leave a multicast group + * @param addr The address of the multicast group to leave + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) + */ +APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock, + apr_sockaddr_t *addr, + apr_sockaddr_t *iface, + apr_sockaddr_t *source); + +/** + * Set the Multicast Time to Live (ttl) for a multicast transmission. + * @param sock The socket to set the multicast ttl + * @param ttl Time to live to Assign. 0-255, default=1 + * @remark If the TTL is 0, packets will only be seen by sockets on + * the local machine, and only when multicast loopback is enabled. + */ +APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock, + apr_byte_t ttl); + +/** + * Toggle IP Multicast Loopback + * @param sock The socket to set multicast loopback + * @param opt 0=disable, 1=enable + */ +APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock, + apr_byte_t opt); + + +/** + * Set the Interface to be used for outgoing Multicast Transmissions. + * @param sock The socket to set the multicast interface on + * @param iface Address of the interface to use for Multicast + */ +APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock, + apr_sockaddr_t *iface); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_NETWORK_IO_H */ + diff --git a/include/apr/apr_optional.h b/include/apr/apr_optional.h new file mode 100644 index 0000000..8c9413f --- /dev/null +++ b/include/apr/apr_optional.h @@ -0,0 +1,92 @@ +/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_OPTIONAL_H +#define APR_OPTIONAL_H + +#include "apu.h" +/** + * @file apr_optional.h + * @brief APR-UTIL registration of functions exported by modules + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Opt Optional Functions + * @ingroup APR_Util + * + * Typesafe registration and retrieval of functions that may not be present + * (i.e. functions exported by optional modules) + * @{ + */ + +/** + * The type of an optional function. + * @param name The name of the function + */ +#define APR_OPTIONAL_FN_TYPE(name) apr_OFN_##name##_t + +/** + * Declare an optional function. + * @param ret The return type of the function + * @param name The name of the function + * @param args The function arguments (including brackets) + */ +#define APR_DECLARE_OPTIONAL_FN(ret,name,args) \ +typedef ret (APR_OPTIONAL_FN_TYPE(name)) args + +/** + * XXX: This doesn't belong here, then! + * Private function! DO NOT USE! + * @internal + */ + +typedef void (apr_opt_fn_t)(void); +/** @internal */ +APU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName, + apr_opt_fn_t *pfn); + +/** + * Register an optional function. This can be later retrieved, type-safely, by + * name. Like all global functions, the name must be unique. Note that, + * confusingly but correctly, the function itself can be static! + * @param name The name of the function + */ +#define APR_REGISTER_OPTIONAL_FN(name) do { \ + APR_OPTIONAL_FN_TYPE(name) *apu__opt = name; \ + apr_dynamic_fn_register(#name,(apr_opt_fn_t *)apu__opt); \ +} while (0) + +/** @internal + * Private function! DO NOT USE! + */ +APU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName); + +/** + * Retrieve an optional function. Returns NULL if the function is not present. + * @param name The name of the function + */ +#define APR_RETRIEVE_OPTIONAL_FN(name) \ + (APR_OPTIONAL_FN_TYPE(name) *)apr_dynamic_fn_retrieve(#name) + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_OPTIONAL_H */ diff --git a/include/apr/apr_optional_hooks.h b/include/apr/apr_optional_hooks.h new file mode 100644 index 0000000..7d01ab0 --- /dev/null +++ b/include/apr/apr_optional_hooks.h @@ -0,0 +1,117 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ +/** + * @file apr_optional_hooks.h + * @brief Apache optional hook functions + */ + + +#ifndef APR_OPTIONAL_HOOK_H +#define APR_OPTIONAL_HOOK_H + +#include "apr_tables.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup APR_Util_OPT_HOOK Optional Hook Functions + * @ingroup APR_Util_Hook + * @{ + */ +/** + * Function to implemnt the APR_OPTIONAL_HOOK Macro + * @internal + * @see APR_OPTIONAL_HOOK + * + * @param name The name of the hook + * @param pfn A pointer to a function that will be called + * @param aszPre a NULL-terminated array of strings that name modules whose hooks should precede this one + * @param aszSucc a NULL-terminated array of strings that name modules whose hooks should succeed this one + * @param nOrder an integer determining order before honouring aszPre and aszSucc (for example HOOK_MIDDLE) + */ + + +APU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void), + const char * const *aszPre, + const char * const *aszSucc, + int nOrder); + +/** + * Hook to an optional hook. + * + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param pfn A pointer to a function that will be called + * @param aszPre a NULL-terminated array of strings that name modules whose hooks should precede this one + * @param aszSucc a NULL-terminated array of strings that name modules whose hooks should succeed this one + * @param nOrder an integer determining order before honouring aszPre and aszSucc (for example HOOK_MIDDLE) + */ + +#define APR_OPTIONAL_HOOK(ns,name,pfn,aszPre,aszSucc,nOrder) do { \ + ns##_HOOK_##name##_t *apu__hook = pfn; \ + apr_optional_hook_add(#name,(void (*)(void))apu__hook,aszPre, aszSucc, nOrder); \ +} while (0) + +/** + * @internal + * @param szName - the name of the function + * @return the hook structure for a given hook + */ +APU_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName); + +/** + * Implement an optional hook that runs until one of the functions + * returns something other than OK or DECLINE. + * + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param ret The type of the return value of the hook + * @param ret The type of the return value of the hook + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param ok Success value + * @param decline Decline value + */ +#define APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ + apr_array_header_t *pHookArray=apr_optional_hook_get(#name); \ +\ + if(!pHookArray) \ + return ok; \ +\ + pHook=(ns##_LINK_##name##_t *)pHookArray->elts; \ + for(n=0 ; n < pHookArray->nelts ; ++n) \ + { \ + rv=(pHook[n].pFunc)args_use; \ +\ + if(rv != ok && rv != decline) \ + return rv; \ + } \ + return ok; \ + } + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_OPTIONAL_HOOK_H */ diff --git a/include/apr/apr_poll.h b/include/apr/apr_poll.h new file mode 100644 index 0000000..d708600 --- /dev/null +++ b/include/apr/apr_poll.h @@ -0,0 +1,196 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_POLL_H +#define APR_POLL_H +/** + * @file apr_poll.h + * @brief APR Poll interface + */ +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_inherit.h" +#include "apr_file_io.h" +#include "apr_network_io.h" + +#if APR_HAVE_NETINET_IN_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_poll Poll Routines + * @ingroup APR + * @{ + */ + +/** + * Poll options + */ +#define APR_POLLIN 0x001 /**< Can read without blocking */ +#define APR_POLLPRI 0x002 /**< Priority data available */ +#define APR_POLLOUT 0x004 /**< Can write without blocking */ +#define APR_POLLERR 0x010 /**< Pending error */ +#define APR_POLLHUP 0x020 /**< Hangup occurred */ +#define APR_POLLNVAL 0x040 /**< Descriptior invalid */ + +/** + * Pollset Flags + */ +#define APR_POLLSET_THREADSAFE 0x001 /**< Adding or Removing a Descriptor is thread safe */ + +/** Used in apr_pollfd_t to determine what the apr_descriptor is */ +typedef enum { + APR_NO_DESC, /**< nothing here */ + APR_POLL_SOCKET, /**< descriptor refers to a socket */ + APR_POLL_FILE, /**< descriptor refers to a file */ + APR_POLL_LASTDESC /**< descriptor is the last one in the list */ +} apr_datatype_e ; + +/** Union of either an APR file or socket. */ +typedef union { + apr_file_t *f; /**< file */ + apr_socket_t *s; /**< socket */ +} apr_descriptor; + +/** @see apr_pollfd_t */ +typedef struct apr_pollfd_t apr_pollfd_t; + +/** Poll descriptor set. */ +struct apr_pollfd_t { + apr_pool_t *p; /**< associated pool */ + apr_datatype_e desc_type; /**< descriptor type */ + apr_int16_t reqevents; /**< requested events */ + apr_int16_t rtnevents; /**< returned events */ + apr_descriptor desc; /**< @see apr_descriptor */ + void *client_data; /**< allows app to associate context */ +}; + + +/* General-purpose poll API for arbitrarily large numbers of + * file descriptors + */ + +/** Opaque structure used for pollset API */ +typedef struct apr_pollset_t apr_pollset_t; + +/** + * Setup a pollset object + * @param pollset The pointer in which to return the newly created object + * @param size The maximum number of descriptors that this pollset can hold + * @param p The pool from which to allocate the pollset + * @param flags Optional flags to modify the operation of the pollset. + * + * @remark If flags equals APR_POLLSET_THREADSAFE, then a pollset is + * created on which it is safe to make concurrent calls to + * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() from + * separate threads. This feature is only supported on some + * platforms; the apr_pollset_create() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + */ +APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags); + +/** + * Destroy a pollset object + * @param pollset The pollset to destroy + */ +APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset); + +/** + * Add a socket or file descriptor to a pollset + * @param pollset The pollset to which to add the descriptor + * @param descriptor The descriptor to add + * @remark If you set client_data in the descriptor, that value + * will be returned in the client_data field whenever this + * descriptor is signalled in apr_pollset_poll(). + * @remark If the pollset has been created with APR_POLLSET_THREADSAFE + * and thread T1 is blocked in a call to apr_pollset_poll() for + * this same pollset that is being modified via apr_pollset_add() + * in thread T2, the currently executing apr_pollset_poll() call in + * T1 will either: (1) automatically include the newly added descriptor + * in the set of descriptors it is watching or (2) return immediately + * with APR_EINTR. Option (1) is recommended, but option (2) is + * allowed for implementations where option (1) is impossible + * or impractical. + */ +APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor); + +/** + * Remove a descriptor from a pollset + * @param pollset The pollset from which to remove the descriptor + * @param descriptor The descriptor to remove + * @remark If the pollset has been created with APR_POLLSET_THREADSAFE + * and thread T1 is blocked in a call to apr_pollset_poll() for + * this same pollset that is being modified via apr_pollset_remove() + * in thread T2, the currently executing apr_pollset_poll() call in + * T1 will either: (1) automatically exclude the newly added descriptor + * in the set of descriptors it is watching or (2) return immediately + * with APR_EINTR. Option (1) is recommended, but option (2) is + * allowed for implementations where option (1) is impossible + * or impractical. + */ +APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor); + +/** + * Block for activity on the descriptor(s) in a pollset + * @param pollset The pollset to use + * @param timeout Timeout in microseconds + * @param num Number of signalled descriptors (output parameter) + * @param descriptors Array of signalled descriptors (output parameter) + */ +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors); + + +/** + * Poll the descriptors in the poll structure + * @param aprset The poll structure we will be using. + * @param numsock The number of descriptors we are polling + * @param nsds The number of descriptors signalled. + * @param timeout The amount of time in microseconds to wait. This is + * a maximum, not a minimum. If a descriptor is signalled, we + * will wake up before this time. A negative number means + * wait until a descriptor is signalled. + * @remark The number of descriptors signalled is returned in the third argument. + * This is a blocking call, and it will not return until either a + * descriptor has been signalled, or the timeout has expired. + * @remark The rtnevents field in the apr_pollfd_t array will only be filled- + * in if the return value is APR_SUCCESS. + */ +APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t numsock, + apr_int32_t *nsds, + apr_interval_time_t timeout); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_POLL_H */ + diff --git a/include/apr/apr_pools.h b/include/apr/apr_pools.h new file mode 100644 index 0000000..52880b6 --- /dev/null +++ b/include/apr/apr_pools.h @@ -0,0 +1,670 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_POOLS_H +#define APR_POOLS_H + +/** + * @file apr_pools.h + * @brief APR memory allocation + * + * Resource allocation routines... + * + * designed so that we don't have to keep track of EVERYTHING so that + * it can be explicitly freed later (a fundamentally unsound strategy --- + * particularly in the presence of die()). + * + * Instead, we maintain pools, and allocate items (both memory and I/O + * handlers) from the pools --- currently there are two, one for per + * transaction info, and one for config info. When a transaction is over, + * we can delete everything in the per-transaction apr_pool_t without fear, + * and without thinking too hard about it either. + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_general.h" /* for APR_STRINGIFY */ +#define APR_WANT_MEMFUNC /**< for no good reason? */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_pools Memory Pool Functions + * @ingroup APR + * @{ + */ + +/** The fundamental pool type */ +typedef struct apr_pool_t apr_pool_t; + + +/** + * Declaration helper macro to construct apr_foo_pool_get()s. + * + * This standardized macro is used by opaque (APR) data types to return + * the apr_pool_t that is associated with the data type. + * + * APR_POOL_DECLARE_ACCESSOR() is used in a header file to declare the + * accessor function. A typical usage and result would be: + *
+ *    APR_POOL_DECLARE_ACCESSOR(file);
+ * becomes:
+ *    APR_DECLARE(apr_pool_t *) apr_file_pool_get(apr_file_t *ob);
+ * 
+ * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurance of apr_foo_pool_get. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_POOL_DECLARE_ACCESSOR(type) \ + APR_DECLARE(apr_pool_t *) apr_##type##_pool_get \ + (const apr_##type##_t *the##type) + +/** + * Implementation helper macro to provide apr_foo_pool_get()s. + * + * In the implementation, the APR_POOL_IMPLEMENT_ACCESSOR() is used to + * actually define the function. It assumes the field is named "pool". + */ +#define APR_POOL_IMPLEMENT_ACCESSOR(type) \ + APR_DECLARE(apr_pool_t *) apr_##type##_pool_get \ + (const apr_##type##_t *the##type) \ + { return the##type->pool; } + + +/** + * Pool debug levels + * + *
+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ * ---------------------------------
+ * |   |   |   |   |   |   |   | x |  General debug code enabled (useful in
+ *                                    combination with --with-efence).
+ *
+ * |   |   |   |   |   |   | x |   |  Verbose output on stderr (report
+ *                                    CREATE, CLEAR, DESTROY).
+ *
+ * |   |   |   | x |   |   |   |   |  Verbose output on stderr (report
+ *                                    PALLOC, PCALLOC).
+ *
+ * |   |   |   |   |   | x |   |   |  Lifetime checking. On each use of a
+ *                                    pool, check its lifetime.  If the pool
+ *                                    is out of scope, abort().
+ *                                    In combination with the verbose flag
+ *                                    above, it will output LIFE in such an
+ *                                    event prior to aborting.
+ *
+ * |   |   |   |   | x |   |   |   |  Pool owner checking.  On each use of a
+ *                                    pool, check if the current thread is the
+ *                                    pools owner.  If not, abort().  In
+ *                                    combination with the verbose flag above,
+ *                                    it will output OWNER in such an event
+ *                                    prior to aborting.  Use the debug
+ *                                    function apr_pool_owner_set() to switch
+ *                                    a pools ownership.
+ *
+ * When no debug level was specified, assume general debug mode.
+ * If level 0 was specified, debugging is switched off
+ * 
+ */ +#if defined(APR_POOL_DEBUG) +/* If APR_POOL_DEBUG is blank, we get 1; if it is a number, we get -1. */ +#if (APR_POOL_DEBUG - APR_POOL_DEBUG -1 == 1) +#undef APR_POOL_DEBUG +#define APR_POOL_DEBUG 1 +#endif +#else +#define APR_POOL_DEBUG 0 +#endif + +/** the place in the code where the particular function was called */ +#define APR_POOL__FILE_LINE__ __FILE__ ":" APR_STRINGIFY(__LINE__) + + + +/** A function that is called when allocation fails. */ +typedef int (*apr_abortfunc_t)(int retcode); + +/* + * APR memory structure manipulators (pools, tables, and arrays). + */ + +/* + * Initialization + */ + +/** + * Setup all of the internal structures required to use pools + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_initialize. + * @internal + */ +APR_DECLARE(apr_status_t) apr_pool_initialize(void); + +/** + * Tear down all of the internal structures required to use pools + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_terminate. + * @internal + */ +APR_DECLARE(void) apr_pool_terminate(void); + + +/* + * Pool creation/destruction + */ + +#include "apr_allocator.h" + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @param abort_fn A function to use if the pool cannot allocate more memory. + * @param allocator The allocator to use with the new pool. If NULL the + * allocator of the parent pool will be used. + */ +APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +/** + * Debug version of apr_pool_create_ex. + * @param newpool @see apr_pool_create. + * @param parent @see apr_pool_create. + * @param abort_fn @see apr_pool_create. + * @param allocator @see apr_pool_create. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_create_ex + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_create_ex in a wrapper, trust the macro + * and don't call apr_pool_create_ex_debug directly. + */ +APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_create_ex(newpool, parent, abort_fn, allocator) \ + apr_pool_create_ex_debug(newpool, parent, abort_fn, allocator, \ + APR_POOL__FILE_LINE__) +#endif + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + */ +#if defined(DOXYGEN) +APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, + apr_pool_t *parent); +#else +#if APR_POOL_DEBUG +#define apr_pool_create(newpool, parent) \ + apr_pool_create_ex_debug(newpool, parent, NULL, NULL, \ + APR_POOL__FILE_LINE__) +#else +#define apr_pool_create(newpool, parent) \ + apr_pool_create_ex(newpool, parent, NULL, NULL) +#endif +#endif + +/** + * Find the pools allocator + * @param pool The pool to get the allocator from. + */ +APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool); + +/** + * Clear all memory in the pool and run all the cleanups. This also destroys all + * subpools. + * @param p The pool to clear + * @remark This does not actually free the memory, it just allows the pool + * to re-use this memory for the next allocation. + * @see apr_pool_destroy() + */ +APR_DECLARE(void) apr_pool_clear(apr_pool_t *p); + +/** + * Debug version of apr_pool_clear. + * @param p See: apr_pool_clear. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_clear + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_clear in a wrapper, trust the macro + * and don't call apr_pool_destroy_clear directly. + */ +APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *p, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_clear(p) \ + apr_pool_clear_debug(p, APR_POOL__FILE_LINE__) +#endif + +/** + * Destroy the pool. This takes similar action as apr_pool_clear() and then + * frees all the memory. + * @param p The pool to destroy + * @remark This will actually free the memory + */ +APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p); + +/** + * Debug version of apr_pool_destroy. + * @param p See: apr_pool_destroy. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have you apr_pool_destroy + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_destroy in a wrapper, trust the macro + * and don't call apr_pool_destroy_debug directly. + */ +APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *p, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pool_destroy(p) \ + apr_pool_destroy_debug(p, APR_POOL__FILE_LINE__) +#endif + + +/* + * Memory allocation + */ + +/** + * Allocate a block of memory from a pool + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The allocated memory + */ +APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size); + +/** + * Debug version of apr_palloc + * @param p See: apr_palloc + * @param size See: apr_palloc + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @return See: apr_palloc + */ +APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *p, apr_size_t size, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_palloc(p, size) \ + apr_palloc_debug(p, size, APR_POOL__FILE_LINE__) +#endif + +/** + * Allocate a block of memory from a pool and set all of the memory to 0 + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The allocated memory + */ +#if defined(DOXYGEN) +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *p, apr_size_t size); +#elif !APR_POOL_DEBUG +#define apr_pcalloc(p, size) memset(apr_palloc(p, size), 0, size) +#endif + +/** + * Debug version of apr_pcalloc + * @param p See: apr_pcalloc + * @param size See: apr_pcalloc + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @return See: apr_pcalloc + */ +APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *p, apr_size_t size, + const char *file_line); + +#if APR_POOL_DEBUG +#define apr_pcalloc(p, size) \ + apr_pcalloc_debug(p, size, APR_POOL__FILE_LINE__) +#endif + + +/* + * Pool Properties + */ + +/** + * Set the function to be called when an allocation failure occurs. + * @remark If the program wants APR to exit on a memory allocation error, + * then this function can be called to set the callback to use (for + * performing cleanup and then exiting). If this function is not called, + * then APR will return an error and expect the calling program to + * deal with the error accordingly. + */ +APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abortfunc, + apr_pool_t *pool); + +/** + * Get the abort function associated with the specified pool. + * @param pool The pool for retrieving the abort function. + * @return The abort function for the given pool. + */ +APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool); + +/** + * Get the parent pool of the specified pool. + * @param pool The pool for retrieving the parent pool. + * @return The parent of the given pool. + */ +APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool); + +/** + * Determine if pool a is an ancestor of pool b. + * @param a The pool to search + * @param b The pool to search for + * @return True if a is an ancestor of b, NULL is considered an ancestor + * of all pools. + * @remark if compiled with APR_POOL_DEBUG, this function will also + * return true if A is a pool which has been guaranteed by the caller + * (using apr_pool_join) to have a lifetime at least as long as some + * ancestor of pool B. + */ +APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b); + +/** + * Tag a pool (give it a name) + * @param pool The pool to tag + * @param tag The tag + */ +APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag); + + +/* + * User data management + */ + +/** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param cleanup The cleanup program to use to cleanup the data (NULL if none) + * @param pool The current pool + * @warning The data to be attached to the pool should have a life span + * at least as long as the pool it is being attached to. + * + * Users of APR must take EXTREME care when choosing a key to + * use for their data. It is possible to accidentally overwrite + * data by choosing a key that another part of the program is using. + * Therefore it is advised that steps are taken to ensure that unique + * keys are used for all of the userdata objects in a particular pool + * (the same key in two different pools or a pool and one of its + * subpools is okay) at all times. Careful namespace prefixing of + * key names is a typical way to help ensure this uniqueness. + * + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_set( + const void *data, + const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool); + +/** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param cleanup The cleanup program to use to cleanup the data (NULL if none) + * @param pool The current pool + * @note same as apr_pool_userdata_set(), except that this version doesn't + * make a copy of the key (this function is useful, for example, when + * the key is a string literal) + * @warning This should NOT be used if the key could change addresses by + * any means between the apr_pool_userdata_setn() call and a + * subsequent apr_pool_userdata_get() on that key, such as if a + * static string is used as a userdata key in a DSO and the DSO could + * be unloaded and reloaded between the _setn() and the _get(). You + * MUST use apr_pool_userdata_set() in such cases. + * @warning More generally, the key and the data to be attached to the + * pool should have a life span at least as long as the pool itself. + * + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_setn( + const void *data, + const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool); + +/** + * Return the data associated with the current pool. + * @param data The user data associated with the pool. + * @param key The key for the data to retrieve + * @param pool The current pool. + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, + apr_pool_t *pool); + + +/** + * @defgroup PoolCleanup Pool Cleanup Functions + * + * Cleanups are performed in the reverse order they were registered. That is: + * Last In, First Out. A cleanup function can safely allocate memory from + * the pool that is being cleaned up. It can also safely register additional + * cleanups which will be run LIFO, directly after the current cleanup + * terminates. Cleanups have to take caution in calling functions that + * create subpools. Subpools, created during cleanup will NOT automatically + * be cleaned up. In other words, cleanups are to clean up after themselves. + * + * @{ + */ + +/** + * Register a function to be called when a pool is cleared or destroyed + * @param p The pool register the cleanup with + * @param data The data to pass to the cleanup function. + * @param plain_cleanup The function to call when the pool is cleared + * or destroyed + * @param child_cleanup The function to call when a child process is about + * to exec - this function is called in the child, obviously! + */ +APR_DECLARE(void) apr_pool_cleanup_register( + apr_pool_t *p, + const void *data, + apr_status_t (*plain_cleanup)(void *), + apr_status_t (*child_cleanup)(void *)); + +/** + * Remove a previously registered cleanup function. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a cleanup will be removed. + * + * @param p The pool to remove the cleanup from + * @param data The data of the registered cleanup + * @param cleanup The function to remove from cleanup + * @remarks For some strange reason only the plain_cleanup is handled by this + * function + */ +APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data, + apr_status_t (*cleanup)(void *)); + +/** + * Replace the child cleanup function of a previously registered cleanup. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a plain_cleanup will have the registered child cleanup + * function replaced with @a child_cleanup. + * + * @param p The pool of the registered cleanup + * @param data The data of the registered cleanup + * @param plain_cleanup The plain cleanup function of the registered cleanup + * @param child_cleanup The function to register as the child cleanup + */ +APR_DECLARE(void) apr_pool_child_cleanup_set( + apr_pool_t *p, + const void *data, + apr_status_t (*plain_cleanup)(void *), + apr_status_t (*child_cleanup)(void *)); + +/** + * Run the specified cleanup function immediately and unregister it. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a cleanup will be removed and @a cleanup will be called + * with @a data as the argument. + * + * @param p The pool to remove the cleanup from + * @param data The data to remove from cleanup + * @param cleanup The function to remove from cleanup + */ +APR_DECLARE(apr_status_t) apr_pool_cleanup_run( + apr_pool_t *p, + void *data, + apr_status_t (*cleanup)(void *)); + +/** + * An empty cleanup function. + * + * Passed to apr_pool_cleanup_register() when no cleanup is required. + * + * @param data The data to cleanup, will not be used by this function. + */ +APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data); + +/** + * Run all registered child cleanups, in preparation for an exec() + * call in a forked child -- close files, etc., but *don't* flush I/O + * buffers, *don't* wait for subprocesses, and *don't* free any + * memory. + */ +APR_DECLARE(void) apr_pool_cleanup_for_exec(void); + +/** @} */ + +/** + * @defgroup PoolDebug Pool Debugging functions. + * + * pools have nested lifetimes -- sub_pools are destroyed when the + * parent pool is cleared. We allow certain liberties with operations + * on things such as tables (and on other structures in a more general + * sense) where we allow the caller to insert values into a table which + * were not allocated from the table's pool. The table's data will + * remain valid as long as all the pools from which its values are + * allocated remain valid. + * + * For example, if B is a sub pool of A, and you build a table T in + * pool B, then it's safe to insert data allocated in A or B into T + * (because B lives at most as long as A does, and T is destroyed when + * B is cleared/destroyed). On the other hand, if S is a table in + * pool A, it is safe to insert data allocated in A into S, but it + * is *not safe* to insert data allocated from B into S... because + * B can be cleared/destroyed before A is (which would leave dangling + * pointers in T's data structures). + * + * In general we say that it is safe to insert data into a table T + * if the data is allocated in any ancestor of T's pool. This is the + * basis on which the APR_POOL_DEBUG code works -- it tests these ancestor + * relationships for all data inserted into tables. APR_POOL_DEBUG also + * provides tools (apr_pool_find, and apr_pool_is_ancestor) for other + * folks to implement similar restrictions for their own data + * structures. + * + * However, sometimes this ancestor requirement is inconvenient -- + * sometimes it's necessary to create a sub pool where the sub pool is + * guaranteed to have the same lifetime as the parent pool. This is a + * guarantee implemented by the *caller*, not by the pool code. That + * is, the caller guarantees they won't destroy the sub pool + * individually prior to destroying the parent pool. + * + * In this case the caller must call apr_pool_join() to indicate this + * guarantee to the APR_POOL_DEBUG code. + * + * These functions are only implemented when #APR_POOL_DEBUG is set. + * + * @{ + */ +#if APR_POOL_DEBUG || defined(DOXYGEN) +/** + * Guarantee that a subpool has the same lifetime as the parent. + * @param p The parent pool + * @param sub The subpool + */ +APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub); + +/** + * Find a pool from something allocated in it. + * @param mem The thing allocated in the pool + * @return The pool it is allocated in + */ +APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem); + +/** + * Report the number of bytes currently in the pool + * @param p The pool to inspect + * @param recurse Recurse/include the subpools' sizes + * @return The number of bytes + */ +APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *p, int recurse); + +/** + * Lock a pool + * @param pool The pool to lock + * @param flag The flag + */ +APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag); + +/* @} */ + +#else /* APR_POOL_DEBUG or DOXYGEN */ + +#ifdef apr_pool_join +#undef apr_pool_join +#endif +#define apr_pool_join(a,b) + +#ifdef apr_pool_lock +#undef apr_pool_lock +#endif +#define apr_pool_lock(pool, lock) + +#endif /* APR_POOL_DEBUG or DOXYGEN */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_POOLS_H */ diff --git a/include/apr/apr_portable.h b/include/apr/apr_portable.h new file mode 100644 index 0000000..b37263b --- /dev/null +++ b/include/apr/apr_portable.h @@ -0,0 +1,506 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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 header file is where you should put ANY platform specific information. + * This should be the only header file that programs need to include that + * actually has platform dependant code which refers to the . + */ +#ifndef APR_PORTABLE_H +#define APR_PORTABLE_H +/** + * @file apr_portable.h + * @brief APR Portability Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_network_io.h" +#include "apr_errno.h" +#include "apr_global_mutex.h" +#include "apr_proc_mutex.h" +#include "apr_time.h" +#include "apr_dso.h" +#include "apr_shm.h" + +#if APR_HAVE_DIRENT_H +#include +#endif +#if APR_HAVE_FCNTL_H +#include +#endif +#if APR_HAVE_PTHREAD_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_portabile Portability Routines + * @ingroup APR + * @{ + */ + +#ifdef WIN32 +/* The primitives for Windows types */ +typedef HANDLE apr_os_file_t; +typedef HANDLE apr_os_dir_t; +typedef SOCKET apr_os_sock_t; +typedef HANDLE apr_os_proc_mutex_t; +typedef HANDLE apr_os_thread_t; +typedef HANDLE apr_os_proc_t; +typedef DWORD apr_os_threadkey_t; +typedef FILETIME apr_os_imp_time_t; +typedef SYSTEMTIME apr_os_exp_time_t; +typedef HANDLE apr_os_dso_handle_t; +typedef HANDLE apr_os_shm_t; + +#elif defined(OS2) +typedef HFILE apr_os_file_t; +typedef HDIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef HMTX apr_os_proc_mutex_t; +typedef TID apr_os_thread_t; +typedef PID apr_os_proc_t; +typedef PULONG apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef HMODULE apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#elif defined(__BEOS__) +#include +#include + +struct apr_os_proc_mutex_t { + sem_id sem; + int32 ben; +}; + +typedef int apr_os_file_t; +typedef DIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef struct apr_os_proc_mutex_t apr_os_proc_mutex_t; +typedef thread_id apr_os_thread_t; +typedef thread_id apr_os_proc_t; +typedef int apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef image_id apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#elif defined(NETWARE) +typedef int apr_os_file_t; +typedef DIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef NXMutex_t apr_os_proc_mutex_t; +typedef NXThreadId_t apr_os_thread_t; +typedef long apr_os_proc_t; +typedef NXKey_t apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef void * apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#else +/* Any other OS should go above this one. This is the lowest common + * denominator typedefs for all UNIX-like systems. :) + */ + +/** Basic OS process mutex structure. */ +struct apr_os_proc_mutex_t { +#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + /** Value used for SYS V Semaphore, FCNTL and FLOCK serialization */ + int crossproc; +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + /** Value used for PTHREAD serialization */ + pthread_mutex_t *pthread_interproc; +#endif +#if APR_HAS_THREADS + /* If no threads, no need for thread locks */ +#if APR_USE_PTHREAD_SERIALIZE + /** This value is currently unused within APR and Apache */ + pthread_mutex_t *intraproc; +#endif +#endif +}; + +typedef int apr_os_file_t; /**< native file */ +typedef DIR apr_os_dir_t; /**< native dir */ +typedef int apr_os_sock_t; /**< native dir */ +typedef struct apr_os_proc_mutex_t apr_os_proc_mutex_t; /**< native proces + * mutex + */ +#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H +typedef pthread_t apr_os_thread_t; /**< native thread */ +typedef pthread_key_t apr_os_threadkey_t; /**< native thread address + * space */ +#endif +typedef pid_t apr_os_proc_t; /**< native pid */ +typedef struct timeval apr_os_imp_time_t; /**< native timeval */ +typedef struct tm apr_os_exp_time_t; /**< native tm */ +/** @var apr_os_dso_handle_t + * native dso types + */ +#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) +#include +typedef shl_t apr_os_dso_handle_t; +#elif defined(DARWIN) +#include +typedef NSModule apr_os_dso_handle_t; +#else +typedef void * apr_os_dso_handle_t; +#endif +typedef void* apr_os_shm_t; /**< native SHM */ + +#endif + +/** + * @typedef apr_os_sock_info_t + * @brief alias for local OS socket + */ +/** + * everything APR needs to know about an active socket to construct + * an APR socket from it; currently, this is platform-independent + */ +struct apr_os_sock_info_t { + apr_os_sock_t *os_sock; /**< always required */ + struct sockaddr *local; /**< NULL if not yet bound */ + struct sockaddr *remote; /**< NULL if not connected */ + int family; /**< always required (APR_INET, APR_INET6, etc.) */ + int type; /**< always required (SOCK_STREAM, SOCK_DGRAM, etc.) */ + int protocol; /**< 0 or actual protocol (APR_PROTO_SCTP, APR_PROTO_TCP, etc.) */ +}; + +typedef struct apr_os_sock_info_t apr_os_sock_info_t; + +#if APR_PROC_MUTEX_IS_GLOBAL || defined(DOXYGEN) +/** Opaque global mutex type */ +#define apr_os_global_mutex_t apr_os_proc_mutex_t +/** @return apr_os_global_mutex */ +#define apr_os_global_mutex_get apr_os_proc_mutex_get +#else + /** Thread and process mutex for those platforms where process mutexes + * are not held in threads. + */ + struct apr_os_global_mutex_t { + apr_pool_t *pool; + apr_proc_mutex_t *proc_mutex; +#if APR_HAS_THREADS + apr_thread_mutex_t *thread_mutex; +#endif /* APR_HAS_THREADS */ + }; + typedef struct apr_os_global_mutex_t apr_os_global_mutex_t; + +APR_DECLARE(apr_status_t) apr_os_global_mutex_get(apr_os_global_mutex_t *ospmutex, + apr_global_mutex_t *pmutex); +#endif + + +/** + * convert the file from apr type to os specific type. + * @param thefile The os specific file we are converting to + * @param file The apr file to convert. + * @remark On Unix, it is only possible to get a file descriptor from + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, + apr_file_t *file); + +/** + * convert the dir from apr type to os specific type. + * @param thedir The os specific dir we are converting to + * @param dir The apr dir to convert. + */ +APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir, + apr_dir_t *dir); + +/** + * Convert the socket from an apr type to an OS specific socket + * @param thesock The socket to convert. + * @param sock The os specifc equivelant of the apr socket.. + */ +APR_DECLARE(apr_status_t) apr_os_sock_get(apr_os_sock_t *thesock, + apr_socket_t *sock); + +/** + * Convert the proc mutex from os specific type to apr type + * @param ospmutex The os specific proc mutex we are converting to. + * @param pmutex The apr proc mutex to convert. + */ +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex); + +/** + * Get the exploded time in the platforms native format. + * @param ostime the native time format + * @param aprtime the time to convert + */ +APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, + apr_time_exp_t *aprtime); + +/** + * Get the imploded time in the platforms native format. + * @param ostime the native time format + * @param aprtime the time to convert + */ +APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, + apr_time_t *aprtime); + +/** + * convert the shm from apr type to os specific type. + * @param osshm The os specific shm representation + * @param shm The apr shm to convert. + */ +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm); + +#if APR_HAS_THREADS || defined(DOXYGEN) +/** + * @defgroup apr_os_thread Thread portability Routines + * @{ + */ +/** + * convert the thread to os specific type from apr type. + * @param thethd The apr thread to convert + * @param thd The os specific thread we are converting to + */ +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, + apr_thread_t *thd); + +/** + * convert the thread private memory key to os specific type from an apr type. + * @param thekey The apr handle we are converting from. + * @param key The os specific handle we are converting to. + */ +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, + apr_threadkey_t *key); + +/** + * convert the thread from os specific type to apr type. + * @param thd The apr thread we are converting to. + * @param thethd The os specific thread to convert + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, + apr_os_thread_t *thethd, + apr_pool_t *cont); + +/** + * convert the thread private memory key from os specific type to apr type. + * @param key The apr handle we are converting to. + * @param thekey The os specific handle to convert + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, + apr_pool_t *cont); +/** + * Get the thread ID + */ +APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void); + +/** + * Compare two thread id's + * @param tid1 1st Thread ID to compare + * @param tid2 2nd Thread ID to compare + */ +APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, + apr_os_thread_t tid2); + +/** @} */ +#endif /* APR_HAS_THREADS */ + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific file to convert + * @param flags The flags that were used to open this file. + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_int32_t flags, apr_pool_t *cont); + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific pipe to convert + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *cont); + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific pipe to convert + * @param register_cleanup A cleanup will be registered on the apr_file_t + * to issue apr_file_close(). + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *cont); + +/** + * convert the dir from os specific type to apr type. + * @param dir The apr dir we are converting to. + * @param thedir The os specific dir to convert + * @param cont The pool to use when creating to apr directory. + */ +APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir, + apr_os_dir_t *thedir, + apr_pool_t *cont); + +/** + * Convert a socket from the os specific type to the apr type + * @param sock The pool to use. + * @param thesock The socket to convert to. + * @param cont The socket we are converting to an apr type. + * @remark If it is a true socket, it is best to call apr_os_sock_make() + * and provide APR with more information about the socket. + */ +APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, + apr_os_sock_t *thesock, + apr_pool_t *cont); + +/** + * Create a socket from an existing descriptor and local and remote + * socket addresses. + * @param apr_sock The new socket that has been set up + * @param os_sock_info The os representation of the socket handle and + * other characteristics of the socket + * @param cont The pool to use + * @remark If you only know the descriptor/handle or if it isn't really + * a true socket, use apr_os_sock_put() instead. + */ +APR_DECLARE(apr_status_t) apr_os_sock_make(apr_socket_t **apr_sock, + apr_os_sock_info_t *os_sock_info, + apr_pool_t *cont); + +/** + * Convert the proc mutex from os specific type to apr type + * @param pmutex The apr proc mutex we are converting to. + * @param ospmutex The os specific proc mutex to convert. + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *cont); + +/** + * Put the imploded time in the APR format. + * @param aprtime the APR time format + * @param ostime the time to convert + * @param cont the pool to use if necessary + */ +APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, + apr_os_imp_time_t **ostime, + apr_pool_t *cont); + +/** + * Put the exploded time in the APR format. + * @param aprtime the APR time format + * @param ostime the time to convert + * @param cont the pool to use if necessary + */ +APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, + apr_os_exp_time_t **ostime, + apr_pool_t *cont); + +/** + * convert the shared memory from os specific type to apr type. + * @param shm The apr shm representation of osshm + * @param osshm The os specific shm identity + * @param cont The pool to use if it is needed. + * @remark On fork()ed architectures, this is typically nothing more than + * the memory block mapped. On non-fork architectures, this is typically + * some internal handle to pass the mapping from process to process. + */ +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **shm, + apr_os_shm_t *osshm, + apr_pool_t *cont); + + +#if APR_HAS_DSO || defined(DOXYGEN) +/** + * @defgroup apr_os_dso DSO (Dynamic Loading) Portabiliity Routines + * @{ + */ +/** + * convert the dso handle from os specific to apr + * @param dso The apr handle we are converting to + * @param thedso the os specific handle to convert + * @param pool the pool to use if it is needed + */ +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **dso, + apr_os_dso_handle_t thedso, + apr_pool_t *pool); + +/** + * convert the apr dso handle into an os specific one + * @param aprdso The apr dso handle to convert + * @param dso The os specific dso to return + */ +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *dso, + apr_dso_handle_t *aprdso); + +#if APR_HAS_OS_UUID +/** + * Private: apr-util's apr_uuid module when supported by the platform + */ +APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data); +#endif + +/** @} */ +#endif /* APR_HAS_DSO */ + + +/** + * Get the name of the system default characer set. + * @param pool the pool to allocate the name from, if needed + */ +APR_DECLARE(const char*) apr_os_default_encoding(apr_pool_t *pool); + + +/** + * Get the name of the current locale character set. + * @param pool the pool to allocate the name from, if needed + * @remark Defers to apr_os_default_encoding if the current locale's + * data can't be retreved on this system. + */ +APR_DECLARE(const char*) apr_os_locale_encoding(apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_PORTABLE_H */ diff --git a/include/apr/apr_proc_mutex.h b/include/apr/apr_proc_mutex.h new file mode 100644 index 0000000..05c9f19 --- /dev/null +++ b/include/apr/apr_proc_mutex.h @@ -0,0 +1,166 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_PROC_MUTEX_H +#define APR_PROC_MUTEX_H + +/** + * @file apr_proc_mutex.h + * @brief APR Process Locking Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_proc_mutex Process Locking Routines + * @ingroup APR + * @{ + */ + +/** + * Enumerated potential types for APR process locking methods + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +typedef enum { + APR_LOCK_FCNTL, /**< fcntl() */ + APR_LOCK_FLOCK, /**< flock() */ + APR_LOCK_SYSVSEM, /**< System V Semaphores */ + APR_LOCK_PROC_PTHREAD, /**< POSIX pthread process-based locking */ + APR_LOCK_POSIXSEM, /**< POSIX semaphore process-based locking */ + APR_LOCK_DEFAULT /**< Use the default process lock */ +} apr_lockmech_e; + +/** Opaque structure representing a process mutex. */ +typedef struct apr_proc_mutex_t apr_proc_mutex_t; + +/* Function definitions */ + +/** + * Create and initialize a mutex that can be used to synchronize processes. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + *
+ *            APR_LOCK_FCNTL
+ *            APR_LOCK_FLOCK
+ *            APR_LOCK_SYSVSEM
+ *            APR_LOCK_POSIXSEM
+ *            APR_LOCK_PROC_PTHREAD
+ *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @see apr_lockmech_e + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool); + +/** + * Re-open a mutex in a child process. + * @param mutex The newly re-opened mutex structure. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_proc_mutex_create(). + * @param pool The pool to operate on. + * @remark This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool); + +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + * @note This function is generally used to kill a cleanup on an already + * created mutex + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex); + +/** + * Return the name of the lockfile for the mutex, or NULL + * if the mutex doesn't use a lock file + */ + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex); + +/** + * Display the name of the mutex, as it relates to the actual method used. + * This matches the valid options for Apache's AcceptMutex directive + * @param mutex the name of the mutex + */ +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex); + +/** + * Display the name of the default mutex: APR_LOCK_DEFAULT + */ +APR_DECLARE(const char *) apr_proc_mutex_defname(void); + +/** + * Get the pool used by this proc_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(proc_mutex); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_PROC_MUTEX_H */ diff --git a/include/apr/apr_queue.h b/include/apr/apr_queue.h new file mode 100644 index 0000000..bde7ce4 --- /dev/null +++ b/include/apr/apr_queue.h @@ -0,0 +1,137 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_QUEUE_H +#define APR_QUEUE_H + +#if APR_HAS_THREADS +/** + * @file apr_queue.h + * @brief Thread Safe FIFO bounded queue + * @note Since most implementations of the queue are backed by a condition + * variable implementation, it isn't available on systems without threads. + * Although condition variables are some times available without threads. + */ + +#include "apu.h" +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_FIFO Thread Safe FIFO bounded queue + * @ingroup APR_Util + * @{ + */ + +/** + * opaque structure + */ +typedef struct apr_queue_t apr_queue_t; + +/** + * create a FIFO queue + * @param queue The new queue + * @param queue_capacity maximum size of the queue + * @param a pool to allocate queue from + */ +APU_DECLARE(apr_status_t) apr_queue_create(apr_queue_t **queue, + unsigned int queue_capacity, + apr_pool_t *a); + +/** + * push/add a object to the queue, blocking if the queue is already full + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking was interrupted (try again) + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successfull push + */ +APU_DECLARE(apr_status_t) apr_queue_push(apr_queue_t *queue, void *data); + +/** + * pop/get an object from the queue, blocking if the queue is already empty + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking was interrupted (try again) + * @returns APR_EOF if the queue has been terminated + * @returns APR_SUCCESS on a successfull pop + */ +APU_DECLARE(apr_status_t) apr_queue_pop(apr_queue_t *queue, void **data); + +/** + * push/add a object to the queue, returning immediatly if the queue is full + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is full + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successfull push + */ +APU_DECLARE(apr_status_t) apr_queue_trypush(apr_queue_t *queue, void *data); + +/** + * pop/get an object to the queue, returning immediatly if the queue is empty + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is empty + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successfull push + */ +APU_DECLARE(apr_status_t) apr_queue_trypop(apr_queue_t *queue, void **data); + +/** + * returns the size of the queue. + * + * @warning this is not threadsafe, and is intended for reporting/monitoring + * of the queue. + * @param queue the queue + * @returns the size of the queue + */ +APU_DECLARE(unsigned int) apr_queue_size(apr_queue_t *queue); + +/** + * interrupt all the threads blocking on this queue. + * + * @param queue the queue + */ +APU_DECLARE(apr_status_t) apr_queue_interrupt_all(apr_queue_t *queue); + +/** + * terminate all queue, sendinging a interupt to all the + * blocking threads + * + * @param queue the queue + */ +APU_DECLARE(apr_status_t) apr_queue_term(apr_queue_t *queue); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* APR_HAS_THREADS */ + +#endif /* APRQUEUE_H */ diff --git a/include/apr/apr_random.h b/include/apr/apr_random.h new file mode 100644 index 0000000..b5c2baa --- /dev/null +++ b/include/apr/apr_random.h @@ -0,0 +1,74 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_RANDOM_H +#define APR_RANDOM_H + +#include + +typedef struct apr_crypto_hash_t apr_crypto_hash_t; + +typedef void apr_crypto_hash_init_t(apr_crypto_hash_t *hash); +typedef void apr_crypto_hash_add_t(apr_crypto_hash_t *hash,const void *data, + apr_size_t bytes); +typedef void apr_crypto_hash_finish_t(apr_crypto_hash_t *hash, + unsigned char *result); + +/* FIXME: make this opaque */ +struct apr_crypto_hash_t { + apr_crypto_hash_init_t *init; + apr_crypto_hash_add_t *add; + apr_crypto_hash_finish_t *finish; + apr_size_t size; + void *data; +}; + +APR_DECLARE(apr_crypto_hash_t *) apr_crypto_sha256_new(apr_pool_t *p); + +typedef struct apr_random_t apr_random_t; + +APR_DECLARE(void) apr_random_init(apr_random_t *g,apr_pool_t *p, + apr_crypto_hash_t *pool_hash, + apr_crypto_hash_t *key_hash, + apr_crypto_hash_t *prng_hash); +APR_DECLARE(apr_random_t *) apr_random_standard_new(apr_pool_t *p); +APR_DECLARE(void) apr_random_add_entropy(apr_random_t *g, + const void *entropy_, + apr_size_t bytes); +APR_DECLARE(apr_status_t) apr_random_insecure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes); +APR_DECLARE(apr_status_t) apr_random_secure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes); +APR_DECLARE(void) apr_random_barrier(apr_random_t *g); +APR_DECLARE(apr_status_t) apr_random_secure_ready(apr_random_t *r); +APR_DECLARE(apr_status_t) apr_random_insecure_ready(apr_random_t *r); + +/* Call this in the child after forking to mix the randomness + pools. Note that its generally a bad idea to fork a process with a + real PRNG in it - better to have the PRNG externally and get the + randomness from there. However, if you really must do it, then you + should supply all your entropy to all the PRNGs - don't worry, they + won't produce the same output. + + Note that apr_proc_fork() calls this for you, so only weird + applications need ever call it themselves. +*/ +struct apr_proc_t; +APR_DECLARE(void) apr_random_after_fork(struct apr_proc_t *proc); + +#endif /* ndef APR_RANDOM_H */ diff --git a/include/apr/apr_reslist.h b/include/apr/apr_reslist.h new file mode 100644 index 0000000..e6b6484 --- /dev/null +++ b/include/apr/apr_reslist.h @@ -0,0 +1,144 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_RESLIST_H +#define APR_RESLIST_H + +/** + * @file apr_reslist.h + * @brief APR-UTIL Resource List Routines + */ + +#include "apr.h" +#include "apu.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_time.h" + +#if APR_HAS_THREADS + +/** + * @defgroup APR_Util_RL Resource List Routines + * @ingroup APR_Util + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Opaque resource list object */ +typedef struct apr_reslist_t apr_reslist_t; + +/* Generic constructor called by resource list when it needs to create a + * resource. + * @param resource opaque resource + * @param param flags + * @param pool Pool + */ +typedef apr_status_t (*apr_reslist_constructor)(void **resource, void *params, + apr_pool_t *pool); + +/* Generic destructor called by resource list when it needs to destroy a + * resource. + * @param resource opaque resource + * @param param flags + * @param pool Pool + */ +typedef apr_status_t (*apr_reslist_destructor)(void *resource, void *params, + apr_pool_t *pool); + +/** + * Create a new resource list with the following parameters: + * @param reslist An address where the pointer to the new resource + * list will be stored. + * @param pool The pool to use for local storage and management + * @param min Allowed minimum number of available resources. Zero + * creates new resources only when needed. + * @param smax Resources will be destroyed to meet this maximum + * restriction as they expire. + * @param hmax Absolute maximum limit on the number of total resources. + * @param ttl If non-zero, sets the maximum amount of time a resource + * may be available while exceeding the soft limit. + * @param con Constructor routine that is called to create a new resource. + * @param de Destructor routine that is called to destroy an expired resource. + * @param params Passed to constructor and deconstructor + * @param pool The pool from which to create this resoure list. Also the + * same pool that is passed to the constructor and destructor + * routines. + */ +APU_DECLARE(apr_status_t) apr_reslist_create(apr_reslist_t **reslist, + int min, int smax, int hmax, + apr_interval_time_t ttl, + apr_reslist_constructor con, + apr_reslist_destructor de, + void *params, + apr_pool_t *pool); + +/** + * Destroy the given resource list and all resources controlled by + * this list. + * FIXME: Should this block until all resources become available, + * or maybe just destroy all the free ones, or maybe destroy + * them even though they might be in use by something else? + * Currently it will abort if there are resources that haven't + * been released, so there is an assumption that all resources + * have been released to the list before calling this function. + * @param reslist The reslist to destroy + */ +APU_DECLARE(apr_status_t) apr_reslist_destroy(apr_reslist_t *reslist); + +/** + * Retrieve a resource from the list, creating a new one if necessary. + * If we have met our maximum number of resources, we will block + * until one becomes available. + */ +APU_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist, + void **resource); + +/** + * Return a resource back to the list of available resources. + */ +APU_DECLARE(apr_status_t) apr_reslist_release(apr_reslist_t *reslist, + void *resource); + +/** + * Set the timeout the acquire will wait for a free resource + * when the maximum number of resources is exceeded. + * @param reslist The resource list. + * @param timeout Timeout to wait. The zero waits forewer. + */ +APU_DECLARE(void) apr_reslist_timeout_set(apr_reslist_t *reslist, + apr_interval_time_t timeout); + +/** + * Invalidate a resource in the pool - e.g. a database connection + * that returns a "lost connection" error and can't be restored. + * Use this instead of apr_reslist_release if the resource is bad. + */ +APU_DECLARE(apr_status_t) apr_reslist_invalidate(apr_reslist_t *reslist, + void *resource); + + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* APR_HAS_THREADS */ + +#endif /* ! APR_RESLIST_H */ diff --git a/include/apr/apr_ring.h b/include/apr/apr_ring.h new file mode 100644 index 0000000..ba1ac1f --- /dev/null +++ b/include/apr/apr_ring.h @@ -0,0 +1,489 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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 code draws heavily from the 4.4BSD macros + * and Dean Gaudet's "splim/ring.h". + * + * + * + * We'd use Dean's code directly if we could guarantee the + * availability of inline functions. + */ + +#ifndef APR_RING_H +#define APR_RING_H + +/** + * @file apr_ring.h + * @brief APR Rings + */ + +/* + * for offsetof() + */ +#include "apr_general.h" + +/** + * @defgroup apr_ring Ring Macro Implementations + * @ingroup APR + * A ring is a kind of doubly-linked list that can be manipulated + * without knowing where its head is. + * @{ + */ + +/** + * The Ring Element + * + * A ring element struct is linked to the other elements in the ring + * through its ring entry field, e.g. + *
+ *      struct my_element_t {
+ *          APR_RING_ENTRY(my_element_t) link;
+ *          int foo;
+ *          char *bar;
+ *      };
+ * 
+ * + * An element struct may be put on more than one ring if it has more + * than one APR_RING_ENTRY field. Each APR_RING_ENTRY has a corresponding + * APR_RING_HEAD declaration. + * + * @warning For strict C standards compliance you should put the APR_RING_ENTRY + * first in the element struct unless the head is always part of a larger + * object with enough earlier fields to accommodate the offsetof() used + * to compute the ring sentinel below. You can usually ignore this caveat. + */ +#define APR_RING_ENTRY(elem) \ + struct { \ + struct elem *next; \ + struct elem *prev; \ + } + +/** + * The Ring Head + * + * Each ring is managed via its head, which is a struct declared like this: + *
+ *      APR_RING_HEAD(my_ring_t, my_element_t);
+ *      struct my_ring_t ring, *ringp;
+ * 
+ * + * This struct looks just like the element link struct so that we can + * be sure that the typecasting games will work as expected. + * + * The first element in the ring is next after the head, and the last + * element is just before the head. + */ +#define APR_RING_HEAD(head, elem) \ + struct head { \ + struct elem *next; \ + struct elem *prev; \ + } + +/** + * The Ring Sentinel + * + * This is the magic pointer value that occurs before the first and + * after the last elements in the ring, computed from the address of + * the ring's head. The head itself isn't an element, but in order to + * get rid of all the special cases when dealing with the ends of the + * ring, we play typecasting games to make it look like one. + * + * Here is a diagram to illustrate the arrangements of the next and + * prev pointers of each element in a single ring. Note that they point + * to the start of each element, not to the APR_RING_ENTRY structure. + * + *
+ *     +->+------+<-+  +->+------+<-+  +->+------+<-+
+ *     |  |struct|  |  |  |struct|  |  |  |struct|  |
+ *    /   | elem |   \/   | elem |   \/   | elem |  \
+ * ...    |      |   /\   |      |   /\   |      |   ...
+ *        +------+  |  |  +------+  |  |  +------+
+ *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
+ *        |  next|--+     | entry|--+     |  next|--...
+ *        +------+        +------+        +------+
+ *        | etc. |        | etc. |        | etc. |
+ *        :      :        :      :        :      :
+ * 
+ * + * The APR_RING_HEAD is nothing but a bare APR_RING_ENTRY. The prev + * and next pointers in the first and last elements don't actually + * point to the head, they point to a phantom place called the + * sentinel. Its value is such that last->next->next == first because + * the offset from the sentinel to the head's next pointer is the same + * as the offset from the start of an element to its next pointer. + * This also works in the opposite direction. + * + *
+ *        last                            first
+ *     +->+------+<-+  +->sentinel<-+  +->+------+<-+
+ *     |  |struct|  |  |            |  |  |struct|  |
+ *    /   | elem |   \/              \/   | elem |  \
+ * ...    |      |   /\              /\   |      |   ...
+ *        +------+  |  |  +------+  |  |  +------+
+ *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
+ *        |  next|--+     |  head|--+     |  next|--...
+ *        +------+        +------+        +------+
+ *        | etc. |                        | etc. |
+ *        :      :                        :      :
+ * 
+ * + * Note that the offset mentioned above is different for each kind of + * ring that the element may be on, and each kind of ring has a unique + * name for its APR_RING_ENTRY in each element, and has its own type + * for its APR_RING_HEAD. + * + * Note also that if the offset is non-zero (which is required if an + * element has more than one APR_RING_ENTRY), the unreality of the + * sentinel may have bad implications on very perverse implementations + * of C -- see the warning in APR_RING_ENTRY. + * + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SENTINEL(hp, elem, link) \ + (struct elem *)((char *)(hp) - APR_OFFSETOF(struct elem, link)) + +/** + * The first element of the ring + * @param hp The head of the ring + */ +#define APR_RING_FIRST(hp) (hp)->next +/** + * The last element of the ring + * @param hp The head of the ring + */ +#define APR_RING_LAST(hp) (hp)->prev +/** + * The next element in the ring + * @param ep The current element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_NEXT(ep, link) (ep)->link.next +/** + * The previous element in the ring + * @param ep The current element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_PREV(ep, link) (ep)->link.prev + + +/** + * Initialize a ring + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INIT(hp, elem, link) do { \ + APR_RING_FIRST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ + APR_RING_LAST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ + } while (0) + +/** + * Determine if a ring is empty + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @return true or false + */ +#define APR_RING_EMPTY(hp, elem, link) \ + (APR_RING_FIRST((hp)) == APR_RING_SENTINEL((hp), elem, link)) + +/** + * Initialize a singleton element + * @param ep The element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_ELEM_INIT(ep, link) do { \ + APR_RING_NEXT((ep), link) = (ep); \ + APR_RING_PREV((ep), link) = (ep); \ + } while (0) + + +/** + * Splice the sequence ep1..epN into the ring before element lep + * (..lep.. becomes ..ep1..epN..lep..) + * @warning This doesn't work for splicing before the first element or on + * empty rings... see APR_RING_SPLICE_HEAD for one that does + * @param lep Element in the ring to splice before + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do { \ + APR_RING_NEXT((epN), link) = (lep); \ + APR_RING_PREV((ep1), link) = APR_RING_PREV((lep), link); \ + APR_RING_NEXT(APR_RING_PREV((lep), link), link) = (ep1); \ + APR_RING_PREV((lep), link) = (epN); \ + } while (0) + +/** + * Splice the sequence ep1..epN into the ring after element lep + * (..lep.. becomes ..lep..ep1..epN..) + * @warning This doesn't work for splicing after the last element or on + * empty rings... see APR_RING_SPLICE_TAIL for one that does + * @param lep Element in the ring to splice after + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_AFTER(lep, ep1, epN, link) do { \ + APR_RING_PREV((ep1), link) = (lep); \ + APR_RING_NEXT((epN), link) = APR_RING_NEXT((lep), link); \ + APR_RING_PREV(APR_RING_NEXT((lep), link), link) = (epN); \ + APR_RING_NEXT((lep), link) = (ep1); \ + } while (0) + +/** + * Insert the element nep into the ring before element lep + * (..lep.. becomes ..nep..lep..) + * @warning This doesn't work for inserting before the first element or on + * empty rings... see APR_RING_INSERT_HEAD for one that does + * @param lep Element in the ring to insert before + * @param nep Element to insert + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_BEFORE(lep, nep, link) \ + APR_RING_SPLICE_BEFORE((lep), (nep), (nep), link) + +/** + * Insert the element nep into the ring after element lep + * (..lep.. becomes ..lep..nep..) + * @warning This doesn't work for inserting after the last element or on + * empty rings... see APR_RING_INSERT_TAIL for one that does + * @param lep Element in the ring to insert after + * @param nep Element to insert + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_AFTER(lep, nep, link) \ + APR_RING_SPLICE_AFTER((lep), (nep), (nep), link) + + +/** + * Splice the sequence ep1..epN into the ring before the first element + * (..hp.. becomes ..hp..ep1..epN..) + * @param hp Head of the ring + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link) \ + APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((hp), elem, link), \ + (ep1), (epN), link) + +/** + * Splice the sequence ep1..epN into the ring after the last element + * (..hp.. becomes ..ep1..epN..hp..) + * @param hp Head of the ring + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link) \ + APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((hp), elem, link), \ + (ep1), (epN), link) + +/** + * Insert the element nep into the ring before the first element + * (..hp.. becomes ..hp..nep..) + * @param hp Head of the ring + * @param nep Element to insert + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_HEAD(hp, nep, elem, link) \ + APR_RING_SPLICE_HEAD((hp), (nep), (nep), elem, link) + +/** + * Insert the element nep into the ring after the last element + * (..hp.. becomes ..nep..hp..) + * @param hp Head of the ring + * @param nep Element to insert + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_TAIL(hp, nep, elem, link) \ + APR_RING_SPLICE_TAIL((hp), (nep), (nep), elem, link) + +/** + * Concatenate ring h2 onto the end of ring h1, leaving h2 empty. + * @param h1 Head of the ring to concatenate onto + * @param h2 Head of the ring to concatenate + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CONCAT(h1, h2, elem, link) do { \ + if (!APR_RING_EMPTY((h2), elem, link)) { \ + APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((h1), elem, link), \ + APR_RING_FIRST((h2)), \ + APR_RING_LAST((h2)), link); \ + APR_RING_INIT((h2), elem, link); \ + } \ + } while (0) + +/** + * Prepend ring h2 onto the beginning of ring h1, leaving h2 empty. + * @param h1 Head of the ring to prepend onto + * @param h2 Head of the ring to prepend + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_PREPEND(h1, h2, elem, link) do { \ + if (!APR_RING_EMPTY((h2), elem, link)) { \ + APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((h1), elem, link), \ + APR_RING_FIRST((h2)), \ + APR_RING_LAST((h2)), link); \ + APR_RING_INIT((h2), elem, link); \ + } \ + } while (0) + +/** + * Unsplice a sequence of elements from a ring + * @warning The unspliced sequence is left with dangling pointers at either end + * @param ep1 First element in the sequence to unsplice + * @param epN Last element in the sequence to unsplice + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_UNSPLICE(ep1, epN, link) do { \ + APR_RING_NEXT(APR_RING_PREV((ep1), link), link) = \ + APR_RING_NEXT((epN), link); \ + APR_RING_PREV(APR_RING_NEXT((epN), link), link) = \ + APR_RING_PREV((ep1), link); \ + } while (0) + +/** + * Remove a single element from a ring + * @warning The unspliced element is left with dangling pointers at either end + * @param ep Element to remove + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_REMOVE(ep, link) \ + APR_RING_UNSPLICE((ep), (ep), link) + + +/* Debugging tools: */ + +#ifdef APR_RING_DEBUG +#include +#include + +#define APR_RING_CHECK_ONE(msg, ptr) \ + fprintf(stderr, "*** %s %p\n", msg, ptr) + +#define APR_RING_CHECK(hp, elem, link, msg) \ + APR_RING_CHECK_ELEM(APR_RING_SENTINEL(hp, elem, link), elem, link, msg) + +#define APR_RING_CHECK_ELEM(ep, elem, link, msg) do { \ + struct elem *start = (ep); \ + struct elem *here = start; \ + fprintf(stderr, "*** ring check start -- %s\n", msg); \ + do { \ + fprintf(stderr, "\telem %p\n", here); \ + fprintf(stderr, "\telem->next %p\n", \ + APR_RING_NEXT(here, link)); \ + fprintf(stderr, "\telem->prev %p\n", \ + APR_RING_PREV(here, link)); \ + fprintf(stderr, "\telem->next->prev %p\n", \ + APR_RING_PREV(APR_RING_NEXT(here, link), link)); \ + fprintf(stderr, "\telem->prev->next %p\n", \ + APR_RING_NEXT(APR_RING_PREV(here, link), link)); \ + if (APR_RING_PREV(APR_RING_NEXT(here, link), link) != here) { \ + fprintf(stderr, "\t*** elem->next->prev != elem\n"); \ + break; \ + } \ + if (APR_RING_NEXT(APR_RING_PREV(here, link), link) != here) { \ + fprintf(stderr, "\t*** elem->prev->next != elem\n"); \ + break; \ + } \ + here = APR_RING_NEXT(here, link); \ + } while (here != start); \ + fprintf(stderr, "*** ring check end\n"); \ + } while (0) + +#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) \ + APR_RING_CHECK_ELEM_CONSISTENCY(APR_RING_SENTINEL(hp, elem, link),\ + elem, link) + +#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) do { \ + struct elem *start = (ep); \ + struct elem *here = start; \ + do { \ + assert(APR_RING_PREV(APR_RING_NEXT(here, link), link) == here); \ + assert(APR_RING_NEXT(APR_RING_PREV(here, link), link) == here); \ + here = APR_RING_NEXT(here, link); \ + } while (here != start); \ + } while (0) + +#else +/** + * Print a single pointer value to STDERR + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param msg Descriptive message + * @param ptr Pointer value to print + */ +#define APR_RING_CHECK_ONE(msg, ptr) +/** + * Dump all ring pointers to STDERR, starting with the head and looping all + * the way around the ring back to the head. Aborts if an inconsistency + * is found. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param hp Head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @param msg Descriptive message + */ +#define APR_RING_CHECK(hp, elem, link, msg) +/** + * Loops around a ring and checks all the pointers for consistency. Pops + * an assertion if any inconsistency is found. Same idea as APR_RING_CHECK() + * except that it's silent if all is well. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param hp Head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) +/** + * Dump all ring pointers to STDERR, starting with the given element and + * looping all the way around the ring back to that element. Aborts if + * an inconsistency is found. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param ep The element + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @param msg Descriptive message + */ +#define APR_RING_CHECK_ELEM(ep, elem, link, msg) +/** + * Loops around a ring, starting with the given element, and checks all + * the pointers for consistency. Pops an assertion if any inconsistency + * is found. Same idea as APR_RING_CHECK_ELEM() except that it's silent + * if all is well. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param ep The element + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) +#endif + +/** @} */ + +#endif /* !APR_RING_H */ diff --git a/include/apr/apr_rmm.h b/include/apr/apr_rmm.h new file mode 100644 index 0000000..a1f0d67 --- /dev/null +++ b/include/apr/apr_rmm.h @@ -0,0 +1,137 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_RMM_H +#define APR_RMM_H +/** + * @file apr_rmm.h + * @brief APR-UTIL Relocatable Memory Management Routines + */ +/** + * @defgroup APR_Util_RMM Relocatable Memory Management Routines + * @ingroup APR_Util + * @{ + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apu.h" +#include "apr_anylock.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Structure to access Relocatable, Managed Memory */ +typedef struct apr_rmm_t apr_rmm_t; + +/** Fundamental allocation unit, within a specific apr_rmm_t */ +typedef apr_size_t apr_rmm_off_t; + +/** + * Initialize a relocatable memory block to be managed by the apr_rmm API. + * @param rmm The relocatable memory block + * @param lock An apr_anylock_t of the appropriate type of lock, or NULL + * if no locking is required. + * @param membuf The block of relocatable memory to be managed + * @param memsize The size of relocatable memory block to be managed + * @param cont The pool to use for local storage and management + * @remark Both @param membuf and @param memsize must be aligned + * (for instance using APR_ALIGN_DEFAULT). + */ +APU_DECLARE(apr_status_t) apr_rmm_init(apr_rmm_t **rmm, apr_anylock_t *lock, + void *membuf, apr_size_t memsize, + apr_pool_t *cont); + +/** + * Destroy a managed memory block. + * @param rmm The relocatable memory block to destroy + */ +APU_DECLARE(apr_status_t) apr_rmm_destroy(apr_rmm_t *rmm); + +/** + * Attach to a relocatable memory block already managed by the apr_rmm API. + * @param rmm The relocatable memory block + * @param lock An apr_anylock_t of the appropriate type of lock + * @param membuf The block of relocatable memory already under management + * @param cont The pool to use for local storage and management + */ +APU_DECLARE(apr_status_t) apr_rmm_attach(apr_rmm_t **rmm, apr_anylock_t *lock, + void *membuf, apr_pool_t *cont); + +/** + * Detach from the managed block of memory. + * @param rmm The relocatable memory block to detach from + */ +APU_DECLARE(apr_status_t) apr_rmm_detach(apr_rmm_t *rmm); + +/** + * Allocate memory from the block of relocatable memory. + * @param rmm The relocatable memory block + * @param reqsize How much memory to allocate + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_malloc(apr_rmm_t *rmm, apr_size_t reqsize); + +/** + * Realloc memory from the block of relocatable memory. + * @param rmm The relocatable memory block + * @param entity The memory allocation to realloc + * @param reqsize The new size + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_realloc(apr_rmm_t *rmm, void *entity, apr_size_t reqsize); + +/** + * Allocate memory from the block of relocatable memory and initialize it to zero. + * @param rmm The relocatable memory block + * @param reqsize How much memory to allocate + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_calloc(apr_rmm_t *rmm, apr_size_t reqsize); + +/** + * Free allocation returned by apr_rmm_malloc or apr_rmm_calloc. + * @param rmm The relocatable memory block + * @param entity The memory allocation to free + */ +APU_DECLARE(apr_status_t) apr_rmm_free(apr_rmm_t *rmm, apr_rmm_off_t entity); + +/** + * Retrieve the physical address of a relocatable allocation of memory + * @param rmm The relocatable memory block + * @param entity The memory allocation to free + * @return address The address, aligned with APR_ALIGN_DEFAULT. + */ +APU_DECLARE(void *) apr_rmm_addr_get(apr_rmm_t *rmm, apr_rmm_off_t entity); + +/** + * Compute the offset of a relocatable allocation of memory + * @param rmm The relocatable memory block + * @param entity The physical address to convert to an offset + */ +APU_DECLARE(apr_rmm_off_t) apr_rmm_offset_get(apr_rmm_t *rmm, void *entity); + +/** + * Compute the required overallocation of memory needed to fit n allocs + * @param n The number of alloc/calloc regions desired + */ +APU_DECLARE(apr_size_t) apr_rmm_overhead_get(int n); + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* ! APR_RMM_H */ + diff --git a/include/apr/apr_sdbm.h b/include/apr/apr_sdbm.h new file mode 100644 index 0000000..7fcf7f6 --- /dev/null +++ b/include/apr/apr_sdbm.h @@ -0,0 +1,175 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: ex-public domain + */ + +#ifndef APR_SDBM_H +#define APR_SDBM_H + +#include "apu.h" +#include "apr_errno.h" +#include "apr_file_io.h" /* for apr_fileperms_t */ + +/** + * @file apr_sdbm.h + * @brief apr-util SDBM library + */ +/** + * @defgroup APR_Util_DBM_SDBM SDBM library + * @ingroup APR_Util_DBM + * @{ + */ + +/** + * Structure for referencing an sdbm + */ +typedef struct apr_sdbm_t apr_sdbm_t; + +/** + * Structure for referencing the datum record within an sdbm + */ +typedef struct { + /** pointer to the data stored/retrieved */ + char *dptr; + /** size of data */ + int dsize; +} apr_sdbm_datum_t; + +/* The extensions used for the database files */ +/** SDBM Directory file extension */ +#define APR_SDBM_DIRFEXT ".dir" +/** SDBM page file extension */ +#define APR_SDBM_PAGFEXT ".pag" + +/* flags to sdbm_store */ +#define APR_SDBM_INSERT 0 /**< Insert */ +#define APR_SDBM_REPLACE 1 /**< Replace */ +#define APR_SDBM_INSERTDUP 2 /**< Insert with duplicates */ + +/** + * Open an sdbm database by file name + * @param db The newly opened database + * @param name The sdbm file to open + * @param mode The flag values (APR_READ and APR_BINARY flags are implicit) + *
+ *           APR_WRITE          open for read-write access
+ *           APR_CREATE         create the sdbm if it does not exist
+ *           APR_TRUNCATE       empty the contents of the sdbm
+ *           APR_EXCL           fail for APR_CREATE if the file exists
+ *           APR_DELONCLOSE     delete the sdbm when closed
+ *           APR_SHARELOCK      support locking across process/machines
+ * 
+ * @param perms Permissions to apply to if created + * @param p The pool to use when creating the sdbm + * @remark The sdbm name is not a true file name, as sdbm appends suffixes + * for seperate data and index files. + */ +APU_DECLARE(apr_status_t) apr_sdbm_open(apr_sdbm_t **db, const char *name, + apr_int32_t mode, + apr_fileperms_t perms, apr_pool_t *p); + +/** + * Close an sdbm file previously opened by apr_sdbm_open + * @param db The database to close + */ +APU_DECLARE(apr_status_t) apr_sdbm_close(apr_sdbm_t *db); + +/** + * Lock an sdbm database for concurency of multiple operations + * @param db The database to lock + * @param type The lock type + *
+ *           APR_FLOCK_SHARED
+ *           APR_FLOCK_EXCLUSIVE
+ * 
+ * @remark Calls to apr_sdbm_lock may be nested. All apr_sdbm functions + * perform implicit locking. Since an APR_FLOCK_SHARED lock cannot be + * portably promoted to an APR_FLOCK_EXCLUSIVE lock, apr_sdbm_store and + * apr_sdbm_delete calls will fail if an APR_FLOCK_SHARED lock is held. + * The apr_sdbm_lock call requires the database to be opened with the + * APR_SHARELOCK mode value. + */ +APU_DECLARE(apr_status_t) apr_sdbm_lock(apr_sdbm_t *db, int type); + +/** + * Release an sdbm lock previously aquired by apr_sdbm_lock + * @param db The database to unlock + */ +APU_DECLARE(apr_status_t) apr_sdbm_unlock(apr_sdbm_t *db); + +/** + * Fetch an sdbm record value by key + * @param db The database + * @param value The value datum retrieved for this record + * @param key The key datum to find this record + */ +APU_DECLARE(apr_status_t) apr_sdbm_fetch(apr_sdbm_t *db, + apr_sdbm_datum_t *value, + apr_sdbm_datum_t key); + +/** + * Store an sdbm record value by key + * @param db The database + * @param key The key datum to store this record by + * @param value The value datum to store in this record + * @param opt The method used to store the record + *
+ *           APR_SDBM_INSERT     return an error if the record exists
+ *           APR_SDBM_REPLACE    overwrite any existing record for key
+ * 
+ */ +APU_DECLARE(apr_status_t) apr_sdbm_store(apr_sdbm_t *db, apr_sdbm_datum_t key, + apr_sdbm_datum_t value, int opt); + +/** + * Delete an sdbm record value by key + * @param db The database + * @param key The key datum of the record to delete + * @remark It is not an error to delete a non-existent record. + */ +APU_DECLARE(apr_status_t) apr_sdbm_delete(apr_sdbm_t *db, + const apr_sdbm_datum_t key); + +/** + * Retrieve the first record key from a dbm + * @param db The database + * @param key The key datum of the first record + * @remark The keys returned are not ordered. To traverse the list of keys + * for an sdbm opened with APR_SHARELOCK, the caller must use apr_sdbm_lock + * prior to retrieving the first record, and hold the lock until after the + * last call to apr_sdbm_nextkey. + */ +APU_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, apr_sdbm_datum_t *key); + +/** + * Retrieve the next record key from an sdbm + * @param db The database + * @param key The key datum of the next record + */ +APU_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, apr_sdbm_datum_t *key); + +/** + * Returns true if the sdbm database opened for read-only access + * @param db The database to test + */ +APU_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db); +/** @} */ +#endif /* APR_SDBM_H */ diff --git a/include/apr/apr_sha1.h b/include/apr/apr_sha1.h new file mode 100644 index 0000000..1ad5065 --- /dev/null +++ b/include/apr/apr_sha1.h @@ -0,0 +1,121 @@ +/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ +/* NIST Secure Hash Algorithm + * heavily modified by Uwe Hollerbach uh@alumni.caltech edu + * from Peter C. Gutmann's implementation as found in + * Applied Cryptography by Bruce Schneier + * This code is hereby placed in the public domain + */ + +#ifndef APR_SHA1_H +#define APR_SHA1_H + +#include "apu.h" +#include "apr_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_sha1.h + * @brief APR-UTIL SHA1 library + */ + +/** size of the SHA1 DIGEST */ +#define APR_SHA1_DIGESTSIZE 20 + +/** + * Define the Magic String prefix that identifies a password as being + * hashed using our algorithm. + */ +#define APR_SHA1PW_ID "{SHA}" + +/** length of the SHA Password */ +#define APR_SHA1PW_IDLEN 5 + +/** @see apr_sha1_ctx_t */ +typedef struct apr_sha1_ctx_t apr_sha1_ctx_t; + +/** + * SHA1 context structure + */ +struct apr_sha1_ctx_t { + /** message digest */ + apr_uint32_t digest[5]; + /** 64-bit bit counts */ + apr_uint32_t count_lo, count_hi; + /** SHA data buffer */ + apr_uint32_t data[16]; + /** unprocessed amount in data */ + int local; +}; + +/** + * Provide a means to SHA1 crypt/encode a plaintext password in a way which + * makes password file compatible with those commonly use in netscape web + * and ldap installations. + * @param clear The plaintext password + * @param len The length of the plaintext password + * @param out The encrypted/encoded password + * @note SHA1 support is useful for migration purposes, but is less + * secure than Apache's password format, since Apache's (MD5) + * password format uses a random eight character salt to generate + * one of many possible hashes for the same password. Netscape + * uses plain SHA1 without a salt, so the same password + * will always generate the same hash, making it easier + * to break since the search space is smaller. + */ +APU_DECLARE(void) apr_sha1_base64(const char *clear, int len, char *out); + +/** + * Initialize the SHA digest + * @param context The SHA context to initialize + */ +APU_DECLARE(void) apr_sha1_init(apr_sha1_ctx_t *context); + +/** + * Update the SHA digest + * @param context The SHA1 context to update + * @param input The buffer to add to the SHA digest + * @param inputLen The length of the input buffer + */ +APU_DECLARE(void) apr_sha1_update(apr_sha1_ctx_t *context, const char *input, + unsigned int inputLen); + +/** + * Update the SHA digest with binary data + * @param context The SHA1 context to update + * @param input The buffer to add to the SHA digest + * @param inputLen The length of the input buffer + */ +APU_DECLARE(void) apr_sha1_update_binary(apr_sha1_ctx_t *context, + const unsigned char *input, + unsigned int inputLen); + +/** + * Finish computing the SHA digest + * @param digest the output buffer in which to store the digest + * @param context The context to finalize + */ +APU_DECLARE(void) apr_sha1_final(unsigned char digest[APR_SHA1_DIGESTSIZE], + apr_sha1_ctx_t *context); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SHA1_H */ diff --git a/include/apr/apr_shm.h b/include/apr/apr_shm.h new file mode 100644 index 0000000..2acb53e --- /dev/null +++ b/include/apr/apr_shm.h @@ -0,0 +1,140 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_SHM_H +#define APR_SHM_H + +/** + * @file apr_shm.h + * @brief APR Shared Memory Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_shm Shared Memory Routines + * @ingroup APR + * @{ + */ + +/** + * Private, platform-specific data struture representing a shared memory + * segment. + */ +typedef struct apr_shm_t apr_shm_t; + +/** + * Create and make accessable a shared memory segment. + * @param m The shared memory structure to create. + * @param reqsize The desired size of the segment. + * @param filename The file to use for shared memory on platforms that + * require it. + * @param pool the pool from which to allocate the shared memory + * structure. + * @remark A note about Anonymous vs. Named shared memory segments: + * Not all plaforms support anonymous shared memory segments, but in + * some cases it is prefered over other types of shared memory + * implementations. Passing a NULL 'file' parameter to this function + * will cause the subsystem to use anonymous shared memory segments. + * If such a system is not available, APR_ENOTIMPL is returned. + * @remark A note about allocation sizes: + * On some platforms it is necessary to store some metainformation + * about the segment within the actual segment. In order to supply + * the caller with the requested size it may be necessary for the + * implementation to request a slightly greater segment length + * from the subsystem. In all cases, the apr_shm_baseaddr_get() + * function will return the first usable byte of memory. + * + */ +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *pool); + +/** + * Remove shared memory segment associated with a filename. + * @param filename The filename associated with shared-memory segment which + * needs to be removed + * @param pool The pool used for file operations + * @remark This function is only supported on platforms which support + * name-based shared memory segments, and will return APR_ENOTIMPL on + * platforms without such support. + */ +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool); + +/** + * Destroy a shared memory segment and associated memory. + * @param m The shared memory segment structure to destroy. + */ +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m); + +/** + * Attach to a shared memory segment that was created + * by another process. + * @param m The shared memory structure to create. + * @param filename The file used to create the original segment. + * (This MUST match the original filename.) + * @param pool the pool from which to allocate the shared memory + * structure for this process. + */ +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *filename, + apr_pool_t *pool); + +/** + * Detach from a shared memory segment without destroying it. + * @param m The shared memory structure representing the segment + * to detach from. + */ +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m); + +/** + * Retrieve the base address of the shared memory segment. + * NOTE: This address is only usable within the callers address + * space, since this API does not guarantee that other attaching + * processes will maintain the same address mapping. + * @param m The shared memory segment from which to retrieve + * the base address. + * @return address, aligned by APR_ALIGN_DEFAULT. + */ +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m); + +/** + * Retrieve the length of a shared memory segment in bytes. + * @param m The shared memory segment from which to retrieve + * the segment length. + */ +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m); + +/** + * Get the pool used by this shared memory segment. + */ +APR_POOL_DECLARE_ACCESSOR(shm); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SHM_T */ diff --git a/include/apr/apr_signal.h b/include/apr/apr_signal.h new file mode 100644 index 0000000..8cf65be --- /dev/null +++ b/include/apr/apr_signal.h @@ -0,0 +1,109 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_SIGNAL_H +#define APR_SIGNAL_H + +/** + * @file apr_signal.h + * @brief APR Signal Handling + */ + +#include "apr.h" +#include "apr_pools.h" + +#if APR_HAVE_SIGNAL_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_signal Handling + * @ingroup APR + * @{ + */ + +#if APR_HAVE_SIGACTION || defined(DOXYGEN) + +#if defined(DARWIN) && !defined(__cplusplus) && !defined(_ANSI_SOURCE) +/* work around Darwin header file bugs + * http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2657228.html + */ +#undef SIG_DFL +#undef SIG_IGN +#undef SIG_ERR +#define SIG_DFL (void (*)(int))0 +#define SIG_IGN (void (*)(int))1 +#define SIG_ERR (void (*)(int))-1 +#endif + +/** Function prototype for signal handlers */ +typedef void apr_sigfunc_t(int); + +/** + * Set the signal handler function for a given signal + * @param signo The signal (eg... SIGWINCH) + * @param func the function to get called + */ +APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func); + +#if defined(SIG_IGN) && !defined(SIG_ERR) +#define SIG_ERR ((apr_sigfunc_t *) -1) +#endif + +#else /* !APR_HAVE_SIGACTION */ +#define apr_signal(a, b) signal(a, b) +#endif + + +/** + * Get the description for a specific signal number + * @param signum The signal number + * @return The description of the signal + */ +APR_DECLARE(const char *) apr_signal_description_get(int signum); + +/** + * APR-private function for initializing the signal package + * @internal + * @param pglobal The internal, global pool + */ +void apr_signal_init(apr_pool_t *pglobal); + +/** + * Block the delivery of a particular signal + * @param signum The signal number + * @return status + */ +APR_DECLARE(apr_status_t) apr_signal_block(int signum); + +/** + * Enable the delivery of a particular signal + * @param signum The signal number + * @return status + */ +APR_DECLARE(apr_status_t) apr_signal_unblock(int signum); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* APR_SIGNAL_H */ diff --git a/include/apr/apr_strings.h b/include/apr/apr_strings.h new file mode 100644 index 0000000..94e99c3 --- /dev/null +++ b/include/apr/apr_strings.h @@ -0,0 +1,357 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* Portions of this file are covered by */ +/* -*- mode: c; c-file-style: "k&r" -*- + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef APR_STRINGS_H +#define APR_STRINGS_H + +/** + * @file apr_strings.h + * @brief APR Strings library + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#define APR_WANT_IOVEC +#include "apr_want.h" + +#if APR_HAVE_STDARG_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_strings String routines + * @ingroup APR + * @{ + */ + +/** + * Do a natural order comparison of two strings. + * @param a The first string to compare + * @param b The second string to compare + * @return Either <0, 0, or >0. If the first string is less than the second + * this returns <0, if they are equivalent it returns 0, and if the + * first string is greater than second string it retuns >0. + */ +APR_DECLARE(int) apr_strnatcmp(char const *a, char const *b); + +/** + * Do a natural order comparison of two strings ignoring the case of the + * strings. + * @param a The first string to compare + * @param b The second string to compare + * @return Either <0, 0, or >0. If the first string is less than the second + * this returns <0, if they are equivalent it returns 0, and if the + * first string is greater than second string it retuns >0. + */ +APR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b); + +/** + * duplicate a string into memory allocated out of a pool + * @param p The pool to allocate out of + * @param s The string to duplicate + * @return The new string + */ +APR_DECLARE(char *) apr_pstrdup(apr_pool_t *p, const char *s); + +/** + * Create a null-terminated string by making a copy of a sequence + * of characters and appending a null byte + * @param p The pool to allocate out of + * @param s The block of characters to duplicate + * @param n The number of characters to duplicate + * @return The new string + * @remark This is a faster alternative to apr_pstrndup, for use + * when you know that the string being duplicated really + * has 'n' or more characters. If the string might contain + * fewer characters, use apr_pstrndup. + */ +APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *p, const char *s, apr_size_t n); + +/** + * duplicate the first n characters of a string into memory allocated + * out of a pool; the new string will be null-terminated + * @param p The pool to allocate out of + * @param s The string to duplicate + * @param n The number of characters to duplicate + * @return The new string + */ +APR_DECLARE(char *) apr_pstrndup(apr_pool_t *p, const char *s, apr_size_t n); + +/** + * Duplicate a block of memory. + * + * @param p The pool to allocate from + * @param m The memory to duplicate + * @param n The number of bytes to duplicate + * @return The new block of memory + */ +APR_DECLARE(void *) apr_pmemdup(apr_pool_t *p, const void *m, apr_size_t n); + +/** + * Concatenate multiple strings, allocating memory out a pool + * @param p The pool to allocate out of + * @param ... The strings to concatenate. The final string must be NULL + * @return The new string + */ +APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *p, ...); + +/** + * Concatenate multiple strings specified in a writev-style vector + * @param p The pool from which to allocate + * @param vec The strings to concatenate + * @param nvec The number of strings to concatenate + * @param nbytes (output) strlen of new string (pass in NULL to omit) + * @return The new string + */ +APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *p, const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes); + +/** + * printf-style style printing routine. The data is output to a string + * allocated from a pool + * @param p The pool to allocate out of + * @param fmt The format of the string + * @param ap The arguments to use while printing the data + * @return The new string + */ +APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *p, const char *fmt, va_list ap); + +/** + * printf-style style printing routine. The data is output to a string + * allocated from a pool + * @param p The pool to allocate out of + * @param fmt The format of the string + * @param ... The arguments to use while printing the data + * @return The new string + */ +APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) + __attribute__((format(printf,2,3))); + +/** + * Copy up to dst_size characters from src to dst; does not copy + * past a NUL terminator in src, but always terminates dst with a NUL + * regardless. + * @param dst The destination string + * @param src The source string + * @param dst_size The space available in dst; dst always receives + * NUL termination, so if src is longer than + * dst_size, the actual number of characters copied is + * dst_size - 1. + * @return Pointer to the NUL terminator of the destination string, dst + * @remark + *
+ * Note the differences between this function and strncpy():
+ *  1) strncpy() doesn't always NUL terminate; apr_cpystrn() does.
+ *  2) strncpy() pads the destination string with NULs, which is often 
+ *     unnecessary; apr_cpystrn() does not.
+ *  3) strncpy() returns a pointer to the beginning of the dst string;
+ *     apr_cpystrn() returns a pointer to the NUL terminator of dst, 
+ *     to allow a check for truncation.
+ * 
+ */ +APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, + apr_size_t dst_size); + +/** + * Strip spaces from a string + * @param dest The destination string. It is okay to modify the string + * in place. Namely dest == src + * @param src The string to rid the spaces from. + * @return The destination string, dest. + */ +APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src); + +/** + * Convert the arguments to a program from one string to an array of + * strings terminated by a NULL pointer + * @param arg_str The arguments to convert + * @param argv_out Output location. This is a pointer to an array of strings. + * @param token_context Pool to use. + */ +APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, + char ***argv_out, + apr_pool_t *token_context); + +/** + * Split a string into separate null-terminated tokens. The tokens are + * delimited in the string by one or more characters from the sep + * argument. + * @param str The string to separate; this should be specified on the + * first call to apr_strtok() for a given string, and NULL + * on subsequent calls. + * @param sep The set of delimiters + * @param last Internal state saved by apr_strtok() between calls. + * @return The next token from the string + */ +APR_DECLARE(char *) apr_strtok(char *str, const char *sep, char **last); + +/** + * @defgroup APR_Strings_Snprintf snprintf implementations + * @warning + * These are snprintf implementations based on apr_vformatter(). + * + * Note that various standards and implementations disagree on the return + * value of snprintf, and side-effects due to %n in the formatting string. + * apr_snprintf (and apr_vsnprintf) behaves as follows: + * + * Process the format string until the entire string is exhausted, or + * the buffer fills. If the buffer fills then stop processing immediately + * (so no further %n arguments are processed), and return the buffer + * length. In all cases the buffer is NUL terminated. It will return the + * number of characters inserted into the buffer, not including the + * terminating NUL. As a special case, if len is 0, apr_snprintf will + * return the number of characters that would have been inserted if + * the buffer had been infinite (in this case, *buffer can be NULL) + * + * In no event does apr_snprintf return a negative number. + * @{ + */ + +/** + * snprintf routine based on apr_vformatter. This means it understands the + * same extensions. + * @param buf The buffer to write to + * @param len The size of the buffer + * @param format The format string + * @param ... The arguments to use to fill out the format string. + */ +APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, + const char *format, ...) + __attribute__((format(printf,3,4))); + +/** + * vsnprintf routine based on apr_vformatter. This means it understands the + * same extensions. + * @param buf The buffer to write to + * @param len The size of the buffer + * @param format The format string + * @param ap The arguments to use to fill out the format string. + */ +APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, + va_list ap); +/** @} */ + +/** + * create a string representation of an int, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n); + +/** + * create a string representation of a long, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n); + +/** + * create a string representation of an apr_off_t, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n); + +/** + * Convert a numeric string into an apr_off_t numeric value. + * @param offset The value of the parsed string. + * @param buf The string to parse. It may contain optional whitespace, + * followed by an optional '+' (positive, default) or '-' (negative) + * character, followed by an optional '0x' prefix if base is 0 or 16, + * followed by numeric digits appropriate for base. + * @param end A pointer to the end of the valid character in buf. If + * not NULL, it is set to the first invalid character in buf. + * @param base A numeric base in the range between 2 and 36 inclusive, + * or 0. If base is zero, buf will be treated as base ten unless its + * digits are prefixed with '0x', in which case it will be treated as + * base 16. + */ +APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *buf, + char **end, int base); + +/** + * parse a numeric string into a 64-bit numeric value + * @param buf The string to parse. It may contain optional whitespace, + * followed by an optional '+' (positive, default) or '-' (negative) + * character, followed by an optional '0x' prefix if base is 0 or 16, + * followed by numeric digits appropriate for base. + * @param end A pointer to the end of the valid character in buf. If + * not NULL, it is set to the first invalid character in buf. + * @param base A numeric base in the range between 2 and 36 inclusive, + * or 0. If base is zero, buf will be treated as base ten unless its + * digits are prefixed with '0x', in which case it will be treated as + * base 16. + * @return The numeric value of the string. On overflow, errno is set + * to ERANGE. + */ +APR_DECLARE(apr_int64_t) apr_strtoi64(const char *buf, char **end, int base); + +/** + * parse a base-10 numeric string into a 64-bit numeric value. + * Equivalent to apr_strtoi64(buf, (char**)NULL, 10). + * @param buf The string to parse + * @return The numeric value of the string + */ +APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf); + +/** + * Format a binary size (magnitiudes are 2^10 rather than 10^3) from an apr_off_t, + * as bytes, K, M, T, etc, to a four character compacted human readable string. + * @param size The size to format + * @param buf The 5 byte text buffer (counting the trailing null) + * @return The buf passed to apr_strfsize() + * @remark All negative sizes report ' - ', apr_strfsize only formats positive values. + */ +APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_STRINGS_H */ diff --git a/include/apr/apr_strmatch.h b/include/apr/apr_strmatch.h new file mode 100644 index 0000000..4753318 --- /dev/null +++ b/include/apr/apr_strmatch.h @@ -0,0 +1,81 @@ +/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_STRMATCH_H +#define APR_STRMATCH_H +/** + * @file apr_strmatch.h + * @brief APR-UTIL string matching routines + */ + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_StrMatch String matching routines + * @ingroup APR_Util + * @{ + */ + +/** @see apr_strmatch_pattern */ +typedef struct apr_strmatch_pattern apr_strmatch_pattern; + +/** + * Precompiled search pattern + */ +struct apr_strmatch_pattern { + /** Function called to compare */ + const char *(*compare)(const apr_strmatch_pattern *this_pattern, + const char *s, apr_size_t slen); + const char *pattern; /**< Current pattern */ + apr_size_t length; /**< Current length */ + void *context; /**< hook to add precomputed metadata */ +}; + +#if defined(DOXYGEN) +/** + * Search for a precompiled pattern within a string + * @param pattern The pattern + * @param s The string in which to search for the pattern + * @param slen The length of s (excluding null terminator) + * @return A pointer to the first instance of the pattern in s, or + * NULL if not found + */ +APU_DECLARE(const char *) apr_strmatch(const apr_strmatch_pattern *pattern, + const char *s, apr_size_t slen); +#else +#define apr_strmatch(pattern, s, slen) (*((pattern)->compare))((pattern), (s), (slen)) +#endif + +/** + * Precompile a pattern for matching using the Boyer-Moore-Horspool algorithm + * @param p The pool from which to allocate the pattern + * @param s The pattern string + * @param case_sensitive Whether the matching should be case-sensitive + * @return a pointer to the compiled pattern, or NULL if compilation fails + */ +APU_DECLARE(const apr_strmatch_pattern *) apr_strmatch_precompile(apr_pool_t *p, const char *s, int case_sensitive); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_STRMATCH_H */ diff --git a/include/apr/apr_support.h b/include/apr/apr_support.h new file mode 100644 index 0000000..17a146a --- /dev/null +++ b/include/apr/apr_support.h @@ -0,0 +1,53 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_SUPPORT_H +#define APR_SUPPORT_H + +/** + * @file apr_support.h + * @brief APR Support functions + */ + +#include "apr.h" +#include "apr_network_io.h" +#include "apr_file_io.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_support Internal APR support functions + * @ingroup APR + * @{ + */ + +/** + * Wait for IO to occur or timeout. + * + * Uses POOL for temporary allocations. + */ +apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, + int for_read); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_SUPPORT_H */ diff --git a/include/apr/apr_tables.h b/include/apr/apr_tables.h new file mode 100644 index 0000000..c30fdcb --- /dev/null +++ b/include/apr/apr_tables.h @@ -0,0 +1,422 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_TABLES_H +#define APR_TABLES_H + +/** + * @file apr_tables.h + * @brief APR Table library + */ + +#include "apr.h" +#include "apr_pools.h" + +#if APR_HAVE_STDARG_H +#include /* for va_list */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_tables Table and Array Functions + * @ingroup APR + * Tables are used to store entirely opaque structures + * for applications, while Arrays are usually used to + * deal with string lists. + * @{ + */ + +/** the table abstract data type */ +typedef struct apr_table_t apr_table_t; + +/** @see apr_array_header_t */ +typedef struct apr_array_header_t apr_array_header_t; + +/** An opaque array type */ +struct apr_array_header_t { + /** The pool the array is allocated out of */ + apr_pool_t *pool; + /** The amount of memory allocated for each element of the array */ + int elt_size; + /** The number of active elements in the array */ + int nelts; + /** The number of elements allocated in the array */ + int nalloc; + /** The elements in the array */ + char *elts; +}; + +/** + * The (opaque) structure for string-content tables. + */ +typedef struct apr_table_entry_t apr_table_entry_t; + +/** The type for each entry in a string-content table */ +struct apr_table_entry_t { + /** The key for the current table entry */ + char *key; /* maybe NULL in future; + * check when iterating thru table_elts + */ + /** The value for the current table entry */ + char *val; + + /** A checksum for the key, for use by the apr_table internals */ + apr_uint32_t key_checksum; +}; + +/** + * Get the elements from a table + * @param t The table + * @return An array containing the contents of the table + */ +APR_DECLARE(const apr_array_header_t *) apr_table_elts(const apr_table_t *t); + +/** + * Determine if the table is empty + * @param t The table to check + * @return True if empty, False otherwise + */ +APR_DECLARE(int) apr_is_empty_table(const apr_table_t *t); + +/** + * Determine if the array is empty + * @param a The array to check + * @return True if empty, False otherwise + */ +APR_DECLARE(int) apr_is_empty_array(const apr_array_header_t *a); + +/** + * Create an array + * @param p The pool to allocate the memory out of + * @param nelts the number of elements in the initial array + * @param elt_size The size of each element in the array. + * @return The new array + */ +APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, + int nelts, int elt_size); + +/** + * Add a new element to an array (as a first-in, last-out stack) + * @param arr The array to add an element to. + * @return Location for the new element in the array. + * @remark If there are no free spots in the array, then this function will + * allocate new space for the new element. + */ +APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr); + +/** + * Remove an element from an array (as a first-in, last-out stack) + * @param arr The array to remove an element from. + * @return Location of the element in the array. + * @remark If there are no elements in the array, NULL is returned. + */ +APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr); + +/** + * Concatenate two arrays together + * @param dst The destination array, and the one to go first in the combined + * array + * @param src The source array to add to the destination array + */ +APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst, + const apr_array_header_t *src); + +/** + * Copy the entire array + * @param p The pool to allocate the copy of the array out of + * @param arr The array to copy + * @return An exact copy of the array passed in + * @remark The alternate apr_array_copy_hdr copies only the header, and arranges + * for the elements to be copied if (and only if) the code subsequently + * does a push or arraycat. + */ +APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p, + const apr_array_header_t *arr); +/** + * Copy the headers of the array, and arrange for the elements to be copied if + * and only if the code subsequently does a push or arraycat. + * @param p The pool to allocate the copy of the array out of + * @param arr The array to copy + * @return An exact copy of the array passed in + * @remark The alternate apr_array_copy copies the *entire* array. + */ +APR_DECLARE(apr_array_header_t *) apr_array_copy_hdr(apr_pool_t *p, + const apr_array_header_t *arr); + +/** + * Append one array to the end of another, creating a new array in the process. + * @param p The pool to allocate the new array out of + * @param first The array to put first in the new array. + * @param second The array to put second in the new array. + * @return A new array containing the data from the two arrays passed in. +*/ +APR_DECLARE(apr_array_header_t *) apr_array_append(apr_pool_t *p, + const apr_array_header_t *first, + const apr_array_header_t *second); + +/** + * Generates a new string from the apr_pool_t containing the concatenated + * sequence of substrings referenced as elements within the array. The string + * will be empty if all substrings are empty or null, or if there are no + * elements in the array. If sep is non-NUL, it will be inserted between + * elements as a separator. + * @param p The pool to allocate the string out of + * @param arr The array to generate the string from + * @param sep The separator to use + * @return A string containing all of the data in the array. + */ +APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t *p, + const apr_array_header_t *arr, + const char sep); + +/** + * Make a new table + * @param p The pool to allocate the pool out of + * @param nelts The number of elements in the initial table. + * @return The new table. + * @warning This table can only store text data + */ +APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts); + +/** + * Create a new table and copy another table into it + * @param p The pool to allocate the new table out of + * @param t The table to copy + * @return A copy of the table passed in + */ +APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, + const apr_table_t *t); + +/** + * Delete all of the elements from a table + * @param t The table to clear + */ +APR_DECLARE(void) apr_table_clear(apr_table_t *t); + +/** + * Get the value associated with a given key from the table. After this call, + * The data is still in the table + * @param t The table to search for the key + * @param key The key to search for + * @return The value associated with the key, or NULL if the key does not exist. + */ +APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key); + +/** + * Add a key/value pair to a table, if another element already exists with the + * same key, this will over-write the old data. + * @param t The table to add the data to. + * @param key The key fo use + * @param val The value to add + * @remark When adding data, this function makes a copy of both the key and the + * value. + */ +APR_DECLARE(void) apr_table_set(apr_table_t *t, const char *key, + const char *val); + +/** + * Add a key/value pair to a table, if another element already exists with the + * same key, this will over-write the old data. + * @param t The table to add the data to. + * @param key The key to use + * @param val The value to add + * @warning When adding data, this function does not make a copy of the key or + * the value, so care should be taken to ensure that the values will + * not change after they have been added.. + */ +APR_DECLARE(void) apr_table_setn(apr_table_t *t, const char *key, + const char *val); + +/** + * Remove data from the table + * @param t The table to remove data from + * @param key The key of the data being removed + */ +APR_DECLARE(void) apr_table_unset(apr_table_t *t, const char *key); + +/** + * Add data to a table by merging the value with data that has already been + * stored + * @param t The table to search for the data + * @param key The key to merge data for + * @param val The data to add + * @remark If the key is not found, then this function acts like apr_table_add + */ +APR_DECLARE(void) apr_table_merge(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table by merging the value with data that has already been + * stored + * @param t The table to search for the data + * @param key The key to merge data for + * @param val The data to add + * @remark If the key is not found, then this function acts like apr_table_addn + */ +APR_DECLARE(void) apr_table_mergen(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table, regardless of whether there is another element with the + * same key. + * @param t The table to add to + * @param key The key to use + * @param val The value to add. + * @remark When adding data, this function makes a copy of both the key and the + * value. + */ +APR_DECLARE(void) apr_table_add(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table, regardless of whether there is another element with the + * same key. + * @param t The table to add to + * @param key The key to use + * @param val The value to add. + * @remark When adding data, this function does not make a copy of the key or the + * value, so care should be taken to ensure that the values will not + * change after they have been added.. + */ +APR_DECLARE(void) apr_table_addn(apr_table_t *t, const char *key, + const char *val); + +/** + * Merge two tables into one new table + * @param p The pool to use for the new table + * @param overlay The first table to put in the new table + * @param base The table to add at the end of the new table + * @return A new table containing all of the data from the two passed in + */ +APR_DECLARE(apr_table_t *) apr_table_overlay(apr_pool_t *p, + const apr_table_t *overlay, + const apr_table_t *base); + +/** + * Declaration prototype for the iterator callback function of apr_table_do() + * and apr_table_vdo(). + * @param rec The data passed as the first argument to apr_table_[v]do() + * @param key The key from this iteration of the table + * @param value The value from this iteration of the table + * @remark Iteration continues while this callback function returns non-zero. + * To export the callback function for apr_table_[v]do() it must be declared + * in the _NONSTD convention. + */ +typedef int (apr_table_do_callback_fn_t)(void *rec, const char *key, + const char *value); + +/** + * Iterate over a table running the provided function once for every + * element in the table. If there is data passed in as a vararg, then the + * function is only run on those elements whose key matches something in + * the vararg. If the vararg is NULL, then every element is run through the + * function. Iteration continues while the function returns non-zero. + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param t The table to iterate over + * @param ... The vararg. If this is NULL, then all elements in the table are + * run through the function, otherwise only those whose key matches + * are run. + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t + */ +APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, ...); + +/** + * Iterate over a table running the provided function once for every + * element in the table. If there is data passed in as a vararg, then the + * function is only run on those element's whose key matches something in + * the vararg. If the vararg is NULL, then every element is run through the + * function. Iteration continues while the function returns non-zero. + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param t The table to iterate over + * @param vp The vararg table. If this is NULL, then all elements in the + * table are run through the function, otherwise only those + * whose key matches are run. + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t + */ +APR_DECLARE(int) apr_table_vdo(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, va_list vp); + +/** flag for overlap to use apr_table_setn */ +#define APR_OVERLAP_TABLES_SET (0) +/** flag for overlap to use apr_table_mergen */ +#define APR_OVERLAP_TABLES_MERGE (1) +/** + * For each element in table b, either use setn or mergen to add the data + * to table a. Which method is used is determined by the flags passed in. + * @param a The table to add the data to. + * @param b The table to iterate over, adding its data to table a + * @param flags How to add the table to table a. One of: + * APR_OVERLAP_TABLES_SET Use apr_table_setn + * APR_OVERLAP_TABLES_MERGE Use apr_table_mergen + * @remark This function is highly optimized, and uses less memory and CPU cycles + * than a function that just loops through table b calling other functions. + */ +/** + *
+ * Conceptually, apr_table_overlap does this:
+ *
+ *  apr_array_header_t *barr = apr_table_elts(b);
+ *  apr_table_entry_t *belt = (apr_table_entry_t *)barr->elts;
+ *  int i;
+ *
+ *  for (i = 0; i < barr->nelts; ++i) {
+ *      if (flags & APR_OVERLAP_TABLES_MERGE) {
+ *          apr_table_mergen(a, belt[i].key, belt[i].val);
+ *      }
+ *      else {
+ *          apr_table_setn(a, belt[i].key, belt[i].val);
+ *      }
+ *  }
+ *
+ *  Except that it is more efficient (less space and cpu-time) especially
+ *  when b has many elements.
+ *
+ *  Notice the assumptions on the keys and values in b -- they must be
+ *  in an ancestor of a's pool.  In practice b and a are usually from
+ *  the same pool.
+ * 
+ */ + +APR_DECLARE(void) apr_table_overlap(apr_table_t *a, const apr_table_t *b, + unsigned flags); + +/** + * Eliminate redundant entries in a table by either overwriting + * or merging duplicates + * + * @param t Table. + * @param flags APR_OVERLAP_TABLES_MERGE to merge, or + * APR_OVERLAP_TABLES_SET to overwrite + */ +APR_DECLARE(void) apr_table_compress(apr_table_t *t, unsigned flags); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_TABLES_H */ diff --git a/include/apr/apr_thread_cond.h b/include/apr/apr_thread_cond.h new file mode 100644 index 0000000..8b8a553 --- /dev/null +++ b/include/apr/apr_thread_cond.h @@ -0,0 +1,134 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_THREAD_COND_H +#define APR_THREAD_COND_H + +/** + * @file apr_thread_cond.h + * @brief APR Condition Variable Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_time.h" +#include "apr_thread_mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS || defined(DOXYGEN) + +/** + * @defgroup apr_thread_cond Condition Variable Routines + * @ingroup APR + * @{ + */ + +/** Opaque structure for thread condition variables */ +typedef struct apr_thread_cond_t apr_thread_cond_t; + +/** + * Note: destroying a condition variable (or likewise, destroying or + * clearing the pool from which a condition variable was allocated) if + * any threads are blocked waiting on it gives undefined results. + */ + +/** + * Create and initialize a condition variable that can be used to signal + * and schedule threads in a single process. + * @param cond the memory address where the newly created condition variable + * will be stored. + * @param pool the pool from which to allocate the mutex. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool); + +/** + * Put the active calling thread to sleep until signaled to wake up. Each + * condition variable must be associated with a mutex, and that mutex must + * be locked before calling this function, or the behavior will be + * undefined. As the calling thread is put to sleep, the given mutex + * will be simultaneously released; and as this thread wakes up the lock + * is again simultaneously acquired. + * @param cond the condition variable on which to block. + * @param mutex the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex); + +/** + * Put the active calling thread to sleep until signaled to wake up or + * the timeout is reached. Each condition variable must be associated + * with a mutex, and that mutex must be locked before calling this + * function, or the behavior will be undefined. As the calling thread + * is put to sleep, the given mutex will be simultaneously released; + * and as this thread wakes up the lock is again simultaneously acquired. + * @param cond the condition variable on which to block. + * @param mutex the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @param timeout The amount of time in microseconds to wait. This is + * a maximum, not a minimum. If the condition is signaled, we + * will wake up before this time, otherwise the error APR_TIMEUP + * is returned. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout); + +/** + * Signals a single thread, if one exists, that is blocking on the given + * condition variable. That thread is then scheduled to wake up and acquire + * the associated mutex. Although it is not required, if predictable scheduling + * is desired, that mutex must be locked while calling this function. + * @param cond the condition variable on which to produce the signal. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond); + +/** + * Signals all threads blocking on the given condition variable. + * Each thread that was signaled is then scheduled to wake up and acquire + * the associated mutex. This will happen in a serialized manner. + * @param cond the condition variable on which to produce the broadcast. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond); + +/** + * Destroy the condition variable and free the associated memory. + * @param cond the condition variable to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond); + +/** + * Get the pool used by this thread_cond. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_cond); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_COND_H */ diff --git a/include/apr/apr_thread_mutex.h b/include/apr/apr_thread_mutex.h new file mode 100644 index 0000000..4d73164 --- /dev/null +++ b/include/apr/apr_thread_mutex.h @@ -0,0 +1,110 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_THREAD_MUTEX_H +#define APR_THREAD_MUTEX_H + +/** + * @file apr_thread_mutex.h + * @brief APR Thread Mutex Routines + */ + +#include "apr.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS || defined(DOXYGEN) + +/** + * @defgroup apr_thread_mutex Thread Mutex Routines + * @ingroup APR + * @{ + */ + +/** Opaque thread-local mutex structure */ +typedef struct apr_thread_mutex_t apr_thread_mutex_t; + +#define APR_THREAD_MUTEX_DEFAULT 0x0 /**< platform-optimal lock behavior */ +#define APR_THREAD_MUTEX_NESTED 0x1 /**< enable nested (recursive) locks */ +#define APR_THREAD_MUTEX_UNNESTED 0x2 /**< disable nested locks */ + +/* Delayed the include to avoid a circular reference */ +#include "apr_pools.h" + +/** + * Create and initialize a mutex that can be used to synchronize threads. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param flags Or'ed value of: + *
+ *           APR_THREAD_MUTEX_DEFAULT   platform-optimal lock behavior.
+ *           APR_THREAD_MUTEX_NESTED    enable nested (recursive) locks.
+ *           APR_THREAD_MUTEX_UNNESTED  disable nested locks (non-recursive).
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @warning Be cautious in using APR_THREAD_MUTEX_DEFAULT. While this is the + * most optimial mutex based on a given platform's performance charateristics, + * it will behave as either a nested or an unnested lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool); +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex); + +/** + * Get the pool used by this thread_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_mutex); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_MUTEX_H */ diff --git a/include/apr/apr_thread_pool.h b/include/apr/apr_thread_pool.h new file mode 100644 index 0000000..cbf382b --- /dev/null +++ b/include/apr/apr_thread_pool.h @@ -0,0 +1,299 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you 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. + */ + +#ifndef APU_THREAD_POOL_H +#define APU_THREAD_POOL_H + +#include "apu.h" +#include "apr_thread_proc.h" + +/** + * @file apr_thread_pool.h + * @brief APR Thread Pool Library + + * @remarks This library implements a thread pool using apr_thread_t. A thread + * pool is a set of threads that can be created in advance or on demand until a + * maximum number. When a task is scheduled, the thread pool will find an idle + * thread to handle the task. In case all existing threads are busy and the + * number of tasks in the queue is higher than the adjustable threshold, the + * pool will try to create a new thread to serve the task if the maximum number + * has not been reached. Otherwise, the task will be put into a queue based on + * priority, which can be valued from 0 to 255, with higher values being served + * first. If there are tasks with the same priority, the new task might be put at + * the top or at the bottom - it depends on which function is used to put the task. + * + * @remarks There may be the case where the thread pool can use up to the maximum + * number of threads at peak load, but having those threads idle afterwards. A + * maximum number of idle threads can be set so that the extra idling threads will + * be terminated to save system resources. + */ +#if APR_HAS_THREADS + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_TP Thread Pool routines + * @ingroup APR_Util + * @{ + */ + +/** Opaque Thread Pool structure. */ +typedef struct apr_thread_pool apr_thread_pool_t; + +#define APR_THREAD_TASK_PRIORITY_LOWEST 0 +#define APR_THREAD_TASK_PRIORITY_LOW 63 +#define APR_THREAD_TASK_PRIORITY_NORMAL 127 +#define APR_THREAD_TASK_PRIORITY_HIGH 191 +#define APR_THREAD_TASK_PRIORITY_HIGHEST 255 + +/** + * Create a thread pool + * @param me The pointer in which to return the newly created apr_thread_pool + * object, or NULL if thread pool creation fails. + * @param init_threads The number of threads to be created initially, this number + * will also be used as the initial value for the maximum number of idle threads. + * @param max_threads The maximum number of threads that can be created + * @param pool The pool to use + * @return APR_SUCCESS if the thread pool was created successfully. Otherwise, + * the error code. + */ +APU_DECLARE(apr_status_t) apr_thread_pool_create(apr_thread_pool_t **me, + apr_size_t init_threads, + apr_size_t max_threads, + apr_pool_t *pool); + +/** + * Destroy the thread pool and stop all the threads + * @return APR_SUCCESS if all threads are stopped. + */ +APU_DECLARE(apr_status_t) apr_thread_pool_destroy(apr_thread_pool_t *me); + +/** + * Schedule a task to the bottom of the tasks of same priority. + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param priority The priority of the task. + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_push(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner); +/** + * Schedule a task to be run after a delay + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param time Time in microseconds + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_schedule(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_interval_time_t time, + void *owner); + +/** + * Schedule a task to the top of the tasks of same priority. + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param priority The priority of the task. + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_top(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner); + +/** + * Cancel tasks submitted by the owner. If there is any task from the owner that + * is currently running, the function will spin until the task finished. + * @param me The thread pool + * @param owner Owner of the task + * @return APR_SUCCESS if the task has been cancelled successfully + * @note The task function should not be calling cancel, otherwise the function + * may get stuck forever. The function assert if it detect such a case. + */ +APU_DECLARE(apr_status_t) apr_thread_pool_tasks_cancel(apr_thread_pool_t *me, + void *owner); + +/** + * Get the current number of tasks waiting in the queue + * @param me The thread pool + * @return Number of tasks in the queue + */ +APU_DECLARE(apr_size_t) apr_thread_pool_tasks_count(apr_thread_pool_t *me); + +/** + * Get the current number of scheduled tasks waiting in the queue + * @param me The thread pool + * @return Number of scheduled tasks in the queue + */ +APU_DECLARE(apr_size_t) apr_thread_pool_scheduled_tasks_count(apr_thread_pool_t *me); + +/** + * Get the current number of threads + * @param me The thread pool + * @return Total number of threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_threads_count(apr_thread_pool_t *me); + +/** + * Get the current number of busy threads + * @param me The thread pool + * @return Number of busy threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_busy_count(apr_thread_pool_t *me); + +/** + * Get the current number of idle threads + * @param me The thread pool + * @return Number of idle threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_idle_count(apr_thread_pool_t *me); + +/** + * Access function for the maximum number of idle threads. Number of current + * idle threads will be reduced to the new limit. + * @param me The thread pool + * @param cnt The number + * @return The number of threads that were stopped. + */ +APU_DECLARE(apr_size_t) apr_thread_pool_idle_max_set(apr_thread_pool_t *me, + apr_size_t cnt); + +/** + * Get number of tasks that have run + * @param me The thread pool + * @return Number of tasks that have run + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_tasks_run_count(apr_thread_pool_t * me); + +/** + * Get high water mark of the number of tasks waiting to run + * @param me The thread pool + * @return High water mark of tasks waiting to run + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_tasks_high_count(apr_thread_pool_t * me); + +/** + * Get high water mark of the number of threads + * @param me The thread pool + * @return High water mark of threads in thread pool + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_threads_high_count(apr_thread_pool_t * me); + +/** + * Get the number of idle threads that were destroyed after timing out + * @param me The thread pool + * @return Number of idle threads that timed out + */ +APU_DECLARE(apr_size_t) + apr_thread_pool_threads_idle_timeout_count(apr_thread_pool_t * me); + +/** + * Access function for the maximum number of idle threads + * @param me The thread pool + * @return The current maximum number + */ +APU_DECLARE(apr_size_t) apr_thread_pool_idle_max_get(apr_thread_pool_t *me); + +/** + * Access function for the maximum number of threads. + * @param me The thread pool + * @param cnt Number of threads + * @return The original maximum number of threads + */ +APU_DECLARE(apr_size_t) apr_thread_pool_thread_max_set(apr_thread_pool_t *me, + apr_size_t cnt); + +/** + * Access function for the maximum wait time (in microseconds) of an + * idling thread that exceeds the maximum number of idling threads. + * A non-zero value allows for the reaping of idling threads to shrink + * over time. Which helps reduce thrashing. + * @param me The thread pool + * @param timeout The number of microseconds an idle thread should wait + * till it reaps itself + * @return The original maximum wait time + */ +APU_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_set(apr_thread_pool_t * me, + apr_interval_time_t timeout); + +/** + * Access function for the maximum wait time (in microseconds) of an + * idling thread that exceeds the maximum number of idling threads + * @param me The thread pool + * @return The current maximum wait time + */ +APU_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_get(apr_thread_pool_t * me); + +/** + * Access function for the maximum number of threads + * @param me The thread pool + * @return The current maximum number + */ +APU_DECLARE(apr_size_t) apr_thread_pool_thread_max_get(apr_thread_pool_t *me); + +/** + * Access function for the threshold of tasks in queue to trigger a new thread. + * @param me The thread pool + * @param cnt The new threshold + * @return The original threshold + */ +APU_DECLARE(apr_size_t) apr_thread_pool_threshold_set(apr_thread_pool_t *me, + apr_size_t val); + +/** + * Access function for the threshold of tasks in queue to trigger a new thread. + * @param me The thread pool + * @return The current threshold + */ +APU_DECLARE(apr_size_t) apr_thread_pool_threshold_get(apr_thread_pool_t * me); + +/** + * Get owner of the task currently been executed by the thread. + * @param thd The thread is executing a task + * @param owner Pointer to receive owner of the task. + * @return APR_SUCCESS if the owner is retrieved successfully + */ +APU_DECLARE(apr_status_t) apr_thread_pool_task_owner_get(apr_thread_t *thd, + void **owner); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_THREADS */ +#endif /* !APR_THREAD_POOL_H */ diff --git a/include/apr/apr_thread_proc.h b/include/apr/apr_thread_proc.h new file mode 100644 index 0000000..edfcad1 --- /dev/null +++ b/include/apr/apr_thread_proc.h @@ -0,0 +1,798 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_THREAD_PROC_H +#define APR_THREAD_PROC_H + +/** + * @file apr_thread_proc.h + * @brief APR Thread and Process Library + */ + +#include "apr.h" +#include "apr_file_io.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#if APR_HAVE_STRUCT_RLIMIT +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_thread_proc Threads and Process Functions + * @ingroup APR + * @{ + */ + +typedef enum { + APR_SHELLCMD, /**< use the shell to invoke the program */ + APR_PROGRAM, /**< invoke the program directly, no copied env */ + APR_PROGRAM_ENV, /**< invoke the program, replicating our environment */ + APR_PROGRAM_PATH, /**< find program on PATH, use our environment */ + APR_SHELLCMD_ENV /**< use the shell to invoke the program, + * replicating our environment + */ +} apr_cmdtype_e; + +typedef enum { + APR_WAIT, /**< wait for the specified process to finish */ + APR_NOWAIT /**< do not wait -- just see if it has finished */ +} apr_wait_how_e; + +/* I am specifically calling out the values so that the macros below make + * more sense. Yes, I know I don't need to, but I am hoping this makes what + * I am doing more clear. If you want to add more reasons to exit, continue + * to use bitmasks. + */ +typedef enum { + APR_PROC_EXIT = 1, /**< process exited normally */ + APR_PROC_SIGNAL = 2, /**< process exited due to a signal */ + APR_PROC_SIGNAL_CORE = 4 /**< process exited and dumped a core file */ +} apr_exit_why_e; + +/** did we exit the process */ +#define APR_PROC_CHECK_EXIT(x) (x & APR_PROC_EXIT) +/** did we get a signal */ +#define APR_PROC_CHECK_SIGNALED(x) (x & APR_PROC_SIGNAL) +/** did we get core */ +#define APR_PROC_CHECK_CORE_DUMP(x) (x & APR_PROC_SIGNAL_CORE) + +/** @see apr_procattr_io_set */ +#define APR_NO_PIPE 0 + +/** @see apr_procattr_io_set */ +#define APR_FULL_BLOCK 1 +/** @see apr_procattr_io_set */ +#define APR_FULL_NONBLOCK 2 +/** @see apr_procattr_io_set */ +#define APR_PARENT_BLOCK 3 +/** @see apr_procattr_io_set */ +#define APR_CHILD_BLOCK 4 + +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_CPU 0 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_MEM 1 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_NPROC 2 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_NOFILE 3 + +/** + * @defgroup APR_OC Other Child Flags + * @{ + */ +#define APR_OC_REASON_DEATH 0 /**< child has died, caller must call + * unregister still */ +#define APR_OC_REASON_UNWRITABLE 1 /**< write_fd is unwritable */ +#define APR_OC_REASON_RESTART 2 /**< a restart is occuring, perform + * any necessary cleanup (including + * sending a special signal to child) + */ +#define APR_OC_REASON_UNREGISTER 3 /**< unregister has been called, do + * whatever is necessary (including + * kill the child) */ +#define APR_OC_REASON_LOST 4 /**< somehow the child exited without + * us knowing ... buggy os? */ +#define APR_OC_REASON_RUNNING 5 /**< a health check is occuring, + * for most maintainence functions + * this is a no-op. + */ +/** @} */ + +/** The APR process type */ +typedef struct apr_proc_t { + /** The process ID */ + pid_t pid; + /** Parent's side of pipe to child's stdin */ + apr_file_t *in; + /** Parent's side of pipe to child's stdout */ + apr_file_t *out; + /** Parent's side of pipe to child's stdouterr */ + apr_file_t *err; +#if APR_HAS_PROC_INVOKED || defined(DOXYGEN) + /** Diagnositics/debugging string of the command invoked for + * this process [only present if APR_HAS_PROC_INVOKED is true] + * @remark Only enabled on Win32 by default. + * @bug This should either always or never be present in release + * builds - since it breaks binary compatibility. We may enable + * it always in APR 1.0 yet leave it undefined in most cases. + */ + char *invoked; +#endif +#if defined(WIN32) || defined(DOXYGEN) + /** (Win32 only) Creator's handle granting access to the process + * @remark This handle is closed and reset to NULL in every case + * corresponding to a waitpid() on Unix which returns the exit status. + * Therefore Win32 correspond's to Unix's zombie reaping characteristics + * and avoids potential handle leaks. + */ + HANDLE hproc; +#endif +} apr_proc_t; + +/** + * The prototype for APR child errfn functions. (See the description + * of apr_procattr_child_errfn_set() for more information.) + * It is passed the following parameters: + * @param pool Pool associated with the apr_proc_t. If your child + * error function needs user data, associate it with this + * pool. + * @param err APR error code describing the error + * @param description Text description of type of processing which failed + */ +typedef void (apr_child_errfn_t)(apr_pool_t *proc, apr_status_t err, + const char *description); + +/** Opaque Thread structure. */ +typedef struct apr_thread_t apr_thread_t; + +/** Opaque Thread attributes structure. */ +typedef struct apr_threadattr_t apr_threadattr_t; + +/** Opaque Process attributes structure. */ +typedef struct apr_procattr_t apr_procattr_t; + +/** Opaque control variable for one-time atomic variables. */ +typedef struct apr_thread_once_t apr_thread_once_t; + +/** Opaque thread private address space. */ +typedef struct apr_threadkey_t apr_threadkey_t; + +/** Opaque record of child process. */ +typedef struct apr_other_child_rec_t apr_other_child_rec_t; + +/** + * The prototype for any APR thread worker functions. + */ +typedef void *(APR_THREAD_FUNC *apr_thread_start_t)(apr_thread_t*, void*); + +typedef enum { + APR_KILL_NEVER, /**< process is never sent any signals */ + APR_KILL_ALWAYS, /**< process is sent SIGKILL on apr_pool_t cleanup */ + APR_KILL_AFTER_TIMEOUT, /**< SIGTERM, wait 3 seconds, SIGKILL */ + APR_JUST_WAIT, /**< wait forever for the process to complete */ + APR_KILL_ONLY_ONCE /**< send SIGTERM and then wait */ +} apr_kill_conditions_e; + +/* Thread Function definitions */ + +#if APR_HAS_THREADS + +/** + * Create and initialize a new threadattr variable + * @param new_attr The newly created threadattr. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new_attr, + apr_pool_t *cont); + +/** + * Set if newly created threads should be created in detached state. + * @param attr The threadattr to affect + * @param on Non-zero if detached threads should be created. + */ +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, + apr_int32_t on); + +/** + * Get the detach state for this threadattr. + * @param attr The threadattr to reference + * @return APR_DETACH if threads are to be detached, or APR_NOTDETACH + * if threads are to be joinable. + */ +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr); + +/** + * Set the stack size of newly created threads. + * @param attr The threadattr to affect + * @param stacksize The stack size in bytes + */ +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize); + +/** + * Set the stack guard area size of newly created threads. + * @param attr The threadattr to affect + * @param guardsize The stack guard area size in bytes + * @note Thread library implementations commonly use a "guard area" + * after each thread's stack which is not readable or writable such that + * stack overflows cause a segfault; this consumes e.g. 4K of memory + * and increases memory management overhead. Setting the guard area + * size to zero hence trades off reliable behaviour on stack overflow + * for performance. */ +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t guardsize); + +/** + * Create a new thread of execution + * @param new_thread The newly created thread handle. + * @param attr The threadattr to use to determine how to create the thread + * @param func The function to start the new thread in + * @param data Any data to be passed to the starting function + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new_thread, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, apr_pool_t *cont); + +/** + * stop the current thread + * @param thd The thread to stop + * @param retval The return value to pass back to any thread that cares + */ +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, + apr_status_t retval); + +/** + * block until the desired thread stops executing. + * @param retval The return value from the dead thread. + * @param thd The thread to join + */ +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, + apr_thread_t *thd); + +/** + * force the current thread to yield the processor + */ +APR_DECLARE(void) apr_thread_yield(void); + +/** + * Initialize the control variable for apr_thread_once. If this isn't + * called, apr_initialize won't work. + * @param control The control variable to initialize + * @param p The pool to allocate data from. + */ +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p); + +/** + * Run the specified function one time, regardless of how many threads + * call it. + * @param control The control variable. The same variable should + * be passed in each time the function is tried to be + * called. This is how the underlying functions determine + * if the function has ever been called before. + * @param func The function to call. + */ +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)); + +/** + * detach a thread + * @param thd The thread to detach + */ +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd); + +/** + * Return the pool associated with the current thread. + * @param data The user data associated with the thread. + * @param key The key to associate with the data + * @param thread The currently open thread. + */ +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, + apr_thread_t *thread); + +/** + * Return the pool associated with the current thread. + * @param data The user data to associate with the thread. + * @param key The key to use for associating the data with the thread + * @param cleanup The cleanup routine to use when the thread is destroyed. + * @param thread The currently open thread. + */ +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread); + +/** + * Create and initialize a new thread private address space + * @param key The thread private handle. + * @param dest The destructor to use when freeing the private memory. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), + apr_pool_t *cont); + +/** + * Get a pointer to the thread private memory + * @param new_mem The data stored in private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new_mem, + apr_threadkey_t *key); + +/** + * Set the data to be stored in thread private memory + * @param priv The data to be stored in private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, + apr_threadkey_t *key); + +/** + * Free the thread private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key); + +/** + * Return the pool associated with the current threadkey. + * @param data The user data associated with the threadkey. + * @param key The key associated with the data + * @param threadkey The currently open threadkey. + */ +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey); + +/** + * Return the pool associated with the current threadkey. + * @param data The data to set. + * @param key The key to associate with the data. + * @param cleanup The cleanup routine to use when the file is destroyed. + * @param threadkey The currently open threadkey. + */ +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_threadkey_t *threadkey); + +#endif + +/** + * Create and initialize a new procattr variable + * @param new_attr The newly created procattr. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new_attr, + apr_pool_t *cont); + +/** + * Determine if any of stdin, stdout, or stderr should be linked to pipes + * when starting a child process. + * @param attr The procattr we care about. + * @param in Should stdin be a pipe back to the parent? + * @param out Should stdout be a pipe back to the parent? + * @param err Should stderr be a pipe back to the parent? + */ +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, apr_int32_t out, + apr_int32_t err); + +/** + * Set the child_in and/or parent_in values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_in apr_file_t value to use as child_in. Must be a valid file. + * @param parent_in apr_file_t value to use as parent_in. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. You can save some + * extra function calls by not creating your own pipe since this + * creates one in the process space for you. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(struct apr_procattr_t *attr, + apr_file_t *child_in, + apr_file_t *parent_in); + +/** + * Set the child_out and parent_out values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_out apr_file_t value to use as child_out. Must be a valid file. + * @param parent_out apr_file_t value to use as parent_out. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(struct apr_procattr_t *attr, + apr_file_t *child_out, + apr_file_t *parent_out); + +/** + * Set the child_err and parent_err values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_err apr_file_t value to use as child_err. Must be a valid file. + * @param parent_err apr_file_t value to use as parent_err. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(struct apr_procattr_t *attr, + apr_file_t *child_err, + apr_file_t *parent_err); + +/** + * Set which directory the child process should start executing in. + * @param attr The procattr we care about. + * @param dir Which dir to start in. By default, this is the same dir as + * the parent currently resides in, when the createprocess call + * is made. + */ +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir); + +/** + * Set what type of command the child process will call. + * @param attr The procattr we care about. + * @param cmd The type of command. One of: + *
+ *            APR_SHELLCMD     --  Anything that the shell can handle
+ *            APR_PROGRAM      --  Executable program   (default) 
+ *            APR_PROGRAM_ENV  --  Executable program, copy environment
+ *            APR_PROGRAM_PATH --  Executable program on PATH, copy env
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd); + +/** + * Determine if the child should start in detached state. + * @param attr The procattr we care about. + * @param detach Should the child start in detached state? Default is no. + */ +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + apr_int32_t detach); + +#if APR_HAVE_STRUCT_RLIMIT +/** + * Set the Resource Utilization limits when starting a new process. + * @param attr The procattr we care about. + * @param what Which limit to set, one of: + *
+ *                 APR_LIMIT_CPU
+ *                 APR_LIMIT_MEM
+ *                 APR_LIMIT_NPROC
+ *                 APR_LIMIT_NOFILE
+ * 
+ * @param limit Value to set the limit to. + */ +APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, + apr_int32_t what, + struct rlimit *limit); +#endif + +/** + * Specify an error function to be called in the child process if APR + * encounters an error in the child prior to running the specified program. + * @param attr The procattr describing the child process to be created. + * @param errfn The function to call in the child process. + * @remark At the present time, it will only be called from apr_proc_create() + * on platforms where fork() is used. It will never be called on other + * platforms, on those platforms apr_proc_create() will return the error + * in the parent process rather than invoke the callback in the now-forked + * child process. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn); + +/** + * Specify that apr_proc_create() should do whatever it can to report + * failures to the caller of apr_proc_create(), rather than find out in + * the child. + * @param attr The procattr describing the child process to be created. + * @param chk Flag to indicate whether or not extra work should be done + * to try to report failures to the caller. + * @remark This flag only affects apr_proc_create() on platforms where + * fork() is used. This leads to extra overhead in the calling + * process, but that may help the application handle such + * errors more gracefully. + */ +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk); + +/** + * Determine if the child should start in its own address space or using the + * current one from its parent + * @param attr The procattr we care about. + * @param addrspace Should the child start in its own address space? Default + * is no on NetWare and yes on other platforms. + */ +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace); + +/** + * Set the username used for running process + * @param attr The procattr we care about. + * @param username The username used + * @param password User password if needed. Password is needed on WIN32 + * or any other platform having + * APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set. + */ +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password); + +/** + * Set the group used for running process + * @param attr The procattr we care about. + * @param groupname The group name used + */ +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname); + + +#if APR_HAS_FORK +/** + * This is currently the only non-portable call in APR. This executes + * a standard unix fork. + * @param proc The resulting process handle. + * @param cont The pool to use. + * @remark returns APR_INCHILD for the child, and APR_INPARENT for the parent + * or an error. + */ +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *cont); +#endif + +/** + * Create a new process and execute a new program within that process. + * @param new_proc The resulting process handle. + * @param progname The program to run + * @param args the arguments to pass to the new program. The first + * one should be the program name. + * @param env The new environment table for the new process. This + * should be a list of NULL-terminated strings. This argument + * is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and + * APR_SHELLCMD_ENV types of commands. + * @param attr the procattr we should use to determine how to create the new + * process + * @param pool The pool to use. + * @note This function returns without waiting for the new process to terminate; + * use apr_proc_wait for that. + */ +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new_proc, + const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool); + +/** + * Wait for a child process to die + * @param proc The process handle that corresponds to the desired child process + * @param exitcode The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * @param exitwhy Why the child died, the bitwise or of: + *
+ *            APR_PROC_EXIT         -- process terminated normally
+ *            APR_PROC_SIGNAL       -- process was killed by a signal
+ *            APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
+ *                                     generated a core dump.
+ * 
+ * @param waithow How should we wait. One of: + *
+ *            APR_WAIT   -- block until the child process dies.
+ *            APR_NOWAIT -- return immediately regardless of if the 
+ *                          child is dead or not.
+ * 
+ * @remark The childs status is in the return code to this process. It is one of: + *
+ *            APR_CHILD_DONE     -- child is no longer running.
+ *            APR_CHILD_NOTDONE  -- child is still running.
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow); + +/** + * Wait for any current child process to die and return information + * about that child. + * @param proc Pointer to NULL on entry, will be filled out with child's + * information + * @param exitcode The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * @param exitwhy Why the child died, the bitwise or of: + *
+ *            APR_PROC_EXIT         -- process terminated normally
+ *            APR_PROC_SIGNAL       -- process was killed by a signal
+ *            APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
+ *                                     generated a core dump.
+ * 
+ * @param waithow How should we wait. One of: + *
+ *            APR_WAIT   -- block until the child process dies.
+ *            APR_NOWAIT -- return immediately regardless of if the 
+ *                          child is dead or not.
+ * 
+ * @param p Pool to allocate child information out of. + * @bug Passing proc as a *proc rather than **proc was an odd choice + * for some platforms... this should be revisited in 1.0 + */ +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p); + +#define APR_PROC_DETACH_FOREGROUND 0 /**< Do not detach */ +#define APR_PROC_DETACH_DAEMONIZE 1 /**< Detach */ + +/** + * Detach the process from the controlling terminal. + * @param daemonize set to non-zero if the process should daemonize + * and become a background process, else it will + * stay in the foreground. + */ +APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize); + +/** + * Register an other_child -- a child associated to its registered + * maintence callback. This callback is invoked when the process + * dies, is disconnected or disappears. + * @param proc The child process to register. + * @param maintenance maintenance is a function that is invoked with a + * reason and the data pointer passed here. + * @param data Opaque context data passed to the maintenance function. + * @param write_fd An fd that is probed for writing. If it is ever unwritable + * then the maintenance is invoked with reason + * OC_REASON_UNWRITABLE. + * @param p The pool to use for allocating memory. + * @bug write_fd duplicates the proc->out stream, it's really redundant + * and should be replaced in the APR 1.0 API with a bitflag of which + * proc->in/out/err handles should be health checked. + * @bug no platform currently tests the pipes health. + */ +APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc, + void (*maintenance) (int reason, + void *, + int status), + void *data, apr_file_t *write_fd, + apr_pool_t *p); + +/** + * Stop watching the specified other child. + * @param data The data to pass to the maintenance function. This is + * used to find the process to unregister. + * @warning Since this can be called by a maintenance function while we're + * scanning the other_children list, all scanners should protect + * themself by loading ocr->next before calling any maintenance + * function. + */ +APR_DECLARE(void) apr_proc_other_child_unregister(void *data); + +/** + * Notify the maintenance callback of a registered other child process + * that application has detected an event, such as death. + * @param proc The process to check + * @param reason The reason code to pass to the maintenance function + * @param status The status to pass to the maintenance function + * @remark An example of code using this behavior; + *
+ * rv = apr_proc_wait_all_procs(&proc, &exitcode, &status, APR_WAIT, p);
+ * if (APR_STATUS_IS_CHILD_DONE(rv)) {
+ * #if APR_HAS_OTHER_CHILD
+ *     if (apr_proc_other_child_alert(&proc, APR_OC_REASON_DEATH, status)
+ *             == APR_SUCCESS) {
+ *         ;  (already handled)
+ *     }
+ *     else
+ * #endif
+ *         [... handling non-otherchild processes death ...]
+ * 
+ */ +APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, + int reason, + int status); + +/** + * Test one specific other child processes and invoke the maintenance callback + * with the appropriate reason code, if still running, or the appropriate reason + * code if the process is no longer healthy. + * @param ocr The registered other child + * @param reason The reason code (e.g. APR_OC_REASON_RESTART) if still running + */ +APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, + int reason); + +/** + * Test all registered other child processes and invoke the maintenance callback + * with the appropriate reason code, if still running, or the appropriate reason + * code if the process is no longer healthy. + * @param reason The reason code (e.g. APR_OC_REASON_RESTART) to running processes + */ +APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason); + +/** + * Terminate a process. + * @param proc The process to terminate. + * @param sig How to kill the process. + */ +APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int sig); + +/** + * Register a process to be killed when a pool dies. + * @param a The pool to use to define the processes lifetime + * @param proc The process to register + * @param how How to kill the process, one of: + *
+ *         APR_KILL_NEVER         -- process is never sent any signals
+ *         APR_KILL_ALWAYS        -- process is sent SIGKILL on apr_pool_t cleanup
+ *         APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL
+ *         APR_JUST_WAIT          -- wait forever for the process to complete
+ *         APR_KILL_ONLY_ONCE     -- send SIGTERM and then wait
+ * 
+ */ +APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *a, apr_proc_t *proc, + apr_kill_conditions_e how); + +#if APR_HAS_THREADS + +#if (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) && !defined(OS2) + +/** + * Setup the process for a single thread to be used for all signal handling. + * @warning This must be called before any threads are created + */ +APR_DECLARE(apr_status_t) apr_setup_signal_thread(void); + +/** + * Make the current thread listen for signals. This thread will loop + * forever, calling a provided function whenever it receives a signal. That + * functions should return 1 if the signal has been handled, 0 otherwise. + * @param signal_handler The function to call when a signal is received + * apr_status_t apr_signal_thread((int)(*signal_handler)(int signum)) + */ +APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)); + +#endif /* (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) && !defined(OS2) */ + +/** + * Get the child-pool used by the thread from the thread info. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_PROC_H */ + diff --git a/include/apr/apr_thread_rwlock.h b/include/apr/apr_thread_rwlock.h new file mode 100644 index 0000000..b7a3928 --- /dev/null +++ b/include/apr/apr_thread_rwlock.h @@ -0,0 +1,180 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_THREAD_RWLOCK_H +#define APR_THREAD_RWLOCK_H + +/** + * @file apr_thread_rwlock.h + * @brief APR Reader/Writer Lock Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS + +/** + * @defgroup apr_thread_rwlock Reader/Writer Lock Routines + * @ingroup APR + * @{ + */ + +/** Opaque read-write thread-safe lock. */ +typedef struct apr_thread_rwlock_t apr_thread_rwlock_t; + +/** + * Note: The following operations have undefined results: unlocking a + * read-write lock which is not locked in the calling thread; write + * locking a read-write lock which is already locked by the calling + * thread; destroying a read-write lock more than once; clearing or + * destroying the pool from which a locked read-write lock is + * allocated. + */ + +/** + * Create and initialize a read-write lock that can be used to synchronize + * threads. + * @param rwlock the memory address where the newly created readwrite lock + * will be stored. + * @param pool the pool from which to allocate the mutex. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool); +/** + * Acquire a shared-read lock on the given read-write lock. This will allow + * multiple threads to enter the same critical section while they have acquired + * the read lock. + * @param rwlock the read-write lock on which to acquire the shared read. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock); + +/** + * Attempt to acquire the shared-read lock on the given read-write lock. This + * is the same as apr_thread_rwlock_rdlock(), only that the function fails + * if there is another thread holding the write lock, or if there are any + * write threads blocking on the lock. If the function fails for this case, + * APR_EBUSY will be returned. Note: it is important that the + * APR_STATUS_IS_EBUSY(s) macro be used to determine if the return value was + * APR_EBUSY, for portability reasons. + * @param rwlock the rwlock on which to attempt the shared read. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock); + +/** + * Acquire an exclusive-write lock on the given read-write lock. This will + * allow only one single thread to enter the critical sections. If there + * are any threads currently holding the read-lock, this thread is put to + * sleep until it can have exclusive access to the lock. + * @param rwlock the read-write lock on which to acquire the exclusive write. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock); + +/** + * Attempt to acquire the exclusive-write lock on the given read-write lock. + * This is the same as apr_thread_rwlock_wrlock(), only that the function fails + * if there is any other thread holding the lock (for reading or writing), + * in which case the function will return APR_EBUSY. Note: it is important + * that the APR_STATUS_IS_EBUSY(s) macro be used to determine if the return + * value was APR_EBUSY, for portability reasons. + * @param rwlock the rwlock on which to attempt the exclusive write. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock); + +/** + * Release either the read or write lock currently held by the calling thread + * associated with the given read-write lock. + * @param rwlock the read-write lock to be released (unlocked). + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock); + +/** + * Destroy the read-write lock and free the associated memory. + * @param rwlock the rwlock to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock); + +/** + * Get the pool used by this thread_rwlock. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_rwlock); + +#endif /* APR_HAS_THREADS */ + +/** Notify event data, events count less than 32. */ +typedef apr_uint32_t apr_event_t; + +/** System default notify event */ +#define DRVS_MSG_BADHANDLE 0x40000000 /**< Driver handle error */ +#define DRVS_MSG_TIMEOUT 0x80000000 /**< Driver accept event timeout */ + +/** + * Opaque thread-safe notify events group. Only apply in multi producer and single + * customer pattern. + */ +typedef struct apr_thread_event_t apr_thread_event_t; + +/** + * Create and initialize a thread event that can be used to synchronize + * threads. + * @param ev the memory address where the newly created thread event + * will be stored. + * @param pool the pool from which to allocate the thread event. + */ +APR_DECLARE(apr_status_t) apr_thread_event_create(apr_thread_event_t **ev, + apr_pool_t *pool); + +/** + * Destroy the thread event and free the associated memory. + * @param ev the thread event to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_event_destroy(apr_thread_event_t *ev); + +/** + * Put the active calling thread to sleep until thread event to wake up or + * the timeout is reached. Each event variable must be associated with event + * mask. + * @param ev the thread event variable on which to block. + * @param mask the thread events mask that can be singled in this function, + * @param timeout The amount of time in microseconds to wait. This is a maximum, + * not a minimum. If the event is signaled, we will wake up before this + * time, otherwise the error DRVS_MSG_TIMEOUT is returned. + */ +APR_DECLARE(apr_event_t) apr_thread_event_read(apr_thread_event_t *ev, + apr_event_t mask, + apr_uint32_t timeout); + +/** + * Notify the thread which is blocking on the thread events. + * That thread is then scheduled to wake up. + * @param ev the thread event handle on which to produce the events. + */ +APR_DECLARE(apr_status_t) apr_thread_event_write(apr_thread_event_t *ev, + apr_event_t event); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_RWLOCK_H */ diff --git a/include/apr/apr_time.h b/include/apr/apr_time.h new file mode 100644 index 0000000..1882b28 --- /dev/null +++ b/include/apr/apr_time.h @@ -0,0 +1,232 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_TIME_H +#define APR_TIME_H + +/** + * @file apr_time.h + * @brief APR Time Library + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_time Time Routines + * @ingroup APR + * @{ + */ + +/** month names */ +APR_DECLARE_DATA extern const char apr_month_snames[12][4]; +/** day names */ +APR_DECLARE_DATA extern const char apr_day_snames[7][4]; + + +/** number of microseconds since 00:00:00 january 1, 1970 UTC */ +typedef apr_int64_t apr_time_t; + + +/** mechanism to properly type apr_time_t literals */ +#define APR_TIME_C(val) APR_INT64_C(val) + +/** mechanism to properly print apr_time_t values */ +#define APR_TIME_T_FMT APR_INT64_T_FMT + +/** intervals for I/O timeouts, in microseconds */ +typedef apr_int64_t apr_interval_time_t; +/** short interval for I/O timeouts, in microseconds */ +typedef apr_int32_t apr_short_interval_time_t; + +/** number of microseconds per second */ +#define APR_USEC_PER_SEC APR_TIME_C(1000000) + +/** @return apr_time_t as a second */ +#define apr_time_sec(time) ((time) / APR_USEC_PER_SEC) + +/** @return apr_time_t as a usec */ +#define apr_time_usec(time) ((time) % APR_USEC_PER_SEC) + +/** @return apr_time_t as a msec */ +#define apr_time_msec(time) (((time) / 1000) % 1000) + +/** @return apr_time_t as a msec */ +#define apr_time_as_msec(time) ((time) / 1000) + +/** @return a second as an apr_time_t */ +#define apr_time_from_sec(sec) ((apr_time_t)(sec) * APR_USEC_PER_SEC) + +/** @return a second and usec combination as an apr_time_t */ +#define apr_time_make(sec, usec) ((apr_time_t)(sec) * APR_USEC_PER_SEC \ + + (apr_time_t)(usec)) + +/** + * @return the current time + */ +APR_DECLARE(apr_time_t) apr_time_now(void); + +/** @see apr_time_exp_t */ +typedef struct apr_time_exp_t apr_time_exp_t; + +/** + * a structure similar to ANSI struct tm with the following differences: + * - tm_usec isn't an ANSI field + * - tm_gmtoff isn't an ANSI field (it's a bsdism) + */ +struct apr_time_exp_t { + /** microseconds past tm_sec */ + apr_int32_t tm_usec; + /** (0-61) seconds past tm_min */ + apr_int32_t tm_sec; + /** (0-59) minutes past tm_hour */ + apr_int32_t tm_min; + /** (0-23) hours past midnight */ + apr_int32_t tm_hour; + /** (1-31) day of the month */ + apr_int32_t tm_mday; + /** (0-11) month of the year */ + apr_int32_t tm_mon; + /** year since 1900 */ + apr_int32_t tm_year; + /** (0-6) days since sunday */ + apr_int32_t tm_wday; + /** (0-365) days since jan 1 */ + apr_int32_t tm_yday; + /** daylight saving time */ + apr_int32_t tm_isdst; + /** seconds east of UTC */ + apr_int32_t tm_gmtoff; +}; + +/** + * convert an ansi time_t to an apr_time_t + * @param result the resulting apr_time_t + * @param input the time_t to convert + */ +APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, + time_t input); + +/** + * convert a time to its human readable components using an offset + * from GMT + * @param result the exploded time + * @param input the time to explode + * @param offs the number of seconds offset to apply + */ +APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, + apr_time_t input, + apr_int32_t offs); + +/** + * convert a time to its human readable components in GMT timezone + * @param result the exploded time + * @param input the time to explode + */ +APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, + apr_time_t input); + +/** + * convert a time to its human readable components in local timezone + * @param result the exploded time + * @param input the time to explode + */ +APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, + apr_time_t input); + +/** + * Convert time value from human readable format to a numeric apr_time_t + * e.g. elapsed usec since epoch + * @param result the resulting imploded time + * @param input the input exploded time + */ +APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *result, + apr_time_exp_t *input); + +/** + * Convert time value from human readable format to a numeric apr_time_t that + * always represents GMT + * @param result the resulting imploded time + * @param input the input exploded time + */ +APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *result, + apr_time_exp_t *input); + +/** + * Sleep for the specified number of micro-seconds. + * @param t desired amount of time to sleep. + * @warning May sleep for longer than the specified time. + */ +APR_DECLARE(void) apr_sleep(apr_interval_time_t t); + +/** length of a RFC822 Date */ +#define APR_RFC822_DATE_LEN (30) +/** + * apr_rfc822_date formats dates in the RFC822 + * format in an efficient manner. It is a fixed length + * format which requires the indicated amount of storage, + * including the trailing NUL terminator. + * @param date_str String to write to. + * @param t the time to convert + */ +APR_DECLARE(apr_status_t) apr_rfc822_date(char *date_str, apr_time_t t); + +/** length of a CTIME date */ +#define APR_CTIME_LEN (25) +/** + * apr_ctime formats dates in the ctime() format + * in an efficient manner. it is a fixed length format + * and requires the indicated amount of storage including + * the trailing NUL terminator. + * Unlike ANSI/ISO C ctime(), apr_ctime() does not include + * a \n at the end of the string. + * @param date_str String to write to. + * @param t the time to convert + */ +APR_DECLARE(apr_status_t) apr_ctime(char *date_str, apr_time_t t); + +/** + * formats the exploded time according to the format specified + * @param s string to write to + * @param retsize The length of the returned string + * @param max The maximum length of the string + * @param format The format for the time string + * @param tm The time to convert + */ +APR_DECLARE(apr_status_t) apr_strftime(char *s, apr_size_t *retsize, + apr_size_t max, const char *format, + apr_time_exp_t *tm); + +/** + * Improve the clock resolution for the lifetime of the given pool. + * Generally this is only desireable on benchmarking and other very + * time-sensitive applications, and has no impact on most platforms. + * @param p The pool to associate the finer clock resolution + */ +APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_TIME_H */ diff --git a/include/apr/apr_uri.h b/include/apr/apr_uri.h new file mode 100644 index 0000000..82a86b2 --- /dev/null +++ b/include/apr/apr_uri.h @@ -0,0 +1,178 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * apr_uri.h: External Interface of apr_uri.c + */ + +/** + * @file apr_uri.h + * @brief APR-UTIL URI Routines + */ + +#ifndef APR_URI_H +#define APR_URI_H + +#include "apu.h" + +#include "apr_network_io.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_URI URI + * @ingroup APR_Util + * @{ + */ + +#define APR_URI_FTP_DEFAULT_PORT 21 /**< default FTP port */ +#define APR_URI_SSH_DEFAULT_PORT 22 /**< default SSH port */ +#define APR_URI_TELNET_DEFAULT_PORT 23 /**< default telnet port */ +#define APR_URI_GOPHER_DEFAULT_PORT 70 /**< default Gopher port */ +#define APR_URI_HTTP_DEFAULT_PORT 80 /**< default HTTP port */ +#define APR_URI_POP_DEFAULT_PORT 110 /**< default POP port */ +#define APR_URI_NNTP_DEFAULT_PORT 119 /**< default NNTP port */ +#define APR_URI_IMAP_DEFAULT_PORT 143 /**< default IMAP port */ +#define APR_URI_PROSPERO_DEFAULT_PORT 191 /**< default Prospero port */ +#define APR_URI_WAIS_DEFAULT_PORT 210 /**< default WAIS port */ +#define APR_URI_LDAP_DEFAULT_PORT 389 /**< default LDAP port */ +#define APR_URI_HTTPS_DEFAULT_PORT 443 /**< default HTTPS port */ +#define APR_URI_RTSP_DEFAULT_PORT 554 /**< default RTSP port */ +#define APR_URI_SNEWS_DEFAULT_PORT 563 /**< default SNEWS port */ +#define APR_URI_ACAP_DEFAULT_PORT 674 /**< default ACAP port */ +#define APR_URI_NFS_DEFAULT_PORT 2049 /**< default NFS port */ +#define APR_URI_TIP_DEFAULT_PORT 3372 /**< default TIP port */ +#define APR_URI_SIP_DEFAULT_PORT 5060 /**< default SIP port */ + +/** Flags passed to unparse_uri_components(): */ +/** suppress "scheme://user\@site:port" */ +#define APR_URI_UNP_OMITSITEPART (1U<<0) +/** Just omit user */ +#define APR_URI_UNP_OMITUSER (1U<<1) +/** Just omit password */ +#define APR_URI_UNP_OMITPASSWORD (1U<<2) +/** omit "user:password\@" part */ +#define APR_URI_UNP_OMITUSERINFO (APR_URI_UNP_OMITUSER | \ + APR_URI_UNP_OMITPASSWORD) +/** Show plain text password (default: show XXXXXXXX) */ +#define APR_URI_UNP_REVEALPASSWORD (1U<<3) +/** Show "scheme://user\@site:port" only */ +#define APR_URI_UNP_OMITPATHINFO (1U<<4) +/** Omit the "?queryarg" from the path */ +#define APR_URI_UNP_OMITQUERY (1U<<5) + +/** @see apr_uri_t */ +typedef struct apr_uri_t apr_uri_t; + +/** + * A structure to encompass all of the fields in a uri + */ +struct apr_uri_t { + /** scheme ("http"/"ftp"/...) */ + char *scheme; + /** combined [user[:password]\@]host[:port] */ + char *hostinfo; + /** user name, as in http://user:passwd\@host:port/ */ + char *user; + /** password, as in http://user:passwd\@host:port/ */ + char *password; + /** hostname from URI (or from Host: header) */ + char *hostname; + /** port string (integer representation is in "port") */ + char *port_str; + /** the request path (or "/" if only scheme://host was given) */ + char *path; + /** Everything after a '?' in the path, if present */ + char *query; + /** Trailing "#fragment" string, if present */ + char *fragment; + + /** structure returned from gethostbyname() */ + struct hostent *hostent; + + /** The port number, numeric, valid only if port_str != NULL */ + apr_port_t port; + + /** has the structure been initialized */ + unsigned is_initialized:1; + + /** has the DNS been looked up yet */ + unsigned dns_looked_up:1; + /** has the dns been resolved yet */ + unsigned dns_resolved:1; +}; + +/* apr_uri.c */ +/** + * Return the default port for a given scheme. The schemes recognized are + * http, ftp, https, gopher, wais, nntp, snews, and prospero + * @param scheme_str The string that contains the current scheme + * @return The default port for this scheme + */ +APU_DECLARE(apr_port_t) apr_uri_port_of_scheme(const char *scheme_str); + +/** + * Unparse a apr_uri_t structure to an URI string. Optionally + * suppress the password for security reasons. + * @param p The pool to allocate out of + * @param uptr All of the parts of the uri + * @param flags How to unparse the uri. One of: + *
+ *    APR_URI_UNP_OMITSITEPART        Suppress "scheme://user\@site:port" 
+ *    APR_URI_UNP_OMITUSER            Just omit user 
+ *    APR_URI_UNP_OMITPASSWORD        Just omit password 
+ *    APR_URI_UNP_OMITUSERINFO        Omit "user:password\@" part
+ *    APR_URI_UNP_REVEALPASSWORD      Show plain text password (default: show XXXXXXXX)
+ *    APR_URI_UNP_OMITPATHINFO        Show "scheme://user\@site:port" only 
+ *    APR_URI_UNP_OMITQUERY           Omit "?queryarg" or "#fragment" 
+ * 
+ * @return The uri as a string + */ +APU_DECLARE(char *) apr_uri_unparse(apr_pool_t *p, + const apr_uri_t *uptr, + unsigned flags); + +/** + * Parse a given URI, fill in all supplied fields of a apr_uri_t + * structure. This eliminates the necessity of extracting host, port, + * path, query info repeatedly in the modules. + * @param p The pool to allocate out of + * @param uri The uri to parse + * @param uptr The apr_uri_t to fill out + * @return APR_SUCCESS for success or error code + */ +APU_DECLARE(apr_status_t) apr_uri_parse(apr_pool_t *p, const char *uri, + apr_uri_t *uptr); + +/** + * Special case for CONNECT parsing: it comes with the hostinfo part only + * @param p The pool to allocate out of + * @param hostinfo The hostinfo string to parse + * @param uptr The apr_uri_t to fill out + * @return APR_SUCCESS for success or error code + */ +APU_DECLARE(apr_status_t) apr_uri_parse_hostinfo(apr_pool_t *p, + const char *hostinfo, + apr_uri_t *uptr); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_URI_H */ diff --git a/include/apr/apr_user.h b/include/apr/apr_user.h new file mode 100644 index 0000000..2529b79 --- /dev/null +++ b/include/apr/apr_user.h @@ -0,0 +1,158 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_USER_H +#define APR_USER_H + +/** + * @file apr_user.h + * @brief APR User ID Services + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_user User and Group ID Services + * @ingroup APR + * @{ + */ + +/** + * Structure for determining user ownership. + */ +#ifdef WIN32 +typedef PSID apr_uid_t; +#else +typedef uid_t apr_uid_t; +#endif + +/** + * Structure for determining group ownership. + */ +#ifdef WIN32 +typedef PSID apr_gid_t; +#else +typedef gid_t apr_gid_t; +#endif + +#if APR_HAS_USER + +/** + * Get the userid (and groupid) of the calling process + * @param userid Returns the user id + * @param groupid Returns the user's group id + * @param p The pool from which to allocate working space + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *userid, + apr_gid_t *groupid, + apr_pool_t *p); + +/** + * Get the user name for a specified userid + * @param username Pointer to new string containing user name (on output) + * @param userid The userid + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + apr_pool_t *p); + +/** + * Get the userid (and groupid) for the specified username + * @param userid Returns the user id + * @param groupid Returns the user's group id + * @param username The username to lookup + * @param p The pool from which to allocate working space + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *userid, apr_gid_t *groupid, + const char *username, apr_pool_t *p); + +/** + * Get the home directory for the named user + * @param dirname Pointer to new string containing directory name (on output) + * @param username The named user + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + const char *username, + apr_pool_t *p); + +/** + * Compare two user identifiers for equality. + * @param left One uid to test + * @param right Another uid to test + * @return APR_SUCCESS if the apr_uid_t strutures identify the same user, + * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid. + * @remark This function is available only if APR_HAS_USER is defined. + */ +#if defined(WIN32) +APR_DECLARE(apr_status_t) apr_uid_compare(apr_uid_t left, apr_uid_t right); +#else +#define apr_uid_compare(left,right) (((left) == (right)) ? APR_SUCCESS : APR_EMISMATCH) +#endif + +/** + * Get the group name for a specified groupid + * @param groupname Pointer to new string containing group name (on output) + * @param groupid The groupid + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, + apr_gid_t groupid, apr_pool_t *p); + +/** + * Get the groupid for a specified group name + * @param groupid Pointer to the group id (on output) + * @param groupname The group name to look up + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *groupid, + const char *groupname, apr_pool_t *p); + +/** + * Compare two group identifiers for equality. + * @param left One gid to test + * @param right Another gid to test + * @return APR_SUCCESS if the apr_gid_t strutures identify the same group, + * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid. + * @remark This function is available only if APR_HAS_USER is defined. + */ +#if defined(WIN32) +APR_DECLARE(apr_status_t) apr_gid_compare(apr_gid_t left, apr_gid_t right); +#else +#define apr_gid_compare(left,right) (((left) == (right)) ? APR_SUCCESS : APR_EMISMATCH) +#endif + +#endif /* ! APR_HAS_USER */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_USER_H */ diff --git a/include/apr/apr_uuid.h b/include/apr/apr_uuid.h new file mode 100644 index 0000000..820d740 --- /dev/null +++ b/include/apr/apr_uuid.h @@ -0,0 +1,76 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/** + * @file apr_uuid.h + * @brief APR UUID library + */ +#ifndef APR_UUID_H +#define APR_UUID_H + +#include "apu.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_UUID UUID Handling + * @ingroup APR + * @{ + */ + +/** + * we represent a UUID as a block of 16 bytes. + */ + +typedef struct { + unsigned char data[16]; /**< the actual UUID */ +} apr_uuid_t; + +/** UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF */ +#define APR_UUID_FORMATTED_LENGTH 36 + + +/** + * Generate and return a (new) UUID + * @param uuid The resulting UUID + */ +APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid); + +/** + * Format a UUID into a string, following the standard format + * @param buffer The buffer to place the formatted UUID string into. It must + * be at least APR_UUID_FORMATTED_LENGTH + 1 bytes long to hold + * the formatted UUID and a null terminator + * @param uuid The UUID to format + */ +APU_DECLARE(void) apr_uuid_format(char *buffer, const apr_uuid_t *uuid); + +/** + * Parse a standard-format string into a UUID + * @param uuid The resulting UUID + * @param uuid_str The formatted UUID + */ +APU_DECLARE(apr_status_t) apr_uuid_parse(apr_uuid_t *uuid, const char *uuid_str); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_UUID_H */ diff --git a/include/apr/apr_version.h b/include/apr/apr_version.h new file mode 100644 index 0000000..81e1dbc --- /dev/null +++ b/include/apr/apr_version.h @@ -0,0 +1,143 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_VERSION_H +#define APR_VERSION_H + +/** + * @file apr_version.h + * @brief APR Versioning Interface + * + * APR's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of APR by use of the compile-time + * constants and the use of the run-time query function. + * + * APR version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for APR. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define APR_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading APR_MAJOR_VERSION + */ +#define APR_MINOR_VERSION 2 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading APR_MINOR_VERSION + */ +#define APR_PATCH_VERSION 7 + +/** + * The symbol APR_IS_DEV_VERSION is only defined for internal, + * "development" copies of APR. It is undefined for released versions + * of APR. + */ +#undef APR_IS_DEV_VERSION + + +#if defined(APR_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define APR_IS_DEV_STRING "-dev" +#else +#define APR_IS_DEV_STRING "" +#endif + +/* APR_STRINGIFY is defined here, and also in apr_general.h, so wrap it */ +#ifndef APR_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) +/** Helper macro for APR_STRINGIFY */ +#define APR_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of APR's version */ +#define APR_VERSION_STRING \ + APR_STRINGIFY(APR_MAJOR_VERSION) "." \ + APR_STRINGIFY(APR_MINOR_VERSION) "." \ + APR_STRINGIFY(APR_PATCH_VERSION) \ + APR_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define APR_VERSION_STRING_CSV APR_MAJOR_VERSION ##, \ + ##APR_MINOR_VERSION ##, \ + ##APR_PATCH_VERSION + + +#ifndef APR_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. APR_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The numeric version information is broken out into fields within this + * structure. + */ +typedef struct { + int major; /**< major number */ + int minor; /**< minor number */ + int patch; /**< patch number */ + int is_dev; /**< is development (1 or 0) */ +} apr_version_t; + +/** + * Return APR's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +APR_DECLARE(void) apr_version(apr_version_t *pvsn); + +/** Return APR's version information as a string. */ +APR_DECLARE(const char *) apr_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APR_VERSION_ONLY */ + +#endif /* ndef APR_VERSION_H */ diff --git a/include/apr/apr_want.h b/include/apr/apr_want.h new file mode 100644 index 0000000..c7556a7 --- /dev/null +++ b/include/apr/apr_want.h @@ -0,0 +1,109 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#include "apr.h" /* configuration data */ +/** + * @file apr_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APR_WANT_STRFUNC:  strcmp, strcat, strcpy, etc
+ *   APR_WANT_MEMFUNC:  memcmp, memcpy, etc
+ *   APR_WANT_STDIO:     and related bits
+ *   APR_WANT_IOVEC:    struct iovec
+ *   APR_WANT_BYTEFUNC: htons, htonl, ntohl, ntohs
+ *
+ * Typical usage:
+ *
+ *   #define APR_WANT_STRFUNC
+ *   #define APR_WANT_MEMFUNC
+ *   #include "apr_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apr_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STRFUNC + +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_STRINGS_H +#include +#endif + +#undef APR_WANT_STRFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_MEMFUNC + +#if APR_HAVE_STRING_H +#include +#endif + +#undef APR_WANT_MEMFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STDIO + +#if APR_HAVE_STDIO_H +#include +#endif + +#undef APR_WANT_STDIO +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_IOVEC + +#if APR_HAVE_SYS_UIO_H +#include +#endif + +#undef APR_WANT_IOVEC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_BYTEFUNC + +/* Single Unix says they are in arpa/inet.h. Linux has them in + * netinet/in.h. FreeBSD has them in arpa/inet.h but requires that + * netinet/in.h be included first. + */ +#if APR_HAVE_NETINET_IN_H +#include +#endif +#if APR_HAVE_ARPA_INET_H +#include +#endif + +#undef APR_WANT_BYTEFUNC +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr/apr_xlate.h b/include/apr/apr_xlate.h new file mode 100644 index 0000000..19402a7 --- /dev/null +++ b/include/apr/apr_xlate.h @@ -0,0 +1,163 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APR_XLATE_H +#define APR_XLATE_H + +#include "apu.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file apr_xlate.h + * @brief APR I18N translation library + */ + +/** + * @defgroup APR_XLATE I18N translation library + * @ingroup APR + * @{ + */ +/** Opaque translation buffer */ +typedef struct apr_xlate_t apr_xlate_t; + +/** + * Set up for converting text from one charset to another. + * @param convset The handle to be filled in by this function + * @param topage The name of the target charset + * @param frompage The name of the source charset + * @param pool The pool to use + * @remark + * Specify APR_DEFAULT_CHARSET for one of the charset + * names to indicate the charset of the source code at + * compile time. This is useful if there are literal + * strings in the source code which must be translated + * according to the charset of the source code. + * APR_DEFAULT_CHARSET is not useful if the source code + * of the caller was not encoded in the same charset as + * APR at compile time. + * + * @remark + * Specify APR_LOCALE_CHARSET for one of the charset + * names to indicate the charset of the current locale. + * + * @remark + * Return APR_EINVAL if unable to procure a convset, or APR_ENOTIMPL + * if charset transcoding is not available in this instance of + * apr-util at all (i.e., APR_HAS_XLATE is undefined). + */ +APU_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset, + const char *topage, + const char *frompage, + apr_pool_t *pool); + +/** + * This is to indicate the charset of the sourcecode at compile time + * names to indicate the charset of the source code at + * compile time. This is useful if there are literal + * strings in the source code which must be translated + * according to the charset of the source code. + */ +#define APR_DEFAULT_CHARSET (const char *)0 +/** + * To indicate charset names of the current locale + */ +#define APR_LOCALE_CHARSET (const char *)1 + +/** + * Find out whether or not the specified conversion is single-byte-only. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param onoff Output: whether or not the conversion is single-byte-only + * @remark + * Return APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + */ +APU_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff); + +/** + * Convert a buffer of text from one codepage to another. + * @param convset The handle allocated by apr_xlate_open, specifying + * the parameters of conversion + * @param inbuf The address of the source buffer + * @param inbytes_left Input: the amount of input data to be translated + * Output: the amount of input data not yet translated + * @param outbuf The address of the destination buffer + * @param outbytes_left Input: the size of the output buffer + * Output: the amount of the output buffer not yet used + * @remark + * Returns APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + * Returns APR_INCOMPLETE if the input buffer ends in an incomplete + * multi-byte character. + * + * To correctly terminate the output buffer for some multi-byte + * character set encodings, a final call must be made to this function + * after the complete input string has been converted, passing + * the inbuf and inbytes_left parameters as NULL. (Note that this + * mode only works from version 1.1.0 onwards) + */ +APU_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset, + const char *inbuf, + apr_size_t *inbytes_left, + char *outbuf, + apr_size_t *outbytes_left); + +/* @see apr_file_io.h the comment in apr_file_io.h about this hack */ +#ifdef APR_NOT_DONE_YET +/** + * The purpose of apr_xlate_conv_char is to translate one character + * at a time. This needs to be written carefully so that it works + * with double-byte character sets. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param inchar The character to convert + * @param outchar The converted character + */ +APU_DECLARE(apr_status_t) apr_xlate_conv_char(apr_xlate_t *convset, + char inchar, char outchar); +#endif + +/** + * Convert a single-byte character from one charset to another. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param inchar The single-byte character to convert. + * @warning This only works when converting between single-byte character sets. + * -1 will be returned if the conversion can't be performed. + */ +APU_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset, + unsigned char inchar); + +/** + * Close a codepage translation handle. + * @param convset The codepage translation handle to close + * @remark + * Return APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + */ +APU_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_XLATE_H */ diff --git a/include/apr/apr_xml.h b/include/apr/apr_xml.h new file mode 100644 index 0000000..ab184e7 --- /dev/null +++ b/include/apr/apr_xml.h @@ -0,0 +1,356 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ +/** + * @file apr_xml.h + * @brief APR-UTIL XML Library + */ +#ifndef APR_XML_H +#define APR_XML_H + +/** + * @defgroup APR_Util_XML XML + * @ingroup APR_Util + * @{ + */ +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_file_io.h" + +#include "apu.h" +#if APR_CHARSET_EBCDIC +#include "apr_xlate.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @package Apache XML library + */ + +/* -------------------------------------------------------------------- */ + +/* ### these will need to move at some point to a more logical spot */ + +/** @see apr_text */ +typedef struct apr_text apr_text; + +/** Structure to keep a linked list of pieces of text */ +struct apr_text { + /** The current piece of text */ + const char *text; + /** a pointer to the next piece of text */ + struct apr_text *next; +}; + +/** @see apr_text_header */ +typedef struct apr_text_header apr_text_header; + +/** A list of pieces of text */ +struct apr_text_header { + /** The first piece of text in the list */ + apr_text *first; + /** The last piece of text in the list */ + apr_text *last; +}; + +/** + * Append a piece of text to the end of a list + * @param p The pool to allocate out of + * @param hdr The text header to append to + * @param text The new text to append + */ +APU_DECLARE(void) apr_text_append(apr_pool_t *p, apr_text_header *hdr, + const char *text); + + +/* -------------------------------------------------------------------- +** +** XML PARSING +*/ + +/* +** Qualified namespace values +** +** APR_XML_NS_DAV_ID +** We always insert the "DAV:" namespace URI at the head of the +** namespace array. This means that it will always be at ID==0, +** making it much easier to test for. +** +** APR_XML_NS_NONE +** This special ID is used for two situations: +** +** 1) The namespace prefix begins with "xml" (and we do not know +** what it means). Namespace prefixes with "xml" (any case) as +** their first three characters are reserved by the XML Namespaces +** specification for future use. mod_dav will pass these through +** unchanged. When this identifier is used, the prefix is LEFT in +** the element/attribute name. Downstream processing should not +** prepend another prefix. +** +** 2) The element/attribute does not have a namespace. +** +** a) No prefix was used, and a default namespace has not been +** defined. +** b) No prefix was used, and the default namespace was specified +** to mean "no namespace". This is done with a namespace +** declaration of: xmlns="" +** (this declaration is typically used to override a previous +** specification for the default namespace) +** +** In these cases, we need to record that the elem/attr has no +** namespace so that we will not attempt to prepend a prefix. +** All namespaces that are used will have a prefix assigned to +** them -- mod_dav will never set or use the default namespace +** when generating XML. This means that "no prefix" will always +** mean "no namespace". +** +** In both cases, the XML generation will avoid prepending a prefix. +** For the first case, this means the original prefix/name will be +** inserted into the output stream. For the latter case, it means +** the name will have no prefix, and since we never define a default +** namespace, this means it will have no namespace. +** +** Note: currently, mod_dav understands the "xmlns" prefix and the +** "xml:lang" attribute. These are handled specially (they aren't +** left within the XML tree), so the APR_XML_NS_NONE value won't ever +** really apply to these values. +*/ +#define APR_XML_NS_DAV_ID 0 /**< namespace ID for "DAV:" */ +#define APR_XML_NS_NONE -10 /**< no namespace for this elem/attr */ + +#define APR_XML_NS_ERROR_BASE -100 /**< used only during processing */ +/** Is this namespace an error? */ +#define APR_XML_NS_IS_ERROR(e) ((e) <= APR_XML_NS_ERROR_BASE) + +/** @see apr_xml_attr */ +typedef struct apr_xml_attr apr_xml_attr; +/** @see apr_xml_elem */ +typedef struct apr_xml_elem apr_xml_elem; +/** @see apr_xml_doc */ +typedef struct apr_xml_doc apr_xml_doc; + +/** apr_xml_attr: holds a parsed XML attribute */ +struct apr_xml_attr { + /** attribute name */ + const char *name; + /** index into namespace array */ + int ns; + + /** attribute value */ + const char *value; + + /** next attribute */ + struct apr_xml_attr *next; +}; + +/** apr_xml_elem: holds a parsed XML element */ +struct apr_xml_elem { + /** element name */ + const char *name; + /** index into namespace array */ + int ns; + /** xml:lang for attrs/contents */ + const char *lang; + + /** cdata right after start tag */ + apr_text_header first_cdata; + /** cdata after MY end tag */ + apr_text_header following_cdata; + + /** parent element */ + struct apr_xml_elem *parent; + /** next (sibling) element */ + struct apr_xml_elem *next; + /** first child element */ + struct apr_xml_elem *first_child; + /** first attribute */ + struct apr_xml_attr *attr; + + /* used only during parsing */ + /** last child element */ + struct apr_xml_elem *last_child; + /** namespaces scoped by this elem */ + struct apr_xml_ns_scope *ns_scope; + + /* used by modules during request processing */ + /** Place for modules to store private data */ + void *priv; +}; + +/** Is this XML element empty? */ +#define APR_XML_ELEM_IS_EMPTY(e) ((e)->first_child == NULL && \ + (e)->first_cdata.first == NULL) + +/** apr_xml_doc: holds a parsed XML document */ +struct apr_xml_doc { + /** root element */ + apr_xml_elem *root; + /** array of namespaces used */ + apr_array_header_t *namespaces; +}; + +/** Opaque XML parser structure */ +typedef struct apr_xml_parser apr_xml_parser; + +/** + * Create an XML parser + * @param pool The pool for allocating the parser and the parse results. + * @return The new parser. + */ +APU_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool); + +/** + * Parse a File, producing a xml_doc + * @param p The pool for allocating the parse results. + * @param parser A pointer to *parser (needed so calling function can get + * errors), will be set to NULL on successfull completion. + * @param ppdoc A pointer to *apr_xml_doc (which has the parsed results in it) + * @param xmlfd A file to read from. + * @param buffer_length Buffer length which would be suitable + * @return Any errors found during parsing. + */ +APU_DECLARE(apr_status_t) apr_xml_parse_file(apr_pool_t *p, + apr_xml_parser **parser, + apr_xml_doc **ppdoc, + apr_file_t *xmlfd, + apr_size_t buffer_length); + + +/** + * Feed input into the parser + * @param parser The XML parser for parsing this data. + * @param data The data to parse. + * @param len The length of the data. + * @return Any errors found during parsing. + * @remark Use apr_xml_parser_geterror() to get more error information. + */ +APU_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser, + const char *data, + apr_size_t len); + +/** + * Terminate the parsing and return the result + * @param parser The XML parser for parsing this data. + * @param pdoc The resulting parse information. May be NULL to simply + * terminate the parsing without fetching the info. + * @return Any errors found during the final stage of parsing. + * @remark Use apr_xml_parser_geterror() to get more error information. + */ +APU_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser, + apr_xml_doc **pdoc); + +/** + * Fetch additional error information from the parser. + * @param parser The XML parser to query for errors. + * @param errbuf A buffer for storing error text. + * @param errbufsize The length of the error text buffer. + * @return The error buffer + */ +APU_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser, + char *errbuf, + apr_size_t errbufsize); + + +/** + * Converts an XML element tree to flat text + * @param p The pool to allocate out of + * @param elem The XML element to convert + * @param style How to covert the XML. One of: + *
+ *     APR_XML_X2T_FULL                start tag, contents, end tag 
+ *     APR_XML_X2T_INNER               contents only 
+ *     APR_XML_X2T_LANG_INNER          xml:lang + inner contents 
+ *     APR_XML_X2T_FULL_NS_LANG        FULL + ns defns + xml:lang 
+ * 
+ * @param namespaces The namespace of the current XML element + * @param ns_map Namespace mapping + * @param pbuf Buffer to put the converted text into + * @param psize Size of the converted text + */ +APU_DECLARE(void) apr_xml_to_text(apr_pool_t *p, const apr_xml_elem *elem, + int style, apr_array_header_t *namespaces, + int *ns_map, const char **pbuf, + apr_size_t *psize); + +/* style argument values: */ +#define APR_XML_X2T_FULL 0 /**< start tag, contents, end tag */ +#define APR_XML_X2T_INNER 1 /**< contents only */ +#define APR_XML_X2T_LANG_INNER 2 /**< xml:lang + inner contents */ +#define APR_XML_X2T_FULL_NS_LANG 3 /**< FULL + ns defns + xml:lang */ + +/** + * empty XML element + * @param p The pool to allocate out of + * @param elem The XML element to empty + * @return the string that was stored in the XML element + */ +APU_DECLARE(const char *) apr_xml_empty_elem(apr_pool_t *p, + const apr_xml_elem *elem); + +/** + * quote an XML string + * Replace '<', '>', and '&' with '<', '>', and '&'. + * @param p The pool to allocate out of + * @param s The string to quote + * @param quotes If quotes is true, then replace '"' with '"'. + * @return The quoted string + * @note If the string does not contain special characters, it is not + * duplicated into the pool and the original string is returned. + */ +APU_DECLARE(const char *) apr_xml_quote_string(apr_pool_t *p, const char *s, + int quotes); + +/** + * Quote an XML element + * @param p The pool to allocate out of + * @param elem The element to quote + */ +APU_DECLARE(void) apr_xml_quote_elem(apr_pool_t *p, apr_xml_elem *elem); + +/* manage an array of unique URIs: apr_xml_insert_uri() and APR_XML_URI_ITEM() */ + +/** + * return the URI's (existing) index, or insert it and return a new index + * @param uri_array array to insert into + * @param uri The uri to insert + * @return int The uri's index + */ +APU_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array, + const char *uri); + +/** Get the URI item for this XML element */ +#define APR_XML_GET_URI_ITEM(ary, i) (((const char * const *)(ary)->elts)[i]) + +#if APR_CHARSET_EBCDIC +/** + * Convert parsed tree in EBCDIC + * @param p The pool to allocate out of + * @param pdoc The apr_xml_doc to convert. + * @param xlate The translation handle to use. + * @return Any errors found during conversion. + */ +APU_DECLARE(apr_status_t) apr_xml_parser_convert_doc(apr_pool_t *p, + apr_xml_doc *pdoc, + apr_xlate_t *convset); +#endif + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* APR_XML_H */ diff --git a/include/apr/apu.h b/include/apr/apu.h new file mode 100644 index 0000000..494a8b7 --- /dev/null +++ b/include/apr/apu.h @@ -0,0 +1,113 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * Note: This is a Windows specific version of apu.h. It is renamed to + * apu.h at the start of a Windows build. + */ +/* @file apu.h + * @brief APR-Utility main file + */ + +#ifdef WIN32 +#ifndef APU_H +#define APU_H +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +#if defined(DOXYGEN) || !defined(WIN32) +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip extern APU_DECLARE_DATA type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +#elif defined(APU_DECLARE_STATIC) +#define APU_DECLARE(type) type __stdcall +#define APU_DECLARE_NONSTD(type) type __cdecl +#define APU_DECLARE_DATA +#elif defined(APU_DECLARE_EXPORT) +#define APU_DECLARE(type) __declspec(dllexport) type __stdcall +#define APU_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APU_DECLARE_DATA __declspec(dllexport) +#else +#define APU_DECLARE(type) __declspec(dllimport) type __stdcall +#define APU_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APU_DECLARE_DATA __declspec(dllimport) +#endif +/** @} */ +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 +#define APU_HAVE_GDBM 0 + +/* Allow external override */ +#if !defined(APU_HAVE_DB) +#define APU_HAVE_DB 0 +#endif + + +#define APU_HAVE_APR_ICONV 1 +#define APU_HAVE_ICONV 0 +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#if !defined(APU_HAVE_PGSQL) +#define APU_HAVE_PGSQL 0 +#endif +#if !defined(APU_HAVE_SQLITE2) +#define APU_HAVE_SQLITE2 0 +#endif +#if !defined(APU_HAVE_SQLITE3) +#define APU_HAVE_SQLITE3 0 +#endif + +#endif /* APU_H */ +#endif /* WIN32 */ diff --git a/include/apr/apu.h.in b/include/apr/apu.h.in new file mode 100644 index 0000000..5bd7d00 --- /dev/null +++ b/include/apr/apu.h.in @@ -0,0 +1,91 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * apu.h is generated from apu.h.in by configure -- do not edit apu.h + */ +/* @file apu.h + * @brief APR-Utility main file + */ +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +#ifndef APU_H +#define APU_H + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip APU_DECLARE_DATA extern type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM @apu_have_sdbm@ +#define APU_HAVE_GDBM @apu_have_gdbm@ +#define APU_HAVE_NDBM @apu_have_ndbm@ +#define APU_HAVE_DB @apu_have_db@ + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION @apu_db_version@ +#endif /* APU_HAVE_DB */ + +#define APU_HAVE_PGSQL @apu_have_pgsql@ +#define APU_HAVE_MYSQL @apu_have_mysql@ +#define APU_HAVE_SQLITE3 @apu_have_sqlite3@ +#define APU_HAVE_SQLITE2 @apu_have_sqlite2@ + +#define APU_HAVE_APR_ICONV @have_apr_iconv@ +#define APU_HAVE_ICONV @have_iconv@ +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#endif /* APU_H */ +/** @} */ diff --git a/include/apr/apu.hnw b/include/apr/apu.hnw new file mode 100644 index 0000000..8c3cee7 --- /dev/null +++ b/include/apr/apu.hnw @@ -0,0 +1,84 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * Note: This is a NetWare specific version of apu.h. It is renamed to + * apu.h at the start of a NetWare build. + */ +/* @file apu.h + * @brief APR-Utility main file + */ +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +#ifndef APU_H +#define APU_H + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip APU_DECLARE_DATA extern type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 +#define APU_HAVE_GDBM 0 +#define APU_HAVE_DB 0 + + +#define HAVE_ICONV_H 1 +#define APU_HAVE_APR_ICONV 0 +#define APU_HAVE_ICONV 1 +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#endif /* APU_H */ +/** @} */ diff --git a/include/apr/apu.hw b/include/apr/apu.hw new file mode 100644 index 0000000..494a8b7 --- /dev/null +++ b/include/apr/apu.hw @@ -0,0 +1,113 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +/* + * Note: This is a Windows specific version of apu.h. It is renamed to + * apu.h at the start of a Windows build. + */ +/* @file apu.h + * @brief APR-Utility main file + */ + +#ifdef WIN32 +#ifndef APU_H +#define APU_H +/** + * @defgroup APR_Util APR Utility Functions + * @{ + */ + + +/** + * APU_DECLARE_EXPORT is defined when building the APR-UTIL dynamic library, + * so that all public symbols are exported. + * + * APU_DECLARE_STATIC is defined when including the APR-UTIL public headers, + * to provide static linkage when the dynamic library may be unavailable. + * + * APU_DECLARE_STATIC and APU_DECLARE_EXPORT are left undefined when + * including the APR-UTIL public headers, to import and link the symbols from + * the dynamic APR-UTIL library and assure appropriate indirection and calling + * conventions at compile time. + */ + +#if defined(DOXYGEN) || !defined(WIN32) +/** + * The public APR-UTIL functions are declared with APU_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APU_DECLARE_NONSTD(). + * + * @deffunc APU_DECLARE(rettype) apr_func(args); + */ +#define APU_DECLARE(type) type +/** + * The public APR-UTIL functions using variable arguments are declared with + * APU_DECLARE_NONSTD(), as they must use the C language calling convention. + * + * @deffunc APU_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APU_DECLARE_NONSTD(type) type +/** + * The public APR-UTIL variables are declared with APU_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * + * @deffunc APU_DECLARE_DATA type apr_variable; + * @tip extern APU_DECLARE_DATA type apr_variable; syntax is required for + * declarations within headers to properly import the variable. + */ +#define APU_DECLARE_DATA +#elif defined(APU_DECLARE_STATIC) +#define APU_DECLARE(type) type __stdcall +#define APU_DECLARE_NONSTD(type) type __cdecl +#define APU_DECLARE_DATA +#elif defined(APU_DECLARE_EXPORT) +#define APU_DECLARE(type) __declspec(dllexport) type __stdcall +#define APU_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APU_DECLARE_DATA __declspec(dllexport) +#else +#define APU_DECLARE(type) __declspec(dllimport) type __stdcall +#define APU_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APU_DECLARE_DATA __declspec(dllimport) +#endif +/** @} */ +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 +#define APU_HAVE_GDBM 0 + +/* Allow external override */ +#if !defined(APU_HAVE_DB) +#define APU_HAVE_DB 0 +#endif + + +#define APU_HAVE_APR_ICONV 1 +#define APU_HAVE_ICONV 0 +#define APR_HAS_XLATE (APU_HAVE_APR_ICONV || APU_HAVE_ICONV) + +#if !defined(APU_HAVE_PGSQL) +#define APU_HAVE_PGSQL 0 +#endif +#if !defined(APU_HAVE_SQLITE2) +#define APU_HAVE_SQLITE2 0 +#endif +#if !defined(APU_HAVE_SQLITE3) +#define APU_HAVE_SQLITE3 0 +#endif + +#endif /* APU_H */ +#endif /* WIN32 */ diff --git a/include/apr/apu_version.h b/include/apr/apu_version.h new file mode 100644 index 0000000..14edec8 --- /dev/null +++ b/include/apr/apu_version.h @@ -0,0 +1,134 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#ifndef APU_VERSION_H +#define APU_VERSION_H + +/** + * @file apu_version.h + * @brief APR-util Versioning Interface + * + * APR-util's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of APU by use of the compile-time + * constants and the use of the run-time query function. + * + * APU version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for APU. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define APU_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading APU_MAJOR_VERSION + */ +#define APU_MINOR_VERSION 2 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading APR_MINOR_VERSION + */ +#define APU_PATCH_VERSION 7 + +/** + * The symbol APU_IS_DEV_VERSION is only defined for internal, + * "development" copies of APU. It is undefined for released versions + * of APU. + */ +#undef APU_IS_DEV_VERSION + + +#if defined(APU_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define APU_IS_DEV_STRING "-dev" +#else +#define APU_IS_DEV_STRING "" +#endif + + +#ifndef APU_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APU_STRINGIFY(n) APU_STRINGIFY_HELPER(n) +/** Helper macro for APU_STRINGIFY */ +#define APU_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of APU's version */ +#define APU_VERSION_STRING \ + APU_STRINGIFY(APU_MAJOR_VERSION) "." \ + APU_STRINGIFY(APU_MINOR_VERSION) "." \ + APU_STRINGIFY(APU_PATCH_VERSION) \ + APU_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define APU_VERSION_STRING_CSV APU_MAJOR_VERSION ##, \ + ##APU_MINOR_VERSION ##, \ + ##APU_PATCH_VERSION + + +#ifndef APU_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. APU_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr_version.h" + +#include "apu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return APR-util's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +APU_DECLARE(void) apu_version(apr_version_t *pvsn); + +/** Return APU's version information as a string. */ +APU_DECLARE(const char *) apu_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APU_VERSION_ONLY */ + +#endif /* ndef APU_VERSION_H */ diff --git a/include/apr/apu_want.h b/include/apr/apu_want.h new file mode 100644 index 0000000..4927da8 --- /dev/null +++ b/include/apr/apu_want.h @@ -0,0 +1,52 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr/apu_want.h.in b/include/apr/apu_want.h.in new file mode 100644 index 0000000..ac29729 --- /dev/null +++ b/include/apr/apu_want.h.in @@ -0,0 +1,51 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header@>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +#include <@apu_db_header@> +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr/apu_want.hnw b/include/apr/apu_want.hnw new file mode 100644 index 0000000..4927da8 --- /dev/null +++ b/include/apr/apu_want.hnw @@ -0,0 +1,52 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr/apu_want.hw b/include/apr/apu_want.hw new file mode 100644 index 0000000..4927da8 --- /dev/null +++ b/include/apr/apu_want.hw @@ -0,0 +1,52 @@ +/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as + * applicable. + * + * 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. + */ + +#include "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + *
+ * Features:
+ *
+ *   APU_WANT_DB:       <@apu_db_header>
+ *
+ * Typical usage:
+ *
+ *   #define APU_WANT_DB
+ *   #include "apu_want.h"
+ *
+ * The appropriate headers will be included.
+ *
+ * Note: it is safe to use this in a header (it won't interfere with other
+ *       headers' or source files' use of apu_want.h)
+ * 
+ */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr/expat.h b/include/apr/expat.h new file mode 100644 index 0000000..9e440e2 --- /dev/null +++ b/include/apr/expat.h @@ -0,0 +1,742 @@ +/* +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#include + +#ifndef XMLPARSEAPI +# if defined(__declspec) && !defined(__CYGWIN__) +# define XMLPARSEAPI __declspec(dllimport) +# else +# define XMLPARSEAPI /* nothing */ +# endif +#endif /* not defined XMLPARSEAPI */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *XML_Parser; + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ + +typedef void (*XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +void XMLPARSEAPI +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* + The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" keyword. + The "isrequired" parameter will be true and the default value will + be NULL in the case of "#REQUIRED". If "isrequired" is true and + default is non-NULL, then this is a "#FIXED" default. + */ + +typedef void (*XML_AttlistDeclHandler) (void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +void XMLPARSEAPI +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + + + /* The XML declaration handler is called for *both* XML declarations and + text declarations. The way to distinguish is that the version parameter + will be null for text declarations. The encoding parameter may be null + for XML declarations. The standalone parameter will be -1, 0, or 1 + indicating respectively that there was no standalone parameter in + the declaration, that it was given as no, or that it was given as yes. + */ + +typedef void (*XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +void XMLPARSEAPI +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the +external protocol or null if there is none specified. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type +names and attribute names that belong to a namespace will be expanded; +unprefixed attribute names are never expanded; unprefixed element type +names are expanded only if there is a default namespace. The expanded +name is the concatenation of the namespace URI, the namespace +separator character, and the local part of the name. If the namespace +separator is '\0' then the namespace URI and the local part will be +concatenated without any separator. When a namespace is not declared, +the name and prefix will be passed through without expansion. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suit referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ + +XML_Parser XMLPARSEAPI +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. */ + +typedef void (*XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (*XML_EndElementHandler)(void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (*XML_CharacterDataHandler)(void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (*XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void (*XML_StartCdataSectionHandler)(void *userData); +typedef void (*XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for +which there is no applicable handler. This includes both +characters that are part of markup which is of a kind that is +not reported (comments, markup declarations), or characters +that are part of a construct which could be reported but +for which no handler has been supplied. The characters are passed +exactly as they were in the XML document except that +they will be encoded in UTF-8. Line boundaries are not normalized. +Note that a byte order mark character is not passed to the default handler. +There are no guarantees about how characters are divided between calls +to the default handler: for example, a comment might be split between +multiple calls. */ + +typedef void (*XML_DefaultHandler)(void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. */ + +typedef void (*XML_StartDoctypeDeclHandler)(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset + ); + +/* This is called for the start of the DOCTYPE declaration when the +closing > is encountered, but after processing any external subset. */ +typedef void (*XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-null and systemId, publicID, and notationName will be null. + The value string is NOT null terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be null and systemId will be non-null. + The publicId argument will be null unless a public identifier was + provided. The notationName argument will have a non-null value only + for unparsed entity declarations. +*/ + +typedef void (*XML_EntityDeclHandler) (void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +void XMLPARSEAPI +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. +This is called for a declaration of an unparsed (NDATA) +entity. The base argument is whatever was set by XML_SetBase. +The entityName, systemId and notationName arguments will never be null. +The other arguments may be. */ + +typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. +The base argument is whatever was set by XML_SetBase. +The notationName will never be null. The other arguments can be. */ + +typedef void (*XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for +each namespace declaration. The call to the start and end element +handlers occur between the calls to the start and end namespace +declaration handlers. For an xmlns attribute, prefix will be null. +For an xmlns="" attribute, uri will be null. */ + +typedef void (*XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (*XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone (it has an +external subset or a reference to a parameter entity, but does not +have standalone="yes"). If this handler returns 0, then processing +will not continue, and the parser will return a +XML_ERROR_NOT_STANDALONE error. */ + +typedef int (*XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general entity. +The referenced entity is not automatically parsed. +The application can parse it immediately or later using +XML_ExternalEntityParserCreate. +The parser argument is the parser parsing the entity containing the reference; +it can be passed as the parser argument to XML_ExternalEntityParserCreate. +The systemId argument is the system identifier as specified in the entity +declaration; it will not be null. +The base argument is the system identifier that should be used as the base for +resolving systemId if systemId was relative; this is set by XML_SetBase; +it may be null. +The publicId argument is the public identifier as specified in the entity +declaration, or null if none was specified; the whitespace in the public +identifier will have been normalized as required by the XML spec. +The context argument specifies the parsing context in the format +expected by the context argument to +XML_ExternalEntityParserCreate; context is valid only until the handler +returns, so if the referenced entity is to be parsed later, it must be copied. +The handler should return 0 if processing should not continue because of +a fatal error in the handling of the external entity. +In this case the calling parser will return an +XML_ERROR_EXTERNAL_ENTITY_HANDLING error. +Note that unlike other handlers the first argument is the parser, not +userData. */ + +typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This structure is filled in by the XML_UnknownEncodingHandler +to provide information to the parser about encodings that are unknown +to the parser. +The map[b] member gives information about byte sequences +whose first byte is b. +If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar +value c. +If map[b] is -1, then the byte sequence is malformed. +If map[b] is -n, where n >= 2, then b is the first byte of an n-byte +sequence that encodes a single Unicode scalar value. +The data member will be passed as the first argument to the convert function. +The convert function is used to convert multibyte sequences; +s will point to a n-byte sequence where map[(unsigned char)*s] == -n. +The convert function must return the Unicode scalar value +represented by this byte sequence or -1 if the byte sequence is malformed. +The convert function may be null if the encoding is a single-byte encoding, +that is if map[b] >= -1 for all bytes b. +When the parser is finished with the encoding, then if release is not null, +it will call release passing it the data member; +once release has been called, the convert function will not be called again. + +Expat places certain restrictions on the encodings that are supported +using this mechanism. + +1. Every ASCII character that can appear in a well-formed XML document, +other than the characters + + $@\^`{}~ + +must be represented by a single byte, and that byte must be the +same byte that represents that character in ASCII. + +2. No character may require more than 4 bytes to encode. + +3. All characters encoded must have Unicode scalar values <= 0xFFFF, +(ie characters that would be encoded by surrogates in UTF-16 +are not allowed). Note that this restriction doesn't apply to +the built-in support for UTF-8 and UTF-16. + +4. No Unicode character may be encoded by more than one distinct sequence +of bytes. */ + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. +The encodingHandlerData argument is that which was passed as the +second argument to XML_SetUnknownEncodingHandler. +The name argument gives the name of the encoding as specified in +the encoding declaration. +If the callback can provide information about the encoding, +it must fill in the XML_Encoding structure, and return 1. +Otherwise it must return 0. +If info does not describe a suitable encoding, +then the parser will return an XML_UNKNOWN_ENCODING error. */ + +typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +void XMLPARSEAPI +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +void XMLPARSEAPI +XML_SetStartElementHandler(XML_Parser, XML_StartElementHandler); + +void XMLPARSEAPI +XML_SetEndElementHandler(XML_Parser, XML_EndElementHandler); + +void XMLPARSEAPI +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +void XMLPARSEAPI +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +void XMLPARSEAPI +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +void XMLPARSEAPI +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +void XMLPARSEAPI +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +void XMLPARSEAPI +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of +internal entities. The entity reference will be passed to the default +handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of +internal entities. The entity reference will not be passed to the +default handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +void XMLPARSEAPI +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +void XMLPARSEAPI +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +void XMLPARSEAPI +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +void XMLPARSEAPI +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +void XMLPARSEAPI +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +void XMLPARSEAPI +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-null value for arg is specified here, then it will be passed +as the first argument to the external entity ref handler instead +of the parser object. */ +void XMLPARSEAPI +XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +void XMLPARSEAPI +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end element, +processing instruction or character data. It causes the corresponding +markup to be passed to the default handler. */ +void XMLPARSEAPI +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single + string separated by the separator character specified when the parser + was created: URI + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the names + has a prefix. +*/ + +void XMLPARSEAPI +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +void XMLPARSEAPI +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or null. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument +to XML_ParserCreate. It must not be called after XML_Parse +or XML_ParseBuffer. */ + +int XMLPARSEAPI +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed +as the first argument to callbacks instead of userData. +The userData will still be accessible using XML_GetUserData. */ + +void XMLPARSEAPI +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* Sets the base to be used for resolving relative URIs in system +identifiers in declarations. Resolving relative identifiers is left +to the application: this value will be passed through as the base +argument to the XML_ExternalEntityRefHandler, XML_NotationDeclHandler +and XML_UnparsedEntityDeclHandler. The base argument will be copied. +Returns zero if out of memory, non-zero otherwise. */ + +int XMLPARSEAPI +XML_SetBase(XML_Parser parser, const XML_Char *base); + +const XML_Char XMLPARSEAPI * +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call +to the XML_StartElementHandler that were specified in the start-tag +rather than defaulted. Each attribute/value pair counts as 2; thus +this correspondds to an index into the atts array passed to the +XML_StartElementHandler. */ + +int XMLPARSEAPI +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to +XML_StartElementHandler, or -1 if there is no ID attribute. Each +attribute/value pair counts as 2; thus this correspondds to an index +into the atts array passed to the XML_StartElementHandler. */ + +int XMLPARSEAPI +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns 0 if a fatal error is detected. +The last call to XML_Parse must have isFinal true; +len may be zero for this call (or any other). */ +int XMLPARSEAPI +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +void XMLPARSEAPI * +XML_GetBuffer(XML_Parser parser, int len); + +int XMLPARSEAPI +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general +entity; context is a '\0'-terminated string specifying the parse +context; encoding is a '\0'-terminated string giving the name of the +externally specified encoding, or null if there is no externally +specified encoding. The context string consists of a sequence of +tokens separated by formfeeds (\f); a token consisting of a name +specifies that the general entity of the name is open; a token of the +form prefix=uri specifies the namespace for a particular prefix; a +token of the form =uri specifies the default namespace. This can be +called at any point after the first call to an +ExternalEntityRefHandler so longer as the parser has not yet been +freed. The new parser is completely independent and may safely be +used in a separate thread. The handlers and userData are initialized +from the parser argument. Returns 0 if out of memory. Otherwise +returns a new XML_Parser object. */ +XML_Parser XMLPARSEAPI +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD +subset). If parsing of parameter entities is enabled, then references +to external parameter entities (including the external DTD subset) +will be passed to the handler set with +XML_SetExternalEntityRefHandler. The context passed will be 0. +Unlike external general entities, external parameter entities can only +be parsed synchronously. If the external parameter entity is to be +parsed, it must be parsed during the call to the external entity ref +handler: the complete sequence of XML_ExternalEntityParserCreate, +XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during +this call. After XML_ExternalEntityParserCreate has been called to +create the parser for the external parameter entity (context must be 0 +for this call), it is illegal to make any calls on the old parser +until XML_ParserFree has been called on the newly created parser. If +the library has been compiled without support for parameter entity +parsing (ie without XML_DTD being defined), then +XML_SetParamEntityParsing will return 0 if parsing of parameter +entities is requested; otherwise it will return non-zero. */ + +int XMLPARSEAPI +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE +}; + +/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode +returns information about the error. */ + +enum XML_Error XMLPARSEAPI +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse location. +They may be called when XML_Parse or XML_ParseBuffer return 0; +in this case the location is the location of the character at which +the error was detected. +They may also be called from any other callback called to report +some parse event; in this the location is the location of the first +of the sequence of characters that generated the event. */ + +int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser); +int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser); +long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. +Returns 0 if the event is in an internal entity. */ + +int XMLPARSEAPI +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a null pointer. Also returns a null pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. */ + +const char XMLPARSEAPI * +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees memory used by the parser. */ +void XMLPARSEAPI +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +const XML_LChar XMLPARSEAPI * +XML_ErrorString(int code); + +/* Return a string containing the version number of this expat */ +const XML_LChar XMLPARSEAPI * +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat */ + +XML_Expat_Version XMLPARSEAPI +XML_ExpatVersionInfo(void); + +#ifndef XML_MAJOR_VERSION +#define XML_MAJOR_VERSION 1 +#endif +#ifndef XML_MINOR_VERSION +#define XML_MINOR_VERSION 95 +#endif +#ifndef XML_MICRO_VERSION +#define XML_MICRO_VERSION 2 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/include/curl/curl.h b/include/curl/curl.h new file mode 100644 index 0000000..4e09cf7 --- /dev/null +++ b/include/curl/curl.h @@ -0,0 +1,2268 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * http://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * http://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#include "curlver.h" /* libcurl version defines */ +#include "curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURL; + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ +#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ +#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ +#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer + do not free in formfree */ +#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer + do not free in formfree */ +#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ +#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ +#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the + regular read callback to get the data + and pass the given pointer as custom + pointer */ + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char * b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_OBSOLETE16, /* 16 - NOT USED */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsoletes error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_GSSNEGOTIATE - HTTP GSS-Negotiate authentication + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_GSSNEGOTIATE (((unsigned long)1)<<2) +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(FILE, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, OBJECTPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, OBJECTPOINT, 4), + + /* "name:password" to use when fetching. */ + CINIT(USERPWD, OBJECTPOINT, 5), + + /* "name:password" to use with proxy. */ + CINIT(PROXYUSERPWD, OBJECTPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, OBJECTPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(INFILE, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, OBJECTPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, OBJECTPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, OBJECTPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, OBJECTPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, OBJECTPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, OBJECTPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(WRITEHEADER, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, OBJECTPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), + + /* HTTP request, for odd commands like DELETE, TRACE and others */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(WRITEINFO, OBJECTPOINT, 40), /* DEPRECATED, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, OBJECTPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, OBJECTPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, OBJECTPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(CLOSEPOLICY, LONG, 72), /* DEPRECATED, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, OBJECTPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, OBJECTPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, OBJECTPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, OBJECTPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, OBJECTPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, OBJECTPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, OBJECTPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, OBJECTPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, OBJECTPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), + + /* feed cookies into cookie engine */ + CINIT(COOKIELIST, OBJECTPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, OBJECTPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, OBJECTPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only + working with OpenSSL-powered builds. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, OBJECTPOINT, 173), + CINIT(PASSWORD, OBJECTPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, OBJECTPOINT, 175), + CINIT(PROXYPASSWORD, OBJECTPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, OBJECTPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, OBJECTPOINT, 186), + + /* set the SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, OBJECTPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, OBJECTPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, OBJECTPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_WRITEDATA CURLOPT_FILE +#define CURLOPT_READDATA CURLOPT_INFILE +#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 42 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + +typedef void CURLSH; + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */ +#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */ +#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ +#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ +#define CURL_VERSION_CONV (1<<12) /* character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/include/curl/curlbuild.h b/include/curl/curlbuild.h new file mode 100644 index 0000000..bdca52b --- /dev/null +++ b/include/curl/curlbuild.h @@ -0,0 +1,198 @@ +/* include/curl/curlbuild.h. Generated from curlbuild.h.in by configure. */ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CURL_PULL_WS2TCPIP_H */ +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CURL_PULL_SYS_TYPES_H 1 +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +/* #undef CURL_PULL_STDINT_H */ +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +/* #undef CURL_PULL_INTTYPES_H */ +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CURL_PULL_SYS_SOCKET_H 1 +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +/* #undef CURL_PULL_SYS_POLL_H */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CURL_SIZEOF_LONG 8 + +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#define CURL_TYPEOF_CURL_OFF_T long + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_T "ld" + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_TU "lu" + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#define CURL_FORMAT_OFF_T "%ld" + +/* The size of `curl_off_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_OFF_T 8 + +/* curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_T L + +/* unsigned curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_TU UL + +#endif /* __CURL_CURLBUILD_H */ diff --git a/include/curl/curlrules.h b/include/curl/curlrules.h new file mode 100644 index 0000000..7c2ede3 --- /dev/null +++ b/include/curl/curlrules.h @@ -0,0 +1,262 @@ +#ifndef __CURL_CURLRULES_H +#define __CURL_CURLRULES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by curl/curl.h when an application is + * being built using an already built libcurl library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the curlbuild.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the libcurl development mailing list: + * http://cool.haxx.se/mailman/listinfo/curl-library/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built libcurl library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +#endif + +#ifndef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __curl_rule_01__ + [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * curl_off_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_02__ + [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; + +/* + * Verify at compile time that the size of curl_off_t as reported + * by sizeof() is greater or equal than the one reported for long + * for the current compilation. + */ + +typedef char + __curl_rule_03__ + [CurlchkszGE(curl_off_t, long)]; + +/* + * Verify that the size previously defined and expected for + * curl_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_04__ + [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of curl_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __curl_rule_05__ + [CurlchkszGE(curl_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +/* + * Get rid of macros private to this header file. + */ + +#undef CurlchkszEQ +#undef CurlchkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CURL_PULL_WS2TCPIP_H +#undef CURL_PULL_SYS_TYPES_H +#undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H +#undef CURL_PULL_STDINT_H +#undef CURL_PULL_INTTYPES_H + +#undef CURL_TYPEOF_CURL_SOCKLEN_T +#undef CURL_TYPEOF_CURL_OFF_T + +#ifdef CURL_NO_OLDIES +#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ +#endif + +#endif /* __CURL_CURLRULES_H */ diff --git a/include/curl/curlver.h b/include/curl/curlver.h new file mode 100644 index 0000000..43c681b --- /dev/null +++ b/include/curl/curlver.h @@ -0,0 +1,69 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2013 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.33.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 33 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. +*/ +#define LIBCURL_VERSION_NUM 0x072100 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "Mon Oct 14 14:42:58 UTC 2013" + +#endif /* __CURL_CURLVER_H */ diff --git a/include/curl/easy.h b/include/curl/easy.h new file mode 100644 index 0000000..c1e3e76 --- /dev/null +++ b/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/curl/mprintf.h b/include/curl/mprintf.h new file mode 100644 index 0000000..cc9e7f5 --- /dev/null +++ b/include/curl/mprintf.h @@ -0,0 +1,81 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef _MPRINTF_REPLACE +# undef printf +# undef fprintf +# undef sprintf +# undef vsprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +#ifdef CURLDEBUG +/* When built with CURLDEBUG we define away the sprintf functions since we + don't want internal code to be using them */ +# define sprintf sprintf_was_used +# define vsprintf vsprintf_was_used +#else +# define sprintf curl_msprintf +# define vsprintf curl_mvsprintf +#endif +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/include/curl/multi.h b/include/curl/multi.h new file mode 100644 index 0000000..3c4acb0 --- /dev/null +++ b/include/curl/multi.h @@ -0,0 +1,399 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURLM; + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/include/curl/stdcheaders.h b/include/curl/stdcheaders.h new file mode 100644 index 0000000..ad82ef6 --- /dev/null +++ b/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h new file mode 100644 index 0000000..e8f1dff --- /dev/null +++ b/include/curl/typecheck-gcc.h @@ -0,0 +1,609 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__ (option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__ (info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string (char* or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a FILE* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a void* or char* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a struct curl_httppost* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a struct curl_slist* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to char * for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to struct curl_slist * for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_URL || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_WRITEDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_WRITEHEADER || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + (option) == CURLOPT_MAIL_RCPT || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (CURLINFO_SLIST < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void*)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *)) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func), type*)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*); +typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*); +typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/include/ied.h b/include/ied.h new file mode 100644 index 0000000..10b497b --- /dev/null +++ b/include/ied.h @@ -0,0 +1,382 @@ +/** + * @file: $RCSfile: ied.h,v $ + * @brief: $豸ݽṹ + * + * @version: $Revision: 1.1 $ + * @date: $Date: 2018/11/24 06:54:49 $ + * @author: $Author: lizhongming $ + * @state: $State: Exp $ + * + * @latest: $Id: ied.h,v 1.1 2018/11/24 06:54:49 lizhongming Exp $ + * + */ + + +#ifndef _IED_STRUCT_H +#define _IED_STRUCT_H + +#include "IEC60870DEF.h" +//#include "drvcommon.h" +typedef byte_t channel_size_type; + +#ifdef _OS_WIN32_ +#pragma pack(push,1) +#endif + + +#define PRV_ANA_EXTENSION (1) //ģûչ +#define PRV_DIGIT_EXTENSION (3) //ңûչ +#define PRV_EVENT_EXTENSION (3) //¼ûչ +#define PRV_PULSE_EXTENSION (2) //ңûչ +//-----ģûչ---------------// +#define ANA_EXTENSION_ALARM (0) //澯:澯ȼ;澯ļ + + + +typedef struct analog_t analog_t; +struct analog_t { + byte_t type; /**< ѹ//й/޹/Ƶ// */ + float initval; /**< ȱʡֵ */ + float minimum; /**< ȡֵ */ + float maximum; /**< ȡֵ */ + float step; /**< */ + byte_t integral; /**< precision ( n , m ) - n */ + byte_t decimal; /**< precision ( n , m ) - m */ + float offset; /**< ʵֵת */ + float factor; /**< ʵֵתϵ */ + float threshold; /**< ֵ */ + float smooth; /**< ƽϵ */ + float lower; /**< 澯ֵ */ + float higher; /**< 澯ֵ */ + float lowest; /**< ޸澯ֵ */ + float highest; /**< ޸澯ֵ */ + float blur; /**< ֵģϵ */ + char dimension[SHORTNAME]; /**< ASCIIʽ(A/V/kV/kvar/kW/MW etc.) */ + void *ext[PRV_ANA_EXTENSION]; /**< չ */ +}ALIGNPACKED; + + +typedef struct ana_extention_t ana_extention_t; +struct ana_extention_t{ + int alarm_level; + int save_flag; + char *high_alarm_sound; + char *low_alarm_sound; + char *recovery_alarm_sound; +}; + +typedef struct digit_t digit_t; +#define DGT_TYP_UNDEF 0x00 /**< δ */ +#define DGT_TYP_SAMPLING 0x01 /**< */ +#define DGT_TYP_EVENT 0x02 /**< ¼ */ +#define DGT_TYP_ALARM 0x03 /**< 澯 */ +#define DGT_TYP_OPERATE 0x04 /**< */ +#define DGT_TYP_SYSTEM 0x05 /**< ϵͳ */ +/** ˽ */ +struct digit_t { + byte_t type; /**< /¼/澯//ϵͳ */ + byte_t initval; /**< default zero value(0 or 1) */ + byte_t level; /**< level */ + byte_t snd_timer; /**< sound play timer (s) */ + byte_t rst_timer; /**< auto restore timer (s) */ + uint16_t act_lim; /**< (0 ==> 1)澯 */ + uint16_t rst_lim; /**< (1 ==> 0)澯 */ + uint16_t act_num; /**< (0 ==> 1)(¼) */ + uint16_t rst_num; /**< (1 ==> 0)(¼) */ + //ڶȥ + //char on[SHORTNAME]; /**< 0==>1(ASCIIʽ) */ + //char off[SHORTNAME]; /**< 1==>0(ASCIIʽ) */ + void *ext[PRV_DIGIT_EXTENSION]; /**< չ */ +}ALIGNPACKED; + + +#define DIGIT_STATE_0_DESCRIBE (0) +#define DIGIT_STATE_1_DESCRIBE (1) +#define DIGIT_STATE_2_DESCRIBE (2) +#define DIGIT_STATE_3_DESCRIBE (3) + +#define DIGIT_OPEN_SOUND (0) +#define DIGIT_CLOSE_SOUND (1) +#define DIGIT_ALARM_SOUND (2) + + +typedef struct state_describe_extention_t state_describe_extention_t; +struct state_describe_extention_t{ + char *state_describe[4]; /**< ״̬0123 */ +}; +typedef struct sound_file_name_extention_t sound_file_name_extention_t; + +struct sound_file_name_extention_t{ + char *sound_file_name[3]; /**< ϱ¹ʱ */ +}; + +typedef struct epfi_addt_extension_t epfi_addt_extension_t; +struct epfi_addt_extension_t { + uint32_t fun; + uint32_t inf; +}; + + + +typedef struct pulse_t pulse_t; +/** Integrated totals private attr */ +#define PLS_TYP_UNDEF 0x00 /**< δ */ +#define PLS_TYP_PLUS_POWER_HV 0x01 /**< й */ +#define PLS_TYP_PLUS_POWER_NO 0x02 /**< ޹ */ +#define PLS_TYP_NEGATIVE_POWER_HV 0x03 /**< й */ +#define PLS_TYP_NEGATIVE_POWER_NO 0x04 /**< ޹ */ +struct pulse_t { + byte_t type; /**< й/޹/й/޹ */ + uint32_t save_flag; /**< 洢 */ + uint32_t initval; /**< default value */ + uint32_t minimum; /**< minimum value */ + uint32_t maximum; /**< maximum value */ + uint32_t step; /**< */ + //changed by zhancg 2017-04-05 ϵ +// uint32_t offset; /**< ʵֵת */ +// uint32_t factor; /**< ʵֵתϵ */ +// uint32_t threshold; /**< ֵ */ +// uint32_t smooth; /**< ƽϵ */ + float offset; /**< ʵֵת */ + float factor; /**< ʵֵתϵ */ + float threshold; /**< ֵ */ + float smooth; /**< ƽϵ */ + char dimension[SHORTNAME]; /**< ASCIIʽ(kvar/kW/MW etc.) */ + void *ext[PRV_PULSE_EXTENSION]; +}ALIGNPACKED; +typedef struct pluse_stage_limits_extention_t pluse_stage_limits_extention_t; +struct pluse_stage_limits_extention_t{ + uint32_t limits[3]; /**< ֵ,յֵ,µֵ */ +}; +typedef struct pluse_stage_const_extention_t pluse_stage_const_extention_t; +struct pluse_stage_const_extention_t{ + char* stage[8]; /**< ʱ1,ʱ2,ʱ3,ʱ4,ʱ1,ʱ2,ʱ3,ʱ4 */ +}; + +// +typedef struct command_t command_t; +/** Ϣṹ */ +struct command_t { + ticks_t ticks; /**< Ticks when command generated */ + apr_time_t tmlimit; /**< ִɵʱ */ + byte_t state; /**< ACTIVEFINISH or TIMEOUT */ + byte_t channel; /**< command channel no */ + byte_t flag; /**< GeneralSystem or Special */ + byte_t typ; /**< Command TYPE(IEC60870-5-101) */ + uint32_t ied; /**< Controlled IED id */ + uint32_t group; /**< Controlled group id */ + uint32_t dot; /**< Controlled element */ + byte_t cot; /**< Cause of transmission */ + byte_t data[255]; /**< Command data */ +}ALIGNPACKED; +// + + +/** status_t code definiens */ +#define STATUS_NORMAL 0 /**< */ +#define STATUS_NOINIT 1 /**< δʼ */ +#define STATUS_OVERTIME 2 /**< ͨųʱ */ +#define STATUS_BREAKOFF 3 /**< ͨж */ +#define STATUS_BLOCKED 4 /**< */ +#define STATUS_TESTING 5 /**< */ +#define STATUS_NOTDEF 6 /**< δã״̬û) */ + +typedef uint16_t status_t; /**< 豸ͨŽڵ״̬ */ + +typedef struct alias_t alias_t; +/** Ԫصıṹ */ +struct alias_t { /**< Ԫصıṹ */ + uint32_t id; /**< Ϣַ */ + uint32_t parent; /**< ָIED */ + uint32_t group; /**< ָIEDڵ */ + uint32_t dot; /**< ָIEDڵ */ + value_t* value; /**< ʱʵʱ */ +}; + +typedef struct ied_t ied_t; +typedef struct group_t group_t; +typedef struct element_t element_t; + +/** ϢԪصĽṹ */ +struct element_t { + uint32_t id; /**< Identification, Information Address */ + uint32_t flags; /**< flags define */ + byte_t type; /**< IEC60870-5-101 TYP.(IEC60870DEF.h) */ + byte_t code; /**< Data code type.(BIN/ASCII/BCD/etc.) */ + uint32_t parent; /**< 豸 */ + uint32_t group; /**< */ + uint32_t dot; /**< */ + uint16_t size; /**< ݿ(ֽΪλ) */ + char name[LONGNAME]; /**< */ + + char *aliasname; /**< ݵƶӦӢ ++EPFI++ */ + + void *owner; /**< ˽Խṹ(analog_t/digit_t/..../etc.) */ + void *script; /**< ļʽ */ + + /** Runtime generate */ + value_t value; /**< ʱʵʱݻ */ + ticks_t last; /**< 仯ʱ */ + uint32_t state; /**< ״̬ */ + byte_t funtype; /**< ̳ͣʾݹ */ + uint16_t index; /**< Ԫ */ + uint16_t n_alias_add_1; /**< ݱĴСԤ1̬ã */ + uint16_t n_alias; /**< ݱԪظ */ + alias_t* alias; /**< ݱ */ + uint16_t alias_pos; /**< ݱǰλ */ + uint32_t offset; /**< 豸ݻڵƫ */ + group_t *grp; /**< */ + ied_t *ied; /**< 豸 */ + + /* Extend property */ + void *sys_ext; /**< ݵϵͳչ,ɻʵ */ + void *app_ext; /**< ݵӦչ,Ӧÿʵ */ + void *usr_ext; /**< ݵûչ,Ӧóʵ */ +}; + +/** group_t->type definiens */ +#define GRP_CUSTOM 0 /**< User custom type */ +#define GRP_ANALOGUE 1 /**< Analogue type */ +#define GRP_DIGITAL 2 /**< Digital type */ +#define GRP_PULSE 3 /**< Pulse type */ +#define GRP_CONTROL 4 /**< Control type */ +#define GRP_SYSTEM 5 /**< System operation type */ +#define GRP_EVENT 6 /**< Protect event type */ +#define GRP_ALARM 7 /**< Alarm type */ +#define GRP_SETTING 8 /**< Fixed value type */ +#define GRP_STATUS 9 /**< State of device */ +#define GRP_VDI 10 /**< ѹ type */ +#define GRP_STEPPOS 11 /**< Step position type */ +#define GRP_COMBO 12 /**< combo/compute type */ +#define GRP_SIMANA 13 /**< ģ */ +#define GRP_SETAREA 14 /**< ֵ */ +#define GRP_ACCANA 15 /**< ¼ģ */ +#define GRP_ACCDGT 16 /**< ¼ */ +#define GRP_SETPOINT 18 /**< Set point type for 101,104 protocol used only */ +#define GRP_STEPCONTROL 19 /**< λõ */ + +/** ṹ */ +struct group_t { + uint32_t id; /**< Identification, Commond Address of Set */ + uint32_t flags; /**< Flags definiens */ + byte_t type; /**< Analogue/Digit/Control/Event/etc. */ + char name[LONGNAME]; /**< */ + uint16_t maxelems; /**< elementsĿ */ + element_t *elements; /**< Ԫض */ + + // runtime generate + uint16_t count; /**< ʵʰԪĿ */ + uint16_t index; /**< IED->groups± */ + value_t value; /**< 黺˳elementsʵʱֵ */ + ied_t *ied; /**< 豸 */ + apr_hash_t *htdots; /**< Ԫضϣ */ + + /* Extend property */ + void *sys_ext; /**< ϵͳչ,ɻʵ */ + void *app_ext; /**< Ӧչ,Ӧÿʵ */ + void *usr_ext; /**< ûչ,Ӧóʵ */ +}; + +//>>>>>>>>>>> %s \n", count, + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); + if (SEND_FLAG == 1) //kafka + { + my_kafka_send(data); + } + else if (SEND_FLAG == 2)//datahub + { + my_datahub_send(data); + //DataHub_Send_Datahub(); + } + else if (SEND_FLAG == 3)//rocketmqlnk10-11 + { + my_rocketmq_send(data); + } + else //δ Ĭmq + { + my_rocketmq_send(data); + } + + printf("END my_kafka_send no.%i -------->>>>>>>>>>>> %s \n\n", count++, + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); + } + + /*if (data_gotten) { + LD_info_t* LD_info = find_LD_info_only_from_mp_id(data.mp_id.toAscii().data()); + ied_t* ied; + ied = find_ied_from_dev_code(LD_info->terminal_code); + ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); + int cpuno; + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + data.mp_id.clear(); + data.mp_id.append(LD_info->mp_id); + + static uint32_t count = 0; + printf("BEGIN my_kafka_send no.%i -------->>>>>>>>>>>> %s \n", count, + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); + my_kafka_send(data); + printf("END my_kafka_send no.%i -------->>>>>>>>>>>> %s \n\n", count++, + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); + } + }*/ +//lnk 20241031 ټ¼ƥʡԡ쳣 +/* + oss_data_t ossdata; + bool oss_data_gotten; + + oss_data_gotten = false; + oss_data_list_mutex.lock(); + if (!oss_data_list.isEmpty()) { + oss_data_gotten = true; + ossdata = oss_data_list.takeFirst(); + } + oss_data_list_mutex.unlock(); + + if (oss_data_gotten) { + + char file_name[256]; + memset(file_name, 0, 256); + sprintf(file_name, "%s", ossdata.filename.toAscii().data()); + char save_name[256]; + memset(save_name, 0, 256); + sprintf(save_name, "%s", ossdata.savename.toAscii().data()); + QString uuid_file_name; + + std::ofstream file(save_name); // һļ󣬴ļ example.txt + if (file.is_open()) { // жļǷɹ + file << ossdata.data.toAscii().data() << "\n"; + file.close(); // رļ + } + else { + cout << "Unable to open file\n" << endl; + } + + if (FILE_FLAG == 1) { + PutOSS(file_name, save_name); + char* file; + // ʹstrrchrҵһ'/'λ + char* last_slash = strrchr(file_name, '/'); + if (last_slash != NULL) { + // һ'/'֮IJ־ļ + file = last_slash + 1; + } + else { + // û'/'ַļ + file = file_name; + } + concatenate_and_separate(file_name, file, &uuid_file_name); + } + else if (FILE_FLAG == 2) { + OBSFile(save_name, file_name, "putObject"); + char* file; + // ʹstrrchrҵһ'/'λ + char* last_slash = strrchr(file_name, '/'); + if (last_slash != NULL) { + // һ'/'֮IJ־ļ + file = last_slash + 1; + } + else { + // û'/'ַļ + file = file_name; + } + concatenate_and_separate(file_name, file, &uuid_file_name); + } + else if (FILE_FLAG == 3) { + char* fileName = (char*)malloc(65 * sizeof(char)); + char* uuid = (char*)malloc(65 * sizeof(char)); + WebAPI_Uds_Upload(UDS_UPLOAD_URL, save_name, uuid, fileName); + concatenate_and_separate(uuid, fileName, &uuid_file_name); + free(fileName); + free(uuid); + } + else { + + } +*/ +//lnk 20241031 ټ¼ƥʡԡ쳣 +/* + if (ossdata.log_name=="comm") { + char tnml_code[128]; + memset(tnml_code, 0, 128); + sprintf(tnml_code, "%s", ossdata.id.toAscii().data()); + errorlog_pgsql(tnml_code, ossdata.time, uuid_file_name); + } + else if (ossdata.log_name == "reason") { + QString pgsql; + pgsql.append(errorlog_num_pgsql(ossdata.id, ossdata.time, uuid_file_name, ossdata.list_num)); + cout << pgsql.toAscii().data() << endl; + } + else if (ossdata.log_name == "match") { + QString pqsql; + pqsql.append(errorlog_datamatch_pgsql(ossdata.id, ossdata.time, ossdata.base_mat_num, ossdata.adv_mat_num, ossdata.base_act_num, ossdata.adv_act_num, uuid_file_name)); + cout << pqsql.toAscii().data() << endl; + } + + + + std::remove(save_name); + } + else { + msleep(1); + }*/ + } //while(1) { + + + //߳̽ݻ + ShutdownAndDestroyProducer();//lnk20241211 +} + +//lnk20241213в/////////////////////////////////////////////////////////////////////////////////////////////// +// ȡ 'data' 鲢Ϊµ JSON ַ ( std::string) +std::string extractDataJson(const char* inputJson) { + // JSON ַ + cJSON* root = cJSON_Parse(inputJson); + if (root == NULL) { + std::cerr << "Error parsing JSON" << std::endl; + return ""; + } + + // ȡ "data" + cJSON* data = cJSON_GetObjectItem(root, "data"); + if (data == NULL || data->type != cJSON_Array) { + std::cerr << "'data' is missing or is not an array" << std::endl; + cJSON_Delete(root); + return ""; + } + + // µ JSON ֻ "data" + cJSON* newJson = cJSON_CreateArray(); // һµ + + // "data" еԪӵ + cJSON* dataItem = NULL; + cJSON_ArrayForEach(dataItem, data) { + cJSON_AddItemToArray(newJson, cJSON_Duplicate(dataItem, 1)); + } + + // µ JSON תΪַ + char* newJsonString = cJSON_Print(newJson); + if (newJsonString == NULL) { + std::cerr << "Error printing new JSON" << std::endl; + cJSON_Delete(root); + cJSON_Delete(newJson); + return ""; + } + + // תΪ std::string + std::string result(newJsonString); + + // ڴ + free(newJsonString); + cJSON_Delete(root); + cJSON_Delete(newJson); + + return result; // std::string ͵Ľ +} +//ʵʱݲ////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ȡ JSON Ϣеֶ +bool parseJsonMessageRT(const std::string& body, std::string& devSeries, std::string& line, bool& realData, bool& soeData, int& limit) +{ + // JSON + cJSON* root = cJSON_Parse(body.c_str()); + if (root == NULL) { + std::cerr << "Failed to parse JSON message." << std::endl; + return false; + } + + // ȡֶ + cJSON* devSeriesItem = cJSON_GetObjectItem(root, "devSeries"); + cJSON* lineItem = cJSON_GetObjectItem(root, "line"); + cJSON* realDataItem = cJSON_GetObjectItem(root, "realData"); + cJSON* soeDataItem = cJSON_GetObjectItem(root, "soeData"); + cJSON* limitItem = cJSON_GetObjectItem(root, "limit"); + + if (devSeriesItem && lineItem && realDataItem && soeDataItem && limitItem) { + devSeries = devSeriesItem->valuestring; + line = lineItem->valuestring; + realData = realDataItem->valueint; + soeData = soeDataItem->valueint; + limit = limitItem->valueint; + } else { + std::cerr << "Missing expected fields in JSON message." << std::endl; + cJSON_Delete(root); + return false; + } + + cJSON_Delete(root); // JSON + return true; +} + +// XML ݵĺ½ɾ +std::string createnewXmlContent(int devindex, int mpindex, bool realData, bool soeData, int limit) +{ + std::ostringstream xmlContent; + xmlContent << "\n" + << "\n" + << " \n" + << " \n" + << " \n" + << "\n"; + return xmlContent.str(); +} + +std::string createdeleteXmlContent(int devindex, int mpindex) +{ + std::ostringstream xmlContent; + xmlContent << "\n" + << "\n" + << " \n" + << " \n" + << " \n" + << "\n"; + return xmlContent.str(); +} + +// д XML ݵļĺ +bool writeToFile(const std::string& filePath, const std::string& xmlContent) +{ + // ļд XML + std::ofstream outFile(filePath.c_str()); // ʹ c_str() תΪ const char* + if (outFile.is_open()) { + outFile << xmlContent; // д + outFile.close(); + std::cout << "XML file created at: " << filePath << std::endl; + return true; + } else { + std::cerr << "Failed to open file for writing: " << filePath << std::endl; + return false; + } +} + +// дµ XML ļ +bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int limit,std::string type) +{ + std::string xmlContent = ""; + std::string directory = ""; + std::string filePath = ""; + + if(type == "new"){ + // XML + xmlContent = createnewXmlContent(devindex, mpindex, realData, soeData, limit); + + // ļ· + directory = "../etc/trigger3s/"; + filePath = directory + "newtrigger.xml"; + } + else if(type == "delete"){ + // XML + xmlContent = createdeleteXmlContent(devindex, mpindex); + + // ļ· + directory = "../etc/trigger3s/"; + filePath = directory + "deletetrigger.xml"; + } + else{ + std::cerr << "Failed to create xmlfile,type error: " << std::endl; + return false; + } + + + // Ŀ¼ڣ + if (system(("mkdir -p " + directory).c_str()) != 0) { + std::cerr << "Failed to create directory: " << directory << std::endl; + return false; + } + + // XML дļ + return writeToFile(filePath, xmlContent); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +//lnk20250108̸² + +// ڹرս̼Ķ˿ +extern int server_socket; //Web Socketʵ +void close_listening_socket() { + if (server_socket != -1) { + // رsocket + close(server_socket); + std::cout << "Server socket closed successfully!" << std::endl; + server_socket = -1; // server_socket + } else { + std::cout << "No server socket to close!" << std::endl; + } +} + +//ִнűƽ +void execute_bash(string fun,int process_num,string type) +{ + // Ϊ char 㹻Ŀռ + char p_num_str[20]; + // ʹ sprintf ת + std::sprintf(p_num_str, "%d", process_num); + const char* script = "/FeProject/bin/set_process.sh";//ʹsetsidֹ˿ռ + const char* param1 = fun.c_str(); + const char* param2 = p_num_str; + const char* param3 = type.c_str(); + + // + char command[256]; + snprintf(command, sizeof(command), "%s %s %s %s &", script, param1, param2, param3); + + std::cout << "command:" << command <valueint; + string index_value_str = index->valuestring; + int index_value = StringToInt(index_value_str); + + //̺Ϊ0Ľ̴̨˸Ϣ + if (index_value != g_front_seg_index && g_front_seg_index !=0) { + std::cout << "msg index:"<< index_value <<"doesnt match self index:" << g_front_seg_index << std::endl; + cJSON_Delete(root); + return; + } + + //̺Ϊ0߽̺ƥ + std::cout << "msg index:"<< index_value <<" self index:" << g_front_seg_index << std::endl; + + // code ִֵֶвͬĽ߼ + std::string code_str = code->valuestring; + + if (code_str == "set_process") { + + if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){ + std::cout << "cfg_stat_data process" << g_front_seg_index <<" handle this msg" << std::endl; + // set_process + cJSON* data = cJSON_GetObjectItem(root, "data"); + if (data != nullptr && data->type == cJSON_Array) { + int data_size = cJSON_GetArraySize(data); + for (int i = 0; i < data_size; i++) { + cJSON* item = cJSON_GetArrayItem(data, i); + + std::string fun = cJSON_GetObjectItem(item, "fun")->valuestring; + int processNum = cJSON_GetObjectItem(item, "processNum")->valueint; + std::string frontType = cJSON_GetObjectItem(item, "frontType")->valuestring; + + //У + if((fun == "reset" || fun == "add") && + (processNum >=1 && processNum < 10) && + (frontType == "stat" || frontType == "recall" || frontType == "all")){ + // ִнű + if(fun == "reset"){ + close_listening_socket(); + } + execute_bash(fun, processNum, frontType); + std::cout << "!!!!!!!!!!!!!!!! execute mark:" << i << " !!!!!!!!!!!!!!!" <" << std::endl; + indentLevel++; + + if (code_str == "ledger_modify" || code_str == "add_terminal") { + + // modify + if (code_str == "ledger_modify") { + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel++; + } + else { + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel++; + } + + // ݲ + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel++; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.terminal_id << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.addr_str << "" << std::endl; // Assuming `addr_str` for IP + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.dev_type << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.maint_name << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.org_name << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.port << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.station_name << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.terminal_code << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.timestamp << "" << std::endl; // Assuming `timestamp` + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.tmnl_factory << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.tmnl_status << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.dev_series << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.dev_key << "" << std::endl; + + // monitorData + for (int i = 0; json_data.line[i].monitor_id[0] != '\0'; i++) { + const monitor& monitor = json_data.line[i]; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel++; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.monitor_id << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.monitor_name << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.logical_device_seq << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.voltage_level << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.terminal_connect << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.timestamp << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.terminal_code << "" << std::endl; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << monitor.status << "" << std::endl; + + indentLevel--; + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + } + + indentLevel--; + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + + // modify add ǩ + if (code_str == "ledger_modify") { + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel--; + } + else { + add_indent(xmlStream, indentLevel); + xmlStream << "
" << std::endl; + indentLevel--; + } + + } else if (code_str == "delete_terminal") { + // delete + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel++; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + indentLevel++; + + add_indent(xmlStream, indentLevel); + xmlStream << "" << json_data.terminal_id << "" << std::endl; + + indentLevel--; + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + + indentLevel--; + add_indent(xmlStream, indentLevel); + xmlStream << "" << std::endl; + } + else { + std::cerr << "code_str error" << std::endl; + return ""; + } + + // ڵ + indentLevel--; + add_indent(xmlStream, indentLevel); + xmlStream << "
" << std::endl; + + return xmlStream.str(); // ع XML ַ +} + +// stringַתΪ +int StringToInt(const std::string& str) { + std::stringstream ss(str); + int number; + ss >> number; // ַжȡ + + // Ƿתɹ + if (ss.fail()) { + std::cerr << "Conversion failed!" << std::endl; + return 0; // ѡ񷵻һʶʧֵܵ-1 + } + return number; +} + +// JSON ִַӦ +void parse_control(const std::string& json_str, const std::string& output_dir) { + // JSON ַ + cJSON* root = cJSON_Parse(json_str.c_str()); + if (root == nullptr) { + std::cout << "Error parsing JSON." << std::endl; + return; + } + + // ȡ code ֶ + cJSON* code = cJSON_GetObjectItem(root, "code"); + if (code == nullptr) { + std::cout << "Missing 'code' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + cJSON* index = cJSON_GetObjectItem(root, "index"); + if (index == nullptr) { + std::cout << "Missing 'index' in JSON." << std::endl; + cJSON_Delete(root); + return; + } + + //жDzԼ̺ţ + //int index_value = index->valueint; + string index_value_str = index->valuestring; + int index_value = StringToInt(index_value_str); + + //̺Ϊ0Ľ̴̨˸Ϣ + if (index_value != g_front_seg_index && g_front_seg_index !=0) { + std::cout << "msg index:"<< index_value <<"doesnt match self index:" << g_front_seg_index << std::endl; + cJSON_Delete(root); + return; + } + + //̺Ϊ0߽̺ƥ + std::cout << "msg index:"<< index_value <<" self index:" << g_front_seg_index << std::endl; + + // code ִֵֶвͬĽ߼ + std::string code_str = code->valuestring; + + if (code_str == "add_terminal" || code_str == "ledger_modify") { + + std::cout << "add or update ledger" <type == cJSON_Array) { + int data_size = cJSON_GetArraySize(data); + for (int i = 0; i < data_size; i++) { + cJSON* item = cJSON_GetArrayItem(data, i); + + terminal json_data; + // terminal_dev + cJSON* id = cJSON_GetObjectItem(item, "id"); // terminal_id + if (id && id->type == cJSON_String) + std::strncpy(json_data.terminal_id, id->valuestring, sizeof(json_data.terminal_id) - 1); + else + std::strncpy(json_data.terminal_id, "N/A", sizeof(json_data.terminal_id) - 1); + + cJSON* name = cJSON_GetObjectItem(item, "name"); // terminal_code + if (name && name->type == cJSON_String) + std::strncpy(json_data.terminal_code, name->valuestring, sizeof(json_data.terminal_code) - 1); + else + std::strncpy(json_data.terminal_code, "N/A", sizeof(json_data.terminal_code) - 1); + + cJSON* org_name = cJSON_GetObjectItem(item, "org_name"); // org_name + if (org_name && org_name->type == cJSON_String) + std::strncpy(json_data.org_name, org_name->valuestring, sizeof(json_data.org_name) - 1); + else + std::strncpy(json_data.org_name, "N/A", sizeof(json_data.org_name) - 1); + + cJSON* maint_name = cJSON_GetObjectItem(item, "maint_name"); // maint_name + if (maint_name && maint_name->type == cJSON_String) + std::strncpy(json_data.maint_name, maint_name->valuestring, sizeof(json_data.maint_name) - 1); + else + std::strncpy(json_data.maint_name, "N/A", sizeof(json_data.maint_name) - 1); + + cJSON* station_name = cJSON_GetObjectItem(item, "stationName"); // station_name + if (station_name && station_name->type == cJSON_String) + std::strncpy(json_data.station_name, station_name->valuestring, sizeof(json_data.station_name) - 1); + else + std::strncpy(json_data.station_name, "N/A", sizeof(json_data.station_name) - 1); + + cJSON* manufacturer = cJSON_GetObjectItem(item, "manufacturer"); // tmnl_factory + if (manufacturer && manufacturer->type == cJSON_String) + std::strncpy(json_data.tmnl_factory, manufacturer->valuestring, sizeof(json_data.tmnl_factory) - 1); + else + std::strncpy(json_data.tmnl_factory, "N/A", sizeof(json_data.tmnl_factory) - 1); + + cJSON* status = cJSON_GetObjectItem(item, "status"); // tmnl_status + if (status && status->type == cJSON_String) + std::strncpy(json_data.tmnl_status, status->valuestring, sizeof(json_data.tmnl_status) - 1); + else + std::strncpy(json_data.tmnl_status, "N/A", sizeof(json_data.tmnl_status) - 1); + + cJSON* dev_type = cJSON_GetObjectItem(item, "devType"); // dev_type + if (dev_type && dev_type->type == cJSON_String) + std::strncpy(json_data.dev_type, dev_type->valuestring, sizeof(json_data.dev_type) - 1); + else + std::strncpy(json_data.dev_type, "N/A", sizeof(json_data.dev_type) - 1); + + cJSON* dev_key = cJSON_GetObjectItem(item, "devKey"); // dev_key + if (dev_key && dev_key->type == cJSON_String) + std::strncpy(json_data.dev_key, dev_key->valuestring, sizeof(json_data.dev_key) - 1); + else + std::strncpy(json_data.dev_key, "N/A", sizeof(json_data.dev_key) - 1); + + cJSON* dev_series = cJSON_GetObjectItem(item, "series"); // dev_series + if (dev_series && dev_series->type == cJSON_String) + std::strncpy(json_data.dev_series, dev_series->valuestring, sizeof(json_data.dev_series) - 1); + else + std::strncpy(json_data.dev_series, "N/A", sizeof(json_data.dev_series) - 1); + + cJSON* ip = cJSON_GetObjectItem(item, "ip"); // addr_str + if (ip && ip->type == cJSON_String) + std::strncpy(json_data.addr_str, ip->valuestring, sizeof(json_data.addr_str) - 1); + else + std::strncpy(json_data.addr_str, "N/A", sizeof(json_data.addr_str) - 1); + + cJSON* port = cJSON_GetObjectItem(item, "port"); // port + if (port && port->type == cJSON_String) + std::strncpy(json_data.port, port->valuestring, sizeof(json_data.port) - 1); + else + std::strncpy(json_data.port, "N/A", sizeof(json_data.port) - 1); + + cJSON* updateTime = cJSON_GetObjectItem(item, "updateTime"); // timestamp + if (updateTime && updateTime->type == cJSON_String) + std::strncpy(json_data.timestamp, updateTime->valuestring, sizeof(json_data.timestamp) - 1); + else + std::strncpy(json_data.timestamp, "N/A", sizeof(json_data.timestamp) - 1); + + // monitorData 䵽 line + cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData"); + if (monitorData != nullptr && monitorData->type == cJSON_Array) { + int monitorData_size = cJSON_GetArraySize(monitorData); + + for (int j = 0; j < monitorData_size && j < 10; j++) { // 10 + cJSON* monitor_item = cJSON_GetArrayItem(monitorData, j); + monitor monitor_data; + + cJSON* monitor_id = cJSON_GetObjectItem(monitor_item, "id"); // monitor_id + if (monitor_id && monitor_id->type == cJSON_String) + std::strncpy(monitor_data.monitor_id, monitor_id->valuestring, sizeof(monitor_data.monitor_id) - 1); + else + std::strncpy(monitor_data.monitor_id, "N/A", sizeof(monitor_data.monitor_id) - 1); + + cJSON* monitor_name = cJSON_GetObjectItem(monitor_item, "name"); // monitor_name + if (monitor_name && monitor_name->type == cJSON_String) + std::strncpy(monitor_data.monitor_name, monitor_name->valuestring, sizeof(monitor_data.monitor_name) - 1); + else + std::strncpy(monitor_data.monitor_name, "N/A", sizeof(monitor_data.monitor_name) - 1); + + cJSON* voltage_level = cJSON_GetObjectItem(monitor_item, "voltageLevel"); // voltage_level + if (voltage_level && voltage_level->type == cJSON_String) + std::strncpy(monitor_data.voltage_level, voltage_level->valuestring, sizeof(monitor_data.voltage_level) - 1); + else + std::strncpy(monitor_data.voltage_level, "N/A", sizeof(monitor_data.voltage_level) - 1); + + cJSON* monitor_status = cJSON_GetObjectItem(monitor_item, "status"); // status + if (monitor_status && monitor_status->type == cJSON_String) + std::strncpy(monitor_data.status, monitor_status->valuestring, sizeof(monitor_data.status) - 1); + else + std::strncpy(monitor_data.status, "N/A", sizeof(monitor_data.status) - 1); + + cJSON* lineNo = cJSON_GetObjectItem(item, "lineNo"); // logical_device_seq + if (lineNo && lineNo->type == cJSON_String) + std::strncpy(monitor_data.logical_device_seq, lineNo->valuestring, sizeof(monitor_data.logical_device_seq) - 1); + else + std::strncpy(monitor_data.logical_device_seq, "N/A", sizeof(monitor_data.logical_device_seq) - 1); + + cJSON* ptType = cJSON_GetObjectItem(item, "ptType"); // terminal_connect + if (ptType && ptType->type == cJSON_String) + std::strncpy(monitor_data.terminal_connect, ptType->valuestring, sizeof(monitor_data.terminal_connect) - 1); + else + std::strncpy(monitor_data.terminal_connect, "N/A", sizeof(monitor_data.terminal_connect) - 1); + + std::strncpy(monitor_data.timestamp, json_data.timestamp, sizeof(monitor_data.timestamp) - 1); + std::strncpy(monitor_data.terminal_code, json_data.terminal_code, sizeof(monitor_data.terminal_code) - 1); + // 䵽 line + json_data.line[j] = monitor_data; + + } + } + + // ׼ XML ݲдļ + std::string xmlContent = prepare_update(code_str, json_data); + if (xmlContent != "") { + + std::cout << "write to xml in /FeProject/etc/ledger_update" <type == cJSON_Array) { + int data_size = cJSON_GetArraySize(data); + for (int i = 0; i < data_size; i++) { + cJSON* item = cJSON_GetArrayItem(data, i); + + // ֻ id ֶ + cJSON* id = cJSON_GetObjectItem(item, "id"); + if (id != nullptr) { + terminal json_data; + std::strncpy(json_data.terminal_id, cJSON_GetObjectItem(item, "id")->valuestring, sizeof(json_data.terminal_id) - 1); + // ׼ XML ݲдļ + std::string xmlContent = prepare_update(code_str, json_data); + if(xmlContent != ""){ + char nodeid[20]; + std::sprintf(nodeid, "%u", g_node_id); // "%u" unsigned int + std::string nodeid_str(nodeid); + + std::string frontindex_str = intToString(g_front_seg_index); + + std::string file_name = output_dir + "/" + nodeid_str + "_" + frontindex_str + "_" + json_data.terminal_id + "_delete_terminal.xml"; + writeToFile(file_name, xmlContent); + } + } + } + } + } + else{ + std::cout << "code_str error" <n_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = (ied_usr_t*)ied->usr_ext; + if (ied_usr && strcmp(ied_usr->terminal_id, dev_id.c_str()) == 0) { + return ied_usr->dev_idx; + } + + } + return 0; +} + +int find_mp_index_from_mp_id(std::string line) +{ + LD_info_t* LD_info = NULL; + LD_info = find_LD_info_only_from_mp_id((char*)line.c_str()); + if(LD_info == NULL){ + return 0; + } + else{ + return LD_info->line_id; + } + +} + +int myMessageCallbackrtdata(CPushConsumer* consumer, CMessageExt* msg) +{ + if (msg == NULL) { + std::cerr << "Received null message." << std::endl; + return E_RECONSUME_LATER; + } + + const char* body = GetMessageBody(msg); + const char* key = GetMessageKeys(msg); + + if (body == NULL) { + std::cerr << "Message body is NULL." << std::endl; + return E_RECONSUME_LATER; + } + else{ + + // Ϣ磬ӡϢݣ + std::cout << "rt data Callback received message: " << body << std::endl; + if (key) { + std::cout << "Message Key: " << key << std::endl; + } + else { + std::cout << "Message Key: N/A" << std::endl; + } + + // + std::string devid, line; + bool realData, soeData; + int limit; + // JSON + if (!parseJsonMessageRT(body, devid, line, realData, soeData, limit)) { + std::cerr << "Failed to parse the JSON message." << std::endl; + return E_RECONSUME_LATER; + } + + //mqʵʱָѯ̨ʱ + pthread_mutex_lock(&mtx); + + int dev_index = find_dev_index_from_dev_id(devid); + int mp_index = find_mp_index_from_mp_id(line); + + pthread_mutex_unlock(&mtx); + + if(dev_index == 0 || mp_index == 0){ + std::cerr << "dev index or mp index is 0" << std::endl; + return E_RECONSUME_LATER; + } + // XML ļ + if (!createXmlFile(dev_index, mp_index, realData, soeData, limit,"new")) { + std::cerr << "Failed to create the XML file." << std::endl; + return E_RECONSUME_LATER; + } + + } + + // ҵ߼״̬ + return E_CONSUME_SUCCESS; +} + +int myMessageCallbackupdate(CPushConsumer* consumer, CMessageExt* msg) +{ + if (msg == NULL) { + std::cerr << "Received null message." << std::endl; + return E_RECONSUME_LATER; + } + + const char* body = GetMessageBody(msg); + const char* key = GetMessageKeys(msg); + + if (body == NULL) { + std::cerr << "Message body is NULL." << std::endl; + return E_RECONSUME_LATER; + } + else{ + // + // Ϣ磬ӡϢݣ + std::cout << "ledger update Callback received message: " << body << std::endl; + if (key) { + std::cout << "Message Key: " << key << std::endl; + } + else { + std::cout << "Message Key: N/A" << std::endl; + } + + //̨˸Ϣ + std::string updatefilepath = "/home/pq/FeProject/etc/ledgerupdate"; + parse_control(body,updatefilepath); + + } + + // ҵ߼״̬ + return E_CONSUME_SUCCESS; +} + +int myMessageCallbackset(CPushConsumer* consumer, CMessageExt* msg) +{ + if (msg == NULL) { + std::cerr << "Received null message." << std::endl; + return E_RECONSUME_LATER; + } + + const char* body = GetMessageBody(msg); + const char* key = GetMessageKeys(msg); + + if (body == NULL) { + std::cerr << "Message body is NULL." << std::endl; + return E_RECONSUME_LATER; + } + else{ + // + // Ϣ磬ӡϢݣ + std::cout << "process Callback received message: " << body << std::endl; + if (key) { + std::cout << "Message Key: " << key << std::endl; + } + else { + std::cout << "Message Key: N/A" << std::endl; + } + + //̸Ϣ + parse_set(body); + + } + + // ҵ߼״̬ + return E_CONSUME_SUCCESS; +} + +int myMessageCallbackrecall(CPushConsumer* consumer, CMessageExt* msg) +{ + // + std::cout << "myMessageCallbackrecall"<< std::endl; + + if (msg == NULL) { + std::cerr << "Received null message." << std::endl; + return E_RECONSUME_LATER; + } + + const char* body = GetMessageBody(msg); + const char* key = GetMessageKeys(msg); + + if (body == NULL) { + std::cerr << "Message body is NULL." << std::endl; + return E_RECONSUME_LATER; + } + else{ + // Ϣ磬ӡϢݣ + std::cout << "recall Callback received message: " << body << std::endl; + if (key) { + std::cout << "Message Key: " << key << std::endl; + } + else { + std::cout << "Message Key: N/A" << std::endl; + } + // + std::string result = extractDataJson(body); // ʹ std::string malloc + + // + std::cout << "extractDataJson:"<< result.c_str() < subscriptions; + // ʼ1 //lnk20241230ֻʵʱ̻ᶩʵʱtopicʵʱtopicĽ޷ʵʱ + if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID){ + subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_RT, G_MQCONSUMER_TAG_RT, myMessageCallbackrtdata)); + } + + // ʼ2 //н̶ᶩ̨˸topic̵̨ͬܽ˲ܻӰ + subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_UD, G_MQCONSUMER_TAG_UD, myMessageCallbackupdate)); + + // ʼ3 //lnk20241230ֻвн̻ᶩIJtopicIJtopicĽ޷ + if(g_node_id == RECALL_HIS_DATA_BASE_NODE_ID){ + subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_RC, G_MQCONSUMER_TAG_RC, myMessageCallbackrecall)); + } + + // ʼ4 //lnk20250108ֻ̬1ᶩĿtopicĿtopicĽ޷ + if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){ + subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_SET, G_MQCONSUMER_TAG_SET, myMessageCallbackset)); + } + + try { + rocketmq_consumer_receive(consumerName, nameServer, subscriptions); + } + catch (const std::exception& e) { + std::cerr << "Exception during consumerUD setup: " << e.what() << std::endl; + } + + // У߻ͨصϢ + + // ģ + std::cout << "Consumer is running. " << std::endl; + + //̵߳ + //ShutdownAndDestroyConsumer(); +} + +//CZY 2023-08-23 get double class voltage level, if false will return 0; +double get_voltage_level(char voltage_level_char[]) { + try + { + int n = atoi(voltage_level_char); + + switch (n) + { + case 1://6V + return 0.006; + case 2://12V + return 0.012; + case 3://24V + return 0.024; + case 4://36V + return 0.036; + case 5://48V + return 0.048; + case 6://110V + return 0.11; + case 7://220V + return 0.22; + case 8://380V400V + return 0.38; + case 9://660V + return 0.66; + case 10://1000V1140V + return 1; + case 11://600V + return 0.6; + case 12://750V + return 0.75; + case 13://1500V + return 1.5; + case 14://2000V + return 2.0; + case 15://2500V + return 2.5; + case 20://3kV + return 3; + case 21://6kV + return 6; + case 22://10kV + return 10; + case 23://15.75kV + return 15.75; + case 24://20kV + return 20; + case 25://35kV + return 35; + case 30://66kV + return 66; + case 31://72.5kV + return 72.5; + case 32://110kV + return 110; + case 33://220kV + return 220; + case 34://330kV + return 330; + case 35://500kV + return 500; + case 36://750kV + return 750; + case 37://1000kV + return 1000; + case 51://ֱ6V + return 0.006; + case 52://ֱ12V + return 0.012; + case 53://ֱ24V + return 0.024; + case 54://ֱ36V + return 0.036; + case 55://ֱ48V + return 0.048; + case 56://ֱ110V + return 0.11; + case 60://ֱ220V + return 0.22; + case 70://ֱ600V + return 0.6; + case 71://ֱ750V + return 0.75; + case 72://ֱ1500V + return 1.5; + case 73://ֱ3000V + return 3.0; + case 76://ֱ35kV + return 35; + case 77://ֱ30kV + return 30; + case 78://ֱ50kV + return 50; + case 80://ֱ120kV + return 120; + case 81://ֱ125kV + return 125; + case 82://ֱ400kV + return 400; + case 83://ֱ500kV + return 500; + case 84://ֱ660kV + return 660; + case 85://ֱ800kV + return 800; + case 86://ֱ1000kV + return 1000; + case 87://ֱ200kV + return 200; + case 88://ֱ320kV + return 320; + default: + return 0; + break; + } + + } + catch (const std::exception&) + { + //error + return 0; + } +} + +void try_start_kafka_thread() +{ + static int kafka_thread_created = 0; + if (!kafka_thread_created) { + myThrd.start(); + kafka_thread_created = 1; + } +} + +//lnk20241213 +void try_start_mqconsumer_thread() +{ + static int mqconsumer_thread_created = 0; + if (!mqconsumer_thread_created) { + mqconsumerThrd.start(); + mqconsumer_thread_created = 1; + } +} + +///////////////////////////////////////////////////////////////////////// +json_block_data json_blkd; + +//void init_json_block_data() +//{ +// json_blkd.monitorId = -1; +// json_blkd.func_type = g_node_id; +// //flag Ʒʣ 쳣1 0 +// json_blkd.flag = 0; // //޳ǣ1޳0޳Ĭ޳ +// json_blkd.mms_str_map.clear(); +//} + +//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ +//json_block_data json_blkd; //jsonƴӲ,ԭеһݶڶICD»ݴλ +//ǽݷLDInfoṹд洢֤һ·һjsonƴӲ +void init_json_block_data(char mp_id[], char voltage_level[], int flicker_flag)//WW 202331316:38:41 ICD޸ +{ + // char[] תΪ std::string + //QString keyString(mp_id); + + json_block_data* pdata; + if (flicker_flag == 1) { + if (!json_flicker_data_map.contains(mp_id)) + { + pdata = new json_block_data(); + json_flicker_data_map.insert(mp_id, pdata); + } + pdata = json_flicker_data_map.value(mp_id); + } + else if (flicker_flag == 0) { + if (!json_data_map.contains(mp_id)) + { + pdata = new json_block_data(); + json_data_map.insert(mp_id, pdata); + } + pdata = json_data_map.value(mp_id); + } + else if (flicker_flag == 2) { + if (!json_pst_data_map.contains(mp_id)) + { + pdata = new json_block_data(); + json_pst_data_map.insert(mp_id, pdata); + } + pdata = json_pst_data_map.value(mp_id); + } + + if (pdata == NULL) + return; + pdata->monitorId = -1; + QString tmp; + tmp.append(mp_id); + pdata->mp_id = tmp; + pdata->func_type = g_node_id; + //flag Ʒʣ 쳣1 0 + pdata->flag = 0; // //޳ǣ1޳0޳Ĭ޳ + pdata->mms_str_map.clear(); + pdata->voltage_level = get_voltage_level(voltage_level); //CZY 2023-08-23 add voltage_level +} + +//0. jsonɿʼ +//int json_block_create_start(int MonitorId ) +//{ +// try_start_kafka_thread(); +// +// init_json_block_data(); +// json_blkd.monitorId = MonitorId; +// printf("\n\n---------- json_block_create_start: MonitorId=%d \n",MonitorId); +// return TRUE; +//} + +int json_block_create_start(char voltage_level[], char monid_char[], int flicker_flag, char temcode[], int line_id)//WW 202331316:38 : 41 ICD޸ +{ + try_start_kafka_thread(); + //WW 2023-08-22 ݿ߳ + //try_start_sql_thread();//lnk2024118Ҫsql߳ + //WW end + + init_json_block_data(monid_char, voltage_level, flicker_flag); + json_block_data* pdata; + if (flicker_flag == 1) { + if (!json_flicker_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_flicker_data_map.value(monid_char); + } + else if (flicker_flag == 0) + { + if (!json_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_data_map.value(monid_char); + } + else if (flicker_flag == 2) + { + if (!json_pst_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_pst_data_map.value(monid_char); + } + + if (pdata != NULL) + { + pdata->dev_type.append(temcode); + pdata->monitorId = line_id; + if (strlen(monid_char) != 0) { + QString tmp; + tmp.append(monid_char); + pdata->mp_id = tmp; + } + else { + monid_char = "not define"; + QString tmp; + tmp.append(monid_char); + pdata->mp_id = tmp; + } + } + + printf("\n\n---------- json_block_create_start: mp_id=%s,voltage_level=%s,line_id=%d \n", monid_char, voltage_level, line_id); + return TRUE; +} + +//1. jsonɿʼ +//int json_block_create_time(int MonitorId , long long Time) +//{ +// json_blkd.time = Time; +// printf("\njson_block_create_time: MonitorId=%d,Time=%lld \n",MonitorId,Time); +// return TRUE; +//} +int json_block_create_time(char monid_char[], long long Time, int flicker_flag)//WW 202331316:38:41 ICD޸ +{ + json_block_data* pdata; + if (flicker_flag == 1) { + if (!json_flicker_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_flicker_data_map.value(monid_char); + } + else if (flicker_flag == 0) + { + if (!json_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_data_map.value(monid_char); + } + else if (flicker_flag == 2) + { + if (!json_pst_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_pst_data_map.value(monid_char); + } + + if (pdata != NULL) + pdata->time = Time; + printf("\njson_block_create_time: mp_id=%s,Time=%lld \n", monid_char, Time); + return TRUE; +} + +//int json_block_create_flag(int MonitorId , int flag) +//{ +// json_blkd.flag = flag; +// printf("\njson_block_create_flag: MonitorId=%d,flag=%d \n",MonitorId,flag); +// return TRUE; +//} + +int json_block_create_flag(char monid_char[], int flag, int flicker_flag)//WW 202331316:38:41 ICD޸ +{ + json_block_data* pdata; + if (flicker_flag == 1) { + if (!json_flicker_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_flicker_data_map.value(monid_char); + } + else if (flicker_flag == 0) + { + if (!json_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_data_map.value(monid_char); + } + else if (flicker_flag == 2) + { + if (!json_pst_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_pst_data_map.value(monid_char); + } + + if (pdata != NULL) + pdata->flag = flag; + printf("\njson_block_create_flag: mp_id=%s,flag=%d \n", monid_char, flag); + return TRUE; +} + +//2. jsonݻص +//int json_block_create_data(int MonitorId , char* mms_str , double v ) +//{ +// static int count = 0; +// //WW2023-08-16 ȥlogע +// //printf("#"); +// //if ( ((count++ %1000)==0) || (count <2000) ) +// // printf("\n%d:json_block_create_data: MonitorId=%d,mms_str=%s,v=%f \n",count,MonitorId,mms_str,v); +// +// json_blkd.mms_str_map.insert(QString::fromAscii(mms_str), v); +// return TRUE; +//} + +int json_block_create_data(char monid_char[], char* mms_str, double v, int flicker_flag)//WW 202331316:38:41 ICD޸ +{ + json_block_data* pdata; + if (flicker_flag == 1) { + if (!json_flicker_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_flicker_data_map.value(monid_char); + } + else if (flicker_flag == 0) + { + if (!json_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_data_map.value(monid_char); + } + else if (flicker_flag == 2) + { + if (!json_pst_data_map.contains(monid_char))//δ鵽 + return 0; + pdata = json_pst_data_map.value(monid_char); + } + + static int count = 0; + if (pdata != NULL) + { + pdata->mms_str_map.insert(QString::fromAscii(mms_str), v); + if (strstr(mms_str, "MMXU2$MX$PhV")) + printf("---------- json_block_create_data: mp_id= %s ,mms_str=%s value=%fkV----------\n", monid_char, mms_str, v); + } + return TRUE; +} + +//3. jsonɽ +//int json_block_create_end(int MonitorId ) +//{ +// printf("\n---------- json_block_create_end: MonitorId=%d \n\n\n",MonitorId); +// +// return transfer_json_block_data(&json_blkd); +//} + +int json_block_create_end(char monid_char[], int flicker_flag)//WW 202331316:38:41 ICD޸ +{ + json_block_data* pdata; + if (flicker_flag == 1) { + if (!json_flicker_data_map.contains(monid_char))//δ鵽 + { + printf("---------- json_block_create_end: mp_id= %s json_flicker_data_map can't find MonitorId----------\n", monid_char); + return 1; + } + pdata = json_flicker_data_map.value(monid_char); + } + else if (flicker_flag == 0) + { + if (!json_data_map.contains(monid_char))//δ鵽 + { + printf("---------- json_block_create_end: mp_id= %s json_data_map can't find MonitorId----------\n", monid_char); + return 1; + } + pdata = json_data_map.value(monid_char); + } + else if (flicker_flag == 2) + { + if (!json_pst_data_map.contains(monid_char))//δ鵽 + { + printf("---------- json_block_create_end: mp_id= %s json_pst_data_map can't find MonitorId----------\n", monid_char); + return 1; + } + pdata = json_pst_data_map.value(monid_char); + } + + + //int ret = transfer_json_block_data(pdata, DevKind);//CZY 2023-08-17 Ҫ + if (pdata->mms_str_map.count() == 0) { + if (flicker_flag == 1) { + json_flicker_data_map.remove(monid_char); + } + else if (flicker_flag == 0) + { + json_data_map.remove(monid_char); + + } + else if (flicker_flag == 2) + { + json_pst_data_map.remove(monid_char); + + } + printf("---------- json_block_create_end: pdata->mms_str_map.count() == 0 ----------\n"); + return 1; + } + int ret = transfer_json_block_data(pdata); + + if (pdata != NULL) + delete pdata; + if (flicker_flag == 1) { + json_flicker_data_map.remove(monid_char); + } + else if (flicker_flag == 0) + { + json_data_map.remove(monid_char); + + } + else if (flicker_flag == 2) + { + json_pst_data_map.remove(monid_char); + + } + printf("---------- json_block_create_end: MonitorId= %s ----------\n", monid_char); + return ret; +} + +//#define STATUS_NORMAL 0 /**< */ +//ƴKafka Producer̬¼Ϣ +//{"DATA_TYPE":"03", "TIME":"1542960911734", "1268918860":["CommResume"]} +void prcess_monitor_comm_2_json(int monitor_id, int status, long long tm) +{ + Ckafka_data_t data; + QString status_str = (status == 0) ? "CommResume" : "CommInterrupt"; + + try_start_kafka_thread(); + + data.monitor_id = monitor_id; + data.strTopic = "RTDATASOE"; + data.strText = QString("{\"DATA_TYPE\":\"03\", \"TIME\":\"%1\", \"%2\":[\"%3\"]}") + .arg(tm).arg(monitor_id).arg(status_str); + //ʱ̣ //װ 1268918860 + QString str = data.strTopic + " " + data.strText; + printf("prcess_monitor_comm_2_json: %s \n", str.toStdString().c_str()); + + kafka_data_list_mutex.lock(); + kafka_data_list.append(data); + kafka_data_list_mutex.unlock(); +} +////////////////////////////////////////////////////////////////////////////// + +//int transfer_json_block_data(json_block_data *data) +//{ +// Ckafka_data_t kafka_data; +// kafka_data.patition_id = 0; +// kafka_data.strText = QString("Time=%1").arg(data->time); +// +// kafka_data_list_mutex.lock(); +// kafka_data_list.append(kafka_data); +// kafka_data_list_mutex.unlock(); +// return TRUE; +//} + +void clear_old_comtrade_files() +{ + if (g_node_id != SOE_COMTRADE_BASE_NODE_ID) + return; + + QString full_fn_str; + QString dir_name("../comtrade/"); + QDir directory_comtrade(dir_name); + QStringList fileNames = directory_comtrade.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Time); + + if (fileNames.size() <= comtrade_remain_file_num) + return; + + for (QStringList::size_type i = comtrade_remain_file_num; i != fileNames.size(); ++i) { + full_fn_str = dir_name + fileNames.at(i); + QFile::remove(full_fn_str); + } +} + + + + +///////////////////////////////////////////// + +//using namespace std; +int process_login_verify() +{ + int length = 64; + char password[64 + 1]; + char* p = NULL; + int count = 0; + char encode_password[256]; + //password = "njcnpqs@2018" + const char* passwordConfirm = "1c0e4e104de596846648ba495bd32601"; + + memset(password, 0, sizeof(password)); + printf("Please input password : \n"); + p = password; + count = 0; + + system("stty -echo"); + std::cin.getline(password, 64); + system("stty echo"); + //while (((*p = getch()) != 13) && count < length) { + // //putch('*'); + // //fflush(stdin); + + // p++; + // count++; + //} + password[length] = '\0'; + //printf("input typed password : %s \n",password); + + MyGetSM4Code(password, (unsigned char*)"epri.sgcc.com.cn", encode_password); + + //printf("encode_password : %s ,should be %s \n",encode_password,passwordConfirm); + return (strcmp(encode_password, passwordConfirm)); + + +} + + +//////////////////////////////////////////// + +/////////////////////////////////////////// +//WW 2023-08-22 ݿ̺߳WebSokcet߳ + +void SQLExcuteThread::run() +{ + //if (THREE_SECS_DATA_BASE_NODE_ID == g_node_id)//3ݴ䲻Ҫд + //return; + + if (1 != g_iOTLFlag) { + Sql_data_list.clear(); + return; + } + + static uint32_t connect_state = 0; + static uint32_t sql_count = 0;//2024-04-01 + const char* pSql = nullptr; + printf("SqlExcuteThread::run() is called ...... \n\n"); + + while (1) + { + msleep(1); + if (!Sql_data_list.isEmpty()) + { + if (0 == sql_count++ % 300) + { + //db.connected + int rtState = OTLDbconnected(); + //int rtState = db.connected; + if (rtState == 0 || connect_state != 0) { + OTLDisconnect(); + int ret = OTLConnect(); + if (ret != 0 && ret != 32031) { + bool bExit = false; + for (int i = 0; i < 3; i++) { + OTLDisconnect(); + ret = OTLConnect(); + if (ret != 0 && ret != 32031) { + if (2 == i) + bExit = true; + else + printf(">>>Postgresql reconnect %d times,errorcode= %d \n", i + 1, ret); + } + } + if (bExit) { + printf(">>>Postgresql reconnect 3 times,errorcode= %d,end thread!\n", ret); + sleep(30); + continue; + //return; + } + } + } + } + // printf("(д)SqlִSql_data_listԪظ= %dʵԪظ= %d \n", g_iSqlListSize, Sql_data_list.size()); + + Sql_data_list_mutex.lock(); + + std::string strSql = Sql_data_list.takeFirst().toStdString(); + printf("get one sql \n"); + if (strSql.length() < 11) + { + // printf("(д)SqlִSql_data_listʣԪظ= %dǰִSql= %scontinueһ䣡\n", Sql_data_list.count(), strSql.c_str()); + continue; + } + pSql = strSql.c_str(); + Sql_data_list_mutex.unlock(); + + //printf("BEGIN my_sql_excute no.%i -------->>>>>>>> %s \n", count, QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); + /*if (2 == Log_Enable) + printf("(д)SqlִSql_data_listʣԪظ= %iǰִSql.%i= %s \n", Sql_data_list.count(), count, pSql);*/ + printf("write one sql %s \n", pSql); + int rt = write_to_db(pSql); + connect_state = rt; + printf("connect state %d \n", connect_state); + //if (0 == rt) + //{ + // if (1 == Log_Enable) + // printf("(д)Sqlִгɹ.%i \n", count); + // else + // printf("(д)Sqlִгɹ.%iSql= %s \n", count, pSql); + //} + //printf("END my_sql_excute no.%i -------->>>>>>>> %s \n\n", count++, QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data()); + } + } + + printf(">>>SqlExcuteThread::run() is end!!!\n"); +} + +void try_start_sql_thread() +{ + static int sql_thread_created = 0; + if (!sql_thread_created) { + //if (2 == Log_Enable) + // printf(">>>Sqḷִ߳\n"); + sqlThrd.start(); + sql_thread_created = 1; + } +} + +void try_start_socket_thread() +{ + static int socket_thread_created = 0; + if (!socket_thread_created) { + //if (2 == Log_Enable) + // printf(">>>Web Sockeṭ߳\n"); + socketThrd.start(); + socket_thread_created = 1; + } +} + +//lnk20241029 +void try_start_web_http_thread() +{ + static int webhttp_thread_created = 0; + if (!webhttp_thread_created) { + webhttpThrd.start(); + webhttp_thread_created = 1; + } +} +void try_start_http_thread() +{ + static int http_thread_created = 0; + if (!http_thread_created) { + httpThrd.start(); + http_thread_created = 1; + } +} +//lnk20241202 +int try_start_mqtest_thread(int argc, char *argv[]) +{ + //ʹü򵥵ѭ̣߳һappִѭ̣߳ҿ + /*static int mqtest_thread_created = 0; + if (!mqtest_thread_created) { + mqtestThrd.start(); + mqtest_thread_created = 1; + }*/ + QCoreApplication a(argc, argv); + + // QThread Worker + QThread *thread = new QThread(); + Worker *worker = new Worker(); + + // Worker ƶ QThread + worker->moveToThread(thread); + + // źźͲ + QObject::connect(thread, SIGNAL(started()), worker, SLOT(startServer())); + QObject::connect(worker, SIGNAL(serverError()), thread, SLOT(quit())); + QObject::connect(worker, SIGNAL(serverError()), worker, SLOT(deleteLater())); + QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + // ߳ + thread->start(); + + //std::cout << "start_mqtest"<>>Web Sockeṭ߳\n"); + onTimerThrd.start(); + ontimer_thread_created = 1; + } +} +//WW 2023-08-22 end + +/////////////////////////////////////////// +//ZW 2024-01-31 ģʽŻ +static QMap mvl_type_ctrl_map;//ZW 2024-01-31 ڱ浥λȡģ +static int mvl_type_ctrl_map_size;// +//static std::map myMap; +//donameӦģ +void add_mvl_type_ctrl(char doname[], int ctrl) +{ + //printf("\nadd_mvl_type_ctrl: %s\n", doname); + //printf("\nadd_mvl_type_ctrl: %p////%p\n", &ctrl,©); + if (!mvl_type_ctrl_map.contains(doname)) + { + //MVL_TYPE_CTRL* copy = ctrl; + mvl_type_ctrl_map.insert(doname, ctrl); + } + //printf("\nadd_mvl_type_ctrl: %p\n", &doname); +} + +//ɾmapģ +void del_mvl_type_ctrl() +{ + for (QMap::iterator it = mvl_type_ctrl_map.begin(); it != mvl_type_ctrl_map.end(); ++it) { + QString key = it.key(); + int value = it.value(); + mvl_type_id_destroy(value); + } + mvl_type_ctrl_map.clear(); +} + +int get_mvl_type_ctrl_map_size() +{ + return mvl_type_ctrl_map.count(); +} +//ҶӦdonameģǷmap +int sel_mvl_type_ctrl_flag(char doname[]) +{ + if (mvl_type_ctrl_map.contains(doname)) + { + return mvl_type_ctrl_map.value(doname); + } + else + { + return -1; + } +} +//ZW 2024-01-31 end \ No newline at end of file diff --git a/json/save2json.h b/json/save2json.h new file mode 100644 index 0000000..73df100 --- /dev/null +++ b/json/save2json.h @@ -0,0 +1,345 @@ +/** +* @file: $RCSfile: save2json.h,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.5 $ +* @date: $Date: 2018/12/23 12:39:52 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: save2json.h,v 1.5 2018/12/23 12:39:52 lizhongming Exp $ +* +*/ + +#ifndef SAVE2DB_8ue3hy0923r_H +#define SAVE2DB_8ue3hy0923r_H +#ifdef __cplusplus +extern "C" { +#endif + extern int g_front_seg_index; +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +#include +#include +#include +#include + +#include + +//lnk20250106 +#include "../include/rocketmq/SimpleProducer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +extern int G_TEST_NUM; +extern void ledger(const char* terminal_id = NULL,QIODevice* outputDevice = NULL); +extern int TEST_PORT; + +////////////////////////////////////////////////////////////////////////////// +//struct json_pair_info +//{ +// string topic; // "RTDATA" ʵʱ "RTDATASOE"ʵʱSOE¼ +// string data_type; //ͣ01/04:̬/ٲ̬02/05:/ٲ䣬03/06:̬/ٲ̬ +// string item; // "I" "PQ" +// string sequence; //"A" "B" "C" "T" +// string name; //jsonkey +// int type; //6-ֵ9-ʵʱSOE¼ +// string mms_ref; //mmsַַ +// float coeff; //Coefficient:ϵ +// unsigned short PltFlag; //0xffff +//}; + +///////////////////////////////////////////////////////////////////////////// + +class KafkaSendThread : public QThread +{ +// Q_OBJECT +//public: + +protected: + void run(); +}; +//WW 2023-08-22 ݿ̺߳WebSocket߳ +class SQLExcuteThread : public QThread +{ +protected: + void run(); +}; + +class WebSocketThread : public QThread +{ +protected: + void run(); +}; + +//lnk20241029 +class WebhttpThread : public QThread +{ +protected: + void run(); +}; +class httpThread : public QThread +{ +protected: + void run(); +}; +//lnk20241202 +/*class mqtestThread : public QThread +{ +protected: + void run(); +};*/ +//lnk20250106 +//ʹtelnet 127.0.0.1 12345 +class Worker : public QObject +{ + Q_OBJECT + +public: + Worker(QObject *parent = NULL) : QObject(parent), server(NULL), TEST_NUM(G_TEST_NUM) {} + ~Worker() { + if (server) { + server->close(); + delete server; + } + } + +public slots: + void startServer() { + server = new QTcpServer(); + connect(server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); + + if (!server->listen(QHostAddress::Any, TEST_PORT)) { + std::cout << "Server failed to start!" << std::endl; + qDebug() << "Server failed to start!"; + delete server; + server = NULL; + emit serverError(); + return; + } else { + std::cout << "Server is running on port " << TEST_PORT << std::endl; + qDebug() << QString("Server is running on port %1").arg(TEST_PORT); + } + + // ʱ + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(doPeriodicTask())); + timer->start(60000); // ÿ60봥һ + + std::cout << "Timer started, event loop running in thread: " << QThread::currentThreadId() << std::endl; + qDebug() << "Timer started, event loop running in thread:" << QThread::currentThreadId(); + } + + void setTestNum(int num) { + QMutexLocker locker(&mutex); + TEST_NUM = num; + } + +private slots: + void doPeriodicTask() { + QMutexLocker locker(&mutex); + std::cout << "Executing TEST_NUM is " << TEST_NUM << std::endl; + qDebug() << "doPeriodicTask() called. TEST_NUM = " << TEST_NUM; + + if (TEST_NUM != 0) { + qDebug() << "Executing rocketmq_test_300()"; + std::cout << "Executing rocketmq_test_300()\n"; + rocketmq_test_300(TEST_NUM, g_front_seg_index); + } + } + + void onNewConnection() { + if (!server) return; + + QTcpSocket *clientSocket = server->nextPendingConnection(); + qDebug() << "New connection established!"; + std::cout << "New connection established!\n"; + + connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); + + // ͻ˷ʾ + if (clientSocket) { + std::cout << "clientSocket OK\n"; + clientSocket->write("Welcome to the test shell. Type 'help' for available commands.\n> "); + clientSocket->flush(); // ȷϢ + } + } + + void onReadyRead() { + QTcpSocket *clientSocket = qobject_cast(sender()); + std::cout << "onReadyRead\n"; + if (!clientSocket) { + std::cout << "Invalid socket\n"; + return; + } + std::cout << "read all\n"; + + QByteArray data = clientSocket->readAll(); + QString command = QString::fromUtf8(data).trimmed(); // ȡȥǰո + + qDebug() << "Received command:" << command; + std::cout << "Received command: " << command.toStdString() << "\n"; + + // ͻ˷ָ͡롱 + clientSocket->write("Received command\n> "); + clientSocket->flush(); + + // ʾʾ + clientSocket->write("test_shell> "); + clientSocket->flush(); // ȷʾʾ + + // TEST_NUM + if (command.startsWith("TEST_NUM=")) { + bool ok; + int num = command.mid(9).toInt(&ok); // ȡȺźֲ + if (ok) { + setTestNum(num); // TEST_NUM + clientSocket->write("TEST_NUM updated\n> "); + std::cout << "TEST_NUM updated\n"; + } else { + clientSocket->write("Invalid number\n> "); + std::cout << "Invalid number\n"; + } + } + // rc + else if (command.startsWith("rc")) { + qDebug() << "Executing rocketmq_test_rc()"; + std::cout << "Executing rocketmq_test_rc()\n"; + rocketmq_test_rc(); // rc + clientSocket->write("Executed rocketmq_test_rc\n> "); + } + // rt + else if (command.startsWith("rt")) { + qDebug() << "Executing rocketmq_test_rt()"; + std::cout << "Executing rocketmq_test_rt()\n"; + rocketmq_test_rt(); // rt + clientSocket->write("Executed rocketmq_test_rt\n> "); + } + // ud + else if (command.startsWith("ud")) { + qDebug() << "Executing rocketmq_test_ud()"; + std::cout << "Executing rocketmq_test_ud()\n"; + rocketmq_test_ud(); // ud + clientSocket->write("Executed rocketmq_test_ud\n> "); + } + else if (command.startsWith("set")) { + qDebug() << "Executing rocketmq_test_set()"; + std::cout << "Executing rocketmq_test_set()\n"; + rocketmq_test_set(); // set + clientSocket->write("Executed rocketmq_test_set\n> "); + } + else if (command.startsWith("ledger")) { + qDebug() << "Executing ledger()"; + std::cout << "Executing ledger()\n"; + + // ȡ + QStringList parts = command.split(" "); // ݿոָ + if (parts.size() > 1) { // а idţ + QString terminalId = parts[1]; + std::cout << "Calling ledger with terminal_id: " << terminalId.toStdString() << std::endl; + + // ޸ģ ledger ʱ clientSocket Ϊ豸 + ledger(terminalId.toStdString().c_str(), clientSocket); // ô ledger clientSocket + + clientSocket->write("Executed ledger with terminal_id\n> "); + } else { + std::cout << "Calling ledger without parameters\n"; + + // ޸ģ޲ ledger clientSocket + ledger(NULL, clientSocket); // ޲ ledger clientSocket + + clientSocket->write("Executed ledger without parameters\n> "); + } + } + + // δ֪ + else { + clientSocket->write("Unknown command\n> "); + } + + clientSocket->flush(); + } + +signals: + void serverError(); + +private: + QTcpServer *server; + QTimer *timer; + int TEST_NUM; + QMutex mutex; +}; + +//lnk20241213 +class mqconsumerThread : public QThread +{ +protected: + void run(); +}; + + +class OnTimerThread : public QThread//ʱ߳ +{ +protected: + void run(); +}; +//WW 2023-08-22 end + +///////////////////////////////////////////////////////////////////////// + + +extern "C" { +#endif + + +//lnk20250106̨˽ṹ +typedef struct terminal terminal; +typedef struct monitor monitor; +struct monitor // ̨ +{ + char monitor_id[64]; + char terminal_code[64]; + char monitor_name[64]; + char logical_device_seq[64]; + char voltage_level[64]; + char terminal_connect[64]; + char timestamp[64]; + char status[255]; + +}; +struct terminal // ն̨ +{ + char terminal_id[64]; + char terminal_code[64]; + char org_name[64]; + char maint_name[64]; + char station_name[64]; + char tmnl_factory[64]; + char tmnl_status[64]; + char dev_type[64]; + char dev_key[255]; + char dev_series[255]; + char addr_str[64]; + char port[64]; + char timestamp[64]; + monitor line[10]; // 10 + +}; + +#ifdef __cplusplus +} +#endif +///////////////////////////////////////////////////////////////////////////// + +#endif //SAVE2DB_8ue3hy0923r_H \ No newline at end of file diff --git a/libhttprun.so b/libhttprun.so new file mode 100644 index 0000000..7918182 Binary files /dev/null and b/libhttprun.so differ diff --git a/librocketmq.a b/librocketmq.a new file mode 100644 index 0000000..b6e0ea7 Binary files /dev/null and b/librocketmq.a differ diff --git a/librocketmq.so b/librocketmq.so new file mode 100644 index 0000000..b236177 Binary files /dev/null and b/librocketmq.so differ diff --git a/misc/CVS/Entries b/misc/CVS/Entries new file mode 100644 index 0000000..a9d2c32 --- /dev/null +++ b/misc/CVS/Entries @@ -0,0 +1,4 @@ +/SM4.h/1.2/Thu Dec 20 06:54:36 2018// +/SM4.cpp/1.4/Thu Dec 20 07:16:23 2018// +/my_encrypt.cpp/1.6/Mon Jan 21 08:16:03 2019// +D diff --git a/misc/CVS/Entries.Extra b/misc/CVS/Entries.Extra new file mode 100644 index 0000000..4037f6b --- /dev/null +++ b/misc/CVS/Entries.Extra @@ -0,0 +1,3 @@ +/SM4.h////*//// +/SM4.cpp////*//// +/my_encrypt.cpp////*//// diff --git a/misc/CVS/Entries.Extra.Old b/misc/CVS/Entries.Extra.Old new file mode 100644 index 0000000..4037f6b --- /dev/null +++ b/misc/CVS/Entries.Extra.Old @@ -0,0 +1,3 @@ +/SM4.h////*//// +/SM4.cpp////*//// +/my_encrypt.cpp////*//// diff --git a/misc/CVS/Entries.Old b/misc/CVS/Entries.Old new file mode 100644 index 0000000..01cbd35 --- /dev/null +++ b/misc/CVS/Entries.Old @@ -0,0 +1,4 @@ +/SM4.h/1.2/Thu Dec 20 06:54:36 2018// +/SM4.cpp/1.4/Thu Dec 20 07:16:23 2018// +/my_encrypt.cpp/1.5/Sat Dec 29 07:28:47 2018// +D diff --git a/misc/CVS/Repository b/misc/CVS/Repository new file mode 100644 index 0000000..2422b9f --- /dev/null +++ b/misc/CVS/Repository @@ -0,0 +1 @@ +jspqfe/src/pt61850netd_pqfe/source/misc diff --git a/misc/CVS/Root b/misc/CVS/Root new file mode 100644 index 0000000..0536776 --- /dev/null +++ b/misc/CVS/Root @@ -0,0 +1 @@ +:ext:lizhongming@10.0.0.2:/JoyProject diff --git a/misc/CVS/Template b/misc/CVS/Template new file mode 100644 index 0000000..e69de29 diff --git a/misc/SM4.cpp b/misc/SM4.cpp new file mode 100644 index 0000000..a6fa695 --- /dev/null +++ b/misc/SM4.cpp @@ -0,0 +1,158 @@ + +#include +#include +#include "SM4.h" + +SM4::SM4(void) +{ +} + + +SM4::~SM4(void) +{ +} + +unsigned char sm4_key[16]; +//unsigned char *sm4_key="@XsdHUfb2ZajLeH3"; +unsigned char kk_buf[]={0x20,0x38,0x53,0x44,0x28,0x35,0x46,0x42,0x12,0x3a,0x41,0x4a,0x2c,0x45,0x28,0x13}; + + + +/* + * SM4 key schedule (128-bit, encryption) + */ +void SM4::sm4_setkey_enc( sm4_context *ctx, unsigned char key[16] ) +{ + ctx->mode = SM4_ENCRYPT; + sm4_setkey( ctx->sk, key ); +} + +/* + * SM4 key schedule (128-bit, decryption) + */ +void SM4::sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] ) +{ + int i; + ctx->mode = SM4_ENCRYPT; + sm4_setkey( ctx->sk, key ); + for( i = 0; i < 16; i ++ ) + { + SWAP( ctx->sk[ i ], ctx->sk[ 31-i] ); + } +} + + +/* + * SM4-ECB block encryption/decryption + */ + +void SM4::sm4_crypt_ecb( sm4_context *ctx, + int mode, + int length, + unsigned char *input, + unsigned char *output) +{ + while( length > 0 ) + { + sm4_one_round( ctx->sk, input, output ); + input += 16; + output += 16; + length -= 16; + } + +} + +/* + * SM4-CBC buffer encryption/decryption + */ +void SM4::sm4_crypt_cbc( sm4_context *ctx, + int mode, + int length, + unsigned char iv[16], + unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( mode == SM4_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + sm4_one_round( ctx->sk, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else /* SM4_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + sm4_one_round( ctx->sk, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } +} + +//SM4 +void SM4::sm4_enc(char *str,int nStrLen,char *result_out,unsigned char *smkey) +{ + unsigned int i; + unsigned char full_str[128]; + unsigned char tmpbuf[64]; + unsigned char output[64]; + sm4_context ctx; + if(smkey==0) {for(i=0;i<16;i++) sm4_key[i]=kk_buf[i]+0x20;} + else {for(i=0;i<16;i++) sm4_key[i]=smkey[i];} + memset(full_str,0,100); //16ֽ0 + memcpy(full_str,str, nStrLen); + sm4_setkey_enc(&ctx,sm4_key); + for(i=0,result_out[0]=0;i<((nStrLen +15)/16);i++) + { + sm4_crypt_ecb(&ctx,1,16,&full_str[i*16],output); + apr_snprintf((char*)tmpbuf,sizeof(tmpbuf), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + output[0],output[1],output[2],output[3],output[4],output[5],output[6],output[7], + output[8],output[9],output[10],output[11],output[12],output[13],output[14],output[15]); + strcat(result_out,(char*)tmpbuf); + } +} +//SM4 +void SM4::sm4_dec(char *str,char *result_out,unsigned char *smkey) +{ + unsigned int i,j; + sm4_context ctx; + unsigned char input[64]; + unsigned char output[64]; + char convs[4]={0}; + if(smkey==0) {for(i=0;i<16;i++) sm4_key[i]=kk_buf[i]+0x20;} + else {for(i=0;i<16;i++) sm4_key[i]=smkey[i];} + sm4_setkey_dec(&ctx,sm4_key); + for(i=0;i +#include +#include + +#define SM4_ENCRYPT 1 +#define SM4_DECRYPT 0 + +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[32]; /*!< SM4 subkeys */ +} +sm4_context; + + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (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) ); \ +} +#endif + +/* + *rotate shift left marco definition + * + */ +#define SHL(x,n) (((x) & 0xFFFFFFFF) << n) +#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n))) + +#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; } + +/* + * Expanded SM4 S-boxes + /* Sbox table: 8bits input convert to 8 bits output*/ + +static const unsigned char SboxTable[16][16] = +{ +{0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05}, +{0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99}, +{0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62}, +{0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6}, +{0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8}, +{0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35}, +{0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87}, +{0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e}, +{0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1}, +{0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3}, +{0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f}, +{0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51}, +{0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8}, +{0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0}, +{0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84}, +{0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48} +}; + +/* System parameter */ +static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc}; + +/* fixed parameter */ +static const unsigned long CK[32] = +{ +0x00070e15,0x1c232a31,0x383f464d,0x545b6269, +0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9, +0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249, +0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9, +0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229, +0x30373e45,0x4c535a61,0x686f767d,0x848b9299, +0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209, +0x10171e25,0x2c333a41,0x484f565d,0x646b7279 +}; + + +/* + * private function: + * look up in SboxTable and get the related value. + * args: [in] inch: 0x00~0xFF (8 bits unsigned value). + */ +static unsigned char sm4Sbox(unsigned char inch) +{ + unsigned char *pTable = (unsigned char *)SboxTable; + unsigned char retVal = (unsigned char)(pTable[inch]); + return retVal; +} + +/* + * private F(Lt) function: + * "T algorithm" == "L algorithm" + "t algorithm". + * args: [in] a: a is a 32 bits unsigned value; + * return: c: c is calculated with line algorithm "L" and nonline algorithm "t" + */ +static unsigned long sm4Lt(unsigned long ka) +{ + unsigned long bb = 0; + unsigned long c = 0; + unsigned char a[4]; + unsigned char b[4]; + PUT_ULONG_BE(ka,a,0) + b[0] = sm4Sbox(a[0]); + b[1] = sm4Sbox(a[1]); + b[2] = sm4Sbox(a[2]); + b[3] = sm4Sbox(a[3]); + GET_ULONG_BE(bb,b,0) + c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24)); + return c; +} + +/* + * private F function: + * Calculating and getting encryption/decryption contents. + * args: [in] x0: original contents; + * args: [in] x1: original contents; + * args: [in] x2: original contents; + * args: [in] x3: original contents; + * args: [in] rk: encryption/decryption key; + * return the contents of encryption/decryption contents. + */ +static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk) +{ + return (x0^sm4Lt(x1^x2^x3^rk)); +} + + +/* private function: + * Calculating round encryption key. + * args: [in] a: a is a 32 bits unsigned value; + * return: sk[i]: i{0,1,2,3,...31}. + */ +static unsigned long sm4CalciRK(unsigned long ka) +{ + unsigned long bb = 0; + unsigned long rk = 0; + unsigned char a[4]; + unsigned char b[4]; + PUT_ULONG_BE(ka,a,0) + b[0] = sm4Sbox(a[0]); + b[1] = sm4Sbox(a[1]); + b[2] = sm4Sbox(a[2]); + b[3] = sm4Sbox(a[3]); + GET_ULONG_BE(bb,b,0) + rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23)); + return rk; +} + +static void sm4_setkey( unsigned long SK[32], unsigned char key[16] ) +{ + unsigned long MK[4]; + unsigned long k[36]; + unsigned long i = 0; + + GET_ULONG_BE( MK[0], key, 0 ); + GET_ULONG_BE( MK[1], key, 4 ); + GET_ULONG_BE( MK[2], key, 8 ); + GET_ULONG_BE( MK[3], key, 12 ); + k[0] = MK[0]^FK[0]; + k[1] = MK[1]^FK[1]; + k[2] = MK[2]^FK[2]; + k[3] = MK[3]^FK[3]; + for(; i<32; i++) + { + k[i+4] = k[i] ^ (sm4CalciRK(k[i+1]^k[i+2]^k[i+3]^CK[i])); + SK[i] = k[i+4]; + } + +} + +/* + * SM4 standard one round processing + * + */ +static void sm4_one_round( unsigned long sk[32], + unsigned char input[16], + unsigned char output[16] ) +{ + unsigned long i = 0; + unsigned long ulbuf[36]; + + memset(ulbuf, 0, sizeof(ulbuf)); + GET_ULONG_BE( ulbuf[0], input, 0 ) + GET_ULONG_BE( ulbuf[1], input, 4 ) + GET_ULONG_BE( ulbuf[2], input, 8 ) + GET_ULONG_BE( ulbuf[3], input, 12 ) + while(i<32) + { + ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]); +// #ifdef _DEBUG +// printf("rk(%02d) = 0x%08x, X(%02d) = 0x%08x \n",i,sk[i], i, ulbuf[i+4] ); +// #endif + i++; + } + PUT_ULONG_BE(ulbuf[35],output,0); + PUT_ULONG_BE(ulbuf[34],output,4); + PUT_ULONG_BE(ulbuf[33],output,8); + PUT_ULONG_BE(ulbuf[32],output,12); +} + +class SM4 +{ +public: + SM4(void); + ~SM4(void); + + void sm4_setkey_enc( sm4_context *ctx, unsigned char key[16] ); + void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] ); + void sm4_crypt_ecb( sm4_context *ctx, + int mode, + int length, + unsigned char *input, + unsigned char *output); + void sm4_crypt_cbc( sm4_context *ctx, + int mode, + int length, + unsigned char iv[16], + unsigned char *input, + unsigned char *output ); + void sm4_enc(char *str,int nStrLen,char *result_out,unsigned char *smkey); + void sm4_dec(char *str,char *result_out,unsigned char *smkey); +}; + + +#endif diff --git a/misc/my_encrypt.cpp b/misc/my_encrypt.cpp new file mode 100644 index 0000000..f28b140 --- /dev/null +++ b/misc/my_encrypt.cpp @@ -0,0 +1,67 @@ + + +using namespace std; + +#include "SM4.h" +#include "../mms/db_interface.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + void GetSM4Code(unsigned char* pSerise,char* pKey,char* output) +{ + int i=0; + unsigned char szKey[16+1] = {0}; + unsigned char input[16+1] = {0}; + time_t now_secs = apr_time_sec(apr_time_now()); + +#if 0 + systime_t tm; + memset(&tm,0,sizeof(systime_t)); + tm.year = 2017; + tm.mon = 5; + tm.mday =29; + tm.hour = 15; + tm.min = 16; + tm.sec = 20; + now_secs = apr_time_sec(getTicksOfSystemTime(&tm)); + apr_snprintf(pSerise,sizeof(pSerise),"%s","0123456789"); + apr_snprintf(pKey,sizeof(pKey),"%s","epri.sgcc.com.cn"); //Ӧɼ FACCAB57B27FD9BD1627506EF751EE61 +#endif + + int seriseLen = strlen((const char*)pSerise); + int keyLen = strlen(pKey); + time_t t = now_secs ;// -8*60*60; //ʱ + unsigned char* pTime = (unsigned char*)&t; + unsigned char* p_u_key = (unsigned char*)pKey; + input[0] = pTime[3]; + input[1] = pTime[2]; + input[2] = pTime[1]; + input[3] = pTime[0]; + for (i = 0; i < 12; i++) { + if(inum_called; ++i) + mvl_called_conn_ctrl[i].aa_objs = (MVL_AA_OBJ_CTRL *) M_CALLOC (MSMEM_STARTUP, 1, sizeof(MVL_AA_OBJ_CTRL)); + for (i = 0; i < mvl_cfg_info->num_calling; ++i) + mvl_calling_conn_ctrl[i].aa_objs = (MVL_AA_OBJ_CTRL *) M_CALLOC (MSMEM_STARTUP, 1, sizeof(MVL_AA_OBJ_CTRL)); +#endif /*#if defined(OBSOLETE_AA_OBJ_INIT)*/ + + mvl_init_type_ctrl (); + mvl_init_vmd_vars (); + mvl_init_dom_vars (); + mvl_init_aa_vars (); + mvl_init_vmd_varLists (); + mvl_init_dom_varLists (); + mvl_init_aa_varLists (); + mvl_init_journals (); + } +/************************************************************************/ + +/* VMD WIDE NAMED VARIABLE ASSOCIATION INITIALIZATION */ + +static ST_VOID mvl_init_vmd_vars () + { +MVL_VAR_ASSOC **ppva; + + mvl_vmd.max_num_var_assoc = 0 + mvl_max_dyn.vmd_vars; + mvl_vmd.num_var_assoc = 0; + if (mvl_vmd.max_num_var_assoc) + mvl_vmd.var_assoc_tbl = ppva = (MVL_VAR_ASSOC **) M_CALLOC (MSMEM_STARTUP, mvl_vmd.max_num_var_assoc, sizeof (MVL_VAR_ASSOC *)); + } +/************************************************************************/ + +/* DOMAIN VARIABLE INITIALIZATION */ +static ST_VOID mvl_init_dom_vars () + { +MVL_DOM_CTRL **ppdom; + + mvl_vmd.num_dom = 0; + mvl_vmd.max_num_dom = 0 + mvl_max_dyn.doms; + if (mvl_vmd.max_num_dom) + mvl_vmd.dom_tbl = ppdom = (MVL_DOM_CTRL **) M_CALLOC (MSMEM_STARTUP, mvl_vmd.max_num_dom, sizeof (MVL_DOM_CTRL *)); + } + +/************************************************************************/ + +/* AA VARIABLE INITIALIZATION */ +static ST_VOID mvl_init_aa_vars () + { +#if defined(OBSOLETE_AA_OBJ_INIT) +MVL_AA_OBJ_CTRL *aa; +MVL_VAR_ASSOC **ppva; +ST_INT i; +ST_INT j; + +/* Do AA specific variables */ + i = 0; + for (j = 0; j < mvl_cfg_info->num_called; ++j, ++i) + { + aa = (MVL_AA_OBJ_CTRL *) mvl_called_conn_ctrl[j].aa_objs; + aa->foundry_objects = SD_TRUE; + aa->max_num_var_assoc = 0 + mvl_max_dyn.aa_vars; + aa->num_var_assoc = 0; + if (aa->max_num_var_assoc) + aa->var_assoc_tbl = ppva = (MVL_VAR_ASSOC **) M_CALLOC (MSMEM_STARTUP, aa->max_num_var_assoc, sizeof (MVL_VAR_ASSOC *)); + } + for (j = 0; j < mvl_cfg_info->num_calling; ++j, ++i) + { + aa = (MVL_AA_OBJ_CTRL *) mvl_calling_conn_ctrl[j].aa_objs; + aa->foundry_objects = SD_TRUE; + aa->max_num_var_assoc = 0 + mvl_max_dyn.aa_vars; + aa->num_var_assoc = 0; + if (aa->max_num_var_assoc) + aa->var_assoc_tbl = ppva = (MVL_VAR_ASSOC **) M_CALLOC (MSMEM_STARTUP, aa->max_num_var_assoc, sizeof (MVL_VAR_ASSOC *)); + } +#endif /*#if defined(OBSOLETE_AA_OBJ_INIT)*/ + } + +/************************************************************************/ + +/* NAMED VARIABLE LIST INITIALIZATION */ + +static ST_VOID mvl_init_vmd_varLists () + { +MVL_NVLIST_CTRL **ppvl; + +/* Do VMD wide variable lists */ + mvl_vmd.max_num_nvlist = 0 + mvl_max_dyn.vmd_nvls; + mvl_vmd.num_nvlist = 0; + if (mvl_vmd.max_num_nvlist) + mvl_vmd.nvlist_tbl = ppvl = (MVL_NVLIST_CTRL **) M_CALLOC (MSMEM_STARTUP, mvl_vmd.max_num_nvlist, sizeof (MVL_NVLIST_CTRL *)); + } +/************************************************************************/ + +/* DOMAIN VARIABLE LIST INITIALIZATION */ +static ST_VOID mvl_init_dom_varLists () + { + } + +/************************************************************************/ + +/* AA VARIABLE LIST INITIALIZATION */ +static ST_VOID mvl_init_aa_varLists () + { +#if defined(OBSOLETE_AA_OBJ_INIT) +MVL_AA_OBJ_CTRL *aa; +MVL_NVLIST_CTRL **ppvl; +ST_INT i; + + +/* Now do AA specific Variable Lists */ + for (i = 0; i < mvl_cfg_info->num_called; ++i) + { + aa = (MVL_AA_OBJ_CTRL *) mvl_called_conn_ctrl[i].aa_objs; + aa->foundry_objects = SD_TRUE; + aa->max_num_nvlist = 0 + mvl_max_dyn.aa_nvls; + aa->num_nvlist = 0; + if (aa->max_num_nvlist) + aa->nvlist_tbl = ppvl = (MVL_NVLIST_CTRL **) M_CALLOC (MSMEM_STARTUP, aa->max_num_nvlist, sizeof (MVL_NVLIST_CTRL *)); + } + for (i = 0; i < mvl_cfg_info->num_calling; ++i) + { + aa = (MVL_AA_OBJ_CTRL *) mvl_calling_conn_ctrl[i].aa_objs; + aa->foundry_objects = SD_TRUE; + aa->max_num_nvlist = 0 + mvl_max_dyn.aa_nvls; + aa->num_nvlist = 0; + if (aa->max_num_nvlist) + aa->nvlist_tbl = ppvl = (MVL_NVLIST_CTRL **) M_CALLOC (MSMEM_STARTUP, aa->max_num_nvlist, sizeof (MVL_NVLIST_CTRL *)); + } +#endif /*#if defined(OBSOLETE_AA_OBJ_INIT)*/ + } + +/************************************************************************/ + +/* JOURNAL INITIALIZATION */ +static ST_VOID mvl_init_journals () + { +MVL_JOURNAL_CTRL **ppjou; + + /* initialize VMD_SPEC journals */ + + mvl_vmd.max_num_jou = 0 + mvl_max_dyn.journals; + mvl_vmd.num_jou = 0; + if (mvl_vmd.max_num_jou) + mvl_vmd.jou_tbl = ppjou = (MVL_JOURNAL_CTRL **) M_CALLOC (MSMEM_STARTUP, mvl_vmd.max_num_jou, sizeof (MVL_JOURNAL_CTRL *)); + } + +/************************************************************************/ + +ST_VOID mvl_init_type_ctrl () + { +static ST_BOOLEAN _mvlInitTypeCtrlCalled = SD_FALSE; + + if (_mvlInitTypeCtrlCalled == SD_TRUE) + return; + _mvlInitTypeCtrlCalled = SD_TRUE; + +#ifndef USE_RT_TYPE_2 + maxMvlRtNames = 16; + numMvlRtNames = 16; + mvlRtNames = foMvlRtNames; +#endif + mvl_num_types = 19 + mvl_max_dyn.types; + + if (mvl_num_types) + mvl_type_ctrl = (MVL_TYPE_CTRL *) M_CALLOC (MSMEM_STARTUP, mvl_num_types, sizeof(MVL_TYPE_CTRL)); +#if defined USR_SUPPLIED_RT + u_mvl_start_init_rt_tbl (19, 194); +#endif + +/* RTYP_BOOL : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BOOL_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_BOOL_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BOOL_TYPEID].data_size = 1; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BOOL_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BOOL_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BOOL_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BOOL_TYPEID].type_name, "RTYP_BOOL"); + +/* RTYP_BTIME6 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BTIME6_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_BTIME6_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BTIME6_TYPEID].data_size = 8; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BTIME6_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BTIME6_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BTIME6_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BTIME6_TYPEID].type_name, "RTYP_BTIME6"); + +/* RTYP_BSTR6 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BSTR6_TYPEID].tdl = + "Bstring6"; +*/ + mvl_type_ctrl[RTYP_BSTR6_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BSTR6_TYPEID].data_size = 1; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BSTR6_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BSTR6_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BSTR6_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BSTR6_TYPEID].type_name, "RTYP_BSTR6"); + +/* RTYP_BSTR8 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BSTR8_TYPEID].tdl = + "Bstring8"; +*/ + mvl_type_ctrl[RTYP_BSTR8_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BSTR8_TYPEID].data_size = 1; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BSTR8_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BSTR8_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BSTR8_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BSTR8_TYPEID].type_name, "RTYP_BSTR8"); + +/* RTYP_BSTR9 : Client needs for writing OptFlds */ +/* + mvl_type_ctrl[RTYP_BSTR9_TYPEID].tdl = + "Bstring9"; +*/ + mvl_type_ctrl[RTYP_BSTR9_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BSTR9_TYPEID].data_size = 2; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BSTR9_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BSTR9_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BSTR9_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BSTR9_TYPEID].type_name, "RTYP_BSTR9"); + +/* RTYP_BVSTR6 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BVSTR6_TYPEID].tdl = + "Bvstring6"; +*/ + mvl_type_ctrl[RTYP_BVSTR6_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BVSTR6_TYPEID].data_size = 3; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BVSTR6_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BVSTR6_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BVSTR6_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BVSTR6_TYPEID].type_name, "RTYP_BVSTR6"); + +/* RTYP_BVSTR8 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BVSTR8_TYPEID].tdl = + "Bvstring8"; +*/ + mvl_type_ctrl[RTYP_BVSTR8_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BVSTR8_TYPEID].data_size = 3; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BVSTR8_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BVSTR8_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BVSTR8_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BVSTR8_TYPEID].type_name, "RTYP_BVSTR8"); + +/* RTYP_BVSTR10 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_BVSTR10_TYPEID].tdl = + "Bvstring10"; +*/ + mvl_type_ctrl[RTYP_BVSTR10_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_BVSTR10_TYPEID].data_size = 4; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_BVSTR10_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_BVSTR10_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_BVSTR10_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_BVSTR10_TYPEID].type_name, "RTYP_BVSTR10"); + +/* RTYP_INT8U : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_INT8U_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_INT8U_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_INT8U_TYPEID].data_size = 1; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_INT8U_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_INT8U_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_INT8U_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_INT8U_TYPEID].type_name, "RTYP_INT8U"); + +/* RTYP_INT16U : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_INT16U_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_INT16U_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_INT16U_TYPEID].data_size = 2; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_INT16U_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_INT16U_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_INT16U_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_INT16U_TYPEID].type_name, "RTYP_INT16U"); + +/* RTYP_OSTR8 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_OSTR8_TYPEID].tdl = + "Ostring8"; +*/ + mvl_type_ctrl[RTYP_OSTR8_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_OSTR8_TYPEID].data_size = 8; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_OSTR8_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_OSTR8_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_OSTR8_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_OSTR8_TYPEID].type_name, "RTYP_OSTR8"); + +/* RTYP_VSTR32 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_VSTR32_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_VSTR32_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_VSTR32_TYPEID].data_size = 33; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_VSTR32_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_VSTR32_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_VSTR32_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_VSTR32_TYPEID].type_name, "RTYP_VSTR32"); + +/* RTYP_VSTR65 : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_VSTR65_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_VSTR65_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_VSTR65_TYPEID].data_size = 66; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_VSTR65_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_VSTR65_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_VSTR65_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_VSTR65_TYPEID].type_name, "RTYP_VSTR65"); + +/* RTYP_INT32U : UCAreporttypes */ +/* + mvl_type_ctrl[RTYP_INT32U_TYPEID].tdl = + ""; +*/ + mvl_type_ctrl[RTYP_INT32U_TYPEID].num_rt = 1; + mvl_type_ctrl[RTYP_INT32U_TYPEID].data_size = 4; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[RTYP_INT32U_TYPEID].rt = u_mvl_get_rt_tbl (RTYP_INT32U_TYPEID, 1); +#else + mvl_type_ctrl[RTYP_INT32U_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[RTYP_INT32U_TYPEID].type_name, "RTYP_INT32U"); + +/* I16 : Single 16-bit signed integer */ +/* + mvl_type_ctrl[I16_TYPEID].tdl = + "Short"; +*/ + mvl_type_ctrl[I16_TYPEID].num_rt = 1; + mvl_type_ctrl[I16_TYPEID].data_size = 2; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[I16_TYPEID].rt = u_mvl_get_rt_tbl (I16_TYPEID, 1); +#else + mvl_type_ctrl[I16_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[I16_TYPEID].type_name, "I16"); + +/* U32 : Single 32-bit unsigned integer */ +/* + mvl_type_ctrl[U32_TYPEID].tdl = + "Ulong"; +*/ + mvl_type_ctrl[U32_TYPEID].num_rt = 1; + mvl_type_ctrl[U32_TYPEID].data_size = 4; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[U32_TYPEID].rt = u_mvl_get_rt_tbl (U32_TYPEID, 1); +#else + mvl_type_ctrl[U32_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[U32_TYPEID].type_name, "U32"); + +/* UTF8VSTRING13 : variable len Unicode UTF8 string */ +/* + mvl_type_ctrl[UTF8VSTRING13_TYPEID].tdl = + "UTF8Vstring13"; +*/ + mvl_type_ctrl[UTF8VSTRING13_TYPEID].num_rt = 1; + mvl_type_ctrl[UTF8VSTRING13_TYPEID].data_size = 28; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[UTF8VSTRING13_TYPEID].rt = u_mvl_get_rt_tbl (UTF8VSTRING13_TYPEID, 1); +#else + mvl_type_ctrl[UTF8VSTRING13_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[UTF8VSTRING13_TYPEID].type_name, "UTF8VSTRING13"); + +/* phv_type : */ +/* + mvl_type_ctrl[phv_type_TYPEID].tdl = + "{(phsA){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(\ +cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q\ +)BVstring13,(t)Utctime,},(phsB){(instCVal){(mag){(i)Long,(f)Float,},(ang\ +){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)\ +Float,},},(range)Byte,(q)BVstring13,(t)Utctime,},(phsC){(instCVal){(mag)\ +{(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)F\ +loat,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}\ +,(neut){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(\ +cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q\ +)BVstring13,(t)Utctime,},(net){(instCVal){(mag){(i)Long,(f)Float,},(ang)\ +{(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)F\ +loat,},},(range)Byte,(q)BVstring13,(t)Utctime,},(res){(instCVal){(mag){(\ +i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Flo\ +at,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,},}\ +"; +*/ + mvl_type_ctrl[phv_type_TYPEID].num_rt = 152; + mvl_type_ctrl[phv_type_TYPEID].data_size = 312; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[phv_type_TYPEID].rt = u_mvl_get_rt_tbl (phv_type_TYPEID, 152); +#else + mvl_type_ctrl[phv_type_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[phv_type_TYPEID].type_name, "phv_type"); + +/* phsx_type : */ +/* + mvl_type_ctrl[phsx_type_TYPEID].tdl = + "{(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(\ +mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstri\ +ng13,(t)Utctime,}"; +*/ + mvl_type_ctrl[phsx_type_TYPEID].num_rt = 25; + mvl_type_ctrl[phsx_type_TYPEID].data_size = 52; +#if defined USR_SUPPLIED_RT + mvl_type_ctrl[phsx_type_TYPEID].rt = u_mvl_get_rt_tbl (phsx_type_TYPEID, 25); +#else + mvl_type_ctrl[phsx_type_TYPEID].rt = mvl_rt_tables[rt_table_index++]; +#endif /* #if defined USR_SUPPLIED_RT */ + strcpy (mvl_type_ctrl[phsx_type_TYPEID].type_name, "phsx_type"); + + +#if defined USR_SUPPLIED_RT + u_mvl_end_init_rt_tbl (); +#endif + } + + +/************************************************************************/ +/* RUNTIME TYPE DATA */ + + +#if !defined USR_SUPPLIED_RT + +/************************************************************************/ +/* RTYP_BOOL : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_0[1] = + { + { /* rt[0] init data ... */ + RT_BOOL, /* el_tag */ + 1, /* el_size */ + 1, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BTIME6 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_1[1] = + { + { /* rt[0] init data ... */ + RT_BINARY_TIME, /* el_tag */ + 8, /* el_size */ + 8, /* offset_to_last */ + { /* u */ + { /* p */ + 6, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BSTR6 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_2[1] = + { + { /* rt[0] init data ... */ + RT_BIT_STRING, /* el_tag */ + 1, /* el_size */ + 1, /* offset_to_last */ + { /* u */ + { /* p */ + 6, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BSTR8 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_3[1] = + { + { /* rt[0] init data ... */ + RT_BIT_STRING, /* el_tag */ + 1, /* el_size */ + 1, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BSTR9 : Client needs for writing OptFlds */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_4[1] = + { + { /* rt[0] init data ... */ + RT_BIT_STRING, /* el_tag */ + 2, /* el_size */ + 2, /* offset_to_last */ + { /* u */ + { /* p */ + 9, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BVSTR6 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_5[1] = + { + { /* rt[0] init data ... */ + RT_BIT_STRING, /* el_tag */ + 3, /* el_size */ + 3, /* offset_to_last */ + { /* u */ + { /* p */ + -6, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BVSTR8 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_6[1] = + { + { /* rt[0] init data ... */ + RT_BIT_STRING, /* el_tag */ + 3, /* el_size */ + 3, /* offset_to_last */ + { /* u */ + { /* p */ + -8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_BVSTR10 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_7[1] = + { + { /* rt[0] init data ... */ + RT_BIT_STRING, /* el_tag */ + 4, /* el_size */ + 4, /* offset_to_last */ + { /* u */ + { /* p */ + -10, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_INT8U : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_8[1] = + { + { /* rt[0] init data ... */ + RT_UNSIGNED, /* el_tag */ + 1, /* el_size */ + 1, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_INT16U : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_9[1] = + { + { /* rt[0] init data ... */ + RT_UNSIGNED, /* el_tag */ + 2, /* el_size */ + 2, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_OSTR8 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_10[1] = + { + { /* rt[0] init data ... */ + RT_OCTET_STRING, /* el_tag */ + 8, /* el_size */ + 8, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_VSTR32 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_11[1] = + { + { /* rt[0] init data ... */ + RT_VISIBLE_STRING, /* el_tag */ + 33, /* el_size */ + 33, /* offset_to_last */ + { /* u */ + { /* p */ + -32, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_VSTR65 : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_12[1] = + { + { /* rt[0] init data ... */ + RT_VISIBLE_STRING, /* el_tag */ + 66, /* el_size */ + 66, /* offset_to_last */ + { /* u */ + { /* p */ + -65, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* RTYP_INT32U : UCAreporttypes */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_13[1] = + { + { /* rt[0] init data ... */ + RT_UNSIGNED, /* el_tag */ + 4, /* el_size */ + 4, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* I16 : Single 16-bit signed integer */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_14[1] = + { + { /* rt[0] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 2, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* U32 : Single 32-bit unsigned integer */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_15[1] = + { + { /* rt[0] init data ... */ + RT_UNSIGNED, /* el_tag */ + 4, /* el_size */ + 4, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* UTF8VSTRING13 : variable len Unicode UTF8 string */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_16[1] = + { + { /* rt[0] init data ... */ + RT_UTF8_STRING, /* el_tag */ + 28, /* el_size */ + 28, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* phv_type : */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_17[152] = + { + { /* rt[0] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 312, /* offset_to_last */ + { /* u */ + { /* p */ + 150, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[1] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_phsA, /* comp_name_ptr 'phsA' */ +#else /* !USE_RT_TYPE_2 */ + FO_PHSA_STRING_INDEX, /* name_index 'phsA' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[2] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[3] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[4] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[5] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[6] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[7] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[8] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[9] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[10] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[11] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[12] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[13] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[14] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[15] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[16] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[17] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[18] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[19] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[20] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[21] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[22] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[23] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[24] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[25] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[26] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_phsB, /* comp_name_ptr 'phsB' */ +#else /* !USE_RT_TYPE_2 */ + FO_PHSB_STRING_INDEX, /* name_index 'phsB' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[27] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[28] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[29] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[30] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[31] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[32] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[33] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[34] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[35] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[36] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[37] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[38] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[39] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[40] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[41] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[42] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[43] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[44] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[45] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[46] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[47] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[48] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[49] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[50] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[51] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_phsC, /* comp_name_ptr 'phsC' */ +#else /* !USE_RT_TYPE_2 */ + FO_PHSC_STRING_INDEX, /* name_index 'phsC' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[52] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[53] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[54] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[55] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[56] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[57] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[58] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[59] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[60] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[61] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[62] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[63] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[64] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[65] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[66] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[67] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[68] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[69] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[70] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[71] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[72] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[73] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[74] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[75] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[76] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_neut, /* comp_name_ptr 'neut' */ +#else /* !USE_RT_TYPE_2 */ + FO_NEUT_STRING_INDEX, /* name_index 'neut' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[77] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[78] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[79] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[80] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[81] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[82] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[83] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[84] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[85] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[86] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[87] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[88] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[89] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[90] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[91] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[92] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[93] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[94] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[95] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[96] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[97] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[98] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[99] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[100] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[101] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_net, /* comp_name_ptr 'net' */ +#else /* !USE_RT_TYPE_2 */ + FO_NET_STRING_INDEX, /* name_index 'net' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[102] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[103] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[104] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[105] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[106] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[107] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[108] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[109] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[110] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[111] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[112] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[113] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[114] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[115] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[116] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[117] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[118] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[119] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[120] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[121] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[122] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[123] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[124] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[125] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[126] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_res, /* comp_name_ptr 'res' */ +#else /* !USE_RT_TYPE_2 */ + FO_RES_STRING_INDEX, /* name_index 'res' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[127] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[128] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[129] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[130] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[131] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[132] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[133] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[134] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[135] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[136] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[137] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[138] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[139] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[140] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[141] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[142] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[143] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[144] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[145] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[146] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[147] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[148] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[149] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[150] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[151] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 150, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ +/* phsx_type : */ + +SD_CONST static RUNTIME_TYPE mvl_rt_table_18[25] = + { + { /* rt[0] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 52, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[1] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_instCVal, /* comp_name_ptr 'instCVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_INSTCVAL_STRING_INDEX, /* name_index 'instCVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[2] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[3] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[4] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[5] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[6] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[7] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[8] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[9] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[10] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[11] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_cVal, /* comp_name_ptr 'cVal' */ +#else /* !USE_RT_TYPE_2 */ + FO_CVAL_STRING_INDEX, /* name_index 'cVal' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[12] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_mag, /* comp_name_ptr 'mag' */ +#else /* !USE_RT_TYPE_2 */ + FO_MAG_STRING_INDEX, /* name_index 'mag' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[13] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[14] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[15] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[16] init data ... */ + RT_STR_START, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_ang, /* comp_name_ptr 'ang' */ +#else /* !USE_RT_TYPE_2 */ + FO_ANG_STRING_INDEX, /* name_index 'ang' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[17] init data ... */ + RT_INTEGER, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_i, /* comp_name_ptr 'i' */ +#else /* !USE_RT_TYPE_2 */ + FO_I_STRING_INDEX, /* name_index 'i' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[18] init data ... */ + RT_FLOATING_POINT, /* el_tag */ + 4, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 4, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_f, /* comp_name_ptr 'f' */ +#else /* !USE_RT_TYPE_2 */ + FO_F_STRING_INDEX, /* name_index 'f' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[19] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 2, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[20] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[21] init data ... */ + RT_INTEGER, /* el_tag */ + 2, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 1, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_range, /* comp_name_ptr 'range' */ +#else /* !USE_RT_TYPE_2 */ + FO_RANGE_STRING_INDEX, /* name_index 'range' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[22] init data ... */ + RT_BIT_STRING, /* el_tag */ + 6, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + -13, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_q, /* comp_name_ptr 'q' */ +#else /* !USE_RT_TYPE_2 */ + FO_Q_STRING_INDEX, /* name_index 'q' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[23] init data ... */ + RT_UTC_TIME, /* el_tag */ + 12, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 8, /* el_len */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + mvlCompName_t, /* comp_name_ptr 't' */ +#else /* !USE_RT_TYPE_2 */ + FO_T_STRING_INDEX, /* name_index 't' */ +#endif /* !USE_RT_TYPE_2 */ + }, + { /* rt[24] init data ... */ + RT_STR_END, /* el_tag */ + 0, /* el_size */ + 0, /* offset_to_last */ + { /* u */ + { /* p */ + 23, /* num_rt_blks */ + 0 /* pad */ + } /* end 'p' */ + }, /* end 'u' */ +#ifdef USE_RT_TYPE_2 + NULL, /* comp_name_ptr */ +#else /* !USE_RT_TYPE_2 */ + 0, /* name_index */ +#endif /* !USE_RT_TYPE_2 */ + } + }; + +/************************************************************************/ + + +ST_INT rt_table_index; + +SD_CONST RUNTIME_TYPE * SD_CONST mvl_rt_tables[] = + { + mvl_rt_table_0, + mvl_rt_table_1, + mvl_rt_table_2, + mvl_rt_table_3, + mvl_rt_table_4, + mvl_rt_table_5, + mvl_rt_table_6, + mvl_rt_table_7, + mvl_rt_table_8, + mvl_rt_table_9, + mvl_rt_table_10, + mvl_rt_table_11, + mvl_rt_table_12, + mvl_rt_table_13, + mvl_rt_table_14, + mvl_rt_table_15, + mvl_rt_table_16, + mvl_rt_table_17, + mvl_rt_table_18 + }; + + +#endif /* #if defined USR_SUPPLIED_RT */ + diff --git a/mms/clntobj.h b/mms/clntobj.h new file mode 100644 index 0000000..5a33a7d --- /dev/null +++ b/mms/clntobj.h @@ -0,0 +1,399 @@ +/** +* @file: $RCSfile: clntobj.h,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:50 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: clntobj.h,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +* +*/ + +#ifndef FOUNDRY_OUTPUT_HEADER_INCLUDED +#define FOUNDRY_OUTPUT_HEADER_INCLUDED + +#include "mvl_uca.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************/ +/* MVL Type Control Information */ +extern MVL_TYPE_CTRL *mvl_type_ctrl; +extern ST_INT mvl_num_types; + +/************************************************************************/ + + +/* MVL Type ID's */ +#define RTYP_BOOL_TYPEID 0 +#define RTYP_BTIME6_TYPEID 1 +#define RTYP_BSTR6_TYPEID 2 +#define RTYP_BSTR8_TYPEID 3 +#define RTYP_BSTR9_TYPEID 4 +#define RTYP_BVSTR6_TYPEID 5 +#define RTYP_BVSTR8_TYPEID 6 +#define RTYP_BVSTR10_TYPEID 7 +#define RTYP_INT8U_TYPEID 8 +#define RTYP_INT16U_TYPEID 9 +#define RTYP_OSTR8_TYPEID 10 +#define RTYP_VSTR32_TYPEID 11 +#define RTYP_VSTR65_TYPEID 12 +#define RTYP_INT32U_TYPEID 13 +#define I16_TYPEID 14 +#define U32_TYPEID 15 +#define UTF8VSTRING13_TYPEID 16 +#define phv_type_TYPEID 17 +#define phsx_type_TYPEID 18 + + +/************************************************************************/ + +/************************************************************************/ + + +/* Common Strings Index Defines */ + +#ifndef USE_RT_TYPE_2 + +#define FO_PHSA_STRING_INDEX 1 +#define FO_INSTCVAL_STRING_INDEX 2 +#define FO_MAG_STRING_INDEX 3 +#define FO_I_STRING_INDEX 4 +#define FO_F_STRING_INDEX 5 +#define FO_ANG_STRING_INDEX 6 +#define FO_CVAL_STRING_INDEX 7 +#define FO_RANGE_STRING_INDEX 8 +#define FO_Q_STRING_INDEX 9 +#define FO_T_STRING_INDEX 10 +#define FO_PHSB_STRING_INDEX 11 +#define FO_PHSC_STRING_INDEX 12 +#define FO_NEUT_STRING_INDEX 13 +#define FO_NET_STRING_INDEX 14 +#define FO_RES_STRING_INDEX 15 +#endif + + +/************************************************************************/ +/* TYPEDEFS for MMS TYPES */ +/************************************************************************/ + +/* Use ":CF", "-notypedefs" in the ODF file to not include this line */ +#define USE_MMS_TYPEDEFS + +#if defined (USE_MMS_TYPEDEFS) + +typedef ST_BOOLEAN RTYP_BOOL_TDEF; + +typedef MMS_BTIME6 RTYP_BTIME6_TDEF; + +typedef ST_UCHAR RTYP_BSTR6_TDEF[1]; /* Bitstring */ + +typedef ST_UCHAR RTYP_BSTR8_TDEF[1]; /* Bitstring */ + +typedef ST_UCHAR RTYP_BSTR9_TDEF[2]; /* Bitstring */ + +typedef struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[1]; + } RTYP_BVSTR6_TDEF; /* Bitstring */ + +typedef struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[1]; + } RTYP_BVSTR8_TDEF; /* Bitstring */ + +typedef struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } RTYP_BVSTR10_TDEF; /* Bitstring */ + +typedef ST_UINT8 RTYP_INT8U_TDEF; + +typedef ST_UINT16 RTYP_INT16U_TDEF; + +typedef ST_UCHAR RTYP_OSTR8_TDEF[8]; /* Octetstring */ + +typedef ST_CHAR RTYP_VSTR32_TDEF[33]; /* Visible String */ + +typedef ST_CHAR RTYP_VSTR65_TDEF[66]; /* Visible String */ + +typedef ST_UINT32 RTYP_INT32U_TDEF; + +typedef ST_INT16 I16_TDEF; + +typedef ST_UINT32 U32_TDEF; + +typedef ST_CHAR UTF8VSTRING13_TDEF[28]; + +typedef struct + { + struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } phsA; + struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } phsB; + struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } phsC; + struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } neut; + struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } net; + struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } res; + } phv_type_TDEF; + +typedef struct + { + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } instCVal; + struct + { + struct + { + ST_INT32 i; + ST_FLOAT f; + } mag; + struct + { + ST_INT32 i; + ST_FLOAT f; + } ang; + } cVal; + ST_INT8 range; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; + } q; + MMS_UTC_TIME t; + } phsx_type_TDEF; + +/************************************************************************/ +#endif /* if defined (USE_MMS_TYPEDEFS) */ +/************************************************************************/ +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef FOUNDRY_OUTPUT_HEADER_INCLUDED */ diff --git a/mms/clntobj.odf b/mms/clntobj.odf new file mode 100644 index 0000000..5e91ed2 --- /dev/null +++ b/mms/clntobj.odf @@ -0,0 +1,198 @@ +# REVISIONS +# 07/22/05 JRB Add phv_type, phsx_type used by cli_goose.c +# 08/10/04 EJV Chg "UTF8VSTRING13" from ":T" to ":TK". +# 11/24/03 JRB Add ":CF", ":TV" to avoid unnecessary type definitions. +# 10/09/03 JRB Add types for dealing with IEC/UCA Reports. Add "client.h". +########################################################################## +# MMS OBJECT CONFIGURATION FILE +# This file is used as input to the 'foundry' utility application. +# It is used to create the following objects for use with MMS-LITE: +# Types +# Domains +# Named Variables +# Named Variable Lists +# +# Note: All objects except for the types can also be created +# by user code at initialization time. The creation of the +# Domains, Variables, and Variable Lists via this utility +# is for convenience only. +# +# Lines beginning with pound-signs are comments and are ignored. +# The general format of object definitions in this file is described +# below. All object definition information is supplied in quotes, and +# can span multiple lines if desired. A object definition string is of +# the form : +# +# "{objectType}","Object Specific String1", "String2", ... +# +# Where the objectType field is used to specify the object and some of +# it's optional attributes. The format of the 'objectType' field is as +# follows - +# +# ":X{flags}" +# +# Where X is one of the set {I,T,D,V,L}, and the set of valid flag +# characters depends on the object type. +# +# C == Control string +# Flags +# C : Config, next string is alignment file to use +# P : Path, next string is include path for ODF files +# F : Flags, next string contains flags to set defaults +# ":VD" +# ":VP" +# ":TU" +# ":TT" +# ":TV" +# "-notypedefs" +# "-nosuffix" +# U : UCA control, next string contains UCA control info +# "MVL_UCA" +# "MVLU_USE_REF" +# +# I == User specified include file, for user object definitions +# Flags +# None +# +# T == Type +# Flags +# U : Unique, do not 'twin' this type +# T : Transient type, do not keep +# V : Keep only if referenced by a variable +# K : Keep this type unconditionally +# +# D == Domain +# Flags +# None +# +# V == Named Variable +# Flags +# D : Use 3rd string to set data pointer +# P : Use 4th (3rd for no D) string to set processing fun +# U : Use 5th (4rd for no D, 3rd for no P) string to set usr_info +# +# L == Named Variable List +# Flags +# U : Use 5th (4rd for no D, 3rd for no P) string to set usr_info +# String ":S" : End of list of variables +# +# N == UCA Model Name Generation +# Flags +# None +# +########################################################################## +# EXECUTION CONTROL +# +# Include path, used to locate included ODF files +# Path for QNX +":CP", "../../../mvl/util/foundry/uca09" +# Path on Windows +":CP", "../../mvl/util/foundry/uca09" + +# Set type handling default flags for all following types +":CF", ":TV" # Delete Runtime types not used by variables + +# Include SISCO UCA Object Definition Files +":CI", "gentypes.odf" +":CI", "rpt.odf" + +########################################################################## +# INCLUDE FILE DEFINITION SECTION +# This section is used to specify user include files that are to be +# included in the output 'C' file. This may be necessary when creating +# variables with data or processing initialzation strings. +# Example - Include the user header file 'umvlinit.h' +# ":I", "server.h" +# + +":I", "mmsclient.h" + +########################################################################## +# TYPE CREATION SECTION +# This section is used to specify MMS-LITE types. There are three +# required parameters per type (plus flags) - +# 1. Type Select Define : The define created to reference the type +# 2. TDL : The SISCO type definition language string +# 3. Comment: Used only in the output 'C' file +# +# Optional flags are - +# U : Do not 'twin' this type +# T : Transient type, do not write; use only as base type +# K : Keep this type unconditionally + +":T", "ANALOG","[32:Ushort]","Array Of 32 16-bit unsigned integers" +":T", "U16","Ushort","Single 16-bit unsigned integer" +":TK", "I16","Short","Single 16-bit signed integer" +":TK", "U32","Ulong","Single 32-bit unsigned integer" +":TK", "UTF8VSTRING13","UTF8Vstring13","variable len Unicode UTF8 string" + +# These types (phv_type, phsx_type) used by cli_goose.c +":TK", "phv_type", +"{(phsA){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}, +(phsB){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}, +(phsC){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}, +(neut){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}, +(net){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}, +(res){(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}, +}", +"" +":TK", "phsx_type", +"{(instCVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(cVal){(mag){(i)Long,(f)Float,},(ang){(i)Long,(f)Float,},},(range)Byte,(q)BVstring13,(t)Utctime,}", +"" + +########################################################################## +# DOMAIN CREATION SECTION +# This section is used to create MMS-LITE domains. The single parameter +# is the domain name, which must be a legal MMS domain name. +# Example - Create a domain named mvlLiteDomain +# ":D", "mvlLiteDomain" +# +########################################################################## +# VARIABLE ASSOCIATION CREATION SECTION +# This section is used to specify MMS-LITE named variables. There are two +# required parameters per variable, and three optional parameters (plus +# flags) - +# 1. Variable Name (must be valid MMS variable name). Note that the +# name can be of the form "domainName:VariableName" for domain vars. +# 2. Type ID : This Type ID must have been created previously +# 3. Data (optional): Used to initialize the va->data element. +# 4. Proc (optional): Used to initialize the va->proc element. +# 5. User (optional): Used to initialize the va->usr_info element. +# +# Optional flags are - +# D : Use 3rd string to set va->data +# P : Use 4th (3rd for no D) string to set va->proc +# U : Use 5th (4th, 3rd for no D, no P) string to set va->usr_info +# +# Note that it may ne necessary to specify an include file to be used +# to resolve the 'data' and 'proc' initialization code. +# +# Example - Create a VMD variable named 'Temperature' +# ":VDP", "Temperature", "I16", "&Temperature", "&varProcFuns" +# +########################################################################## +# NAMED VARIABLE LIST CREATION SECTION +# This section is used to specify MMS-LITE named variable lists. +# There are two required parameters per variable list, and a list of +# variables to be included in the list (plus flags) - +# 1. Variable list Name (must be valid MMS variable name). Note that the +# name can be of the form "domainName:VariableListName" for domain vars. +# 2. List of variables to be part of the named variable list. +# 3. End of variables marker. This is a string of form ":S", +# +# Example - Create a VMD Variable List named 'nvl1' with 'Temperature', +# and 'arr1' as members. +# ":L", "nvl1", "arr1", "Temperature", ":S" +# +########################################################################## +# UCA MODEL NAME GENERATION SECTION +# This section is used to generate UCA variable names from a selected +# structure type. The first parameter is the name base to be used. The +# second parameter is the type to use in extracting the names, and will +# generally be a high level UCA object type. +# Note: These objects are used only when the '-v' or '-n' command line +# parameters is used. +# Example - Extract the names for the +# "Automatic Switch Controller Device Model" +#":N","ASWC","ASWC" +# diff --git a/mms/db_interface.h b/mms/db_interface.h new file mode 100644 index 0000000..10be391 --- /dev/null +++ b/mms/db_interface.h @@ -0,0 +1,229 @@ +/** +* @file: $RCSfile: db_interface.h,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.12 $ +* @date: $Date: 2019/01/12 08:44:26 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: db_interface.h,v 1.12 2019/01/12 08:44:26 lizhongming Exp $ +* +*/ + +#ifndef DB_INTERFACE_7ew2327hyhy0923r_H +#define DB_INTERFACE_7ew2327hyhy0923r_H + +#include "apr_time.h" + +#include //lnk20241022 + +#define LOG_IDX (0) +#define RPT_IDX (1) + +/////////////////////////////////////////////////////////////////////////////// +#define INVALID_DEV_IDX -1 + +#define STAT_DATA_BASE_NODE_ID 100 +#define THREE_SECS_DATA_BASE_NODE_ID 200 +#define SOE_COMTRADE_BASE_NODE_ID 300 +#define HIS_DATA_BASE_NODE_ID 400 +#define NEW_HIS_DATA_BASE_NODE_ID 500 +#define RECALL_HIS_DATA_BASE_NODE_ID 600 +#define RECALL_ALL_DATA_BASE_NODE_ID 700 + +#define REPORT_TYPE_STAT 1 +#define REPORT_TYPE_REAL 2 +#define REPORT_TYPE_SOE 4 +#define REPORT_TYPE_EVENT 8 + +#define SHOULD_DO_NOTHING 0 +#define SHOULD_REGISTER 1 +#define SHOULD_UNREGISTER 2 +/////////////////////////////////////////////////////////////////////////////// + + + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +extern char* OSS_ENDPOINT; +extern char* ACCESS_KEY_ID; +extern char* ACCESS_KEY_SECRET; +extern char* BUCKET_NAME; + +extern char* POSTGRES_SCHEMA; +extern char* POSTGRES_TABLEPREFIX; + +void GetSM4Code(unsigned char* pSerise,char* pKey,char* output); +void MyGetSM4Code(char* input,unsigned char* szKey,char* output); + +void try_start_kafka_thread(); + +void try_start_mqconsumer_thread();//lnk20241216 + +//0. jsonɿʼ +int json_block_create_start( char voltage_level[],char monid_char[],int flicker_flag, char temcode[],int line_id); +//1. jsonʱ꺯 +int json_block_create_time(char monid_char[], long long Time, int flicker_flag); +//1.5 jsonflag +int json_block_create_flag(char monid_char[], int flag, int flicker_flag); +//2. jsonݻص +int json_block_create_data(char monid_char[], char* mms_str , double v, int flicker_flag); +//3. jsonɽ +int json_block_create_end(char monid_char[], int flicker_flag); //CZY 2023-08-17 +//int json_block_create_end(int MonitorId,int devkind);//CZY 2023-08-17 + +//zw 2024-01-31 ģʽŻ +void add_mvl_type_ctrl(char doname[], int ctrl); +int sel_mvl_type_ctrl_flag(char doname[]); +void del_mvl_type_ctrl(); +//ģʽŻ end +#ifndef DB_INTERFACE_H +#define DB_INTERFACE_H +// ǰ LD_info_t +typedef struct LD_info_t LD_info_t; +int urcbRealDataHasReceived(int dev_index, LD_info_t* LD_info, long long Time); //lnk20241223 +#endif + +//void set_log_LineID(int id); +//void set_rpt_LineID(int id); + +//void set_log_TimeID(apr_time_t time); +//void set_rpt_TimeID(apr_time_t time); + +//void set_log_QualityFlag(int QualityFlag); +//void set_rpt_QualityFlag(int QualityFlag); + +int is_rpt_Time_exact_hour() ; + +apr_status_t app_get_private_config(const char *myfilename); + +void parse_log_switch_ini(unsigned int* error,unsigned int* warn,unsigned int* info); + + +int parse_device_cfg_json_test(); +int parse_line_cfg_pg_test(); + +int parse_device_cfg_json(); +int parse_device_cfg_pg(); +int parse_line_cfg_pg(); +void init_config(); +int init_ping_telnet(); +int GetServerIndexFromDB(); + +int parse_device_cfg(); +int parse_line_cfg(); +int parse_rpt_log_ini(); +int parse_json_cfg(); + +void clear_all_LD_real_soe_report_shoud_register(); + +void add_comm_log(char* log_str); +void prcess_monitor_comm_2_json(int monitor_id,int status,long long tm); + +void clear_old_comtrade_files(); + +int process_login_verify(); + +//////////////////////////////WW 20230819ݿ +int OTLConnect(); //OTLOracleݿ +int OTLDisconnect(); //OTLϿOracleݿ +int OTLState(); //OTLOracleݿ״̬ +int OTLDbconnected(); +int write_to_db(const char* sqlstm); //ݿд +int OTLTestSelect();//ݿȡ +void TestToken(); +void TestBodyPost();//WW qt post +void TestSMSPost();//WW qt post +void TestJson(char* szJson); +void TestOSS();//WW +void PutOSS(char* File_Name, char* data); //zw޸ 2023-9-7 ossļ +void GetOSS(char* File_Name, char* savepath); //zw޸ 2023-9-7 ȡossļ +void DelOSS(char* File_Name); +void delete_object_new(char* File_Name); +void coutTest();//CZY 2023-09-11 test +void TestOBS();//WW 20230921 ԻΪƷ +void OBSFile(char* localpath, char* cloudpath,const char* code); +void OBSFile_del(char* cloudpath, const char* code); + +void DataHub_Send_Datahub(char* topic, char* data);//datahubͨѶ +void Nacos_GetParam(char* postgres_uid, char* postgres_pwd, char* web_clientid, char* web_clientsecret);//nacos +void Nacos_GetParam_Ptr(const char* code, char** ptr); +void Read_Nacos_Param_Postgres(char** database_ip, char** database_port, char** postgres_database, char** postgres_username, char** postgres_password, char** postgres_schema, char** postgres_dnsname, char** postgres_tableprefix); +void Read_Nacos_Param_Kafka(char** broker_list, char** topic_stat, char** topic_pst, char** topic_plt, char** topic_event, char** topic_alarm, char** topic_sng, char** protocol, char** mechanisms, char** service_name, char** principal, char** domain_name); +void Read_Nacos_Param_Web(char** client_id, char** client_secret, char** token_url, char** device_url, char** grant_type); +void Read_Nacos_Param_Flag(int* file_flag, int* send_flag, int* front_inst, char** front_ip); +void Read_Nacos_Param_Recall(int* recall_len, int* recall_sta, int* recall_daily); +void Read_Nacos_Param_Uds(char** uds_upload_url, char** uds_download_url, char** uds_delete_url);//nacosȡuds +int WebAPI_Uds_Upload(char* strUrl, char* loacl_path, char* uuid,char* filename); +void WebAPI_Uds_Download(char* strUrl, char* uuid, char* local_path,char* filename); +int base64_decode(const char* indata, int inlen, char* outdata, long* outlen); +int testbase64(); +/////////////////////////////WW end + + +//////////////////////////////WW 20230822ݿWebSocket߳ +void try_start_sql_thread(); //Sqlִ߳ +void try_start_socket_thread(); //Web Socket߳ +void try_start_ontimer_thread();//ʱ߳s +/////////////////////////////WW end + +//lnk20241029http߳//////////////////////////////////////// +void try_start_web_http_thread(); //Webhttp߳ +void try_start_http_thread(); //http߳ + +int try_start_mqtest_thread(int argc, char *argv[]); //20241202 +////////////////////////////////////////////////////////////////////// + +int OTL_Select_xmlModel(); //xmlģݿȡ +void OTL_Select_recall(char* time, char* id); +int OTL_Select_DecideRecall(char* time, char* id);//жǷҪ +char* getoneday(int num); +void deletechar(char* day); +void CreateRecallXml(); +void DeletcRecallXml(); + + +/*lnk10-11*//////////////////////////////////////////////////////////////////////// +void rocketmq_test(); +void rocketmq_test_300(int mpnum,int front_index); +void curltest(); +void SOEFileWeb_test(); +void qvvr_test(); +void integrity_test(); +void comflag_test(); + +int parse_device_web_test_ext(); +int parse_device_web_test_dev(); +int parse_line_web_test(); +int parse_model_web_test(); +int parse_intact_web_test_read(); +int parse_device_web_test_front_read(); +int parse_device_web_test_front_write(); + +int parse_device_cfg_web(); +//int parse_line_cfg_web(); +int parse_model_cfg_web(); +void SOEFileWeb(char* localpath,char* cloudpath,char* wavepath); + +void OTL_Select_recall_web(char* time, char* id); +int OTL_Select_DecideRecall_web(char* time, char* id); +bool CheckPG_To_Recall_web(long long start, long long end, char* Monitorid); +////////////////////////////////////////////////////////////////////////////////////// + + +/*int parse_database_delete(const std::vector& codes); +int parse_commerror_write(const std::vector& codes); +int parse_commstatus_write(const std::vector& codes); +int parse_match_write(const std::vector& codes); +int parse_dataintegrity_write(const std::vector& codes); +int parse_rationality_write(const std::vector& codes);*/ + +#ifdef __cplusplus +} +#endif + + +#endif //DB_INTERFACE_7ew2327hyhy0923r_H \ No newline at end of file diff --git a/mms/event.c b/mms/event.c new file mode 100644 index 0000000..92593e7 --- /dev/null +++ b/mms/event.c @@ -0,0 +1,199 @@ +/** +* @file: $RCSfile: event.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:50 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: event.c,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1998 All Rights Reserved */ +/* */ +/* MODULE NAME : event.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* Event handling functions. */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* wait_any_event () */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 04/20/05 JRB 08 Add header files (included indirectly before).*/ +/* 07/07/04 JRB 07 Del #ifdef MOSI. May need a_get_event_handles*/ +/* added to stack lib if non-MOSI stack used. */ +/* 10/23/03 JRB 06 Call a_get_event_handles_unix for default system.*/ +/* 05/17/02 JRB 05 Put back old code for PHARLAP_ETS, PharLap */ +/* doesn't have "Wait..Ex". */ +/* 04/10/00 JRB 04 Del "select.h". See "sysincs.h". */ +/* 04/06/00 JRB 03 Use WaitForMultipleObjectsEx for WIN32: */ +/* CRITICAL for ethernet driver interface. */ +/* 08/05/99 JRB 02 Use a_get_ev.., gs_wait.. for WIN32. */ +/* Use hTcpEvent for OS2. */ +/* 11/10/98 JRB 01 Created */ +/************************************************************************/ + +#include "glbtypes.h" +#include "sysincs.h" +#include "mmsdefs.h" +#include "glbsem.h" +#include "acse2usr.h" + +#include "mvl_defs.h" +#include + +#if defined (_WIN32) +/************************************************************************/ +/* wait_any_event */ +/************************************************************************/ + +ST_VOID wait_any_event (ST_LONG max_ms_delay) + { +ST_EVENT_SEM *EventArray; +ST_INT NumEntries; +#if defined (PHARLAP_ETS) +ST_BOOLEAN activity [2]; /* We don't chk it, but gs_wait.. needs it*/ +#endif + + EventArray = a_get_event_handles (&NumEntries); + + /* Make sure there is at least 1 event to wait on. If not, probably */ + /* because library not compiled with correct switches. */ + assert (NumEntries > 0); + + /* If this fails, size of "activity" array must be increased. */ + assert (NumEntries <= 2); + +#if defined (PHARLAP_ETS) /* PharLap doesn't have/need "Wait...Ex"*/ + gs_wait_mult_event_sem (NumEntries, EventArray, activity, max_ms_delay); +#else + /* CRITICAL: Use Wait..Ex with last arg TRUE so that Ethernet driver */ + /* completion routines may be called. */ + WaitForMultipleObjectsEx (NumEntries, EventArray, + FALSE, /* return when ANY object signaled */ + max_ms_delay, + TRUE); +#endif + + /* Something woke us up. Don't care if it was event or timeout. */ + /* Just return to main loop to attempt processing. */ + return; + } + +#elif defined (__OS2__) + +/************************************************************************/ +/* wait_any_event */ +/* DEBUG: not tested but should work on OS/2. */ +/************************************************************************/ + +ST_VOID wait_any_event (ST_LONG max_ms_delay) + { +#define MMS_EVENT_SEM_ID 0 +static SEMRECORD sems[2]; +static HMUX hMux; +APIRET apiret; +ST_ULONG post_count; +ST_ULONG semId; + + /* This function only waits on the MMS event. To wait on other events */ + /* also, add to the "sems" array. */ + + if (hMux == NULL) + { + sems[0].hsemCur = (void *) hTcpEvent; + sems[0].ulUser = MMS_EVENT_SEM_ID; + apiret = DosCreateMuxWaitSem (NULL, &hMux, 1, sems, DCMW_WAIT_ANY); + if (apiret != NO_ERROR) + { + printf ("\n DosCreateMuxWaitSem failed, rc = %d",apiret); + hMux = NULL; + } + return; /* Just return. New event so no one has signaled it yet.*/ + } + + /* Wait on the MMS Event Semaphore. */ + + apiret = DosWaitMuxWaitSem (hMux, max_ms_delay, &semId); + + if (apiret == NO_ERROR) + { + if (semId == MMS_EVENT_SEM_ID) /* MMS event */ + { + gs_reset_event_sem (hTcpEvent); /* OS2 requires reset */ + } + } + else if (apiret != ERROR_TIMEOUT) + { + printf ("\n DosWaitMuxWaitSem error, apiret = %d",apiret); + } + } + +#elif defined(MSDOS) || defined(__MSDOS__) + +/************************************************************************/ +/* wait_any_event */ +/************************************************************************/ + +ST_VOID wait_any_event (ST_LONG max_ms_delay) + { + return; + } +#else /* All other systems */ + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif +/************************************************************************/ +/* wait_any_event */ +/************************************************************************/ +ST_VOID wait_any_event (ST_LONG max_ms_delay) + { + struct timeval stTimeVal; + fd_set readfds; + fd_set writefds; + fd_set exceptfds; + int nfds=0; + int *fd_array; /* ptr to array of handles on which to wait */ + int num_entries; /* num of entries in fd_array. */ + int j; /* loop index */ + + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); +// FD_SET (0, &readfds); /* select on "stdin" */ + + /* Ask ACSE for array of handles on which to wait. */ + fd_array = a_get_event_handles_unix (&num_entries); + + for (j = 0; j < num_entries; j++) + { + FD_SET (fd_array[j], &readfds); + nfds = max (nfds,fd_array[j]); + } + nfds++; /* must be 1 greater than max handle. */ + + /* If you want to wait for other events too, add more FD_SET calls, */ + /* and recompute "nfds" (or just set it to FD_SETSIZE). */ + + max_ms_delay *= 1000; /*** Convert to micro seconds ***/ + stTimeVal.tv_sec = max_ms_delay / 1000000; + stTimeVal.tv_usec = max_ms_delay % 1000000; + + nfds = select (nfds, &readfds, &writefds, &exceptfds, &stTimeVal); + if (nfds<0){ + printf("select error: errno= %i , %s",errno, strerror(errno) ); + } + } + +#endif /* All other systems */ + diff --git a/mms/event2.c b/mms/event2.c new file mode 100644 index 0000000..5f11456 --- /dev/null +++ b/mms/event2.c @@ -0,0 +1,74 @@ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 2003 All Rights Reserved */ +/* */ +/* MODULE NAME : event2.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* Event handling function. This function may be used ONLY if */ +/* the the POLLING version of the "gensock2" sockets interface is */ +/* used (i.e. gensock2.c is compiled with GENSOCK_THREAD_SUPPORT */ +/* NOT defined). */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* wait_any_event () */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 01/30/07 JRB 04 Shorten sleep to avoid delay detecting connect.*/ +/* 12/11/06 JRB 03 Wait for Subnetwork events too. */ +/* 11/01/06 JRB 02 Call sMsSleep when no connections, */ +/* so we don't hog the CPU. */ +/* 07/10/03 JRB 01 Created */ +/************************************************************************/ + +#include "glbtypes.h" +#include "sysincs.h" +#include "mmsdefs.h" +#include "gensock2.h" +#include "clnp_sne.h" /* for "Subnetwork" event stuff */ + +/************************************************************************/ +/* wait_any_event */ +/* Wait for "socket" events OR "Subnetwork" events. */ +/* NOTE: See comments about "PORTING" if this function needs */ +/* to wait on "other" handles. */ +/************************************************************************/ +ST_VOID wait_any_event (ST_LONG max_ms_delay) + { +GENSOCK_FD_SET sockFds; +int nfds; +struct timeval selectTimeout; + + /* This function assumes only one group of sockets to process. */ + sockInitAllFds (&sockFds); + + /* If Subnetwork handle "hPktSock" is valid, add it to list. */ + if (hPktSock >= 0) + sockAddReadFds (&sockFds, hPktSock); + + /* PORTING: Call sockAddReadFds, sockAddWriteFds, sockAddExceptFds + * to add "other" handles on which to wait. + */ + if (sockFds.totalfds) + { + /* Convert milliseconds to seconds and microseconds */ + selectTimeout.tv_sec = max_ms_delay / 1000; /* seconds */ + selectTimeout.tv_usec = (max_ms_delay % 1000) * 1000; /* microseconds */ + nfds = select (sockFds.selectnfds, &sockFds.readfds, &sockFds.writefds, &sockFds.exceptfds, &selectTimeout); + + /* PORTING: Add code to process "other" handles. */ + } + else + sMsSleep (10); /* no sockets to wait on, so sleep a little to avoid hogging CPU.*/ + + /* NOTE: socket events are NOT processed here. This function simply returns, + * and the caller must call "mvl_comm_serve" to process the events. + */ + return; + } + diff --git a/mms/gentypes.odf b/mms/gentypes.odf new file mode 100644 index 0000000..d06b9cd --- /dev/null +++ b/mms/gentypes.odf @@ -0,0 +1,207 @@ +############################################################# +#Copyright 1998-2003, Systems Integration Specialists Company, Inc. +# All Rights Reserved +############################################################# +# 08/23/04 JRB Fix BOOLEAN definition. +# 05/13/04 JRB Fix INT16U definition. +# 10/08/03 RKR Added types from chapter 8 + 61850-8-1_CDV_R1-06_To-IEC-CO_2002-11-22.doc +# 03/13/03 JRB Reverse last chg. Use new types in "rpt.odf" instead. +# 12/16/02 JRB Chg types needed for Rpts to ":TK". Add "VBSTR5", "OSTR8". + +# IEC-61850-8-1: section 8.1.1 Basic data attribute types + +":T","BOOLEAN" "Bool", "0 or 1" +":T","INT8" "Byte", "-128 to 127" +":T","INT16" "Short", "-32,768 to 32,767" +":T","INT32" "Long", "-2,147,483,648 to 2,147,483,647" +":T","INT128" "Long", "-2**127 to (2**127)-1 Good luck" +":T","INT8U" "Ubyte", "0 to 255" +":T","INT16U" "Ushort", "0 to 65,535" +":T","INT32U" "Ulong", "0 to 4,294,967,295" +":T","FLOAT32" "Float", "Range of values IEEE 754 single" +":T","FLOAT64" "Double", "Range of values IEEE 754 double" +":T","ENUMERATED8", "Byte", "signed enumeration8-bits" +":T","ENUMERATED16", "Short", "signed enumeration16-bits" +":T","OCTET_STRING8", "OVstring8", "Maximum 8 Octets" +":T","OCTET_STRING64", "OVstring64", "Maximum 64 Octets" +":T","VISIBLE_STRING255","Vstring255", "Maximum 255 characters" +":T","VISIBLE_STRING64","Vstring64", "Maximum 64 characters" +":T","VISIBLE_STRING97","Vstring97", "Maximum 97 characters" +":T","UTC_TM", "Utctime", "Used by TimeStamp" +":T","CODED_ENUM2", "Bstring2", "2 bits - 4 values" +":T","UNICODE_STRING255","UTF8Vstring255","Maximum 255 Unicode" + +":T", "TimeStamp" "", "UTC Time" +":T", "EntryTime" "Btime6", " 8.1 Section 8.1.3.7" +":T", "Quality" "BVstring13", "Quality" + + +#general types for clause 4.2.1 of GOMSFE +":T","IDENT", "Vstring65", "" +":T","BOOL", "Bool", "generalboolean" +":T","B2", "Bstring2", "GeneralDoubleBit" +":T","D", "VString32", "generaldescriptioncomponent" +":T","DB", "UShort", "Deadband" +":T","F", "Float", "Generalizedfloatingpoint" +":T","FF", "Float", "FrozenFloatingPointvalue" +":T","HL", "Short", "HighLimit" +":T","HHL", "Short", "HighHighLimit" +":T","LL", "Short", "lowlimit" +":T","LLL", "Short", "lowlowlimit" +":T","I", "Short", "Generalizedicomponenttype" +":T","FI", "Short", "frozenicomponenttype" +":T","O", "Float", "Offset" +":T","Q", "Bvstring16", "Generalizedqualitybitstringtype" +":T","R", "ULong", "runningcount" +":T","FR", "ULong", "frozenrunningcount" +":T","S", "Float", "scale" +":T","T", "Btime6", "GeneralizedTimeStamp" +":T","FT", "Btime6", "frozentimestamp" +":T","PP", "Bool", "PseudoPoint" +":T","U", "Short", "Enumeratevalue" +":T","VSTR8", "Vstring8", "VisibleString8-variablelength" +":T","VSTR16", "Vstring16", "VisibleString16-variablelength" +":T","VSTR32", "Vstring32", "VisbleString32-variablelength" +":T","VSTR64", "Vstring64", "VisibleString64-variablelength" +":T","VSTR65", "Vstring65", "VisibleString65-variablelength" +":T","VSTR128", "Vstring128", "VisibleString128-variablelength" + +#From Clause 4.2.2 of GOMSFE + +":T","BSTR1", "Bstring1", "Twobitbistring" +":T","BSTR2", "Bstring2", "Twobitbistring" +":T","BSTR8", "Bstring8", "Bitstring-8" +":T","BSTR16", "Bstring16", "Bitstring-16" +":T","BSTR32", "Bstring32", "Bitstring-32" +":T","VBSTR8", "Bvstring8", "VariablelengthBitstring-8" +":T","VBSTR16", "Bvstring16", "VariablelengthBitstring-16" +":T","VBSTR32", "Bvstring32", "VariablelengthBitstring-32" +#INT8U, INT16U, & INT32U already defined in IEC-61850 section above +":T","INT8S", "Byte", "SignedInteger-8" +":T","INT16S", "Short", "SignedInteger-16" +":T","INT32S", "Long", "SignedInteger-32" +":T","FLT32", "Float", "32bitfloatingpoint" +":T","FLT64", "Double", "64bitfloatingpoint" +":T","BTIME4", "Btime4", "Binarytimeofday" +":T","BTIME6", "Btime6", "Binarytimeofdaytomsec" +":T","ENUM8", "Byte", "signed enumeration8-bits" +":T","ENUM16", "Short", "signed enumeration16-bits" + +#missing from GOMSFE +":T","MAG", "", "Magnitude" +":T","ANG", "", "Angle" + + +":T","ACCRPTENA", "", "AccumulatorReportEnable" +":T","ACCRS", "", "AccumulatorReset" +":T","ACCSET", "", "AccumulatorSetting" +":T","ACTTAGARR", "", "Accumulatortagarray" +":T","ANCESTRY", "", "Ancestry" +":T","ANFMT", "Vstring6", "AnalogFormat" +":T","BUFTIM", "", "Buffertime" +":T","CID", "", "CanonicalID" +":T","CKTID", "", "CircuitID" +":T","CKTPHS", "", "CircuitPhases" +":T","CLASS", "", "Classidentifier" +":T","COMMADR", "", "Communicationaddress" +":T","COMMREV", "", "Communicationrevision" +":T","CONTCURRTG", "", "Continuouscurrentrating" +":T","COUNT", "", "count" +":T","CRIRPT", "", "criticalreport" +":T","DATSETNAM", "", "Datasetname" +":T","DESTAE", "", "destinationAEname" +":T","DEVFCT", "", "devicefunction" +":T","DEVMDLS", "", "devicemodelname" +":T","DOW", "", "Dayoftheweek" +":T","DOWSCHED", "[6:]", "Dayoftheweekschedule" +":T","ENABLE", "", "enable" +":T","ENCOPT", "", "encodingoptions" +":T","ENROLL", "", "enrollname" +":T","EORBDESC", "", "" +":T","EVACON", "", "evaluationconditionname" +":T","EVACNS", "", "evaluationconditionname" +":T","EVACRI", "", "evaluationcriterianame" +":T","EVAFCT", "", "evaluationfunctionname" +":T","EVAPAR", "", "evaluationparametersname" +":T","EVTENA", "", "eventenable" +":T","FLTCURDUR", "", "Faultcurrentduration" +":T","FLTCURRTG", "", "Placeholder" +":T","FRZENA", "", "freezeenable" +":T","FRZPD", "", "freezeperiod" +":T","FWDPWRHA", "[31:]", "ForwardPowerharmonics" +":T","HWREV", "", "HardwareRevision" +":T","HZRTG", "", "Hertzrating" +":T","INDAT", "", "InputDataName" +":T","INTGPD", "", "IntegrityPeriod" +":T","LINLENM", "", "Linelengthinmeters" +":T","LOC", "", "Location" +":T","LOGENA", "", "Logenable" +":T","LOGENR", "", "Logenroll" +":T","LOGNAM", "", "Logname" +":T","LOGSIZE", "", "Logsize" +":T","LOGWRP", "", "LogWrapped" +":T","MAC", "", "MediumAccessControl" +":T","MDL", "", "Modelname" +":T","MED", "", "mediatype" +":T","MXREF", "", "Measurementreference" +":T","MXTYP", "", "MeasurementType" +":T","NAME", "", "ownername" +":T","NEWTIM", "", "newesttime" +":T","NUMBITS", "", "numberofbits" +":T","NUMPLS", "", "numberofpulses" +":T","NUMSMP", "", "numberofsamples" +":T","NUMUNIT", "", "numberofunits" +":T","OFFDUR", "", "Offduration" +":T","OLDTIM", "", "Oldesttime" +":T","ONDUR", "", "Onduration" +":T","OPERDEV", "", "Operatedevice" +":T","OPTFLDS", "", "Optionalfields" +":T","OUTDAT", "", "outputdatasetname" +":T","OVRST", "", "Overflowstatus" +":T","OWN", "", "Owner" +":T","PRO", "", "enumeratedprotocolid" +":T","PWRHA", "[31:]", "powerharmonics" +":T","QURPTENA", "", "qualityreportenable" +":T","RBEPD", "", "reportperiod" +":T","RPTENA", "", "Reportenable" +":T","RPTID", "", "ReportID" +":T","RVSPWRHA", "[31:]", "reversepowerharmonics" +":T","SBOENA", "", "SBOenable" +":T","SETTIMOUT", "", "SBOSelectTimeout" +":T","SEQNUM", "", "Sequencenumber" +":T","SERNUM", "", "Serialnumber" +":T","SFTREV", "", "SoftwareRevisionNumber" +":T","SMPRATE", "", "samplerate" +":T","TAGD", "", "tagdescription" +":T","TAGID", "", "tagID" +":T","TAGOWN", "", "tagowner" +":T","TAGTYP", "", "tagtypepermitted" +":T","TEMPRAT", "", "temperaturerating" +":T","TEMPRTG", "", "temperaturerating" +":T","TIMOFFRZ", "", "timeoffreeze" +":T","TIMRPTENA", "", "Timestampreportenable" +":T","TRGOPS", "", "Triggeroptions" +":T","TRGS", "", "numberoftriggers" +":T","UNITVARRTG", "", "Unitvarrating" +":T","UNKPWRHA", "[31:]", "Unkownharmonicdirection" +":T","USEST", "", "utilizationstatus" +":T","VARRTG", "", "Varsrating" +":T","VARTG", "", "VARsrating" +":T","VND", "", "VendorID" +":T","VRTG", "", "voltagerating" +":T","WRNLEV", "", "logwarninglevel" +":T","WRNST", "", "warningstatus" + +":T","PHSTAR", "", "PhaseTarget" +":T","SBO", "", "" + +#Additional types added from other sections +#to support GOOSE and PACT +":T","STNUM", "", "" +":T","HOLDTIM", "", "" +":T","BACKTIM", "", "" +":T","PHSID", "", "" +":T","DNA", "Bstring64", "" +":T","USERST", "BVstring128", "" + diff --git a/mms/interface.h b/mms/interface.h new file mode 100644 index 0000000..558b234 --- /dev/null +++ b/mms/interface.h @@ -0,0 +1,182 @@ +/** +* @file: $RCSfile: interface.h,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.4 $ +* @date: $Date: 2019/01/08 08:15:34 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: interface.h,v 1.4 2019/01/08 08:15:34 lizhongming Exp $ +* +*/ + +//$Header: /JoyProject/jspqfe/src/pt61850netd_pqfe/source/mms/interface.h,v 1.4 2019/01/08 08:15:34 lizhongming Exp $ +/************************************************************************/ +/* SAC HEADER ************************************************************/ +/************************************************************************/ +/* */ +/* MODULE NAME : interface.h */ +/* PRODUCT(S) : wg_sac_61850 */ +/* */ +/* MODULE DESCRIPTION : */ +/* Defines functions that should be use between mmsease and scadacom */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ + +/* 2006-6-23 lzm 01 New */ +/************************************************************************/ + +#ifndef SAC_INTERFACE_H +#define SAC_INTERFACE_H + + +/////////////////////////////////////////////////////// +#if defined (_WIN32) +#include +#endif + +#include "sasstd.h" + +#include "glbtypes.h" +#include "sysincs.h" +#include "signal.h" +#include "mmsdefs.h" +#include "mms_pvmd.h" +#include "mms_pvar.h" +#include "mms_vvar.h" +#include "mms_err.h" +#include "mms_pcon.h" +#include "asn1defs.h" +#include "mmsop_en.h" +#include "mvl_log.h" +#include "slog.h" +#include "tp4api.h" +#include "clntobj.h" +#include "mmsclient.h" + + +/////////////////////////////////////////////////// + + +#define MAX_DATA_STR_SIZE 256 + +#define DATA_INT_TYPE 0 +#define DATA_UINT_TYPE 1 +#define DATA_INT64_TYPE 2 +#define DATA_UINT64_TYPE 3 +#define DATA_DOUBLE_TYPE 4 +#define DATA_STR_TYPE 5 +#define DATA_TIME_TYPE 6 + +typedef struct mms_decode_data_item + { + ST_CHAR comp_name[MAX_DATA_STR_SIZE]; + ST_UCHAR type; // + ST_UCHAR size; //ݵЧֽ + union + { + ST_INT32 data_int; + ST_UINT32 data_uint; +#ifdef INT64_SUPPORT + ST_INT64 data_int64; + ST_UINT64 data_uint64; +#endif + ST_DOUBLE data_double; + ST_CHAR data_str[MAX_DATA_STR_SIZE]; + MMS_BTIME6 data_bTime6; + } u; + + } MMS_DECODE_DATA_ITEM; + +#define MAX_DATA_ITEMS_IN_ONE_DATA 1024 // change for PQS882 2016-5-10 //10-10-26-8-53 bei jing +typedef struct mms_decode_data + { + ST_UINT item_num; //ݵЧ + MMS_DECODE_DATA_ITEM data_item[MAX_DATA_ITEMS_IN_ONE_DATA]; + + } MMS_DECODE_DATA; + + +void init_MMS(); +void exit_MMS(); +ST_VOID doCommService (); + +ST_VOID init_log_cfg (ST_VOID); +ST_VOID set_rem_dib_table_size (ST_INT size); +ST_VOID add_rem_dib_table (ST_INT pos,ST_CHAR *remAr,unsigned short port); + +ST_RET mms_connectToServer (ST_CHAR * dev_key,ST_CHAR *dev_series, ST_CHAR *serverARName, + MVL_NET_INFO **clientNetInfo, MVL_REQ_PEND **reqCtrl); + +ST_RET mms_mvla_identify (MVL_NET_INFO *net_info,char** ident,int iTimeout); +ST_RET mms_mvla_fdir (MVL_NET_INFO *net_info,ST_CHAR *filespec,int iTimeout, + char*** filenames ,int* filenum,apr_pool_t *pool); +ST_RET mms_getFile (MVL_NET_INFO *clientNetInfo, ST_CHAR *loc_file, + ST_CHAR *rem_file, ST_INT iTimeout); + +ST_RET mms_mvla_status (MVL_NET_INFO *net_info,int iTimeout); + +ST_RET mms_mvla_getnam (MVL_NET_INFO *net_info,ST_INT scope, + ST_CHAR *domName,ST_INT16 mms_class, int iTimeout, + char*** varnames ,int* varnum,apr_pool_t *pool); + +ST_INT mms_var_type_id_create (MVL_NET_INFO *clientNetInfo, ST_INT scope, + ST_CHAR *dom_name, ST_CHAR *var_name, int iTimeOut); + +ST_RET mms_named_var_read (MVL_NET_INFO *net_info, ST_CHAR *varName, + ST_INT scope, ST_CHAR *domName, + ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut); + +ST_VOID Callback_channel_disconnect_ind(MVL_NET_INFO * NetInfo, ST_INT discType); +ST_RET mms_disconnectFromServer (MVL_NET_INFO *clientNetInfo,MVL_REQ_PEND **reqCtrl); + +RCB_INFO *mms_register_iec_rpt (MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, + ST_CHAR *dom_name, /* domain which contains the RCB*/ + ST_CHAR *rcb_name, /* RCB (e.g. "LLN0$BR$PosReport")*/ + ST_INT timeOut, ST_INT scanRate,ST_UCHAR trgops,ST_UINT8* pEntryID,ST_UINT8* OptFlds); + +ST_RET mms_unregister_iec_rpt (MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, + ST_CHAR *dom_name, /* domain which contains the RCB*/ + ST_CHAR *rcb_name, /* RCB (e.g. "LLN0$BR$PosReport")*/ + ST_INT timeOut ); +//WW 2023-08-29 豸ʹ +RCB_INFO *mms_register_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, + ST_CHAR *dom_name, /* domain which contains the RCB*/ + ST_CHAR *rcb_name, /* RCB (e.g. "LLN0$BR$PosReport")*/ + ST_INT timeOut, ST_CHAR *dev_type, ST_CHAR *ip, int port, ST_INT scanRate, ST_UCHAR trgops, ST_UINT8* pEntryID, ST_UINT8* OptFlds); + +ST_RET mms_unregister_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, ST_CHAR *dev_type, ST_CHAR *ip, int port, + ST_CHAR *dom_name, /* domain which contains the RCB*/ + ST_CHAR *rcb_name, /* RCB (e.g. "LLN0$BR$PosReport")*/ + ST_INT timeOut); +//WW end + +void my_local_to_data (ST_CHAR *datptr, SD_CONST RUNTIME_TYPE *rt_head, + ST_INT rt_num,MMS_DECODE_DATA *data); + + +RCB_INFO* FindRcbInfo(MVL_NET_INFO *net_info,ST_CHAR *dom_name, ST_CHAR *rcb_name); + +int mms_iec_setPoint(ST_UCHAR ctlModel, MVL_NET_INFO *clientNetInfo, + ST_CHAR *dom_name, ST_CHAR *ctrl_name, float32_t fctlVal, ST_BOOLEAN Check, int iTimeOut); + +int mms_iec_control (ST_UCHAR ctlModel,MVL_NET_INFO *clientNetInfo, + ST_CHAR *dom_name, ST_CHAR *ctrl_name, int ictlVal, ST_BOOLEAN Check, int iTimeOut); + +int mms_iec_control_yt (ST_UCHAR ctlModel,MVL_NET_INFO *clientNetInfo, + ST_CHAR *dom_name, ST_CHAR *ctrl_name, int ictlVal, ST_BOOLEAN Check, int iTimeOut); + +ST_INT mms_get_datatype_from_type_id (ST_INT type_id, ST_UCHAR* datatype,ST_INT *len); + +void convert_apr_time_to_utc_time(apr_time_t tm,MMS_UTC_TIME *utc_time); + +ST_RET my_asn1_convert_utc_to_btod (MMS_UTC_TIME *utc, MMS_BTOD *btod); + +apr_time_t convert_btod_to_apr_time (MMS_BTOD *btod ); +apr_time_t convert_btime6_to_apr_time (MMS_BTIME6 *bTime6 ); + +#endif //SAC_INTERFACE_H + diff --git a/mms/logcfg.xml b/mms/logcfg.xml new file mode 100644 index 0000000..0106a7c --- /dev/null +++ b/mms/logcfg.xml @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ON + OFF + OFF + OFF + OFF + + + + ON + 1000000 + mms.log + + + OFF + 1000 + mmsdmem.log + OFF + + + TimeDate + ON + OFF + ON + ON + ON + OFF + ON + ON + ON + + + + OFF + OFF + + + + ON + OFF + OFF + OFF + + ON + OFF + OFF + OFF + + + + OFF + OFF + + + ON + OFF + OFF + + + ON + OFF + OFF + OFF + OFF + OFF + + + ON + OFF + OFF + OFF + OFF + OFF + + + OFF + OFF + OFF + OFF + OFF + OFF + OFF + OFF + OFF + OFF + + + OFF + OFF + + + OFF + OFF + OFF + OFF + OFF + + + + OFF + OFF + OFF + OFF + + + ON + OFF + OFF + OFF + OFF + OFF + OFF + OFF + + + OFF + OFF + + + OFF + OFF + OFF + OFF + + + OFF + OFF + OFF + OFF + OFF + OFF + + + diff --git a/mms/logcfgx.c b/mms/logcfgx.c new file mode 100644 index 0000000..3416c5b --- /dev/null +++ b/mms/logcfgx.c @@ -0,0 +1,645 @@ +/** +* @file: $RCSfile: logcfgx.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:50 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: logcfgx.c,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 2000 - 2005, All Rights Reserved */ +/* */ +/* MODULE NAME : logcfgx.c */ +/* PRODUCT(S) : */ +/* */ +/* MODULE DESCRIPTION : This module processes each value parsed in */ +/* the logcfg.xml file . The logcfg.xml file */ +/* assigns Log File Attributes and */ +/* Miscellaneous Control Flags as well as */ +/* Memory Use Logging and various Log Masks */ +/* to enable specific logging required. */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ -------------------------------------------- */ +/* 08/10/05 MDE 13 Added logCfgRemoveAllMaskGroups */ +/* 06/21/05 EJV 12 Deleted obsolete logcfgx function. */ +/* 05/23/05 EJV 11 Moved xxxLogMaskMapCtrl to respective C files.*/ +/* Del m_track_prev_free (not used anymore). */ +/* Force user to use logcfgx_ex insted of logcfgx*/ +/* 04/25/05 MDE 10 Added MMS_LOG_CLIENT & MMS_LOG_SERVER */ +/* 03/31/05 MDE 09 Put suicacse.h back, for MAP30_ACSE */ +/* 03/28/05 JRB 08 Del suicacse header. */ +/* 02/10/05 MDE 07 Changed MILOG_ to MI_LOG_ */ +/* 02/10/05 MDE 06 Added new DATATYPE's */ +/* 01/27/05 MDE 05 DEBUG_SISCO #ifdefs, LINUX warning cleanup */ +/* 01/20/05 MDE 04 Lot's more work ... */ +/* 12/10/04 ASK 03 Added Slog IPC params, added */ +/* case _LOGCFG_DATATYPE_UINT32_MASK */ +/* Modify params to use 'R'everse data type */ +/* Update copyright year */ +/* 11/16/04 MDE 02 Fixed to compile with MAP30_ACSE */ +/* 10/12/04 MDE 01 Complete rewrite to work with SX changes, */ +/* make extendable */ +/************************************************************************/ + +#include "glbtypes.h" +#include "sysincs.h" +#include "mem_chk.h" +#include "gen_list.h" +#include "str_util.h" +#include "slog.h" + +#include "sx_defs.h" +#include "sx_log.h" + +/************************************************************************/ + +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ + +#if defined(DEBUG_SISCO) +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +/************************************************************************/ + +LOGCFG_VALUE_GROUP *logCfgLogMaskGroupList; +static LOGCFGX_TAG_VAL *_tagValList; + +/************************************************************************/ +#if defined(DEBUG_SISCO) +static LOG_CTRL tmp_sLogCtrl; + +ST_UINT logcfg_debug_sel; + +/* Log type strings */ +SD_CONST ST_CHAR *SD_CONST _logcfg_log_err_logstr = "LOGCFG_ERR"; +SD_CONST ST_CHAR *SD_CONST _logcfg_log_nerr_logstr = "LOGCFG_NERR"; +SD_CONST ST_CHAR *SD_CONST _logcfg_log_flow_logstr = "LOGCFG_FLOW"; + +LOGCFGX_VALUE_MAP logcfgMaskMaps[] = + { + {"LOGCFG_ERR", LOGCFG_ERR, &logcfg_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Error"}, + {"LOGCFG_NERR", LOGCFG_NERR, &logcfg_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Notice"}, + {"LOGCFG_FLOW", LOGCFG_FLOW, &logcfg_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Flow"} + }; + +LOGCFG_VALUE_GROUP logcfgMaskMapCtrl = + { + {NULL,NULL}, + "LOGCFG", + sizeof(logcfgMaskMaps)/sizeof(LOGCFGX_VALUE_MAP), + logcfgMaskMaps + }; + +/************************************************************************/ +/************************************************************************/ + +LOGCFGX_VALUE_MAP logCfgLogMaskMaps[] = + { +/* SLOG Control */ + {"LogFileEnable", LOG_FILE_EN, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_UINT32_MASK}, + {"DestroyOldFile", FIL_CTRL_NO_APPEND, &tmp_sLogCtrl.fc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"Setbuf", FIL_CTRL_SETBUF_EN, &tmp_sLogCtrl.fc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"MsgHeader", FIL_CTRL_MSG_HDR_EN, &tmp_sLogCtrl.fc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"Wipe", FIL_CTRL_WIPE_EN, &tmp_sLogCtrl.fc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"Wrap", FIL_CTRL_WRAP_EN, &tmp_sLogCtrl.fc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"HardFlush", FIL_CTRL_HARD_FLUSH, &tmp_sLogCtrl.fc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"LogMemoryEnable", LOG_MEM_EN, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_UINT32_MASK}, + {"MemoryFileDump", MEM_CTRL_AUTODUMP_EN, &tmp_sLogCtrl.mc.ctrl, _LOGCFG_DATATYPE_UINT_MASK}, + {"LogIpcListenEnable", LOG_IPC_LISTEN_EN, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_UINT32_MASK}, + {"LogIpcCallEnable", LOG_IPC_CALL_EN, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_UINT32_MASK}, + {"LogIpcSmartMode", LOG_IPC_SMART, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_UINT32_MASK}, + {"HeaderCr", LOG_NO_HEADER_CR, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_RUINT32_MASK}, + {"HeaderFilename", LOG_FILENAME_SUPPRESS, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_RUINT32_MASK}, + {"HeaderLogType", LOG_LOGTYPE_SUPPRESS, &tmp_sLogCtrl.logCtrl, _LOGCFG_DATATYPE_RUINT32_MASK}, + {"LogFileSize", 0, &tmp_sLogCtrl.fc.maxSize, _LOGCFG_DATATYPE_ULONG}, + {"LogFileName", 0, &tmp_sLogCtrl.fc.fileName, _LOGCFG_DATATYPE_FILENAME}, + {"LogMemoryItems", 0, &tmp_sLogCtrl.mc.maxItems, _LOGCFG_DATATYPE_ULONG}, + {"MemoryFileName", 0, &tmp_sLogCtrl.mc.dumpFileName, _LOGCFG_DATATYPE_FILENAME}, + {"LogIpcAppId", 0, &tmp_sLogCtrl.ipc.appId, _LOGCFG_DATATYPE_STRING}, + {"LogIpcListenPort", 0, &tmp_sLogCtrl.ipc.port, _LOGCFG_DATATYPE_UINT16}, + {"LogIpcNumListenPorts", 0, &tmp_sLogCtrl.ipc.portCnt, _LOGCFG_DATATYPE_UINT16}, + {"LogIpcMaxListenConn", 0, &tmp_sLogCtrl.ipc.maxConns, _LOGCFG_DATATYPE_UINT}, + {"LogIpcCallingPort", 0, &tmp_sLogCtrl.ipc.callingPort, _LOGCFG_DATATYPE_UINT16}, + {"LogIpcCallingIp", 0, &tmp_sLogCtrl.ipc.callingIp, _LOGCFG_DATATYPE_STRING}, + {"LogIpcMaxQueCount", 0, &tmp_sLogCtrl.ipc.maxQueCnt, _LOGCFG_DATATYPE_UINT}, + }; + +LOGCFG_VALUE_GROUP logCfgLogCtrlMapCtrl = + { + {NULL,NULL}, + "", + sizeof(logCfgLogMaskMaps)/sizeof(LOGCFGX_VALUE_MAP), + logCfgLogMaskMaps + }; +#endif /* defined(DEBUG_SISCO) */ + + +/************************************************************************/ +/************************************************************************/ + +static ST_RET _logcfg_data_start (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag); +static ST_RET _logcfg_data_end (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag); + + +/************************************************************************/ +/* logCfgAddMaskGroup */ +/************************************************************************/ + +ST_VOID logCfgAddMaskGroup (LOGCFG_VALUE_GROUP *logMaskGroup) + { + if (list_find_node (logCfgLogMaskGroupList, logMaskGroup) != SD_SUCCESS) + list_add_last (&logCfgLogMaskGroupList, logMaskGroup); + } + +/************************************************************************/ +/* logCfgRemoveMaskGroup */ +/************************************************************************/ + +ST_VOID logCfgRemoveMaskGroup (LOGCFG_VALUE_GROUP *logMaskGroup) + { + if (list_find_node (logCfgLogMaskGroupList, logMaskGroup) == SD_SUCCESS) + list_unlink (&logCfgLogMaskGroupList, logMaskGroup); + } + +/************************************************************************/ +/* logCfgRemoveAllMaskGroups */ +/************************************************************************/ + +ST_VOID logCfgRemoveAllMaskGroups () + { + logCfgLogMaskGroupList = NULL; + } + +/************************************************************************/ +/* logCfgFindTagVal */ +/************************************************************************/ + +LOGCFGX_TAG_VAL *logCfgFindTagVal (ST_CHAR *tag) + { +LOGCFGX_TAG_VAL *tagVal; + + tagVal = _tagValList; + while (tagVal != NULL) + { + if (!strcmp (tag, tagVal->tag)) + return (tagVal); + + tagVal =(LOGCFGX_TAG_VAL*) list_get_next (_tagValList, tagVal); + } + return (NULL); + } + +/************************************************************************/ +/* logCfgClearTagVals */ +/************************************************************************/ + +ST_VOID logCfgClearTagVals () + { +LOGCFGX_TAG_VAL *tagVal; + + while (_tagValList) + { + tagVal = (LOGCFGX_TAG_VAL *) list_unlink (&_tagValList, _tagValList); + if (tagVal->dataType == _LOGCFG_DATATYPE_STRING || + tagVal->dataType == _LOGCFG_DATATYPE_FILENAME) + { + chk_free (tagVal->u.str); + } + chk_free (tagVal); + } + } + +/************************************************************************/ +/************************************************************************/ +/* logcfgx_ex */ +/* User must call logCfgAddMaskGroup for each group of log masks to be */ +/* configured BEFORE calling this function to parse the file. */ +/************************************************************************/ + +typedef struct + { + LOG_CTRL *destLogCtrl; + ST_INT state; + ST_CHAR *logFileName; + ST_CHAR *fileNamePrefix; + ST_BOOLEAN masksOnly; + ST_BOOLEAN saveTagVals; + } LOGCFGX_CTRL; + + +ST_RET logcfgx_ex (LOG_CTRL *destLogCtrl, ST_CHAR *logFileName, ST_CHAR *fileNamePrefix, + ST_BOOLEAN masksOnly, ST_BOOLEAN saveTagVals) + { +LOGCFGX_CTRL logCfgxCtrl; +ST_UINT sx_debug_sel_save; +ST_RET rc; +#if defined(DEBUG_SISCO) +ST_CHAR *savedFileName; +#endif + + logCfgxCtrl.destLogCtrl = destLogCtrl; + logCfgxCtrl.logFileName = logFileName; + logCfgxCtrl.fileNamePrefix = fileNamePrefix; + logCfgxCtrl.masksOnly = masksOnly; + logCfgxCtrl.saveTagVals = saveTagVals; + +#if defined(DEBUG_SISCO) + logcfg_debug_sel |= LOGCFG_ERR; + logcfg_debug_sel |= LOGCFG_NERR; + sx_debug_sel |= SX_LOG_ERR; + sx_debug_sel |= SX_LOG_NERR; + + if (masksOnly) + logCfgRemoveMaskGroup (&logCfgLogCtrlMapCtrl); + else + logCfgAddMaskGroup (&logCfgLogCtrlMapCtrl); + +/* Always allow LOGCFG & SX logging ... */ + logCfgAddMaskGroup (&logcfgMaskMapCtrl); + logCfgAddMaskGroup (&sxLogMaskMapCtrl); + + savedFileName = sLogCtrl->fc.fileName; + + /* Copy original "sLogCtrl" to temporary struct which may be modified */ + /* by the configuration. */ + /* This prevents logging control changes while there may be logging. */ + + memcpy (&tmp_sLogCtrl, sLogCtrl, sizeof (LOG_CTRL)); +#endif + + rc = sx_parseEx_mt (logFileName, 0, NULL, &logCfgxCtrl, _logcfg_data_start, _logcfg_data_end); + if (rc != SD_SUCCESS) + { + /* Config failed: Do not modify "sLogCtrl". */ + /* Turn on cfg logging and parse file again. */ + sx_debug_sel_save = sx_debug_sel; + + sx_debug_sel |= SX_LOG_DEC | SX_LOG_ENC | SX_LOG_FLOW | SX_LOG_DEBUG; + LOGCFG_ERR0 ("ERROR Parsing Logging Configuration File: Trying again w/debug on ... "); + rc = sx_parseEx_mt (logFileName, 0,NULL,&logCfgxCtrl, _logcfg_data_start, _logcfg_data_end); + sx_debug_sel = sx_debug_sel_save; + } + else /* rc == SD_SUCCESS */ + { + LOGCFG_FLOW0 ("Logging configuration complete"); + } + return (rc); + } + +/************************************************************************/ +/************************************************************************/ +/* _logcfg_data_start */ +/************************************************************************/ + +#define LOGCFGX_STATE_NONE 0 +#define LOGCFGX_STATE_UNKNOWN 1 +#define LOGCFGX_STATE_LOGCTRL 2 +#define LOGCFGX_STATE_LOGMASKS 3 + +static ST_RET _logcfg_data_start (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag) + { +LOGCFGX_CTRL *logCfgxCtrl; + + logCfgxCtrl =(LOGCFGX_CTRL*) sxDecCtrl->usr; + if (!strcmp (tag, "LogControl")) + logCfgxCtrl->state = LOGCFGX_STATE_LOGCTRL; + else if (!strcmp (tag, "LogMasks")) + logCfgxCtrl->state = LOGCFGX_STATE_LOGMASKS; + + return (SD_SUCCESS); + } + +/************************************************************************/ +/* _logcfg_data_end */ +/************************************************************************/ + + +static ST_RET _logcfg_data_end (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag) + { +LOGCFGX_CTRL *logCfgxCtrl; +LOGCFG_VALUE_GROUP *slogMaskGroup; +LOG_CTRL *destLogCtrl; +LOGCFGX_TAG_VAL *tagVal; +SX_DEC_ELEMENT_INFO *sxDecElInfo; +ST_VOID (*logCfgCallbackFun) (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag, + LOGCFGX_VALUE_MAP *valMap); +ST_CHAR *cp; +ST_CHAR *str; +ST_BOOLEAN *bp; +ST_BOOLEAN b; +ST_INT i; +ST_INT strLen; +ST_RET rc; +ST_UINT *up; +ST_UINT32 *u32p; +ST_UINT16 *u16p; +ST_ULONG *ulp; +ST_CHAR **cpp; +ST_DOUBLE *dp; +#if defined(DEBUG_SISCO) +ST_CHAR *oldFileName; +ST_BOOLEAN logFileChanged; +#endif +ST_BOOLEAN found; +ST_CHAR *p; + + logCfgxCtrl =(LOGCFGX_CTRL*) sxDecCtrl->usr; + + if (!strcmp (tag, "LogMasks")) + { + logCfgxCtrl->state = LOGCFGX_STATE_NONE; + return (SD_SUCCESS); + } + + destLogCtrl = logCfgxCtrl->destLogCtrl; + sxDecElInfo = &sxDecCtrl->sxDecElInfo; + + if (!strcmp (tag, "LogControl")) + { +#if defined(DEBUG_SISCO) + logFileChanged = SD_FALSE; + if (logCfgxCtrl->masksOnly == SD_FALSE) + { + /* If the log file name has changed and the log file is open, */ + /* close the log file and clear state. */ + + if (destLogCtrl->fc.state & FIL_STATE_OPEN) + { + oldFileName = destLogCtrl->fc.fileName; +#ifdef _WIN32 /* Filenames NOT case sensitive on Windows */ + if (_stricmp (tmp_sLogCtrl.fc.fileName, oldFileName) != 0) +#else + if (strcmp (tmp_sLogCtrl.fc.fileName, oldFileName) != 0) +#endif + { /* NEW log file name different from OLD. */ + fclose (destLogCtrl->fc.fp); /* close it */ + destLogCtrl->fc.state &= ~(FIL_STATE_OPEN); /* clear state */ + logFileChanged = SD_TRUE; + } + } + if (tmp_sLogCtrl.fc.ctrl & FIL_CTRL_MSG_HDR_EN) + tmp_sLogCtrl.mc.ctrl |= MEM_CTRL_MSG_HDR_EN; + else + tmp_sLogCtrl.mc.ctrl &= ~MEM_CTRL_MSG_HDR_EN; + + destLogCtrl->logCtrl = tmp_sLogCtrl.logCtrl; + destLogCtrl->fc.ctrl = tmp_sLogCtrl.fc.ctrl; + destLogCtrl->fc.fileName = tmp_sLogCtrl.fc.fileName; + destLogCtrl->fc.maxSize = tmp_sLogCtrl.fc.maxSize; + destLogCtrl->mc.ctrl = tmp_sLogCtrl.mc.ctrl; + destLogCtrl->mc.dumpFileName = tmp_sLogCtrl.mc.dumpFileName; + destLogCtrl->mc.maxItems = tmp_sLogCtrl.mc.maxItems; + destLogCtrl->ipc.appId = tmp_sLogCtrl.ipc.appId; + destLogCtrl->ipc.port = tmp_sLogCtrl.ipc.port; + destLogCtrl->ipc.portCnt = tmp_sLogCtrl.ipc.portCnt; + destLogCtrl->ipc.maxConns = tmp_sLogCtrl.ipc.maxConns; + destLogCtrl->ipc.callingIp = tmp_sLogCtrl.ipc.callingIp; + destLogCtrl->ipc.callingPort = tmp_sLogCtrl.ipc.callingPort; + destLogCtrl->ipc.maxQueCnt = tmp_sLogCtrl.ipc.maxQueCnt; + + } + LOGCFG_FLOW2 ("LogCfg loading file %s, prefix %s", + logCfgxCtrl->logFileName, logCfgxCtrl->fileNamePrefix); + if (logFileChanged) + { + _slog (destLogCtrl,_logcfg_log_flow_logstr, thisFileName,__LINE__, + "See the file '%s' for messages logged before or during Logging config", + oldFileName); + } +#endif + logCfgxCtrl->state = LOGCFGX_STATE_NONE; + return (SD_SUCCESS); + } + + +/* Get the pointer to the contents */ + strLen = 0; + rc = sx_get_string_ptr (sxDecCtrl, &str, &strLen); + if (rc != SD_SUCCESS) + return (rc); + +/* OK, this might be an Log Mask or other value of interest */ +/* If we are to save this in a list, start here */ + if (logCfgxCtrl->saveTagVals && logCfgxCtrl->state == LOGCFGX_STATE_LOGMASKS) + { + tagVal = logCfgFindTagVal (tag); + if (tagVal) + { + list_unlink (&_tagValList, tagVal); + if (tagVal->dataType == _LOGCFG_DATATYPE_STRING || + tagVal->dataType == _LOGCFG_DATATYPE_FILENAME) + { + chk_free (tagVal->u.str); + } + chk_free (tagVal); + } + + tagVal = (LOGCFGX_TAG_VAL*)chk_calloc (1, sizeof (LOGCFGX_TAG_VAL) + strlen (tag) + 1); + p = (ST_CHAR *) (tagVal + 1); + tagVal->tag = p; + strcpy (p, tag); + list_add_last (&_tagValList, tagVal); + } + else + tagVal = NULL; + +/* Now see if we can find it ... */ + found = SD_FALSE; + slogMaskGroup = logCfgLogMaskGroupList; + while (slogMaskGroup) + { + for (i = 0; i < slogMaskGroup->numMaskMap; ++i) + { + if (!strcmp (tag, slogMaskGroup->maskMapTbl[i].tag)) + { + found = SD_TRUE; + if (tagVal != NULL) + tagVal->dataType = slogMaskGroup->maskMapTbl[i].dataType; + + switch (slogMaskGroup->maskMapTbl[i].dataType) + { + case _LOGCFG_DATATYPE_UINT_MASK: + up =(ST_UINT*) slogMaskGroup->maskMapTbl[i].addr; + sx_get_string_OnOff_bool (sxDecCtrl, &b, SX_ERR_CONVERT); + if (b) + *up |= slogMaskGroup->maskMapTbl[i].mask; /* Set the bit */ + else + *up &= ~slogMaskGroup->maskMapTbl[i].mask; /* Clear the bit */ + + LOGCFG_CFLOW2 ("Setting log mask %-16s %s", tag, b ? "ON" : "OFF"); + + if (tagVal != NULL) + tagVal->u.b = b; + break; + + case _LOGCFG_DATATYPE_UINT32_MASK: + u32p =(ST_UINT32 *) slogMaskGroup->maskMapTbl[i].addr; + sx_get_string_OnOff_bool (sxDecCtrl, &b, SX_ERR_CONVERT); + if (b) + *u32p |= slogMaskGroup->maskMapTbl[i].mask; /* Set the bit */ + else + *u32p &= ~slogMaskGroup->maskMapTbl[i].mask; /* Clear the bit */ + + LOGCFG_CFLOW2 ("Setting log mask %-16s %s", tag, b ? "ON" : "OFF"); + if (tagVal != NULL) + tagVal->u.b = b; + break; + + /* 'R'everse mask settings */ + case _LOGCFG_DATATYPE_RUINT32_MASK: + up =(ST_UINT *) slogMaskGroup->maskMapTbl[i].addr; + sx_get_string_OnOff_bool (sxDecCtrl, &b, SX_ERR_CONVERT); + if (b) + *up &= ~slogMaskGroup->maskMapTbl[i].mask; /* Clear the bit */ + else + *up |= slogMaskGroup->maskMapTbl[i].mask; /* Set the bit */ + + LOGCFG_CFLOW2 ("Setting log mask %-16s %s", tag, b ? "ON" : "OFF"); + if (tagVal != NULL) + tagVal->u.b = b; + break; + + case _LOGCFG_DATATYPE_BOOLEAN: + bp = (ST_BOOLEAN *) slogMaskGroup->maskMapTbl[i].addr; + sx_get_string_OnOff_bool (sxDecCtrl, bp, SX_ERR_CONVERT); + LOGCFG_CFLOW2 ("Setting boolean %-16s %s", tag, *bp ? "ON" : "OFF"); + if (tagVal != NULL) + tagVal->u.b = *bp; + break; + + case _LOGCFG_DATATYPE_INT: + case _LOGCFG_DATATYPE_UINT: + up =(ST_UINT *) slogMaskGroup->maskMapTbl[i].addr; + sx_get_uint (sxDecCtrl, up); + LOGCFG_CFLOW2 ("Setting %16s to %d", tag, (int) *up); + if (tagVal != NULL) + tagVal->u.uInt = *up; + break; + + case _LOGCFG_DATATYPE_LONG: + case _LOGCFG_DATATYPE_ULONG: + ulp =(ST_ULONG *) slogMaskGroup->maskMapTbl[i].addr; + sx_get_ulong (sxDecCtrl, ulp); + LOGCFG_CFLOW2 ("Setting %16s to %ld", tag, (long int) *ulp); + if (tagVal != NULL) + tagVal->u.uLong = *ulp; + break; + + case _LOGCFG_DATATYPE_INT16: + case _LOGCFG_DATATYPE_UINT16: + u16p =(ST_UINT16*) slogMaskGroup->maskMapTbl[i].addr; + sx_get_uint16 (sxDecCtrl, u16p); + LOGCFG_CFLOW2 ("Setting %16s to %d", tag, (int) *u16p); + if (tagVal != NULL) + tagVal->u.uInt16 = *u16p; + break; + + case _LOGCFG_DATATYPE_INT32: + case _LOGCFG_DATATYPE_UINT32: + u32p = (ST_UINT32 *)slogMaskGroup->maskMapTbl[i].addr; + sx_get_ulong (sxDecCtrl, u32p); + LOGCFG_CFLOW2 ("Setting %16s to %d", tag, (int) *u32p); + if (tagVal != NULL) + tagVal->u.uInt32 = *u32p; + break; + + case _LOGCFG_DATATYPE_DOUBLE: + dp =(ST_DOUBLE *) slogMaskGroup->maskMapTbl[i].addr; + sx_get_double (sxDecCtrl, dp); + LOGCFG_CFLOW2 ("Setting %16s to %.4f", tag, *dp); + if (tagVal != NULL) + tagVal->u.uInt32 = *u32p; + break; + + case _LOGCFG_DATATYPE_STRING: + cpp =(ST_CHAR **) slogMaskGroup->maskMapTbl[i].addr; + sx_get_alloc_string (sxDecCtrl, cpp); + LOGCFG_CFLOW2 ("Setting %16s to '%s'", tag, *cpp); + if (tagVal != NULL) + tagVal->u.str = *cpp; + break; + + case _LOGCFG_DATATYPE_STRINGBUF: + cp =(ST_CHAR *) slogMaskGroup->maskMapTbl[i].addr; + strLen = 0; + sx_get_string_ptr (sxDecCtrl, &str, &strLen); + LOGCFG_CFLOW2 ("Setting %16s to '%s'", tag, str); + cp =(ST_CHAR *) slogMaskGroup->maskMapTbl[i].addr; + strncpy_safe (cp, str, slogMaskGroup->maskMapTbl[i].mask); + + if (tagVal != NULL) + tagVal->u.str = cp; + break; + + case _LOGCFG_DATATYPE_FILENAME: + cpp = (ST_CHAR **)slogMaskGroup->maskMapTbl[i].addr; + + /* The user might want a prefix for this file name */ + strLen = 0; + sx_get_string_ptr (sxDecCtrl, &str, &strLen); + if (logCfgxCtrl->fileNamePrefix) + strLen += strlen (logCfgxCtrl->fileNamePrefix); + p =(ST_CHAR *) chk_malloc (strLen+1); + *cpp = p; + if (logCfgxCtrl->fileNamePrefix) + strcpy (p, logCfgxCtrl->fileNamePrefix); + else + *p = 0; + strcat (p, str); + + LOGCFG_CFLOW2 ("Setting %-16s to '%s'", tag, p); + if (tagVal != NULL) + tagVal->u.str = p; + break; + + case _LOGCFG_DATATYPE_CALLBACK: + logCfgCallbackFun = (ST_VOID(*)(SX_DEC_CTRL*,ST_CHAR*,LOGCFGX_VALUE_MAP*)) slogMaskGroup->maskMapTbl[i].addr; + if (logCfgCallbackFun != NULL) + (*logCfgCallbackFun) (sxDecCtrl, tag, &slogMaskGroup->maskMapTbl[i]); + break; + } + break; + } + } + slogMaskGroup =(LOGCFG_VALUE_GROUP*) list_get_next (logCfgLogMaskGroupList, slogMaskGroup); + } + +/* If we did not find it but are supposed to get it's value anyway ... */ + if (tagVal != NULL && found == SD_FALSE) + { + strLen = 0; + sx_get_string_ptr (sxDecCtrl, &str, &strLen); + if (!stricmp (str, "On")) + { + LOGCFG_CFLOW1 ("Setting log mask %-16s ON", tag); + tagVal->u.b = SD_TRUE; + tagVal->dataType = _LOGCFG_DATATYPE_BOOLEAN; + } + else if (!stricmp (str, "Off")) + { + LOGCFG_CFLOW1 ("Setting log mask %-16s OFF", tag); + tagVal->u.b = SD_FALSE; + tagVal->dataType = _LOGCFG_DATATYPE_BOOLEAN; + } + else + { + tagVal->u.str = chk_strdup (p);; + tagVal->dataType = _LOGCFG_DATATYPE_STRING; + } + } + + return (SD_SUCCESS); + } + diff --git a/mms/main.c b/mms/main.c new file mode 100644 index 0000000..7fcf6c1 --- /dev/null +++ b/mms/main.c @@ -0,0 +1,456 @@ +/** +* @file: $RCSfile: main.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.9 $ +* @date: $Date: 2020/10/28 05:21:18 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: main.c,v 1.9 2020/10/28 05:21:18 lizhongming Exp $ +* +*/ + +#include "rdb_client.h" +#include "db_interface.h" +#include "node.h" + +/*lnk10-10 */ +#include "../include/rocketmq/SimpleProducer.h" +extern G_TEST_FLAG; +extern pthread_mutex_t mtx; + +extern pt61850app_t *g_pt61850app; +extern node_t *g_node; +char g_my_conf_fname[256]; +//extern byte_t g_Master; +char g_onlyIP[255]; //ֱijIPΪ +//extern byte_t g_protect_file; //0:ٻ¼ļ 1:ٻ¼ļ + +apr_pool_t *g_root_pool; +apr_pool_t *g_rdb_pool; +apr_pool_t *g_cfg_pool; +uint16_t g_client_id = 0; +uint32_t g_node_id = 0; +uint32_t g_min_free_size = 1024; +int g_need_password = 0; + +char subdir[128] = "cfg_stat_data" ; + +int usage(); +int parse_param(int argc, const char **argv); + +#include "ver_conf.h" + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +/////////////////////////////////////////////////////// +uint32_t g_dead_lock_counter = 0; +uint32_t g_thread_blocked_times = 0; +/////////////////////////////////////////////////////////////////////////////// +int three_secs_enabled = 0; +int auto_register_report_enabled = 0; +int g_front_seg_index = 0; +int g_front_seg_num = 0; +int FRONT_MP_NUM = 0;//ն +int g_front_num_count = 0;//նʹ + + +/////////////////////////////////////////////////////////////////////////////// +//Ŀ¼бȫֹܵͶˣ趨ĸֹܾĹл趨 +void init_global_function_enable() +{ + if (strcmp(subdir,"cfg_stat_data")==0) { //ʷ̬ + g_node_id = STAT_DATA_BASE_NODE_ID; + auto_register_report_enabled = 1; + }else if (strcmp(subdir,"cfg_3s_data")==0) { //ʵʱ + g_node_id = THREE_SECS_DATA_BASE_NODE_ID; + three_secs_enabled = 1; + }else if (strcmp(subdir,"cfg_soe_comtrade")==0) { //澯¼̬ + g_node_id = SOE_COMTRADE_BASE_NODE_ID; + }else if (strcmp(subdir,"cfg_his_data")==0) { //ʹ + g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; + g_node_id = HIS_DATA_BASE_NODE_ID; + } + else if (strcmp(subdir, "cfg_newhis_data") == 0) { //ʹ + g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; + g_node_id = NEW_HIS_DATA_BASE_NODE_ID; + } + else if (strcmp(subdir, "cfg_recallhis_data") == 0) { // + g_node_id = RECALL_HIS_DATA_BASE_NODE_ID; + } + else if (strcmp(subdir, "cfg_recallall_data") == 0) { //ʹ + g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; + } +} +////////////////////////////////////////////////////////////////////////////////// + +#ifdef _OS_UNIX_ +void init_daemon(void) +{ + int pid; + int i; + + if( pid = fork() ) + exit(0); /** Ṇ̀ */ + else if( pid < 0 ) + exit(1); /** forkʧܣ˳ */ + + /** ǵһӽִ̨̣ */ + + setsid(); /** һӽ̳ΪµĻỰ鳤ͽ鳤ն˷ */ + + if( pid = fork() ) + exit(0); /** ǵһӽ̣һӽ */ + else if( pid < 0) + exit(1); /** forkʧܣ˳ */ + + chdir("/FeProject/bin/"); //multi process running at same time + umask(0); /** ļ */ + + return; +} +#endif + +//"--subdir, set the subdir of /CloudForward/ as the working directory, \n" +int usage() +{ + // fprintf(stderr,"\n\n******** IEC61850 Protocol ********\n"); + fprintf(stderr,"\nUsage : pt61850netd_pqfe -d [subdir] \n"); + + exit(-1); +} + + +int prepare_entironment_2() +{ + apr_status_t rv; + + /* apr library need call this first. */ + apr_initialize(); //APACHEʼ + atexit(apr_terminate); + + + /* Create node root pool */ + rv = apr_pool_create(&g_root_pool, NULL); //ڴ + if(rv != APR_SUCCESS) { + fprintf(stderr,"%s","Create node root pool failed!\n"); + return (-1); + } + +#ifdef SIGPIPE + /* Ignore writes to connections that have been closed at the other end. */ + apr_signal(SIGPIPE, SIG_IGN); +#endif + + rv = create_log_handle(g_root_pool); + if(rv != APR_SUCCESS) { + printf("init_log failed!\n"); + return (-1); + } + else { + unsigned int error = 0; + unsigned int warn = 0; + unsigned int info = 0; + log_config_t *log_handle = get_log_handle(); + parse_log_switch_ini(&error,&warn,&info); + log_handle->status.debug = info;//0;//1; + log_handle->status.warn = warn;//0;//1; + log_handle->status.error = error;//0;//1; + } + echo_msg("==============================================================\n"); + + rv = apr_pool_create(&g_rdb_pool, g_root_pool); //RDBڴ + if(rv != APR_SUCCESS) { + echo_errg("Create system runtime pool failed!\n"); + return (-1); + } + + rv = apr_pool_create(&g_cfg_pool, g_root_pool); //ڴ + if(rv != APR_SUCCESS) { + echo_errg("Create system config pool failed!\n"); + return (-1); + } + + //g_fun_pool = 0; + + //rv = apr_thread_mutex_create(&g_rdb_mutex, APR_THREAD_MUTEX_NESTED,g_root_pool);//RDB + //if ( rv != APR_SUCCESS) { + // return rv; + //} + /* Initialize the register table. Call these functions first! */ + echo_msg1("%-60s","Initialize system register......"); + //init_default_dbparser_table(); //ݸXMLļRDBʼ + //load_driver_library(); //ø˿ + echo_msg("OK\n\n"); + + initTimezoneOffset(); + + return APR_SUCCESS; +} + +#ifdef _OS_UNIX_ +#include +#include +#include +void printf_cur_user() +{ + struct passwd *pwd; + pwd = getpwuid(getuid()); + echo_warn1("Current user: %s\n", pwd->pw_name); +} +#endif + +int main(int argc, const char **argv) +{ + +// ipcclient_t *ipcclient = NULL; +// void *cookie = NULL; + uint32_t stimer = 1; + apr_status_t rv; +// int pid; + + /* Prepare the system context */ + rv=prepare_entironment_2(); + if (rv!=APR_SUCCESS){ + return rv; + } + + getVersion(argc,argv); + + //////////////////// + //WW json + //TestJson(NULL); + //WW 2023-08-31 end + /////////////////// + //TestSMSPost();//WW 2023-08-28Թ˾post + //TestBodyPost(); + //TestToken();//Դҵ̨ + + //////////////////// + //WW json + //TestOSS(); + //TestOBS(); + //WW 2023-09-01 end + /////////////////// + /* Parse the command-line parameter */ + rv=parse_param(argc, argv); + if (rv!=APR_SUCCESS){ + return rv; + } + +#ifdef _OS_UNIX_ + #ifdef QT_NO_DEBUG + if (!g_need_password) + init_daemon(); + #endif +#endif + + init_global_function_enable(); + apr_snprintf(g_my_conf_fname,sizeof(g_my_conf_fname),"../%s/etc/pt61850netd_pqfe.xml",subdir); + +#if defined (DEBUG_SISCO) + init_log_cfg (); +#endif + + printf("\n\n"); +#ifdef _OS_UNIX_ + printf_cur_user(); +#endif + + if (g_need_password) { + if ( process_login_verify() == 0) { + echo_warn("User login succeeded!\n"); + } else { + echo_warn("User login failed!\n"); + apr_sleep(apr_time_from_sec(3)); + exit(-59); + } + } + + rv = init_rdb(); + if (rv!=APR_SUCCESS){ + return rv; + } + +//lnk20241024ȥݿ + //OTLConnect(); + + + rv = run_protocol(); + if (rv!=APR_SUCCESS){ + return rv; + } + + + while(1) { + /* sleep 1s, just like 1s timer */ + apr_sleep(apr_time_from_sec(1)); + /* ÿ30Ӽһ״̬ */ + + /*mqlnk10-10 */ + //rocketmq_test_rt(); + //rocketmq_test_ud(); + //rocketmq_test_rc(); + /*lnk20241029recallӿڲ*/ + //curltest(); + /*202411-1lnkļϴ */ + //SOEFileWeb_test(); + //ϴ + //qvvr_test(); + //apr_sleep(apr_time_from_sec(3)); + //comflag_test(); + //apr_sleep(apr_time_from_sec(3)); + + if( !(stimer++ % 60) ) {// + if (g_dead_lock_counter++ >=3) {// + g_thread_blocked_times++; + g_dead_lock_counter = 0; + } + MVL_LOG_ACSE1 ("MYLOG: current g_thread_blocked_times = %u ", g_thread_blocked_times); + + if (FRONT_MP_NUM <= 1) {// + g_front_num_count++; + } + else { + g_front_num_count = 0; + } + } + + //work߳3*13ӣ˳ + if (g_thread_blocked_times>=13) { + MVL_LOG_ACSE0 ("MYLOG: g_thread_blocked_times>=3, so exit to restart "); + apr_sleep(apr_time_from_sec(10)); + exit(-1039); + } + + //lnk20241211 ӲԿ + pthread_mutex_lock(&mtx);//̶߳ʱɨȡ̨˼ + if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30Ҳǵ̨˴ʮն + MVL_LOG_ACSE0("MYLOG: g_front_num_count>=20, so exit to restart "); + apr_sleep(apr_time_from_sec(10)); + exit(-1039); + } + pthread_mutex_unlock(&mtx); + + } + + echo_warn1("%-60s","System shutdown now......"); + apr_pool_destroy(g_root_pool); + echo_msg("OK\n"); + + return 0; +} + + +int parse_param(int argc, const char **argv) +{ + apr_status_t rv; + apr_getopt_t *opt; + char *opt_arg; + char ch; + + char *p; + char temp[128]; + //int g_front_seg_index, g_front_seg_num; + /* Set default command-line parameter */ + g_node_id = 0; + //g_protect_file = 0; + + echo_warn2("================= compiled@ %s %s =================\n",__DATE__ , __TIME__ ); + + /* Parse the command-line parameter */ + if( argc > 1 ) { + rv = apr_getopt_init(&opt, g_root_pool, argc, argv); + + while (apr_getopt(opt, "q:Q:a:A:d:D:p:P:f:F:r:R:T:t:s:S", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { + case 'q': + case 'Q': + if (opt_arg[0] >= '0' && opt_arg[0] <= '9' ) { + g_min_free_size = atoi(opt_arg); + } + else + return (usage()); + break; + case 'R': + case 'r': + // if (opt_arg[0] >= '0' && opt_arg[0] <= '9' ) + // { + // g_client_id = atoi(opt_arg); + // if (g_client_id>2||g_client_id<0) + // { + // printf("Do not support triple or above clients \n "); + // return (usage()); + // } + ////g_auto_client_id = FALSE; + // } + // else + // return (usage()); + break; + case 's': + case 'S': + echo_warn1(">>>>>>>>>>>>>>>>>>>>>parse -s %s ", opt_arg); + strcpy(temp, opt_arg); + + p = strtok(temp, "_"); //1_5 + echo_warn1("p %s ", p); + g_front_seg_index = atoi(p); + + printf("g_front_seg_index:%d",g_front_seg_index); + + p = strtok(NULL, "_"); //1_5 + echo_warn1("p %s ", p); + g_front_seg_num = atoi(p); + + printf("g_front_seg_num:%d",g_front_seg_num); + + //echo_warn2("================= compiled@ %d %d =================\n", g_front_seg_index, g_front_seg_num); + //lnk20241206Ҫ¼subdirʹ + //echo_warn1("subdir %s ", opt_arg + 6); + //strcpy(subdir, opt_arg + 6); + + break; + break; + case 'a': + case 'A': + strcpy(g_onlyIP,opt_arg); + break; + case 'd': + case 'D': + strcpy(subdir,opt_arg); + break; + case 'T': + case 't': + break; + case 'f': + case 'F': + //if (opt_arg[strlen(opt_arg)-1] == '/' + // || opt_arg[strlen(opt_arg)-1] == '\\') { + // echo_errg( "Error: Bad or invalid file name"); + // return (usage()); + // } + // //g_my_conf_fname = SHR_GetPrivateFileName(opt_arg,g_root_pool); + // echo_warn1("using config file %s!\n", g_my_conf_fname); + // break; + case 'P': + case 'p': + if (opt_arg[0] >= '0' && opt_arg[0] <= '9' ) { + g_need_password = atoi(opt_arg); + } + else + return (usage()); + break; + case '?': + default: + return (usage()); + } + } + } + + return 0; +} + + diff --git a/mms/mms_process.c b/mms/mms_process.c new file mode 100644 index 0000000..a1a526d --- /dev/null +++ b/mms/mms_process.c @@ -0,0 +1,2044 @@ +/** +* @file: $RCSfile: mms_process.c,v $ +* @brief: $PROFIBUS SSRTDB +* +* @version: $Revision: 1.28 $ +* @date: $Date: 2022/11/28 07:13:13 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mms_process.c,v 1.28 2022/11/28 07:13:13 lizhongming Exp $ +*/ +#include + +#include "rdb_client.h" + +//#include "../misc/utf8_to_gb.h" +//#include "../misc/gb_to_utf8.h" +#include +#include "db_interface.h" +#include "node.h" +#include "ied.h" + +#include "../json/mms_json_inter.h" + +void clear_rpt_counter_by_trigger(trigger_t *trigger); + +//lnk20241031 +extern void SOEFileWeb(char* localpath,char* cloudpath,char* wavepath); +//lnk 2024-11-4 ʱת +char* convertMsToDateTimeString(int msTime); +//lnk20250115 +extern pthread_mutex_t mtx; +extern apr_pool_t* g_cfg_pool; +extern apr_pool_t* g_init_pool; + +extern int g_DevFlag; + +//lnk20250115end + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +#ifdef _OS_UNIX_ +#include +#endif +extern uint32_t g_dead_lock_counter; +extern uint32_t g_thread_blocked_times; + +extern uint16_t g_client_id; + +extern RPT_TYPEIDS g_rpt_typeids; +//extern rdb_t *g_rdb ; +extern node_t *g_node ; +extern char g_my_conf_fname[256]; +extern apr_pool_t *g_init_pool; +extern apr_pool_t *g_run_pool; +extern pt61850app_t *g_pt61850app; +//extern char *g_sysfile_filedir; +extern char g_onlyIP[255]; //ֱijIPΪ +//extern int g_sysfile_appid; //add by rzx +//extern apr_time_t g_file_valid_time; +extern uint32_t g_min_free_size; +///////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +extern uint32_t g_node_id; + +extern int three_secs_enabled; +extern int auto_register_report_enabled; +extern int FRONT_MP_NUM; +/////////////////////////////////////////////////////////////////////////////// +extern int FILE_FLAG; + +extern int recall_len; +extern int recall_sta; +extern int recall_daily; +extern char* UDS_UPLOAD_URL; + +/////////////////////////////////////////////////////////////////// + +apr_status_t init_rem_dib_table() +{ + int pos = 0; + int iedno,chnl_no; + ied_t *ied; + struct in_addr ip; + chnl_usr_t *chnl_usr; + + set_rem_dib_table_size( g_pt61850app->chnl_counts ); + g_pt61850app->chnl_usr = apr_pcalloc( g_init_pool,g_pt61850app->chnl_counts*sizeof(chnl_usr_t*) ); + printf( "set_rem_dib_table_size %d \n",g_pt61850app->chnl_counts ); + for(iedno=0 ; iednon_clients; iedno++) { + ied = g_node->clients[iedno]; + for(chnl_no=0 ; chnl_nochncount; chnl_no++) { + chnl_usr = ied->channel[chnl_no].connect; + g_pt61850app->chnl_usr[pos] = chnl_usr; + ip.s_addr = htonl(ied->channel[chnl_no].addr); + strcpy(chnl_usr->ip_str,inet_ntoa(ip)); + printf( " add_rem_dib_table %s:%d \n",chnl_usr->ip_str ,ied->channel[chnl_no].port ); + add_rem_dib_table (pos++,chnl_usr->ip_str,ied->channel[chnl_no].port ); + { + char comm_str[256]; + memset(comm_str,0,256); + apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tinited",chnl_usr->ip_str,ied->channel[chnl_no].port); + add_comm_log(comm_str); + } + } + } + return APR_SUCCESS; +} + + +void CloseIECReports(chnl_usr_t *chnl_usr) +{ + ied_t *ied; + ied_usr_t *ied_usr; + LD_info_t *LD_info; + rptinfo_t *rptinfo = NULL; + int cpuno,rpt_no; + ST_RET ret; + + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { + char rpt_inst_name[65]; + rptinfo = LD_info->rptinfo[rpt_no]; + if ( ! rptinfo->rpt_registered ) + continue; + if ( rptinfo->chnl_id != chnl_usr->chnl_id) + continue; + /*get_rpt_inst_name(rptinfo,rpt_inst_name); + ret = mms_unregister_iec_rpt (chnl_usr->net_info, &g_rpt_typeids, + LD_info->LD_name,rpt_inst_name,g_pt61850app->mmsOpTimeout ); + if(ret == SD_FAILURE) + { + echo_warn3("unregister iec_rpt failed !!! domain: %s ,rpt_inst_name: %s ,chnl_id: %d \n", + LD_info->LD_name,rpt_inst_name,chnl_usr->chnl_id); + } + else + { + printf("unregister iec_rpt succeed, domain: %s ,rpt_inst_name: %s ,chnl_id: %d \n", + LD_info->LD_name,rpt_inst_name,chnl_usr->chnl_id); + } */ + rptinfo->rpt_registered = FALSE; + //עȡ10 עһεƣע + rptinfo->m_LastRegisterFailedTime = sGetMsTime() -10*60*1000; + rptinfo->m_rcb_info = NULL; + } + } +} + +void prcess_ied_comm_2_json(ied_t *ied,int status) +{ + ied_usr_t *ied_usr = NULL; + LD_info_t *LD_info = NULL; + int cpuno ; + apr_time_t tm = apr_time_now()/1000; + + if (!three_secs_enabled) + return; + ied_usr = (ied_usr_t*)ied->usr_ext; + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info ) { + //prcess_monitor_comm_2_json(LD_info->line_id,status,tm); + } + } +} + +void closeChannel(chnl_usr_t *chnl_usr) +{ + char comm_str[256]; + memset(comm_str,0,256); + apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tdisconnected !!!",chnl_usr->ip_str,chnl_usr->chnl->port); + add_comm_log(comm_str); + FRONT_MP_NUM--; + echo_warn1("Close Channel IP: %s",chnl_usr->ip_str ); + //prcess_ied_comm_2_json(chnl_usr->chnl->ied,STATUS_BREAKOFF); + //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_BREAKOFF, chnl_usr->chnl_id); + //write_status_to_db(0,chnl_usr->chnl->addr); + + CloseIECReports(chnl_usr); + echo_warn1("-------Close Channel IP: %s success!!!!!!!!!", chnl_usr->ip_str); + + if (chnl_usr->net_info) { + ALL_RCB_INFO *all_rcb_info; + RCB_INFO *rcb_info; + ST_RET ret; + if(chnl_usr->net_info->user_info) + { + all_rcb_info = (ALL_RCB_INFO *)chnl_usr->net_info->user_info; + while((rcb_info = (RCB_INFO *)list_get_first(&all_rcb_info->rcb_info_list)) != NULL) + rcb_info_destroy (rcb_info); + chk_free(all_rcb_info); + chnl_usr->net_info->user_info=NULL; + } + chnl_usr->net_info->rem_vmd = NULL; + echo_warn("---------start disconnectFromServer!\n"); + ret = mms_disconnectFromServer(chnl_usr->net_info,&chnl_usr->m_reqCtrl); + echo_warn("---------end disconnectFromServer!\n"); + + if (ret != SD_SUCCESS){ + echo_warn("---------disconnectFromServer success!\n"); + //cout<ip_str,chnl_usr->net_info); + //mms_release_connection(chnl_usr->net_info); ??????? + mvl_free_req_ctrl(chnl_usr->m_reqCtrl); + + chnl_usr->net_info->user_ext = NULL; + chnl_usr->net_info = NULL; + + //cout<<"CHANNEL Close roughly, NetInfo_Channel_Map.entries()= "<m_reqCtrl = NULL; + chnl_usr->net_info = NULL; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = sGetMsTime(); + + chnl_usr->chnl->status = STATUS_BREAKOFF; + } + else{ + chnl_usr->m_state = CHANNEL_DISCONNECTING; + chnl_usr->m_StartDisconnectingTime = sGetMsTime(); + } + }else { + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = sGetMsTime(); + //cout<<"m_ClosedMsTime "<chnl->status = STATUS_BREAKOFF; + } +} + +ST_VOID Callback_channel_disconnect_ind(MVL_NET_INFO * NetInfo, ST_INT discType) +{ + chnl_usr_t *chnl_usr; + + chnl_usr = (chnl_usr_t*)NetInfo->user_ext; + //cout<<"NetInfo_Channel_Map.entries()= "<m_state == CHANNEL_CONNECTING) + { //do nothing; + printf("Do nothing,m_state == CHANNEL_CONNECTING ,NetInfo = %x",NetInfo); + }else if ( chnl_usr->m_state == CHANNEL_CONNECTED ) + { + closeChannel(chnl_usr); + }else if ( chnl_usr->m_state == CHANNEL_DISCONNECTING ) + { //do nothing; + printf("Do nothing,m_state == CHANNEL_DISCONNECTING ,NetInfo = %x",NetInfo); + }else if ( chnl_usr->m_state == CHANNEL_DISCONNECTED ) + { //do nothing; + printf("Do nothing,m_state == CHANNEL_DISCONNECTED ,NetInfo = %x",NetInfo); + } + + //cout <<"NetInfo_Channel_Map[NetInfo] " << pCh <net_info = NULL; + NetInfo->user_ext = NULL; + + } + printf(" Callback_channel_disconnect_ind ,NetInfo = %x",NetInfo); + /* cout<<"after: NetInfo_Channel_Map.entries()= "<chnl[0].ied->usr_ext); + //printf("%s", ied_usr->terminal_code); + //connectlog_pgsql(ied_usr->terminal_code); + //apr_time_t tm = apr_time_now();// + //printf("time: %llu", tm); + //apr_time_exp_t pTm; + //apr_time_exp_gmt(&pTm, tm); + //printf("time: %u %u %u", pTm.tm_year, pTm.tm_mon, pTm.tm_mday); +} + + +void IECReport_tryGI(chnl_usr_t *chnl_usr,rptinfo_t *rptinfo) +{ + char varName[64] = ""; + ST_BOOLEAN GI = TRUE; /* call GI */ + + if ( (sGetMsTime() -rptinfo->m_LastGITime) < g_pt61850app->giTime*1000 ) + return; + rptinfo->m_LastGITime = sGetMsTime(); + get_rpt_inst_name(rptinfo,varName); + strcat(varName, "$GI"); + mms_named_var_write (chnl_usr->net_info, varName, DOM_SPEC, rptinfo->LD_info->LD_name, + g_rpt_typeids.mmsbool, (ST_CHAR *) &GI, g_pt61850app->mmsOpTimeout); +} + +//Ӵ̬̬ܵȣ ǷҪעᡢȡע κδ +int judge_rpt_next_should_do(rptinfo_t *rptinfo) +{ + int should_register_state = 1; //Ĭע + int is_real_report = (rptinfo->report_PQ_type & REPORT_TYPE_REAL);//а + int is_soe_report = (rptinfo->report_PQ_type & REPORT_TYPE_SOE); + + if (three_secs_enabled) { + should_register_state = 0; //3빦ģ飬Ĭϲע + if (is_real_report) {//ӳаƿҴ + should_register_state = rptinfo->LD_info->real_data; + } + if (is_soe_report) { + should_register_state = rptinfo->LD_info->soe_data; + } + } + + if (should_register_state==rptinfo->rpt_registered)//Ѿ/ûдûб䶯 + return SHOULD_DO_NOTHING; + else if (should_register_state)//б䶯Ҫ + return SHOULD_REGISTER; + else + return SHOULD_UNREGISTER;//б䶯 +} + +void ChannelCheckIECReports(chnl_usr_t *chnl_usr) +{ + ied_t *ied; + ied_usr_t *ied_usr; + LD_info_t *LD_info; + rptinfo_t *rptinfo = NULL; + channel_t *channel = NULL; + int cpuno,rpt_no; + char rpt_inst_name[65]; + ST_RET ret; + + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + channel = chnl_usr->chnl; + //printf("1 chnl_usr->ip_str = %s \n",chnl_usr->ip_str); + for(cpuno=0 ; cpunocpucount; cpuno++) + //for(cpuno = ied->cpucount - 1; cpuno >= 0; cpuno--) + { + LD_info = &(ied_usr->LD_info[cpuno]); // + if (LD_info->cpuno==0) + continue; + //printf("2 chnl_usr->ip_str = %s \n",chnl_usr->ip_str); + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { //棨ӳļжȡıƣ + rptinfo = LD_info->rptinfo[rpt_no] ; + /*if ( strstr(rptinfo->rptID,"LLN0$RP$urcbRealData") ) + continue;*/ + if (judge_rpt_next_should_do(rptinfo)==SHOULD_DO_NOTHING)//Ƿ񴥷 + continue; + //printf("3 chnl_usr->ip_str = %s \n",chnl_usr->ip_str); + if(rptinfo->m_curRptSuffix==-1) + rptinfo->m_curRptSuffix = g_pt61850app->rptSuffix[g_client_id][0] ; + get_rpt_inst_name(rptinfo,rpt_inst_name);//ȡ + if ( ! rptinfo->rpt_registered ) { + if ( (sGetMsTime() -rptinfo->m_LastRegisterFailedTime) > 20*1000 ) { + //עʧܺ 20 עһ + RCB_INFO *rcb_info; + printf("start mms_register_iec_rpt................................\n"); + + if ( strstr(rptinfo->rptID,"LLN0$BR$brcbFlickerData") ) + rptinfo->IntgPd = 600; //10 + /////////////////////////WW 2023-08-30 豸뱨 + rcb_info = mms_register_iec_rpt (chnl_usr->net_info, &g_rpt_typeids, + LD_info->LD_name,rpt_inst_name,g_pt61850app->mmsOpTimeout, rptinfo->IntgPd,rptinfo->TrgOpt, + (ST_UINT8*)rptinfo->m_EntryID ,(ST_UINT8*)rptinfo->OptFlds); + //rcb_info = mms_register_iec_rpt_by_devtype(chnl_usr->net_info, &g_rpt_typeids, + // LD_info->LD_name, rpt_inst_name, g_pt61850app->mmsOpTimeout, ied_usr->dev_type, chnl_usr->ip_str, channel->port, + // rptinfo->IntgPd, rptinfo->TrgOpt, + // (ST_UINT8*)rptinfo->m_EntryID, (ST_UINT8*)rptinfo->OptFlds); + //WW end + /////////////////////////// + if( !rcb_info ) + { + if ( ++rptinfo->m_curRptSuffix > g_pt61850app->rptSuffix[g_client_id][1] ) + rptinfo->m_curRptSuffix = g_pt61850app->rptSuffix[g_client_id][0] ; + rptinfo->m_LastRegisterFailedTime = sGetMsTime() ; + echo_err9("\nעᱨʧܣRregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d ,IntgPd=%d ,TrgOpt=0x%x \n", + APR_EGENERAL, LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port, + chnl_usr->chnl_id, rptinfo->IntgPd,rptinfo->TrgOpt ); + + //ټ¼ݽ־lnk20241104 + /*if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) + { + //ݽ¼¼¼ + SoeRptSql(LD_info->terminal_code,1, rptinfo->rptID); + }*/ + //zw޸ 2023 - 8 - 18 ʧܼ¼ + //printf("start %s \n", Rpt_errorlog_json()); + //insert into "MEAS_PQ_COMM_ERROR_TR"("TERMINAL_ID","COMM_DATE","FILE_NAME") values('8afaa9a15707483a0157262f8e78077d',date'2023-08-18','FILENAME111') + //char ERROR_DES[256] = "", ERROR_PARAM[256] = ""; + //char** varnames; + //int varnum,j; + ////double beforeCallDomainMsTime = sGetMsTime() ; + //ST_RET ret = mms_mvla_getnam(chnl_usr->net_info, VMD_SPEC, NULL, MMS_CLASS_DOM, g_pt61850app->mmsOpTimeout, + // &varnames, &varnum, g_pt61850app->tmp_pool); + //for (j = 0; j < varnum; ++j) { + // //printf("LD %d name: %s \n", j, varnames[j]); + // strcat(ERROR_PARAM, varnames[j]); + // strcat(ERROR_PARAM, " "); + //} + + //ret = mms_mvla_getnam(chnl_usr->net_info, DOM_SPEC, varnames[1], MMS_CLASS_VARLIST, 3, + // &varnames, &varnum, g_pt61850app->tmp_pool); + //for (j = 0; j < varnum; ++j) { + // //printf("LD %d name: [%s] \n", j, varnames[j]); + // strcat(ERROR_PARAM, varnames[j]); + // strcat(ERROR_PARAM, " "); + //} + + //strcat(ERROR_DES, ied_usr->org_name); + //strcat(ERROR_DES, ","); + //strcat(ERROR_DES, ied_usr->station_name); + //strcat(ERROR_DES, ","); + //strcat(ERROR_DES, ied_usr->dev_type); + //strcat(ERROR_DES, ","); + //strcat(ERROR_DES, chnl_usr->ip_str); + //strcat(ERROR_DES, ","); + //strcat(ERROR_DES, rpt_inst_name); + //errorlog_json(LD_info->terminal_code, chnl_usr->ip_str, chnl_usr->chnl->port, g_node_id, "津ʧ", ERROR_DES, ERROR_PARAM); + } + else + { + //ټ¼ݽ־lnk20241104 + /*if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) + { + //ݽ¼¼ʧܼ¼ + SoeRptSql(LD_info->terminal_code, 0, rptinfo->rptID); + }*/ + + double GIoffset; + rptinfo->rpt_registered = TRUE; + //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 ȥ + rptinfo->m_rcb_info = rcb_info; + rptinfo->chnl_id = chnl_usr->chnl_id; + chnl_usr->m_NegRespTimes = 0; + chnl_usr->m_LastPosRespTime = sGetMsTime(); + echo_msg11("\nRegister iec_rpt succeed, IED_ID=%d ,CPU=%d ,domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d ,IntgPd=%d ,TrgOpt=0x%x ,OptFlds=0x%x%x \n", + LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port,chnl_usr->chnl_id, + rptinfo->IntgPd,rptinfo->TrgOpt,rptinfo->OptFlds[0],rptinfo->OptFlds[1] ); + // add here to GI not the same time + GIoffset = 0.5 * g_pt61850app->giTime; + rptinfo->m_LastGITime = sGetMsTime() - GIoffset*1000; + } + printf("end mms_register_iec_rpt................................\n"); + } + } + else { //rpt_registered ==TRUE + if ( (sGetMsTime() -rptinfo->m_LastUnRegisterFailedTime) > 20*1000 ) { + //ȡעʧܺ 20 ȡעһ + printf("start mms_unregister_iec_rpt................................\n"); + ret = mms_unregister_iec_rpt (chnl_usr->net_info, &g_rpt_typeids, + LD_info->LD_name,rpt_inst_name,g_pt61850app->mmsOpTimeout); + if( ret == SD_FAILURE ) { + rptinfo->m_LastUnRegisterFailedTime = sGetMsTime() ; + echo_err6("\nȡעᱨʧܣUnRregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s,chnl_id: %d \n", + APR_EGENERAL, LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl_id); + } + else { + rptinfo->rpt_registered = FALSE; + echo_msg7("\nUnRegister iec_rpt succeed, IED_ID=%d ,CPU=%d ,domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d \n", + LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port,chnl_usr->chnl_id ); + } + printf("end mms_unregister_iec_rpt................................\n"); + } + //double nowMsTime = sGetMsTime() ; + //int ScanRateMs = 3*rptinfo->IntgPd*1000; + //if (rptinfo->chnl_id==chnl_usr->chnl_id) { + // //IECReport_tryGI(chnl_usr,rptinfo); + // if ( (ScanRateMs) && BSTR_BIT_GET( &(rptinfo->TrgOpt), TRGOPS_BITNUM_INTEGRITY ) ) // IntgPdʱ 0, Ч + // if ( (nowMsTime - rptinfo->m_LastDataTime) > ScanRateMs ) + // { + // echo_err4("IntgPdʱδյݣͨ, domain: %s ,rpt_inst_name: %s ,ip: %s,chnl_id: %d \n", + // APR_EGENERAL,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl_id); + // closeChannel(chnl_usr); + // return; + // } + //} + } //else { //rpt_registered ==TRUE + } + } +} + +void ChannelCheckWaveFiles(chnl_usr_t *chnl_usr) +{ + ied_t *ied; + ied_usr_t *ied_usr; + LD_info_t *LD_info; + int cpuno; + + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info->line_id<=0) { + continue; + } + call_cn_wavelist(LD_info); //try to call wave file + } +} + +void ChannelCheckIECLogs(chnl_usr_t *chnl_usr) +{ + ST_RET ret; + ied_t *ied; + ied_usr_t *ied_usr; + LD_info_t *LD_info; + loginfo_t *loginfo = NULL; + int cpuno; + + double now; + static double last_check_recall_config_time = 0.0; + + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + + if (LD_info->logcount<=0) + continue; + loginfo = LD_info->loginfo[0] ; + + apr_sleep(apr_time_from_sec(1) / 10); + + Check_Recall_Config(LD_info->mp_id);//Իȡxmlṹ + //add_comm_log(LD_info->mp_id); + if (LD_info->autorecallcount != 0 && LD_info->autorecallflag != 1) { + int i; + int failed_count = 0; + for (i = 0; i < LD_info->autorecallcount; i++) { + + LD_info->autorecallflag = 1; + + //loginfo->need_steady = 1; loginfo->need_voltage = 1; + //ǰ̬̬lnk20241030޸ģCheck_Recall_Configxmlļȡݺ󣬸ֵLD_info + loginfo->need_steady = LD_info->autorecall[i]->need_steady; loginfo->need_voltage = LD_info->autorecall[i]->need_voltage; + + loginfo->start_time = apr_time_from_sec(LD_info->autorecall[i]->start - 5); + loginfo->end_time = apr_time_from_sec(LD_info->autorecall[i]->end - 5); + //printf("bef mms_jread............. %11d %11d \n", LD_info->autorecall[i]->start, LD_info->autorecall[i]->end); + + if (loginfo->need_steady == 0 && loginfo->need_voltage == 0) + continue; + if (loginfo->end_time <= loginfo->start_time) + continue; + /*if ( (sGetMsTime() -loginfo->last_checktime) < 180*1000 ) + continue;*/ + + //loginfo->last_checktime = sGetMsTime(); + printf("start mms_jread................................\n"); + //now = sGetMsTime(); + //last_check_recall_config_time = now; + //printf("start ==============%.2f================\n", last_check_recall_config_time); + echo_msg6("\n mms_jread IED_ID=%d ,CPU=%d ,domain: %s ,logName: %s ,ip: %s,chnl_id: %d \n", + LD_info->ied->id, LD_info->cpuno, LD_info->LD_name, loginfo->logName, chnl_usr->ip_str, chnl_usr->chnl_id); + //set_log_LineID(LD_info->line_id); + //set_line_info(LOG_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); + + //long long start = LD_info->autorecall[i]->start; + //long long end = start; + //for (;end < LD_info->autorecall[i]->end;) + //{ + // if (end < LD_info->autorecall[i]->end - 180) + // { + // start = end; + // end = end + 180; + // loginfo->start_time = apr_time_from_sec(start - 5); + // loginfo->end_time = apr_time_from_sec(end - 5); + // } + // else { + // start = end; + // end = LD_info->autorecall[i]->end; + // loginfo->start_time = apr_time_from_sec(start - 5); + // loginfo->end_time = apr_time_from_sec(end - 5); + // } + //} + + //printf(" mms_jread..... start time: %d end time: %d\n", start, end); + ret = mms_jread(loginfo, chnl_usr->net_info, loginfo->LD_info->LD_name, loginfo->logName, + loginfo->start_time, loginfo->end_time, g_pt61850app->mmsOpTimeout, chnl_usr->ip_str); + if (ret != SD_SUCCESS) { + echo_warn6("\n mms_jread Failed! IED_ID=%d ,CPU=%d ,domain: %s ,logName: %s ,ip: %s,chnl_id: %d \n", + LD_info->ied->id, LD_info->cpuno, LD_info->LD_name, loginfo->logName, chnl_usr->ip_str, chnl_usr->chnl_id); + failed_count++; + } + + del_mvl_type_ctrl(); + + loginfo->need_steady = 0; + loginfo->need_voltage = 0; + loginfo->start_time = loginfo->end_time; + + g_dead_lock_counter = 0; + g_thread_blocked_times = 0; //ֹʱ½˳ + + now = sGetMsTime(); + last_check_recall_config_time = now; + printf("end ==============%.2f================\n", last_check_recall_config_time); + printf("end mms_jread................................\n"); + } + + if (failed_count==0) {//ɹ + Delete_recall_Xml(LD_info->mp_id); + } + } + /*apr_time_from_sec(&loginfo->start_time, 1694275200); + apr_time_from_sec(&loginfo->end_time, 1694361600);*/ + } +} + + +void process_3s_config(trigger_3s_xml_t *trigger_3s_xml) +{ + int i,j; + trigger_t *trigger; + trigger_t *trigger_work; + int trigger_num; + ied_t *ied; + LD_info_t *LD_info; +// int rpt_no; +// rptinfo_t *rptinfo; + int need_write_file; + int new_in_work_found; + + printf("start process_3s_config\n"); + + need_write_file = FALSE; + trigger = trigger_3s_xml->new_triggers; //3sļеnewtrigger飬ûnewtrigger0 + trigger_num = trigger_3s_xml->new_trigger_num; + for (i=0; iwork_trigger_num; j++){ + trigger_work = &trigger_3s_xml->work_triggers[j]; + if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) { + //*trigger_work = trigger[i]; + if (trigger[i].real_data>=0) + trigger_work->real_data = trigger[i].real_data;//rtdata־ + if (trigger[i].soe_data>=0) + trigger_work->soe_data = trigger[i].soe_data; //soe־ + trigger_work->limit = trigger[i].limit; + + clear_rpt_counter_by_trigger(trigger_work);// + new_in_work_found = TRUE; + } + } + if (!new_in_work_found) { //newtriggerΪ0ȫµĴڹĴ + clear_rpt_counter_by_trigger(&trigger[i]); + if (trigger[i].real_data<0) + trigger[i].real_data = 0; + if (trigger[i].soe_data<0) + trigger[i].soe_data = 0; + trigger_3s_xml->work_triggers[trigger_3s_xml->work_trigger_num++] = trigger[i]; + } + need_write_file = TRUE;//Ҫĵдļ + } + + trigger = trigger_3s_xml->delete_triggers; //ûdeletetrigger0 + trigger_num = trigger_3s_xml->delete_trigger_num; + for (i=0; iwork_trigger_num; j++){ + trigger_work = &trigger_3s_xml->work_triggers[j]; + if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) { + clear_rpt_counter_by_trigger(trigger_work); + trigger_work->dev_idx = INVALID_DEV_IDX; + } + } + need_write_file = TRUE; + } + + trigger = trigger_3s_xml->modify_triggers; //ûmodifytrigger0 + trigger_num = trigger_3s_xml->modify_trigger_num; + for (i=0; iwork_trigger_num; j++){ + trigger_work = &trigger_3s_xml->work_triggers[j]; + if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) { + *trigger_work = trigger[i]; + clear_rpt_counter_by_trigger(trigger_work); + } + } + need_write_file = TRUE; + } + + clear_all_LD_real_soe_report_shoud_register(); //Ҫעı棬ʵʱļʹLD_info->real_data = 0;LD_info->soe_data = 0;Ͳᴥ + + trigger = trigger_3s_xml->work_triggers; //ļwork + trigger_num = trigger_3s_xml->work_trigger_num; + + for (i=0; irptinfo[rpt_no]->count + + // + printf("terminal:%s - mp:%s real_report_count %d\n", ((ied_usr_t*)(ied->usr_ext))->terminal_id, LD_info->mp_id, real_report_count); + + trigger[i].count = real_report_count; //¼ʱʵʱ + if (trigger[i].real_data && trigger[i].limit && (real_report_count>trigger[i].limit) ) {//ʵʱڵǰļеƣ㲻ٴ + trigger[i].real_data = 0; + trigger[i].limit = 0; + trigger[i].count = 0; + need_write_file = TRUE; + } + LD_info->real_data = trigger[i].real_data; //ļеãȻڱ津дʵʱ + LD_info->soe_data = trigger[i].soe_data; + LD_info->limit = trigger[i].limit; + LD_info->count = trigger[i].count; + if (LD_info->limit > 0) //¼¼ + need_write_file = TRUE; + if ( trigger[i].real_data==0 && trigger[i].soe_data==0 )//¼ + need_write_file = TRUE; + } + + if (need_write_file) + create_3s_xml(trigger_3s_xml); //дļwork +} + +void del_process_recall_config(recall_xml_t* recall_xml) +{ + int i,j; + recall_t *recall; + recall_t *recall_work; + int recall_num; + ied_t *ied; + LD_info_t *LD_info; + loginfo_t *loginfo = NULL; + int need_write_file; + + need_write_file = FALSE; + recall = recall_xml->new_recalls; + recall_num = recall_xml->new_recall_num; + for (i=0; iwork_recalls[recall_xml->work_recall_num++] = recall[i]; + need_write_file = TRUE; + } + + recall = recall_xml->work_recalls; + recall_num = recall_xml->work_recall_num; + for (i=0; ilogcount<=0) + continue; + loginfo = LD_info->loginfo[0] ; + + loginfo->need_steady = recall[i].need_steady; + loginfo->need_voltage = recall[i].need_voltage; + + loginfo->start_time = recall[i].start_time; + loginfo->end_time = recall[i].end_time; + + } + + //remove_recall_xml(); +} + +void check_3s_config() +{ + double now; + static double last_check_3s_config_time = 0.0;//ʼʱ + trigger_3s_xml_t trigger_3s_xml; //3sļ + + if (!three_secs_enabled) //cfg_3s_data̲ŻῪ + return; + now = sGetMsTime(); //ǰʱ + if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //ǰִʱ鿴ǰʱϴִʱС3벻ִУڵ3ִ + return; + + printf("begin 3s config...\n"); + + last_check_3s_config_time = now; //¼ʱ + while (APR_SUCCESS==parse_3s_xml(&trigger_3s_xml)){ //3ļ + //ʵʱ̨lnk20250114 + pthread_mutex_lock(&mtx); + process_3s_config(&trigger_3s_xml); //ļ + pthread_mutex_unlock(&mtx); + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//lnk20250114ʵʱݷ̨Ϣ +void process_ledger_update(trigger_update_xml_t *ledger_update_xml) +{ + int i,j; + terminal *update; + terminal *update_work; + int update_num; + ied_t *ied; + LD_info_t *LD_info; + int need_write_file; + int new_in_work_found; + + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + + printf("!!!start update ledger!!!\n"); + + need_write_file = FALSE; //д̨˸¼¼ļ + update = ledger_update_xml->new_updates; //̨˲ + update_num = ledger_update_xml->new_update_num; + printf("add ledger num:%d\n",update_num); + for (i=0; imodify_update_num < MAX_UPDATEA_NUM) { + // ӵ modify_updates + ledger_update_xml->modify_updates[ledger_update_xml->modify_update_num] = update[i]; + ledger_update_xml->modify_update_num++; // modify ļ + + // ɾնˣ new_updates Ƴ + for (j = i; j < ledger_update_xml->new_update_num - 1; j++) { + ledger_update_xml->new_updates[j] = ledger_update_xml->new_updates[j + 1]; // ǰƶԪ + } + + ledger_update_xml->new_update_num--; // new_update_numһԪ + i--; // ¼еĵǰԪأ + } else { + fprintf(stderr, "Exceeded MAX_UPDATEA_NUM limit for modify_updates!\n"); + } + + } + + if (!new_in_work_found) { //ȫµ̨ˣڹ̨ + + //̨Ӻͳʼ + //1-µڴռ////////////////////////////// + //µ̨ (n_clients) ԭе̨ (ԭΪ g_node->n_clients) + int new_client_count = g_node->n_clients + 1; // һµ̨ + + // µڴռ䣺ԭ clients ָһָ飬Ϊµڴ + ied_t** new_clients = (ied_t**)apr_pcalloc(g_cfg_pool, new_client_count * sizeof(ied_t*)); + + // ԭݵ·ڴռ + int k; + for (k = 0; k < g_node->n_clients; k++) { + new_clients[k] = g_node->clients[k]; + } + + // Ϊ̨ڴռ + new_clients[g_node->n_clients] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t)); + + // ָ̨ + g_node->clients = new_clients; // clients ָµڴռ + g_node->n_clients = new_client_count; // ̨ + //1-µڴռ////////////////////////////// + + //2-ն̨/////////////////////////////////// + ied = g_node->clients[new_client_count - 1];//նָ̨붨·ڴһλ + ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000; + ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t)); + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + ied_usr->dev_flag = g_DevFlag; + ied->chncount = 1; + ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount); + ied->channel[0].ied = ied; + ied->channel[0].status = STATUS_BREAKOFF; + ied->cpucount = 0; + //2-ն̨/////////////////////////////////// + + //3-д̨////////////////////////////// + int ret = update_one_terminal_ledger(update,i,ied,g_node->n_clients); +#if 0 + // update[i] ед뵽 ied_usr + if (strlen(update[i].terminal_id) != 0) { + apr_snprintf(ied_usr->terminal_id, sizeof(ied_usr->terminal_id), "%s", update[i].terminal_id); + printf("ied_usr->terminal_id: %s\n", ied_usr->terminal_id); + } + + if (update[i].terminal_code != NULL) { + apr_snprintf(ied_usr->terminal_code, sizeof(ied_usr->terminal_code), "%s", update[i].terminal_code); + printf("ied_usr->terminal_code: %s\n", ied_usr->terminal_code); + } + + if (update[i].tmnl_factory != NULL) { + apr_snprintf(ied_usr->tmnl_factory, sizeof(ied_usr->tmnl_factory), "%s", update[i].tmnl_factory); + printf("ied_usr->tmnl_factory: %s\n", ied_usr->tmnl_factory); + } + + if (update[i].tmnl_status != NULL) { + apr_snprintf(ied_usr->tmnl_status, sizeof(ied_usr->tmnl_status), "%s", update[i].tmnl_status); + printf("ied_usr->tmnl_status: %s\n", ied_usr->tmnl_status); + } + + if (update[i].dev_type != NULL) { + apr_snprintf(ied_usr->dev_type, sizeof(ied_usr->dev_type), "%s", update[i].dev_type); + printf("ied_usr->dev_type: %s\n", ied_usr->dev_type); + } + + if (update[i].dev_series != NULL) { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", update[i].dev_series); + printf("ied_usr->dev_series: %s\n", ied_usr->dev_series); + } else { + apr_snprintf(ied_usr->dev_series, sizeof(ied_usr->dev_series), "%s", ""); // ĬΪַ + printf("ied_usr->dev_series (default): %s\n", ied_usr->dev_series); + } + + if (update[i].dev_key != NULL) { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", update[i].dev_key); + printf("ied_usr->dev_key: %s\n", ied_usr->dev_key); + } else { + apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", ""); // ĬΪַ + printf("ied_usr->dev_key (default): %s\n", ied_usr->dev_key); + } + + ied_usr->dev_idx = new_client_count; // µһնź + printf("dev_idx: %d\n", ied_usr->dev_idx); + + ied->channel[0].channel_type = CHANNEL_TYPE_IPV4; // channel + ied->channel[0].addr_str[LONGNAME - 1] = 0; // DEV_IP + if (update[i].addr_str != NULL) { + ied->channel[0].addr = ntohl(inet_addr(update[i].addr_str)); // DEV_IP + strncpy(ied->channel[0].addr_str, update[i].addr_str, LONGNAME - 1); // DEV_IP + printf("ied_usr->addr_str: %s\n", ied->channel[0].addr_str); + } else { + ied->channel[0].addr = ntohl(inet_addr("0.0.0.0")); // DEV_IP + strncpy(ied->channel[0].addr_str, update[i].addr_str, LONGNAME - 1); // DEV_IP + printf("ied_usr->addr_str: %s\n", ied->channel[0].addr_str); + } + + if (update[i].port != NULL) { + int port = 102; + if (stringToInt(update[i].port, &port)) { + // תɹportStrȫΪ֣ѾתΪint͵port + ied->channel[0].port = port; // DEV_PortID + printf("ied_usr->port: %d\n", ied->channel[0].port); // DEV_PortID + } else { + ied->channel[0].port = 102; // DEV_PortID + printf("ied_usr->port: %s, ǺϷ˿. ʹĬ϶˿: %d\n", update[i].port, ied->channel[0].port); // DEV_PortID + } + } + + if (update[i].timestamp != NULL && strlen(update[i].timestamp) > 0) { + // struct tm + struct tm timeinfo = {0}; // ʼΪ0 + + // ʱַʽΪ "YYYY-MM-DD HH:MM:SS" + // ʹsscanfַȡʱֶ + if (sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d", + &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, + &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec) == 6) { + // ݴ1900ʼ + timeinfo.tm_year -= 1900; + // ·ݴ0ʼ㣬ȥ1 + timeinfo.tm_mon -= 1; + // tm_isdstгʼͨΪ-1mktimeԶж + timeinfo.tm_isdst = -1; + + // ʹmktimestruct tmתΪtime_t + time_t raw_time = mktime(&timeinfo); + + // жmktimeǷɹ + if (raw_time != -1) { + ied_usr->time = (long long)raw_time; + printf("ied_usr->time: %lld\n", ied_usr->time); + } else { + printf("Error: mktime failed.\n"); + } + } else { + printf("Error: sscanf failed. Invalid timestamp format.\n"); + } + } + + + chnl_usr = (chnl_usr_t*)apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[0].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[0]); + chnl_usr->chnl_id = 0; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + g_pt61850app->chnl_counts++; + + // monitorData ед뵽 LD_info + int count_real_monitor = 0; //̨˵ļ + int j; + for (j = 0; j < 10 && update[i].line[j].monitor_id[0] != '\0'; ++j) { + monitor monitor_data = update[i].line[j]; + + // + count_real_monitor++; + + // ʼ LD_info + LD_info_t line_info; + memset(&line_info, 0, sizeof(line_info)); + + char logical_device_seq[64]; + + // Ϣ + strncpy(line_info.mp_id, monitor_data.monitor_id, sizeof(line_info.mp_id) - 1); + strncpy(line_info.name, monitor_data.monitor_name, sizeof(line_info.name) - 1); + strncpy(line_info.voltage_level, monitor_data.voltage_level, sizeof(line_info.voltage_level) - 1); + strncpy(line_info.v_wiring_type, monitor_data.terminal_connect, sizeof(line_info.v_wiring_type) - 1); + strncpy(line_info.monitor_status, monitor_data.status, sizeof(line_info.monitor_status) - 1); + strncpy(line_info.terminal_code, monitor_data.terminal_code, sizeof(line_info.terminal_code) - 1); + + strncpy(logical_device_seq, monitor_data.logical_device_seq, sizeof(logical_device_seq) - 1); + if (isCharPtrEmpty(logical_device_seq)) { + line_info.cpuno = 1; // Ĭϼʵ1 + printf("logical_device_seq: is null, set cpuno: %d\n", line_info.cpuno); + } else { + line_info.cpuno = atoi(logical_device_seq); + printf("logical_device_seq: %d\n", line_info.cpuno); + } + + line_info.line_id = count_real_monitor; // ¼նź + + printf("line_id: %d\n", line_info.line_id); + printf("mp_id: %d\n", line_info.mp_id); + printf("terminal_code: %s\n", line_info.terminal_code); + printf("voltage_level: %d\n", line_info.voltage_level); + printf("v_wiring_type: %d\n", line_info.v_wiring_type); + printf("monitor_status: %d\n", line_info.monitor_status); + printf("name: %s\n", line_info.name); + + + // ʱ + if (update[i].timestamp[0] != '\0') { + struct tm timeinfo; + char timestamp[64]; + + // update[i].timestampʽΪ "YYYY-MM-DD HH:MM:SS" + // 磺"2023-01-14 12:34:56" + sscanf(update[i].timestamp, "%4d-%2d-%2d %2d:%2d:%2d", + &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, + &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); + + // ݴ1900꿪ʼ + timeinfo.tm_year -= 1900; + // ·ݴ0ʼ1 + timeinfo.tm_mon -= 1; + // tm_isdstгʼͨΪ-1mktimeԶж + timeinfo.tm_isdst = -1; + + // ʹmktimestruct tmתΪtime_t + time_t raw_time = mktime(&timeinfo); + + // жmktimeǷɹ + if (raw_time != -1) { + line_info.time = (long long)raw_time; + printf("time: %lld\n", line_info.time); + } else { + printf("Error: mktime failed.\n"); + } + } + + line_info.read_flag = 1; //Ч + + // LD_info + if (ied && ied->usr_ext && line_info.cpuno && ((int)line_info.cpuno < 10)) { + char str[256]; + byte_t cpuno = line_info.cpuno; + printf("cpuno: %d\n", line_info.cpuno); + printf("index cpuno: %d\n", cpuno - 1); + ied_usr = (ied_usr_t*)ied->usr_ext; + ied_usr->LD_info[cpuno - 1] = line_info; // cpunoĬ1 + ied_usr->LD_info[cpuno - 1].ied = ied; + apr_snprintf(str, sizeof(str), "PQMonitorPQM%d", cpuno); + ied_usr->LD_info[cpuno - 1].LD_name = apr_pstrdup(g_init_pool, str); + ied_usr->LD_info[cpuno - 1].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno - 1].rptcount = 0; + printf("rptcount: %d\n", ied_usr->LD_info[cpuno - 1].rptcount); + if (cpuno > ied->cpucount) { + ied->cpucount = cpuno; + } + } + // ied_usr->LD_info[j] = line_info; + printf("Monitor Info [ID: %s, Name: %s] saved in LD_info\n", line_info.mp_id, line_info.name); + + } +#endif + + //3-д̨/////////////////////////////////// + + //4-ӳļ////////////////////////////// + + //4-ӳļ/////////////////////////////////// + + //5-ʼ////////////////////////////// + + //5-ʼ/////////////////////////////////// + + //6-init_rem_dib_table////////////////////////////// + + //6-init_rem_dib_table/////////////////////////////////// + + } + need_write_file = TRUE;//Ҫ̨д̨˸¼¼ļ + } +////////////////////////////////////////////////////////////////////////////// + /*trigger = trigger_3s_xml->delete_triggers; //ûdelete0 + trigger_num = trigger_3s_xml->delete_trigger_num; + for (i=0; iwork_trigger_num; j++){ + trigger_work = &trigger_3s_xml->work_triggers[j]; + if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) { + clear_rpt_counter_by_trigger(trigger_work); + trigger_work->dev_idx = INVALID_DEV_IDX; + } + } + need_write_file = TRUE; + } +////////////////////////////////////////////////////////////////////////////// + trigger = trigger_3s_xml->modify_triggers; //ûmodify0 + trigger_num = trigger_3s_xml->modify_trigger_num; + for (i=0; iwork_trigger_num; j++){ + trigger_work = &trigger_3s_xml->work_triggers[j]; + if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) { + *trigger_work = trigger[i]; + clear_rpt_counter_by_trigger(trigger_work); + } + } + need_write_file = TRUE; + } +/////////////////////////////////////////////////////////////////////////////// + trigger = trigger_3s_xml->work_triggers; //ļwork + trigger_num = trigger_3s_xml->work_trigger_num; + + if (need_write_file) + create_3s_xml(trigger_3s_xml); //дļwork*/ +} + +//̨˸µԴӡ +// ַǷΪ +// ַǷΪ +int is_empty(const char* str) { + return (str == NULL || str[0] == '\0'); +} + +// ӡ monitor ṹϢ +void print_monitor(const monitor* mon) { + printf("Monitor ID: %s\n", is_empty(mon->monitor_id) ? "N/A" : mon->monitor_id); + printf("Terminal Code: %s\n", is_empty(mon->terminal_code) ? "N/A" : mon->terminal_code); + printf("Monitor Name: %s\n", is_empty(mon->monitor_name) ? "N/A" : mon->monitor_name); + printf("Logical Device Sequence: %s\n", is_empty(mon->logical_device_seq) ? "N/A" : mon->logical_device_seq); + printf("Voltage Level: %s\n", is_empty(mon->voltage_level) ? "N/A" : mon->voltage_level); + printf("Terminal Connect: %s\n", is_empty(mon->terminal_connect) ? "N/A" : mon->terminal_connect); + printf("Timestamp: %s\n", is_empty(mon->timestamp) ? "N/A" : mon->timestamp); + printf("Status: %s\n", is_empty(mon->status) ? "N/A" : mon->status); +} + +// ӡ terminal ṹϢ +void print_terminal(const terminal* tmnl) { + printf("Terminal ID: %s\n", is_empty(tmnl->terminal_id) ? "N/A" : tmnl->terminal_id); + printf("Terminal Code: %s\n", is_empty(tmnl->terminal_code) ? "N/A" : tmnl->terminal_code); + printf("Organization Name: %s\n", is_empty(tmnl->org_name) ? "N/A" : tmnl->org_name); + printf("Maintenance Name: %s\n", is_empty(tmnl->maint_name) ? "N/A" : tmnl->maint_name); + printf("Station Name: %s\n", is_empty(tmnl->station_name) ? "N/A" : tmnl->station_name); + printf("Factory Name: %s\n", is_empty(tmnl->tmnl_factory) ? "N/A" : tmnl->tmnl_factory); + printf("Terminal Status: %s\n", is_empty(tmnl->tmnl_status) ? "N/A" : tmnl->tmnl_status); + printf("Device Type: %s\n", is_empty(tmnl->dev_type) ? "N/A" : tmnl->dev_type); + printf("Device Key: %s\n", is_empty(tmnl->dev_key) ? "N/A" : tmnl->dev_key); + printf("Device Series: %s\n", is_empty(tmnl->dev_series) ? "N/A" : tmnl->dev_series); + printf("Address: %s\n", is_empty(tmnl->addr_str) ? "N/A" : tmnl->addr_str); + printf("Port: %s\n", is_empty(tmnl->port) ? "N/A" : tmnl->port); + printf("Timestamp: %s\n", is_empty(tmnl->timestamp) ? "N/A" : tmnl->timestamp); + + // ӡϢֶΪգӡ N/A + int i; + for (i = 0; i < 10 && !is_empty(tmnl->line[i].monitor_id); ++i) { + printf(" Monitor %d:\n", i + 1); + print_monitor(&tmnl->line[i]); + } +} + +// ӡ trigger_update_xml_t ṹϢ +void print_trigger_update_xml(const trigger_update_xml_t* trigger_update) { + printf("Work Updates Count: %d\n", trigger_update->work_update_num); + printf("New Updates Count: %d\n", trigger_update->new_update_num); + printf("Delete Updates Count: %d\n", trigger_update->delete_update_num); + printf("Modify Updates Count: %d\n", trigger_update->modify_update_num); + + printf("\nWork Updates:\n"); + int i; + for (i = 0; i < trigger_update->work_update_num; ++i) { + printf("Work Update %d:\n", i + 1); + print_terminal(&trigger_update->work_updates[i]); + } + + printf("\nNew Updates:\n"); + for (i = 0; i < trigger_update->new_update_num; ++i) { + printf("New Update %d:\n", i + 1); + print_terminal(&trigger_update->new_updates[i]); + } + + printf("\nDelete Updates:\n"); + for (i = 0; i < trigger_update->delete_update_num; ++i) { + printf("Delete Update %d:\n", i + 1); + print_terminal(&trigger_update->delete_updates[i]); + } + + printf("\nModify Updates:\n"); + for (i = 0; i < trigger_update->modify_update_num; ++i) { + printf("Modify Update %d:\n", i + 1); + print_terminal(&trigger_update->modify_updates[i]); + } +} + +void check_ledger_update()//lnk20250113 +{ + double now; + static double last_check_3s_config_time = 0.0;//ʼʱ + + now = sGetMsTime(); //ǰʱ + if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //ǰִʱ鿴ǰʱϴִʱС3벻ִУڵ3ִ + return; + + trigger_update_xml_t trigger_ledger_update_xml; //̨˸ļṹ + + printf("begin ledger update...\n"); + + //жǷִһļһնˣȡļɾļ + while (APR_SUCCESS==parse_ledger_update_xml(&trigger_ledger_update_xml)){ //̨˸ļ,пԸ»̨˵ + print_trigger_update_xml(&trigger_ledger_update_xml); + //̨˸¼̨lnk20250114 + pthread_mutex_lock(&mtx); + process_ledger_update(&trigger_ledger_update_xml); //̨˸ + pthread_mutex_unlock(&mtx); + } +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef _OS_UNIX_ +uint32_t get_freedisk_MB(uint32_t* totalSizeMB) +{ + struct statfs diskInfo; + unsigned long long totalBlocks = 0; + unsigned long long totalSize = 0; + size_t mbTotalsize = 0; + size_t freeDisk=0; + size_t mbFreeDisk = 0; + + statfs("/home/pq", &diskInfo); + totalBlocks = diskInfo.f_bsize; + totalSize = totalBlocks * diskInfo.f_blocks; + mbTotalsize = totalSize >> 20; + freeDisk = diskInfo.f_bfree*totalBlocks; + mbFreeDisk = freeDisk >> 20; + printf("/home/pq total=%dMB, free=%dMB \n", mbTotalsize, mbFreeDisk); + if (totalSizeMB) + *totalSizeMB = mbTotalsize; + return mbFreeDisk; +} +#else +uint32_t get_freedisk_MB(uint32_t* totalSizeMB) { + if (totalSizeMB) + *totalSizeMB = 1000; + return 5; +} +#endif + +void check_disk_quota() +{ + double now; + static double last_check_time = -10000000.0; + uint32_t freeSizeMB,totalSizeMB; + + if(g_node_id != STAT_DATA_BASE_NODE_ID) + return; + now = sGetMsTime(); + if ( fabs(now - last_check_time) < 15*1000 ) //wait 15 secs + return; + + last_check_time = now; + + freeSizeMB = get_freedisk_MB(&totalSizeMB); + + //printf("Current user disk free size: %dMB ,total size: %dMB \n",freeSizeMB,totalSizeMB); + if (freeSizeMB 30) { + recall_start = 30; + } + if (recall_lenth > 10) { + recall_lenth = 10; + } + if (recall_start < recall_lenth) //ʼСڲг ֹΪ + { + recall_lenth = recall_start; + } + if (recall_count < recall_lenth) + { + recall_pgsql(recall_start - recall_count);// + //char* day = getoneday(recall_start - recall_count);//ȡǰn yyyy-mm-dd + //printf("==============%s================\n", day); + //deletechar(day); + recall_count++; + } + else + { + recall_flag = 3; + } + } + if (localTime.tm_hour != recall_dailytime && recall_flag == 3) { + recall_flag = 1; + recall_count = 0; + } +} + +void recall_pgsql(int num) +{ + char* day = getoneday(num);//ȡǰn yyyy-mm-dd + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + if (chnl_usr->m_state == CHANNEL_CONNECTED) + { + while (cpuno < ied->cpucount) + { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info->logcount <= 0) + continue; + printf("/home/pq mpid=%s\n", LD_info->mp_id); +//滻webӿ2024-10-21 lnk + //int ReDecide = OTL_Select_DecideRecall(day, LD_info->mp_id); + //int ReDecide = OTL_Select_DecideRecall_web(day, LD_info->mp_id);//ʹlnk20241206 + + //if (ReDecide == 1) {//ʹlnk20241206 +//滻webӿ2024-10-21 lnk + //OTL_Select_recall(day, LD_info->mp_id); + //OTL_Select_recall_web(day, LD_info->mp_id);//ʹlnk20241206 + //}//ʹlnk20241206 + + g_dead_lock_counter = 0; + g_thread_blocked_times = 0; + cpuno++; + } + } + i++; + } + deletechar(day); +} + +void create_recall_xml() +{ + //ɴxmlļ + if (g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) { + DeletcRecallXml(); + CreateRecallXml(); + } +} + +void Delete_recall_Xml(char* id) { + if (g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) { + delete_recall_xml(id); + //process_recall_config(&recall_xml); + //remove_recall_xml(); + } +} + +void Check_Recall_Config(char *id) //鲹ļRecall.xml +{ + if (g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) { + + recall_xml_t recall_xml; + memset((char*)&recall_xml, 0, sizeof(recall_xml_t)); + parse_recall_xml(&recall_xml,id); //ļ + process_recall_config(&recall_xml); //IJݸֵȫֱ + //process_recall_config(&recall_xml); + //remove_recall_xml(); + } + /*recall_xml_t recall_xml; + memset((char*)&recall_xml, 0, sizeof(recall_xml_t)); + int ret = parse_recall_xml(&recall_xml); + if (0 == ret) + process_recall_config(&recall_xml);*/ +} + +void CheckAllConnectedChannel() +{ + chnl_usr_t *chnl_usr; + static uint32_t chnl_sequence_no = 0; + //10-11-02 20:18 beijing, only one ied by visited every loop һηһն + do { + chnl_usr = g_pt61850app->chnl_usr[chnl_sequence_no]; + chnl_sequence_no = (chnl_sequence_no+1) % g_pt61850app->chnl_counts; + } while ( (g_onlyIP[0]!=0) && (strcmp(g_onlyIP,chnl_usr->ip_str)!=0) ); + //for (i=0; ichnl_counts; i++) { + //chnl_usr = g_pt61850app->chnl_usr[i] ; + //printf("CheckAllConnectedChannel chnl_usr->ip_str = %s \n",chnl_usr->ip_str); + if(chnl_usr->m_state == CHANNEL_CONNECTED) + { + /*if(chnl_usr->chnl->ied->id==virtual_ied){ + chnl_usr->m_state = CHANNEL_CONNECTED; + return; + }*/ + ChannelCheckIECReports(chnl_usr);// + if ( (g_node_id == SOE_COMTRADE_BASE_NODE_ID) || (g_node_id == HIS_DATA_BASE_NODE_ID) || (g_node_id == NEW_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) + ChannelCheckWaveFiles(chnl_usr);//¼ļ + if(g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) + ChannelCheckIECLogs(chnl_usr);//ļ + if ( (sGetMsTime() - chnl_usr->m_LastPosRespTime) > 15*1000 ) //wait 15 secs + { + char** varnames ; + int varnum; + //double beforeCallDomainMsTime = sGetMsTime() ; + ST_RET ret = mms_mvla_getnam(chnl_usr->net_info, VMD_SPEC, NULL,MMS_CLASS_DOM,g_pt61850app->mmsOpTimeout, + &varnames,&varnum,g_pt61850app->tmp_pool); + //for ( j = 0; j < varnum; ++j) + //printf("LD %d name: %s \n",j,varnames[j]); + + //ret = mms_mvla_getnam(chnl_usr->net_info, DOM_SPEC, varnames[1],MMS_CLASS_VARLIST,3, + // &varnames,&varnum,g_pt61850app->tmp_pool); + ////ret = mms_mvla_getnam(chnl_usr->net_info, DOM_SPEC, varnames[1], MMS_CLASS_VAR, 3, + //// &varnames, &varnum, g_pt61850app->tmp_pool); + //for ( j = 0; j < varnum; ++j) + // printf("LD %d name: [%s] \n",j,varnames[j]); + + //double comdiff = sGetMsTime() - beforeCallDomainMsTime; + //cout<<"cost secs to check com "<net_info, 15 ); + chnl_usr->m_LastPosRespTime = sGetMsTime(); + if (ret == SD_SUCCESS) { + //chnl_usr->m_LastPosRespTime = sGetMsTime(); + chnl_usr->m_NegRespTimes = 0; + }else { + // cout<<" "<GetIP()<<" domain name ʧ "<m_NegRespTimes); + chnl_usr->m_NegRespTimes++; + } + } + if ( chnl_usr->m_NegRespTimes >=2 ) { + //printf("==============chnl_usr->m_NegRespTimes================\n"); + closeChannel(chnl_usr);//???ǷҪ mms_release_connection + chnl_usr->m_NegRespTimes = 0; + chnl_usr->m_LastPosRespTime = sGetMsTime(); + } + } + //} +} + +void CheckNextNotConnectedChannel() +{ + static uint32_t chnl_total_no = 0; + chnl_usr_t *chnl_usr; +// element_t *elem_a; +// element_t *elem_b; + do { + chnl_usr = g_pt61850app->chnl_usr[chnl_total_no]; + chnl_total_no = (chnl_total_no+1) % g_pt61850app->chnl_counts; + } while ( (g_onlyIP[0]!=0) && (strcmp(g_onlyIP,chnl_usr->ip_str)!=0) ) ; + //10-11-01 22:03 beijing + if( ( (chnl_total_no+1)==g_pt61850app->chnl_counts) || (g_onlyIP[0]!=0) ){ + if(g_pt61850app->initNum<255) + g_pt61850app->initNum++; + } + if(chnl_usr->chnl->ied->chncount == 2){ + //elem_a = RDB_GetElement(SUBSTATION, chnl_usr->chnl->ied->id,64264, 5); + //elem_b = RDB_GetElement(SUBSTATION, chnl_usr->chnl->ied->id,64264, 6); + //if(elem_a&&elem_b){ + // if((((M_DP_NA_1_t*)elem_a->value.data)->diq.parts.DPI == 0x01)&&(((M_DP_NA_1_t*)elem_b->value.data)->diq.parts.DPI == 0x01)){ + // iecs_set_ied_invalid(chnl_usr->chnl->ied); + // } + //} + } + else{ + //elem_a = RDB_GetElement(SUBSTATION, chnl_usr->chnl->ied->id,64264, 5); + //if(elem_a){ + // if(((M_DP_NA_1_t*)elem_a->value.data)->diq.parts.DPI == 0x01){ + // iecs_set_ied_invalid(chnl_usr->chnl->ied); + // } + //} + } + if(chnl_usr->m_state == CHANNEL_CONNECTING)// + { + MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ; + if( reqCtrl->done == SD_TRUE) + { + if(reqCtrl->result == SD_SUCCESS) + { + ALL_RCB_INFO *all_rcb_info; + // cout<GetIP()<<" CHANNEL_CONNECTED netInfo "<net_info<ip_str,chnl_usr->chnl->port,chnl_usr->net_info,chnl_usr); + mvl_free_req_ctrl(chnl_usr->m_reqCtrl); + chnl_usr->m_reqCtrl = NULL; + + chnl_usr->m_state = CHANNEL_CONNECTED; + chnl_usr->net_info->user_ext = chnl_usr; + + all_rcb_info = (ALL_RCB_INFO *)chk_calloc(1, sizeof (ALL_RCB_INFO)); + all_rcb_info->rpt_typeids = &g_rpt_typeids; + //assert(chnl_usr->net_info->user_info == NULL); + if (chnl_usr->net_info->user_info != NULL) { + echo_warn("chnl_usr->net_info->user_info is not NULL\n"); + } + + chnl_usr->net_info->user_info = all_rcb_info; + chnl_usr->chnl->ied->status = STATUS_NORMAL; + chnl_usr->chnl->status = STATUS_NORMAL; + //prcess_ied_comm_2_json(chnl_usr->chnl->ied,STATUS_NORMAL); + //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NORMAL, chnl_usr->chnl_id); + { + char comm_str[256]; + memset(comm_str,0,256); + apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tconnected",chnl_usr->ip_str,chnl_usr->chnl->port); + add_comm_log(comm_str); + FRONT_MP_NUM++; + } + + //lnk202411-1ӳɹļ¼ + ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; + connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),1);//1ɹ + + } + else + {// solaris 9 224 + int secsSince = (int)(sGetMsTime() - chnl_usr->m_StartConnectingTime)/1000 ; + //cout<<"reqCtrl->result == FAIL, Since StartConnecting "<GetIP()<<" !!! "<chnl->ied->usr_ext; + if (g_node_id == STAT_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID) { + //lnk202411-4 + //connectlog_pgsql(ied_usr->terminal_code);//ʧ + connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),0);//0ʧ + } + printf( "reqCtrl->result == FAIL, Since StartConnecting %i ,channel IP %s:%d \n",secsSince,chnl_usr->ip_str,chnl_usr->chnl->port); + mvl_free_req_ctrl(chnl_usr->m_reqCtrl); + chnl_usr->m_reqCtrl = NULL; + chnl_usr->net_info->rem_vmd = NULL; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = sGetMsTime(); + } + } + else + {// + if ( (sGetMsTime() - chnl_usr->m_StartConnectingTime) > 300*1000 ) //300*1000 ) //wait 300 secs ????? + { + ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; + if (g_node_id == STAT_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID) { + //connectlog_pgsql(ied_usr->terminal_code);//reqCtrl->doneδɣʱ5 + //lnk202411-4 + connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),0);//0ʧ + } + //cout<GetIP()<<" reqCtrl->done == SD_false but time over 300 secs, close channel !!!"<doneδ,but time over 300 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info); + if (chnl_usr->net_info->req_pend_list) { + echo_warn("reqCtrl->doneδ,but time over 300 secs!!!!!!!!\n"); + mvl_free_req_ctrl(chnl_usr->m_reqCtrl); + chnl_usr->m_reqCtrl = NULL; + } + mms_release_connection(chnl_usr->net_info); + //mvl_free_req_ctrl(chnl_usr->m_reqCtrl); //??? + chnl_usr->net_info->rem_vmd = NULL; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = sGetMsTime(); + //if(chnl_usr->chnl->ied->id==virtual_ied){ + // chnl_usr->m_state = CHANNEL_CONNECTED; + // chnl_usr->chnl->ied->status = STATUS_NORMAL; + // chnl_usr->chnl->status = STATUS_NORMAL; + // //Special_CPU_Set(chnl_usr->chnl->ied, STATUS_NORMAL); + // //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NORMAL,0); + //} + } + } + } //if(pChannel->m_state == CHANNEL_CONNECTING) + + else if(chnl_usr->m_state == CHANNEL_DISCONNECTED) + { + if ( (sGetMsTime() - chnl_usr->m_ClosedMsTime) > NEXT_CONNECT_TIME ) //wait 10 secs + { + ST_RET ret; + ST_CHAR serverARName[32]; + ied_usr_t *ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext; + apr_snprintf(serverARName,sizeof(serverARName),"%s:%d",chnl_usr->ip_str,chnl_usr->chnl->port); + if (chnl_usr->chnl->ied->cpucount != NULL && chnl_usr->chnl->ied->cpucount > 0) {//2023-09-26 czy line count<0 Ҫ + ret = mms_connectToServer(ied_usr->dev_key, ied_usr->dev_series, serverARName, &(chnl_usr->net_info), &(chnl_usr->m_reqCtrl)); + if (ret == SD_SUCCESS) + { + //if(chnl_usr->chnl->ied->id==virtual_ied){ + // chnl_usr->m_state = CHANNEL_CONNECTED; + // chnl_usr->chnl->ied->status = STATUS_NORMAL; + // chnl_usr->chnl->status = STATUS_NORMAL; + // //Special_CPU_Set(chnl_usr->chnl->ied, STATUS_NORMAL); + // //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NORMAL,0); + // return; + //} + //echo_warn3("!!!!!!!!!!!!!!!!!!!!!!!!! %s:%d %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info); + echo_msg3("mms_connectToServer IP %s:%d ,NetInfo= %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info); + chnl_usr->m_state = CHANNEL_CONNECTING; + chnl_usr->m_StartConnectingTime = sGetMsTime(); + //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NOINIT, chnl_usr->chnl_id); + //write_status_to_db(0,chnl_usr->chnl->addr); + + //lnk202411-1ӣûӳɹûӵļ¼ + //connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),1);//1ɹ + + } + else + { + chnl_usr->m_ClosedMsTime = sGetMsTime(); + if (g_node_id == STAT_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID) { + //lnk202411-4 + //connectlog_pgsql(ied_usr->terminal_code);//ʧ + connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),0);//0ʧ + } + echo_warn3("FAILED: mms_connectToServer IP %s:%d ,NetInfo= %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info); + } + } + + } + }//if(pChannel->m_state == CHANNEL_DISCONNECTED) + else if(chnl_usr->m_state == CHANNEL_DISCONNECTING) //need check timeout?᲻Զͣ??? + { + MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ; + if( reqCtrl->done == SD_TRUE) + { + //cout<GetIP()<<" CHANNEL_DISCONNECTING done"<ip_str,chnl_usr->chnl->port,chnl_usr->net_info); + mvl_free_req_ctrl(chnl_usr->m_reqCtrl); + if(chnl_usr->net_info) + chnl_usr->net_info->user_ext = NULL; + //NetInfo_Channel_Map.remove(chnl_usr->net_info); + //cout<<"CHANNEL_DISCONNECTING done NetInfo_Channel_Map.entries()= "<m_reqCtrl = NULL; + chnl_usr->net_info = NULL; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = sGetMsTime(); + } + else + {// + // cout<GetIP()<<" CHANNEL_DISCONNECTING waiting ..."<ip_str,chnl_usr->net_info); + + if ( (sGetMsTime() - chnl_usr->m_StartDisconnectingTime) > 30*1000 ) // //wait 30 secs ????? + { + //cout<GetIP()<<"CHANNEL_DISCONNECTING reqCtrl->done == SD_false but time over 180 secs, close channel !!!"<doneδ,but time over 180 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info); + mvl_free_req_ctrl(chnl_usr->m_reqCtrl); + chnl_usr->net_info->user_ext = NULL; + //NetInfo_Channel_Map.remove(chnl_usr->net_info); + mms_release_connection(chnl_usr->net_info); + chnl_usr->net_info->rem_vmd = NULL; + chnl_usr->m_reqCtrl = NULL; + chnl_usr->net_info = NULL; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = sGetMsTime(); + } + } + }//if(pChannel->m_state == CHANNEL_DISCONNECTING) + ////////////////// +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////*********ؿƲ**********//////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + + +static ST_RET Read_Named_Var(LD_info_t *LD_info,chnl_usr_t *chnl_usr,char* VarName,ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut) +{ + ST_RET ret= SD_FAILURE; + ST_CHAR *domName = LD_info->LD_name; + int Need_Destroy_Typeid = FALSE; + assert(chnl_usr && LD_info); + if (type_id==-1) { + Need_Destroy_Typeid = TRUE; + type_id= mms_var_type_id_create (chnl_usr->net_info,DOM_SPEC, domName, VarName,timeOut); + if (type_id==-1) ret = SD_FAILURE; else ret = SD_SUCCESS; + if (ret == SD_FAILURE) return SD_FAILURE; + } + ret=mms_named_var_read (chnl_usr->net_info,VarName,DOM_SPEC, domName,type_id, dataDest, timeOut); + if (Need_Destroy_Typeid) + if (type_id!=-1) mvl_type_id_destroy(type_id); + return ret; +} + +static ST_RET Write_Named_Var(LD_info_t *LD_info,chnl_usr_t *chnl_usr,char* VarName,ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut) +{ + ST_RET ret= SD_FAILURE; + ST_CHAR *domName = LD_info->LD_name; + int Need_Destroy_Typeid = FALSE; + assert(chnl_usr && LD_info); + if (type_id==-1) { + Need_Destroy_Typeid = TRUE; + type_id= mms_var_type_id_create (chnl_usr->net_info,DOM_SPEC, domName, VarName,timeOut); + if (type_id==-1) ret = SD_FAILURE; else ret = SD_SUCCESS; + if (ret == SD_FAILURE) return SD_FAILURE; + } + ret=mms_named_var_write(chnl_usr->net_info,VarName,DOM_SPEC, domName,type_id, dataDest, timeOut); + if (Need_Destroy_Typeid) + if (type_id!=-1) mvl_type_id_destroy(type_id); + return ret; +} + +/* + +status-only +direct-with-normal-security +sbo-with-normal-security +direct-with-enhanced-security +sbo-with-enhanced-security + +*/ + + +#define TICKS_PER_MIN 60LL*1000LL*1000LL + + +int pt61850_write_cn_file(chnl_usr_t *chnl_usr, ied_t *ied, char *rem_filename, char *only_filename_ret) +{ + int ret ; +// ticks_t ticks; + char loc_filename[128], loc_file_fullname[256], rem_file_fullname[256],only_filename_str[256]; +// int result ;//= FILE_NAME_UNIQUE; +// uint8_t cpuNo =0; + char *only_filename,*the_full_file; +// ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + + memset(loc_filename,0,sizeof(loc_filename)); + memset(only_filename_str,0,sizeof(only_filename_str) ); + + strcat(only_filename_str,rem_filename); + only_filename = only_filename_str; + the_full_file = only_filename_str; + while ( *the_full_file != 0 ) { + if (*the_full_file == '/') + only_filename=the_full_file+1; + the_full_file++; + } + + memset(rem_file_fullname,0,sizeof(rem_file_fullname) ); + if (strstr(rem_filename,"/")!= NULL) { + strcat(rem_file_fullname,rem_filename); + } + else { + strcat(rem_file_fullname,g_pt61850app->accPath); + strcat(rem_file_fullname,rem_filename); + } + + memset(loc_file_fullname,0,sizeof(loc_file_fullname) ); + apr_snprintf(loc_file_fullname,sizeof(loc_file_fullname),"../comtrade/%s",only_filename); + apr_snprintf(only_filename_ret,256,"%s",only_filename); + printf("\n >>>>>>>>>****** Get wave file : %s from %s\n",loc_file_fullname,rem_file_fullname); + + ret = mms_getFile(chnl_usr->net_info,loc_file_fullname,rem_file_fullname,g_pt61850app->mmsOpTimeout); + if (ret==SD_SUCCESS) { + + } + else { + echo_warn3(">>>>>**** Error!!! %s mms_getFile wave file : %s from %s\n",chnl_usr->ip_str ,loc_file_fullname,rem_file_fullname); + } + return ret; +} + +apr_status_t prepare_call_cn_wavelist(LD_info_t *LD_info, int FltNum) +{ + int i; + + for (i=0;i<256;i++) { + if (LD_info->FltNum[i]<=0) { + LD_info->FltNum[i] = FltNum; + break; + } + } + return APR_SUCCESS; +} + +apr_status_t call_cn_wavelist(LD_info_t *LD_info ) +{ + int ret ; + int chnl_no; + chnl_usr_t *chnl_usr = NULL; + char **filenames; + int filenum ; + int i; + char file_match_str[65]; + char *ldstr; + ied_t *ied = LD_info->ied; + ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + int have_new_files = FALSE; + + for (i=0;i<256;i++) { + if (LD_info->FltNum[i]<=0) + continue; + //LDƹ淶ֽڣPQMn, PQLDn ,5ֽڣ Ҳֻȡ4ַƥ + ldstr = LD_info->LD_name+strlen(LD_info->LD_name)-4; + apr_snprintf(file_match_str,sizeof(file_match_str),"%s_%06d",ldstr,LD_info->FltNum[i]); + + printf(">>>>>>>> IED [%d]: %s is calling cn wavefile, !!!!!!!! file_match_str=%s \n",ied->id,ied->name,file_match_str); + ret = SD_FAILURE; + filenum = 0; + assert(ied->chncount); + for(chnl_no=0 ; chnl_nochncount; chnl_no++) { + chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect; + if (chnl_usr->m_state!=CHANNEL_CONNECTED) + continue; + ret = mms_mvla_fdir(chnl_usr->net_info,g_pt61850app->accPath,3*g_pt61850app->mmsOpTimeout,&filenames,&filenum,g_pt61850app->tmp_pool); + if (ret==SD_SUCCESS) + break; + } + if (ret==SD_SUCCESS) { + int cfg_idx,dat_idx; + char file_base_name[128]; + char file_yyyymm[128]; + char cfg_only_filename_ret[256]; + char dat_only_filename_ret[256]; + int ret2,ret3; + + //WW 2023-11-01¼κַƥ޸Ϊintfltnumƥ + ret2 = parse_file_names_by_fltnum(LD_info->FltNum[i], ldstr, filenames, filenum, &cfg_idx, &dat_idx, file_base_name, file_yyyymm); + //ret2 = parse_file_names(file_match_str,filenames,filenum,&cfg_idx,&dat_idx,file_base_name,file_yyyymm); + //WW 2023-11-01 end + if (ret2 !=APR_SUCCESS) + return ret2; + + //¼ļ¼ļdat/cfg_only_filename_retУ׺һ¼ļҪϴ + ret2 = pt61850_write_cn_file(chnl_usr,ied,filenames[cfg_idx],cfg_only_filename_ret); + ret3 = pt61850_write_cn_file(chnl_usr,ied,filenames[dat_idx],dat_only_filename_ret); + have_new_files = TRUE; + +/////////////////////////////////////////////////////////////////////////////////////////////ϴļ + if (ret2==SD_SUCCESS && ret3==SD_SUCCESS ) { //ļд + QVVR_t *qvvr; //̬¼ + long long start_tm,trig_tm,end_tm; + //char ftp_filename[256]; + //doCommService(); + //memset(ftp_filename,0,256); + ret2 = extract_timestamp_from_cfg_file(filenames[cfg_idx],&start_tm,&trig_tm);//ȡļĿʼʱʹʱ + printf(">>>>>>>> extract_timestamp_from_cfg_file end \n"); + if (ret2 ==APR_SUCCESS) { + //to find the paired qvvr by the time of trig_tm + qvvr = find_qvvr_by_trig_tm(LD_info,trig_tm); //ļĴʱҼ¼ƥϵ̬¼ + if (qvvr) { + char* uuid_cfg = (char*)malloc(65 * sizeof(char));//ϴļȡ· + char* uuid_dat = (char*)malloc(65 * sizeof(char)); + char* filename_cfg = (char*)malloc(100 * sizeof(char));//ϴļȡļ + char* filename_dat = (char*)malloc(100 * sizeof(char)); + + //lnk202411-5 ¼webص·+ļ + char* wavepath_cfg = (char*)malloc(168 * sizeof(char)); + char* wavepath_dat = (char*)malloc(168 * sizeof(char)); +/*ϴ.cfg.datļ*/ + char linux_cmd[256] = {0}; + printf(">>>>>>>> qvvr ok end \n"); + apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",cfg_only_filename_ret,file_yyyymm,LD_info->line_id);//ûʹ + //printf("\n>>>>>> %s ...... \n",linux_cmd); + //system(linux_cmd); + + char loc_file_fullname_cfg[256];//ļ + memset(loc_file_fullname_cfg, 0, sizeof(loc_file_fullname_cfg)); + apr_snprintf(loc_file_fullname_cfg, sizeof(loc_file_fullname_cfg), "/home/pq/FeProject/comtrade/%s", cfg_only_filename_ret); + char oss_file_fullname_cfg[256];//Զļ + memset(oss_file_fullname_cfg, 0, sizeof(oss_file_fullname_cfg)); + apr_snprintf(oss_file_fullname_cfg, sizeof(oss_file_fullname_cfg), "comtrade/wave/%s/%s", LD_info->mp_id, cfg_only_filename_ret); + if (FILE_FLAG == 1) { + PutOSS(oss_file_fullname_cfg, loc_file_fullname_cfg);//ʹbufferļ + } + else if (FILE_FLAG == 2) { + OBSFile(loc_file_fullname_cfg, oss_file_fullname_cfg, "putObject");//ﲢûϴļ + } + else if(FILE_FLAG==3){ + WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_cfg, uuid_cfg, filename_cfg);//ͨform-dataϴļ + } + //LNK20241031ʹJSONļϴ-Զ·ԭӲļлȡ + else if (FILE_FLAG == 4) { + SOEFileWeb(loc_file_fullname_cfg, oss_file_fullname_cfg, wavepath_cfg); + } + else + { + + } + printf("\n>>>>>>!! %s %s...... \n", oss_file_fullname_cfg, loc_file_fullname_cfg); + + apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",dat_only_filename_ret,file_yyyymm,LD_info->line_id);//ͨsftpϴŷjsonȥ + //printf("\n>>>>>> %s ...... \n",linux_cmd); + //system(linux_cmd); + + char loc_file_fullname_dat[256]; + memset(loc_file_fullname_dat, 0, sizeof(loc_file_fullname_dat)); + apr_snprintf(loc_file_fullname_dat, sizeof(loc_file_fullname_dat), "/home/pq/FeProject/comtrade/%s", dat_only_filename_ret); + char oss_file_fullname_dat[256]; + memset(oss_file_fullname_dat, 0, sizeof(oss_file_fullname_dat)); + apr_snprintf(oss_file_fullname_dat, sizeof(oss_file_fullname_dat), "comtrade/wave/%s/%s", LD_info->mp_id, dat_only_filename_ret); + if (FILE_FLAG == 1) { + PutOSS(oss_file_fullname_dat, loc_file_fullname_dat);//ʹbufferļ + } + else if (FILE_FLAG == 2) { + OBSFile(loc_file_fullname_dat, oss_file_fullname_dat, "putObject");//ﲢûϴļ + } + else if(FILE_FLAG==3){ + WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_dat, uuid_dat, filename_dat);//ͨform-dataϴļ + } + //LNK20241031ʹJSONļϴ-Զ·ԭӲļлȡ + else if (FILE_FLAG == 4) { + SOEFileWeb(loc_file_fullname_dat, oss_file_fullname_dat, wavepath_dat); + } + printf("\n>>>>>>!! %s %s...... \n", oss_file_fullname_dat, loc_file_fullname_dat); +/*ϴ.cfg.datļ*/ +/*ϴϢ*/ + //to send json of this qvvr and rdre + end_tm = (long long)(qvvr->QVVR_PerTime*1000) + trig_tm; //ʱdzʱӴʱ + if (FILE_FLAG == 3) { + size_t cfg_len = strlen(uuid_cfg) + strlen(filename_cfg) + 3; // 3ַ"-"ͽ'\0' + char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // ̬㹻ڴռ + size_t dat_len = strlen(uuid_dat) + strlen(filename_dat) + 3; // 3ַ"-"ͽ'\0' + char* dat_result = (char*)malloc(dat_len * sizeof(char)); // ̬㹻ڴռ + if (cfg_result != NULL && dat_result != NULL) { + snprintf(cfg_result, cfg_len, "%s-%s", uuid_cfg, filename_cfg); // ƴַȷĿ껺 + snprintf(dat_result, dat_len, "%s-%s", uuid_dat, filename_dat); // ƴַȷĿ껺 + ret3 = transfer_json_qvvr_data(g_node_id, LD_info->line_id, qvvr->QVVR_Amg, qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, cfg_result, dat_result, LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type); + } + free(cfg_result); // ʹϺͷŶ̬ڴռ + free(dat_result); // ʹϺͷŶ̬ڴռ + } + else if(FILE_FLAG==4)//lnk20241031̬webϢ + { + //ڴ䲿ֲ޸ + size_t cfg_len = strlen(wavepath_cfg); + char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // ̬㹻ڴռ + size_t dat_len = strlen(wavepath_dat); + char* dat_result = (char*)malloc(dat_len * sizeof(char)); // ̬㹻ڴռ + + if (cfg_result != NULL && dat_result != NULL) { + snprintf(cfg_result, cfg_len, wavepath_cfg); // ƴַȷĿ껺 + snprintf(dat_result, dat_len, wavepath_dat); // ƴַȷĿ껺 + ret3 = transfer_json_qvvr_data(g_node_id, //ûʹ + LD_info->line_id, // + qvvr->QVVR_Amg, qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, //ֵʱ䡢ʼʱ䡢ʱ䡢̬ + cfg_result, dat_result, //ļ· + LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type);//ţļͼ̬¼ƥϵ̬ն + } + free(cfg_result); // ʹϺͷŶ̬ڴռ + free(dat_result); // ʹϺͷŶ̬ڴռ + } + else if (FILE_FLAG == 1 || FILE_FLAG == 2) + { + size_t cfg_len = strlen(oss_file_fullname_cfg) + strlen(cfg_only_filename_ret) + 3; // 3ַ"-"ͽ'\0' + char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // ̬㹻ڴռ + size_t dat_len = strlen(oss_file_fullname_dat) + strlen(dat_only_filename_ret) + 3; // 3ַ"-"ͽ'\0' + char* dat_result = (char*)malloc(dat_len * sizeof(char)); // ̬㹻ڴռ + if (cfg_result != NULL && dat_result != NULL) { + snprintf(cfg_result, cfg_len, "%s-%s", oss_file_fullname_cfg, cfg_only_filename_ret); // ƴַȷĿ껺 + snprintf(dat_result, dat_len, "%s-%s", oss_file_fullname_dat, dat_only_filename_ret); // ƴַȷĿ껺 + ret3 = transfer_json_qvvr_data(g_node_id, LD_info->line_id, qvvr->QVVR_Amg, qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, cfg_result, dat_result, LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type); + } + free(cfg_result); // ʹϺͷŶ̬ڴռ + free(dat_result); // ʹϺͷŶ̬ڴռ + } +/*ϴϢ*/ + qvvr->used_status = QVVR_DATA_NOT_USED; + free(uuid_cfg); + free(uuid_dat); + free(filename_cfg); + free(filename_dat); + + //lnk 202411-5 + free(wavepath_cfg); + free(wavepath_dat); + + } + } + } + + } + else { + if (ied && chnl_usr) + echo_warn2("mms_mvla_fdir Failed: IED [%d] %s \n", ied->id , chnl_usr->ip_str) ; + return APR_EAGAIN; + } + LD_info->FltNum[i]= -1; + } + + if (have_new_files) + clear_old_comtrade_files(); + + return APR_SUCCESS; +} + +//lnk 2024-11-4 ʱת +char* convertMsToDateTimeString(int msTime) { + // ʱתΪʱ + time_t seconds = msTime / 1000; + + // ȡʱ + struct tm* timeInfo = localtime(&seconds); + + // ַ̬洢תַ + static char buffer[20]; + strftime(buffer, sizeof(buffer), "%y-%m-%d %H:%M:%S", timeInfo); + + return buffer; +} + \ No newline at end of file diff --git a/mms/mmscli_log.c b/mms/mmscli_log.c new file mode 100644 index 0000000..2dc9056 --- /dev/null +++ b/mms/mmscli_log.c @@ -0,0 +1,609 @@ +/** +* @file: $RCSfile: mmscli_log.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.7 $ +* @date: $Date: 2019/01/08 03:06:27 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmscli_log.c,v 1.7 2019/01/08 03:06:27 lizhongming Exp $ +* +*/ + +/************************************************************************/ +#include "rdb_client.h" +#include "glbtypes.h" +#include "sysincs.h" +#include "signal.h" +#include "mmsdefs.h" +#include "mms_pvmd.h" +#include "mms_pvar.h" +#include "mms_vvar.h" +#include "mms_err.h" +#include "mms_pcon.h" +#include "asn1defs.h" +#include "mmsop_en.h" + +#include "lean_a.h" //add by lzm +#include "tp0_sock.h" +#include "mvl_defs.h" +#include "acse2.h" + +#include "mvl_acse.h" +#include "mvl_log.h" +#include "tp4api.h" +#include "clntobj.h" +#include "mmsclient.h" +#include "tp4.h" + +#include "db_interface.h" +/************************************************************************/ +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ +/************************************************************************/ + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + + + +/************************************************************************/ +/* Global variables. */ +/************************************************************************/ + +extern pt61850app_t* g_pt61850app; + +/************************************************************************/ +/* Static function prototypes. */ +/************************************************************************/ + +static ST_VOID log_var_jou_data (ST_INT var_type_id,VAR_ACC_DATA *var ,MMS_DECODE_DATA *data, ST_CHAR* dom_name) +{ + ST_INT rc; + ST_CHAR tdl_buf [500]; /* increase size if complex TDL expected*/ + MVL_TYPE_CTRL *type_ctrl; + ST_INT va_data_size; + ST_CHAR* temp_data_buf; + + ST_INT num_rt; /* Runtime type table */ + SD_CONST RUNTIME_TYPE* rt; + ST_INT data_size; /* size of data element */ + + type_ctrl = mvl_type_ctrl_find (var_type_id); + //char doname[32]; + //strcpy(doname, dom_name); + //type_ctrl = (MVL_TYPE_CTRL*)(sel_mvl_type_ctrl(doname)); + //printf ("\naddress: %p \n", type_ctrl); + if (type_ctrl) + { + num_rt = type_ctrl->num_rt; + rt = type_ctrl->rt; + data_size = type_ctrl->data_size; + //printf ("\nTYPE: %d %d %d\n", num_rt, data_size, rt->el_size); + /* If the TDL produced is longer than max_tdl_len, this function */ + /* "gracefully" fails (i.e. returns 0). */ + if (ms_runtime_to_tdl (rt, num_rt, tdl_buf, sizeof(tdl_buf))>0) + ;//SLOGCALWAYS1 (" TYPE: %s", tdl_buf); + else + echo_warn (" TYPE: unknown"); + //printf("\nrt %p and rt_num: %d \n", &type_ctrl->rt,type_ctrl->num_rt); + //printf ("\nTYPE: %s \n", tdl_buf); + va_data_size = data_size; + temp_data_buf = (ST_CHAR*)malloc( va_data_size); + rc = ms_asn1_to_local (rt, num_rt, var->data, var->len, temp_data_buf); + //printf("type_ctrl->num_rt %d %x %x \n", type_ctrl->num_rt , &data, &(var->data)); + my_local_to_data (temp_data_buf,rt,num_rt, data); + if (data->item_num==0) { + echo_warn("!!!!!!!!!!!!!!!!!!!data num is 0 !!!!!!!!!!!!!!!!\n"); + } + free(temp_data_buf); + } + else + echo_warn (" ERR: type_id is invalid"); +} + +/************************************************************************/ +/************************************************************************/ +#define STEADY_DATA (0) +#define QVVR_DATA (1) +#define RDRE_DATA (2) +apr_time_t process_jou_entry_t = apr_time_from_sec(0); +static ST_RET process_jou_entry(loginfo_t *loginfo,apr_time_t t, + MVL_JOURNAL_ENTRY *jou_entry, MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_name, ST_INT iTimeout) +{ + ST_RET ret = SD_SUCCESS; + ST_INT var_type_id; /* type_id for "ctrl_name" arg */ + int ii,j; + char *do_name; + MMS_DECODE_DATA mms_dec_data; + int log_data_type = STEADY_DATA; + ST_INT not_set_log_q_this; + ST_INT not_set_log_t_this; + int length_FCDA; + + not_set_log_q_this = TRUE; + not_set_log_t_this = TRUE; + + ST_INT timeflag = TRUE;//ִǰȡʱ + int log_data_steady_type = 0;//̬ ־ + + double start, end; + static double last_check_recall_config_time = 0.0; + printf("\nbrf for"); + for (j = 0; j < jou_entry->ef.data.num_of_var; j++) { + + printf("\nfor %d", jou_entry->ef.data.num_of_var); + printf("\nfor %s", jou_entry->ef.data.list_of_var[j].var_tag); + + if (strstr(jou_entry->ef.data.list_of_var[j].var_tag, dom_name) == NULL) + { + do_name = jou_entry->ef.data.list_of_var[j].var_tag; + } + else if (strstr(jou_entry->ef.data.list_of_var[j].var_tag, "reasonCode") != NULL) + { + continue; + } + else + { + do_name = strstr(jou_entry->ef.data.list_of_var[j].var_tag, "/"); + do_name++; + } + //printf("do_name =====%s=====\n", do_name); + //start = sGetMsTime(); + printf("\nbrf if"); + if (sel_mvl_type_ctrl_flag(do_name) == -1) + { + var_type_id = mms_var_type_id_create(clientNetInfo, DOM_SPEC, + dom_name, do_name, iTimeout); + + char doname[32]; + strcpy(doname, do_name); + add_mvl_type_ctrl(doname, var_type_id); + //printf("create var_type_id =====%d=====%p======\n", var_type_id, &doname); + } + printf("\nbrf var_type_id"); + var_type_id = sel_mvl_type_ctrl_flag(do_name); + printf("\nafter var_type_id"); + //end = sGetMsTime(); + //last_check_recall_config_time = last_check_recall_config_time + end - start; + //printf("jou_entry->ef.data.num_of_var =====%d===== =====%d=====\n", jou_entry->ef.data.num_of_var, var_type_id); + + /*var_type_id = mms_var_type_id_create(clientNetInfo, DOM_SPEC, + dom_name, do_name, iTimeout);*/ + //printf("var_type_id =====%d=====\n", var_type_id); + if (var_type_id < 0) { + //return SD_FAILURE; + continue; + } + log_var_jou_data(var_type_id,&(jou_entry->ef.data.list_of_var[j].value_spec),&mms_dec_data, do_name); + printf("\nafter log_var_jou_data"); + if (timeflag) { + int readtime = 0; + int readquailty = 0; + apr_time_t t; + int quality; + for (ii = 0; ii < mms_dec_data.item_num; ++ii) { + double v = 0.0; + char mms_ref[256]; + if (mms_dec_data.data_item[ii].type == DATA_INT_TYPE) + v = mms_dec_data.data_item[ii].u.data_int; + else if (mms_dec_data.data_item[ii].type == DATA_UINT_TYPE) + v = mms_dec_data.data_item[ii].u.data_uint; + else if (mms_dec_data.data_item[ii].type == DATA_INT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_int64; + else if (mms_dec_data.data_item[ii].type == DATA_UINT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_uint64; + else if (mms_dec_data.data_item[ii].type == DATA_DOUBLE_TYPE) + v = mms_dec_data.data_item[ii].u.data_double; + apr_snprintf(mms_ref, sizeof(mms_ref), "%s$%s", do_name, mms_dec_data.data_item[ii].comp_name); + + if (strstr(mms_ref, "QVVR")) { + log_data_type = QVVR_DATA; + timeflag = FALSE; + break; + } + else if (strstr(mms_ref, "RDRE")) { + log_data_type = RDRE_DATA; + timeflag = FALSE; + break; + } + + length_FCDA = strlen(mms_ref); + if (('$' == mms_ref[length_FCDA - 2]) && ('t' == mms_ref[length_FCDA - 1])) { + readtime = 1; + t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); + } + if (('$' == mms_ref[length_FCDA - 2]) && ('q' == mms_ref[length_FCDA - 1])) { + if (log_data_type == STEADY_DATA) { + readquailty = 1; + char* q = mms_dec_data.data_item[ii].u.data_str; + if (q[0] == '0' && q[1] == '0') + quality = 0; + else + quality = 1; + } + } + if (readtime == 1 && readquailty == 1) { + break; + } + } + if (readtime == 1 && readquailty == 1) { + if (quality == 1) { + timeflag = TRUE; + continue; + } + else + { + timeflag = FALSE; + if (process_jou_entry_t == 0) { + process_jou_entry_t = t; + } + + apr_time_exp_t newTime; + apr_time_exp_gmt(&newTime, t); + + apr_time_exp_t preTime; + apr_time_exp_gmt(&preTime, process_jou_entry_t); + if (newTime.tm_year != preTime.tm_year || newTime.tm_mon != preTime.tm_mon || newTime.tm_mday != preTime.tm_mday || newTime.tm_hour != preTime.tm_hour || newTime.tm_min != preTime.tm_min) //ʱ䷢ ִ̬json + { + printf("\n newTime: %d %d %d %d %d %d", newTime.tm_year, newTime.tm_mon, newTime.tm_mday, newTime.tm_hour, newTime.tm_min, newTime.tm_sec); + printf("\n preTime: %d %d %d %d %d %d", preTime.tm_year, preTime.tm_mon, preTime.tm_mday, preTime.tm_hour, preTime.tm_min, preTime.tm_sec); + json_block_create_end(loginfo->LD_info->mp_id, 0);//̬ + json_block_create_end(loginfo->LD_info->mp_id, 1);// + json_block_create_end(loginfo->LD_info->mp_id, 2);// + process_jou_entry_t = t;//ʱ + + ied_t* ied; + ied = find_ied_from_dev_code(loginfo->LD_info->terminal_code); + ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 0, ied_usr->dev_type, loginfo->LD_info->line_id);//ͽ ³ʼ¶ ̬ + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 1, ied_usr->dev_type, loginfo->LD_info->line_id);// + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 2, ied_usr->dev_type, loginfo->LD_info->line_id);// + } + } + } + } + + for ( ii = 0; ii < mms_dec_data.item_num; ++ii) { + double v = 0.0; + char mms_ref[256]; + if (mms_dec_data.data_item[ii].type==DATA_INT_TYPE) + v = mms_dec_data.data_item[ii].u.data_int; + else if (mms_dec_data.data_item[ii].type==DATA_UINT_TYPE) + v = mms_dec_data.data_item[ii].u.data_uint; + else if (mms_dec_data.data_item[ii].type==DATA_INT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_int64; + else if (mms_dec_data.data_item[ii].type==DATA_UINT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_uint64; + else if (mms_dec_data.data_item[ii].type==DATA_DOUBLE_TYPE) + v = mms_dec_data.data_item[ii].u.data_double; + //printf("%s %s = %f \n",jou_entry->ef.data.list_of_var[j].var_tag, mms_dec_data.data_item[ii].comp_name,v); + apr_snprintf(mms_ref,sizeof(mms_ref),"%s$%s",do_name,mms_dec_data.data_item[ii].comp_name); + if ( (strstr(mms_ref,"]")==NULL) || (strstr(mms_ref,"0]")) ) + //printf("\nlog read: %s=%f\n",mms_ref,v); + if (j==0 && ii==0) { + printf("\n ----------------------------------------------------------------log read: %s=%f--------------------------------------------------------------\n",mms_ref,v); + if ( strstr(mms_ref,"QVVR") ) { + log_data_type = QVVR_DATA; + } + else if ( strstr(mms_ref,"RDRE") ) { + log_data_type = RDRE_DATA; + } + else if (strcasestr(mms_ref, "PLT") ) { + log_data_steady_type = 1; + } + else if (strcasestr(mms_ref, "PST") || strcasestr(mms_ref, "FLUC")) { + log_data_steady_type = 2; + } + if ( ( (loginfo->need_steady==0) &&(log_data_type == STEADY_DATA)) + || ( (loginfo->need_voltage==0) &&(log_data_type != STEADY_DATA)) ){ + //mvl_type_id_destroy(var_type_id); + return SD_SUCCESS; + } + + if ( log_data_type == QVVR_DATA ) { + processQVVR_start(loginfo->LD_info); + //processQVVR_time(loginfo->LD_info,t/1000); + } + else if ( log_data_type == RDRE_DATA ) { + processRDRE_start(loginfo->LD_info); + } + else { + /*ied_t* ied; + ied = find_ied_from_dev_code(loginfo->LD_info->terminal_code); + ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; + json_block_create_start( loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id,0, ied_usr->dev_type);*/ + //json_block_create_time(loginfo->LD_info->line_id,t/1000); + } + } + //set_db_value(LOG_IDX,mms_ref,v,FALSE); + length_FCDA = strlen( mms_ref ); + if ( ('$'==mms_ref[length_FCDA-2]) && ('q'==mms_ref[length_FCDA-1]) ) { + if(not_set_log_q_this && ( log_data_type == STEADY_DATA )) { + int quality = 0; + char* q = mms_dec_data.data_item[ii].u.data_str; + if (q[0]=='0'&& q[1]=='0') + quality = 0; + else + quality = 1; + if (quality == 1) { + continue; + } + //set_log_QualityFlag(quality); + if (log_data_steady_type == 0) { + json_block_create_flag(loginfo->LD_info->mp_id, quality, 0); + } + else if (log_data_steady_type == 1) { + json_block_create_flag(loginfo->LD_info->mp_id, quality, 1); + } + else if (log_data_steady_type == 2) { + json_block_create_flag(loginfo->LD_info->mp_id, quality, 2); + } + not_set_log_q_this = FALSE; + } + } + else if ( ('$'==mms_ref[length_FCDA-2]) && ('t'==mms_ref[length_FCDA-1]) ) { + if (not_set_log_t_this) { + apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); + if ( log_data_type == QVVR_DATA ) { + if ( strstr(mms_ref,"VarStr$t") ) { + processQVVR_time(loginfo->LD_info,t/1000); + not_set_log_t_this = FALSE; + } + } + else if ( log_data_type == RDRE_DATA ) { + //need do nothing! + not_set_log_t_this = FALSE; + } + else { + if (log_data_steady_type == 0) { + json_block_create_time(loginfo->LD_info->mp_id, t / 1000, 0); + } + else if (log_data_steady_type == 1) { + json_block_create_time(loginfo->LD_info->mp_id, t / 1000, 1); + } + else if (log_data_steady_type == 2) { + json_block_create_time(loginfo->LD_info->mp_id, t / 1000, 2); + } + not_set_log_t_this = FALSE; + } + } + } + else { + if ( log_data_type == QVVR_DATA ){ + processQVVR_data(loginfo->LD_info,mms_ref,v); + } + else if ( log_data_type == RDRE_DATA ) { + processRDRE_data(loginfo->LD_info,mms_ref,v); + } + else + { + if (log_data_steady_type == 0) { + json_block_create_data(loginfo->LD_info->mp_id, mms_ref, v, 0); + } + else if (log_data_steady_type == 1) { + json_block_create_data(loginfo->LD_info->mp_id, mms_ref, v, 1); + } + else if (log_data_steady_type == 2) { + json_block_create_data(loginfo->LD_info->mp_id, mms_ref, v, 2); + } + } + + } + + } + + //mvl_type_id_destroy(var_type_id); + } + printf("\naft for"); + if ( log_data_type == QVVR_DATA ) { + processQVVR_end(loginfo->LD_info); + } + else if ( log_data_type == RDRE_DATA ) { + processRDRE_end(loginfo->LD_info); + } + else { + //json_block_create_end(loginfo->LD_info->mp_id,0); + } + printf("\nend process_jou_entry"); + //printf("process_jou_entry ==============%.2f================\n", last_check_recall_config_time); + return ret; +} + +/************************************************************************/ +/* mms_jread */ +/************************************************************************/ +ST_RET mms_jread (loginfo_t *loginfo,MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_name,ST_CHAR *logName, + apr_time_t start_time,apr_time_t end_time,ST_INT iTimeout, ST_CHAR* ip) +{ + ST_RET ret; + ST_INT i, k; + MVL_REQ_PEND *reqCtrl; + JREAD_REQ_INFO jread_req; + MVL_JREAD_RESP_INFO *jread_resp; /* set to reqCtrl->u.jread_resp_info*/ + MVL_JOURNAL_ENTRY *jou_entry; + MMS_UTC_TIME utc_time_start,utc_time_end; + MMS_BTOD btod_time_start,btod_time_end; + ST_UCHAR entry_id[8]; + ST_INT more_follows = 0; + MMS_BTOD last_occur_time; + + memset(&last_occur_time,0,sizeof(MMS_BTOD)); + memset(&jread_req,0,sizeof(MVL_JREAD_RESP_INFO)); + jread_req.jou_name.object_tag = DOM_SPEC; + jread_req.jou_name.domain_id = dom_name; + + jread_req.jou_name.obj_name.vmd_spec = logName;//vmd_spec item_id + jread_req.range_start_pres = 1; + jread_req.range_stop_pres = 1; + jread_req.start_tag = 0; //starting time + jread_req.stop_tag = 0; //ending time + convert_apr_time_to_utc_time(start_time,&utc_time_start); + my_asn1_convert_utc_to_btod (&utc_time_start, &btod_time_start); + memcpy(&jread_req.start_time, &btod_time_start, sizeof(MMS_BTOD)); + convert_apr_time_to_utc_time(end_time,&utc_time_end); + my_asn1_convert_utc_to_btod (&utc_time_end, &btod_time_end); + memcpy(&jread_req.end_time, &btod_time_end, sizeof(MMS_BTOD)); + jread_req.num_of_entries = 0; + jread_req.num_of_var = 0; + jread_req.list_of_var_pres = 0; + jread_req.sa_entry_pres = 0; + jread_req.entry_spec_len = 0; + jread_req.entry_spec = 0; + memcpy(&jread_req.time_spec, &btod_time_start, sizeof(MMS_BTOD)); + process_jou_entry_t = apr_time_from_sec(0); + + double start,end; + static double last_check_recall_config_time = 0.0; + + static double heart_time_cout = 0.0;//ʱ + static double heart_time_cout_start = 0.0;//ʱ ʼ + static double heart_time_cout_now = 0.0;//ʱ ǰ + do { + heart_time_cout_now = sGetMsTime(); + if (heart_time_cout_now - heart_time_cout_start > 30000)//30 ʱ + { + printf("\n heart_time_cout OK"); + heart_time_cout_start = sGetMsTime(); + int i = 0; + while (i < g_pt61850app->chnl_counts) + { + chnl_usr_t* chnl_usr; + int cpuno = 0; + + chnl_usr = g_pt61850app->chnl_usr[i]; + //printf("\n chnl_usr->m_state ===== %d\n", chnl_usr->m_state); + if (strstr(chnl_usr->ip_str, ip) != NULL) + { + printf("\nSame Ip %s : %s", chnl_usr->ip_str, ip); + i++; + continue; + } + if (chnl_usr->m_state == CHANNEL_CONNECTED) { + char** varnames; + int varnum; + ST_RET ret = mms_mvla_getnam(chnl_usr->net_info, VMD_SPEC, NULL, MMS_CLASS_DOM, g_pt61850app->mmsOpTimeout, + &varnames, &varnum, g_pt61850app->tmp_pool); + chnl_usr->m_LastPosRespTime = sGetMsTime(); + if (ret == SD_SUCCESS) { + printf("\n heart success!"); + chnl_usr->m_NegRespTimes = 0; + } + else { + printf("%d--------------\n", chnl_usr->m_NegRespTimes); + chnl_usr->m_NegRespTimes++; + } + } + i++; + } + heart_time_cout_start = sGetMsTime(); + } + ret = mvla_jread (clientNetInfo, &jread_req, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) { + more_follows = 0; + printf ("\n mvl_jread () Error, ret = 0x%X.", ret); + } + else + { + printf ("\n mvl_jread OK"); + jread_resp = reqCtrl->u.jread.resp_info; + printf ("\n num_entry = %d", jread_resp->num_of_jou_entry); + printf ("\n more_follows = %d", jread_resp->more_follows); + more_follows = jread_resp->more_follows; + for (i = 0; i < jread_resp->num_of_jou_entry; i++) + { + apr_time_t t; + jou_entry = &jread_resp->jou_entry[i]; + if ( ( (i+1)==jread_resp->num_of_jou_entry) && more_follows ) { + jread_req.range_start_pres = 0; + jread_req.sa_entry_pres = 1; + jread_req.entry_spec_len = jou_entry->entry_id_len; + memcpy(entry_id,jou_entry->entry_id,sizeof(entry_id)); + jread_req.entry_spec = entry_id; + jread_req.time_spec = jou_entry->occur_time; + jread_req.num_of_entries = 0; + } + printf ("\n Journal Entry # %d:", i); + printf ("\n entry_id_len = %d ", jou_entry->entry_id_len); + for (k = 0; k < jou_entry->entry_id_len; k++) + printf("%02x ", jou_entry->entry_id[k]); + printf ("\n occur_time.form = %s", (jou_entry->occur_time.form == MMS_BTOD6 ? "MMS_BTOD6" : "MMS_BTOD4")); + printf ("\n occur_time.ms = %lu", jou_entry->occur_time.ms); + printf ("\n occur_time.day = %lu", jou_entry->occur_time.day); + printf ("\n entry_form_tag = %d", jou_entry->entry_form_tag); + + if( (last_occur_time.day!=jou_entry->occur_time.day)||(last_occur_time.ms!=jou_entry->occur_time.ms) ) { + last_occur_time=jou_entry->occur_time; + //append_db_records(LOG_IDX); + } + printf("\nbrf convert_btod_to_apr_time"); + t = convert_btod_to_apr_time(&jou_entry->occur_time); + //set_log_TimeID(convert_btod_to_apr_time(&jou_entry->occur_time)); + if (jou_entry->entry_form_tag == 2) + { + printf("\nbrf jou_entry->ef.data.list_of_var_pres"); + if (jou_entry->ef.data.list_of_var_pres) + { + //for (j = 0; j < jou_entry->ef.data.num_of_var; j++) + //{ + // printf ("\n Var # %d: var_tag = %s", j, jou_entry->ef.data.list_of_var[j].var_tag); + // printf ("\n Var # %d: value_spec.len = %d", j,jou_entry->ef.data.list_of_var[j].value_spec.len); + //} + start = sGetMsTime(); + printf("\nbrf process_jou_entry"); + process_jou_entry(loginfo,t,jou_entry, clientNetInfo, dom_name, iTimeout) ; + //start = sGetMsTime(); + if ( jread_resp->more_follows == 0 && ((i + 1) == jread_resp->num_of_jou_entry)) { + printf("\njread_resp->more_follows == 0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + json_block_create_end(loginfo->LD_info->mp_id, 0);//more followsΪ0 ݽһ ǿд̬ݵjsonֹ + json_block_create_end(loginfo->LD_info->mp_id, 1); + json_block_create_end(loginfo->LD_info->mp_id, 2); + + ied_t* ied; + ied = find_ied_from_dev_code(loginfo->LD_info->terminal_code); + ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 0, ied_usr->dev_type, loginfo->LD_info->line_id);//ͽ ³ʼ¶ ̬ + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 1, ied_usr->dev_type, loginfo->LD_info->line_id);// + json_block_create_start(loginfo->LD_info->voltage_level, loginfo->LD_info->mp_id, 2, ied_usr->dev_type, loginfo->LD_info->line_id);// + } + end = sGetMsTime(); + } + last_check_recall_config_time = last_check_recall_config_time + end - start; + //printf("jread_resp->more_follows = 0 ==============%.2f================\n", last_check_recall_config_time); + } + else { + printf ("\n annotation = %s", jou_entry->ef.annotation); + } + + //apr_time_exp_t newTime; + //apr_time_exp_gmt(&newTime, t); + printf("\nstart timecheck"); + apr_time_exp_t newTime; + apr_time_exp_gmt(&newTime, process_jou_entry_t); + printf("\nstart timecheck_1"); + apr_time_exp_t preTime; + apr_time_exp_gmt(&preTime, end_time); + printf("\nstart timecheck_2"); + if (newTime.tm_year != preTime.tm_year || newTime.tm_mon != preTime.tm_mon || newTime.tm_mday != preTime.tm_mday || (newTime.tm_hour != preTime.tm_hour && newTime.tm_hour != preTime.tm_hour + 1 && newTime.tm_hour != preTime.tm_hour - 1)) //ʱж ʱ䳬ʱʱ + { + printf("\nstart timecheck_3"); + printf("\n more_follows newTime: %d %d %d %d %d %d", newTime.tm_year, newTime.tm_mon, newTime.tm_mday, newTime.tm_hour, newTime.tm_min, newTime.tm_sec); + printf("\n more_follows preTime: %d %d %d %d %d %d", preTime.tm_year, preTime.tm_mon, preTime.tm_mday, preTime.tm_hour, preTime.tm_min, preTime.tm_sec); + more_follows = 0; + } + printf("\nstart timecheck_end"); + } /* end "loop" */ + } + mvl_free_req_ctrl (reqCtrl); /* CRITICAL: */ + } while (more_follows); + //mvl_type_id_destroy(1); + //del_mvl_type_ctrl(); + //printf("do while ==============%.2f================\n", last_check_recall_config_time); + //append_db_records(LOG_IDX); + return (ret); +} + diff --git a/mms/mmscli_rpt.c b/mms/mmscli_rpt.c new file mode 100644 index 0000000..4488e1d --- /dev/null +++ b/mms/mmscli_rpt.c @@ -0,0 +1,2663 @@ +/** +* @file: $RCSfile: mmscli_rpt.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.12 $ +* @date: $Date: 2022/11/28 07:13:13 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmscli_rpt.c,v 1.12 2022/11/28 07:13:13 lizhongming Exp $ +* +*/ +//$Header: /JoyProject/jspqfe/src/pt61850netd_pqfe/source/mms/mmscli_rpt.c,v 1.12 2022/11/28 07:13:13 lizhongming Exp $ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 2003 - 2005, All Rights Reserved */ +/* */ +/* MODULE NAME : cli_rpt.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* Functions to perform "client" processing of IEC-61850 Reports */ +/* and UCA Reports received from "servers". */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* rpt_typeids_find */ +/* rcb_info_create */ +/* rcb_info_destroy */ +/* u_iec_rpt_ind */ +/* u_iec_rpt_ind_data (user modify or replace) */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 07/22/05 JRB 08 Allow one conn to control multiple RCBs */ +/* (user_info must point to ALL_RCB_INFO). */ +/* Save varNameArray in rcb_info to use later. */ +/* Chg u_iec_rpt_ind_data 4th arg to (RCB_INFO *).*/ +/* 12/03/04 JRB 07 Extract domain name of NVL from dataSetName. */ +/* Increase RptID length to vstring65. */ +/* 08/04/04 EJV 06 rcb_info_create: added typecast for Inclusion*/ +/* 06/29/04 JRB 05 Del mvl_tdl_to_type_id & instead use new */ +/* mvl_type_id_create_from_tdl. */ +/* 05/13/04 JRB 04 Chg SqNum to INT16U to match 61850-7-2. */ +/* 01/23/04 JRB 03 Use ms_local_to_text. */ +/* 12/17/03 JRB 02 61850-8-1 FDIS changes: */ +/* Decode ConfRev in rpt if enabled by OptFlds. */ +/* Move SubSeqNum, MoreSegmentsFollow to just */ +/* before inclusion bitstring. */ +/* Chg OptFlds from bvstring9 to bvstring10. */ +/* 10/24/03 JRB 01 New */ +/************************************************************************/ + +#include "rdb_client.h" +#include "db_interface.h" +#include "../json/mms_json_inter.h" +/************************************************************************/ +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ +/************************************************************************/ + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR* SD_CONST thisFileName = __FILE__; +#endif + +extern pt61850app_t* g_pt61850app; +extern RPT_TYPEIDS g_rpt_typeids; +//lnk20250115 +extern pthread_mutex_t mtx; + +/************************************************************************/ +/* Global variables. */ +/************************************************************************/ +/* NONE */ + +/************************************************************************/ +/* Static function prototypes. */ +/************************************************************************/ +static OBJECT_NAME** nvl_var_name_array_create(MVL_NET_INFO* net_info, ST_CHAR* domName, + ST_CHAR* nvlName, ST_INT* numVarOut, ST_INT timeOut); +static ST_VOID nvl_var_name_array_destroy(OBJECT_NAME** varNameArray, ST_INT numVar); +static ST_INT var_type_create(MVL_NET_INFO* net_info, OBJECT_NAME* varObj, + ST_INT timeOut); +static ST_RET rcb_info_var_create(RCB_INFO* rcb_info, RPT_TYPEIDS* rpt_typeids); +static ST_VOID rcb_info_var_destroy(RCB_INFO* rcb_info); +static ST_VOID log_var_data(MVL_VAR_ASSOC* var, MMS_DECODE_DATA* data); + +/* DEBUG: move these functions to library modules? */ +OBJECT_NAME* object_name_clone_create(OBJECT_NAME* srcobj); +ST_VOID object_name_clone_destroy(OBJECT_NAME* obj); + +static ST_ULONG a_get_rem_ip_addr_inline(ST_LONG acse_conn_id, int* nPort); +static char* _convert_ip_2_char(unsigned long dwIP); + +#if 1 // ȡIP WW 2023-08-29 +static char* _convert_ip_2_char(unsigned long dwIP) +{ + static char buf[64] = { 0 }; + sprintf(buf, "%d.%d.%d.%d", (dwIP >> 24) & 0xff, (dwIP >> 16) & 0xff, (dwIP >> 8) & 0xff, (dwIP) & 0xff); + return buf; +} + +#if defined (TP0_ENABLED) +/************************************************************************/ +/* a_get_rem_ip_addr */ +/* This function returns the remote IP Address as an unsigned long in */ +/* "network byte order", just like the "standard sockets" function */ +/* "inet_addr" does. If there is an error, it returns */ +/* "htonl (INADDR_NONE)", just like "inet_addr" does. */ +/* The return value can be stored in the appropriate union member */ +/* in the structure "in_addr", which can be passed to "inet_ntoa". */ +/************************************************************************/ +#include "tp4.h" /* Need internal TP4 defines */ +#include "tp0_sock.h" /* Need "sockets" defines */ +#include "acse2.h" /* Need "sockets" defines */ +#define MAX_PATH 256 +static ST_ULONG get_rem_ip_addr_inline(ST_LONG acse_conn_id, int* nPort) +{ + ACSE_CONN *acse_conn; + ST_LONG tp_conn_id; + TP0_CONN *tp0_conn; + ST_INT ret; + SOCKADDR_IN sockaddr_in; + SOCK_ADDRLEN addr_len; + char buf[MAX_PATH] = { 0 }; + acse_conn = (ACSE_CONN *)acse_conn_id; + tp_conn_id = acse_conn->tp4_conn_id; + if (tp_conn_id >= MIN_TP0_CONN_ID && + tp_conn_id < tp0_cfg.max_num_conns + MIN_TP0_CONN_ID) + { /* Conn id is a legal TP0 conn id */ + tp0_conn = &tp0_conn_arr[tp_conn_id - MIN_TP0_CONN_ID]; + + addr_len = sizeof(SOCKADDR_IN); /* CRITICAL: set to expected len.*/ + ret = getpeername(tp0_conn->sock_info->genSock->hSock, (SOCKADDR *)&sockaddr_in, &addr_len); + *nPort = htons(sockaddr_in.sin_port); + if (ret == 0) + return (sockaddr_in.sin_addr.s_addr); + } + + return (htonl(INADDR_NONE)); /* something failed */ +} +#endif /* defined (TP0_ENABLED) */ +#endif + +/************************************************************************/ +/* rpt_typeids_find */ +/* Find ALL types needed for controlling & decoding IEC/UCA reports. */ +/* These types must be defined in the ODF file and created by Foundry. */ +/* RETURN: SD_SUCCESS or SD_FAILURE (if ANY type is NOT found) */ +/* NOTE: this function based on "mvlu_rpt_find_typeids" in "mvlu_rpt.c".*/ +/************************************************************************/ +ST_RET rpt_typeids_find(RPT_TYPEIDS* rpt_typeids) +{ + ST_RET retCode = SD_FAILURE; /* assume FAILURE for now */ + ST_CHAR* type_name; /* name of type to be found */ + + /* stop on any error */ + do + { /* "one-time" loop: just to have something to break out of */ + if ((rpt_typeids->mmsbool = mvl_typename_to_typeid(type_name = "RTYP_BOOL")) < 0) + break; + if ((rpt_typeids->bstr6 = mvl_typename_to_typeid(type_name = "RTYP_BSTR6")) < 0) + break; + if ((rpt_typeids->bstr8 = mvl_typename_to_typeid(type_name = "RTYP_BSTR8")) < 0) + break; + if ((rpt_typeids->bstr9 = mvl_typename_to_typeid(type_name = "RTYP_BSTR9")) < 0) + break; + if ((rpt_typeids->bvstring6 = mvl_typename_to_typeid(type_name = "RTYP_BVSTR6")) < 0) + break; + if ((rpt_typeids->bvstring8 = mvl_typename_to_typeid(type_name = "RTYP_BVSTR8")) < 0) + break; + if ((rpt_typeids->bvstring10 = mvl_typename_to_typeid(type_name = "RTYP_BVSTR10")) < 0) + break; + if ((rpt_typeids->btime6 = mvl_typename_to_typeid(type_name = "RTYP_BTIME6")) < 0) + break; + if ((rpt_typeids->int8u = mvl_typename_to_typeid(type_name = "RTYP_INT8U")) < 0) + break; + if ((rpt_typeids->int16u = mvl_typename_to_typeid(type_name = "RTYP_INT16U")) < 0) + break; + if ((rpt_typeids->int32u = mvl_typename_to_typeid(type_name = "RTYP_INT32U")) < 0) + break; + if ((rpt_typeids->ostring8 = mvl_typename_to_typeid(type_name = "RTYP_OSTR8")) < 0) + break; + if ((rpt_typeids->vstring32 = mvl_typename_to_typeid(type_name = "RTYP_VSTR32")) < 0) + break; + if ((rpt_typeids->vstring65 = mvl_typename_to_typeid(type_name = "RTYP_VSTR65")) < 0) + break; + + retCode = SD_SUCCESS; /* If we get here, all were successful */ + } while (0); /* end of "one-time" loop */ + + if (retCode) + MVL_LOG_ERR1("Can't find type '%s'", type_name); + return (retCode); /* If ANY find failed, SD_FAILURE is returned */ +} + +/************************************************************************/ +/* rcb_info_create */ +/************************************************************************/ +RCB_INFO* rcb_info_create(MVL_NET_INFO* net_info, ST_CHAR* domName, + ST_CHAR* rcbName, RPT_TYPEIDS* rpt_typeids, ST_INT timeOut) +{ + RCB_INFO* rcb_info; + ST_CHAR varName[MAX_IDENT_LEN + 1]; + ST_CHAR datSetName[65 + 1]; /* data set name (Vstring65) */ + ST_CHAR datdomName[65 + 1]; /* data set name (Vstring65) */ + ST_CHAR RptID[65 + 1]; /* RptID (Vstring65) */ + ST_CHAR* nvlName; + ST_INT numDsVar; /* num variables in NVL */ + OBJECT_NAME** varNameArray; /* array of variable names in NVL */ + ST_INT j; + size_t extended_size; + ST_CHAR* extended_ptr; + ST_CHAR InclusionTdl[30]; /* place to create TDL for inclusion bstr*/ + ST_RET status = SD_SUCCESS; /* set to SD_FAILURE if anything fails. */ + ST_CHAR* nvlDomName; + ST_INT rcb_type; + + assert(rpt_typeids->mmsbool || rpt_typeids->int8u); /* make sure global struct initialized*/ + + /* Read "RptID" from the server & save in "RptID" local variable. */ + /* Copy to "rcb_info" struct later. */ + strcpy(varName, rcbName); + strcat(varName, "$RptID"); + if (mms_named_var_read(net_info, varName, DOM_SPEC, domName, rpt_typeids->vstring65, RptID, timeOut)) + { + echo_warn2("Error reading RptID '%s' in domain '%s'\n", varName, domName); + return (NULL); + } + /* Figure out RCB type from 'rcbName'. */ + if (strstr(rcbName, "$BR$") != NULL) + rcb_type = RCB_TYPE_IEC_BRCB; + else if (strstr(rcbName, "$RP$") != NULL) + { + /* This could be IEC URCB or UCA URCB. Only IEC contains "Resv" attr.*/ + /* Try to read "Resv". If successful, RCB is IEC_URCB, else it is UCA.*/ + /* NOTE: "RptID" read was successful, so we know this RCB exists. */ + ST_BOOLEAN tmpResv; + strcpy(varName, rcbName); + strcat(varName, "$Resv"); + if (mms_named_var_read(net_info, varName, DOM_SPEC, domName, rpt_typeids->mmsbool, &tmpResv, timeOut) == SD_SUCCESS) + rcb_type = RCB_TYPE_IEC_URCB; + else + rcb_type = RCB_TYPE_UCA; + } + else + { + echo_warn1("RCB name '%s' invalid. Must contain 'BR' or 'RP'.\n", rcbName); + return (NULL); + } + /* Read "DatSet" from the server. */ + strcpy(varName, rcbName); + strcat(varName, "$DatSet"); + if (mms_named_var_read(net_info, varName, DOM_SPEC, domName, rpt_typeids->vstring65, datSetName, timeOut)) + { /* can't read data set name */ + echo_warn2("Error reading data set name ('%s' in domain '%s')\n", varName, domName); + return (NULL); + } + /* datSetName should now be set */ + strcpy(datdomName, datSetName);//WW 2023-10-23 + nvlDomName = strtok(datdomName, "/");/* extract domain name of NVL */ + nvlName = strtok(NULL, ""); /* extract NVL name */ + if (nvlName == NULL) /* "/" not found */ + { + echo_warn1("datSetName '%s' invalid. Does not contain '/' character.", datSetName); + return (NULL); + } + /* Get NVL Attributes from the server */ + /* NOTE: Resources allocated by this funct are freed by calling */ + /* nvl_var_name_array_destroy (called from rcb_info_destroy). */ + varNameArray = nvl_var_name_array_create(net_info, nvlDomName, nvlName, &numDsVar, timeOut); + if (varNameArray == NULL) + { + echo_warn2("GetNamedVariableListAttributes request failed for '%s' in domain '%s'", + nvlName, domName); + return (NULL); + } + /* Allocate RCB_INFO structure plus extra room for additional data + * that depends on "numDsVar". This effectively combines 8 allocations into one. + * Set pointers in RCB_INFO structure to point into the extra space. + * CRITICAL: use chk_calloc to start with clean structure + */ + extended_size = sizeof(RCB_INFO) + + numDsVar * sizeof(ST_INT) /* rcb_info->typeIdArr */ + + numDsVar * sizeof(MVL_VAR_ASSOC*) /* rcb_info->rcb_var.dataRefName*/ + + numDsVar * sizeof(MVL_VAR_ASSOC*) /* rcb_info->rcb_var.dataValue */ + + numDsVar * sizeof(MVL_VAR_ASSOC*) /* rcb_info->rcb_var.Reason */ + + numDsVar * 66 /* rcb_info->rcb_data.dataRefName*/ + + numDsVar * sizeof(MMS_BVSTRING) /* rcb_info->rcb_data.Reason */ + + BSTR_NUMBITS_TO_NUMBYTES(numDsVar); /* rcb_info->rcb_data.Inclusion */ + + rcb_info = (RCB_INFO*)chk_calloc(1, extended_size); + strcpy(rcb_info->dom_Name, domName); //WW 2023-08-29 ߼豸 + strcpy(rcb_info->rcb_name, rcbName); //WW 2023-08-29 ƿ + ////////////////////////////////////////////////////////////////////////// + strcpy(rcb_info->ds_Nam, datSetName); //WW 2023-08-29 ݼ + ////////////////////////////////////////////////////////////////////////// + + echo_msg4("Client RCB info 0x%X created for '%s' in domain '%s'.datasetnam '%s' \n", rcb_info, rcbName, domName, datSetName); + extended_ptr = (ST_CHAR*)(rcb_info + 1); /* point after RCB_INFO struct */ + + rcb_info->typeIdArr = (ST_INT*)extended_ptr; + extended_ptr += numDsVar * sizeof(ST_INT); /* point after rcb_info->typeIdArr*/ + + rcb_info->rcb_var.dataRefName = (MVL_VAR_ASSOC**)extended_ptr; + extended_ptr += numDsVar * sizeof(MVL_VAR_ASSOC*); /* rcb_info->rcb_var.dataRefName*/ + + rcb_info->rcb_var.dataValue = (MVL_VAR_ASSOC**)extended_ptr; + extended_ptr += numDsVar * sizeof(MVL_VAR_ASSOC*); /* rcb_info->rcb_var.dataValue */ + + rcb_info->rcb_var.Reason = (MVL_VAR_ASSOC**)extended_ptr; + extended_ptr += numDsVar * sizeof(MVL_VAR_ASSOC*); /* rcb_info->rcb_var.Reason */ + + rcb_info->rcb_data.dataRefName = extended_ptr; + extended_ptr += numDsVar * 66; /* rcb_info->rcb_data.dataRefName*/ + + rcb_info->rcb_data.Reason = (MMS_BVSTRING*)extended_ptr; + extended_ptr += numDsVar * sizeof(MMS_BVSTRING); /* rcb_info->rcb_data.Reason */ + + rcb_info->rcb_data.Inclusion = (ST_UINT8*)extended_ptr; + extended_ptr += BSTR_NUMBITS_TO_NUMBYTES(numDsVar); /* rcb_info->rcb_data.Inclusion */ + + /* Make sure we computed sizes correctly. */ + assert(extended_ptr == (ST_CHAR*)rcb_info + extended_size); + + /* Fill in other rcb_info structure members. */ + rcb_info->rcb_type = rcb_type; + strcpy(rcb_info->RptID, RptID); /* save RptID to compare when RPTs received*/ + rcb_info->varNameArray = varNameArray; + rcb_info->numDsVar = numDsVar; + + /* Create all necessary types. */ + /* Try to create all types even if one fails. */ + /* This way, we can later destroy all without remembering which */ + /* were successfully created. */ + + /* Create a Type for the Inclusion bitstring. Save it in "rcb_info->InclusionTypeid" */ + apr_snprintf(InclusionTdl, sizeof(InclusionTdl), "Bstring%d", rcb_info->numDsVar); + rcb_info->InclusionTypeid = mvl_type_id_create_from_tdl(NULL, InclusionTdl); + if (rcb_info->InclusionTypeid < 0) + { + echo_warn("Error - could not add type for 'Inclusion'."); + status = SD_FAILURE; + } + + /* Create types and fill in rcb_info->typeIdArr */ + /* Start with all set to invalid, so if some fail, cleanup is easier. */ + for (j = 0; j < numDsVar; j++) + rcb_info->typeIdArr[j] = -1; /* invalid type_id */ + for (j = 0; j < numDsVar; j++) + { + if ((rcb_info->typeIdArr[j] = var_type_create(net_info, varNameArray[j], timeOut)) + < 0) + { /* couldn't create this type, so stop */ + echo_warn1("Error creating type for variable '%s'", + varNameArray[j]->obj_name.vmd_spec); + status = SD_FAILURE; + break; + } + } + + if (status == SD_SUCCESS) + { + /* Types created OK, so create variables */ + status = rcb_info_var_create(rcb_info, rpt_typeids); /* returns SD_SUCCESS or SD_FAILURE*/ + } + + if (status != SD_SUCCESS) + { /* something failed. Destroy anything created. */ + rcb_info_destroy(rcb_info); + rcb_info = NULL; + } + + return (rcb_info); +} + +/************************************************************************/ +/* rcb_info_destroy */ +/************************************************************************/ +ST_VOID rcb_info_destroy(RCB_INFO* rcb_info) +{ + ST_INT j; + + /* Free up array of variable names saved in rcb_info_create */ + nvl_var_name_array_destroy(rcb_info->varNameArray, rcb_info->numDsVar); + + /* Destroy all variables. */ + rcb_info_var_destroy(rcb_info); + + + /* Destroy "Inclusion" Type (this should be AFTER destroying "Inclusion" Variable).*/ + if (rcb_info->InclusionTypeid > 0) /* 0=never created. -1=error */ + mvl_type_id_destroy(rcb_info->InclusionTypeid); + + /* Destroy "dataValue" Types (this should be AFTER destroying "dataValue" variables). */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + /* All types were initialized to -1. They are also set to -1 if create failed.*/ + /* Only destroy types that are NOT (-1). */ + if (rcb_info->typeIdArr[j] >= 0) + mvl_type_id_destroy(rcb_info->typeIdArr[j]); + } + + chk_free(rcb_info); + echo_warn1("Client RCB info 0x%X destroyed", rcb_info); +} +/************************************************************************/ +/* nvl_var_name_array_create */ +/* Send a GetNamedVariableListAttributes request to get a list of */ +/* variable names in a NamedVariableList (NVL). */ +/* Assume the NVL is domain-specific */ +/* RETURN: ptr to array of ptrs to variable names (OBJECT_NAME structs).*/ +/* Also the variable pointed to by numVarOut contains the number*/ +/* of variables in the NVL. */ +/* NOTE: this function allocates memory for the (OBJECT_NAME *) array. */ +/* Call "nvl_var_name_array_destroy" to free the memory. */ +/************************************************************************/ +static OBJECT_NAME** nvl_var_name_array_create(MVL_NET_INFO* net_info, ST_CHAR* domName, ST_CHAR* nvlName, + ST_INT* numVarOut, + ST_INT timeOut) +{ + MVL_REQ_PEND* reqCtrl; + GETVLIST_REQ_INFO getvlist_req; + GETVLIST_RESP_INFO* getvlist_resp; /* set to reqCtrl->u.getvlist_resp_info*/ + VARIABLE_LIST* variable_list; + OBJECT_NAME** varNameArray; /* Ptr to array of ptrs to var names */ + ST_RET ret; /* general purpose return code */ + ST_INT j; + + getvlist_req.vl_name.object_tag = DOM_SPEC; + getvlist_req.vl_name.domain_id = domName; + getvlist_req.vl_name.obj_name.vmd_spec = nvlName; + + ret = mvla_getvlist(net_info, &getvlist_req, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone(reqCtrl, timeOut); + if (ret != SD_SUCCESS) + { + echo_warn1("mvla_getvlist Error = 0x%X.", ret); + varNameArray = NULL; + } + else + { + getvlist_resp = reqCtrl->u.getvlist.resp_info; + variable_list = (VARIABLE_LIST*)(getvlist_resp + 1); + /* Allocate array of variable names. */ + *numVarOut = getvlist_resp->num_of_variables; + varNameArray = (OBJECT_NAME**)chk_malloc(getvlist_resp->num_of_variables * sizeof(OBJECT_NAME*)); + /* Copy info from response to allocated array */ + for (j = 0; j < getvlist_resp->num_of_variables; j++, variable_list++) + { + /* Assume all variables are named. */ + assert(variable_list->var_spec.var_spec_tag == VA_SPEC_NAMED); + varNameArray[j] = object_name_clone_create(&variable_list->var_spec.vs.name); + } + } + + mvl_free_req_ctrl(reqCtrl); /* CRITICAL: */ + return (varNameArray); +} +/************************************************************************/ +/* nvl_var_name_array_destroy */ +/* Free up all resources allocated by "nvl_var_name_array_create". */ +/************************************************************************/ +static ST_VOID nvl_var_name_array_destroy(OBJECT_NAME** varNameArray, ST_INT numVar) +{ + ST_INT j; + for (j = 0; j < numVar; j++) + object_name_clone_destroy(varNameArray[j]); + chk_free(varNameArray); +} + +/************************************************************************/ +/* var_type_create */ +/* Send GetVariableAccessAttributes request. Wait for response. When */ +/* response received, create new type. Pass NULL as type_name arg to */ +/* "mvl_type_id_create" (this avoids the problem of duplicate names). */ +/* RETURN: Type ID */ +/* NOTE: Call "mvl_type_id_destroy" to destroy the type created here. */ +/************************************************************************/ +static ST_INT var_type_create(MVL_NET_INFO* net_info, OBJECT_NAME* varObj, + ST_INT timeOut) +{ + MVL_REQ_PEND* reqCtrl; + GETVAR_REQ_INFO getvar_req; + VAR_ACC_TSPEC* type_spec; + ST_INT type_id = -1; /* invalid. If anything fails, this value returned*/ + ST_RET ret; + + getvar_req.req_tag = GETVAR_NAME; + getvar_req.name = *varObj; + + /* Send GetVariableAccessAttributes request & wait for response. */ + ret = mvla_getvar(net_info, &getvar_req, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone(reqCtrl, timeOut); + if (ret != SD_SUCCESS) + echo_warn1("GetVariableAccessAttributes error = 0x%x.", ret); + else + { + type_spec = &reqCtrl->u.getvar.resp_info->type_spec; + /* First arg (type_name) is NULL to avoid duplicate names. */ + type_id = mvl_type_id_create(NULL, type_spec->data, type_spec->len); + } + mvl_free_req_ctrl(reqCtrl); + return (type_id); +} + +/************************************************************************/ +/* rcb_info_var_create */ +/* Create dummy variables to be used later when a report is received. */ +/* These variables are needed to decode the data received in a report. */ +/* This function fills in "rcb_info->rcb_data" and "rcb_info->rcb_var". */ +/************************************************************************/ +static ST_RET rcb_info_var_create(RCB_INFO* rcb_info, RPT_TYPEIDS* rpt_typeids) +{ + OBJECT_NAME dummyvar_objname; /* dummy variable object name */ + ST_INT j; + ST_INT incSize; /* num bytes for inclusion bitstring */ + + /* CRITICAL: "mvl_var_create" is used (NOT "mvl_var_add") to create + * local variables to store data received later in IEC/UCA Reports. + * These are NOT real variables, so remote MMS nodes cannot access them. + * All variables use the same name (dummyvar): that's OK because + * "mvl_var_create" does NOT add them to the database and nothing needs + * to use the name. + */ + + /* NOTE: last arg to mvl_var_create is always SD_FALSE, so the name is + * NOT copied. This is OK because all names here are fixed strings. + */ + + /* Set up one OBJECT_NAME to use for all variables. */ + dummyvar_objname.object_tag = VMD_SPEC; + dummyvar_objname.obj_name.vmd_spec = "dummyvar"; /* all vars use same name */ + + if ((rcb_info->rcb_var.RptID = mvl_var_create(&dummyvar_objname, rpt_typeids->vstring65, + &rcb_info->rcb_data.RptID, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.OptFlds = mvl_var_create(&dummyvar_objname, rpt_typeids->bvstring10, + &rcb_info->rcb_data.OptFlds, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.SqNum = mvl_var_create(&dummyvar_objname, rpt_typeids->int16u, + &rcb_info->rcb_data.SqNum, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.TimeOfEntry = mvl_var_create(&dummyvar_objname, rpt_typeids->btime6, + &rcb_info->rcb_data.TimeOfEntry, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.DatSetNa = mvl_var_create(&dummyvar_objname, rpt_typeids->vstring65, + &rcb_info->rcb_data.DatSetNa, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.BufOvfl = mvl_var_create(&dummyvar_objname, rpt_typeids->mmsbool, + &rcb_info->rcb_data.BufOvfl, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.SubSeqNum = mvl_var_create(&dummyvar_objname, rpt_typeids->int16u, + &rcb_info->rcb_data.SubSeqNum, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.MoreSegmentsFollow = mvl_var_create(&dummyvar_objname, rpt_typeids->mmsbool, + &rcb_info->rcb_data.MoreSegmentsFollow, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.EntryID = mvl_var_create(&dummyvar_objname, rpt_typeids->ostring8, + &rcb_info->rcb_data.EntryID, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + if ((rcb_info->rcb_var.ConfRev = mvl_var_create(&dummyvar_objname, rpt_typeids->int32u, + &rcb_info->rcb_data.ConfRev, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + incSize = BSTR_NUMBITS_TO_NUMBYTES(rcb_info->numDsVar); + /* Note: rcb_info->rcb_data.Inclusion is a "ptr" to data, so don't add "&". */ + if ((rcb_info->rcb_var.Inclusion = mvl_var_create(&dummyvar_objname, rcb_info->InclusionTypeid, + rcb_info->rcb_data.Inclusion, NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + + /* Allocate array of DataRefName (vstring65) */ + /* & array of (MVL_VAR_ASSOC *). */ + /* Can't alloc array of strings, so we just allocate one big buffer */ + /* and use [j*66] to find postion for each string in the buffer. */ + /* Create separate variable for each array entry. */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + if ((rcb_info->rcb_var.dataRefName[j] = mvl_var_create(&dummyvar_objname, rpt_typeids->vstring65, + &rcb_info->rcb_data.dataRefName[j * 66], NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + } + + /* Create variable for each DataSet variable. */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + ST_VOID* remote_data; /* buffer to store remote data */ + MVL_TYPE_CTRL* type_ctrl; + + type_ctrl = mvl_type_ctrl_find(rcb_info->typeIdArr[j]); + assert(type_ctrl); /* find should never fail */ + /* Allocate buffer to store remote data. */ + remote_data = chk_malloc(type_ctrl->data_size); + + if ((rcb_info->rcb_var.dataValue[j] = mvl_var_create(&dummyvar_objname, + rcb_info->typeIdArr[j], /* Use type just created */ + remote_data, /* buffer for data */ + NULL, /* proc funs */ + SD_FALSE)) /* DON'T copy name */ + == NULL) + { /* couldn't create this variable, so stop */ + return (SD_FAILURE); + } + } + + /* Allocate array of Reason (bstr6)(one byte for each Reason) */ + /* & array of (MVL_VAR_ASSOC *). */ + /* Create separate variable for each array entry. */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + /* Use bvstring8 because IEC sends bstr6 and UCA sends bstr8. */ + if ((rcb_info->rcb_var.Reason[j] = mvl_var_create(&dummyvar_objname, rpt_typeids->bvstring8, + &rcb_info->rcb_data.Reason[j], NULL, SD_FALSE)) == NULL) + return (SD_FAILURE); + } + + /* If we get this far, everything was successful. */ + return (SD_SUCCESS); +} + +/************************************************************************/ +/* rcb_info_var_destroy */ +/* Destroy everything created in "rcb_info_var_create". */ +/* Check that each was successfully creating before destroying. Any one */ +/* of the "mvl_var_create" calls in "rcb_info_var_create" may have failed.*/ +/************************************************************************/ +static ST_VOID rcb_info_var_destroy(RCB_INFO* rcb_info) +{ + ST_INT j; + + if (rcb_info->rcb_var.RptID) + mvl_var_destroy(rcb_info->rcb_var.RptID); + + if (rcb_info->rcb_var.OptFlds) + mvl_var_destroy(rcb_info->rcb_var.OptFlds); + + if (rcb_info->rcb_var.SqNum) + mvl_var_destroy(rcb_info->rcb_var.SqNum); + + if (rcb_info->rcb_var.TimeOfEntry) + mvl_var_destroy(rcb_info->rcb_var.TimeOfEntry); + + if (rcb_info->rcb_var.DatSetNa) + mvl_var_destroy(rcb_info->rcb_var.DatSetNa); + + if (rcb_info->rcb_var.BufOvfl) + mvl_var_destroy(rcb_info->rcb_var.BufOvfl); + + if (rcb_info->rcb_var.SubSeqNum) + mvl_var_destroy(rcb_info->rcb_var.SubSeqNum); + + if (rcb_info->rcb_var.MoreSegmentsFollow) + mvl_var_destroy(rcb_info->rcb_var.MoreSegmentsFollow); + + if (rcb_info->rcb_var.EntryID) + mvl_var_destroy(rcb_info->rcb_var.EntryID); + + if (rcb_info->rcb_var.ConfRev) + mvl_var_destroy(rcb_info->rcb_var.ConfRev); + + if (rcb_info->rcb_var.Inclusion) + mvl_var_destroy(rcb_info->rcb_var.Inclusion); + + /* Destroy "dataRefName" variables. */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + if (rcb_info->rcb_var.dataRefName[j]) + mvl_var_destroy(rcb_info->rcb_var.dataRefName[j]); + } + + /* Destroy "dataValue" variables. */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + if (rcb_info->rcb_var.dataValue[j] != NULL) + { + chk_free(rcb_info->rcb_var.dataValue[j]->data); + mvl_var_destroy(rcb_info->rcb_var.dataValue[j]); + } + } + + /* Destroy "Reason" variables. */ + for (j = 0; j < rcb_info->numDsVar; j++) + { + if (rcb_info->rcb_var.Reason[j]) + mvl_var_destroy(rcb_info->rcb_var.Reason[j]); + } +} + +/************************************************************************/ +/* This sample function sets some options and enables the RCB. */ +/* If any write fails, stop. */ +/* If more options needed, add more arguments to this function. */ +/************************************************************************/ +ST_RET rcb_enable(MVL_NET_INFO* netInfo, ST_CHAR* domName, + ST_CHAR* rcbName, ST_UCHAR* OptFlds, ST_UCHAR* TrgOps, + ST_UINT32 IntgPd, RPT_TYPEIDS* rpt_typeids, ST_INT timeOut) +{ + ST_BOOLEAN RptEna = 1; /* 1 = enable the report */ + ST_RET ret = SD_SUCCESS; + ST_CHAR varName[MAX_IDENT_LEN + 1]; + + //if (ret == SD_SUCCESS) + //{ + // apr_snprintf (varName,sizeof(varName),"%s$IntgPd", rcbName); + // ret = mms_named_var_write (netInfo, varName, DOM_SPEC, domName, rpt_typeids->int32u, (ST_CHAR *) &IntgPd, timeOut); + //} + + if (ret == SD_SUCCESS) + { + /* NOTE: only write 9 bits. 10th bit (segmentation) is read-only. */ + apr_snprintf(varName, sizeof(varName), "%s$OptFlds", rcbName); + ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->bstr9, OptFlds, timeOut); + } + + if (ret == SD_SUCCESS) + { + apr_snprintf(varName, sizeof(varName), "%s$TrgOps", rcbName); + ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->bstr6, TrgOps, timeOut); + if (ret != SD_SUCCESS) { + printf("%s Write Error!!!", varName); + echo_warn1("Reportע %s Write Error!!!", varName); + } + } + +#if 0 /* Add something like this if other options needed. ???????? BufTm ??*/ + if (ret == SD_SUCCESS) + { + apr_snprintf(varName, sizeof(varName), "%s$Trgs", rcbName); + ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->int16u, (ST_CHAR*)&Trgs, timeOut); + } +#endif + + if (ret == SD_SUCCESS) + { + apr_snprintf(varName, sizeof(varName), "%s$RptEna", rcbName); + ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->mmsbool, (ST_CHAR*)&RptEna, timeOut); + } + + return (ret); +} + + +ST_RET rcb_disable(MVL_NET_INFO* netInfo, ST_CHAR* domName, + ST_CHAR* rcbName, RPT_TYPEIDS* rpt_typeids, ST_INT timeOut) +{ + ST_BOOLEAN RptEna = 0; /* 0 = disable the report */ + ST_UINT32 IntgPd = 0; + ST_RET ret = SD_SUCCESS; + ST_CHAR varName[MAX_IDENT_LEN + 1]; + + if (ret == SD_SUCCESS) + { + apr_snprintf(varName, sizeof(varName), "%s$RptEna", rcbName); + ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->mmsbool, (ST_CHAR*)&RptEna, timeOut); + } + + if (ret == SD_SUCCESS) + { + apr_snprintf(varName, sizeof(varName), "%s$IntgPd", rcbName); + ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->int32u, (ST_CHAR*)&IntgPd, timeOut); + } + return (ret); +} + +/************************************************************************/ +/************************************************************************/ +static ST_VOID log_var_data(MVL_VAR_ASSOC* var, MMS_DECODE_DATA* data) +{ + ST_CHAR tdl_buf[500]; /* increase size if complex TDL expected*/ + MVL_TYPE_CTRL* type_ctrl; + + type_ctrl = mvl_type_ctrl_find(var->type_id); + if (type_ctrl) + { + /* If the TDL produced is longer than max_tdl_len, this function */ + /* "gracefully" fails (i.e. returns 0). */ + if (ms_runtime_to_tdl(type_ctrl->rt, type_ctrl->num_rt, tdl_buf, sizeof(tdl_buf)) > 0) + ;//SLOGCALWAYS1 (" TYPE: %s", tdl_buf); + else + echo_warn(" TYPE: unknown"); + + //printf ("\nTYPE: %s \n", tdl_buf); + + //printf("type_ctrl->num_rt %d %x %x \n", type_ctrl->num_rt , &data, &(var->data)); + my_local_to_data((ST_CHAR*)var->data, type_ctrl->rt, type_ctrl->num_rt, data); + if (data->item_num == 0) { + echo_warn("!!!!!!!!!!!!!!!!!!!data num is 0 !!!!!!!!!!!!!!!!\n"); + } + + } + else + echo_warn(" ERR: type_id is invalid"); +} + + + +/************************************************************************/ +/* u_iec_rpt_ind_data */ +/* User function to process the received report data. This example */ +/* function simply writes the data to the log file. */ +/* */ +/* It should be easy to modify or rewrite this function to do whatever */ +/* is appropriate for your application. */ +/************************************************************************/ +ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, + ST_UINT8* OptFldsData, /* ptr to data part of OptFlds bvstring */ + ST_UINT8* InclusionData, /* ptr to Inclusion bstring */ + RCB_INFO* rcb_info, + ST_INT va_total, + MVL_NET_INFO* net_info) +{ + ST_INT va_num = 0; + ST_INT j; + MMS_DECODE_DATA mms_dec_data; + //uint32_t add_mms_dec_data = &mms_dec_data; + ied_t* ied; + rptinfo_t* rptinfo; + // element_t* pDataOMSObject; + LD_info_t* LD_info; + chnl_usr_t* chnl_usr; + char** DataObjectFullName; + // LD_info_t* LD_info_of_Data; + ST_INT not_set_rpt_TimeID_this; + ST_INT not_set_rpt_q_this; + + //printf("Var# %02d: RptId", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + rptinfo = find_rptinfo_from_net_rpt_info_name(net_info, rcb_info); + //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 ȥ + LD_info = rptinfo->LD_info; + chnl_usr = net_info->user_ext; + ied = chnl_usr->chnl->ied; + + not_set_rpt_TimeID_this = TRUE; + not_set_rpt_q_this = TRUE; + //g_db_inf_clear_data(RPT_IDX); + rptinfo->count++; + printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,count = %i \n", + chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); + + //apr_time_t previousTime = apr_time_now();// + //apr_time_exp_t localTime; + //apr_time_exp_gmt(&localTime, previousTime); + //printf("\n ------>>>>>>> begind time %d %d:%d:%d.%d \n", + // localTime.tm_mday, localTime.tm_hour, localTime.tm_min, localTime.tm_sec, localTime.tm_usec); + + va_num++; + // SLOGCALWAYS1("Var# %02d: OptFlds", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + + /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) + { + // SLOGCALWAYS1("Var# %02d: SqNum", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + printf("\n ------>>>>>>> SqNum received in Report From %s %s %s ,SqNum = %d \n", + chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, mms_dec_data.data_item[0].u.data_uint); + va_num++; + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) + { + // SLOGCALWAYS1("Var# %02d: TimeOfEntry", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + //set_rpt_TimeID(convert_btime6_to_apr_time(&(mms_dec_data.data_item[0].u.data_bTime6)) ); + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) + { + // SLOGCALWAYS1("Var# %02d: DatSetNa", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) + { + // SLOGCALWAYS1("Var# %02d: BufOvfl", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) + { + char* EntryIDStr; + int i; + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + EntryIDStr = mms_dec_data.data_item[0].u.data_str; + printf("\n ------>>>>>>> EntryID received in Report From %s %s %s ,EntryID = %s\n\n\n", + chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, EntryIDStr); + for (i = 0; i < 8; i++) { + EntryIDStr[2] = '\0'; + rptinfo->m_EntryID[i] = (byte_t)strtol(EntryIDStr, NULL, 16); + EntryIDStr += 3; //skip a blank + } + va_num++; + } + printf("\n -------------rptinfo->m_EntryID %02x %02x %02x %02x %02x %02x %02x %02x -------- EntryID\n\n\n", + *rptinfo->m_EntryID, *(rptinfo->m_EntryID + 1), *(rptinfo->m_EntryID + 2), + *(rptinfo->m_EntryID + 3), *(rptinfo->m_EntryID + 4), *(rptinfo->m_EntryID + 5), + *(rptinfo->m_EntryID + 6), *(rptinfo->m_EntryID + 7)); + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) + { + // SLOGCALWAYS1("Var# %02d: ConfRev", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + //printf("\n ----1--va_num %d -\n", va_num); + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) + { + // SLOGCALWAYS1("Var# %02d: SubSeqNum", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + // SLOGCALWAYS1("Var# %02d: MoreSegmentsFollow", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + //printf("\n ----2---va_num %d \n", va_num); + // SLOGCALWAYS1("Var# %02d: Inclusion", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + + /* If data-Ref enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) + { + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) + { + // SLOGCALWAYS2("Var# %02d: DataRefName# %d", va_num, j); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + } + } + //printf("\n ----3---%d \n", va_num); + //rcb_info->numDsVar+1 just to avoid rcb_info->numDsVar==0 ,waste a little memory + DataObjectFullName = apr_pcalloc(g_pt61850app->tmp_pool, (rcb_info->numDsVar + 1) * sizeof(char*)); + //RWCStringVec DataName(rcb_info->numDsVar+1); + //RWCStringVec AttrName(rcb_info->numDsVar+1); + //RWTValVector pDataOMSObjects(rcb_info->numDsVar+1); + //printf("\n ----4--%d rcb_info->numDsVar %d -\n", va_num, rcb_info->numDsVar); + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) + { + DataObjectFullName[j] = apr_pstrdup(g_pt61850app->tmp_pool, rcb_info->varNameArray[j]->obj_name.vmd_spec); + } + } + //printf("\n ----5--%d-\n", va_num); + // if (g_pt61850app->IsCallEvtDes ) + // cout<<"pEquipment->m_OMSObject_FULL_FCDA_Map.entries() = "<m_OMSObject_FULL_FCDA_Map.entries()<line_id > 0) { + if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + processQVVR_start(LD_info); + else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + processRDRE_start(LD_info); + else { + ied_t* ied; + ied = find_ied_from_dev_code(LD_info->terminal_code); + + ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; + + if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 ֻ͵һνŻʼ json_block_create_start(LD_info->line_id); + json_block_create_start( LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); + else if(rptinfo->flickerflag == 0) { + if (LD_info->rptRecvCheckFlag == 0) + json_block_create_start( LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); + LD_info->rptRecvCheckFlag |= 0x01 << rptinfo->rptNo; + } + else if (rptinfo->flickerflag == 2) { + if (LD_info->rptPstRecvCheckFlag == 0) + json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); + LD_info->rptPstRecvCheckFlag |= 0x01 << rptinfo->rptNo; + } + } + } + /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ + for (j = 0; j < rcb_info->numDsVar; ++j) + { + /*if (rcb_info->numDsVar==13) { + printf("bbbbbbbbbbbbbbbbbbbbbbbbb\n"); + }*/ + if (BSTR_BIT_GET(InclusionData, j)) + { + int ii; + // SLOGCALWAYS3("Var# %02d: DataSet Var# %d: Name=%s", va_num, j, + // rcb_info->varNameArray[j]->obj_name.vmd_spec); + //printf("\n ----5.0--%d-\n", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + //printf("\n ----5.1--%d-%d\n", va_num,mms_dec_data.item_num); + // if ( !pDataOMSObjects[j] ) continue; + + //cout<tmp_pool, DataObjectFullName[j]); + else + FULL_FCDA_Name = apr_pstrcat(g_pt61850app->tmp_pool, DataObjectFullName[j], "$", mms_dec_data.data_item[ii].comp_name, NULL); + // cout<<" FULL_FCDA_Name "<< FULL_FCDA_Name <RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + //need do nothing! + not_set_rpt_q_this = FALSE; + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + //need do nothing! + not_set_rpt_q_this = FALSE; + } + else { + json_block_create_flag(LD_info->mp_id, flag, rptinfo->flickerflag); + not_set_rpt_q_this = FALSE; + } + } + } + else if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { + if (not_set_rpt_TimeID_this) { + apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(FULL_FCDA_Name, "VarStr$t")) { + processQVVR_time(LD_info, t / 1000); + not_set_rpt_TimeID_this = FALSE; + } + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + //need do nothing! + not_set_rpt_TimeID_this = FALSE; + } + else { + json_block_create_time(LD_info->mp_id, t / 1000, rptinfo->flickerflag); + printf("rcb_info->RptID=%s ,LineId=%d , Timestamp= %lld \n", rcb_info->RptID, LD_info->line_id, t / 1000); + not_set_rpt_TimeID_this = FALSE; + if (strstr(rcb_info->RptID, "LLN0$RP$urcbRealData")) { + //20241223lnkն˺Ų + ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000)) + return; + } + } + } + } + else { + double v = 0.0; + if (mms_dec_data.data_item[ii].type == DATA_INT_TYPE) + v = mms_dec_data.data_item[ii].u.data_int; + else if (mms_dec_data.data_item[ii].type == DATA_UINT_TYPE) + v = mms_dec_data.data_item[ii].u.data_uint; + else if (mms_dec_data.data_item[ii].type == DATA_INT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_int64; + else if (mms_dec_data.data_item[ii].type == DATA_UINT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_uint64; + else if (mms_dec_data.data_item[ii].type == DATA_DOUBLE_TYPE) + v = mms_dec_data.data_item[ii].u.data_double; + else if (mms_dec_data.data_item[ii].type == DATA_STR_TYPE) + v = strtol(mms_dec_data.data_item[ii].u.data_str, NULL, 2); + + //set_db_value(RPT_IDX,FULL_FCDA_Name,v, is_rpt_Time_exact_hour() ); + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + processQVVR_data(LD_info, FULL_FCDA_Name, v); + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + processRDRE_data(LD_info, FULL_FCDA_Name, v); + } + else + json_block_create_data(LD_info->mp_id, FULL_FCDA_Name, v, rptinfo->flickerflag); + }//else + } + } + } + if (LD_info->line_id > 0) { + //set_rpt_LineID(LD_info->line_id); + //set_line_info(RPT_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); + //write_updatetime_to_db(chnl_usr->chnl->addr); + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + processQVVR_end(LD_info); + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + processRDRE_end(LD_info); + } + else { + printf("%d : %d", LD_info->rptRecvFlag, LD_info->rptRecvCheckFlag); + //append_db_records(RPT_IDX); + if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 ־ + { + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //int devkind = ied_usr->dev_flag; + json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); + } + else if(rptinfo->flickerflag == 0){//CZY 2023-08-17 WW 2022-11-14 Ӷж + if (LD_info->rptRecvFlag == LD_info->rptRecvCheckFlag) { + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //int devkind = ied_usr->dev_flag; + json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); + LD_info->rptRecvCheckFlag = 0; + } + } + else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 Ӷж + if (LD_info->rptPstRecvFlag == LD_info->rptPstRecvCheckFlag) { + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //int devkind = ied_usr->dev_flag; + json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); + LD_info->rptPstRecvCheckFlag = 0; + } + } + } + } + else { + echo_err3("Ignore this report due to line_id invalid , Report From %s %s %s !!!", + APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID); + } + printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,count = %i \n", + chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); + + //apr_time_t previousTimeend = apr_time_now();// + //apr_time_exp_t localTimeend; + //apr_time_exp_gmt(&localTimeend, previousTimeend); + //printf("\n ------>>>>>>> end time %d %d:%d:%d.%d \n", + // localTimeend.tm_mday, localTimeend.tm_hour, localTimeend.tm_min, localTimeend.tm_sec, localTimeend.tm_usec); + //printf("\n ----6-%d--\n", va_num); + /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) { + for (j = 0; j < rcb_info->numDsVar; ++j) { + if (BSTR_BIT_GET(InclusionData, j)) { + // SLOGCALWAYS2("Var# %02d: Reason# %d", va_num, j); + //log_var_data (info_va[va_num],&mms_dec_data); + va_num++; + } + } + } + + //Ӧʱ䣬Ƶٻװƣ¶ add on Aug 3 for testing of guangdong CRITICAL + chnl_usr->m_LastPosRespTime = sGetMsTime(); + + //assert (va_num==va_total); /* Did we count right? */ + if (va_num != va_total) + echo_err5("va_num!=va_total! Report From %s %s %s , %d!=%d !!!", + APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, va_num, va_total); +} +ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, + ST_UINT8* OptFldsData, /* ptr to data part of OptFlds bvstring */ + ST_UINT8* InclusionData, /* ptr to Inclusion bstring */ + RCB_INFO* rcb_info, + ST_INT va_total, + MVL_NET_INFO* net_info) +{ + ST_INT va_num = 0; + ST_INT j; + MMS_DECODE_DATA mms_dec_data; + //uint32_t add_mms_dec_data = &mms_dec_data; + ied_t* ied; + rptinfo_t* rptinfo; + // element_t* pDataOMSObject; + LD_info_t* LD_info; + chnl_usr_t* chnl_usr; + char** DataObjectFullName; + // LD_info_t* LD_info_of_Data; + ST_INT not_set_rpt_TimeID_this; + ST_INT not_set_rpt_q_this; + + //printf("Var# %02d: RptId", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + rptinfo = find_rptinfo_from_net_rcb_info(net_info, rcb_info); + //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 ȥ + LD_info = rptinfo->LD_info; + chnl_usr = net_info->user_ext; + ied = chnl_usr->chnl->ied; + + not_set_rpt_TimeID_this = TRUE; + not_set_rpt_q_this = TRUE; + //g_db_inf_clear_data(RPT_IDX); + rptinfo->count++; + printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,count = %i mp_id=%s\n", + chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count, LD_info->mp_id); + + //apr_time_t previousTime = apr_time_now();// + //apr_time_exp_t localTime; + //apr_time_exp_gmt(&localTime, previousTime); + //printf("\n ------>>>>>>> begind time %d %d:%d:%d.%d \n", + // localTime.tm_mday, localTime.tm_hour, localTime.tm_min, localTime.tm_sec, localTime.tm_usec); + + va_num++; + // SLOGCALWAYS1("Var# %02d: OptFlds", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + + /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) + { + // SLOGCALWAYS1("Var# %02d: SqNum", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + printf("\n ------>>>>>>> SqNum received in Report From %s %s %s ,SqNum = %d \n", + chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, mms_dec_data.data_item[0].u.data_uint); + va_num++; + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) + { + // SLOGCALWAYS1("Var# %02d: TimeOfEntry", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + //set_rpt_TimeID(convert_btime6_to_apr_time(&(mms_dec_data.data_item[0].u.data_bTime6)) ); + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) + { + // SLOGCALWAYS1("Var# %02d: DatSetNa", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) + { + // SLOGCALWAYS1("Var# %02d: BufOvfl", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) + { + char* EntryIDStr; + int i; + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + EntryIDStr = mms_dec_data.data_item[0].u.data_str; + printf("\n ------>>>>>>> EntryID received in Report From %s %s %s ,EntryID = %s\n\n\n", + chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, EntryIDStr); + for (i = 0; i < 8; i++) { + EntryIDStr[2] = '\0'; + rptinfo->m_EntryID[i] = (byte_t)strtol(EntryIDStr, NULL, 16); + EntryIDStr += 3; //skip a blank + } + va_num++; + } + printf("\n -------------rptinfo->m_EntryID %02x %02x %02x %02x %02x %02x %02x %02x -------- EntryID\n\n\n", + *rptinfo->m_EntryID, *(rptinfo->m_EntryID + 1), *(rptinfo->m_EntryID + 2), + *(rptinfo->m_EntryID + 3), *(rptinfo->m_EntryID + 4), *(rptinfo->m_EntryID + 5), + *(rptinfo->m_EntryID + 6), *(rptinfo->m_EntryID + 7)); + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) + { + // SLOGCALWAYS1("Var# %02d: ConfRev", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + //printf("\n ----1--va_num %d -\n", va_num); + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) + { + // SLOGCALWAYS1("Var# %02d: SubSeqNum", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + // SLOGCALWAYS1("Var# %02d: MoreSegmentsFollow", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + //printf("\n ----2---va_num %d \n", va_num); + // SLOGCALWAYS1("Var# %02d: Inclusion", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + + /* If data-Ref enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) + { + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) + { + // SLOGCALWAYS2("Var# %02d: DataRefName# %d", va_num, j); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + } + } + } + //printf("\n ----3---%d \n", va_num); + //rcb_info->numDsVar+1 just to avoid rcb_info->numDsVar==0 ,waste a little memory + DataObjectFullName = apr_pcalloc(g_pt61850app->tmp_pool, (rcb_info->numDsVar + 1) * sizeof(char*)); + //RWCStringVec DataName(rcb_info->numDsVar+1); + //RWCStringVec AttrName(rcb_info->numDsVar+1); + //RWTValVector pDataOMSObjects(rcb_info->numDsVar+1); + //printf("\n ----4--%d rcb_info->numDsVar %d -\n", va_num, rcb_info->numDsVar); + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) + { + DataObjectFullName[j] = apr_pstrdup(g_pt61850app->tmp_pool, rcb_info->varNameArray[j]->obj_name.vmd_spec); + } + } + //printf("\n ----5--%d-\n", va_num); + // if (g_pt61850app->IsCallEvtDes ) + // cout<<"pEquipment->m_OMSObject_FULL_FCDA_Map.entries() = "<m_OMSObject_FULL_FCDA_Map.entries()<line_id > 0) { + if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + processQVVR_start(LD_info);//͵ıļ + else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + processRDRE_start(LD_info); + else { + ied_t* ied; + + ied = find_ied_from_dev_code(LD_info->terminal_code); + + ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; + if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 ֻ͵һνŻʼ json_block_create_start(LD_info->line_id); + json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); + else if (rptinfo->flickerflag == 0) { + if (LD_info->rptRecvCheckFlag == 0) + json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); + LD_info->rptRecvCheckFlag |= 0x01 << rptinfo->rptNo; + } + else if (rptinfo->flickerflag == 2) { + if (LD_info->rptPstRecvCheckFlag == 0) + json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); + LD_info->rptPstRecvCheckFlag |= 0x01 << rptinfo->rptNo; + } + } + } + /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ + for (j = 0; j < rcb_info->numDsVar; ++j) + { + /*if (rcb_info->numDsVar==13) { + printf("bbbbbbbbbbbbbbbbbbbbbbbbb\n"); + }*/ + if (BSTR_BIT_GET(InclusionData, j)) + { + int ii; + // SLOGCALWAYS3("Var# %02d: DataSet Var# %d: Name=%s", va_num, j, + // rcb_info->varNameArray[j]->obj_name.vmd_spec); + //printf("\n ----5.0--%d-\n", va_num); + log_var_data(info_va[va_num], &mms_dec_data); + //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); + va_num++; + //printf("\n ----5.1--%d-%d\n", va_num,mms_dec_data.item_num); + // if ( !pDataOMSObjects[j] ) continue; + + //cout<tmp_pool, DataObjectFullName[j]); + else + FULL_FCDA_Name = apr_pstrcat(g_pt61850app->tmp_pool, DataObjectFullName[j], "$", mms_dec_data.data_item[ii].comp_name, NULL); + length_FCDA = strlen(FULL_FCDA_Name); + if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) + { + apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); + time = t / 1000; + break; + } + } + for (ii = 0; ii < mms_dec_data.item_num; ++ii)//FCDA + { + char* FULL_FCDA_Name; + int length_FCDA; + + //printf("\n ----5.11--%d-%s\n", va_num, mms_dec_data.data_item[ii].comp_name); + if (strcmp(mms_dec_data.data_item[ii].comp_name, "") == 0) + FULL_FCDA_Name = apr_pstrdup(g_pt61850app->tmp_pool, DataObjectFullName[j]); + else + FULL_FCDA_Name = apr_pstrcat(g_pt61850app->tmp_pool, DataObjectFullName[j], "$", mms_dec_data.data_item[ii].comp_name, NULL); + // cout<<" FULL_FCDA_Name "<< FULL_FCDA_Name <RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + //need do nothing! + not_set_rpt_q_this = FALSE; + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + //need do nothing! + not_set_rpt_q_this = FALSE; + } + else if (strstr(FULL_FCDA_Name, "GGIO")) + { + not_set_rpt_q_this = FALSE; + } + else { + json_block_create_flag(LD_info->mp_id, flag, rptinfo->flickerflag); + not_set_rpt_q_this = FALSE; + } + } + } + else if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { + if (not_set_rpt_TimeID_this) { + apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + if (strstr(FULL_FCDA_Name, "VarStr$t")) { + processQVVR_time(LD_info, t / 1000); + not_set_rpt_TimeID_this = FALSE; + } + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + //need do nothing! + not_set_rpt_TimeID_this = FALSE; + } + else if (strstr(FULL_FCDA_Name, "GGIO")) {//CZY 2023-08-17 WW 2022-11-14޸ж LLN0$BR$brcbRDRE + //need do nothing! + not_set_rpt_TimeID_this = FALSE; + } + else { + json_block_create_time(LD_info->mp_id, t / 1000, rptinfo->flickerflag); + printf("rcb_info->RptID=%s ,LineId=%d , Timestamp= %lld \n", rcb_info->RptID, LD_info->line_id, t / 1000); + not_set_rpt_TimeID_this = FALSE; + if (strstr(rcb_info->RptID, "LLN0$RP$urcbRealData")) { + //20241223lnkն˺Ų + ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000))//жʱظ + return; + } + } + } + } + else { + double v = 0.0; + if (mms_dec_data.data_item[ii].type == DATA_INT_TYPE) + v = mms_dec_data.data_item[ii].u.data_int; + else if (mms_dec_data.data_item[ii].type == DATA_UINT_TYPE) + v = mms_dec_data.data_item[ii].u.data_uint; + else if (mms_dec_data.data_item[ii].type == DATA_INT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_int64; + else if (mms_dec_data.data_item[ii].type == DATA_UINT64_TYPE) + v = (double)mms_dec_data.data_item[ii].u.data_uint64; + else if (mms_dec_data.data_item[ii].type == DATA_DOUBLE_TYPE) + v = mms_dec_data.data_item[ii].u.data_double; + else if (mms_dec_data.data_item[ii].type == DATA_STR_TYPE) + v = strtol(mms_dec_data.data_item[ii].u.data_str, NULL, 2); + + //set_db_value(RPT_IDX,FULL_FCDA_Name,v, is_rpt_Time_exact_hour() ); + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + processQVVR_data(LD_info, FULL_FCDA_Name, v); + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + processRDRE_data(LD_info, FULL_FCDA_Name, v); + } + else if (strstr(FULL_FCDA_Name, "GGIO")) + { + ied_t* ied = LD_info->ied; + ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); + processGGIO_start_data_end(LD_info->mp_id, FULL_FCDA_Name, v, time, ied_usr->dev_type, LD_info->line_id);//GGIOȫ״ + } + else + json_block_create_data(LD_info->mp_id, FULL_FCDA_Name, v, rptinfo->flickerflag); + }//else + } + + } + } + if (LD_info->line_id > 0) { + //set_rpt_LineID(LD_info->line_id); + //set_line_info(RPT_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); + //write_updatetime_to_db(chnl_usr->chnl->addr); + if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbQVVR + processQVVR_end(LD_info); + } + else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 ޸жLLN0$BR$brcbRDRE + processRDRE_end(LD_info); + } + else { + printf("%d : %d", LD_info->rptRecvFlag, LD_info->rptRecvCheckFlag); + //append_db_records(RPT_IDX); + if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 ־ + { + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //int devkind = ied_usr->dev_flag; + json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); + } + else if (rptinfo->flickerflag == 0) {//CZY 2023-08-17 WW 2022-11-14 Ӷж + if (LD_info->rptRecvFlag == LD_info->rptRecvCheckFlag) { + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //int devkind = ied_usr->dev_flag; + json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); + LD_info->rptRecvCheckFlag = 0; + } + } + else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 Ӷж + if (LD_info->rptPstRecvFlag == LD_info->rptPstRecvCheckFlag) { + //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 202212614:09:08 ӶICD֧ + //int devkind = ied_usr->dev_flag; + json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); + LD_info->rptPstRecvCheckFlag = 0; + } + } + } + } + else { + echo_err3("Ignore this report due to line_id invalid , Report From %s %s %s !!!", + APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID); + } + printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,count = %i \n", + chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); + + //apr_time_t previousTimeend = apr_time_now();// + //apr_time_exp_t localTimeend; + //apr_time_exp_gmt(&localTimeend, previousTimeend); + //printf("\n ------>>>>>>> end time %d %d:%d:%d.%d \n", + // localTimeend.tm_mday, localTimeend.tm_hour, localTimeend.tm_min, localTimeend.tm_sec, localTimeend.tm_usec); + + //printf("\n ----6-%d--\n", va_num); + /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) { + for (j = 0; j < rcb_info->numDsVar; ++j) { + if (BSTR_BIT_GET(InclusionData, j)) { + // SLOGCALWAYS2("Var# %02d: Reason# %d", va_num, j); + //log_var_data (info_va[va_num],&mms_dec_data); + va_num++; + } + } + } + //Ӧʱ䣬Ƶٻװƣ¶ add on Aug 3 for testing of guangdong CRITICAL + chnl_usr->m_LastPosRespTime = sGetMsTime(); + //assert (va_num==va_total); /* Did we count right? */ + if (va_num != va_total) + echo_err5("va_num!=va_total! Report From %s %s %s , %d!=%d !!!", + APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, va_num, va_total); +} +/************************************************************************/ +/* object_name_clone_create */ +/* Create clone of OBJECT_NAME struct. Can't just copy struct because */ +/* struct contains pointers to strings. */ +/* The function "object_name_clone_destroy" should be called to destroy */ +/* the clone. */ +/************************************************************************/ +OBJECT_NAME* object_name_clone_create(OBJECT_NAME* srcobj) +{ + OBJECT_NAME* dstobj; + size_t extended_size; + ST_CHAR* extended_ptr; + + /* Allocate OBJECT_NAME structure plus extra room for additional data. + * This effectively combines 3 allocations into one. + * Set pointers in OBJECT_NAME structure to point into the extra space. + */ + extended_size = sizeof(OBJECT_NAME) + + MAX_IDENT_LEN + 1 /* dstobj->obj_name.vmd_spec */ + + MAX_IDENT_LEN + 1; /* dstobj->domain_id */ + + dstobj = (OBJECT_NAME*)chk_malloc(extended_size); + + /* Copy old struct to new struct (before setting ptrs in new struct). */ + memcpy(dstobj, srcobj, sizeof(OBJECT_NAME)); + + /* Fix ptrs to strings in new struct */ + extended_ptr = (ST_CHAR*)(dstobj + 1); /* point after dstobj struct */ + + dstobj->obj_name.vmd_spec = extended_ptr; + extended_ptr += (MAX_IDENT_LEN + 1); /* point after dstobj->obj_name.vmd_spec*/ + + dstobj->domain_id = extended_ptr; + + /* Copy strings to the new struct. */ + strcpy(dstobj->obj_name.vmd_spec, srcobj->obj_name.vmd_spec); + if (dstobj->object_tag == DOM_SPEC) + strcpy(dstobj->domain_id, srcobj->domain_id); + return (dstobj); +} + +/************************************************************************/ +/* object_name_clone_destroy */ +/* Destroy OBJECT_NAME clone created by "object_name_clone_create". */ +/************************************************************************/ +ST_VOID object_name_clone_destroy(OBJECT_NAME* obj) +{ + /* allocated by object_name_clone_create using chk_malloc, so use chk_free.*/ + chk_free(obj); +} + +ST_RET check_va_count_too_big(ST_INT va_current_count, ST_INT va_total) +{ + if (va_current_count < va_total) { + return SD_SUCCESS; + } + else { + echo_warn1("report va total %d is so small,may be error\n", va_total); + return SD_FAILURE; + } +} + +/************************************************************************/ +/* u_iec_rpt_ind */ +/* This function processes ONLY IEC-61850 and UCA Reports. If any */ +/* other InformationReport is received, it logs an error message and */ +/* ignores it. */ +/* CRITICAL: this function assumes that a pointer to an ALL_RCB_INFO */ +/* structure has been saved in the */ +/* user_info member of the MVL_NET_INFO structure for this conn. */ +/************************************************************************/ +ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT* event) +{ + INFO_REQ_INFO* info_ptr; + ST_INT j, va_num, va_total; + VAR_ACC_SPEC* va_spec; + MVL_VAR_ASSOC** info_va; + RCB_INFO* rcb_info; + ST_UINT8* OptFldsData; /* ptr to data part of OptFlds bvstring */ + ST_UINT8* InclusionData; /* ptr to Inclusion bstring */ + ST_CHAR saveRptID[66]; + ALL_RCB_INFO* all_rcb_info; + ST_RET retcode = SD_SUCCESS; + + info_ptr = (INFO_REQ_INFO*)event->u.mms.dec_rslt.data_ptr; + va_spec = &info_ptr->va_spec; + va_total = info_ptr->num_of_acc_result; + + /* An IEC-61850 or UCA report must be a NamedVariableList named "RPT". + * Ignore any other InformationReport. + */ + if (va_spec->var_acc_tag != VAR_ACC_NAMEDLIST + || strcmp(va_spec->vl_name.obj_name.vmd_spec, "RPT") != 0) + { + echo_warn("Received InformationReport is not a IEC-61850 Report or UCA Report. Ignored."); + return (SD_FAILURE); + } + ////////////////// + //WW 2023-08-29 ն뱨rcb_info󶨴 + int port; //˿ + + RCB_INFO *rcb_info1; + ST_CHAR rptID[MVL61850_MAX_RPTID_LEN + 1] = { 0 }; //ID 66 + ST_ULONG a_ip = get_rem_ip_addr_inline(event->net_info->acse_conn_id, &port); //WW 2023-08-29 ȡװIP˿ں + ST_CHAR *p_ip = _convert_ip_2_char(htonl(a_ip)); //WW 2023-08-29 IPתΪַָ 192.168.1.238 + if (gDev_rcb_list.dev_rcb_info_Head == NULL) //ȫֱƿָ || gDev_rcb_list->rcb_info_list == NULL + { + //SLOGALWAYS0 ("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); + //LOG_INFO("յ棬δIEC-61850UCA RCBʹܡԣ"); //ʹã zl 2019-1-23 09:10:39 + return (SD_FAILURE); + } + //߼װIP˿ںţҵװͣƥ䱨Ϣٽ棡2019-12-24 17:27:29 +//װͲж------------------------------------------------------------------------------------------------------------------------------ + Dev_RCB_INFO *dev_rcb = NULL;//װñṹָ + Dev_IP_Port_INFO *dev_info = NULL; //װIP˿ںŽṹָ + ST_BOOLEAN bFindIpPort = 0; //Ƿƥ䵽װIP˿ں + for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //ٱ ȫװñƿ + { + //LOG_INFO("()gDev_rcb_list, dev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:16:31 + //װIP˿ںŲж------------------------------------------------------------------------------------------------------------------------------------------------------------------- + for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //ڱ ȫװIP˿ + { + //LOG_INFO("()dev_ip_port_list, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:16:31 + if ((strcmp(dev_info->IP, p_ip) == 0) && (dev_info->Port == port)) //ƥ װIP && ˿ں + { + bFindIpPort = 1; //ҵװIP && ˿ں + //LOG_INFO("()ƥ䵽װdev_type_name= %s, IP= %sPort= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 + //strcpy(dev_rcb->dev_type_name, dev_rcb->dev_type_name); //ƥ װ + break; + } + } // װIP˿ + if (bFindIpPort) //ƥ䵽װIP˿ں + break; + } // ȫװñƿ + + if (!bFindIpPort) //δҵװIP˿ + { + //LOG_INFO("()dev_type_name= %sδƥ䵽IP= %sPort= %dװͣgoto CLEANUP", dev_rcb->dev_type_name, p_ip, port); //ʹã zl 2019-12-24 00:23:55 + retcode = SD_FAILURE; + goto END; //ת CLEANUPretcode + } + + rcb_info = dev_rcb->rcb_info_list; //װͣƥ䱨ƿϢ + //WW 2023-08-29 end + ////////////////////////////// + + + /* Get "all_rcb_info" from "user_info". User must set "user_info" when conn established.*/ + ////////////////////// + //WW 2023-08-29ע + //all_rcb_info = (ALL_RCB_INFO*)event->net_info->user_info; + + ///* Check "all_rcb_info" to see if any RCB has been enabled. */ + //if (all_rcb_info == NULL || all_rcb_info->rcb_info_list == NULL) + //{ + // echo_warn("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); + // return (SD_FAILURE); + //} + //WW 2023-08-29 end + //////////////////////// + /* Create array of (MVL_VAR_ASSOC *) needed for converting the received + * data to local format. + * Use variables created earlier to fill in the array. These variables will + * hold the decoded data. + * NOTE: any return after this must free info_va (see CLEANUP label). + */ + info_va = (MVL_VAR_ASSOC**)chk_calloc(va_total, + sizeof(MVL_VAR_ASSOC*)); + + ////////////////// +//WW 2023-08-29 ն뱨rcb_info󶨴 + rcb_info = dev_rcb->rcb_info_list; //װͣƥ䱨ƿϢ + va_num = 0; + info_va[va_num++] = rcb_info->rcb_var.RptID; + //LOG_INFO("va_num = %d", va_num); //ʹã zl 2019-1-23 09:10:39 + + all_rcb_info = (ALL_RCB_INFO*)chk_calloc(1, sizeof(ALL_RCB_INFO)); + all_rcb_info->rpt_typeids = &g_rpt_typeids; + all_rcb_info->rcb_info_list = dev_rcb->rcb_info_list; + event->net_info->user_info = all_rcb_info; + rcb_info = all_rcb_info->rcb_info_list; + rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ + mvl_info_data_to_local(event, va_num, info_va); //תΪظʽ + /* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ + strcpy(saveRptID, rcb_info->rcb_data.RptID); //װͱID PQM2/LLN0$BR$brcbStatisticData01 + //LOG_INFO("װͱsaveRptID%s", saveRptID); //ʹã zl 2019-1-23 09:10:39 + chk_free(all_rcb_info); + event->net_info->user_info = NULL; + /* Search list of "rcb_info" to find one with matching RptID. If not found, rcb_info will be == NULL. */ + //װñƿж----------------------------------------------------------------------------------------------------------------------------------------------------- + for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) // ȫֱƿ + { + //LOG_INFO("ƿRptID%ssaveRptID%s", rcb_info->RptID, saveRptID); //ʹã zl 2019-1-23 09:10:39 + if (strcmp(rcb_info->RptID, saveRptID) == 0) + break; /* rcb_info now points to right structure */ + } + + if (!rcb_info) //ƿָΪգ + { + //SLOGALWAYS1 ("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); + //LOG_INFO("()ƿҲRptID= '%s'goto CLEANUP", saveRptID); //ʹã zl 2019-12-23 15:09:36 + retcode = SD_FAILURE; + goto CLEANUP; //ת CLEANUPretcode + } +//WW 2023-08-29 end +////////////////////////////// + ////////////////////// + //WW 2023-08-29ע + ///* Must decode the RptID first to find the correct RCB_INFO. Could decode into + //* any "vstring65" variable. We just use the RptID variable from the first + //* rcb_info on the list. + //*/ + //rcb_info = all_rcb_info->rcb_info_list; /* use first rcb_info on list*/ + //va_num = 0; + //info_va[va_num++] = rcb_info->rcb_var.RptID; + + //rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ + //mvl_info_data_to_local(event, va_num, info_va); + ///* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ + //strcpy(saveRptID, rcb_info->rcb_data.RptID); + + ///* Search list of "rcb_info" to find one with matching RptID. */ + ///* If not found, rcb_info will be == NULL. */ + //for (rcb_info = all_rcb_info->rcb_info_list; + // rcb_info != NULL; + // rcb_info = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info)) + //{ + // if (strcmp(rcb_info->RptID, saveRptID) == 0) + // break; /* rcb_info now points to right structure */ + //} + + //if (!rcb_info) + //{ + // echo_warn1("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); + // retcode = SD_FAILURE; + // goto CLEANUP; + //} + + //WW 2023-08-29 end + //////////////////////// + va_num = 0; + info_va[va_num++] = rcb_info->rcb_var.RptID; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + info_va[va_num++] = rcb_info->rcb_var.OptFlds; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + /* Perform 1st decode (up through "OptFlds"). Need "OptFlds" to figure + * out what comes next. + */ + mvl_info_data_to_local(event, va_num, info_va); + + /* Examine "OptFlds", and set up 2nd decode to decode all options */ + OptFldsData = rcb_info->rcb_data.OptFlds.data_1; /* use local var */ + // printf ("OptFlds = 0x%02x 0x%02x\n", OptFldsData[0],OptFldsData[1]); /* 9 bit bstr (2 bytes) */ + + /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) + info_va[va_num++] = rcb_info->rcb_var.SqNum; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) + info_va[va_num++] = rcb_info->rcb_var.TimeOfEntry; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) + { + info_va[va_num++] = rcb_info->rcb_var.DatSetNa; + /////////////////// + //WW 2023-08-29 + + log_var_to_data(rcb_info->rcb_var.DatSetNa, rptID); + //for (rcb_info1 = all_rcb_info->rcb_info_list; + // rcb_info1 != NULL; + // rcb_info1 = (RCB_INFO *) list_get_next (all_rcb_info->rcb_info_list, rcb_info1)) // װñƿ + for (rcb_info1 = dev_rcb->rcb_info_list; + rcb_info1 != NULL; + rcb_info1 = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info1)) // ƿ + { + if (strcmp(rcb_info1->ds_Nam, rptID) == 0) //IDΪͬΨһʶ + { + //SLOGALWAYS3 ("Num of var received in RPT (%d) does not match expected (%d)dateSet=%s ", va_total, va_num,rptID); + //LOG_INFO("()ձRptID= '%s'ݼrptID= %sС(%d)ԤڴС(%d)ƥ䣬brak", saveRptID, rptID, va_total, va_num); //ʹã zl 2019-12-23 15:09:30 + rcb_info = rcb_info1; + break; + } + } + //WW 2023-08-29 en + /////////////////////////// + } + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + /* The following optional vars are supported by IEC-61850 but they are + * NOT supported by UCA. This client must NOT set these OptFlds bits + * when connected to a UCA server, and these variables will NOT be + * included in a report received from a UCA server. + */ + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) + info_va[va_num++] = rcb_info->rcb_var.BufOvfl; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) + info_va[va_num++] = rcb_info->rcb_var.EntryID; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) + info_va[va_num++] = rcb_info->rcb_var.ConfRev; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) + { + info_va[va_num++] = rcb_info->rcb_var.SubSeqNum; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + info_va[va_num++] = rcb_info->rcb_var.MoreSegmentsFollow; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + } + info_va[va_num++] = rcb_info->rcb_var.Inclusion; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + assert(va_num < va_total); + + /* Perform 2nd decode (up through "Inclusion"). */ + mvl_info_data_to_local(event, va_num, info_va); + + /* Examine "Inclusion", and set up 3rd decode to decode all data. */ + InclusionData = rcb_info->rcb_data.Inclusion; /* use local var */ + // printf ("\nThe 1st byte Inclusion = 0x%02X\n", InclusionData[0]); /* Just print 1st byte */ + + /* NOTE: Don't change initial entries in "info_va". Add these right after "Inclusion".*/ + + /* If "data-Ref" enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) + { + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) { + info_va[va_num++] = rcb_info->rcb_var.dataRefName[j]; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + } + } + } + + /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) { + info_va[va_num++] = rcb_info->rcb_var.dataValue[j]; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + } + } + + /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) + { + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) { + info_va[va_num++] = rcb_info->rcb_var.Reason[j]; + } + } + } + + /* Does num of variables received match expected num.*/ + if (va_num != va_total) + { + echo_warn2("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring", va_total, va_num); + // printf ("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring\n", va_total, va_num); + } + else + { + /* Perform 3rd decode (everything). */ + mvl_info_data_to_local(event, va_num, info_va); + + u_iec_rpt_ind_data_by_devtype(info_va, OptFldsData, InclusionData, rcb_info, va_total, event->net_info); + } + +CLEANUP: + chk_free(info_va); +END: + return (retcode); +} + +ST_RET u_iec_rpt_ind(MVL_COMM_EVENT* event) +{ + INFO_REQ_INFO* info_ptr; + ST_INT j, va_num, va_total; + VAR_ACC_SPEC* va_spec; + MVL_VAR_ASSOC** info_va; + RCB_INFO* rcb_info, * rcb_info1; + ST_UINT8* OptFldsData; /* ptr to data part of OptFlds bvstring */ + ST_UINT8* InclusionData; /* ptr to Inclusion bstring */ + ST_CHAR saveRptID[66]; + ALL_RCB_INFO* all_rcb_info; + ST_RET retcode = SD_SUCCESS; + + info_ptr = (INFO_REQ_INFO*)event->u.mms.dec_rslt.data_ptr; + va_spec = &info_ptr->va_spec; + va_total = info_ptr->num_of_acc_result; + + /* An IEC-61850 or UCA report must be a NamedVariableList named "RPT". + * Ignore any other InformationReport. + */ + if (va_spec->var_acc_tag != VAR_ACC_NAMEDLIST + || strcmp(va_spec->vl_name.obj_name.vmd_spec, "RPT") != 0) + { + echo_warn("Received InformationReport is not a IEC-61850 Report or UCA Report. Ignored."); + return (SD_FAILURE); + } + + /* Get "all_rcb_info" from "user_info". User must set "user_info" when conn established.*/ + all_rcb_info = (ALL_RCB_INFO*)event->net_info->user_info; + + /* Check "all_rcb_info" to see if any RCB has been enabled. */ + if (all_rcb_info == NULL || all_rcb_info->rcb_info_list == NULL) + { + echo_warn("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); + return (SD_FAILURE); + } + + /* Create array of (MVL_VAR_ASSOC *) needed for converting the received + * data to local format. + * Use variables created earlier to fill in the array. These variables will + * hold the decoded data. + * NOTE: any return after this must free info_va (see CLEANUP label). + */ + info_va = (MVL_VAR_ASSOC**)chk_calloc(va_total, + sizeof(MVL_VAR_ASSOC*)); + + /* Must decode the RptID first to find the correct RCB_INFO. Could decode into + * any "vstring65" variable. We just use the RptID variable from the first + * rcb_info on the list. + */ + rcb_info = all_rcb_info->rcb_info_list; /* use first rcb_info on list*/ + va_num = 0; + info_va[va_num++] = rcb_info->rcb_var.RptID; + + rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ + mvl_info_data_to_local(event, va_num, info_va); + /* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ + strcpy(saveRptID, rcb_info->rcb_data.RptID); + + /* Search list of "rcb_info" to find one with matching RptID. */ + /* If not found, rcb_info will be == NULL. */ + for (rcb_info = all_rcb_info->rcb_info_list; + rcb_info != NULL; + rcb_info = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info)) + { + if (strcmp(rcb_info->RptID, saveRptID) == 0) + break; /* rcb_info now points to right structure */ + } + + if (!rcb_info) + { + echo_warn1("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); + retcode = SD_FAILURE; + goto CLEANUP; + } + + va_num = 0; + info_va[va_num++] = rcb_info->rcb_var.RptID; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + info_va[va_num++] = rcb_info->rcb_var.OptFlds; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + /* Perform 1st decode (up through "OptFlds"). Need "OptFlds" to figure + * out what comes next. + */ + mvl_info_data_to_local(event, va_num, info_va); + + /* Examine "OptFlds", and set up 2nd decode to decode all options */ + OptFldsData = rcb_info->rcb_data.OptFlds.data_1; /* use local var */ + // printf ("OptFlds = 0x%02x 0x%02x\n", OptFldsData[0],OptFldsData[1]); /* 9 bit bstr (2 bytes) */ + + /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) + info_va[va_num++] = rcb_info->rcb_var.SqNum; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) + info_va[va_num++] = rcb_info->rcb_var.TimeOfEntry; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + + //WW 2024-09-02 ݼȷ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) + info_va[va_num++] = rcb_info->rcb_var.DatSetNa; + + mvl_info_data_to_local(event, va_num, info_va); + //WW 2024-09-02 endss + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) + { + //info_va[va_num++] = rcb_info->rcb_var.DatSetNa; //WW 2024-09-02 ע + /////////////////// + //WW 2023-08-29 + log_var_to_data(rcb_info->rcb_var.DatSetNa, saveRptID); + for (rcb_info1 = all_rcb_info->rcb_info_list; + rcb_info1 != NULL; + rcb_info1 = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info1)) // ƿ + { + if (strcmp(rcb_info1->ds_Nam, saveRptID) == 0) //IDΪͬΨһʶ + { + printf("ds_name '%s' ! Recive name %s WWTest \n", rcb_info1->ds_Nam, saveRptID); + //SLOGALWAYS3 ("Num of var received in RPT (%d) does not match expected (%d)dateSet=%s ", va_total, va_num,rptID); + //LOG_INFO("()ձRptID= '%s'ݼrptID= %sС(%d)ԤڴС(%d)ƥ䣬brak", saveRptID, rptID, va_total, va_num); //ʹã zl 2019-12-23 15:09:30 + rcb_info = rcb_info1; + break; + } + } + //WW 2023-08-29 en + /////////////////////////// + } + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + /* The following optional vars are supported by IEC-61850 but they are + * NOT supported by UCA. This client must NOT set these OptFlds bits + * when connected to a UCA server, and these variables will NOT be + * included in a report received from a UCA server. + */ + + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) + info_va[va_num++] = rcb_info->rcb_var.BufOvfl; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) + info_va[va_num++] = rcb_info->rcb_var.EntryID; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) + info_va[va_num++] = rcb_info->rcb_var.ConfRev; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) + { + info_va[va_num++] = rcb_info->rcb_var.SubSeqNum; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + info_va[va_num++] = rcb_info->rcb_var.MoreSegmentsFollow; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + } + info_va[va_num++] = rcb_info->rcb_var.Inclusion; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + assert(va_num < va_total); + + /* Perform 2nd decode (up through "Inclusion"). */ + mvl_info_data_to_local(event, va_num, info_va); + + /* Examine "Inclusion", and set up 3rd decode to decode all data. */ + InclusionData = rcb_info->rcb_data.Inclusion; /* use local var */ + // printf ("\nThe 1st byte Inclusion = 0x%02X\n", InclusionData[0]); /* Just print 1st byte */ + + /* NOTE: Don't change initial entries in "info_va". Add these right after "Inclusion".*/ + + /* If "data-Ref" enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) + { + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) { + info_va[va_num++] = rcb_info->rcb_var.dataRefName[j]; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + } + } + } + + /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) { + info_va[va_num++] = rcb_info->rcb_var.dataValue[j]; + if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; + } + } + + /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ + if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) + { + for (j = 0; j < rcb_info->numDsVar; ++j) + { + if (BSTR_BIT_GET(InclusionData, j)) { + info_va[va_num++] = rcb_info->rcb_var.Reason[j]; + } + } + } + + /* Does num of variables received match expected num.*/ + if (va_num != va_total) + { + echo_warn2("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring", va_total, va_num); + // printf ("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring\n", va_total, va_num); + } + else + { + /* Perform 3rd decode (everything). */ + mvl_info_data_to_local(event, va_num, info_va); + + //洦lnk20250114 + pthread_mutex_lock(&mtx); + u_iec_rpt_ind_data(info_va, OptFldsData, InclusionData, rcb_info, va_total, event->net_info); + pthread_mutex_unlock(&mtx); + } + +CLEANUP: + chk_free(info_va); + return (retcode); +} +/************************************************************************/ +//61850Ϊ +/************************************************************************/ +void log_var_to_data(MVL_VAR_ASSOC *var, char *pdata) +{ + static char text_buf[30000]; /* increase size if ms_local_to_text fails */ + // ST_CHAR tdl_buf [500]; /* increase size if complex TDL expected*/ + MVL_TYPE_CTRL *type_ctrl; + ST_CHAR *data_text; /* var data converted to text */ + text_buf[0] = 0; + type_ctrl = mvl_type_ctrl_find(var->type_id); + if (type_ctrl) + { + //if (ms_runtime_to_tdl(type_ctrl->rt,type_ctrl->num_rt,tdl_buf,sizeof(tdl_buf))>0) + // RTP_PRI (" TYPE: %s\r\n", tdl_buf); + //else RTP_PRI (" TYPE: unknown\r\n"); + data_text = ms_local_to_text((char *)var->data, type_ctrl->rt, type_ctrl->num_rt, text_buf, sizeof(text_buf)); + if (data_text) { strcpy(pdata, data_text); } + else *pdata = '0'; + } + else *pdata = '0'; +} +/************************************************************************/ +/* LocToTextBs */ +/************************************************************************/ +#define TEMP_DATA_BUF_SIZE 1024 + +static ST_RET myLocToTextBs(ST_UCHAR* pSrc, RUNTIME_TYPE* rt, ST_CHAR* text) +{ + int i; + int j; + int k; + int numBits; + ST_INT16* sp; + ST_CHAR* destBuf; + ST_UCHAR mask; + + //printf("%s text_len %d %d pSrc %d %d \n", text, strlen(text), rt->u.p.el_len, pSrc[0], pSrc[1]); + + text[0] = 0; + numBits = rt->u.p.el_len; + + /* We take 1 dest byte per bit, make sure it fits */ + if (numBits > TEMP_DATA_BUF_SIZE - 1) + { + MLOG_NERR1("Bit String (%d bits) too long to encode", numBits); + return (SD_FAILURE); + } + + if (numBits < 0) /* a variable length bit string */ + { + sp = (ST_INT16*)pSrc; + numBits = *sp; + //printf("numBits %d \n", numBits); + if ((numBits > TEMP_DATA_BUF_SIZE - 1) || (numBits <= 0)) { + if (numBits != 0) //add by lzm @2018.11.1,to avoid too many print message!!! + echo_warn1("Bit String (%d bits) too long to encode\n", numBits); + return (SD_FAILURE); + } + k = 2; + } + else + k = 0; + + destBuf = text; + for (i = 0; i < numBits; ++k) /* for each byte, while bits remain */ + { + mask = 0x80; + for (j = 0; j < 8 && i < numBits; ++i, ++j) + { + if (pSrc[k] & mask) + destBuf[i] = '1'; + else + destBuf[i] = '0'; + mask >>= 1; + } + } + destBuf[i] = 0; + return (SD_SUCCESS); +} +/************************************************************************/ +/* LocToTextOct */ +/************************************************************************/ +static ST_RET myLocToTextOct(ST_UCHAR* pSrc, RUNTIME_TYPE* rt, ST_CHAR* text) +{ + int i, k; + int numBytes; + ST_INT16* sp; + ST_CHAR* destBuf; + + text[0] = 0; + numBytes = rt->u.p.el_len; + + if (numBytes < 0) /* a variable length octet string */ + { + sp = (ST_INT16*)pSrc; + numBytes = *sp; + k = 2; + } + else + k = 0; + + /* We take 3 bytes per octet, make sure it fits */ + if (numBytes > TEMP_DATA_BUF_SIZE / 3) + { + MLOG_NERR1("Octet String (%d bytes) too long to encode", numBytes); + return SD_FAILURE; + } + + destBuf = text; + for (i = 0; i < numBytes; ++i, ++k) + { + apr_snprintf(destBuf, sizeof(destBuf), "%02x ", (unsigned int)pSrc[k]); + destBuf += 3; + } + + /* Eliminate the trailing space */ + *(destBuf - 1) = 0; + return (SD_SUCCESS); +} + +/************************************************************************/ +/* asn1_convert_utc_to_btod */ +/* This function converts MMS_UTC_TIME (time relative to 1/1/1970) to */ +/* the MMS_BTOD (time relative to 1/1/1984). */ +/* The form field in the MMS_BTOD is set to MMS_BTOD6 by this function. */ +/* Parameters: */ +/* utc pointer to MMS_UTC_TIME struct that should be converted */ +/* to the MMS_BTOD */ +/* btod pointer to MMS_BTOD struct where the result of the */ +/* conversion will be placed */ +/* Return: */ +/* SD_SUCCESS if function successful */ +/* SD_FAILURE otherwise */ +/************************************************************************/ +ST_RET my_asn1_convert_utc_to_btod(MMS_UTC_TIME* utc, MMS_BTOD* btod) +{ + time_t tJan84 = TIME_T_1984_JAN_1; + + /* Now compute the MMS_BTOD time */ + btod->day = (long)(utc->secs - tJan84) / SECONDS_PER_DAY; /* num of days since 1/1/1984 */ + btod->ms = (long)((utc->secs - tJan84) % SECONDS_PER_DAY) * 1000; /* num milliseconds since midnight */ + /* NOTE: use 0x01000000 (2**24) in fraction computations. */ + // Ҫ뵽 28.9999Ӧ29ms + btod->ms += (ST_INT32)(0.5 + (ST_DOUBLE)utc->fraction * 1000.0 / (ST_DOUBLE)0x01000000); + /* add the milliseconds left in a sec */ + btod->form = MMS_BTOD6; + + return (SD_SUCCESS); +} + +/************************************************************************/ +/* ms_local_to_text */ +/* NOTE: tmpBuf is passed to most "LocToText.." static functions. These */ +/* functions must NOT write past end of tmpBuf. */ +/************************************************************************/ + + +void my_local_to_data(ST_CHAR* datptr, SD_CONST RUNTIME_TYPE* rt_head, + ST_INT rt_num, MMS_DECODE_DATA* data) +{ + RUNTIME_TYPE* rt_ptr; + RUNTIME_TYPE* rt_end; + ST_RET uDataRet; + ST_INT arr_loop_level = 0; + ST_INT arr_loops[ASN1_MAX_LEVEL]; + //ST_CHAR *ret_ptr; + ST_CHAR tmpBuf[TEMP_DATA_BUF_SIZE]; + //ST_UINT nStrLen = 0; /* Current text total length */ + ST_UINT valid_item_num = 0; + SD_CONST ST_CHAR* comp_name; /* component name *///add by lzm + //ST_INT comp_name_len; /* len of component name*/ + ST_UINT deep = 0; // deep of structure + unsigned int jjj; + char attr_str[256]; + char comp_str[32][256]; + int cur_array_deep = -1; + ST_UINT cur_array_idx; + + if (data == NULL) { + echo_warn("error ~~~~~~~ my_local_to_data MMS_DECODE_DATA data is NULL return \n"); + return; + } + if (rt_num <= 0) { + echo_warn1("error !!!!!!! my_local_to_data rt_num %d = return \n", rt_num); + return; + } + if (rt_head->el_tag > RT_ARR_END) { + echo_warn2("error @@@@@@@ my_local_to_data rt_head->el_tag %d size %d = return \n", rt_head->el_tag, rt_head->el_size); + return; + } + data->item_num = 0; + rt_ptr = (RUNTIME_TYPE*)rt_head; /* point to head rt_block */ + rt_end = rt_ptr + rt_num; /* done when pointer is here */ + if (rt_end == NULL) { + echo_warn("error XXXXXX my_local_to_data rt_end \n"); + return; + } + // SLOGCALWAYS1(" rt_num = %i",rt_num); + uDataRet = SD_SUCCESS; + while (rt_ptr < rt_end && uDataRet == SD_SUCCESS) + { + if (rt_ptr == NULL) { + echo_warn("error !!!!!!! my_local_to_data rt_ptr is NULL error,return \n"); + return; + } + if (valid_item_num >= MAX_DATA_ITEMS_IN_ONE_DATA) { + echo_warn2("my_local_to_data RUNTIME_TYPE valid_item_num % >= %d \n", valid_item_num, MAX_DATA_ITEMS_IN_ONE_DATA); + return; + } + if (rt_ptr->el_tag == RT_ARR_END) /* treat case of array ending */ + { + if (--arr_loops[arr_loop_level] > 0) /* if need to do next ar elmnt */ + rt_ptr -= rt_ptr->u.arr.num_rt_blks; /* mv rt_ptr to start of arr */ + else + --arr_loop_level; + } + if (rt_ptr->el_tag == RT_ARR_START) /* treat case of array starting */ + { + /* initialize the loop counter for the array */ + ++arr_loop_level; + arr_loops[arr_loop_level] = rt_ptr->u.arr.num_elmnts; + } + + comp_name = ms_comp_name_find(rt_ptr);//add by lzm + //printf ("\n %i, comp_name = %s cur_array_deep/deep: %d/%d \n",rt_ptr->el_tag,comp_name,cur_array_deep,deep); + // if (comp_name != NULL && comp_name[0] != 0) + // SLOGCALWAYS2 (" comp_name= %s, rt_ptr->el_tag =%i ",comp_name,rt_ptr->el_tag); // add by lzm + memset(attr_str, 0, sizeof(attr_str)); + if (deep == (cur_array_deep + 1)) + cur_array_idx++; + for (jjj = 0; jjj < deep; jjj++) + { + if (strcmp(comp_str[jjj], "")) { + strcat(attr_str, comp_str[jjj]); + } + if (jjj == cur_array_deep) { + char tmp_str[8]; + apr_snprintf(tmp_str, sizeof(tmp_str), "[%d]", cur_array_idx); + strcat(attr_str, tmp_str); + } + if (strcmp(comp_str[jjj], "")) { + strcat(attr_str, "$"); + } + //if (strcmp (comp_str[jjj], "")) { + //} + } + strcat(attr_str, comp_name); + + switch (rt_ptr->el_tag) + { + case RT_ARR_START: + strcpy(comp_str[deep], comp_name); + cur_array_deep = deep; + cur_array_idx = -1; + assert(++deep < 32); + break; /* do nothing */ + + case RT_ARR_END: /* array done */ + assert(--deep >= 0); + memset(comp_str[deep], 0, sizeof(comp_str[deep])); + cur_array_deep = -1; + cur_array_idx = -1; + break; /* do nothing */ + + case RT_STR_START: + strcpy(comp_str[deep], comp_name); + assert(++deep < 32); + //uDataRet = AddString ("{", textBuf, textBufSize, &nStrLen); + break; + + case RT_STR_END: /* structure done */ + assert(--deep >= 0); + memset(comp_str[deep], 0, sizeof(comp_str[deep])); + //uDataRet = AddString ("}", textBuf, textBufSize, &nStrLen); + break; + + case RT_BOOL: + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = 1; + data->data_item[valid_item_num].type = DATA_INT_TYPE; + data->data_item[valid_item_num].u.data_int = *((ST_BOOLEAN*)datptr); + valid_item_num++; + // SLOGCALWAYS2("valid_item_num = %i , value=%i",valid_item_num, *((ST_BOOLEAN *) datptr) ); + data->item_num = valid_item_num; + break; + + case RT_BIT_STRING: + myLocToTextBs((ST_UCHAR*)datptr, rt_ptr, tmpBuf); + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); + data->data_item[valid_item_num].type = DATA_STR_TYPE; + strcpy(data->data_item[valid_item_num].u.data_str, tmpBuf); + valid_item_num++; + // SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, tmpBuf ); + data->item_num = valid_item_num; + break; + + case RT_INTEGER: + case RT_BCD: + switch (rt_ptr->u.p.el_len) /* determine length */ + { + case 1: /* one byte int */ + case 2: /* two byte int */ + case 4: /* four byte integer */ + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; + data->data_item[valid_item_num].type = DATA_INT_TYPE; + if (rt_ptr->u.p.el_len == 1) + data->data_item[valid_item_num].u.data_int = *((ST_INT8*)datptr); + else if (rt_ptr->u.p.el_len == 2) + data->data_item[valid_item_num].u.data_int = *((ST_INT16*)datptr); + else if (rt_ptr->u.p.el_len == 4) + data->data_item[valid_item_num].u.data_int = *((ST_INT32*)datptr); + // SLOGCALWAYS1("value=%i",data->data_item[valid_item_num].u.data_int ); + valid_item_num++; + // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); + data->item_num = valid_item_num; + break; + +#ifdef INT64_SUPPORT + case 8: /* eight byte integer */ + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; + data->data_item[valid_item_num].type = DATA_INT64_TYPE; + data->data_item[valid_item_num].u.data_int64 = *((ST_INT64*)datptr); + // SLOGCALWAYS1(" value=%lld ",data->data_item[valid_item_num].u.data_int64 ); + valid_item_num++; + // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); + data->item_num = valid_item_num; + break; +#endif + default: + echo_warn1("δRT_INTEGERRT_BCD size = %i \n", rt_ptr->u.p.el_len); + break; + } + break; + + case RT_UNSIGNED: + switch (rt_ptr->u.p.el_len) /* determine length */ + { + case 1: /* one byte int */ + case 2: /* two byte int */ + case 4: /* four byte integer */ + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; + data->data_item[valid_item_num].type = DATA_UINT_TYPE; + if (rt_ptr->u.p.el_len == 1) + data->data_item[valid_item_num].u.data_uint = *((ST_UCHAR*)datptr); + else if (rt_ptr->u.p.el_len == 2) + data->data_item[valid_item_num].u.data_uint = *((ST_UINT16*)datptr); + else if (rt_ptr->u.p.el_len == 4) + data->data_item[valid_item_num].u.data_uint = *((ST_UINT32*)datptr); + // SLOGCALWAYS1("value=%u",data->data_item[valid_item_num].u.data_uint ); + valid_item_num++; + // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); + data->item_num = valid_item_num; + break; + +#ifdef INT64_SUPPORT + case 8: /* eight byte integer */ + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; + data->data_item[valid_item_num].type = DATA_UINT64_TYPE; + data->data_item[valid_item_num].u.data_int64 = *((ST_UINT64*)datptr); + // SLOGCALWAYS1(" value=%llu ",data->data_item[valid_item_num].u.data_uint64 ); + valid_item_num++; + // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); + data->item_num = valid_item_num; + break; +#endif /* INT64_SUPPORT */ + default: + echo_warn1("δ ޷ size = %i \n", rt_ptr->u.p.el_len); + break; + } + break; + + + +#ifdef FLOAT_DATA_SUPPORT + case RT_FLOATING_POINT: + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; + data->data_item[valid_item_num].type = DATA_DOUBLE_TYPE; + if (rt_ptr->u.p.el_len != sizeof(ST_FLOAT)) + data->data_item[valid_item_num].u.data_double = *((ST_DOUBLE*)datptr); + else + data->data_item[valid_item_num].u.data_double = *((ST_FLOAT*)datptr); + // SLOGCALWAYS1(" value=%.16g ",data->data_item[valid_item_num].u.data_double ); + valid_item_num++; + // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); + data->item_num = valid_item_num; + break; +#endif + + case RT_OCTET_STRING: + myLocToTextOct((ST_UCHAR*)datptr, rt_ptr, tmpBuf); + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); + data->data_item[valid_item_num].type = DATA_STR_TYPE; + strcpy(data->data_item[valid_item_num].u.data_str, tmpBuf); + valid_item_num++; + //SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, tmpBuf ); + data->item_num = valid_item_num; + break; + + case RT_VISIBLE_STRING: /* No conversion needed. Just add to working text*/ + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); + data->data_item[valid_item_num].type = DATA_STR_TYPE; + strcpy(data->data_item[valid_item_num].u.data_str, datptr); + valid_item_num++; + // SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, datptr ); + data->item_num = valid_item_num; + break; + +#ifdef TIME_DATA_SUPPORT + case RT_GENERAL_TIME: + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); + data->data_item[valid_item_num].type = DATA_TIME_TYPE; + asn1_convert_timet_to_btime6(*((time_t*)datptr), + &(data->data_item[valid_item_num].u.data_bTime6)); + valid_item_num++; + data->item_num = valid_item_num; + break; +#endif + +#ifdef BTOD_DATA_SUPPORT + case RT_BINARY_TIME: + switch (rt_ptr->u.p.el_len) /* determine length */ + { + MMS_BTIME6 btime6; + case 4: + asn1_convert_timet_to_btime6(time(NULL), &btime6); + btime6.ms = *((ST_INT32*)datptr); + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = 4; + data->data_item[valid_item_num].type = DATA_TIME_TYPE; + data->data_item[valid_item_num].u.data_bTime6 = btime6; + valid_item_num++; + data->item_num = valid_item_num; + break; + case 6: + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = 6; + data->data_item[valid_item_num].type = DATA_TIME_TYPE; + data->data_item[valid_item_num].u.data_bTime6 = *((MMS_BTIME6*)datptr); + valid_item_num++; + data->item_num = valid_item_num; + break; + } + break; +#endif + + case RT_UTC_TIME: + { + MMS_BTOD btod; + //cout<<"((MMS_UTC_TIME *) datptr)->fraction = "<<((MMS_UTC_TIME *) datptr)->fraction; + //cout<<"((MMS_UTC_TIME *)datptr)->qflags = "<<((MMS_UTC_TIME *)datptr)->qflags<data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = 1; + data->data_item[valid_item_num].type = DATA_TIME_TYPE; + data->data_item[valid_item_num].u.data_bTime6.day = btod.day; + data->data_item[valid_item_num].u.data_bTime6.ms = btod.ms; + valid_item_num++; + // SLOGALWAYS3("valid_item_num = %i , UTC TIME seconds=%lu, fraction=%lu", + // valid_item_num, ((MMS_UTC_TIME *) datptr)->fraction, + // ((MMS_UTC_TIME *) datptr)->secs ); + data->item_num = valid_item_num; + } + break; + + case RT_UTF8_STRING: + strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); + data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); + data->data_item[valid_item_num].type = DATA_STR_TYPE; + strcpy(data->data_item[valid_item_num].u.data_str, datptr); + valid_item_num++; + // SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, datptr ); + data->item_num = valid_item_num; + break; + + default: /* should not be any other tag */ + MLOG_ERR1("Invalid tag: %d", (int)rt_ptr->el_tag); + uDataRet = SD_FAILURE; + break; + } + + assert(strlen(tmpBuf) < sizeof(tmpBuf)); /* Must not exceed buffer*/ + + datptr += rt_ptr->el_size; /* Adjust data pointer */ + rt_ptr++; /* point to next rt element */ + } +} + + diff --git a/mms/mmsclient.c b/mms/mmsclient.c new file mode 100644 index 0000000..1995e96 --- /dev/null +++ b/mms/mmsclient.c @@ -0,0 +1,1969 @@ +/** +* @file: $RCSfile: mmsclient.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.12 $ +* @date: $Date: 2022/11/28 07:13:13 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmsclient.c,v 1.12 2022/11/28 07:13:13 lizhongming Exp $ +* +*/ + +//$Header: /JoyProject/jspqfe/src/pt61850netd_pqfe/source/mms/mmsclient.c,v 1.12 2022/11/28 07:13:13 lizhongming Exp $ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1986 - 2005, All Rights Reserved */ +/* (c) Copyright GDNZ Company, Inc., */ +/* 2006- 2006, All Rights Reserved */ +/* */ +/* MODULE NAME : mmsclient.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* */ +/* This module include the functions would be use by others */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* NONE */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/*2006-06-28 Lzm 101 Change the file to be functions used by others . */ +/* 09/09/05 JRB 55 Don't print BUILD_NUM. */ +/* 09/10/97 MDE 01 MMS-LITE V4.0 Release */ +/************************************************************************/ + +#define HARD_CODED_CFG +#if 1 + /* move outside #if to enable */ + + #define ACSE_AUTH_ENABLED /* for password authentication without */ + /* security */ +/* S_SEC_ENABLED for certificate based authentication & */ +/* SSL encryption, put this define in */ +/* application's DSP/MAK file */ +#endif + +/************************************************************************/ +#include "rdb_client.h" + +#include "glbtypes.h" +#include "sysincs.h" +#include "signal.h" +#include "mmsdefs.h" +#include "mms_pvmd.h" +#include "mms_pvar.h" +#include "mms_vvar.h" +#include "mms_err.h" +#include "mms_pcon.h" +#include "asn1defs.h" +#include "mmsop_en.h" + +#include "lean_a.h" //add by lzm +#include "tp0_sock.h" +#include "mvl_defs.h" +#include "acse2.h" + +#include "mvl_acse.h" +#include "mvl_log.h" +#include "tp4api.h" +#include "clntobj.h" +#include "mmsclient.h" +#include "tp4.h" + +#include "../mms/db_interface.h" + +#include //lnk20241119 + +extern uint32_t g_node_id; +extern char subdir[128]; +unsigned int g_no_auth = 0; +DEV_TYPE_LIST gDev_rcb_list; //ȫֱƿ +#if defined(MVL_GOOSE_SUPPORT) +/* Need parts of "iecgoose" sample app */ +#include "iec_demo.h" /* definitions from "iecgoose" sample app */ +/* Prototype here because it needs struct def from "iec_demo.h". */ +IEC_GOOSE_RX_USER_INFO *goose_init (ST_VOID); +#endif + +/*----------------------------------------------------------------------*/ +/* NOTE: The MMS-EASE Lite Secured applications (Client, Server) */ +/* are designed to work with Security Toolkit for MMS-EASE Lite */ +/* (LITESECURE-000-001). */ +/* The S_SEC_ENABLED delimits the security related code. */ +/*----------------------------------------------------------------------*/ +#if defined(S_SEC_ENABLED) && defined(ACSE_AUTH_ENABLED) +#error Only one S_SEC_ENABLED or ACSE_AUTH_ENABLED may be defined +#endif + +#if defined(S_SEC_ENABLED) +#include "mmslusec.h" +#endif + +#include "fkeydefs.h" +#ifdef kbhit /* CRITICAL: fkeydefs may redefine kbhit. DO NOT want that.*/ +#undef kbhit +#endif + +/************************************************************************/ +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ +/************************************************************************/ + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +/************************************************************************/ +/* Identify server information */ + +IDENT_RESP_INFO identify_response_info = + { + "Joyway JoyCom", /* Vendor */ + MMSLITE_NAME, /* Model */ + MMSLITE_VERSION, 0, /* Version */ + }; + + +/************************************************************************/ + +extern TP0_CONN *tp0_conn_arr; /* ptr to array of "max_num_conns" structs */ + +static ST_VOID disc_ind_fun (MVL_NET_INFO *cc, ST_INT discType); + +ST_VOID test_simple_requests (MVL_NET_INFO *clientNetInfo); + + +ST_INT timeOut = 60; /* timeout (in seconds) passed to waitReqDone */ + + +INIT_INFO callingInitInfo; +INIT_INFO initRespInfo; + +MVL_CFG_INFO mvlCfg; +RPT_TYPEIDS g_rpt_typeids; + +/************************************************************************/ +#if defined(HARD_CODED_CFG) + +DIB_ENTRY localDibTable[] = + { + { + 0, /* reserved */ + "local1", /* name[65] */ + SD_TRUE, /* local */ + SD_TRUE, /* AP_title_pres */ + { /* AP_title */ + 4, /* num_comps */ + 1, 3, 9999, 105 + }, + SD_FALSE, /* AP_inv_id_pres */ + 0, /* AP_invoke_id */ + SD_TRUE, /* AE_qual_pres */ + 33, /* AE_qual */ + SD_FALSE, /* AE_inv_id_pres */ + 0, /* AE_invoke_id */ +#if defined(REDUCED_STACK) + 105 /* adlcAddr */ +#else + { /* PRES_ADDR */ + 4, /* P-selector length */ + {'\x00','\x00','\x00','\x01'}, /* P-selector */ + 2, /* S-selector length */ + "\x00\x01", /* S-selector */ + TP_TYPE_TCP,// change by lzm /* Transport type */ + 2, /* T-selector length */ + "\x00\x01", /* T-selector */ + 0, /* Network address length */ + "" /* Network address (ignored on local) */ + } +#endif + } + }; + +#endif + +ST_VOID set_rem_dib_table_size (ST_INT size) +{ + mvlCfg.num_calling = size; + num_rem_dib_entries = size; + rem_dib_table = malloc(sizeof(DIB_ENTRY)*size); +} + +ST_VOID add_rem_dib_table (ST_INT pos,ST_CHAR *remAr,unsigned short port) +{ + DIB_ENTRY *de; + de = &rem_dib_table[pos]; + + de->reserved = 0; + /*de->name = (ST_CHAR *)chk_malloc(strlen(remAr) + 1); + strcpy(de->name, remAr);*/ + de->name = (ST_CHAR *)chk_malloc(32); + apr_snprintf(de->name,32,"%s:%d",remAr,port); + + de->local = SD_TRUE; + de->AP_title.num_comps = 4; + de->AP_title.comps[0] = 1; + de->AP_title.comps[1] = 3; + de->AP_title.comps[2] = 9999; + de->AP_title.comps[3] = 106; + de->AP_title_pres = SD_TRUE; /* defaults to FALSE */ + + de->AE_qual_pres = SD_TRUE; /* defaults to FALSE */ + de->AE_qual = 33; + + de->AP_inv_id_pres = SD_FALSE; + de->AP_invoke_id = 0; + de->AE_inv_id_pres = SD_FALSE; + de->AE_invoke_id = 0; + + de->pres_addr.psel[0] = 0; + de->pres_addr.psel[1] = 0; + de->pres_addr.psel[2] = 0; + de->pres_addr.psel[3] = 1; + de->pres_addr.psel_len = 4; + de->pres_addr.ssel[0] = 0; + de->pres_addr.ssel[1] = 1; + de->pres_addr.ssel_len = 2; + de->pres_addr.tp_type = TP_TYPE_TCP; + de->pres_addr.tsel[0] = 0; + de->pres_addr.tsel[1] = 1; + de->pres_addr.tsel_len = 2; + de->pres_addr.nsap_len = 4; + de->pres_addr.netAddr.ip = tp0_convert_ip(remAr); +// printf (" %x", de->pres_addr.netAddr.ip ); +// de->pres_addr.netAddr.nsap[0] = '\xAC'; +// de->pres_addr.netAddr.nsap[1] = '\x15'; +// de->pres_addr.netAddr.nsap[2] = '\x64'; +// de->pres_addr.netAddr.nsap[3] = '\x64'; + de->pres_addr.port = port;//IPPORT_RFC1006; +} + +static ST_VOID init_mem (ST_VOID); +#if defined (DEBUG_SISCO) +// ST_VOID init_log_cfg (ST_VOID); +#endif + +/************************************************************************/ +/* Global variables */ +/************************************************************************/ +typedef struct + { + ST_INT cmd_term_num_va; /* num of vars received in CommandTermination*/ + ST_CHAR oper_name [MAX_IDENT_LEN +1]; + } MY_CONTROL_INFO; +/* NOTE: this global variable can be avoided if a (MVL_CONTROL_INFO *) */ +/* is saved in the "user_info" member of MVL_NET_INFO, but to do so, */ +/* you must make sure "user_info" is not used for something else. */ +MY_CONTROL_INFO my_control_info; + +/************************************************************************/ +/* mms_var_type_id_create */ +/* Get the type for any domain-specific var and create a type_id. */ +/************************************************************************/ +ST_INT mms_var_type_id_create (MVL_NET_INFO *clientNetInfo, ST_INT scope, + ST_CHAR *dom_name, ST_CHAR *var_name, int iTimeOut) + { +MVL_REQ_PEND *reqCtrl; + +GETVAR_REQ_INFO getvar_req; +ST_INT type_id = -1; /* start with invalid type id */ +ST_RET ret; + + /* Get the type of this "Oper" attribute & create type. */ + /* Would be more efficient to do this just once before this function.*/ + getvar_req.req_tag = GETVAR_NAME; + + getvar_req.name.object_tag = scope; /* set scope */ + if (scope == DOM_SPEC) + getvar_req.name.domain_id= dom_name; + getvar_req.name.obj_name.vmd_spec = var_name; + + ret = mvla_getvar (clientNetInfo, &getvar_req, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeOut); + if (ret != SD_SUCCESS) + echo_warn2 ("Error getting type of variable '%s' in domain '%s'\n", var_name, dom_name); + else + { + /* Don't care about name so pass NULL. */ + type_id = mvl_type_id_create (NULL, reqCtrl->u.getvar.resp_info->type_spec.data, + reqCtrl->u.getvar.resp_info->type_spec.len); + } + mvl_free_req_ctrl (reqCtrl); /* Done with request struct */ + return (type_id); + } + +/************************************************************************/ +/* mms_var_type_id_create */ +/* Get the type for any domain-specific var and create a type_id. */ +/************************************************************************/ +ST_INT mms_get_datatype_from_type_id (ST_INT type_id, ST_UCHAR* datatype,ST_INT *len) +{ + ST_RET ret; + RUNTIME_CTRL rt_ctrl; + + if(type_id < 0) return SD_FAILURE; + + ret = mvl_get_runtime (type_id, &rt_ctrl.rt_first,&rt_ctrl.rt_num); + if (ret == SD_SUCCESS) + {//ֻ rt_ctrl.rt_num еһݵͺ + RUNTIME_TYPE *rt_type = &rt_ctrl.rt_first[0]; + *datatype = rt_type->el_tag; + *len = rt_type->u.p.el_len; + } + return ret; +} + +ST_INT32 u_safe_chang_double_to_int32 (ST_DOUBLE value, ST_CHAR *FileName, ST_INT32 line) +{ + ST_INT32 gInt32; + if(value > LONG_MAX) { + gInt32 = LONG_MAX; + MVL_LOG_NERR2 ("%s:%d Change double to int32 max overflow", FileName, line); + printf(" %s:%ld Change double to int32 max overflow!\n", FileName, line); + } + else if(value < LONG_MIN) { + gInt32 = LONG_MIN; + MVL_LOG_NERR2 ("%s:%d Change double to int32 min overflow", FileName, line); + printf(" %s:%ld Change double to int32 mxin overflow!\n", FileName, line); + } + else { + gInt32 = (ST_INT32)(value + 0.5); + } + + return(gInt32); +} + +void u_get_current_utc_time(MMS_UTC_TIME *utc_time) +{ + ST_DOUBLE temp = 0.0; + apr_time_t us; + apr_time_t tm = apr_time_now(); + + us = tm%1000000LL; + utc_time->secs = (ST_UINT32)(tm/1000000LL); + temp = (ST_DOUBLE)us/1000000 * 0x00FFFFFF; + utc_time->fraction = u_safe_chang_double_to_int32(temp, __FILE__, __LINE__); + utc_time->qflags = 0x00; +} + +void convert_apr_time_to_utc_time(apr_time_t tm,MMS_UTC_TIME *utc_time) +{ + ST_DOUBLE temp = 0.0; + apr_time_t us; + + us = tm%1000000LL; + utc_time->secs = (ST_UINT32)(tm/1000000LL); + temp = (ST_DOUBLE)us/1000000 * 0x00FFFFFF; + utc_time->fraction = u_safe_chang_double_to_int32(temp, __FILE__, __LINE__); + utc_time->qflags = 0x00; +} + + + +void mms_waitEventForever() +{ + while (1) + { + doCommService (); + } +} + +void exit_MMS() +{ + dyn_mem_ptr_statistics (0); + mvl_end_acse (); + dyn_mem_ptr_status (); /* is everything freed up? */ +} +/************************************************************************/ +/* init_MMS */ +/************************************************************************/ +void init_MMS() + { + ST_RET ret; + + setbuf (stdout, NULL); /* do not buffer the output to stdout */ + setbuf (stderr, NULL); /* do not buffer the output to stderr */ + + printf ("%s Version %s\n", MMSLITE_NAME, MMSLITE_VERSION); +#if defined(S_SEC_ENABLED) + printf ("%s Version %s\n", S_SEC_LITESECURE_NAME, S_SEC_LITESECURE_VERSION_STR); +#endif + puts (MMSLITE_COPYRIGHT); + + +#ifdef S_MT_SUPPORT + /* init glbsem explicitly to avoid auto-initialization calls from multiple threads */ + if ((ret = gs_init()) != SD_SUCCESS) + { + printf ("gs_init() failed"); + exit (1); + } +#endif + + /* init stime explicitly to avoid auto-initialization calls from multiple threads */ + if ((ret = stimeInit()) != SD_SUCCESS) + { + printf ("stimeInit() failed"); + exit (1); + } + +#if defined(NO_GLB_VAR_INIT) + mvl_init_glb_vars (); +#endif + + init_mem (); /* Set up memory allocation tools */ + + + echo_msg2 ("%s Version %s \n", MMSLITE_NAME, MMSLITE_VERSION); + +/* We want to know about connection activity */ + u_mvl_disc_ind_fun = disc_ind_fun; + +#if !defined(MAP30_ACSE) + +#if defined(HARD_CODED_CFG) + num_loc_dib_entries = sizeof(localDibTable)/sizeof(DIB_ENTRY); + loc_dib_table = localDibTable; +// num_rem_dib_entries = sizeof(rem_dib_table)/sizeof(DIB_ENTRY); + + memset(&gDev_rcb_list, 0, sizeof(DEV_TYPE_LIST)); //WW 2023-08-29 ȫװñָʼ + + // tp4_config(); /* see tp4_hc.c */ + tp0_cfg.max_tpdu_len = 8192;//8192; + tp0_cfg.max_num_conns = 8; /* see tp4_hc.c */ + //printf("OLD tp0_cfg.keepalive = %i \n" ,tp0_cfg.keepalive ); + tp0_cfg.keepalive = 1; + //printf("OLD tp0_cfg.max_spdu_outst = %i \n" ,tp0_cfg.max_spdu_outst ); + tp0_cfg.max_spdu_outst = 50; +#if 0 /* Only call config functions necessary for stack being used. */ + tp4_config(); /* see tp4_hc.c */ + clnp_config(); /* see clnp_hc.c */ + adlcConfigure(); /* see adlc_hc.c */ +#endif + /* Fill in mvlCfg. */ + + mvlCfg.num_called = 0; + mvlCfg.max_msg_size = 320000; //to enlage to fit the 豸 + strcpy (mvlCfg.local_ar_name, "local1"); + +#else /* #if defined(HARD_CODED_CFG) */ + +/* Read the configuration from a file */ + ret = osicfgx ("osicfg.xml", &mvlCfg); /* This fills in mvlCfg */ + if (ret != SD_SUCCESS) + { + printf ("\n Stack configuration failed, err = 0x%X. Check configuration.\n", ret ); + exit (1); + } +#endif /* HARD_CODED_CFG */ + +#else /* MAP30_ACSE */ + mvlCfg.num_calling = 4; + mvlCfg.num_called = 0; + mvlCfg.max_msg_size = 8000; + strcpy (mvlCfg.local_ar_name, "local1"); +#endif /* MAP30_ACSE */ + + +#if defined(S_SEC_ENABLED) + /* set security configuration file name, MUST be before mvl_start_acse*/ + secManCfgXmlFile = "secmancfg.xml"; +#endif /* defined(S_SEC_ENABLED) */ + + ret = mvl_start_acse (&mvlCfg); /* MAKE SURE mvlCfg is filled in*/ + if (ret != SD_SUCCESS) + { + printf ("\n mvl_start_acse () failed, err = 0x%X.\n", ret ); + exit (1); + } + + if ((ret = rpt_typeids_find (&g_rpt_typeids)) != SD_SUCCESS) + { + printf ("rpt_typeids_find () failed = 0x%X.\n", ret ); + exit (1); + } + +#if defined(MVL_GOOSE_SUPPORT) + /* NOTE: this GOOSE initialization must be AFTER mvl_start_acse so */ + /* that required types can be found. */ + goosehandle = goose_init (); +#endif + + chk_malloc(1); /* memory marker */ + +#if !defined(NO_KEYBOARD) && !defined(_WIN32) && !defined(__QNX__) + //term_init (); /* makes getchar work right */ +#endif +} +// + + +ST_RET mms_mvla_identify (MVL_NET_INFO *net_info,char** ident,int iTimeout) +{ + static char ident_str[256]; + MVL_REQ_PEND *reqCtrl; + IDENT_RESP_INFO *ident_resp; + ST_RET ret = mvla_identify (net_info, &reqCtrl); + + memset(ident_str,0,sizeof(ident_str)); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret == SD_SUCCESS) + { + ident_resp = reqCtrl->u.ident.resp_info; + apr_snprintf( ident_str, sizeof(ident_str), "Vendor = %s, Model = %s, Rev = %s", ident_resp->vend, + ident_resp->model, ident_resp->rev); + printf ("%s\n",ident_str); + *ident = ident_str; + } + else + printf ("\n mvl_identify () Error, ret = 0x%X.", ret); + mvl_free_req_ctrl (reqCtrl); + return ret; +} + +#if (MMS_STATUS_EN & REQ_EN) +ST_RET mms_mvla_status (MVL_NET_INFO *net_info,int iTimeout) +{ + ST_RET ret; + STATUS_REQ_INFO status_req; + MVL_REQ_PEND *reqCtrl; + status_req.extended = SD_FALSE; + ret = mvla_status (net_info, &status_req, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) + printf ("\n mvl_status () Error, ret = 0x%x ", ret); + else + { +// printf (" mvl_status OK \n"); +// printf ("\n logical status = %d", reqCtrl->u.status.resp_info->logical_stat); +// printf ("\n physical status = %d", reqCtrl->u.status.resp_info->physical_stat); +// if (reqCtrl->u.status.resp_info->local_detail_pres == SD_FALSE) +// printf ("\n No local detail"); +// else +// { +// printf ("\n Local detail present"); +// printf ("\n Local detail len = %d bits", +// reqCtrl->u.status.resp_info->local_detail_len); +// } + } + mvl_free_req_ctrl (reqCtrl); + return ret; +} +#endif + +#if (MMS_OBTAINFILE_EN & REQ_EN) +ST_RET mms_mvla_obtfile (MVL_NET_INFO *net_info,ST_CHAR *srcfilename, + ST_CHAR *destfilename,int iTimeout) +{ + MVL_REQ_PEND *reqCtrl; + ST_RET ret = mvla_obtfile (net_info, srcfilename, destfilename, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) + printf ("\n mvl_obtfile () Error obtaining file '%s', ret = 0x%X.", + srcfilename, ret); + else + printf ("\n mvl_obtfile () of '%s' OK.", srcfilename); + mvl_free_req_ctrl (reqCtrl); + return ret; +} +#endif + +#if (MMS_FDELETE_EN & REQ_EN) +ST_RET mms_mvla_fdelete (MVL_NET_INFO *net_info,ST_CHAR *file_to_delete,int iTimeout) +{ + MVL_REQ_PEND *reqCtrl; + ST_RET ret = mvla_fdelete (net_info, file_to_delete, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) + printf ("\n mvl_fdelete () Error deleting file '%s', ret = 0x%X.", + file_to_delete, ret); + else + printf ("\n mvl_fdelete () of '%s' OK.", file_to_delete); + mvl_free_req_ctrl (reqCtrl); + return ret; +} +#endif + +//ڷļĿ¼󣬻ȡԶ豸ļбطļ +#if (MMS_FDIR_EN & REQ_EN) +ST_RET mms_mvla_fdir (MVL_NET_INFO *net_info,ST_CHAR *filespec,int iTimeout, + char*** filenames ,int* filenum,apr_pool_t *pool) +{ + MVL_REQ_PEND *reqCtrl; + MVL_FDIR_RESP_INFO *fdir_resp; + ST_RET ret; + ST_CHAR ca_filename[255]; + ST_BOOLEAN more_follows = SD_FALSE; + ST_INT i; + char** filenames2; + + *filenum = 0; +// "*.*", /* fs_name */ + do { + if (more_follows) + ret = mvla_fdir (net_info, filespec, ca_filename ,&reqCtrl); + else + ret = mvla_fdir (net_info, filespec, NULL ,&reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) { + printf ("\n mvl_fdir () Error, ret = 0x%X. \n", ret); + mvl_free_req_ctrl (reqCtrl); /* CRITICAL: */ + break; + } + else + { + fdir_resp = reqCtrl->u.fdir.resp_info; + more_follows = fdir_resp->more_follows; + printf ("\n mvl_fdir results: num=%i \n",fdir_resp->num_dir_ent); + + filenames2 = apr_pcalloc( pool,(*filenum+fdir_resp->num_dir_ent)*sizeof(char*) ); + for ( i = 0; i < *filenum; ++i) + filenames2[i] =(*filenames)[i]; + (*filenames) = filenames2; + + + for (i = 0; i < fdir_resp->num_dir_ent; i++) + { + //printf ("\n File #%d: %s", i, fdir_resp->dir_ent[i].filename); + (*filenames)[*filenum+i] = apr_pstrdup(pool,fdir_resp->dir_ent[i].filename); + } + } + if (fdir_resp->num_dir_ent >0 ) + strcpy(ca_filename,fdir_resp->dir_ent[fdir_resp->num_dir_ent-1].filename); + *filenum += fdir_resp->num_dir_ent; + mvl_free_req_ctrl (reqCtrl); /* CRITICAL: */ + } while (more_follows); + return ret; +} + +#endif + + +#if (MMS_GETNAMES_EN & REQ_EN) +//#define MMS_CLASS_VAR 0 +//#define MMS_CLASS_SCAT_ACC 1 +//#define MMS_CLASS_VARLIST 2 +//#define MMS_CLASS_TYPE 3 +//#define MMS_CLASS_SEM 4 +//#define MMS_CLASS_EV_COND 5 +//#define MMS_CLASS_EV_ACT 6 +//#define MMS_CLASS_EV_ENROLL 7 +//#define MMS_CLASS_JOU 8 +//#define MMS_CLASS_DOM 9 +//#define MMS_CLASS_PI 10 +//#define MMS_CLASS_OPER_STA 11 + +ST_RET mms_mvla_getnam (MVL_NET_INFO *net_info,ST_INT scope, + ST_CHAR *domName,ST_INT16 mms_class, int iTimeout, + char*** varnames ,int* varnum,apr_pool_t *pool) +{ + MVL_REQ_PEND *reqCtrl; + NAMELIST_REQ_INFO getnam_req; + NAMELIST_RESP_INFO *getnam_resp; + ST_RET ret; + ST_CHAR continue_after[255]; + ST_BOOLEAN more_follows = SD_FALSE; + ST_CHAR **nptr; + ST_INT i; + char** varnames2; + + *varnum=0; + getnam_req.cs_objclass_pres = SD_FALSE; + getnam_req.obj.mms_class = mms_class; + + getnam_req.objscope = scope; + if (scope == DOM_SPEC) + strcpy (getnam_req.dname, domName); + //getnam_req.dname = domName; /* set domain name */ + getnam_req.cont_after_pres = SD_FALSE; + do { + if (more_follows) + { + getnam_req.cont_after_pres = SD_TRUE; + strcpy(getnam_req.continue_after,continue_after); + } + ret = mvla_getnam (net_info, &getnam_req, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) { + printf ("\n mvl_getnam () Error, ret = 0x%x.", ret); + more_follows = SD_FALSE; + } + else + { +// printf ("\n mvl_getnam OK"); + getnam_resp = (NAMELIST_RESP_INFO *) reqCtrl->u.ident.resp_info; + more_follows = getnam_resp->more_follows; + //if (more_follows) { + // printf ("\n More Follows : TRUE"); + //} + //else { + // printf ("\n More Follows : FALSE"); + //} + printf("");// + //printf ("mms_mvla_getname %d Names returned . \n",getnam_resp->num_names); + + varnames2 = apr_pcalloc( pool,(*varnum+getnam_resp->num_names)*sizeof(char*) ); + for ( i = 0; i < *varnum; ++i) + varnames2[i] =(*varnames)[i]; + (*varnames) = varnames2; + + //printf ("\n Name List :"); + nptr = (ST_CHAR **) (getnam_resp + 1); + for ( i = 0; i < getnam_resp->num_names; ++i) + (*varnames)[*varnum +i] = apr_pstrdup(pool, nptr[i] ); + //printf ("\n%d %s ",total+i,nptr[i]); + if (getnam_resp->num_names >0 ) + strcpy(continue_after,nptr[getnam_resp->num_names-1]); + *varnum += getnam_resp->num_names; + } + mvl_free_req_ctrl (reqCtrl); + } while (more_follows); + return ret; +} +#endif + +ST_RET mms_rcb_setEntryID(MVL_NET_INFO *netInfo, ST_CHAR *domName, + ST_CHAR *rcbName, RPT_TYPEIDS *rpt_typeids, ST_INT timeOut, ST_UINT8* pEntryID) +{ + ST_RET ret; + ST_CHAR varName [MAX_IDENT_LEN + 1]; + apr_snprintf (varName, sizeof(varName), "%s$EntryID", rcbName); + ret = mms_named_var_write (netInfo, varName, DOM_SPEC, domName, rpt_typeids->ostring8, (ST_CHAR *)pEntryID, timeOut); + if (ret == SD_SUCCESS) + printf ("\n Report setEntryID successed,EntryID: %02x %02x %02x %02x %02x %02x %02x %02x \n", + *pEntryID, *(pEntryID+1), *(pEntryID+2), *(pEntryID+3), *(pEntryID+4), *(pEntryID+5), + *(pEntryID+6), *(pEntryID+7) ); + else + echo_warn8("\n Report setEntryID failed,EntryID: %02x %02x %02x %02x %02x %02x %02x %02x \n", + *pEntryID, *(pEntryID+1), *(pEntryID+2), *(pEntryID+3), *(pEntryID+4), *(pEntryID+5), + *(pEntryID+6), *(pEntryID+7) ); + return ret; +} + +/************************************************************************/ +/* mms_register_iec_rpt */ +/* This function sets up to receive IEC-61850 or UCA reports on this connection*/ +// RCB (e.g. "LLN0$BR$PosReport") +/************************************************************************/ +RCB_INFO* mms_register_iec_rpt (MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, + ST_CHAR *dom_name,ST_CHAR *rcb_name,ST_INT timeOut, + ST_INT scanRate,ST_UCHAR trgops,ST_UINT8* pEntryID,ST_UINT8* OptFlds ) +{ +ST_RET ret; +RCB_INFO *rcb_info; /* UCA/IEC Report Control Block info */ +//ST_UCHAR OptFlds [2]; /* 10 bit bitstring but only allow write of 9 bits*/ +ST_UCHAR TrgOps [1]; /* 8 bit bitstring */ + rcb_info = rcb_info_create (clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); + if (rcb_info) + { + //ע + ST_BOOLEAN RptDisEna = 0; /* 0 = disable the report */ + ST_CHAR varName [MAX_IDENT_LEN + 1]; + apr_snprintf (varName,sizeof(varName), "%s$RptEna", rcb_name); + mms_named_var_write (clientNetInfo, varName, DOM_SPEC, dom_name, rpt_typeids->mmsbool, (ST_CHAR *) &RptDisEna, timeOut); + + printf ("rcb_info->numDsVar = %d\n", rcb_info->numDsVar); + /* Enable options we want to see in report. */ + //OptFlds [0] = 0; + /* These options valid for IEC BRCB, IEC URCB, or UCA. */ + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_SQNUM); + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_TIMESTAMP); + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_REASON); + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_DATSETNAME); + /* NOTE: these options ONLY available for IEC-61850 (not UCA) + * SUBSEQNUM is only set by the server, so don't try to set it. + */ + if (rcb_info->rcb_type == RCB_TYPE_IEC_BRCB) + { /* These only valid for IEC BRCB */ +// BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_BUFOVFL); + BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_ENTRYID); + if ((pEntryID[0]!=0xff)||(pEntryID[1]!=0xff)||(pEntryID[2]!=0xff)||(pEntryID[3]!=0xff) + ||(pEntryID[4]!=0xff)||(pEntryID[5]!=0xff)||(pEntryID[6]!=0xff)||(pEntryID[7]!=0xff) ) + mms_rcb_setEntryID(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut, pEntryID); + } + //if (rcb_info->rcb_type != RCB_TYPE_UCA) + // { /* These only valid for IEC BRCB or IEC URCB */ + // BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_DATAREF); + // BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_CONFREV); + // } + + TrgOps [0] = trgops; + ret = rcb_enable (clientNetInfo, dom_name, rcb_name, OptFlds, TrgOps, + scanRate*1000, /* Integrity Period (ms) */ + rpt_typeids, + timeOut); /* timeout (s) */ + + if(ret == SD_SUCCESS) + { + list_add_last(&((ALL_RCB_INFO *)clientNetInfo->user_info)->rcb_info_list, rcb_info); /* add RCB to list*/ + } + else{ + rcb_info_destroy(rcb_info); + rcb_info = NULL; + echo_warn2 ("rcb_enable error for dom='%s', rcb='%s'\n", dom_name, rcb_name); + } + } + else + { + printf ("rcb_info_create error for dom='%s', rcb='%s'\n", dom_name, rcb_name); + rcb_info = NULL; + } + return (rcb_info); +} + +/////////////////////////////////////////// +//WW 2023-08-29 豸ʹ,Ż津ٶ +RCB_INFO* mms_register_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, + ST_CHAR *dom_name, ST_CHAR *rcb_name, ST_INT timeOut, ST_CHAR *dev_type, ST_CHAR *ip, int port, + ST_INT scanRate, ST_UCHAR trgops, ST_UINT8* pEntryID, ST_UINT8* OptFlds) +{ + ST_RET ret; + //ST_UCHAR OptFlds [2]; /* 10 bit bitstring but only allow write of 9 bits*/ + ST_UCHAR TrgOps[1]; /* 8 bit bitstring */ + + + //һװͲж--------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindDevType = 0; //Ƿвҵװ + Dev_RCB_INFO *dev_rcb = NULL;//װñṹָ + for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //ٱ ȫװñƿ + { + //LOG_INFO("(津)gDev_rcb_list, dev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:16:31 + if ((strcmp(dev_rcb->dev_type_name, dev_type) == 0)) //ƥ װ + { + bFindDevType = 1; //ҵװ + //LOG_INFO("(津)ƥ䵽װͣdev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:23:55 + break; + } + } // װ + if (!bFindDevType) //δҵװ + { + dev_rcb = (Dev_RCB_INFO *)chk_calloc(1, sizeof(Dev_RCB_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New + strcpy(dev_rcb->dev_type_name, dev_type); //װ + //LOG_INFO("(津)װͣdev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:23:55 + list_add_last(&gDev_rcb_list.dev_rcb_info_Head, dev_rcb); // ȫװñƿ + } + + //װIP˿ںŲж--------------------------------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindIpPort = 0; //ǷвҵװIP˿ں + Dev_IP_Port_INFO *dev_info = NULL; //װIP˿ںŽṹָ + for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //ڱ ȫװIP˿ + { + //LOG_INFO("(津)dev_ip_port_list, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:16:31 + if ((strcmp(dev_info->IP, ip) == 0) && (dev_info->Port == port)) //ƥ װIP && ˿ں + { + bFindIpPort = 1; //ҵװIP && ˿ں + //LOG_INFO("(津)ƥ䵽װdev_type_name= %s, IP= %s Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 + break; + } + }// װIP˿ + if (!bFindIpPort) //δҵװIP˿ + { + dev_info = (Dev_IP_Port_INFO *)chk_calloc(1, sizeof(Dev_IP_Port_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New + + strcpy(dev_info->IP, ip); //װIP + dev_info->Port = port; //˿ں + //LOG_INFO("(津)װdev_type_name= %s, IP= %s Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 + list_add_last(&dev_rcb->dev_ip_port_list, dev_info); // ȫװñƿ->װIP˿ + } + + //װñƿж---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + RCB_INFO *rcb_info = NULL; //ƿָ + ST_BOOLEAN bFindRCB = 0; //Ƿװñƿвҵ + for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //۱ ȫװñƿ->ƿϢ + { + //LOG_INFO("(津)rcb_info_list, RptID= %sdom_Name= %sdom= %srcb_name= %srpt= %s", rcb_info->RptID, rcb_info->dom_Name, dom, rcb_info->rcb_name, rpt); //ʹã zl 2018-10-17 21:19:36 + if ((strcmp(rcb_info->rcb_name, rcb_name) == 0) && (strcmp(rcb_info->dom_Name, dom_name) == 0)) //ƥ װñƿ + { + bFindRCB = 1; //ҵװñƿ + //LOG_INFO("(津)ƥ䵽ƿdev_type_name= %s, dom= %srcb= %sѴ", dev_rcb->dev_type_name, dom, rpt); //ʹã zl 2019-3-13 14:24:43 + break; /* rcb_info now points to right structure */ + } + } + if (!bFindRCB) //δҵװñƿ + { + rcb_info = rcb_info_create(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); // װñƿ >> עúΪʱװ͵ıƿѴٽд + if (rcb_info == NULL) { + //LOG_INFO("(津)ƿʧܣdev_type_name= %s, dom= %srcb= %s", dev_rcb->dev_type_name, dom, rpt); //ʹã zl 2019-3-13 14:24:43 + return SD_FAILURE; + } + else { + //LOG_INFO("(津)ƿɹȫֱƿdev_type_name= %s, dom= %srcb= %s", dev_rcb->dev_type_name, dom, rpt); //ʹã zl 2019-3-13 14:24:43 + list_add_last(&dev_rcb->rcb_info_list, rcb_info); // ȫֱƿ->ƿϢ + } + //TRACE("(津)ƿ飡dom= %s rcb= %sʱ:%0.6fС:%d", dom, rpt, dwEnd - dwStart, sizeof(RCB_INFO)); + } + + if (rcb_info) + { + //ע WW 2023-08-29עעĴ + //ST_BOOLEAN RptDisEna = 0; /* 0 = disable the report */ + //ST_CHAR varName[MAX_IDENT_LEN + 1]; + //apr_snprintf(varName, sizeof(varName), "%s$RptEna", rcb_name); + //mms_named_var_write(clientNetInfo, varName, DOM_SPEC, dom_name, rpt_typeids->mmsbool, (ST_CHAR *)&RptDisEna, timeOut); + //WW 2023-08-29 end + + printf("rcb_info->numDsVar = %d\n", rcb_info->numDsVar); + /* Enable options we want to see in report. */ + //OptFlds [0] = 0; + /* These options valid for IEC BRCB, IEC URCB, or UCA. */ + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_SQNUM); + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_TIMESTAMP); + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_REASON); + //BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_DATSETNAME); + /* NOTE: these options ONLY available for IEC-61850 (not UCA) + * SUBSEQNUM is only set by the server, so don't try to set it. + */ + if (rcb_info->rcb_type == RCB_TYPE_IEC_BRCB) + { /* These only valid for IEC BRCB */ + // BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_BUFOVFL); + BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_ENTRYID); + if ((pEntryID[0] != 0xff) || (pEntryID[1] != 0xff) || (pEntryID[2] != 0xff) || (pEntryID[3] != 0xff) + || (pEntryID[4] != 0xff) || (pEntryID[5] != 0xff) || (pEntryID[6] != 0xff) || (pEntryID[7] != 0xff)) + mms_rcb_setEntryID(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut, pEntryID); + } + //if (rcb_info->rcb_type != RCB_TYPE_UCA) + // { /* These only valid for IEC BRCB or IEC URCB */ + // BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_DATAREF); + // BSTR_BIT_SET_ON(OptFlds, OPTFLD_BITNUM_CONFREV); + // } + + TrgOps[0] = trgops; + ret = rcb_enable(clientNetInfo, dom_name, rcb_name, OptFlds, TrgOps, + scanRate * 1000, /* Integrity Period (ms) */ + rpt_typeids, + timeOut); /* timeout (s) */ + + if (ret == SD_SUCCESS) + { + list_add_last(&((ALL_RCB_INFO *)clientNetInfo->user_info)->rcb_info_list, rcb_info); /* add RCB to list*/ + } + else { + rcb_info_destroy(rcb_info); + rcb_info = NULL; + echo_warn2("rcb_enable error for dom='%s', rcb='%s'\n", dom_name, rcb_name); + } + } + else + { + printf("rcb_info_create error for dom='%s', rcb='%s'\n", dom_name, rcb_name); + rcb_info = NULL; + } + return (rcb_info); +} + +ST_RET mms_unregister_iec_rpt_by_devtype(MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, ST_CHAR *dev_type, ST_CHAR *ip, int port, + ST_CHAR *dom_name, ST_CHAR *rcb_name, + ST_INT timeOut) +{ + + ST_BOOLEAN RptEna = 0; + ST_CHAR varName[MAX_IDENT_LEN + 1]; + ST_RET ret; //ִзֵ + + //һװͲж--------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindDevType = 0; //Ƿвҵװ + Dev_RCB_INFO *dev_rcb = NULL;//װñṹָ + for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //ٱ ȫװñƿ + { + //LOG_INFO("(ֹͣ)gDev_rcb_list, dev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:16:31 + if ((strcmp(dev_rcb->dev_type_name, dev_type) == 0)) //ƥ װ + { + bFindDevType = 1; //ҵװ + //LOG_INFO("(ֹͣ)ƥ䵽װͣdev_type_name= %s", dev_rcb->dev_type_name); //ʹã zl 2019-12-24 00:23:55 + break; + } + } // װ + + if (!bFindDevType) //δҵװ + { + dev_rcb = (Dev_RCB_INFO *)chk_calloc(1, sizeof(Dev_RCB_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New + //memset(dev_rcb, 0, sizeof(Dev_RCB_INFO)); //ָ 0 + strcpy(dev_rcb->dev_type_name, dev_type); //װ + list_add_last(&gDev_rcb_list.dev_rcb_info_Head, dev_rcb); // ȫװñƿ + } + + //װIP˿ںŲж--------------------------------------------------------------------------------------------------------------------------------------------------- + ST_BOOLEAN bFindIpPort = 0; //ǷвҵװIP˿ں + Dev_IP_Port_INFO *dev_info = NULL; //װIP˿ںŽṹָ + for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //ڱ ȫװIP˿ + { + //LOG_INFO("(ֹͣ)dev_ip_port_list, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:16:31 + if ((strcmp(dev_info->IP, ip) == 0) && (dev_info->Port == port)) //ƥ װIP && ˿ں + { + bFindIpPort = 1; //ҵװIP && ˿ں + //LOG_INFO("(ֹͣ)ƥ䵽װdev_type_name= %s, IP= %s Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //ʹã zl 2019-12-24 00:23:55 + break; + } + } // װIP˿ + if (!bFindIpPort) //δҵװIP˿ + { + dev_info = (Dev_IP_Port_INFO *)chk_calloc(1, sizeof(Dev_IP_Port_INFO)); // ڴռ䣬ʼΪ0׵ַָ룬൱New + //memset(dev_info, 0, sizeof(Dev_IP_Port_INFO)); //ָ 0 + strcpy(dev_info->IP, ip); //װIP + dev_info->Port = port; //˿ں + list_add_last(&dev_rcb->dev_ip_port_list, dev_info); // ȫװñƿ->װIP˿ + } + + //װñƿж---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + RCB_INFO *rcb_info = NULL; //ƿָ + ST_BOOLEAN bFindRCB = 0; //Ƿװñƿвҵ + for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //۱ ȫװñƿ->ƿϢ + { + //LOG_INFO("(ֹͣ)rcb_info_list, RptID= %sdom_Name= %sdom= %srcb_name= %srpt= %s", rcb_info->RptID, rcb_info->dom_Name, dom, rcb_info->rcb_name, rpt); //ʹã zl 2018-10-17 21:19:36 + //if ((strcmp (rcb_info->rcb_name, rpt) == 0) && (strcmp(rcb_info->dom_Name, dom) == 0)) //ƥ װñƿ zl 2019-12-26 17:27:29 + if ((strcmp(rcb_info->rcb_name, rcb_name) == 0)) //ƥ װñƿ + { + bFindRCB = 1; //ҵװñƿ + //LOG_INFO("(ֹͣ)ƥ䵽ƿdom= %srcb= %sѴ", dom, rpt); //ʹã zl 2019-3-13 14:24:43 + break; /* rcb_info now points to right structure */ + } + } + if (!bFindRCB) //δҵװñƿ + { + rcb_info = rcb_info_create(clientNetInfo, dom_name, rcb_name, rpt_typeids, timeOut); // װñƿ >> עúΪʱװ͵ıƿѴٽд + if (rcb_info == NULL) { + //LOG_INFO("(ֹͣ)ƿʧܣdom= %srcb= %s", dom, rpt); //ʹã zl 2019-3-13 14:24:43 + return SD_FAILURE; + } + else { + //LOG_INFO("(ֹͣ)ƿɹȫֱƿdom= %srcb= %s", dom, rpt); //ʹã zl 2019-3-13 14:24:43 + list_add_last(&dev_rcb->rcb_info_list, rcb_info); // ȫֱƿ->ƿϢ + } + } + + sprintf(varName, "%s$RptEna", rcb_name); //ֹͣ LLN0$BR$brcbStatisticData03$RptEna + ret = mms_named_var_write(clientNetInfo, varName, DOM_SPEC, dom_name, rpt_typeids->mmsbool, (ST_CHAR *)&RptEna, timeOut); // дװñƿ(ֹͣ) + + return ret; + +} +//WW 2023-08-29 end +//////////////////////////////////// +ST_RET mms_unregister_iec_rpt (MVL_NET_INFO *clientNetInfo, RPT_TYPEIDS *rpt_typeids, + ST_CHAR *dom_name, ST_CHAR *rcb_name, + ST_INT timeOut ) + { + ST_RET ret; + RCB_INFO *rcb_info; + RCB_INFO* this_rcb_info; + + this_rcb_info = FindRcbInfo(clientNetInfo,dom_name,rcb_name ); + + ret = rcb_disable(clientNetInfo, dom_name, rcb_name,rpt_typeids,timeOut); + // remove the if condition + ALL_RCB_INFO *all_rcb_info = (ALL_RCB_INFO *)clientNetInfo->user_info ; + for (rcb_info = all_rcb_info->rcb_info_list; + rcb_info != NULL; + rcb_info = (RCB_INFO *) list_get_next (all_rcb_info->rcb_info_list, rcb_info)) + { + if( rcb_info == this_rcb_info ) + { + ret = list_unlink(&all_rcb_info->rcb_info_list, rcb_info); + if(ret == SD_SUCCESS) + { + rcb_info_destroy(rcb_info); + return ret; + } + } + } + + return SD_FAILURE; + } + + +/************************************************************************/ +/* doCommService */ +/************************************************************************/ + +ST_VOID doCommService () + { +#if defined (MOSI) /* If stack is MOSI, use events */ + wait_any_event (50); /* Wait 50 milliseconds */ + while (mvl_comm_serve ()) /* Perform communications service */ + { /* Loop until "mvl_comm_serve" returns 0*/ + } +#else + mvl_comm_serve (); /* Perform communications service */ +#endif + } + + + + +/************************************************************************/ +/* connectToServer */ +/************************************************************************/ + +// ַǷΪաո򲻿ɼַlnk20241119 +int is_empty_or_whitespace(const char* str) { + if (str == NULL) { + return 1; // NULL Ϊ"" + } + while (*str) { + if (!isspace((unsigned char)*str)) { + return 0; // зǿոַ"" + } + str++; + } + return 1; // ȫǿո򲻿ɼַΪ"" +} + +ST_RET mms_connectToServer (ST_CHAR * dev_key,ST_CHAR *dev_series, ST_CHAR *serverARName, + MVL_NET_INFO **clientNetInfo, MVL_REQ_PEND **reqCtrl) + { + +ST_RET ret; + +#if defined(S_SEC_ENABLED) || defined(ACSE_AUTH_ENABLED) +ST_CHAR ied_password[256]; +ACSE_AUTH_INFO authInfoStr = {0}; +#endif +#if defined(S_SEC_ENABLED) +S_SEC_ENCRYPT_CTRL encryptCtrlStr = {0}; +S_SEC_LOC_AR *loc_ar_sec = NULL; +S_SEC_REM_AR *rem_ar_sec = NULL; +#endif +ACSE_AUTH_INFO *authInfo = NULL; /* conn authentication info */ +S_SEC_ENCRYPT_CTRL *encryptCtrl = NULL; /* conn enctryption info */ + + callingInitInfo.mms_p_context_pres = SD_TRUE; + callingInitInfo.max_segsize_pres = SD_TRUE; + callingInitInfo.max_segsize = mvl_cfg_info->max_msg_size; + callingInitInfo.maxreq_calling = 1; + callingInitInfo.maxreq_called = 1; + callingInitInfo.max_nest_pres = SD_TRUE; + callingInitInfo.max_nest = 5; + callingInitInfo.mms_detail_pres = SD_TRUE; + callingInitInfo.version = 1; + callingInitInfo.num_cs_init = 0; + callingInitInfo.core_position = 0; + callingInitInfo.param_supp[0] = m_param[0]; + callingInitInfo.param_supp[1] = m_param[1]; + memcpy (callingInitInfo.serv_supp, m_service_resp,11); + +#if defined(S_SEC_ENABLED) + authInfo = &authInfoStr; + encryptCtrl = &encryptCtrlStr; + /* set authentication and encryption infor for this connection */ + ret = ulSetSecurityCalling (clientARName, serverARName, + &loc_ar_sec, &rem_ar_sec, + authInfo, encryptCtrl); + if (ret != SD_SUCCESS)9 + { + printf ("\n Initialization of security info failed"); + return (NULL); /* error */ + } +#elif defined(ACSE_AUTH_ENABLED) + if (g_no_auth==0) { + /* Fill out an authentication structure */ + //authInfo = &authInfoStr; + //authInfo->auth_pres = SD_TRUE; + //authInfo->mech_type = ACSE_AUTH_MECH_PASSWORD; + //memset(ied_password,0,sizeof(ied_password)); + + //lnk20241119жϺʹӡȷʶԿΪʱü + if (!is_empty_or_whitespace(dev_series) || !is_empty_or_whitespace(dev_key)) { + printf("dev_series= %s\n", dev_series); + printf("dev_key= %s\n", dev_key); + /* Fill out an authentication structure */ + authInfo = &authInfoStr; + authInfo->auth_pres = SD_TRUE; + authInfo->mech_type = ACSE_AUTH_MECH_PASSWORD; + memset(ied_password,0,sizeof(ied_password)); + GetSM4Code((unsigned char*)dev_series,dev_key,ied_password); + strcpy (authInfo->u.pw_auth.password, ied_password); + } else { + printf("dev_series or dev_key is null or space!\n"); + } + + //GetSM4Code((unsigned char*)dev_series,dev_key,ied_password); + //strcpy (authInfo->u.pw_auth.password, ied_password); + + //cout<<"old password:"<< ied_password <u.pw_auth.password, "7a88179802378762611182956231b315"); /* this is the password */ + + } +#endif /* defined(ACSE_AUTH_ENABLED) */ + +// *reqCtrl = NULL; + *clientNetInfo = NULL; + ret = mvla_initiate_req_ex (serverARName, &callingInitInfo, + &initRespInfo, clientNetInfo, reqCtrl, + authInfo, encryptCtrl); + if (ret == SD_SUCCESS) + { +#if defined(S_SEC_ENABLED) + /* Save the AR Security pointers, for convenience when the confirm is rxd */ + clientNetInfo->loc_ar_sec = loc_ar_sec; + clientNetInfo->rem_ar_sec = rem_ar_sec; +#endif +// ret = waitReqDone (reqCtrl, 60); /* need to wait longer on connect */ + + } + if (ret != SD_SUCCESS) *clientNetInfo = NULL; + + //printf ("\n %s clientNetInfo = 0x%x ,ret =0x%X ",serverARName,*clientNetInfo,ret); +#if defined(S_SEC_ENABLED) + ulFreeAssocSecurity (authInfo); /* free local auth info, not needed anymore */ +#endif + +// mvl_free_req_ctrl (reqCtrl); + return ret; + } + +/************************************************************************/ +/* disconnectFromServer */ +/************************************************************************/ + +ST_RET mms_disconnectFromServer (MVL_NET_INFO *clientNetInfo,MVL_REQ_PEND **reqCtrl) + { + ST_RET ret; + echo_warn1( "mms_disconnectFromServer clientNetInfo= %x \n",clientNetInfo); + ret = mvla_concl (clientNetInfo, reqCtrl); + //waitReqDone (*reqCtrl, 0); + //mvl_free_req_ctrl (*reqCtrl); + return ret; + } + +ST_RET mms_release_connection (MVL_NET_INFO *clientNetInfo) + { + echo_warn1( "mms_release_connection NetInfo= %x \n",clientNetInfo); + mvl_abort_req(clientNetInfo); + return SD_SUCCESS; + } + + +/************************************************************************/ +/* u_mvl_info_rpt_ind */ +/************************************************************************/ + + +ST_VOID u_mvl_info_rpt_ind (MVL_COMM_EVENT *event) + { + //printf(" ST_VOID u_mvl_info_rpt_ind (MVL_COMM_EVENT *event) \n"); + //printf(" %d \n",event->net_info);//->rem_ar_sec->arName); +INFO_REQ_INFO *info_ptr; +ST_INT j; +OBJECT_NAME *vobj; +VARIABLE_LIST *vl; +VAR_ACC_SPEC *va_spec; + +//MVL_VAR_ASSOC *va; +ST_INT num_va; +ST_CHAR *name; + + /* Assume this is an IEC-61850/UCA report, and try to process it. + * If processing successful, then skip other processing. + */ +//WW 2023-08-30 + if (u_iec_rpt_ind (event) == SD_SUCCESS) +// if (u_iec_rpt_ind_by_devtype(event) == SD_SUCCESS) + return; /* this funct processed it. Skip other processing. */ +//WW 2023-08-30 end +/* We want to get a table of pointers to VARIABLE_ASSOCIATIONS so we */ +/* can convert the received data to local format. */ + + info_ptr = (INFO_REQ_INFO *) event->u.mms.dec_rslt.data_ptr; + va_spec = &info_ptr->va_spec; + num_va = info_ptr->num_of_acc_result; + + if (va_spec->var_acc_tag == VAR_ACC_NAMEDLIST) + { + printf ("Unrecognized Report received with NamedVariableList='%s'. Ignored.\n", + va_spec->vl_name.obj_name.vmd_spec); + } + else if (va_spec->var_acc_tag == VAR_ACC_VARLIST) + { + vl = (VARIABLE_LIST *) (info_ptr + 1); + + for (j = 0; j < num_va; ++j, ++vl) + { + printf (" Recognized Report received with NamedVariable "); + if (vl->var_spec.var_spec_tag == VA_SPEC_NAMED) + { + vobj = &vl->var_spec.vs.name; + name = vobj->obj_name.vmd_spec; + printf (" var name= %s \n ",name); + + if (!strcmp (name, my_control_info.oper_name) && vobj->object_tag == DOM_SPEC) + { + /* This is IEC 61850 CommandTermination. Save num of vars. */ + my_control_info.cmd_term_num_va = num_va; + } + } + else + { + printf ("InfoRpt Ind : VA Spec not named \n"); + } + } + } /* end if VAR_ACC_VARLIST */ + + } + + +/************************************************************************/ +/* u_mvl_connect_ind_ex */ +/*----------------------------------------------------------------------*/ +/* This function is called when a remote node has connected to us. We */ +/* can look at the assReqInfo to see who it is (assuming that the */ +/* AP-Titles are used), or at the cc->rem_init_info to see initiate */ +/* request parameters. */ +/************************************************************************/ +extern ST_ACSE_AUTH u_mvl_connect_ind_ex (MVL_NET_INFO *cc, INIT_INFO *init_info, + ACSE_AUTH_INFO *req_auth_info, ACSE_AUTH_INFO *rsp_auth_info) +{ + ST_ACSE_AUTH ret = ACSE_AUTH_SUCCESS; + +#if defined(S_SEC_ENABLED) + /* this Client will reject the connection since there is no security */ + /* checking code in place (see Server for sample) */ + ret = ACSE_DIAG_NO_REASON; +#elif defined(ACSE_AUTH_ENABLED) + /* this Client will reject the connection since there is no password */ + /* checking code in place (see Server for sample) */ + if (g_no_auth==0) + ret = ACSE_DIAG_NO_REASON; + else + return (ret); + +#endif + + return (ret); +} + +/************************************************************************/ +/* u_mvl_connect_cnf_ex */ +/*----------------------------------------------------------------------*/ +/* This function is called when we have received an initiate response. */ +/* Depending on the server's authentication scheme, we may have been */ +/* sent responding authentication that we can pull out of the response */ +/* PDU. */ +/************************************************************************/ + +ST_ACSE_AUTH u_mvl_connect_cnf_ex (MVL_NET_INFO *cc, AARE_APDU *ass_rsp_info) +{ + ST_RET ret = ACSE_AUTH_SUCCESS; + +#if defined(S_SEC_ENABLED) + /* check security parameters of the Associate Confirm */ + ret = ulCheckSecureAssocConf (cc); +#elif defined(ACSE_AUTH_ENABLED) + if (g_no_auth==0) + { + ACSE_AUTH_INFO *rsp_auth_info; + + rsp_auth_info = &ass_rsp_info->auth_info; + + + if(rsp_auth_info->auth_pres == SD_TRUE) + { + /* Looks like we have some authentication to look at, simply print */ + /* the password and continue as normal. */ + if(rsp_auth_info->mech_type == ACSE_AUTH_MECH_PASSWORD) + { + //printf("\nPassword recieved from peer: %s\n", rsp_auth_info->u.pw_auth.password); + } + /* We were sent a mechanism we don't support, let's reject the */ + /* the connection with the appropriate diagnostic. */ + else + { + ret = ACSE_DIAG_AUTH_MECH_NAME_NOT_RECOGNIZED; + } + } + else + { + /* Hmm... looks like we weren't sent any authentication even though */ + /* we require it. Let's reject with the appropriate diagnostic. */ + ret = ACSE_AUTH_SUCCESS;//ww 2024-01-09 ACSE DIAG AUTH REQUIRED + } + } +#endif /* defined(ACSE_AUTH_ENABLED) */ + + /* to accept the confirm ACSE_AUTH_SUCCESS need to be returned */ + return ((ST_ACSE_AUTH) ret); +} + + +/************************************************************************/ +/* disc_ind_fun */ +/************************************************************************/ +/* This function is called when connection is terminated. */ + +static ST_VOID disc_ind_fun (MVL_NET_INFO *cc, ST_INT discType) + { + +ALL_RCB_INFO *all_rcb_info; +RCB_INFO *rcb_info; + + printf("disc_ind_fun clientNetInfo= 0x%x discType=%i\n",cc,discType); + Callback_channel_disconnect_ind(cc, discType); + + /* Free up rcb_info if necessary. */ + if (cc->user_info) + { + all_rcb_info = (ALL_RCB_INFO*)cc->user_info; + while ((rcb_info =(RCB_INFO*) list_get_first (&all_rcb_info->rcb_info_list)) != NULL) + rcb_info_destroy (rcb_info); + chk_free (all_rcb_info); + cc->user_info=NULL; + } + + cc->rem_vmd = NULL; + + + } + +#if (MMS_IDENT_EN & RESP_EN) +/************************************************************************/ +/* u_mvl_ident_ind */ +/************************************************************************/ +ST_VOID u_mvl_ident_ind (MVL_IND_PEND *indCtrl) + { +//#if 0 /* enable this to print when Ind received */ + printf ("\n Identify Indication received."); +//#endif + indCtrl->u.ident.resp_info = &identify_response_info; + mplas_ident_resp (indCtrl); + } +#endif /* #if (MMS_IDENT_EN & RESP_EN) */ + +/************************************************************************/ +/* getFile */ +/************************************************************************/ +ST_RET mms_getFile (MVL_NET_INFO *clientNetInfo, ST_CHAR *loc_file, + ST_CHAR *rem_file, ST_INT iTimeout) +{ + FREAD_REQ_INFO fread_req_info; + FCLOSE_REQ_INFO fclose_req_info; + ST_RET ret; + FILE *loc_fp; + MVL_REQ_PEND *reqCtrl; + ST_INT32 frsmid; + ST_BOOLEAN more_follows; + + ret = mvla_fopen (clientNetInfo, + rem_file, + 0, /* init_pos: start at beginning of file */ + &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + + if (ret == SD_SUCCESS) + frsmid = reqCtrl->u.fopen.resp_info->frsmid; /* save frsmid */ + mvl_free_req_ctrl (reqCtrl); + if (ret != SD_SUCCESS) + return (ret); + + loc_fp = fopen (loc_file, "wb"); + if (loc_fp == NULL) + goto ERR; + + fread_req_info.frsmid = frsmid; /* "fread" request doesn't chg. */ + do + { + ret = mvla_fread (clientNetInfo, &fread_req_info, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret == SD_SUCCESS) + { + more_follows = reqCtrl->u.fread.resp_info->more_follows; + fwrite (reqCtrl->u.fread.resp_info->filedata, 1, + reqCtrl->u.fread.resp_info->fd_len, loc_fp); + } + mvl_free_req_ctrl (reqCtrl); + if (ret != SD_SUCCESS) + goto ERR; + } while (more_follows); + + fclose_req_info.frsmid = frsmid; + ret = mvla_fclose (clientNetInfo, &fclose_req_info, &reqCtrl); + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, iTimeout); + if (ret != SD_SUCCESS) + printf ("\n mvl_fclose failed, ret = 0x%X", ret); + mvl_free_req_ctrl (reqCtrl); + + fclose (loc_fp); + return (SD_SUCCESS); + +ERR: + if (loc_fp == NULL) { + return (SD_FAILURE); /* Can't open local file. */ + } else { + fclose(loc_fp); + return (ret); + } +} + + +/************************************************************************/ +/* init_mem */ +/************************************************************************/ + +static ST_VOID mem_chk_error_detected (ST_VOID); +static ST_VOID *my_malloc_err (ST_UINT size); +static ST_VOID *my_calloc_err (ST_UINT num, ST_UINT size); +static ST_VOID *my_realloc_err (ST_VOID *old, ST_UINT size); + +static ST_CHAR *spareMem; + +static ST_VOID init_mem () + { +#if defined(NO_GLB_VAR_INIT) + mvl_init_glb_vars (); +#endif + +/* Allocate spare memory to allow logging/printing memory errors */ + spareMem = (ST_CHAR *) malloc (500); + +/* trap mem_chk errors */ + mem_chk_err = mem_chk_error_detected; + m_memerr_fun = my_malloc_err; + c_memerr_fun = my_calloc_err; + r_memerr_fun = my_realloc_err; + +#if 0 + m_heap_check_enable = SD_TRUE; + m_check_list_enable = SD_TRUE; + m_no_realloc_smaller = SD_TRUE; + m_fill_en = SD_TRUE; +#endif + m_mem_debug = SD_TRUE; + } + +/************************************************************************/ +/* This function is called from the DEBUG version of the mem library */ +/* when an error of any type is detected. */ +/************************************************************************/ + +static ST_INT memErrDetected; + +static ST_VOID mem_chk_error_detected (ST_VOID) + { + if (!memErrDetected) + { + free (spareMem); + memErrDetected = SD_TRUE; + printf ("\n Memory Error Detected!"); + dyn_mem_ptr_status (); + } + } + +/************************************************************************/ +/* Memory Allocation Error Handling Functions. */ +/* These functions are called from mem_chk when it is unable to */ +/* perform the requested operation. These functions must either return */ +/* a valid buffer or not return at all. */ +/************************************************************************/ + +static ST_VOID *my_malloc_err (ST_UINT size) + { + mem_chk_error_detected (); + printf ("\n Malloc"); + exit (2); + return (NULL); + } + +static ST_VOID *my_calloc_err (ST_UINT num, ST_UINT size) + { + mem_chk_error_detected (); + exit (3); + return (NULL); + } + +static ST_VOID *my_realloc_err (ST_VOID *old, ST_UINT size) + { + mem_chk_error_detected (); + exit (4); + return (NULL); + } + +///////////////////////////////////////////////////////////////////////// +//#define MAX_FILE_HANDLE_NUM (256) +//static FILE *fp_arr[MAX_FILE_HANDLE_NUM]; +//static ST_INT32 cur_handle = 0; +//ST_INT32 set_file_pointer( FILE *fp) +//{ +// ST_INT32 the_handle = cur_handle; +// fp_arr[cur_handle++] = fp; +// cur_handle %= MAX_FILE_HANDLE_NUM; +// return the_handle; +//} +//FILE* get_file_pointer(ST_INT32 handle) +//{ +// return fp_arr[handle]; +//} +/////////////////////////////////////////////////////////////////////// + +#if (MMS_FOPEN_EN & RESP_EN) +/************************************************************************/ +/* u_mvl_fopen_ind */ +/************************************************************************/ +ST_VOID u_mvl_fopen_ind (MVL_IND_PEND *indCtrl) + { +//FILE *fp; +//FOPEN_RESP_INFO resp_info; +//struct stat stat_buf; + + //fp = fopen (indCtrl->u.fopen.filename, "rb"); /* CRITICAL: use "b" flag for binary transfer*/ + //if (fp == NULL) + // { + // _mplas_err_resp (indCtrl,11,6); /* File-access denied */ + // return; + // } + //if (fseek (fp, indCtrl->u.fopen.init_pos, SEEK_SET)) + // { + // _mplas_err_resp (indCtrl,11,5); /* Position invalid */ + // return; + // } + + ///* WARNING: this only works if (FILE *) is a 32-bit pointer. */ + //resp_info.frsmid = set_file_pointer(fp); //(ST_INT32) fp; + + //if (fstat (fileno (fp), &stat_buf)) + // { /* Can't get file size or time */ + // _mplas_err_resp (indCtrl,11,0); /* File Problem, Other */ + // return; + // } + //else + // { + // resp_info.ent.fsize = stat_buf.st_size; + // resp_info.ent.mtimpres = SD_TRUE; + // resp_info.ent.mtime = stat_buf.st_mtime; + // } + + //indCtrl->u.fopen.resp_info = &resp_info; + //mplas_fopen_resp (indCtrl); + } +#endif /* MMS_FOPEN_EN & RESP_EN */ + + +#if (MMS_FREAD_EN & RESP_EN) +/************************************************************************/ +/* u_mvl_fread_ind */ +/************************************************************************/ +ST_VOID u_mvl_fread_ind (MVL_IND_PEND *indCtrl) + { +//FILE *fp; +//ST_UCHAR *tmp_buf; +//MVLAS_FREAD_CTRL *fread_ctrl = &indCtrl->u.fread; +//FREAD_RESP_INFO resp_info; + + //fp = get_file_pointer(fread_ctrl->req_info->frsmid);// (FILE *) fread_ctrl->req_info->frsmid; + ///* Do NOT read more than "max_size". */ + //tmp_buf = (ST_UCHAR *) chk_malloc (fread_ctrl->max_size); + + //resp_info.fd_len = fread (tmp_buf, 1, fread_ctrl->max_size, fp); + //if (resp_info.fd_len == 0 && ferror (fp)) + // { + // _mplas_err_resp (indCtrl, 3, 0); + // return; + // } + + //resp_info.filedata = tmp_buf; + //if (resp_info.fd_len == fread_ctrl->max_size) + // resp_info.more_follows = SD_TRUE; + //else + // resp_info.more_follows = SD_FALSE; + + //fread_ctrl->resp_info = &resp_info; + //mplas_fread_resp (indCtrl); + //chk_free (tmp_buf); /* Temporary buffer */ + } +#endif /* #if (MMS_FREAD_EN & RESP_EN) */ + +#if (MMS_FCLOSE_EN & RESP_EN) +/************************************************************************/ +/* u_mvl_fclose_ind */ +/************************************************************************/ +ST_VOID u_mvl_fclose_ind (MVL_IND_PEND *indCtrl) + { +//FILE *fp; +//MVLAS_FCLOSE_CTRL *fclose_ctrl = &indCtrl->u.fclose; + + //fp = get_file_pointer(fclose_ctrl->req_info->frsmid);//(FILE *) fclose_ctrl->req_info->frsmid; + + //if (fclose (fp)) + // _mplas_err_resp (indCtrl, 11, 0); /* File problem, other */ + //else + // mplas_fclose_resp (indCtrl); + } +#endif /* #if (MMS_FCLOSE_EN & RESP_EN) */ + +/************************************************************************/ +/* waitReqDone */ +/*----------------------------------------------------------------------*/ +/* Wait for request to complete. Service communications while waiting. */ +/* Check for timeout or Ctrl-C (i.e. doIt=SD_FALSE). */ +/* NOTE: if other processing should be done while waiting, add it to */ +/* this function. */ +/* Parameters: */ +/* req request to wait for. */ +/* timeout time to wait (seconds). 0 means wait forever. */ +/* RETURNS: SD_SUCCESS, MVL_ERR_USR_TIMEOUT or other MVL error code. */ +/************************************************************************/ +ST_RET waitReqDone (MVL_REQ_PEND *req, ST_INT timeout) +{ + ST_DOUBLE stopTime = sGetMsTime() + (ST_DOUBLE) timeout * 1000.0; + while (req->done == SD_FALSE) /* wait until done */ + { + if (timeout != 0 && sGetMsTime() > stopTime) + { + req->result = MVL_ERR_USR_TIMEOUT; + MVL_LOG_ERR1 ("MMS request (opcode = %d) timed out", req->op); + break; + } + doCommService(); /* wait for events if possible & call mvl_comm_serve*/ + } /* end loop */ + return (req->result); +} + + +void doCommForSecs (ST_INT timeout) +{ + ST_DOUBLE stopTime = sGetMsTime() + (ST_DOUBLE) timeout * 1000.0; + while ( sGetMsTime() < stopTime) + { + doCommService(); /* wait for events if possible & call mvl_comm_serve*/ + } +} + +/************************************************************************/ +/* named_var_read */ +/* Read a single named variable. */ +/* scope = VMD_SPEC, DOM_SPEC, or AA_SPEC */ +/* CRITICAL: the local variable "parse_info" is written indirectly */ +/* from waitReqDone when the response is received. The call */ +/* to "waitReqDone" MUST NOT be moved outside this function. */ +/************************************************************************/ +ST_RET mms_named_var_read (MVL_NET_INFO *net_info, ST_CHAR *varName, + ST_INT scope, ST_CHAR *domName, + ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut) + { +ST_INT num_data; +ST_CHAR buffer[512]; +MVL_READ_RESP_PARSE_INFO parse_info; +READ_REQ_INFO *req_info; +VARIABLE_LIST *vl; +ST_INT ret; +MVL_REQ_PEND *reqCtrl; + + /* Create a read request info struct */ + req_info = (READ_REQ_INFO *) buffer; + req_info->spec_in_result = SD_FALSE; + req_info->va_spec.var_acc_tag = VAR_ACC_VARLIST; + req_info->va_spec.num_of_variables = 1; + vl = (VARIABLE_LIST *) (req_info + 1); + + vl->alt_access_pres = SD_FALSE; + vl->var_spec.var_spec_tag = VA_SPEC_NAMED; + vl->var_spec.vs.name.object_tag = scope; /* set scope */ + if (scope == DOM_SPEC) + vl->var_spec.vs.name.domain_id = domName; /* set domain name */ + vl->var_spec.vs.name.obj_name.vmd_spec = varName; + + num_data = 1; /* Number of named variables returned */ + + /* IMPORTANT: start with clean structure, then set appropriate elements.*/ + memset (&parse_info, 0, sizeof (parse_info)); + parse_info.dest = dataDest; + parse_info.type_id = type_id; + parse_info.descr_arr = SD_FALSE; + + /* Send read request. */ + ret = mvla_read_variables (net_info,req_info,num_data, + &parse_info, &reqCtrl); + + /* If request sent successfully, wait for reply. */ + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, timeOut); + + mvl_free_req_ctrl (reqCtrl); + if (ret != SD_SUCCESS) + return (ret); + + return (parse_info.result); /* Return the single variable result */ + } +/************************************************************************/ +/* mms_named_var_write */ +/* Write a single named variable. */ +/* scope = VMD_SPEC, DOM_SPEC, or AA_SPEC */ +/* CRITICAL: the local variable "wr_info" is written indirectly */ +/* from waitReqDone when the response is received. The call */ +/* to "waitReqDone" MUST NOT be moved outside this function. */ +/************************************************************************/ +ST_RET mms_named_var_write (MVL_NET_INFO *netInfo, ST_CHAR *varName, + ST_INT scope, ST_CHAR *domName, + ST_INT type_id, ST_VOID *dataSrc, ST_INT timeOut) + { +ST_CHAR buffer[512]; +MVL_WRITE_REQ_INFO *wr_info; +WRITE_REQ_INFO *req_info; +VARIABLE_LIST *vl; +ST_RET ret; +MVL_REQ_PEND *reqCtrl; + + req_info = (WRITE_REQ_INFO *) buffer; + req_info->num_of_data = 1; + req_info->va_spec.var_acc_tag = VAR_ACC_VARLIST; + req_info->va_spec.num_of_variables = 1; + vl = (VARIABLE_LIST *) (req_info + 1); + + vl->alt_access_pres = SD_FALSE; + vl->var_spec.var_spec_tag = VA_SPEC_NAMED; + vl->var_spec.vs.name.object_tag = scope; /* set scope */ + if (scope == DOM_SPEC) + vl->var_spec.vs.name.domain_id = domName; /* set domain name */ + vl->var_spec.vs.name.obj_name.vmd_spec = varName; + + /* Alloc array of structs. Here only one var so alloc one struct. */ + /* To read multiple vars, allocate more. */ + /* CRITICAL: response code writes to this struct. Do not free until */ + /* response received. */ + wr_info = (MVL_WRITE_REQ_INFO*)chk_calloc (1, sizeof (MVL_WRITE_REQ_INFO)); + + wr_info->local_data = dataSrc; + wr_info->type_id = type_id; + wr_info->arr = SD_FALSE; + + /* Send write request. */ + ret = mvla_write_variables (netInfo, req_info, 1, wr_info, &reqCtrl); + + /* If request sent successfully, wait for response. */ + if (ret == SD_SUCCESS) + ret = waitReqDone (reqCtrl, timeOut); + + mvl_free_req_ctrl (reqCtrl); + if (ret == SD_SUCCESS) /* response received OK. */ + ret = wr_info->result; /* return single variable result */ + chk_free (wr_info); + + return (ret); + } + + +/************************************************************************/ +/* init_log_cfg */ +/************************************************************************/ + +#define HARD_CODED_CFG + +#ifdef DEBUG_SISCO +ST_VOID init_log_cfg (ST_VOID) + { + static char log_filename[256]; +#if defined (HARD_CODED_CFG) +/* Use File logging */ + sLogCtrl->logCtrl = LOG_FILE_EN; + +/* Use time/date time log */ + sLogCtrl->logCtrl |= (LOG_DIFFTIME_EN | LOG_TIME_EN); + +/* File Logging Control defaults */ +#ifdef _OS_UNIX_ + apr_snprintf(log_filename,sizeof(log_filename),"/usr/local/saslog/pt61850netd_pqfe_%d.log",g_node_id); +#else + apr_snprintf(log_filename,sizeof(log_filename),"../etc/log/pt61850netd_pqfe_%d.log",g_node_id); +#endif + sLogCtrl->fc.fileName = log_filename; + + sLogCtrl->fc.maxSize = 50000000L; // 50M + sLogCtrl->fc.ctrl = (FIL_CTRL_WIPE_EN | + FIL_CTRL_WRAP_EN | +// FIL_CTRL_NO_APPEND | + FIL_CTRL_MSG_HDR_EN); + + mms_debug_sel |= MMS_LOG_ERR; + mms_debug_sel |= MMS_LOG_NERR; +// mms_debug_sel |= MMS_LOG_DEC; +// mms_debug_sel |= MMS_LOG_ENC; + + mvl_debug_sel |= MVLLOG_ERR; + mvl_debug_sel |= MVLLOG_NERR; + + mvl_debug_sel |= MVLLOG_ACSE; +#if 0 + mvl_debug_sel |= MVLLOG_ACSEDATA; + mvl_debug_sel |= MVLLOG_TIMING; +#endif + + acse_debug_sel |= ACSE_LOG_ERR; +#if 0 + acse_debug_sel |= ACSE_LOG_ENC; + acse_debug_sel |= ACSE_LOG_DEC; + acse_debug_sel |= COPP_LOG_ERR; + acse_debug_sel |= COPP_LOG_DEC; + acse_debug_sel |= COPP_LOG_DEC_HEX; + acse_debug_sel |= COPP_LOG_ENC; + acse_debug_sel |= COPP_LOG_ENC_HEX; + acse_debug_sel |= COSP_LOG_ERR; + acse_debug_sel |= COSP_LOG_DEC; + acse_debug_sel |= COSP_LOG_DEC_HEX; + acse_debug_sel |= COSP_LOG_ENC; + acse_debug_sel |= COSP_LOG_ENC_HEX; +#endif + + + tp4_debug_sel |= TP4_LOG_ERR; +#if 0 + tp4_debug_sel |= TP4_LOG_FLOWUP; + tp4_debug_sel |= TP4_LOG_FLOWDOWN; +#endif + +#if !defined(REDUCED_STACK) + clnp_debug_sel |= CLNP_LOG_ERR; + clnp_debug_sel |= CLNP_LOG_NERR; + +#if 0 + clnp_debug_sel |= CLNP_LOG_REQ; + clnp_debug_sel |= CLNP_LOG_IND; + clnp_debug_sel |= CLNP_LOG_ENC_DEC; + clnp_debug_sel |= CLNP_LOG_LLC_ENC_DEC; + clnp_debug_sel |= CLSNS_LOG_REQ; + clnp_debug_sel |= CLSNS_LOG_IND; +#endif +#endif + +#else /* !defined (HARD_CODED_CFG) */ +#if defined(S_SEC_ENABLED) + logCfgAddMaskGroup (&secLogMaskMapCtrl); + logCfgAddMaskGroup (&ssleLogMaskMapCtrl); +#endif + logCfgAddMaskGroup (&mvlLogMaskMapCtrl); + logCfgAddMaskGroup (&mmsLogMaskMapCtrl); + logCfgAddMaskGroup (&acseLogMaskMapCtrl); + logCfgAddMaskGroup (&tp4LogMaskMapCtrl); + logCfgAddMaskGroup (&clnpLogMaskMapCtrl); + logCfgAddMaskGroup (&asn1LogMaskMapCtrl); + logCfgAddMaskGroup (&sxLogMaskMapCtrl); +#if defined(S_MT_SUPPORT) + logCfgAddMaskGroup (&gsLogMaskMapCtrl); +#endif + logCfgAddMaskGroup (&sockLogMaskMapCtrl); + logCfgAddMaskGroup (&memLogMaskMapCtrl); + logCfgAddMaskGroup (&memDebugMapCtrl); + + if (logcfgx_ex (sLogCtrl, "logcfg.xml", NULL, SD_FALSE, SD_FALSE) != SD_SUCCESS) + { + printf ("\n Parsing of 'logging' configuration file failed."); + if (sLogCtrl->fc.fileName) + printf ("\n Check log file '%s'.", sLogCtrl->fc.fileName); + exit (5); + } +#endif /* !defined (HARD_CODED_CFG) */ + } +#endif /* DEBUG_SISCO */ + diff --git a/mms/mmsclient.h b/mms/mmsclient.h new file mode 100644 index 0000000..600cad3 --- /dev/null +++ b/mms/mmsclient.h @@ -0,0 +1,239 @@ +/** +* @file: $RCSfile: mmsclient.h,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:50 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmsclient.h,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +* +*/ +//$Header: /JoyProject/jspqfe/src/pt61850netd_pqfe/source/mms/mmsclient.h,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 2003 - 2003, All Rights Reserved */ +/* */ +/* MODULE NAME : mmsclient.h */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* Defines for sample "client" application. */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 07/22/05 JRB 05 Add rcb_type, RptID, varNameArray to RCB_INFO.*/ +/* Add ALL_RCB_INFO struct. */ +/* Chg u_iec_rpt_ind_data 4th arg to (RCB_INFO *).*/ +/* 07/15/05 JRB 04 Add mvl_defs.h */ +/* 05/13/04 JRB 03 Chg SqNum to INT16U to match 61850-7-2. */ +/* 12/17/03 JRB 02 61850-8-1 FDIS changes: */ +/* Add ConfRev to RCB_DATA & RCB_VAR. */ +/* Chg bvstring9 to bvstring10 for OptFlds. */ +/* 10/09/03 JRB 01 New */ +/************************************************************************/ +#ifndef SAC_MMSCLIENT_H +#define SAC_MMSCLIENT_H + +#include "mvl_defs.h" /* need base MVL types. */ + +/* Defines required by Foundry generated code. */ +/* Default values defined in "mvl_defs.h" but we don't like the defaults*/ +/* so we undefine and redefine them here. */ + +#undef MVL_NUM_DYN_DOMS +#undef MVL_NUM_DYN_VMD_VARS +#undef MVL_NUM_DYN_VMD_NVLS +#undef MVL_NUM_DYN_JOUS +#undef MVL_NUM_DYN_DOM_VARS +#undef MVL_NUM_DYN_DOM_NVLS +#undef MVL_NUM_DYN_AA_VARS +#undef MVL_NUM_DYN_AA_NVLS +#undef MVLU_NUM_DYN_TYPES + +#define MVL_NUM_DYN_DOMS 10 +#define MVL_NUM_DYN_VMD_VARS 100 +#define MVL_NUM_DYN_VMD_NVLS 10 +#define MVL_NUM_DYN_JOUS 10 +#define MVL_NUM_DYN_DOM_VARS 100 +#define MVL_NUM_DYN_DOM_NVLS 10 +#define MVL_NUM_DYN_AA_VARS 10 +#define MVL_NUM_DYN_AA_NVLS 10 + +//???? should change if servers num is large ?????? +#define MVLU_NUM_DYN_TYPES 65535+20000 /* important for UCA */ + +/* Struct to store common type ids needed for IEC/UCA Reports. */ +typedef struct + { + ST_INT mmsbool; /* named so not confused with C++ 'bool' type */ + ST_INT int8u; + ST_INT int16u; /* for SqNum. */ + /* NOTE: UCA server sends int8u for SqNum */ + /* but it's safe to decode it as int16u */ + ST_INT int32u; /* for IntgPd */ + ST_INT vstring65; /* for RptID & ObjectReference */ + ST_INT btime6; /* for EntryTime */ + ST_INT ostring8; /* for EntryID */ + ST_INT vstring32; /* for RptId */ + ST_INT bvstring6; /* for TrgOps (IEC) */ + ST_INT bvstring8; /* for OptFlds,TrgOps (UCA) */ + ST_INT bvstring10; /* for OptFlds (IEC) */ + ST_INT bstr6; /* for Reason (IEC) */ + ST_INT bstr8; /* for Reason (UCA) */ + ST_INT bstr9; /* for Writing OptFlds (IEC). Can't write all 10 bits.*/ + } RPT_TYPEIDS; + +typedef struct + { + ST_CHAR RptID[66]; + struct /* BVstring */ + { + ST_INT16 len_1; + ST_UCHAR data_1[2]; /* BVstring9 - need 2 bytes */ + } OptFlds; + ST_UINT16 SqNum; + MMS_BTIME6 TimeOfEntry; + ST_CHAR DatSetNa[66]; + ST_BOOLEAN BufOvfl; + ST_UINT16 SubSeqNum; + ST_BOOLEAN MoreSegmentsFollow; + ST_UINT8 EntryID [8]; /* ostring8 */ + ST_UINT32 ConfRev; + ST_UINT8 *Inclusion; /* ptr to bitstring */ + /* Must alloc appropriate size */ + /* buffer for bitstring. */ + ST_CHAR *dataRefName; /* ptr to array of dataRefName */ + MMS_BVSTRING *Reason; /* ptr to array of Reason bitstrings */ + /* WARNING: this only works for variable*/ + /* len bitstring up to 8 bits. */ + } RCB_DATA; + +typedef struct + { + MVL_VAR_ASSOC * RptID; + MVL_VAR_ASSOC * OptFlds; + MVL_VAR_ASSOC * SqNum; + MVL_VAR_ASSOC * TimeOfEntry; + MVL_VAR_ASSOC * DatSetNa; + MVL_VAR_ASSOC * BufOvfl; + MVL_VAR_ASSOC * SubSeqNum; + MVL_VAR_ASSOC * MoreSegmentsFollow; + MVL_VAR_ASSOC * EntryID; + MVL_VAR_ASSOC * ConfRev; + MVL_VAR_ASSOC * Inclusion; + MVL_VAR_ASSOC ** dataRefName; /* array of ptrs */ + MVL_VAR_ASSOC ** dataValue; /* array of ptrs */ + MVL_VAR_ASSOC ** Reason; /* array of ptrs */ + } RCB_VAR; + +typedef struct + { + DBL_LNK link; /* allows linked list of this struct */ + ST_CHAR dom_Name[MAX_IDENT_LEN + 1];//WW 2023-08-29 + ST_CHAR rcb_name[MAX_IDENT_LEN + 1];//WW 2023-08-29 + ST_INT rcb_type; /* RCB_TYPE_UCA, RCB_TYPE_IEC_BRCB, etc. */ + /* see RCB_TYPE.. defines in 'mvl_uca.h'. */ + ST_CHAR RptID [66]; /* RptID of this RCB (Vstring65) */ + OBJECT_NAME **varNameArray; /* array of variable names in NVL */ + ST_INT numDsVar; /* num variables in rpt dataset */ + ST_INT *typeIdArr; /* array of type ids */ + ST_INT InclusionTypeid; /*Type ID for Inclusion Bitstring*/ + RCB_DATA rcb_data; + RCB_VAR rcb_var; + ST_CHAR ds_Nam[MAX_IDENT_LEN * 2];//WW 2023-08-29 + } RCB_INFO; + +typedef struct + { + RPT_TYPEIDS *rpt_typeids; + RCB_INFO *rcb_info_list; /* linked list of RCB_INFO structs */ + } ALL_RCB_INFO; /* used to track multiple RCBs. */ +///////////////////////////////// +//WW 2023-08-29 ͬն˲ƿ +typedef struct +{ + DBL_LNK l; //ڴṹ׵ַ + ST_CHAR IP[MAX_IDENT_LEN]; //װIP[64] + int Port; //˿ں +} Dev_IP_Port_INFO; //װIP˿ںŽṹ + +typedef struct +{ + DBL_LNK l; //ڴṹ׵ַ + ST_CHAR dev_type_name[MAX_IDENT_LEN * 2]; //װ[128] + Dev_IP_Port_INFO * dev_ip_port_list; //װIP˿ָ + RCB_INFO *rcb_info_list; //ƿϢָ +} Dev_RCB_INFO; //װñṹ + +typedef struct //zl 2019-12-26 12:24:06 +{ + DBL_LNK l; //ڴṹ׵ַ + Dev_RCB_INFO *dev_rcb_info_Head; +} DEV_TYPE_LIST; // +extern DEV_TYPE_LIST gDev_rcb_list; //ȫֱƿ + +//WW 2023-08-29 end +///////////////////////////////////// +/************************************************************************/ +/* Global variables. */ +/************************************************************************/ +/* NONE */ + +/************************************************************************/ +/* Function prototypes. */ +/************************************************************************/ +ST_RET waitReqDone (MVL_REQ_PEND *req, ST_INT timeout); + +void doCommForSecs (ST_INT timeout); + +ST_VOID doCommService (ST_VOID); + +ST_RET rpt_typeids_find (RPT_TYPEIDS *rpt_typeids); + +RCB_INFO *rcb_info_create (MVL_NET_INFO *net_info, ST_CHAR *domName, + ST_CHAR *rcbName, RPT_TYPEIDS *rpt_typeids, ST_INT timeOut); +ST_VOID rcb_info_destroy (RCB_INFO *rcb_info); + +ST_RET rcb_enable (MVL_NET_INFO *netInfo, ST_CHAR *domName, + ST_CHAR *rcbName, ST_UCHAR *OptFlds, ST_UCHAR *TrgOps, + ST_UINT32 IntgPd, RPT_TYPEIDS *rpt_typeids, ST_INT timeOut); + +ST_RET rcb_disable (MVL_NET_INFO *netInfo, ST_CHAR *domName, + ST_CHAR *rcbName, RPT_TYPEIDS *rpt_typeids, ST_INT timeOut); +/* Simple functions to read/write a single variable. */ +ST_RET mms_named_var_read (MVL_NET_INFO *net_info, ST_CHAR *varName, + ST_INT scope, ST_CHAR *domName, + ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut); +ST_RET mms_named_var_write (MVL_NET_INFO *netInfo, ST_CHAR *varName, + ST_INT scope, ST_CHAR *domName, + ST_INT type_id, ST_VOID *dataSrc, ST_INT timeOut); + +ST_RET mms_release_connection (MVL_NET_INFO *clientNetInfo); + +ST_RET u_iec_rpt_ind (MVL_COMM_EVENT *event); +ST_VOID u_iec_rpt_ind_data (MVL_VAR_ASSOC **info_va, + ST_UINT8 *OptFldsData, /* ptr to data part of OptFlds bvstring */ + ST_UINT8 *InclusionData, /* ptr to Inclusion bstring */ + RCB_INFO *rcb_info, + ST_INT va_total, + MVL_NET_INFO *net_info); + +//////////////////////////////// +//WW 2023-08-30Ӱװӱƥṹ +ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT *event); +ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC **info_va, + ST_UINT8 *OptFldsData, /* ptr to data part of OptFlds bvstring */ + ST_UINT8 *InclusionData, /* ptr to Inclusion bstring */ + RCB_INFO *rcb_info, + ST_INT va_total, + MVL_NET_INFO *net_info); +//WW 2023-08-30 end +//////////////////////////////// + +#endif //SAC_MMSCLIENT_H + diff --git a/mms/mmslvar.c b/mms/mmslvar.c new file mode 100644 index 0000000..7019427 --- /dev/null +++ b/mms/mmslvar.c @@ -0,0 +1,245 @@ +/** +* @file: $RCSfile: mmslvar.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:50 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmslvar.c,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1993 - 2005, All Rights Reserved. */ +/* */ +/* PROPRIETARY AND CONFIDENTIAL */ +/* */ +/* MODULE NAME : mmslvar.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* All global MMSEASE-LITE variables are defined in this module, */ +/* and declared in LMMSDEFS.H */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* NONE */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 06/22/05 JRB 13 Remove static from usrLog* var. */ +/* 06/06/05 EJV 12 usrLogMaskMapCtrl not used when FOUNDRY def. */ +/* 05/23/05 EJV 11 Add xxxLogMaskMapCtrl for parsing logcfg.xml */ +/* 09/04/03 EJV 10 Chg mms_debug_sel to ST_UINT (from ST_UINT32)*/ +/* 03/13/03 JRB 09 Del u_ml_get_rt_type func ptr, it is func now*/ +/* 01/02/03 JRB 08 Add arg to u_ml_get_rt_type. */ +/* 03/15/01 JRB 07 Added user_debug_sel & _user_*_logstr */ +/* 09/13/99 MDE 06 Added SD_CONST modifiers */ +/* 02/23/99 JRB 05 Don't init m_data_algn_tbl, it's a constant. */ +/* 10/21/98 MDE 04 Removed VMS ifdef */ +/* 10/08/98 MDE 03 Migrated to updated SLOG interface */ +/* 11/05/97 MDE 02 Changed mmsl_msg_start to ST_UCHAR * */ +/* 09/10/97 MDE 01 MMS-LITE V4.0 Release */ +/************************************************************************/ + +#include "glbtypes.h" +#include "sysincs.h" + +#include "mmsdefs.h" +#include "mms_err.h" +#include "mms_pvar.h" +#include "mms_vvar.h" + + +/************************************************************************/ +/************************************************************************/ +/* MMSEASE-LITE Global Variables */ +/************************************************************************/ + +ST_INT mmsl_enc_buf_size; +ST_UCHAR *mmsl_enc_buf; +ST_INT mmsl_dec_info_size; + +#if !defined(NO_GLB_VAR_INIT) +ST_INT16 mmsl_version = 1; /* select IS for version */ +ST_UINT32 mmsl_invoke_id = 1; +#else +ST_INT16 mmsl_version; /* select IS for version */ +ST_UINT32 mmsl_invoke_id; +#endif + +ST_UCHAR *mmsl_msg_start; +ST_INT mmsl_msg_len; + +/************************************************************************/ +/* Variables in common with MMS-EASE */ + +#if !defined(NO_GLB_VAR_INIT) +ST_UINT _mmsdec_ctxt = MMS_PCI;/* decode context type, default to core */ +ST_INT m_use_long_ints = SD_TRUE; +#else +ST_UINT _mmsdec_ctxt; /* decode context type, default to core */ +ST_INT m_use_long_ints; +#endif +ST_INT _mmsdec_msglen; /* MMS decode message length */ +ST_UCHAR *_mmsdec_msgptr; /* MMS decode message ptr */ +ST_BOOLEAN _mms_dec_info_pres; +MMSDEC_INFO *_mmsdec_rslt; +ST_VOID *_mms_dec_info; + +ADTNL_ERR_RESP_INFO adtnl_err_info; + +ST_RET mms_op_err; + + +/************************************************************************/ +/************************************************************************/ +/************************************************************************/ +/* Some Alternate Access related variables. These are defined in */ +/* mmsvar.c for MMS-EASE, but are put here for MMS-LITE */ + +#if !defined(NO_GLB_VAR_INIT) +ST_INT m_max_dec_aa = 50; +ST_INT m_max_rt_aa_ctrl = 1000; +#else +ST_INT m_max_dec_aa; +ST_INT m_max_rt_aa_ctrl; +#endif + +ST_INT m_hw_dec_aa; +ST_INT m_hw_rt_aa_ctrl; +ST_BOOLEAN m_alt_acc_packed; + +/************************************************************************/ +/************************************************************************/ +/* This variable can be set to force use of the DIS MMS floating point */ +/* type protocol (used in any over the wire and internal ASN.1 type */ +/* definitions). */ +/************************************************************************/ + +ST_BOOLEAN m_use_dis_float; + +/************************************************************************/ +/* Global variables for modifier support */ +/************************************************************************/ + +#if !defined (NO_GLB_VAR_INIT) +LIST_OF_MODS modifier_list; /* used to encode modifier info */ +ST_INT m_max_mods = 1; /* num of modifier structs calloced during dec. */ +#else +LIST_OF_MODS modifier_list; +ST_INT m_max_mods; +#endif + +/************************************************************************/ +/* Global variables for compantion standard (IS) */ +/************************************************************************/ + +CSI cs_send; /* SEND CS info structure */ +ST_BOOLEAN cs_send_reset_val; + +/************************************************************************/ +/* Logging variables */ +/************************************************************************/ + +#if !defined(NO_GLB_VAR_INIT) +ST_UINT mms_debug_sel = MMS_LOG_ERR; +ST_UINT user_debug_sel = USER_LOG_ERR; +#else +ST_UINT mms_debug_sel; +ST_UINT user_debug_sel; +#endif + +#ifdef DEBUG_SISCO +SD_CONST ST_CHAR *SD_CONST _mms_log_dec_logstr = "MMS_LOG_DEC"; +SD_CONST ST_CHAR *SD_CONST _mms_log_enc_logstr = "MMS_LOG_ENC"; +SD_CONST ST_CHAR *SD_CONST _mms_log_acse_logstr = "MMS_LOG_ACSE"; +SD_CONST ST_CHAR *SD_CONST _mms_log_llc_logstr = "MMS_LOG_LLC"; +SD_CONST ST_CHAR *SD_CONST _mms_log_ique_logstr = "MMS_LOG_IQUE"; +SD_CONST ST_CHAR *SD_CONST _mms_log_rque_logstr = "MMS_LOG_RQUE"; +SD_CONST ST_CHAR *SD_CONST _mms_log_ind_logstr = "MMS_LOG_IND"; +SD_CONST ST_CHAR *SD_CONST _mms_log_conf_logstr = "MMS_LOG_CONF"; +SD_CONST ST_CHAR *SD_CONST _mms_log_vm_logstr = "MMS_LOG_VM"; +SD_CONST ST_CHAR *SD_CONST _mms_log_err_logstr = "MMS_LOG_ERR"; +SD_CONST ST_CHAR *SD_CONST _mms_log_nerr_logstr = "MMS_LOG_NERR"; +SD_CONST ST_CHAR *SD_CONST _mms_log_pdu_logstr = "MMS_LOG_PDU"; +SD_CONST ST_CHAR *SD_CONST _mms_log_config_logstr = "MMS_LOG_CONFIG"; +SD_CONST ST_CHAR *SD_CONST _mms_log_always_logstr = "MMS_LOG_ALWAYS"; + +SD_CONST ST_CHAR *SD_CONST _user_err_logstr = "USER_LOG_ERR"; +SD_CONST ST_CHAR *SD_CONST _user_client_logstr = "USER_LOG_CLIENT"; +SD_CONST ST_CHAR *SD_CONST _user_server_logstr = "USER_LOG_SERVER"; + +LOGCFGX_VALUE_MAP mmsLogMaskMaps[] = + { + {"MMS_LOG_ERR", MMS_LOG_ERR, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Error"}, + {"MMS_LOG_NERR", MMS_LOG_NERR, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Notice"}, + {"MMS_LOG_DEC", MMS_LOG_DEC, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Decode"}, + {"MMS_LOG_ENC", MMS_LOG_ENC, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Encode"}, + + {"MMS_LOG_CLIENT", MMS_LOG_REQ|MMS_LOG_CONF, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Client"}, + {"MMS_LOG_SERVER", MMS_LOG_IND|MMS_LOG_RESP, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Server"}, + + {"MMS_LOG_REQ", MMS_LOG_REQ, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Request"}, + {"MMS_LOG_RESP", MMS_LOG_RESP, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Response"}, + {"MMS_LOG_IND", MMS_LOG_IND, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Indication"}, + {"MMS_LOG_CONF", MMS_LOG_CONF, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Confirm"}, + {"MMS_LOG_RT", MMS_LOG_RT, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Runtime Type"}, + {"MMS_LOG_RTAA", MMS_LOG_RTAA, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Runtime Type Alternate Access"}, + {"MMS_LOG_AA", MMS_LOG_AA, &mms_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Alternate Access"}, + }; + +LOGCFG_VALUE_GROUP mmsLogMaskMapCtrl = + { + {NULL,NULL}, + "MMS", + sizeof(mmsLogMaskMaps)/sizeof(LOGCFGX_VALUE_MAP), + mmsLogMaskMaps + }; + +LOGCFGX_VALUE_MAP usrLogMaskMaps[] = + { + {"USER_LOG_ERR", USER_LOG_ERR, &user_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Error"}, + {"USER_LOG_CLIENT", USER_LOG_CLIENT, &user_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Client"}, + {"USER_LOG_SERVER", USER_LOG_SERVER, &user_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Server"} + }; + +LOGCFG_VALUE_GROUP usrLogMaskMapCtrl = + { + {NULL,NULL}, + "User", + sizeof(usrLogMaskMaps)/sizeof(LOGCFGX_VALUE_MAP), + usrLogMaskMaps + }; +#endif /* DEBUG_SISCO */ + +/************************************************************************/ +/* m_init_glb_vars */ +/************************************************************************/ + +#if defined(NO_GLB_VAR_INIT) +ST_VOID a_init_glb_vars (ST_VOID); + +ST_VOID m_init_glb_vars (ST_VOID) + { + a_init_glb_vars (); + mmsl_version = 1; + mmsl_invoke_id = 1; + _mmsdec_ctxt = MMS_PCI; + m_use_long_ints = SD_TRUE; + m_max_mods = 1; + mms_debug_sel = MMS_LOG_ERR; +#if defined(NO_GLB_VAR_INIT) + if (!m_data_algn_tbl) + m_data_algn_tbl = m_packed_data_algn_tbl; +#endif + m_max_dec_aa = 50; + m_max_rt_aa_ctrl = 1000; + } + +#endif + diff --git a/mms/mmsop_en.c b/mms/mmsop_en.c new file mode 100644 index 0000000..3b91cfc --- /dev/null +++ b/mms/mmsop_en.c @@ -0,0 +1,3490 @@ +/** +* @file: $RCSfile: mmsop_en.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:50 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmsop_en.c,v 1.1 2018/11/24 06:54:50 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1986 - 1998, All Rights Reserved. */ +/* */ +/* MODULE NAME : mmsop_en.c */ +/* PRODUCT(S) : MMSEASE, MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* This module is used to initialize the tables used in defining */ +/* the supported operation set, and MUST be re-compiled if the */ +/* supported command set is reduced (or expanded) via the subset */ +/* creation mechanism. This module also defines and initializes */ +/* the supported services parameters. */ +/* */ +/* The following tables are initialized: */ +/* */ +/* *operation enable table (mmsop_en [MAX_MMSOP_DIS+1]) : */ +/* used to check if an MMS operation is to be supported */ +/* as requestor and/or responder, and if the data element */ +/* containing the opcode is of the proper form. */ +/* */ +/* *operation name table (mms_op_string [MAX_MMSOP_DIS+1]) : */ +/* used to print the name of the MMS operation. */ +/* */ +/* *request decode function table */ +/* (mms_req_decode_fun [MAX_MMSOP_DIS+1]) : */ +/* used to define which function will be executed to */ +/* decode a request. */ +/* */ +/* *response decode function table */ +/* (mms_rsp_decode_fun [MAX_MMSOP_DIS+1]) : */ +/* used to define which function will be executed to */ +/* decode a response. */ +/* */ +/* **indication service function table */ +/* (mms_ind_serve_fun [MAX_IND_SFUN+1]) : */ +/* used to define which function will be executed to */ +/* service an indication. */ +/* */ +/* **confirmation service function table */ +/* (mms_conf_serve_fun [MAX_CONF_SFUN+1]) : */ +/* used to define which function will be executed to */ +/* service a confirmation. */ +/* */ +/* * - these tables are not normally modified by the user. */ +/* ** - these tables may be modified by the user. */ +/* */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* NOTE: If this module changes the mmsop_en_versionN variable need */ +/* to change to (N+1) to prevent linking of old versions of this */ +/* file to user applications. The strt_MMS() in mmsutil.c should */ +/* reference the new name. */ +/* 05/07/03 EJV 18 Add mmsop_en_version1 global & comment above.*/ +/* 07/11/02 EJV 17 mms_conf_serve_fun: corrected few entries. */ +/* 07/09/02 MDE 16 Fixed up opcode defines */ +/* 12/18/01 JRB 15 Convert to use ASN1R. */ +/* 04/19/00 JRB 14 Fix SD_CONST for decode funct ptr arrays. */ +/* 09/13/99 MDE 13 Added SD_CONST modifiers */ +/* 10/05/98 EJV 12 Replace struct acse_assinfo with ACSE_ASSINFO*/ +/* Chg u_mllp_l_assoc_ind_fun return to ST_RET. */ +/* 05/27/98 MDE 11 Added MLOG_DISABLE define use */ +/* 04/13/98 MDE 10 MMS-LITE MLOG logging, unconfirmed logging */ +/* 12/30/97 EJV 09 Added typecast to all functions in tables: */ +/* m_req_log_fun_tbl and m_resp_log_fun_tbl */ +/* 10/13/97 DSF 08 no more MAP21_CASE!!! */ +/* 09/05/97 DSF 07 Fixed m_cl_max_getvla_vars #ifdef problem */ +/* 09/02/97 DSF 06 Always define mms_op_string if not MMS-LITE */ +/* 08/18/97 MDE 05 Moved parameter support def's to mmsop_en.h */ +/* 08/14/97 DSF 04 define MLOG_ENABLE if not MMS-LITE */ +/* 08/05/97 MDE 03 MLOG integration */ +/* 07/03/97 MDE 02 Minor tweaks to decode size control vars */ +/* 06/09/97 MDE 01 Added decode size control variables */ +/* 04/15/97 DSF 7.00 MMSEASE 7.0 release. See MODL70.DOC for */ +/* history. */ +/************************************************************************/ + +#include "glbtypes.h" +#include "sysincs.h" +#include "mmsop_en.h" +#include "mms_dfun.h" + +#if !defined(MMS_LITE) && !defined(MLOG_DISABLE) +#define MLOG_ENABLE +#endif + +#if !defined(MMS_LITE) +#include "mms_usr.h" +#else +#include "mms_def2.h" +#endif + +#ifdef MLOG_ENABLE +#include "mloguser.h" +#endif + +/************************************************************************/ +/************************************************************************/ +/* NOTE: This variable will prevent linking of old version of the */ +/* mmsop_en.c file to user application. If this file changes this */ +/* variable's name should be changed to mmsop_en_version(N+1) and */ +/* the strt_MMS() in mmsutil.c should reference the new name. */ +ST_INT mmsop_en_version1; + + +/************************************************************************/ +/************************************************************************/ +/* The following defines are used in initializing the mmsop_en array. */ +/* Each entry of the array consists of 8 bits: 00ijklmn, where the */ +/* bottom 6 bits mean the following: */ +/* */ +/* i - if 1, then response is NULL */ +/* j - if 1, then request is NULL */ +/* k - if 1, then response is constructor; otherwise, primitive. */ +/* l - if 1, then request is constructor; otherwise, primitive. */ +/* m - if 1, then response is supported; otherwise not. */ +/* n - if 1, then request is supported; otherwise not. */ +/* */ +/* By "supported" is meant that the executable program contains code to */ +/* handle that op code. */ +/************************************************************************/ +/* */ +/* resp req */ +#define PRIM_PRIM 0x00 /* primitive resp and req */ + +#define PRIM_CSTR 0x04 /* prim resp, constructor req */ +#define CSTR_PRIM 0x08 /* constructor resp, prim req */ +#define CSTR_CSTR 0x0C /* cstr resp, cstr req */ +#define NULL_NULL 0x30 /* primitive resp and req */ +#define NULL_PRIM 0x20 /* prim resp, constructor req */ +#define PRIM_NULL 0x10 /* constructor resp, prim req */ +#define NULL_CSTR 0x24 /* prim resp, constructor req */ +#define CSTR_NULL 0x18 /* constructor resp, prim req */ + +/************************************************************************/ +/* initialize the operation enable table, opcode is index into table */ +/************************************************************************/ +SD_CONST ST_UCHAR mmsop_en [MAX_MMSOP_DIS+1] = + { + MMS_STATUS_EN | CSTR_PRIM, /* 00 STATUS */ + MMS_GETNAMES_EN | CSTR_CSTR, /* 01 GET_NAMLIST */ + MMS_IDENT_EN | CSTR_NULL, /* 02 IDENTIFY */ + MMS_RENAME_EN | NULL_CSTR, /* 03 RENAME */ + MMS_READ_EN | CSTR_CSTR, /* 04 READ */ + MMS_WRITE_EN | CSTR_CSTR, /* 05 WRITE */ + MMS_GETVAR_EN | CSTR_CSTR, /* 06 GET_VARDEF */ + MMS_DEFVAR_EN | NULL_CSTR, /* 07 DEF_VARNAM */ + MMS_DEFSCAT_EN | NULL_CSTR, /* 08 DEF_SCATTERED */ + MMS_GETSCAT_EN | CSTR_CSTR, /* 09 GET_SCATTERED */ + MMS_DELVAR_EN | CSTR_CSTR, /* 10 DEL_VARNAM */ + MMS_DEFVLIST_EN | NULL_CSTR, /* 11 DEF_VARLIST */ + MMS_GETVLIST_EN | CSTR_CSTR, /* 12 GET_VARLIST */ + MMS_DELVLIST_EN | CSTR_CSTR, /* 13 DEL_VARLIST */ + MMS_DEFTYPE_EN | NULL_CSTR, /* 14 DEF_TYPENAM */ + MMS_GETTYPE_EN | CSTR_CSTR, /* 15 GET_TYPEDEF */ + MMS_DELTYPE_EN | CSTR_CSTR, /* 16 DEL_TYPENAM */ + MMS_INPUT_EN | PRIM_CSTR, /* 17 INPUT */ + MMS_OUTPUT_EN | NULL_CSTR, /* 18 OUTPUT */ + MMS_TAKECTRL_EN | CSTR_CSTR, /* 19 TAKE_CONTROL */ + MMS_RELCTRL_EN | NULL_CSTR, /* 20 REL_CONTROL */ + MMS_DEFINE_SEM_EN | NULL_CSTR, /* 21 DEF_SEMAPHORE */ + MMS_DELETE_SEM_EN | NULL_CSTR, /* 22 DEL_SEMAPHORE */ + MMS_REP_SEMSTAT_EN | CSTR_CSTR, /* 23 REP_SEM_STATUS */ + MMS_REP_SEMPOOL_EN | CSTR_CSTR, /* 24 REP_SEM_POOL_STATUS */ + MMS_REP_SEMENTRY_EN | CSTR_CSTR, /* 25 REP_SEM_ENTRY_STATUS */ + MMS_INIT_DWN_EN | CSTR_CSTR, /* 26 INIT_DOWNLOAD */ + MMS_DWN_LOAD_EN | CSTR_PRIM, /* 27 DOWN_LOAD */ + MMS_TERM_DWN_EN | NULL_CSTR, /* 28 TERM_DOWNLOAD */ + MMS_INIT_UPL_EN | CSTR_PRIM, /* 29 INIT_UPLOAD */ + MMS_UP_LOAD_EN | CSTR_PRIM, /* 30 UP_LOAD */ + MMS_TERM_UPL_EN | NULL_PRIM, /* 31 TERM_UPLOAD */ + MMS_RDDWN_EN | NULL_CSTR, /* 32 REQ_DOWNLOAD */ + MMS_RDUPL_EN | NULL_CSTR, /* 33 REQ_UPLOAD */ + MMS_LOAD_DOM_EN | NULL_CSTR, /* 34 LOAD_DOMAIN */ + MMS_STR_DOM_EN | NULL_CSTR, /* 35 STORE_DOMAIN */ + MMS_DEL_DOM_EN | NULL_PRIM, /* 36 DELETE_DOMAIN */ + MMS_GET_DOM_EN | CSTR_PRIM, /* 37 GET_DOMAIN */ + MMS_CRE_PI_EN | NULL_CSTR, /* 38 CREATE_PROGRAM_INVOCATION*/ + MMS_DEL_PI_EN | NULL_PRIM, /* 39 DEL_PROGRAM_INVOCATION */ + MMS_START_EN | NULL_CSTR, /* 40 START */ + MMS_STOP_EN | NULL_CSTR, /* 41 STOP */ + MMS_RESUME_EN | NULL_CSTR, /* 42 RESUME */ + MMS_RESET_EN | NULL_CSTR, /* 43 RESET */ + MMS_KILL_EN | NULL_CSTR, /* 44 KILL */ + MMS_GET_PI_EN | CSTR_PRIM, /* 45 GET_PROGRAM_INVOCATION */ + MMS_OBTAINFILE_EN | NULL_CSTR, /* 46 OBTAIN_FILE */ + MMS_DEFEC_EN | NULL_CSTR, /* 47 DEFINE_EVENT_CONDITION */ + MMS_DELEC_EN | PRIM_CSTR, /* 48 DELETE_EVENT_CONDITION */ + MMS_GETECA_EN | CSTR_CSTR, /* 49 GET EVENT CONDITION ATTR */ + MMS_REPECS_EN | CSTR_CSTR, /* 50 REPORT EVENT COND STATUS */ + MMS_ALTECM_EN | NULL_CSTR, /* 51 ALTER_EVENT_COND_MON */ + MMS_TRIGE_EN | NULL_CSTR, /* 52 TRIGGER_EVENT */ + MMS_DEFEA_EN | NULL_CSTR, /* 53 DEFINE_EVENT_ACTION */ + MMS_DELEA_EN | PRIM_CSTR, /* 54 DELETE_EVENT_ACTION */ + MMS_GETEAA_EN | CSTR_CSTR, /* 55 GET_EVENT_ACTION_ATTRIB */ + MMS_REPEAS_EN | PRIM_CSTR, /* 56 REPORT_EVENT_ACTION_STAT */ + MMS_DEFEE_EN | NULL_CSTR, /* 57 DEFINE_EVENT_ENROLLMENT */ + MMS_DELEE_EN | PRIM_CSTR, /* 58 DELETE_EVENT_ENROLLMENT */ + MMS_ALTEE_EN | CSTR_CSTR, /* 59 ALTER_EVENT_ENROLLMENT */ + MMS_REPEES_EN | CSTR_CSTR, /* 60 REPORT_EVENT_ENROLL_STAT */ + MMS_GETEEA_EN | CSTR_CSTR, /* 61 GET_EVENT_ENROLL_ATTRIB */ + MMS_ACKEVNOT_EN | NULL_CSTR, /* 62 ACK_EVENT_NOTIFICATION */ + MMS_GETAS_EN | CSTR_CSTR, /* 63 GET_ALARM_SUMMARY */ + MMS_GETAES_EN | CSTR_CSTR, /* 64 GET_ALARM_ENROLL_SUMMARY */ + MMS_JREAD_EN | CSTR_CSTR, /* 65 READ_JOURNAL */ + MMS_JWRITE_EN | NULL_CSTR, /* 66 WRITE_JOURNAL */ + MMS_JINIT_EN | PRIM_CSTR, /* 67 INITIALIZE_JOURNAL */ + MMS_JSTAT_EN | CSTR_CSTR, /* 68 REPORT_JOURNAL_STATUS */ + MMS_JCREATE_EN | NULL_CSTR, /* 69 CREATE JOURNAL */ + MMS_JDELETE_EN | NULL_CSTR, /* 70 DELETE JOURNAL */ + MMS_GETCL_EN | CSTR_CSTR, /* 71 GET CAPABILITY LIST */ + MMS_FOPEN_EN | CSTR_CSTR, /* 72 FILE_OPEN */ + MMS_FREAD_EN | CSTR_PRIM, /* 73 FILE_READ */ + MMS_FCLOSE_EN | NULL_PRIM, /* 74 FILE_CLOSE */ + MMS_FRENAME_EN | NULL_CSTR, /* 75 FILE_RENAME */ + MMS_FDELETE_EN | NULL_CSTR, /* 76 FILE_DELETE */ + MMS_FDIR_EN | CSTR_CSTR, /* 77 FILE_DIR */ + MMS_USTATUS_EN | CSTR_CSTR, /* 78 UNSOLICITED_STATUS */ + MMS_INFO_EN | CSTR_CSTR, /* 79 INFO_RPT */ + MMS_EVNOT_EN | CSTR_CSTR, /* 80 EVENT NOTIFICATION */ + 0, /* 81 ATTACH TO EVENT COND */ + 0, /* 82 ATTACH TO SEMAPHORE */ + MMS_CONCLUDE_EN | NULL_NULL, /* 83 CONCLUDE */ + MMS_CANCEL_EN | PRIM_PRIM, /* 84 CANCEL */ + MMS_INIT_EN | CSTR_CSTR /* 85 INITIATE */ + }; + +#if !defined (MMS_LITE) || defined (DEBUG_SISCO) +/************************************************************************/ +/************************************************************************/ +/* INITIALIZE THE OPCODE PRINT STRINGS */ +/************************************************************************/ + + + +ST_CHAR *mms_op_string [] = /* opcode is index into table */ + { + "STATUS", /* 00 STATUS */ + "GET_NAMLIST", /* 01 GET_NAMLIST */ + "IDENTIFY", /* 02 IDENTIFY */ + "RENAME", /* 03 RENAME */ + "READ", /* 04 READ */ + "WRITE", /* 05 WRITE */ + "GET_VARDEF", /* 06 GET_VARDEF */ + "DEF_VARNAM", /* 07 DEF_VARNAM */ + "DEF_SCATTERED", /* 08 DEF_SCATTERED */ + "GET_SCATTERED", /* 09 GET_SCATTERED */ + "DEL_VARNAM", /* 10 DEL_VARNAM */ + "DEF_VARLIST", /* 11 DEF_VARLIST */ + "GET_VARLIST", /* 12 GET_VARLIST */ + "DEL_VARLIST", /* 13 DEL_VARLIST */ + "DEF_TYPENAM", /* 14 DEF_TYPENAM */ + "GET_TYPEDEF", /* 15 GET_TYPEDEF */ + "DEL_TYPENAM", /* 16 DEL_TYPENAM */ + "INPUT", /* 17 INPUT */ + "OUTPUT", /* 18 OUTPUT */ + "TAKE_CONTROL", /* 19 TAKE_CONTROL */ + "REL_CONTROL", /* 20 REL_CONTROL */ + "DEF_SEMAPHORE", /* 21 DEF_SEMAPHORE */ + "DEL_SEMAPHORE", /* 22 DEL_SEMAPHORE */ + "REP_SEM_STATUS", /* 23 REP_SEM_STATUS */ + "REP_SEM_POOL_STATUS", /* 24 REP_SEM_POOL_STATUS */ + "REP_SEM_ENTRY_STATUS", /* 25 REP_SEM_ENTRY_STATUS */ + "INIT_DOWNLOAD", /* 26 INIT_DOWNLOAD */ + "DOWN_LOAD", /* 27 DOWN_LOAD */ + "TERM_DOWNLOAD", /* 28 TERM_DOWNLOAD */ + "INIT_UPLOAD", /* 29 INIT_UPLOAD */ + "UP_LOAD", /* 30 UP_LOAD */ + "TERM_UPLOAD", /* 31 TERM_UPLOAD */ + "REQ_DOWNLOAD", /* 32 REQ_DOWNLOAD */ + "REQ_UPLOAD", /* 33 REQ_UPLOAD */ + "LOAD_DOMAIN", /* 34 LOAD_DOMAIN */ + "STORE_DOMAIN", /* 35 STORE_DOMAIN */ + "DELETE_DOMAIN", /* 36 DELETE_DOMAIN */ + "GET_DOMAIN", /* 37 GET_DOMAIN */ + "CREATE_PROGRAM_INVOCATION", /* 38 CREATE_PROG_INVOCATION */ + "DEL_PROGRAM_INVOCATION", /* 39 DEL_PROGRAM_INVOCATION */ + "START", /* 40 START */ + "STOP", /* 41 STOP */ + "RESUME", /* 42 RESUME */ + "RESET", /* 43 RESET */ + "KILL", /* 44 KILL */ + "GET_PROGRAM_INVOCATION", /* 45 GET_PROGRAM_INVOCATION */ + "OBTAIN_FILE", /* 46 OBTAIN_FILE */ + "DEFINE_EVENT_COND", /* 47 DEFINE_EVENT_COND */ + "DELETE_EVENT_COND", /* 48 DELETE_EVENT_COND */ + "GET_EVENT_CONDITION_ATTR", /* 49 GET_EVENT_COND_ATTR */ + "REPORT_EVENT_COND_STATUS", /* 50 REPORT_EVENT_COND_STAT */ + "ALTER_EVENT_COND_MON", /* 51 ALTER_EVENT_COND_MON */ + "TRIGGER_EVENT", /* 52 TRIGGER_EVENT */ + "DEFINE_EVEVT_ACTION", /* 53 DEFINE_EVENT_ACTION */ + "DELETE_EVENT_ACTION", /* 54 DELETE_EVENT_ACTION */ + "GET_EVENT_ACTION_ATTR", /* 55 GET_EVENT_ACT_ATTR */ + "REPORT_EVENT_ACTION_STAT", /* 56 REPORT_EVENT_ACT_STAT */ + "DEFINE_EVENT_ENROLLMENT", /* 57 DEFINE_EVENT_ENROLL */ + "DELETE_EVENT_ENROLLMENT", /* 58 DELETE_EVENT_ENROLL */ + "ALTER_EVENT_ENROLLMENT", /* 59 ALTER_EVENT_ENROLL */ + "REPORT_EVENT_ENROLL_STAT", /* 60 REPORT_EV_ENROLL_STAT */ + "GET_EVENT_ENROLL_ATTR", /* 61 GET_EVENT_ENROLL_ATTR */ + "ACK_EVENT_NOTIFICATION", /* 62 ACK_EVENT_NOTIFICATION */ + "GET_ALARM_SUMMARY", /* 63 GET_ALARM_SUMMARY */ + "GET_ALARM_ENROLL_SUMMARY", /* 64 GET_ALARM_ENROLL_SUM */ + "READ_JOURNAL", /* 65 READ_JOURNAL */ + "WRITE_JOURNAL", /* 66 WRITE_JOURNAL */ + "INITIALIZE_JOURNAL", /* 67 INITIALIZE_JOURNAL */ + "REPORT_JOURNAL_STATUS", /* 68 REPORT_JOURNAL_STATUS */ + "CREATE JOURNAL", /* 69 CREATE JOURNAL */ + "DELETE JOURNAL", /* 70 DELETE JOURNAL */ + "GET CAPABILITY LIST", /* 71 GET CAPABILITY LIST */ + "FILE_OPEN", /* 72 FILE_OPEN */ + "FILE_READ", /* 73 FILE_READ */ + "FILE_CLOSE", /* 74 FILE_CLOSE */ + "FILE_RENAME", /* 75 FILE_RENAME */ + "FILE_DELETE", /* 76 FILE_DELETE */ + "FILE_DIR", /* 77 FILE_DIR */ + "UNSOLICITED_STATUS", /* 78 UNSOLICITED_STATUS */ + "INFO_RPT", /* 79 INFO_RPT */ + "EVENT NOTIFICATION", /* 80 EVENT NOTIFICATION */ + "ATTACH TO EVENT CONDITION", /* 81 ATTACH TO EVENT COND */ + "ATTACH TO SEMAPHORE", /* 82 ATTACH TO SEMAPHORE */ + "CONCLUDE", /* 83 CONCLUDE */ + "CANCEL", /* 84 CANCEL */ + "INITIATE", /* 85 INITIATE */ + "", /* 86 NOT A MMS OPERATION */ + "", /* 87 NOT A MMS OPERATION */ + "", /* 88 NOT A MMS OPERATION */ + "", /* 89 NOT A MMS OPERATION */ + "MV READ", /* 90 NAMED READ */ + "MV WRITE", /* 91 NAMED WRITE */ + "", /* 92 NOT A MMS OPERATION */ + "MV MVE_FOPEN", /* 93 REMOTE FILE OPEN */ + "MV FREAD", /* 94 REMOTE FILE READ */ + "MV FCLOSE", /* 95 REMOTE FILE CLOSE */ + "MV INIT", /* 96 INITIATE */ + "MV DEFTYPE", /* 97 TYPE DEFINITION */ + "MV FCOPY", /* 98 REMOTE FILE COPY */ + "MV DOWNLOAD", /* 99 VM DOMAIN DOWNLOAD */ + "MV UPLOAD", /* 100 VM DOMAIN UPLOAD */ + "MV READ VARS", /* 101 GENERAL READ */ + "MV WRITE VARS", /* 102 GENERAL WRITE */ + "", /* 103 NOT A MMS OPERATION */ + "", /* 104 NOT A MMS OPERATION */ + "" /* 105 NOT A MMS OPERATION */ + }; + +ST_INT m_num_mms_op_string = sizeof (mms_op_string)/sizeof (ST_CHAR *); + +#endif + +/************************************************************************/ +/************************************************************************/ +/* The following defines are used in initializing the request and */ +/* response decode functions, the indication and confirmation service */ +/* funtions, and the supported service indicators. */ +/************************************************************************/ + +/************************************************************************/ +/************************************************************************/ +/* VMD SUPPORT - CONFIRMED SERVICES */ +/************************************************************************/ +#if (MMS_STATUS_EN & REQ_EN) +#define MMS_STATUS_RSP_DFUN mms_status_rsp +#define MMS_STATUS_CONF_SFUN u_mp_status_conf +#else +#define MMS_STATUS_RSP_DFUN mms_rsp_not_supp +#define MMS_STATUS_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_STATUS_EN & RESP_EN) +#define MMS_STATUS_REQ_DFUN mms_status_req +#define MMS_STATUS_IND_SFUN u_status_ind +#define STATUS_SSI 0x80 +#else +#define MMS_STATUS_REQ_DFUN mms_req_not_supp +#define MMS_STATUS_IND_SFUN u_ind_not_supp +#define STATUS_SSI 0x00 +#endif + +#if (MMS_GETNAMES_EN & REQ_EN) +#define MMS_GETNAMES_RSP_DFUN mms_namelist_rsp +#define MMS_GETNAMES_CONF_SFUN u_mp_namelist_conf +#else +#define MMS_GETNAMES_RSP_DFUN mms_rsp_not_supp +#define MMS_GETNAMES_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETNAMES_EN & RESP_EN) +#define MMS_GETNAMES_REQ_DFUN mms_namelist_req +#define MMS_GETNAMES_IND_SFUN u_namelist_ind +#define GETNAMES_SSI 0x40 +#else +#define MMS_GETNAMES_REQ_DFUN mms_req_not_supp +#define MMS_GETNAMES_IND_SFUN u_ind_not_supp +#define GETNAMES_SSI 0x00 +#endif + +#if (MMS_IDENT_EN & REQ_EN) +#define MMS_IDENT_RSP_DFUN mms_identify_rsp +#define MMS_IDENT_CONF_SFUN u_mp_ident_conf +#else +#define MMS_IDENT_RSP_DFUN mms_rsp_not_supp +#define MMS_IDENT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_IDENT_EN & RESP_EN) +#define MMS_IDENT_REQ_DFUN _mms_null_pdu_dec +#define MMS_IDENT_IND_SFUN u_ident_ind +#define IDENT_SSI 0x20 +#else +#define MMS_IDENT_REQ_DFUN mms_req_not_supp +#define MMS_IDENT_IND_SFUN u_ind_not_supp +#define IDENT_SSI 0x00 +#endif + +#if (MMS_RENAME_EN & REQ_EN) +#define MMS_RENAME_RSP_DFUN _mms_null_pdu_dec +#define MMS_RENAME_CONF_SFUN u_mp_rename_conf +#else +#define MMS_RENAME_RSP_DFUN mms_rsp_not_supp +#define MMS_RENAME_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_RENAME_EN & RESP_EN) +#define MMS_RENAME_REQ_DFUN mms_rename_req +#define MMS_RENAME_IND_SFUN u_rename_ind +#define RENAME_SSI 0x10 +#else +#define MMS_RENAME_REQ_DFUN mms_req_not_supp +#define MMS_RENAME_IND_SFUN u_ind_not_supp +#define RENAME_SSI 0x00 +#endif + +#if (MMS_GETCL_EN & REQ_EN) +#define MMS_GETCL_RSP_DFUN mms_getcl_rsp +#define MMS_GETCL_CONF_SFUN u_mp_getcl_conf +#else +#define MMS_GETCL_RSP_DFUN mms_rsp_not_supp +#define MMS_GETCL_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETCL_EN & RESP_EN) +#define MMS_GETCL_REQ_DFUN mms_getcl_req +#define MMS_GETCL_IND_SFUN u_getcl_ind +#define GETCL_SSI 0x01 +#else +#define MMS_GETCL_REQ_DFUN mms_req_not_supp +#define MMS_GETCL_IND_SFUN u_ind_not_supp +#define GETCL_SSI 0x00 +#endif + +/************************************************************************/ +/* VARIABLE ACCESS - CONFIRMED SERVICES */ +/************************************************************************/ + +/* VM named read */ +#if (MMS_MV_READ_EN & REQ_EN) +#define MMS_MV_READ_CONF_SFUN u_mv_read_conf +#else +#define MMS_MV_READ_CONF_SFUN u_conf_not_supp +#endif + +/* VM general read */ +#if (MMS_MV_RDVARS_EN & REQ_EN) +#define MMS_MV_RDVARS_CONF_SFUN u_mv_read_vars_conf +#else +#define MMS_MV_RDVARS_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_READ_EN & REQ_EN) +#define MMS_READ_RSP_DFUN mms_read_rsp +#define MMS_READ_CONF_SFUN u_mp_read_conf +#else +#define MMS_READ_RSP_DFUN mms_rsp_not_supp +#define MMS_READ_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_READ_EN & RESP_EN) +#define MMS_READ_REQ_DFUN mms_read_req +#define MMS_READ_IND_SFUN u_read_ind +#define READ_SSI 0x08 +#else +#define MMS_READ_REQ_DFUN mms_req_not_supp +#define MMS_READ_IND_SFUN u_ind_not_supp +#define READ_SSI 0x00 +#endif + +/* VM named write */ +#if (MMS_MV_WRITE_EN & REQ_EN) +#define MMS_MV_WRITE_CONF_SFUN u_mv_write_conf +#else +#define MMS_MV_WRITE_CONF_SFUN u_conf_not_supp +#endif + +/* VM general write */ +#if (MMS_MV_WRVARS_EN & REQ_EN) +#define MMS_MV_WRVARS_CONF_SFUN u_mv_write_vars_conf +#else +#define MMS_MV_WRVARS_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_WRITE_EN & REQ_EN) +#define MMS_WRITE_RSP_DFUN mms_write_rsp +#define MMS_WRITE_CONF_SFUN u_mp_write_conf +#else +#define MMS_WRITE_RSP_DFUN mms_rsp_not_supp +#define MMS_WRITE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_WRITE_EN & RESP_EN) +#define MMS_WRITE_REQ_DFUN mms_write_req +#define MMS_WRITE_IND_SFUN u_write_ind +#define WRITE_SSI 0x04 +#else +#define MMS_WRITE_REQ_DFUN mms_req_not_supp +#define MMS_WRITE_IND_SFUN u_ind_not_supp +#define WRITE_SSI 0x00 +#endif + +#if (MMS_GETVAR_EN & REQ_EN) +#define MMS_GETVAR_RSP_DFUN mms_get_var_rsp +#define MMS_GETVAR_CONF_SFUN u_mp_getvar_conf +#else +#define MMS_GETVAR_RSP_DFUN mms_rsp_not_supp +#define MMS_GETVAR_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETVAR_EN & RESP_EN) +#define MMS_GETVAR_REQ_DFUN mms_get_var_req +#define MMS_GETVAR_IND_SFUN u_getvar_ind +#define GETVAR_SSI 0x02 +#else +#define MMS_GETVAR_REQ_DFUN mms_req_not_supp +#define MMS_GETVAR_IND_SFUN u_ind_not_supp +#define GETVAR_SSI 0x00 +#endif + +#if (MMS_DEFVAR_EN & REQ_EN) +#define MMS_DEFVAR_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFVAR_CONF_SFUN u_mp_defvar_conf +#else +#define MMS_DEFVAR_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFVAR_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFVAR_EN & RESP_EN) +#define MMS_DEFVAR_REQ_DFUN mms_def_var_req +#define MMS_DEFVAR_IND_SFUN u_defvar_ind +#define DEFVAR_SSI 0x01 +#else +#define MMS_DEFVAR_REQ_DFUN mms_req_not_supp +#define MMS_DEFVAR_IND_SFUN u_ind_not_supp +#define DEFVAR_SSI 0x00 +#endif + +#if (MMS_DEFSCAT_EN & REQ_EN) +#define MMS_DEFSCAT_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFSCAT_CONF_SFUN u_mp_defscat_conf +#else +#define MMS_DEFSCAT_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFSCAT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFSCAT_EN & RESP_EN) +#define MMS_DEFSCAT_REQ_DFUN mms_def_scat_req +#define MMS_DEFSCAT_IND_SFUN u_defscat_ind +#define DEFSCAT_SSI 0x80 +#else +#define MMS_DEFSCAT_REQ_DFUN mms_req_not_supp +#define MMS_DEFSCAT_IND_SFUN u_ind_not_supp +#define DEFSCAT_SSI 0x00 +#endif + +#if (MMS_GETSCAT_EN & REQ_EN) +#define MMS_GETSCAT_RSP_DFUN mms_get_scat_rsp +#define MMS_GETSCAT_CONF_SFUN u_mp_getscat_conf +#else +#define MMS_GETSCAT_RSP_DFUN mms_rsp_not_supp +#define MMS_GETSCAT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETSCAT_EN & RESP_EN) +#define MMS_GETSCAT_REQ_DFUN mms_get_scat_req +#define MMS_GETSCAT_IND_SFUN u_getscat_ind +#define GETSCAT_SSI 0x40 +#else +#define MMS_GETSCAT_REQ_DFUN mms_req_not_supp +#define MMS_GETSCAT_IND_SFUN u_ind_not_supp +#define GETSCAT_SSI 0x00 +#endif + +#if (MMS_DELVAR_EN & REQ_EN) +#define MMS_DELVAR_RSP_DFUN mms_del_var_rsp +#define MMS_DELVAR_CONF_SFUN u_mp_delvar_conf +#else +#define MMS_DELVAR_RSP_DFUN mms_rsp_not_supp +#define MMS_DELVAR_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DELVAR_EN & RESP_EN) +#define MMS_DELVAR_REQ_DFUN mms_del_var_req +#define MMS_DELVAR_IND_SFUN u_delvar_ind +#define DELVAR_SSI 0x20 +#else +#define MMS_DELVAR_REQ_DFUN mms_req_not_supp +#define MMS_DELVAR_IND_SFUN u_ind_not_supp +#define DELVAR_SSI 0x00 +#endif + +#if (MMS_DEFVLIST_EN & REQ_EN) +#define MMS_DEFVLIST_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFVLIST_CONF_SFUN u_mp_defvlist_conf +#else +#define MMS_DEFVLIST_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFVLIST_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFVLIST_EN & RESP_EN) +#define MMS_DEFVLIST_REQ_DFUN mms_def_vlist_req +#define MMS_DEFVLIST_IND_SFUN u_defvlist_ind +#define DEFVLIST_SSI 0x10 +#else +#define MMS_DEFVLIST_REQ_DFUN mms_req_not_supp +#define MMS_DEFVLIST_IND_SFUN u_ind_not_supp +#define DEFVLIST_SSI 0x00 +#endif + +#if (MMS_GETVLIST_EN & REQ_EN) +#define MMS_GETVLIST_RSP_DFUN mms_get_vlist_rsp +#define MMS_GETVLIST_CONF_SFUN u_mp_getvlist_conf +#else +#define MMS_GETVLIST_RSP_DFUN mms_rsp_not_supp +#define MMS_GETVLIST_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETVLIST_EN & RESP_EN) +#define MMS_GETVLIST_REQ_DFUN mms_get_vlist_req +#define MMS_GETVLIST_IND_SFUN u_getvlist_ind +#define GETVLIST_SSI 0x08 +#else +#define MMS_GETVLIST_REQ_DFUN mms_req_not_supp +#define MMS_GETVLIST_IND_SFUN u_ind_not_supp +#define GETVLIST_SSI 0x00 +#endif + +#if (MMS_DELVLIST_EN & REQ_EN) +#define MMS_DELVLIST_RSP_DFUN mms_del_vlist_rsp +#define MMS_DELVLIST_CONF_SFUN u_mp_delvlist_conf +#else +#define MMS_DELVLIST_RSP_DFUN mms_rsp_not_supp +#define MMS_DELVLIST_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DELVLIST_EN & RESP_EN) +#define MMS_DELVLIST_REQ_DFUN mms_del_vlist_req +#define MMS_DELVLIST_IND_SFUN u_delvlist_ind +#define DELVLIST_SSI 0x04 +#else +#define MMS_DELVLIST_REQ_DFUN mms_req_not_supp +#define MMS_DELVLIST_IND_SFUN u_ind_not_supp +#define DELVLIST_SSI 0x00 +#endif + +#if (MMS_MV_DEFTYPE_EN & REQ_EN) +#define MMS_MV_DEFTYPE_CONF_SFUN u_mv_deftype_conf +#else +#define MMS_MV_DEFTYPE_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_DEFTYPE_EN & REQ_EN) +#define MMS_DEFTYPE_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFTYPE_CONF_SFUN u_mp_deftype_conf +#else +#define MMS_DEFTYPE_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFTYPE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFTYPE_EN & RESP_EN) +#define MMS_DEFTYPE_REQ_DFUN mms_def_type_req +#define MMS_DEFTYPE_IND_SFUN u_deftype_ind +#define DEFTYPE_SSI 0x02 +#else +#define MMS_DEFTYPE_REQ_DFUN mms_req_not_supp +#define MMS_DEFTYPE_IND_SFUN u_ind_not_supp +#define DEFTYPE_SSI 0x00 +#endif + +#if (MMS_GETTYPE_EN & REQ_EN) +#define MMS_GETTYPE_RSP_DFUN mms_get_type_rsp +#define MMS_GETTYPE_CONF_SFUN u_mp_gettype_conf +#else +#define MMS_GETTYPE_RSP_DFUN mms_rsp_not_supp +#define MMS_GETTYPE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETTYPE_EN & RESP_EN) +#define MMS_GETTYPE_REQ_DFUN mms_get_type_req +#define MMS_GETTYPE_IND_SFUN u_gettype_ind +#define GETTYPE_SSI 0x01 +#else +#define MMS_GETTYPE_REQ_DFUN mms_req_not_supp +#define MMS_GETTYPE_IND_SFUN u_ind_not_supp +#define GETTYPE_SSI 0x00 +#endif + +#if (MMS_DELTYPE_EN & REQ_EN) +#define MMS_DELTYPE_RSP_DFUN mms_del_type_rsp +#define MMS_DELTYPE_CONF_SFUN u_mp_deltype_conf +#else +#define MMS_DELTYPE_RSP_DFUN mms_rsp_not_supp +#define MMS_DELTYPE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DELTYPE_EN & RESP_EN) +#define MMS_DELTYPE_REQ_DFUN mms_del_type_req +#define MMS_DELTYPE_IND_SFUN u_deltype_ind +#define DELTYPE_SSI 0x80 +#else +#define MMS_DELTYPE_REQ_DFUN mms_req_not_supp +#define MMS_DELTYPE_IND_SFUN u_ind_not_supp +#define DELTYPE_SSI 0x00 +#endif + +/************************************************************************/ +/* OPERATOR COMMUNICATION SERVICES */ +/************************************************************************/ + +#if (MMS_INPUT_EN & REQ_EN) +#define MMS_INPUT_RSP_DFUN mms_input_rsp +#define MMS_INPUT_CONF_SFUN u_mp_input_conf +#else +#define MMS_INPUT_RSP_DFUN mms_rsp_not_supp +#define MMS_INPUT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_INPUT_EN & RESP_EN) +#define MMS_INPUT_REQ_DFUN mms_input_req +#define MMS_INPUT_IND_SFUN u_input_ind +#define INPUT_SSI 0x40 +#else +#define MMS_INPUT_REQ_DFUN mms_req_not_supp +#define MMS_INPUT_IND_SFUN u_ind_not_supp +#define INPUT_SSI 0x00 +#endif + +#if (MMS_OUTPUT_EN & REQ_EN) +#define MMS_OUTPUT_RSP_DFUN _mms_null_pdu_dec +#define MMS_OUTPUT_CONF_SFUN u_mp_output_conf +#else +#define MMS_OUTPUT_RSP_DFUN mms_rsp_not_supp +#define MMS_OUTPUT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_OUTPUT_EN & RESP_EN) +#define MMS_OUTPUT_REQ_DFUN mms_output_req +#define MMS_OUTPUT_IND_SFUN u_output_ind +#define OUTPUT_SSI 0x20 +#else +#define MMS_OUTPUT_REQ_DFUN mms_req_not_supp +#define MMS_OUTPUT_IND_SFUN u_ind_not_supp +#define OUTPUT_SSI 0x00 +#endif + +/************************************************************************/ +/* SEMAPHORE MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_TAKECTRL_EN & REQ_EN) +#define MMS_TAKECTRL_RSP_DFUN mms_takectrl_rsp +#define MMS_TAKECTRL_CONF_SFUN u_mp_takectrl_conf +#else +#define MMS_TAKECTRL_RSP_DFUN mms_rsp_not_supp +#define MMS_TAKECTRL_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_TAKECTRL_EN & RESP_EN) +#define MMS_TAKECTRL_REQ_DFUN mms_takectrl_req +#define MMS_TAKECTRL_IND_SFUN u_takectrl_ind +#define TAKECTRL_SSI 0x10 +#else +#define MMS_TAKECTRL_REQ_DFUN mms_req_not_supp +#define MMS_TAKECTRL_IND_SFUN u_ind_not_supp +#define TAKECTRL_SSI 0x00 +#endif + +#if (MMS_RELCTRL_EN & REQ_EN) +#define MMS_RELCTRL_RSP_DFUN _mms_null_pdu_dec +#define MMS_RELCTRL_CONF_SFUN u_mp_relctrl_conf +#else +#define MMS_RELCTRL_RSP_DFUN mms_rsp_not_supp +#define MMS_RELCTRL_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_RELCTRL_EN & RESP_EN) +#define MMS_RELCTRL_REQ_DFUN mms_relctrl_req +#define MMS_RELCTRL_IND_SFUN u_relctrl_ind +#define RELCTRL_SSI 0x08 +#else +#define MMS_RELCTRL_REQ_DFUN mms_req_not_supp +#define MMS_RELCTRL_IND_SFUN u_ind_not_supp +#define RELCTRL_SSI 0x00 +#endif + +#if (MMS_DEFINE_SEM_EN & REQ_EN) +#define MMS_DEFINE_SEM_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFINE_SEM_CONF_SFUN u_mp_defsem_conf +#else +#define MMS_DEFINE_SEM_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFINE_SEM_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_DEFINE_SEM_EN & RESP_EN) +#define MMS_DEFINE_SEM_REQ_DFUN mms_defsem_req +#define MMS_DEFINE_SEM_IND_SFUN u_defsem_ind +#define DEFSEM_SSI 0x04 +#else +#define MMS_DEFINE_SEM_REQ_DFUN mms_req_not_supp +#define MMS_DEFINE_SEM_IND_SFUN u_ind_not_supp +#define DEFSEM_SSI 0x00 +#endif + +#if (MMS_DELETE_SEM_EN & REQ_EN) +#define MMS_DELETE_SEM_RSP_DFUN _mms_null_pdu_dec +#define MMS_DELETE_SEM_CONF_SFUN u_mp_delsem_conf +#else +#define MMS_DELETE_SEM_RSP_DFUN mms_rsp_not_supp +#define MMS_DELETE_SEM_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_DELETE_SEM_EN & RESP_EN) +#define MMS_DELETE_SEM_REQ_DFUN mms_delsem_req +#define MMS_DELETE_SEM_IND_SFUN u_delsem_ind +#define DELSEM_SSI 0x02 +#else +#define MMS_DELETE_SEM_REQ_DFUN mms_req_not_supp +#define MMS_DELETE_SEM_IND_SFUN u_ind_not_supp +#define DELSEM_SSI 0x00 +#endif + +#if (MMS_REP_SEMSTAT_EN & REQ_EN) +#define MMS_REP_SEMSTAT_RSP_DFUN mms_rsstat_rsp +#define MMS_REP_SEMSTAT_CONF_SFUN u_mp_rsstat_conf +#else +#define MMS_REP_SEMSTAT_RSP_DFUN mms_rsp_not_supp +#define MMS_REP_SEMSTAT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_REP_SEMSTAT_EN & RESP_EN) +#define MMS_REP_SEMSTAT_REQ_DFUN mms_rsstat_req +#define MMS_REP_SEMSTAT_IND_SFUN u_rsstat_ind +#define RSSTAT_SSI 0x01 +#else +#define MMS_REP_SEMSTAT_REQ_DFUN mms_req_not_supp +#define MMS_REP_SEMSTAT_IND_SFUN u_ind_not_supp +#define RSSTAT_SSI 0x00 +#endif + +#if (MMS_REP_SEMPOOL_EN & REQ_EN) +#define MMS_REP_SEMPOOL_RSP_DFUN mms_rspool_rsp +#define MMS_REP_SEMPOOL_CONF_SFUN u_mp_rspool_conf +#else +#define MMS_REP_SEMPOOL_RSP_DFUN mms_rsp_not_supp +#define MMS_REP_SEMPOOL_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_REP_SEMPOOL_EN & RESP_EN) +#define MMS_REP_SEMPOOL_REQ_DFUN mms_rspool_req +#define MMS_REP_SEMPOOL_IND_SFUN u_rspool_ind +#define RSPOOL_SSI 0x80 +#else +#define MMS_REP_SEMPOOL_REQ_DFUN mms_req_not_supp +#define MMS_REP_SEMPOOL_IND_SFUN u_ind_not_supp +#define RSPOOL_SSI 0x00 +#endif + +#if (MMS_REP_SEMENTRY_EN & REQ_EN) +#define MMS_REP_SEMENTRY_RSP_DFUN mms_rsentry_rsp +#define MMS_REP_SEMENTRY_CONF_SFUN u_mp_rsentry_conf +#else +#define MMS_REP_SEMENTRY_RSP_DFUN mms_rsp_not_supp +#define MMS_REP_SEMENTRY_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_REP_SEMENTRY_EN & RESP_EN) +#define MMS_REP_SEMENTRY_REQ_DFUN mms_rsentry_req +#define MMS_REP_SEMENTRY_IND_SFUN u_rsentry_ind +#define RSENTRY_SSI 0x40 +#else +#define MMS_REP_SEMENTRY_REQ_DFUN mms_req_not_supp +#define MMS_REP_SEMENTRY_IND_SFUN u_ind_not_supp +#define RSENTRY_SSI 0x00 +#endif + +/************************************************************************/ +/* DOMAIN MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_INIT_DWN_EN & REQ_EN) +#define MMS_INIT_DWN_RSP_DFUN mms_init_download_rsp +#define MMS_INIT_DWN_CONF_SFUN u_mp_initdown_conf +#else +#define MMS_INIT_DWN_RSP_DFUN mms_rsp_not_supp +#define MMS_INIT_DWN_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_INIT_DWN_EN & RESP_EN) +#define MMS_INIT_DWN_REQ_DFUN mms_init_download_req +#define MMS_INIT_DWN_IND_SFUN u_initdown_ind +#define INITDWN_SSI 0x20 +#else +#define MMS_INIT_DWN_REQ_DFUN mms_req_not_supp +#define MMS_INIT_DWN_IND_SFUN u_ind_not_supp +#define INITDWN_SSI 0x00 +#endif + +#if (MMS_DWN_LOAD_EN & REQ_EN) +#define MMS_DWN_LOAD_RSP_DFUN mms_download_rsp +#define MMS_DWN_LOAD_CONF_SFUN u_mp_download_conf +#else +#define MMS_DWN_LOAD_RSP_DFUN mms_rsp_not_supp +#define MMS_DWN_LOAD_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_DWN_LOAD_EN & RESP_EN) +#define MMS_DWN_LOAD_REQ_DFUN mms_download_req +#define MMS_DWN_LOAD_IND_SFUN u_download_ind +#define DOWNLOAD_SSI 0x10 +#else +#define MMS_DWN_LOAD_REQ_DFUN mms_req_not_supp +#define MMS_DWN_LOAD_IND_SFUN u_ind_not_supp +#define DOWNLOAD_SSI 0x00 +#endif + +#if (MMS_TERM_DWN_EN & REQ_EN) +#define MMS_TERM_DWN_RSP_DFUN _mms_null_pdu_dec +#define MMS_TERM_DWN_CONF_SFUN u_mp_termdown_conf +#else +#define MMS_TERM_DWN_RSP_DFUN mms_rsp_not_supp +#define MMS_TERM_DWN_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_TERM_DWN_EN & RESP_EN) +#define MMS_TERM_DWN_REQ_DFUN mms_term_download_req +#define MMS_TERM_DWN_IND_SFUN u_termdown_ind +#define TERMDOWN_SSI 0x08 +#else +#define MMS_TERM_DWN_REQ_DFUN mms_req_not_supp +#define MMS_TERM_DWN_IND_SFUN u_ind_not_supp +#define TERMDOWN_SSI 0x00 +#endif + +#if (MMS_MV_DWN_EN & REQ_EN) +#define MMS_MV_DOWNLOAD_CONF_SFUN u_mv_download_conf +#else +#define MMS_MV_DOWNLOAD_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_INIT_UPL_EN & REQ_EN) +#define MMS_INIT_UPL_RSP_DFUN mms_init_upload_rsp +#define MMS_INIT_UPL_CONF_SFUN u_mp_initupl_conf +#else +#define MMS_INIT_UPL_RSP_DFUN mms_rsp_not_supp +#define MMS_INIT_UPL_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_INIT_UPL_EN & RESP_EN) +#define MMS_INIT_UPL_REQ_DFUN mms_init_upload_req +#define MMS_INIT_UPL_IND_SFUN u_initupl_ind +#define INITUPL_SSI 0x04 +#else +#define MMS_INIT_UPL_REQ_DFUN mms_req_not_supp +#define MMS_INIT_UPL_IND_SFUN u_ind_not_supp +#define INITUPL_SSI 0x00 +#endif + +#if (MMS_UP_LOAD_EN & REQ_EN) +#define MMS_UP_LOAD_RSP_DFUN mms_upload_rsp +#define MMS_UP_LOAD_CONF_SFUN u_mp_upload_conf +#else +#define MMS_UP_LOAD_RSP_DFUN mms_rsp_not_supp +#define MMS_UP_LOAD_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_UP_LOAD_EN & RESP_EN) +#define MMS_UP_LOAD_REQ_DFUN mms_upload_req +#define MMS_UP_LOAD_IND_SFUN u_upload_ind +#define UPLOAD_SSI 0x02 +#else +#define MMS_UP_LOAD_REQ_DFUN mms_req_not_supp +#define MMS_UP_LOAD_IND_SFUN u_ind_not_supp +#define UPLOAD_SSI 0x00 +#endif + +#if (MMS_TERM_UPL_EN & REQ_EN) +#define MMS_TERM_UPL_RSP_DFUN _mms_null_pdu_dec +#define MMS_TERM_UPL_CONF_SFUN u_mp_termupl_conf +#else +#define MMS_TERM_UPL_RSP_DFUN mms_rsp_not_supp +#define MMS_TERM_UPL_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_TERM_UPL_EN & RESP_EN) +#define MMS_TERM_UPL_REQ_DFUN mms_term_upload_req +#define MMS_TERM_UPL_IND_SFUN u_termupl_ind +#define TERMUPL_SSI 0x01 +#else +#define MMS_TERM_UPL_REQ_DFUN mms_req_not_supp +#define MMS_TERM_UPL_IND_SFUN u_ind_not_supp +#define TERMUPL_SSI 0x00 +#endif + +#if (MMS_MV_UPL_EN & REQ_EN) +#define MMS_MV_UPLOAD_CONF_SFUN u_mv_upload_conf +#else +#define MMS_MV_UPLOAD_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_RDDWN_EN & REQ_EN) +#define MMS_RDDWN_RSP_DFUN _mms_null_pdu_dec +#define MMS_RDDWN_CONF_SFUN u_mp_rddwn_conf +#else +#define MMS_RDDWN_RSP_DFUN mms_rsp_not_supp +#define MMS_RDDWN_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_RDDWN_EN & RESP_EN) +#define MMS_RDDWN_REQ_DFUN mms_rddwn_req +#define MMS_RDDWN_IND_SFUN u_rddwn_ind +#define RDDWN_SSI 0x80 +#else +#define MMS_RDDWN_REQ_DFUN mms_req_not_supp +#define MMS_RDDWN_IND_SFUN u_ind_not_supp +#define RDDWN_SSI 0x00 +#endif + +#if (MMS_RDUPL_EN & REQ_EN) +#define MMS_RDUPL_RSP_DFUN _mms_null_pdu_dec +#define MMS_RDUPL_CONF_SFUN u_mp_rdupl_conf +#else +#define MMS_RDUPL_RSP_DFUN mms_rsp_not_supp +#define MMS_RDUPL_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_RDUPL_EN & RESP_EN) +#define MMS_RDUPL_REQ_DFUN mms_rdupl_req +#define MMS_RDUPL_IND_SFUN u_rdupl_ind +#define RDUPL_SSI 0x40 +#else +#define MMS_RDUPL_REQ_DFUN mms_req_not_supp +#define MMS_RDUPL_IND_SFUN u_ind_not_supp +#define RDUPL_SSI 0x00 +#endif + +#if (MMS_LOAD_DOM_EN & REQ_EN) +#define MMS_LOAD_DOM_RSP_DFUN _mms_null_pdu_dec +#define MMS_LOAD_DOM_CONF_SFUN u_mp_loaddom_conf +#else +#define MMS_LOAD_DOM_RSP_DFUN mms_rsp_not_supp +#define MMS_LOAD_DOM_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_LOAD_DOM_EN & RESP_EN) +#define MMS_LOAD_DOM_REQ_DFUN mms_load_domain_req +#define MMS_LOAD_DOM_IND_SFUN u_loaddom_ind +#define LOADDOM_SSI 0x20 +#else +#define MMS_LOAD_DOM_REQ_DFUN mms_req_not_supp +#define MMS_LOAD_DOM_IND_SFUN u_ind_not_supp +#define LOADDOM_SSI 0x00 +#endif + +#if (MMS_STR_DOM_EN & REQ_EN) +#define MMS_STR_DOM_RSP_DFUN _mms_null_pdu_dec +#define MMS_STR_DOM_CONF_SFUN u_mp_storedom_conf +#else +#define MMS_STR_DOM_RSP_DFUN mms_rsp_not_supp +#define MMS_STR_DOM_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_STR_DOM_EN & RESP_EN) +#define MMS_STR_DOM_REQ_DFUN mms_store_domain_req +#define MMS_STR_DOM_IND_SFUN u_storedom_ind +#define STRDOM_SSI 0x10 +#else +#define MMS_STR_DOM_REQ_DFUN mms_req_not_supp +#define MMS_STR_DOM_IND_SFUN u_ind_not_supp +#define STRDOM_SSI 0x00 +#endif + +#if (MMS_DEL_DOM_EN & REQ_EN) +#define MMS_DEL_DOM_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEL_DOM_CONF_SFUN u_mp_deldom_conf +#else +#define MMS_DEL_DOM_RSP_DFUN mms_rsp_not_supp +#define MMS_DEL_DOM_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEL_DOM_EN & RESP_EN) +#define MMS_DEL_DOM_REQ_DFUN mms_delete_domain_req +#define MMS_DEL_DOM_IND_SFUN u_deldom_ind +#define DELDOM_SSI 0x08 +#else +#define MMS_DEL_DOM_REQ_DFUN mms_req_not_supp +#define MMS_DEL_DOM_IND_SFUN u_ind_not_supp +#define DELDOM_SSI 0x00 +#endif + +#if (MMS_GET_DOM_EN & REQ_EN) +#define MMS_GET_DOM_RSP_DFUN mms_get_dom_attr_rsp +#define MMS_GET_DOM_CONF_SFUN u_mp_getdom_conf +#else +#define MMS_GET_DOM_RSP_DFUN mms_rsp_not_supp +#define MMS_GET_DOM_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GET_DOM_EN & RESP_EN) +#define MMS_GET_DOM_REQ_DFUN mms_get_dom_attr_req +#define MMS_GET_DOM_IND_SFUN u_getdom_ind +#define GETDOM_SSI 0x04 +#else +#define MMS_GET_DOM_REQ_DFUN mms_req_not_supp +#define MMS_GET_DOM_IND_SFUN u_ind_not_supp +#define GETDOM_SSI 0x00 +#endif + +/************************************************************************/ +/* PROGRAM INVOCATION MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_CRE_PI_EN & REQ_EN) +#define MMS_CRE_PI_RSP_DFUN _mms_null_pdu_dec +#define MMS_CRE_PI_CONF_SFUN u_mp_crepi_conf +#else +#define MMS_CRE_PI_RSP_DFUN mms_rsp_not_supp +#define MMS_CRE_PI_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_CRE_PI_EN & RESP_EN) +#define MMS_CRE_PI_REQ_DFUN mms_create_pi_req +#define MMS_CRE_PI_IND_SFUN u_crepi_ind +#define CREPI_SSI 0x02 +#else +#define MMS_CRE_PI_REQ_DFUN mms_req_not_supp +#define MMS_CRE_PI_IND_SFUN u_ind_not_supp +#define CREPI_SSI 0x00 +#endif + +#if (MMS_DEL_PI_EN & REQ_EN) +#define MMS_DEL_PI_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEL_PI_CONF_SFUN u_mp_delpi_conf +#else +#define MMS_DEL_PI_RSP_DFUN mms_rsp_not_supp +#define MMS_DEL_PI_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEL_PI_EN & RESP_EN) +#define MMS_DEL_PI_REQ_DFUN mms_delete_pi_req +#define MMS_DEL_PI_IND_SFUN u_delpi_ind +#define DELPI_SSI 0x01 +#else +#define MMS_DEL_PI_REQ_DFUN mms_req_not_supp +#define MMS_DEL_PI_IND_SFUN u_ind_not_supp +#define DELPI_SSI 0x00 +#endif + +#if (MMS_START_EN & REQ_EN) +#define MMS_START_RSP_DFUN _mms_null_pdu_dec +#define MMS_START_CONF_SFUN u_mp_start_conf +#else +#define MMS_START_RSP_DFUN mms_rsp_not_supp +#define MMS_START_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_START_EN & RESP_EN) +#define MMS_START_REQ_DFUN mms_start_req +#define MMS_START_IND_SFUN u_start_ind +#define START_SSI 0x80 +#else +#define MMS_START_REQ_DFUN mms_req_not_supp +#define MMS_START_IND_SFUN u_ind_not_supp +#define START_SSI 0x00 +#endif + +#if (MMS_STOP_EN & REQ_EN) +#define MMS_STOP_RSP_DFUN _mms_null_pdu_dec +#define MMS_STOP_CONF_SFUN u_mp_stop_conf +#else +#define MMS_STOP_RSP_DFUN mms_rsp_not_supp +#define MMS_STOP_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_STOP_EN & RESP_EN) +#define MMS_STOP_REQ_DFUN mms_stop_req +#define MMS_STOP_IND_SFUN u_stop_ind +#define STOP_SSI 0x40 +#else +#define MMS_STOP_REQ_DFUN mms_req_not_supp +#define MMS_STOP_IND_SFUN u_ind_not_supp +#define STOP_SSI 0x00 +#endif + +#if (MMS_RESUME_EN & REQ_EN) +#define MMS_RESUME_RSP_DFUN _mms_null_pdu_dec +#define MMS_RESUME_CONF_SFUN u_mp_resume_conf +#else +#define MMS_RESUME_RSP_DFUN mms_rsp_not_supp +#define MMS_RESUME_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_RESUME_EN & RESP_EN) +#define MMS_RESUME_REQ_DFUN mms_resume_req +#define MMS_RESUME_IND_SFUN u_resume_ind +#define RESUME_SSI 0x20 +#else +#define MMS_RESUME_REQ_DFUN mms_req_not_supp +#define MMS_RESUME_IND_SFUN u_ind_not_supp +#define RESUME_SSI 0x00 +#endif + +#if (MMS_RESET_EN & REQ_EN) +#define MMS_RESET_RSP_DFUN _mms_null_pdu_dec +#define MMS_RESET_CONF_SFUN u_mp_reset_conf +#else +#define MMS_RESET_RSP_DFUN mms_rsp_not_supp +#define MMS_RESET_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_RESET_EN & RESP_EN) +#define MMS_RESET_REQ_DFUN mms_reset_req +#define MMS_RESET_IND_SFUN u_reset_ind +#define RESET_SSI 0x10 +#else +#define MMS_RESET_REQ_DFUN mms_req_not_supp +#define MMS_RESET_IND_SFUN u_ind_not_supp +#define RESET_SSI 0x00 +#endif + +#if (MMS_KILL_EN & REQ_EN) +#define MMS_KILL_RSP_DFUN _mms_null_pdu_dec +#define MMS_KILL_CONF_SFUN u_mp_kill_conf +#else +#define MMS_KILL_RSP_DFUN mms_rsp_not_supp +#define MMS_KILL_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_KILL_EN & RESP_EN) +#define MMS_KILL_REQ_DFUN mms_kill_req +#define MMS_KILL_IND_SFUN u_kill_ind +#define KILL_SSI 0x08 +#else +#define MMS_KILL_REQ_DFUN mms_req_not_supp +#define MMS_KILL_IND_SFUN u_ind_not_supp +#define KILL_SSI 0x00 +#endif + +#if (MMS_GET_PI_EN & REQ_EN) +#define MMS_GET_PI_RSP_DFUN mms_get_pi_rsp +#define MMS_GET_PI_CONF_SFUN u_mp_getpi_conf +#else +#define MMS_GET_PI_RSP_DFUN mms_rsp_not_supp +#define MMS_GET_PI_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GET_PI_EN & RESP_EN) +#define MMS_GET_PI_REQ_DFUN mms_get_pi_req +#define MMS_GET_PI_IND_SFUN u_getpi_ind +#define GETPI_SSI 0x04 +#else +#define MMS_GET_PI_REQ_DFUN mms_req_not_supp +#define MMS_GET_PI_IND_SFUN u_ind_not_supp +#define GETPI_SSI 0x00 +#endif + +/************************************************************************/ +/* EVENT MANAGEMENT - CONFIRMED SERVICES */ +/************************************************************************/ + +#if (MMS_DEFEC_EN & REQ_EN) +#define MMS_DEFEC_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFEC_CONF_SFUN u_mp_defec_conf +#else +#define MMS_DEFEC_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFEC_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFEC_EN & RESP_EN) +#define MMS_DEFEC_REQ_DFUN mms_defec_req +#define MMS_DEFEC_IND_SFUN u_defec_ind +#define DEFEC_SSI 0x01 +#else +#define MMS_DEFEC_REQ_DFUN mms_req_not_supp +#define MMS_DEFEC_IND_SFUN u_ind_not_supp +#define DEFEC_SSI 0x00 +#endif + +#if (MMS_DELEC_EN & REQ_EN) +#define MMS_DELEC_RSP_DFUN mms_delec_rsp +#define MMS_DELEC_CONF_SFUN u_mp_delec_conf +#else +#define MMS_DELEC_RSP_DFUN mms_rsp_not_supp +#define MMS_DELEC_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DELEC_EN & RESP_EN) +#define MMS_DELEC_REQ_DFUN mms_delec_req +#define MMS_DELEC_IND_SFUN u_delec_ind +#define DELEC_SSI 0x80 +#else +#define MMS_DELEC_REQ_DFUN mms_req_not_supp +#define MMS_DELEC_IND_SFUN u_ind_not_supp +#define DELEC_SSI 0x00 +#endif + +#if (MMS_GETECA_EN & REQ_EN) +#define MMS_GETECA_RSP_DFUN mms_geteca_rsp +#define MMS_GETECA_CONF_SFUN u_mp_geteca_conf +#else +#define MMS_GETECA_RSP_DFUN mms_rsp_not_supp +#define MMS_GETECA_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETECA_EN & RESP_EN) +#define MMS_GETECA_REQ_DFUN mms_geteca_req +#define MMS_GETECA_IND_SFUN u_geteca_ind +#define GETECA_SSI 0x40 +#else +#define MMS_GETECA_REQ_DFUN mms_req_not_supp +#define MMS_GETECA_IND_SFUN u_ind_not_supp +#define GETECA_SSI 0x00 +#endif + +#if (MMS_REPECS_EN & REQ_EN) +#define MMS_REPECS_RSP_DFUN mms_repecs_rsp +#define MMS_REPECS_CONF_SFUN u_mp_repecs_conf +#else +#define MMS_REPECS_RSP_DFUN mms_rsp_not_supp +#define MMS_REPECS_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_REPECS_EN & RESP_EN) +#define MMS_REPECS_REQ_DFUN mms_repecs_req +#define MMS_REPECS_IND_SFUN u_repecs_ind +#define REPECS_SSI 0x20 +#else +#define MMS_REPECS_REQ_DFUN mms_req_not_supp +#define MMS_REPECS_IND_SFUN u_ind_not_supp +#define REPECS_SSI 0x00 +#endif + +#if (MMS_ALTECM_EN & REQ_EN) +#define MMS_ALTECM_RSP_DFUN _mms_null_pdu_dec +#define MMS_ALTECM_CONF_SFUN u_mp_altecm_conf +#else +#define MMS_ALTECM_RSP_DFUN mms_rsp_not_supp +#define MMS_ALTECM_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_ALTECM_EN & RESP_EN) +#define MMS_ALTECM_REQ_DFUN mms_altecm_req +#define MMS_ALTECM_IND_SFUN u_altecm_ind +#define ALTECM_SSI 0x10 +#else +#define MMS_ALTECM_REQ_DFUN mms_req_not_supp +#define MMS_ALTECM_IND_SFUN u_ind_not_supp +#define ALTECM_SSI 0x00 +#endif + +#if (MMS_TRIGE_EN & REQ_EN) +#define MMS_TRIGE_RSP_DFUN _mms_null_pdu_dec +#define MMS_TRIGE_CONF_SFUN u_mp_trige_conf +#else +#define MMS_TRIGE_RSP_DFUN mms_rsp_not_supp +#define MMS_TRIGE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_TRIGE_EN & RESP_EN) +#define MMS_TRIGE_REQ_DFUN mms_trige_req +#define MMS_TRIGE_IND_SFUN u_trige_ind +#define TRIGE_SSI 0x08 +#else +#define MMS_TRIGE_REQ_DFUN mms_req_not_supp +#define MMS_TRIGE_IND_SFUN u_ind_not_supp +#define TRIGE_SSI 0x00 +#endif + +#if (MMS_DEFEA_EN & REQ_EN) +#define MMS_DEFEA_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFEA_CONF_SFUN u_mp_defea_conf +#else +#define MMS_DEFEA_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFEA_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFEA_EN & RESP_EN) +#define MMS_DEFEA_REQ_DFUN mms_defea_req +#define MMS_DEFEA_IND_SFUN u_defea_ind +#define DEFEA_SSI 0x04 +#else +#define MMS_DEFEA_REQ_DFUN mms_req_not_supp +#define MMS_DEFEA_IND_SFUN u_ind_not_supp +#define DEFEA_SSI 0x00 +#endif + +#if (MMS_DELEA_EN & REQ_EN) +#define MMS_DELEA_RSP_DFUN mms_delea_rsp +#define MMS_DELEA_CONF_SFUN u_mp_delea_conf +#else +#define MMS_DELEA_RSP_DFUN mms_rsp_not_supp +#define MMS_DELEA_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DELEA_EN & RESP_EN) +#define MMS_DELEA_REQ_DFUN mms_delea_req +#define MMS_DELEA_IND_SFUN u_delea_ind +#define DELEA_SSI 0x02 +#else +#define MMS_DELEA_REQ_DFUN mms_req_not_supp +#define MMS_DELEA_IND_SFUN u_ind_not_supp +#define DELEA_SSI 0x00 +#endif + +#if (MMS_GETEAA_EN & REQ_EN) +#define MMS_GETEAA_RSP_DFUN mms_geteaa_rsp +#define MMS_GETEAA_CONF_SFUN u_mp_geteaa_conf +#else +#define MMS_GETEAA_RSP_DFUN mms_rsp_not_supp +#define MMS_GETEAA_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETEAA_EN & RESP_EN) +#define MMS_GETEAA_REQ_DFUN mms_geteaa_req +#define MMS_GETEAA_IND_SFUN u_geteaa_ind +#define GETEAA_SSI 0x01 +#else +#define MMS_GETEAA_REQ_DFUN mms_req_not_supp +#define MMS_GETEAA_IND_SFUN u_ind_not_supp +#define GETEAA_SSI 0x00 +#endif + +#if (MMS_REPEAS_EN & REQ_EN) +#define MMS_REPEAS_RSP_DFUN mms_repeas_rsp +#define MMS_REPEAS_CONF_SFUN u_mp_repeas_conf +#else +#define MMS_REPEAS_RSP_DFUN mms_rsp_not_supp +#define MMS_REPEAS_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_REPEAS_EN & RESP_EN) +#define MMS_REPEAS_REQ_DFUN mms_repeas_req +#define MMS_REPEAS_IND_SFUN u_repeas_ind +#define REPEAS_SSI 0x80 +#else +#define MMS_REPEAS_REQ_DFUN mms_req_not_supp +#define MMS_REPEAS_IND_SFUN u_ind_not_supp +#define REPEAS_SSI 0x00 +#endif + +#if (MMS_DEFEE_EN & REQ_EN) +#define MMS_DEFEE_RSP_DFUN _mms_null_pdu_dec +#define MMS_DEFEE_CONF_SFUN u_mp_defee_conf +#else +#define MMS_DEFEE_RSP_DFUN mms_rsp_not_supp +#define MMS_DEFEE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DEFEE_EN & RESP_EN) +#define MMS_DEFEE_REQ_DFUN mms_defee_req +#define MMS_DEFEE_IND_SFUN u_defee_ind +#define DEFEE_SSI 0x40 +#else +#define MMS_DEFEE_REQ_DFUN mms_req_not_supp +#define MMS_DEFEE_IND_SFUN u_ind_not_supp +#define DEFEE_SSI 0x00 +#endif + +#if (MMS_DELEE_EN & REQ_EN) +#define MMS_DELEE_RSP_DFUN mms_delee_rsp +#define MMS_DELEE_CONF_SFUN u_mp_delee_conf +#else +#define MMS_DELEE_RSP_DFUN mms_rsp_not_supp +#define MMS_DELEE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_DELEE_EN & RESP_EN) +#define MMS_DELEE_REQ_DFUN mms_delee_req +#define MMS_DELEE_IND_SFUN u_delee_ind +#define DELEE_SSI 0x20 +#else +#define MMS_DELEE_REQ_DFUN mms_req_not_supp +#define MMS_DELEE_IND_SFUN u_ind_not_supp +#define DELEE_SSI 0x00 +#endif + +#if (MMS_ALTEE_EN & REQ_EN) +#define MMS_ALTEE_RSP_DFUN mms_altee_rsp +#define MMS_ALTEE_CONF_SFUN u_mp_altee_conf +#else +#define MMS_ALTEE_RSP_DFUN mms_rsp_not_supp +#define MMS_ALTEE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_ALTEE_EN & RESP_EN) +#define MMS_ALTEE_REQ_DFUN mms_altee_req +#define MMS_ALTEE_IND_SFUN u_altee_ind +#define ALTEE_SSI 0x10 +#else +#define MMS_ALTEE_REQ_DFUN mms_req_not_supp +#define MMS_ALTEE_IND_SFUN u_ind_not_supp +#define ALTEE_SSI 0x00 +#endif + +#if (MMS_REPEES_EN & REQ_EN) +#define MMS_REPEES_RSP_DFUN mms_repees_rsp +#define MMS_REPEES_CONF_SFUN u_mp_repees_conf +#else +#define MMS_REPEES_RSP_DFUN mms_rsp_not_supp +#define MMS_REPEES_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_REPEES_EN & RESP_EN) +#define MMS_REPEES_REQ_DFUN mms_repees_req +#define MMS_REPEES_IND_SFUN u_repees_ind +#define REPEES_SSI 0x08 +#else +#define MMS_REPEES_REQ_DFUN mms_req_not_supp +#define MMS_REPEES_IND_SFUN u_ind_not_supp +#define REPEES_SSI 0x00 +#endif + +#if (MMS_GETEEA_EN & REQ_EN) +#define MMS_GETEEA_RSP_DFUN mms_geteea_rsp +#define MMS_GETEEA_CONF_SFUN u_mp_geteea_conf +#else +#define MMS_GETEEA_RSP_DFUN mms_rsp_not_supp +#define MMS_GETEEA_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETEEA_EN & RESP_EN) +#define MMS_GETEEA_REQ_DFUN mms_geteea_req +#define MMS_GETEEA_IND_SFUN u_geteea_ind +#define GETEEA_SSI 0x04 +#else +#define MMS_GETEEA_REQ_DFUN mms_req_not_supp +#define MMS_GETEEA_IND_SFUN u_ind_not_supp +#define GETEEA_SSI 0x00 +#endif + +#if (MMS_ACKEVNOT_EN & REQ_EN) +#define MMS_ACKEVNOT_RSP_DFUN _mms_null_pdu_dec +#define MMS_ACKEVNOT_CONF_SFUN u_mp_ackevnot_conf +#else +#define MMS_ACKEVNOT_RSP_DFUN mms_rsp_not_supp +#define MMS_ACKEVNOT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_ACKEVNOT_EN & RESP_EN) +#define MMS_ACKEVNOT_REQ_DFUN mms_ackevnot_req +#define MMS_ACKEVNOT_IND_SFUN u_ackevnot_ind +#define ACKEVNOT_SSI 0x02 +#else +#define MMS_ACKEVNOT_REQ_DFUN mms_req_not_supp +#define MMS_ACKEVNOT_IND_SFUN u_ind_not_supp +#define ACKEVNOT_SSI 0x00 +#endif + +#if (MMS_GETAS_EN & REQ_EN) +#define MMS_GETAS_RSP_DFUN mms_getas_rsp +#define MMS_GETAS_CONF_SFUN u_mp_getas_conf +#else +#define MMS_GETAS_RSP_DFUN mms_rsp_not_supp +#define MMS_GETAS_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETAS_EN & RESP_EN) +#define MMS_GETAS_REQ_DFUN mms_getas_req +#define MMS_GETAS_IND_SFUN u_getas_ind +#define GETAS_SSI 0x01 +#else +#define MMS_GETAS_REQ_DFUN mms_req_not_supp +#define MMS_GETAS_IND_SFUN u_ind_not_supp +#define GETAS_SSI 0x00 +#endif + +#if (MMS_GETAES_EN & REQ_EN) +#define MMS_GETAES_RSP_DFUN mms_getaes_rsp +#define MMS_GETAES_CONF_SFUN u_mp_getaes_conf +#else +#define MMS_GETAES_RSP_DFUN mms_rsp_not_supp +#define MMS_GETAES_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_GETAES_EN & RESP_EN) +#define MMS_GETAES_REQ_DFUN mms_getaes_req +#define MMS_GETAES_IND_SFUN u_getaes_ind +#define GETAES_SSI 0x80 +#else +#define MMS_GETAES_REQ_DFUN mms_req_not_supp +#define MMS_GETAES_IND_SFUN u_ind_not_supp +#define GETAES_SSI 0x00 +#endif + +/************************************************************************/ +/* JOURNAL MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_JREAD_EN & REQ_EN) +#define MMS_JREAD_RSP_DFUN mms_jread_rsp +#define MMS_JREAD_CONF_SFUN u_mp_jread_conf +#else +#define MMS_JREAD_RSP_DFUN mms_rsp_not_supp +#define MMS_JREAD_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_JREAD_EN & RESP_EN) +#define MMS_JREAD_REQ_DFUN mms_jread_req +#define MMS_JREAD_IND_SFUN u_jread_ind +#define JREAD_SSI 0x40 +#else +#define MMS_JREAD_REQ_DFUN mms_req_not_supp +#define MMS_JREAD_IND_SFUN u_ind_not_supp +#define JREAD_SSI 0x00 +#endif + +#if (MMS_JWRITE_EN & REQ_EN) +#define MMS_JWRITE_RSP_DFUN _mms_null_pdu_dec +#define MMS_JWRITE_CONF_SFUN u_mp_jwrite_conf +#else +#define MMS_JWRITE_RSP_DFUN mms_rsp_not_supp +#define MMS_JWRITE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_JWRITE_EN & RESP_EN) +#define MMS_JWRITE_REQ_DFUN mms_jwrite_req +#define MMS_JWRITE_IND_SFUN u_jwrite_ind +#define JWRITE_SSI 0x20 +#else +#define MMS_JWRITE_REQ_DFUN mms_req_not_supp +#define MMS_JWRITE_IND_SFUN u_ind_not_supp +#define JWRITE_SSI 0x00 +#endif + +#if (MMS_JINIT_EN & REQ_EN) +#define MMS_JINIT_RSP_DFUN mms_jinit_rsp +#define MMS_JINIT_CONF_SFUN u_mp_jinit_conf +#else +#define MMS_JINIT_RSP_DFUN mms_rsp_not_supp +#define MMS_JINIT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_JINIT_EN & RESP_EN) +#define MMS_JINIT_REQ_DFUN mms_jinit_req +#define MMS_JINIT_IND_SFUN u_jinit_ind +#define JINIT_SSI 0x10 +#else +#define MMS_JINIT_REQ_DFUN mms_req_not_supp +#define MMS_JINIT_IND_SFUN u_ind_not_supp +#define JINIT_SSI 0x00 +#endif + +#if (MMS_JSTAT_EN & REQ_EN) +#define MMS_JSTAT_RSP_DFUN mms_jstat_rsp +#define MMS_JSTAT_CONF_SFUN u_mp_jstat_conf +#else +#define MMS_JSTAT_RSP_DFUN mms_rsp_not_supp +#define MMS_JSTAT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_JSTAT_EN & RESP_EN) +#define MMS_JSTAT_REQ_DFUN mms_jstat_req +#define MMS_JSTAT_IND_SFUN u_jstat_ind +#define JSTAT_SSI 0x08 +#else +#define MMS_JSTAT_REQ_DFUN mms_req_not_supp +#define MMS_JSTAT_IND_SFUN u_ind_not_supp +#define JSTAT_SSI 0x00 +#endif + +#if (MMS_JCREATE_EN & REQ_EN) +#define MMS_JCREATE_RSP_DFUN _mms_null_pdu_dec +#define MMS_JCREATE_CONF_SFUN u_mp_jcreate_conf +#else +#define MMS_JCREATE_RSP_DFUN mms_rsp_not_supp +#define MMS_JCREATE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_JCREATE_EN & RESP_EN) +#define MMS_JCREATE_REQ_DFUN mms_jcreate_req +#define MMS_JCREATE_IND_SFUN u_jcreate_ind +#define JCREATE_SSI 0x04 +#else +#define MMS_JCREATE_REQ_DFUN mms_req_not_supp +#define MMS_JCREATE_IND_SFUN u_ind_not_supp +#define JCREATE_SSI 0x00 +#endif + +#if (MMS_JDELETE_EN & REQ_EN) +#define MMS_JDELETE_RSP_DFUN _mms_null_pdu_dec +#define MMS_JDELETE_CONF_SFUN u_mp_jdelete_conf +#else +#define MMS_JDELETE_RSP_DFUN mms_rsp_not_supp +#define MMS_JDELETE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_JDELETE_EN & RESP_EN) +#define MMS_JDELETE_REQ_DFUN mms_jdelete_req +#define MMS_JDELETE_IND_SFUN u_jdelete_ind +#define JDELETE_SSI 0x02 +#else +#define MMS_JDELETE_REQ_DFUN mms_req_not_supp +#define MMS_JDELETE_IND_SFUN u_ind_not_supp +#define JDELETE_SSI 0x00 +#endif + +/************************************************************************/ +/* FILE MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_OBTAINFILE_EN & REQ_EN) +#define MMS_OBTAINFILE_RSP_DFUN _mms_null_pdu_dec +#define MMS_OBTAINFILE_CONF_SFUN u_mp_obtfile_conf +#else +#define MMS_OBTAINFILE_RSP_DFUN mms_rsp_not_supp +#define MMS_OBTAINFILE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_OBTAINFILE_EN & RESP_EN) +#define MMS_OBTAINFILE_REQ_DFUN mms_obtain_file_req +#define MMS_OBTAINFILE_IND_SFUN u_obtfile_ind +#define OBTFILE_SSI 0x02 +#else +#define MMS_OBTAINFILE_REQ_DFUN mms_req_not_supp +#define MMS_OBTAINFILE_IND_SFUN u_ind_not_supp +#define OBTFILE_SSI 0x00 +#endif + +#if (MMS_MV_FOPEN_EN & REQ_EN) +#define MMS_MV_FOPEN_CONF_SFUN u_mv_fopen_conf +#else +#define MMS_MV_FOPEN_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_FOPEN_EN & REQ_EN) +#define MMS_FOPEN_RSP_DFUN mms_file_open_rsp +#define MMS_FOPEN_CONF_SFUN u_mp_fopen_conf +#else +#define MMS_FOPEN_RSP_DFUN mms_rsp_not_supp +#define MMS_FOPEN_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_FOPEN_EN & RESP_EN) +#define MMS_FOPEN_REQ_DFUN mms_file_open_req +#define MMS_FOPEN_IND_SFUN u_fopen_ind +#define FOPEN_SSI 0x80 +#else +#define MMS_FOPEN_REQ_DFUN mms_req_not_supp +#define MMS_FOPEN_IND_SFUN u_ind_not_supp +#define FOPEN_SSI 0x00 +#endif + +#if (MMS_MV_FREAD_EN & REQ_EN) +#define MMS_MV_FREAD_CONF_SFUN u_mv_fread_conf +#else +#define MMS_MV_FREAD_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_FREAD_EN & REQ_EN) +#define MMS_FREAD_RSP_DFUN mms_file_read_rsp +#define MMS_FREAD_CONF_SFUN u_mp_fread_conf +#else +#define MMS_FREAD_RSP_DFUN mms_rsp_not_supp +#define MMS_FREAD_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_FREAD_EN & RESP_EN) +#define MMS_FREAD_REQ_DFUN mms_file_read_req +#define MMS_FREAD_IND_SFUN u_fread_ind +#define FREAD_SSI 0x40 +#else +#define MMS_FREAD_REQ_DFUN mms_req_not_supp +#define MMS_FREAD_IND_SFUN u_ind_not_supp +#define FREAD_SSI 0x00 +#endif + +#if (MMS_MV_FCLOSE_EN & REQ_EN) +#define MMS_MV_FCLOSE_CONF_SFUN u_mv_fclose_conf +#else +#define MMS_MV_FCLOSE_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_FCLOSE_EN & REQ_EN) +#define MMS_FCLOSE_RSP_DFUN _mms_null_pdu_dec +#define MMS_FCLOSE_CONF_SFUN u_mp_fclose_conf +#else +#define MMS_FCLOSE_RSP_DFUN mms_rsp_not_supp +#define MMS_FCLOSE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_FCLOSE_EN & RESP_EN) +#define MMS_FCLOSE_REQ_DFUN mms_file_close_req +#define MMS_FCLOSE_IND_SFUN u_fclose_ind +#define FCLOSE_SSI 0x20 +#else +#define MMS_FCLOSE_REQ_DFUN mms_req_not_supp +#define MMS_FCLOSE_IND_SFUN u_ind_not_supp +#define FCLOSE_SSI 0x00 +#endif + +#if (MMS_MV_FCOPY_EN & REQ_EN) +#define MMS_MV_FCOPY_CONF_SFUN u_mv_fcopy_conf +#else +#define MMS_MV_FCOPY_CONF_SFUN u_conf_not_supp +#endif + +#if (MMS_FRENAME_EN & REQ_EN) +#define MMS_FRENAME_RSP_DFUN _mms_null_pdu_dec +#define MMS_FRENAME_CONF_SFUN u_mp_frename_conf +#else +#define MMS_FRENAME_RSP_DFUN mms_rsp_not_supp +#define MMS_FRENAME_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_FRENAME_EN & RESP_EN) +#define MMS_FRENAME_REQ_DFUN mms_file_rename_req +#define MMS_FRENAME_IND_SFUN u_frename_ind +#define FRENAME_SSI 0x10 +#else +#define MMS_FRENAME_REQ_DFUN mms_req_not_supp +#define MMS_FRENAME_IND_SFUN u_ind_not_supp +#define FRENAME_SSI 0x00 +#endif + +#if (MMS_FDELETE_EN & REQ_EN) +#define MMS_FDELETE_RSP_DFUN _mms_null_pdu_dec +#define MMS_FDELETE_CONF_SFUN u_mp_fdelete_conf +#else +#define MMS_FDELETE_RSP_DFUN mms_rsp_not_supp +#define MMS_FDELETE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_FDELETE_EN & RESP_EN) +#define MMS_FDELETE_REQ_DFUN mms_file_delete_req +#define MMS_FDELETE_IND_SFUN u_fdelete_ind +#define FDELETE_SSI 0x08 +#else +#define MMS_FDELETE_REQ_DFUN mms_req_not_supp +#define MMS_FDELETE_IND_SFUN u_ind_not_supp +#define FDELETE_SSI 0x00 +#endif + +#if (MMS_FDIR_EN & REQ_EN) +#define MMS_FDIR_RSP_DFUN mms_file_dir_rsp +#define MMS_FDIR_CONF_SFUN u_mp_fdir_conf +#else +#define MMS_FDIR_RSP_DFUN mms_rsp_not_supp +#define MMS_FDIR_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_FDIR_EN & RESP_EN) +#define MMS_FDIR_REQ_DFUN mms_file_dir_req +#define MMS_FDIR_IND_SFUN u_fdir_ind +#define FDIR_SSI 0x04 +#else +#define MMS_FDIR_REQ_DFUN mms_req_not_supp +#define MMS_FDIR_IND_SFUN u_ind_not_supp +#define FDIR_SSI 0x00 +#endif + +/************************************************************************/ +/************************************************************************/ +/* UNCONFIRMED SERVICES FROM VARIABLE ACCESS, VMD SUPPORT AND EVENT */ +/* MANAGEMENT SERVICES */ +/************************************************************************/ +#if (MMS_INFO_EN & RESP_EN) +#define MMS_INFO_REQ_DFUN mms_info_rpt_req +#define MMS_INFO_IND_SFUN u_info_ind +#define INFO_SSI 0x01 +#else +#define MMS_INFO_REQ_DFUN mms_req_not_supp +#define MMS_INFO_IND_SFUN u_ind_not_supp +#define INFO_SSI 0x00 +#endif + +#if (MMS_USTATUS_EN & RESP_EN) +#define MMS_USTATUS_REQ_DFUN mms_ustatus_req +#define MMS_USTATUS_IND_SFUN u_ustatus_ind +#define USTATUS_SSI 0x02 +#else +#define MMS_USTATUS_REQ_DFUN mms_req_not_supp +#define MMS_USTATUS_IND_SFUN u_ind_not_supp +#define USTATUS_SSI 0x00 +#endif + +#if (MMS_EVNOT_EN & RESP_EN) +#define MMS_EVNOT_REQ_DFUN mms_evnot_req +#define MMS_EVNOT_IND_SFUN u_evnot_ind +#define EVNOT_SSI 0x80 +#else +#define MMS_EVNOT_REQ_DFUN mms_req_not_supp +#define MMS_EVNOT_IND_SFUN u_ind_not_supp +#define EVNOT_SSI 0x00 +#endif + +/************************************************************************/ +/************************************************************************/ +/* ENVIRONMENT & GENERAL MANAGEMENT */ +/************************************************************************/ +#if (MMS_CONCLUDE_EN & REQ_EN) +#define MMS_CONCLUDE_RSP_DFUN _mms_null_pdu_dec +#define MMS_CONCLUDE_CONF_SFUN u_mp_conclude_conf +#else +#define MMS_CONCLUDE_RSP_DFUN mms_rsp_not_supp +#define MMS_CONCLUDE_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_CONCLUDE_EN & RESP_EN) +#define MMS_CONCLUDE_REQ_DFUN _mms_null_pdu_dec +#define MMS_CONCLUDE_IND_SFUN u_conclude_ind +#define CONCLUDE_SSI 0x10 +#else +#define MMS_CONCLUDE_REQ_DFUN mms_req_not_supp +#define MMS_CONCLUDE_IND_SFUN u_ind_not_supp +#define CONCLUDE_SSI 0x00 +#endif + +#if (MMS_CANCEL_EN & REQ_EN) +#define MMS_CANCEL_RSP_DFUN mms_cancel_rsp +#define MMS_CANCEL_CONF_SFUN u_mp_cancel_conf +#else +#define MMS_CANCEL_RSP_DFUN mms_rsp_not_supp +#define MMS_CANCEL_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_CANCEL_EN & RESP_EN) +#define MMS_CANCEL_REQ_DFUN mms_cancel_req +#define MMS_CANCEL_IND_SFUN u_cancel_ind +#define CANCEL_SSI 0x08 +#else +#define MMS_CANCEL_REQ_DFUN mms_req_not_supp +#define MMS_CANCEL_IND_SFUN u_ind_not_supp +#define CANCEL_SSI 0x00 +#endif + +#if (MMS_INIT_EN & REQ_EN) +#define MMS_INIT_RSP_DFUN mms_init_rsp +#define MMS_INIT_CONF_SFUN u_conf_not_supp +#define MMS_MV_INIT_CONF_SFUN u_mv_init_conf +#else +#define MMS_INIT_RSP_DFUN mms_rsp_not_supp +#define MMS_INIT_CONF_SFUN u_conf_not_supp +#define MMS_MV_INIT_CONF_SFUN u_conf_not_supp +#endif +#if (MMS_INIT_EN & RESP_EN) +#define MMS_INIT_REQ_DFUN mms_init_req +#define MMS_INIT_IND_SFUN u_init_ind +#define INIT_SSI 0x10 +#else +#define MMS_INIT_REQ_DFUN mms_req_not_supp +#define MMS_INIT_IND_SFUN u_ind_not_supp +#define INIT_SSI 0x00 +#endif + + +/************************************************************************/ +/************************************************************************/ +/* initialize the REQUEST DECODE table, opcode is index into table */ +/************************************************************************/ +ST_VOID (* SD_CONST mms_req_decode_fun [MAX_MMSOP_DIS+1]) (ASN1_DEC_CTXT *) = + { + MMS_STATUS_REQ_DFUN, /* 00 STATUS */ + MMS_GETNAMES_REQ_DFUN, /* 01 GET_NAMLIST */ + MMS_IDENT_REQ_DFUN, /* 02 IDENTIFY */ + MMS_RENAME_REQ_DFUN, /* 03 RENAME */ + MMS_READ_REQ_DFUN, /* 04 READ */ + MMS_WRITE_REQ_DFUN, /* 05 WRITE */ + MMS_GETVAR_REQ_DFUN, /* 06 GET_VARDEF */ + MMS_DEFVAR_REQ_DFUN, /* 07 DEF_VARNAM */ + MMS_DEFSCAT_REQ_DFUN, /* 08 DEF_SCATTERED */ + MMS_GETSCAT_REQ_DFUN, /* 09 GET_SCATTERED */ + MMS_DELVAR_REQ_DFUN, /* 10 DEL_VARNAM */ + MMS_DEFVLIST_REQ_DFUN, /* 11 DEF_VARLIST */ + MMS_GETVLIST_REQ_DFUN, /* 12 GET_VARLIST */ + MMS_DELVLIST_REQ_DFUN, /* 13 DEL_VARLIST */ + MMS_DEFTYPE_REQ_DFUN, /* 14 DEF_TYPENAM */ + MMS_GETTYPE_REQ_DFUN, /* 15 GET_TYPEDEF */ + MMS_DELTYPE_REQ_DFUN, /* 16 DEL_TYPENAM */ + MMS_INPUT_REQ_DFUN, /* 17 INPUT */ + MMS_OUTPUT_REQ_DFUN, /* 18 OUTPUT */ + MMS_TAKECTRL_REQ_DFUN, /* 19 TAKE_CONTROL */ + MMS_RELCTRL_REQ_DFUN, /* 20 REL_CONTROL */ + MMS_DEFINE_SEM_REQ_DFUN, /* 21 DEF_SEMAPHORE */ + MMS_DELETE_SEM_REQ_DFUN, /* 22 DEL_SEMAPHORE */ + MMS_REP_SEMSTAT_REQ_DFUN, /* 23 REP_SEM_STATUS */ + MMS_REP_SEMPOOL_REQ_DFUN, /* 24 REP_SEM_POOL_STATUS */ + MMS_REP_SEMENTRY_REQ_DFUN, /* 25 REP_SEM_ENTRY_STATUS */ + MMS_INIT_DWN_REQ_DFUN, /* 26 INIT_DOWNLOAD */ + MMS_DWN_LOAD_REQ_DFUN, /* 27 DOWN_LOAD */ + MMS_TERM_DWN_REQ_DFUN, /* 28 TERM_DOWNLOAD */ + MMS_INIT_UPL_REQ_DFUN, /* 29 INIT_UPLOAD */ + MMS_UP_LOAD_REQ_DFUN, /* 30 UP_LOAD */ + MMS_TERM_UPL_REQ_DFUN, /* 31 TERM_UPLOAD */ + MMS_RDDWN_REQ_DFUN, /* 32 REQ_DOWNLOAD */ + MMS_RDUPL_REQ_DFUN, /* 33 REQ_UPLOAD */ + MMS_LOAD_DOM_REQ_DFUN, /* 34 LOAD_DOMAIN */ + MMS_STR_DOM_REQ_DFUN, /* 35 STORE_DOMAIN */ + MMS_DEL_DOM_REQ_DFUN, /* 36 DELETE_DOMAIN */ + MMS_GET_DOM_REQ_DFUN, /* 37 GET_DOMAIN */ + MMS_CRE_PI_REQ_DFUN, /* 38 CREATE_PROGRAM_INVOCATION*/ + MMS_DEL_PI_REQ_DFUN, /* 39 DEL_PROGRAM_INVOCATION */ + MMS_START_REQ_DFUN, /* 40 START */ + MMS_STOP_REQ_DFUN, /* 41 STOP */ + MMS_RESUME_REQ_DFUN, /* 42 RESUME */ + MMS_RESET_REQ_DFUN, /* 43 RESET */ + MMS_KILL_REQ_DFUN, /* 44 KILL */ + MMS_GET_PI_REQ_DFUN, /* 45 GET_PROGRAM_INVOCATION */ + MMS_OBTAINFILE_REQ_DFUN, /* 46 OBTAIN_FILE */ + MMS_DEFEC_REQ_DFUN, /* 47 DEFINE EVENT CONDITION */ + MMS_DELEC_REQ_DFUN, /* 48 DELETE EVENT CONDITION */ + MMS_GETECA_REQ_DFUN, /* 49 GET EVENT CONDITION ATTR */ + MMS_REPECS_REQ_DFUN, /* 50 REPORT EVENT COND STATUS */ + MMS_ALTECM_REQ_DFUN, /* 51 ALTER EV COND MONITORING */ + MMS_TRIGE_REQ_DFUN, /* 52 TRIGGER EVENT */ + MMS_DEFEA_REQ_DFUN, /* 53 DEFINE EVENT ACTION */ + MMS_DELEA_REQ_DFUN, /* 54 DELETE EVENT ACTION */ + MMS_GETEAA_REQ_DFUN, /* 55 GET EV ACTION ATTRIBUTES */ + MMS_REPEAS_REQ_DFUN, /* 56 REPORT EV ACTION STATUS */ + MMS_DEFEE_REQ_DFUN, /* 57 DEFINE EVENT ENROLLMENT */ + MMS_DELEE_REQ_DFUN, /* 58 DELETE EVENT ENROLLMENT */ + MMS_ALTEE_REQ_DFUN, /* 59 ALTER EVENT ENROLLMENT */ + MMS_REPEES_REQ_DFUN, /* 60 REPORT ENROLL ATTRIBUTES */ + MMS_GETEEA_REQ_DFUN, /* 61 GET ENROLLMENT STATUS */ + MMS_ACKEVNOT_REQ_DFUN, /* 62 ACK_EVENT_NOTIFICATION */ + MMS_GETAS_REQ_DFUN, /* 63 GET_ALARM_SUMMARY */ + MMS_GETAES_REQ_DFUN, /* 64 GET ALARM ENROLLMENT SUM */ + MMS_JREAD_REQ_DFUN, /* 65 READ_JOURNAL */ + MMS_JWRITE_REQ_DFUN, /* 66 WRITE_JOURNAL */ + MMS_JINIT_REQ_DFUN, /* 67 INITIALIZE_JOURNAL */ + MMS_JSTAT_REQ_DFUN, /* 68 REPORT_JOURNAL_STATUS */ + MMS_JCREATE_REQ_DFUN, /* 69 CREATE JOURNAL */ + MMS_JDELETE_REQ_DFUN, /* 70 DELETE JOURNAL */ + MMS_GETCL_REQ_DFUN, /* 71 GET CAPABILITY LIST */ + MMS_FOPEN_REQ_DFUN, /* 72 FILE_OPEN */ + MMS_FREAD_REQ_DFUN, /* 73 FILE_READ */ + MMS_FCLOSE_REQ_DFUN, /* 74 FILE_CLOSE */ + MMS_FRENAME_REQ_DFUN, /* 75 FILE_RENAME */ + MMS_FDELETE_REQ_DFUN, /* 76 FILE_DELETE */ + MMS_FDIR_REQ_DFUN, /* 77 FILE_DIR */ + MMS_USTATUS_REQ_DFUN, /* 78 UNSOLICITED_STATUS */ + MMS_INFO_REQ_DFUN, /* 79 INFO_RPT */ + MMS_EVNOT_REQ_DFUN, /* 80 EVENT NOTIFICATION */ + mms_req_not_supp, /* 81 ATTACH TO EVENT COND */ + mms_req_not_supp, /* 82 ATTACH TO SEMAPHORE */ + MMS_CONCLUDE_REQ_DFUN, /* 83 CONCLUDE */ + MMS_CANCEL_REQ_DFUN, /* 84 CANCEL */ + MMS_INIT_REQ_DFUN /* 85 INITIATE */ + }; + +/************************************************************************/ +/* initialize the RESPONSE DECODE table, opcode is index into table */ +/************************************************************************/ +ST_VOID (* SD_CONST mms_rsp_decode_fun [MAX_MMSOP_DIS+1]) (ASN1_DEC_CTXT *) = + { + MMS_STATUS_RSP_DFUN, /* 00 STATUS */ + MMS_GETNAMES_RSP_DFUN, /* 01 GET_NAMLIST */ + MMS_IDENT_RSP_DFUN, /* 02 IDENTIFY */ + MMS_RENAME_RSP_DFUN, /* 03 RENAME */ + MMS_READ_RSP_DFUN, /* 04 READ */ + MMS_WRITE_RSP_DFUN, /* 05 WRITE */ + MMS_GETVAR_RSP_DFUN, /* 06 GET_VARDEF */ + MMS_DEFVAR_RSP_DFUN, /* 07 DEF_VARNAM */ + MMS_DEFSCAT_RSP_DFUN, /* 08 DEF_SCATTERED */ + MMS_GETSCAT_RSP_DFUN, /* 09 GET_SCATTERED */ + MMS_DELVAR_RSP_DFUN, /* 10 DEL_VARNAM */ + MMS_DEFVLIST_RSP_DFUN, /* 11 DEF_VARLIST */ + MMS_GETVLIST_RSP_DFUN, /* 12 GET_VARLIST */ + MMS_DELVLIST_RSP_DFUN, /* 13 DEL_VARLIST */ + MMS_DEFTYPE_RSP_DFUN, /* 14 DEF_TYPENAM */ + MMS_GETTYPE_RSP_DFUN, /* 15 GET_TYPEDEF */ + MMS_DELTYPE_RSP_DFUN, /* 16 DEL_TYPENAM */ + MMS_INPUT_RSP_DFUN, /* 17 INPUT */ + MMS_OUTPUT_RSP_DFUN, /* 18 OUTPUT */ + MMS_TAKECTRL_RSP_DFUN, /* 19 TAKE_CONTROL */ + MMS_RELCTRL_RSP_DFUN, /* 20 REL_CONTROL */ + MMS_DEFINE_SEM_RSP_DFUN, /* 21 DEF_SEMAPHORE */ + MMS_DELETE_SEM_RSP_DFUN, /* 22 DEL_SEMAPHORE */ + MMS_REP_SEMSTAT_RSP_DFUN, /* 23 REP_SEM_STATUS */ + MMS_REP_SEMPOOL_RSP_DFUN, /* 24 REP_SEM_POOL_STATUS */ + MMS_REP_SEMENTRY_RSP_DFUN, /* 25 REP_SEM_ENTRY_STATUS */ + MMS_INIT_DWN_RSP_DFUN, /* 26 INIT_DOWNLOAD */ + MMS_DWN_LOAD_RSP_DFUN, /* 27 DOWN_LOAD */ + MMS_TERM_DWN_RSP_DFUN, /* 28 TERM_DOWNLOAD */ + MMS_INIT_UPL_RSP_DFUN, /* 29 INIT_UPLOAD */ + MMS_UP_LOAD_RSP_DFUN, /* 30 UP_LOAD */ + MMS_TERM_UPL_RSP_DFUN, /* 31 TERM_UPLOAD */ + MMS_RDDWN_RSP_DFUN, /* 32 REQ_DOWNLOAD */ + MMS_RDUPL_RSP_DFUN, /* 33 REQ_UPLOAD */ + MMS_LOAD_DOM_RSP_DFUN, /* 34 LOAD_DOMAIN */ + MMS_STR_DOM_RSP_DFUN, /* 35 STORE_DOMAIN */ + MMS_DEL_DOM_RSP_DFUN, /* 36 DELETE_DOMAIN */ + MMS_GET_DOM_RSP_DFUN, /* 37 GET_DOMAIN */ + MMS_CRE_PI_RSP_DFUN, /* 38 CREATE_PROGRAM_INVOCATION*/ + MMS_DEL_PI_RSP_DFUN, /* 39 DEL_PROGRAM_INVOCATION */ + MMS_START_RSP_DFUN, /* 40 START */ + MMS_STOP_RSP_DFUN, /* 41 STOP */ + MMS_RESUME_RSP_DFUN, /* 42 RESUME */ + MMS_RESET_RSP_DFUN, /* 43 RESET */ + MMS_KILL_RSP_DFUN, /* 44 KILL */ + MMS_GET_PI_RSP_DFUN, /* 45 GET_PROGRAM_INVOCATION */ + MMS_OBTAINFILE_RSP_DFUN, /* 46 OBTAIN_FILE */ + MMS_DEFEC_RSP_DFUN, /* 47 DEFINE EVENT CONDITION */ + MMS_DELEC_RSP_DFUN, /* 48 DELETE EVENT CONDITION */ + MMS_GETECA_RSP_DFUN, /* 49 GET EVENT CONDITION ATTR */ + MMS_REPECS_RSP_DFUN, /* 50 REPORT EVENT COND STATUS */ + MMS_ALTECM_RSP_DFUN, /* 51 ALTER EV COND MONITORING */ + MMS_TRIGE_RSP_DFUN, /* 52 TRIGGER EVENT */ + MMS_DEFEA_RSP_DFUN, /* 53 DEFINE EVENT ACTION */ + MMS_DELEA_RSP_DFUN, /* 54 DELETE EVENT ACTION */ + MMS_GETEAA_RSP_DFUN, /* 55 GET EV ACTION ATTRIBUTES */ + MMS_REPEAS_RSP_DFUN, /* 56 REPORT EV ACTION STATUS */ + MMS_DEFEE_RSP_DFUN, /* 57 DEFINE EVENT ENROLLMENT */ + MMS_DELEE_RSP_DFUN, /* 58 DELETE EVENT ENROLLMENT */ + MMS_ALTEE_RSP_DFUN, /* 59 ALTER EVENT ENROLLMENT */ + MMS_REPEES_RSP_DFUN, /* 60 REPORT ENROLL ATTRIBUTES */ + MMS_GETEEA_RSP_DFUN, /* 61 GET ENROLLMENT STATUS */ + MMS_ACKEVNOT_RSP_DFUN, /* 62 ACK_EVENT_NOTIFICATION */ + MMS_GETAS_RSP_DFUN, /* 63 GET_ALARM_SUMMARY */ + MMS_GETAES_RSP_DFUN, /* 64 GET ALARM ENROLLMENT SUM */ + MMS_JREAD_RSP_DFUN, /* 65 READ_JOURNAL */ + MMS_JWRITE_RSP_DFUN, /* 66 WRITE_JOURNAL */ + MMS_JINIT_RSP_DFUN, /* 67 INITIALIZE_JOURNAL */ + MMS_JSTAT_RSP_DFUN, /* 68 REPORT_JOURNAL_STATUS */ + MMS_JCREATE_RSP_DFUN, /* 69 CREATE JOURNAL */ + MMS_JDELETE_RSP_DFUN, /* 70 DELETE JOURNAL */ + MMS_GETCL_RSP_DFUN, /* 71 GET CAPABILITY LIST */ + MMS_FOPEN_RSP_DFUN, /* 72 FILE_OPEN */ + MMS_FREAD_RSP_DFUN, /* 73 FILE_READ */ + MMS_FCLOSE_RSP_DFUN, /* 74 FILE_CLOSE */ + MMS_FRENAME_RSP_DFUN, /* 75 FILE_RENAME */ + MMS_FDELETE_RSP_DFUN, /* 76 FILE_DELETE */ + MMS_FDIR_RSP_DFUN, /* 77 FILE_DIR */ + + + mms_rsp_not_supp, /* 78 UNSOLICITED_STATUS */ + mms_rsp_not_supp, /* 79 INFO_RPT */ + mms_rsp_not_supp, /* 80 EVENT NOTIFICATION */ + mms_rsp_not_supp, /* 81 ATTACH TO EVENT COND */ + mms_rsp_not_supp, /* 82 ATTACH TO SEMAPHORE */ + MMS_CONCLUDE_RSP_DFUN, /* 83 CONCLUDE */ + MMS_CANCEL_RSP_DFUN, /* 84 CANCEL */ + MMS_INIT_RSP_DFUN /* 85 INITIATE */ + }; + +#ifndef MMS_LITE +/************************************************************************/ +/* initialize the INDICATION SERVICE table, opcode is index into table */ +/************************************************************************/ + +ST_VOID (*mms_ind_serve_fun [MAX_IND_SFUN+1]) (MMSREQ_IND *) = + { + MMS_STATUS_IND_SFUN, /* 00 STATUS */ + MMS_GETNAMES_IND_SFUN, /* 01 GET_NAMLIST */ + MMS_IDENT_IND_SFUN, /* 02 IDENTIFY */ + MMS_RENAME_IND_SFUN, /* 03 RENAME */ + MMS_READ_IND_SFUN, /* 04 READ */ + MMS_WRITE_IND_SFUN, /* 05 WRITE */ + MMS_GETVAR_IND_SFUN, /* 06 GET_VARDEF */ + MMS_DEFVAR_IND_SFUN, /* 07 DEF_VARNAM */ + MMS_DEFSCAT_IND_SFUN, /* 08 DEF_SCATTERED */ + MMS_GETSCAT_IND_SFUN, /* 09 GET_SCATTERED */ + MMS_DELVAR_IND_SFUN, /* 10 DEL_VARNAM */ + MMS_DEFVLIST_IND_SFUN, /* 11 DEF_VARLIST */ + MMS_GETVLIST_IND_SFUN, /* 12 GET_VARLIST */ + MMS_DELVLIST_IND_SFUN, /* 13 DEL_VARLIST */ + MMS_DEFTYPE_IND_SFUN, /* 14 DEF_TYPENAM */ + MMS_GETTYPE_IND_SFUN, /* 15 GET_TYPEDEF */ + MMS_DELTYPE_IND_SFUN, /* 16 DEL_TYPENAM */ + MMS_INPUT_IND_SFUN, /* 17 INPUT */ + MMS_OUTPUT_IND_SFUN, /* 18 OUTPUT */ + MMS_TAKECTRL_IND_SFUN, /* 19 TAKE_CONTROL */ + MMS_RELCTRL_IND_SFUN, /* 20 REL_CONTROL */ + MMS_DEFINE_SEM_IND_SFUN, /* 21 DEF_SEMAPHORE */ + MMS_DELETE_SEM_IND_SFUN, /* 22 DEL_SEMAPHORE */ + MMS_REP_SEMSTAT_IND_SFUN, /* 23 REP_SEM_STATUS */ + MMS_REP_SEMPOOL_IND_SFUN, /* 24 REP_SEM_POOL_STATUS */ + MMS_REP_SEMENTRY_IND_SFUN, /* 25 REP_SEM_ENTRY_STATUS */ + MMS_INIT_DWN_IND_SFUN, /* 26 INIT_DOWNLOAD */ + MMS_DWN_LOAD_IND_SFUN, /* 27 DOWN_LOAD */ + MMS_TERM_DWN_IND_SFUN, /* 28 TERM_DOWNLOAD */ + MMS_INIT_UPL_IND_SFUN, /* 29 INIT_UPLOAD */ + MMS_UP_LOAD_IND_SFUN, /* 30 UP_LOAD */ + MMS_TERM_UPL_IND_SFUN, /* 31 TERM_UPLOAD */ + MMS_RDDWN_IND_SFUN, /* 32 REQ_DOWNLOAD */ + MMS_RDUPL_IND_SFUN, /* 33 REQ_UPLOAD */ + MMS_LOAD_DOM_IND_SFUN, /* 34 LOAD_DOMAIN */ + MMS_STR_DOM_IND_SFUN, /* 35 STORE_DOMAIN */ + MMS_DEL_DOM_IND_SFUN, /* 36 DELETE_DOMAIN */ + MMS_GET_DOM_IND_SFUN, /* 37 GET_DOMAIN */ + MMS_CRE_PI_IND_SFUN, /* 38 CREATE_PROGRAM_INVOCATION*/ + MMS_DEL_PI_IND_SFUN, /* 39 DEL_PROGRAM_INVOCATION */ + MMS_START_IND_SFUN, /* 40 START */ + MMS_STOP_IND_SFUN, /* 41 STOP */ + MMS_RESUME_IND_SFUN, /* 42 RESUME */ + MMS_RESET_IND_SFUN, /* 43 RESET */ + MMS_KILL_IND_SFUN, /* 44 KILL */ + MMS_GET_PI_IND_SFUN, /* 45 GET_PROGRAM_INVOCATION */ + MMS_OBTAINFILE_IND_SFUN, /* 46 OBTAIN_FILE */ + MMS_DEFEC_IND_SFUN, /* 47 DEFINE EVENT CONDITION */ + MMS_DELEC_IND_SFUN, /* 48 DELETE EVENT CONDITION */ + MMS_GETECA_IND_SFUN, /* 49 GET EVENT CONDITION ATTR */ + MMS_REPECS_IND_SFUN, /* 50 REPORT EVENT COND STATUS */ + MMS_ALTECM_IND_SFUN, /* 51 ALTER EV COND MONITORING */ + MMS_TRIGE_IND_SFUN, /* 52 TRIGGER EVENT */ + MMS_DEFEA_IND_SFUN, /* 53 DEFINE EVENT ACTION */ + MMS_DELEA_IND_SFUN, /* 54 DELETE EVENT ACTION */ + MMS_GETEAA_IND_SFUN, /* 55 GET EV ACTION ATTRIBUTES */ + MMS_REPEAS_IND_SFUN, /* 56 REPORT EV ACTION STATUS */ + MMS_DEFEE_IND_SFUN, /* 57 DEFINE EVENT ENROLLMENT */ + MMS_DELEE_IND_SFUN, /* 58 DELETE EVENT ENROLLMENT */ + MMS_ALTEE_IND_SFUN, /* 59 ALTER EVENT ENROLLMENT */ + MMS_REPEES_IND_SFUN, /* 60 REPORT ENROLL ATTRIBUTES */ + MMS_GETEEA_IND_SFUN, /* 61 GET ENROLLMENT STATUS */ + MMS_ACKEVNOT_IND_SFUN, /* 62 ACK_EVENT_NOTIFICATION */ + MMS_GETAS_IND_SFUN, /* 63 GET_ALARM_SUMMARY */ + MMS_GETAES_IND_SFUN, /* 64 GET ALARM ENROLLMENT SUM */ + MMS_JREAD_IND_SFUN, /* 65 READ_JOURNAL */ + MMS_JWRITE_IND_SFUN, /* 66 WRITE_JOURNAL */ + MMS_JINIT_IND_SFUN, /* 67 INITIALIZE_JOURNAL */ + MMS_JSTAT_IND_SFUN, /* 68 REPORT_JOURNAL_STATUS */ + MMS_JCREATE_IND_SFUN, /* 69 CREATE JOURNAL */ + MMS_JDELETE_IND_SFUN, /* 70 DELETE JOURNAL */ + MMS_GETCL_IND_SFUN, /* 71 GET CAPABILITY LIST */ + MMS_FOPEN_IND_SFUN, /* 72 FILE_OPEN */ + MMS_FREAD_IND_SFUN, /* 73 FILE_READ */ + MMS_FCLOSE_IND_SFUN, /* 74 FILE_CLOSE */ + MMS_FRENAME_IND_SFUN, /* 75 FILE_RENAME */ + MMS_FDELETE_IND_SFUN, /* 76 FILE_DELETE */ + MMS_FDIR_IND_SFUN, /* 77 FILE_DIR */ + MMS_USTATUS_IND_SFUN, /* 78 UNSOLICITED_STATUS */ + MMS_INFO_IND_SFUN, /* 79 INFO_RPT */ + MMS_EVNOT_IND_SFUN, /* 80 EVENT NOTIFICATION */ + u_ind_not_supp, /* 81 ATTACH TO EVENT COND */ + u_ind_not_supp, /* 82 ATTACH TO SEMAPHORE */ + MMS_CONCLUDE_IND_SFUN, /* 83 CONCLUDE */ + MMS_CANCEL_IND_SFUN, /* 84 CANCEL */ + MMS_INIT_IND_SFUN /* 85 INITIATE */ + }; + +/************************************************************************/ +/* initialize the CONFIRMATION SERVICE table, opcode is index into table*/ +/************************************************************************/ +ST_VOID (*mms_conf_serve_fun [MAX_CONF_SFUN+1]) (MMSREQ_PEND *) = + { + MMS_STATUS_CONF_SFUN, /* 00 STATUS */ + MMS_GETNAMES_CONF_SFUN, /* 01 GET_NAMLIST */ + MMS_IDENT_CONF_SFUN, /* 02 IDENTIFY */ + MMS_RENAME_CONF_SFUN, /* 03 RENAME */ + MMS_READ_CONF_SFUN, /* 04 READ */ + MMS_WRITE_CONF_SFUN, /* 05 WRITE */ + MMS_GETVAR_CONF_SFUN, /* 06 GET_VARDEF */ + MMS_DEFVAR_CONF_SFUN, /* 07 DEF_VARNAM */ + MMS_DEFSCAT_CONF_SFUN, /* 08 DEF_SCATTERED */ + MMS_GETSCAT_CONF_SFUN, /* 09 GET_SCATTERED */ + MMS_DELVAR_CONF_SFUN, /* 10 DEL_VARNAM */ + MMS_DEFVLIST_CONF_SFUN, /* 11 DEF_VARLIST */ + MMS_GETVLIST_CONF_SFUN, /* 12 GET_VARLIST */ + MMS_DELVLIST_CONF_SFUN, /* 13 DEL_VARLIST */ + MMS_DEFTYPE_CONF_SFUN, /* 14 DEF_TYPENAM */ + MMS_GETTYPE_CONF_SFUN, /* 15 GET_TYPEDEF */ + MMS_DELTYPE_CONF_SFUN, /* 16 DEL_TYPENAM */ + MMS_INPUT_CONF_SFUN, /* 17 INPUT */ + MMS_OUTPUT_CONF_SFUN, /* 18 OUTPUT */ + MMS_TAKECTRL_CONF_SFUN, /* 19 TAKE_CONTROL */ + MMS_RELCTRL_CONF_SFUN, /* 20 REL_CONTROL */ + MMS_DEFINE_SEM_CONF_SFUN, /* 21 DEF_SEMAPHORE */ + MMS_DELETE_SEM_CONF_SFUN, /* 22 DEL_SEMAPHORE */ + MMS_REP_SEMSTAT_CONF_SFUN, /* 23 REP_SEM_STATUS */ + MMS_REP_SEMPOOL_CONF_SFUN, /* 24 REP_SEM_POOL_STATUS */ + MMS_REP_SEMENTRY_CONF_SFUN, /* 25 REP_SEM_ENTRY_STATUS */ + MMS_INIT_DWN_CONF_SFUN, /* 26 INIT_DOWNLOAD */ + MMS_DWN_LOAD_CONF_SFUN, /* 27 DOWN_LOAD */ + MMS_TERM_DWN_CONF_SFUN, /* 28 TERM_DOWNLOAD */ + MMS_INIT_UPL_CONF_SFUN, /* 29 INIT_UPLOAD */ + MMS_UP_LOAD_CONF_SFUN, /* 30 UP_LOAD */ + MMS_TERM_UPL_CONF_SFUN, /* 31 TERM_UPLOAD */ + MMS_RDDWN_CONF_SFUN, /* 32 REQ_DOWNLOAD */ + MMS_RDUPL_CONF_SFUN, /* 33 REQ_UPLOAD */ + MMS_LOAD_DOM_CONF_SFUN, /* 34 LOAD_DOMAIN */ + MMS_STR_DOM_CONF_SFUN, /* 35 STORE_DOMAIN */ + MMS_DEL_DOM_CONF_SFUN, /* 36 DELETE_DOMAIN */ + MMS_GET_DOM_CONF_SFUN, /* 37 GET_DOMAIN */ + MMS_CRE_PI_CONF_SFUN, /* 38 CREATE_PROGRAM_INVOCATION*/ + MMS_DEL_PI_CONF_SFUN, /* 39 DEL_PROGRAM_INVOCATION */ + MMS_START_CONF_SFUN, /* 40 START */ + MMS_STOP_CONF_SFUN, /* 41 STOP */ + MMS_RESUME_CONF_SFUN, /* 42 RESUME */ + MMS_RESET_CONF_SFUN, /* 43 RESET */ + MMS_KILL_CONF_SFUN, /* 44 KILL */ + MMS_GET_PI_CONF_SFUN, /* 45 GET_PROGRAM_INVOCATION */ + MMS_OBTAINFILE_CONF_SFUN, /* 46 OBTAIN_FILE */ + MMS_DEFEC_CONF_SFUN, /* 47 DEFINE EVENT CONDITION */ + MMS_DELEC_CONF_SFUN, /* 48 DELETE EVENT CONDITION */ + MMS_GETECA_CONF_SFUN, /* 49 GET EVENT CONDITION ATTR */ + MMS_REPECS_CONF_SFUN, /* 50 REPORT EVENT COND STATUS */ + MMS_ALTECM_CONF_SFUN, /* 51 ALTER EV COND MONITORING */ + MMS_TRIGE_CONF_SFUN, /* 52 TRIGGER EVENT */ + MMS_DEFEA_CONF_SFUN, /* 53 DEFINE EVENT ACTION */ + MMS_DELEA_CONF_SFUN, /* 54 DELETE EVENT ACTION */ + MMS_GETEAA_CONF_SFUN, /* 55 GET EV ACTION ATTRIBUTES */ + MMS_REPEAS_CONF_SFUN, /* 56 REPORT EV ACTION STATUS */ + MMS_DEFEE_CONF_SFUN, /* 57 DEFINE EVENT ENROLLMENT */ + MMS_DELEE_CONF_SFUN, /* 58 DELETE EVENT ENROLLMENT */ + MMS_ALTEE_CONF_SFUN, /* 59 ALTER EVENT ENROLLMENT */ + MMS_REPEES_CONF_SFUN, /* 60 REPORT ENROLL ATTRIBUTES */ + MMS_GETEEA_CONF_SFUN, /* 61 GET ENROLLMENT STATUS */ + MMS_ACKEVNOT_CONF_SFUN, /* 62 ACK_EVENT_NOTIFICATION */ + MMS_GETAS_CONF_SFUN, /* 63 GET_ALARM_SUMMARY */ + MMS_GETAES_CONF_SFUN, /* 64 GET ALARM ENROLLMENT SUM */ + MMS_JREAD_CONF_SFUN, /* 65 READ_JOURNAL */ + MMS_JWRITE_CONF_SFUN, /* 66 WRITE_JOURNAL */ + MMS_JINIT_CONF_SFUN, /* 67 INITIALIZE_JOURNAL */ + MMS_JSTAT_CONF_SFUN, /* 68 REPORT_JOURNAL_STATUS */ + MMS_JCREATE_CONF_SFUN, /* 69 CREATE JOURNAL */ + MMS_JDELETE_CONF_SFUN, /* 70 DELETE JOURNAL */ + MMS_GETCL_CONF_SFUN, /* 71 GET CAPABILITY LIST */ + MMS_FOPEN_CONF_SFUN, /* 72 FILE_OPEN */ + MMS_FREAD_CONF_SFUN, /* 73 FILE_READ */ + MMS_FCLOSE_CONF_SFUN, /* 74 FILE_CLOSE */ + MMS_FRENAME_CONF_SFUN, /* 75 FILE_RENAME */ + MMS_FDELETE_CONF_SFUN, /* 76 FILE_DELETE */ + MMS_FDIR_CONF_SFUN, /* 77 FILE_DIR */ + u_conf_not_supp, /* 78 UNSOLICITED_STATUS */ + u_conf_not_supp, /* 79 INFO_RPT */ + u_conf_not_supp, /* 80 EVENT NOTIFICATION */ + u_conf_not_supp, /* 81 ATTACH TO EVENT COND */ + u_conf_not_supp, /* 82 ATTACH TO SEMAPHORE */ + MMS_CONCLUDE_CONF_SFUN, /* 83 CONCLUDE */ + u_conf_not_supp, /* 84 CANCEL; handled elsewhere*/ + MMS_INIT_CONF_SFUN, /* 85 INITIATE */ + u_conf_not_supp, /* 86 NOT A MMS OPERATION */ + u_conf_not_supp, /* 87 NOT A MMS OPERATION */ + u_conf_not_supp, /* 88 NOT A MMS OPERATION */ + u_conf_not_supp, /* 89 NOT A MMS OPERATION */ + MMS_MV_READ_CONF_SFUN, /* 90 NAMED READ */ + MMS_MV_WRITE_CONF_SFUN, /* 91 NAMED WRITE */ + u_conf_not_supp, /* 92 NOT A MMS OPERATION */ + MMS_MV_FOPEN_CONF_SFUN, /* 93 REMOTE FILE OPEN */ + MMS_MV_FREAD_CONF_SFUN, /* 94 REMOTE FILE READ */ + MMS_MV_FCLOSE_CONF_SFUN, /* 95 REMOTE FILE CLOSE */ + MMS_MV_INIT_CONF_SFUN, /* 96 INITIATE */ + MMS_MV_DEFTYPE_CONF_SFUN, /* 97 TYPE DEFINITION */ + MMS_MV_FCOPY_CONF_SFUN, /* 98 REMOTE FILE COPY */ + MMS_MV_DOWNLOAD_CONF_SFUN, /* 99 VM DOMAIN DOWNLOAD */ + MMS_MV_UPLOAD_CONF_SFUN, /* 100 VM DOMAIN UPLOAD */ + MMS_MV_RDVARS_CONF_SFUN, /* 101 GENERAL READ */ + MMS_MV_WRVARS_CONF_SFUN, /* 102 GENERAL WRITE */ + u_conf_not_supp, /* 103 NOT A MMS OPERATION */ + u_conf_not_supp, /* 104 NOT A MMS OPERATION */ + u_conf_not_supp /* 105 NOT A MMS OPERATION */ + }; +#endif + +/************************************************************************/ +/************************************************************************/ +/* MODIFIERS */ +/************************************************************************/ +#define MODAEC_SSI 0x00 +#define MODAS_SSI 0x00 + + +/************************************************************************/ + +SD_CONST ST_UCHAR m_param[2] = { MPARAM0, MPARAM1 }; /* parameter support */ + + +/************************************************************************/ +/************************************************************************/ +/* initialize the supported services variable for the INITIATE service. */ +/************************************************************************/ +#define NOTUSED_SSI 0x00 + + +/* 0x80 | 0x40 | 0x20 | 0x10 | + 0x08 | 0x04 | 0x02 | 0x01 */ +#define SERV0 STATUS_SSI | GETNAMES_SSI | IDENT_SSI | RENAME_SSI | \ + READ_SSI | WRITE_SSI | GETVAR_SSI | DEFVAR_SSI + +#define SERV1 DEFSCAT_SSI | GETSCAT_SSI | DELVAR_SSI | DEFVLIST_SSI | \ + GETVLIST_SSI | DELVLIST_SSI | DEFTYPE_SSI | GETTYPE_SSI + +#define SERV2 DELTYPE_SSI | INPUT_SSI | OUTPUT_SSI | TAKECTRL_SSI | \ + RELCTRL_SSI | DEFSEM_SSI | DELSEM_SSI | RSSTAT_SSI + +#define SERV3 RSPOOL_SSI | RSENTRY_SSI | INITDWN_SSI | DOWNLOAD_SSI | \ + TERMDOWN_SSI | INITUPL_SSI | UPLOAD_SSI | TERMUPL_SSI + +#define SERV4 RDDWN_SSI | RDUPL_SSI | LOADDOM_SSI | STRDOM_SSI | \ + DELDOM_SSI | GETDOM_SSI | CREPI_SSI | DELPI_SSI + +#define SERV5 START_SSI | STOP_SSI | RESUME_SSI | RESET_SSI | \ + KILL_SSI | GETPI_SSI | OBTFILE_SSI | DEFEC_SSI + +#define SERV6 DELEC_SSI | GETECA_SSI | REPECS_SSI | ALTECM_SSI | \ + TRIGE_SSI | DEFEA_SSI | DELEA_SSI | GETEAA_SSI + +#define SERV7 REPEAS_SSI | DEFEE_SSI | DELEE_SSI | ALTEE_SSI | \ + REPEES_SSI | GETEEA_SSI | ACKEVNOT_SSI | GETAS_SSI + +#define SERV8 GETAES_SSI | JREAD_SSI | JWRITE_SSI | JINIT_SSI | \ + JSTAT_SSI | JCREATE_SSI | JDELETE_SSI | GETCL_SSI + +#define SERV9 FOPEN_SSI | FREAD_SSI | FCLOSE_SSI | FRENAME_SSI | \ + FDELETE_SSI | FDIR_SSI | USTATUS_SSI | INFO_SSI + +#define SERV10 EVNOT_SSI | MODAEC_SSI | MODAS_SSI | CONCLUDE_SSI | \ + CANCEL_SSI | NOTUSED_SSI | NOTUSED_SSI | NOTUSED_SSI + + /* services supported as responder */ +SD_CONST ST_UCHAR m_service_resp[SERVICE_RESP_SIZE] = + {SERV0,SERV1,SERV2,SERV3,SERV4,SERV5,SERV6, + SERV7,SERV8,SERV9,SERV10}; + + +/************************************************************************/ +/************************************************************************/ +/* These variables are used help control decode operation specific data */ +/* structure allocation. For MMS-LITE (M_USR_DEC_BUF), these variables */ +/* are used to tell the decode system how many objects the allocated */ +/* buffer (_mms_dec_info). For MMS-EASE, these are normally not used; */ +/* if they are set non-zero, they will be used in calculating the size */ +/* of the dec info buffer to be allocated. */ + +#if (MMS_READ_EN & REQ_EN) +ST_INT m_cl_read_spec_in_result = SD_TRUE; +ST_INT m_cl_max_read_var_spec; +ST_INT m_cl_max_read_acc_rslt; +#endif + +#if (MMS_INFO_EN & RESP_EN) +ST_INT m_cl_max_info_var_spec; +ST_INT m_cl_max_info_acc_rslt; +#endif + +#if (MMS_GETVLIST_EN & REQ_EN) +ST_INT m_cl_max_getvla_vars; +#endif + +#if (MMS_WRITE_EN & REQ_EN) +ST_INT m_cl_max_write_rslts; +#endif + +#if (MMS_GETNAMES_EN & REQ_EN) +ST_INT m_cl_max_namel_names; +#endif + +#if (MMS_GETCL_EN & REQ_EN) +ST_INT m_cl_max_getcl_cap; +#endif + +#if (MMS_GET_PI_EN & REQ_EN) +ST_INT m_cl_max_getpi_doms; +#endif + +#if (MMS_GET_DOM_EN & REQ_EN) +ST_INT m_cl_max_getdom_cap; +ST_INT m_cl_max_getdom_pi; +#endif + +#if (MMS_INIT_UPL_EN & REQ_EN) +ST_INT m_cl_max_initupl_cap; +#endif + +#if (MMS_GETAS_EN & REQ_EN) +ST_INT m_cl_max_alarm_summary; +#endif + +#if (MMS_JREAD_EN & REQ_EN) +ST_INT m_cl_max_journal_entries; +ST_INT m_cl_max_entry_content; +#endif + +#if (MMS_REP_SEMSTAT_EN & REQ_EN) +ST_INT m_cl_max_semaphore_entries; +#endif + +#if (MMS_REP_SEMPOOL_EN & REQ_EN) +ST_INT m_cl_max_named_tokens; +#endif + +#if (MMS_FDIR_EN & REQ_EN) +ST_INT m_cl_max_file_directory; +#endif + +#if (MMS_GETEEA_EN & REQ_EN) +ST_INT m_cl_max_event_enrollment; +#endif + +#if (MMS_GETAES_EN & REQ_EN) +ST_INT m_cl_max_enrollment_summary; +#endif + +#if (MMS_LOAD_DOM_EN & RESP_EN) +ST_INT m_sv_max_loadd_cap; +#endif + +#if (MMS_READ_EN & RESP_EN) +ST_INT m_sv_max_read_var_spec; +#endif + +#if (MMS_WRITE_EN & RESP_EN) +ST_INT m_sv_max_write_var_spec; +ST_INT m_sv_max_write_data; +#endif + +#if (MMS_RDDWN_EN & RESP_EN) +ST_INT m_sv_max_rqdlnl_cap; +#endif + +#if (MMS_INIT_DWN_EN & RESP_EN) +ST_INT m_sv_max_initdnld_cap; +#endif + +#if (MMS_CRE_PI_EN & RESP_EN) +ST_INT m_sv_max_vstr; +#endif + +ST_INT m_sv_max_file_names; +ST_INT m_sv_max_obj_name; + +#if (MMS_INPUT_EN & RESP_EN) +ST_INT m_sv_max_prompt_count; +#endif + +#if (MMS_DEFVLIST_EN & RESP_EN) +ST_INT m_sv_max_num_vars; +#endif + +#if (MMS_OUTPUT_EN & RESP_EN) +ST_INT m_sv_max_data_count; +#endif + +#if (MMS_JWRITE_EN & RESP_EN) +ST_INT m_sv_max_entry_content; +#endif + +#if (MMS_JWRITE_EN & RESP_EN) +ST_INT m_sv_max_data_vars; +#endif + +#if (MMS_JREAD_EN & RESP_EN) +ST_INT m_sv_max_jread_vars; +#endif + +/************************************************************************/ +#ifndef MMS_LITE +/************************************************************************/ +/* LLP indication function pointers */ + +ST_VOID (*u_abort_ind_fun)(ST_INT chan, ST_INT reason, ST_BOOLEAN au_flag) = + u_abort_ind; + +ST_VOID (*u_llp_error_ind_fun)(ST_INT chan, ST_LONG code) = + u_llp_error_ind; + +ST_VOID (*u_release_ind_fun)(ST_INT chan) = + u_release_ind; + +ST_VOID (*u_mmsexcept_ind_fun)(ST_INT code, ST_INT chan) = + u_mmsexcept_ind; + +ST_VOID (*u_cancel_ind_fun)(MMSREQ_IND *req_info) = + MMS_CANCEL_IND_SFUN; + +ST_VOID (*u_reject_ind_fun)(ST_INT chan, struct reject_resp_info *rej_ptr) = + u_reject_ind; + +/************************************************************************/ +/* LLP confirmation function pointers */ + +ST_VOID (*u_mp_conclude_done_fun)(ST_INT chan, ST_RET ret_code) = + u_mp_conclude_done; + +ST_VOID (*u_mp_cancel_conf_fun)(MMSREQ_PEND *req_ptr, ST_BOOLEAN errdata_pres, + struct err_info *err_ptr) = + u_mp_cancel_conf; + +ST_VOID (*u_mp_abort_done_fun)(ST_INT chan) = + u_mp_abort_done; + +ST_VOID (*u_init_resp_done_fun)(ST_INT chan) = + u_init_resp_done; + +/************************************************************************/ +/* LLP association function pointers */ + +#ifdef MAP30_ACSE +ST_RET (*u_mllp_a_assoc_ind_fun)(ST_INT chan, ACSE_ASSINFO *assinfo) = + u_mllp_a_assoc_ind; + +ST_RET (*u_mllp_a_assoc_conf_fun)(ST_INT chan, ACSE_ASSINFO *assinfo) = + u_mllp_a_assoc_conf; +#endif + +#ifdef MAP30_LLC +ST_VOID (*u_mllp_l_error_ind_fun)(ST_INT chan, TRANS_ID *tid, ST_INT status) = + u_mllp_l_error_ind; +ST_RET (*u_mllp_l_assoc_ind_fun)(ST_INT chan, LLC_RXINFO *rx_info) = + u_mllp_l_assoc_ind; +#endif + +/************************************************************************/ +#endif /* #ifndef MMS_LITE */ +/************************************************************************/ +/************************************************************************/ +/************************************************************************/ +/* MLOG LOGGING FUNCTION POINTER INITIALIZATION */ +/************************************************************************/ + +#ifdef MLOG_ENABLE + +/************************************************************************/ +/* VMD SUPPORT - CONFIRMED SERVICES */ +/************************************************************************/ + +#if (MMS_STATUS_EN & (REQ_EN | RESP_EN)) +#define MMS_STATUS_RSP_LFUN m_log_status_resp +#define MMS_STATUS_REQ_LFUN m_log_status_req +#else +#define MMS_STATUS_RSP_LFUN m_no_log_resp +#define MMS_STATUS_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETNAMES_EN & (REQ_EN | RESP_EN)) +#define MMS_GETNAMES_RSP_LFUN m_log_namelist_resp +#define MMS_GETNAMES_REQ_LFUN m_log_namelist_req +#else +#define MMS_GETNAMES_RSP_LFUN m_no_log_resp +#define MMS_GETNAMES_REQ_LFUN m_no_log_req +#endif + +#if (MMS_IDENT_EN & (REQ_EN | RESP_EN)) +#define MMS_IDENT_RSP_LFUN m_log_ident_resp +#define MMS_IDENT_REQ_LFUN m_no_log_req +#else +#define MMS_IDENT_RSP_LFUN m_no_log_resp +#define MMS_IDENT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_RENAME_EN & (REQ_EN | RESP_EN)) +#define MMS_RENAME_RSP_LFUN m_no_log_resp +#define MMS_RENAME_REQ_LFUN m_log_rename_req +#else +#define MMS_RENAME_RSP_LFUN m_no_log_resp +#define MMS_RENAME_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETCL_EN & (REQ_EN | RESP_EN)) +#define MMS_GETCL_RSP_LFUN m_log_getcl_resp +#define MMS_GETCL_REQ_LFUN m_log_getcl_req +#else +#define MMS_GETCL_RSP_LFUN m_no_log_resp +#define MMS_GETCL_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* VARIABLE ACCESS - CONFIRMED SERVICES */ +/************************************************************************/ + +#if (MMS_READ_EN & (REQ_EN | RESP_EN)) +#define MMS_READ_RSP_LFUN m_log_read_resp +#define MMS_READ_REQ_LFUN m_log_read_req +#else +#define MMS_READ_RSP_LFUN m_no_log_resp +#define MMS_READ_REQ_LFUN m_no_log_req +#endif + +#if (MMS_WRITE_EN & (REQ_EN | RESP_EN)) +#define MMS_WRITE_RSP_LFUN m_log_write_resp +#define MMS_WRITE_REQ_LFUN m_log_write_req +#else +#define MMS_WRITE_RSP_LFUN m_no_log_resp +#define MMS_WRITE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETVAR_EN & (REQ_EN | RESP_EN)) +#define MMS_GETVAR_RSP_LFUN m_log_getvar_resp +#define MMS_GETVAR_REQ_LFUN m_log_getvar_req +#else +#define MMS_GETVAR_RSP_LFUN m_no_log_resp +#define MMS_GETVAR_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEFVAR_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFVAR_RSP_LFUN m_no_log_resp +#define MMS_DEFVAR_REQ_LFUN m_log_defvar_req +#else +#define MMS_DEFVAR_RSP_LFUN m_no_log_resp +#define MMS_DEFVAR_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEFSCAT_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFSCAT_RSP_LFUN m_no_log_resp +#define MMS_DEFSCAT_REQ_LFUN m_log_defscat_req +#else +#define MMS_DEFSCAT_RSP_LFUN m_no_log_resp +#define MMS_DEFSCAT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETSCAT_EN & (REQ_EN | RESP_EN)) +#define MMS_GETSCAT_RSP_LFUN m_log_getscat_resp +#define MMS_GETSCAT_REQ_LFUN m_log_getscat_req +#else +#define MMS_GETSCAT_RSP_LFUN m_no_log_resp +#define MMS_GETSCAT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DELVAR_EN & (REQ_EN | RESP_EN)) +#define MMS_DELVAR_RSP_LFUN m_log_delvar_resp +#define MMS_DELVAR_REQ_LFUN m_log_delvar_req +#else +#define MMS_DELVAR_RSP_LFUN m_no_log_resp +#define MMS_DELVAR_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEFVLIST_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFVLIST_RSP_LFUN m_no_log_resp +#define MMS_DEFVLIST_REQ_LFUN m_log_defvlist_req +#else +#define MMS_DEFVLIST_RSP_LFUN m_no_log_resp +#define MMS_DEFVLIST_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETVLIST_EN & (REQ_EN | RESP_EN)) +#define MMS_GETVLIST_RSP_LFUN m_log_getvlist_resp +#define MMS_GETVLIST_REQ_LFUN m_log_getvlist_req +#else +#define MMS_GETVLIST_RSP_LFUN m_no_log_resp +#define MMS_GETVLIST_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DELVLIST_EN & (REQ_EN | RESP_EN)) +#define MMS_DELVLIST_RSP_LFUN m_log_delvlist_resp +#define MMS_DELVLIST_REQ_LFUN m_log_delvlist_req +#else +#define MMS_DELVLIST_RSP_LFUN m_no_log_resp +#define MMS_DELVLIST_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_DEFTYPE_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFTYPE_RSP_LFUN m_no_log_resp +#define MMS_DEFTYPE_REQ_LFUN m_log_deftype_req +#else +#define MMS_DEFTYPE_RSP_LFUN m_no_log_resp +#define MMS_DEFTYPE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETTYPE_EN & (REQ_EN | RESP_EN)) +#define MMS_GETTYPE_RSP_LFUN m_log_gettype_resp +#define MMS_GETTYPE_REQ_LFUN m_log_gettype_req +#else +#define MMS_GETTYPE_RSP_LFUN m_no_log_resp +#define MMS_GETTYPE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DELTYPE_EN & (REQ_EN | RESP_EN)) +#define MMS_DELTYPE_RSP_LFUN m_log_deltype_resp +#define MMS_DELTYPE_REQ_LFUN m_log_deltype_req +#else +#define MMS_DELTYPE_RSP_LFUN m_no_log_resp +#define MMS_DELTYPE_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* OPERATOR COMMUNICATION SERVICES */ +/************************************************************************/ + +#if (MMS_INPUT_EN & (REQ_EN | RESP_EN)) +#define MMS_INPUT_RSP_LFUN m_log_input_resp +#define MMS_INPUT_REQ_LFUN m_log_input_req +#else +#define MMS_INPUT_RSP_LFUN m_no_log_resp +#define MMS_INPUT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_OUTPUT_EN & (REQ_EN | RESP_EN)) +#define MMS_OUTPUT_RSP_LFUN m_no_log_resp +#define MMS_OUTPUT_REQ_LFUN m_log_output_req +#else +#define MMS_OUTPUT_RSP_LFUN m_no_log_resp +#define MMS_OUTPUT_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* SEMAPHORE MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_TAKECTRL_EN & (REQ_EN | RESP_EN)) +#define MMS_TAKECTRL_RSP_LFUN m_log_takectrl_resp +#define MMS_TAKECTRL_REQ_LFUN m_log_takectrl_req +#else +#define MMS_TAKECTRL_RSP_LFUN m_no_log_resp +#define MMS_TAKECTRL_REQ_LFUN m_no_log_req +#endif + +#if (MMS_RELCTRL_EN & (REQ_EN | RESP_EN)) +#define MMS_RELCTRL_RSP_LFUN m_no_log_resp +#define MMS_RELCTRL_REQ_LFUN m_log_relctrl_req +#else +#define MMS_RELCTRL_RSP_LFUN m_no_log_resp +#define MMS_RELCTRL_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEFINE_SEM_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFINE_SEM_RSP_LFUN m_no_log_resp +#define MMS_DEFINE_SEM_REQ_LFUN m_log_defsem_req +#else +#define MMS_DEFINE_SEM_RSP_LFUN m_no_log_resp +#define MMS_DEFINE_SEM_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_DELETE_SEM_EN & (REQ_EN | RESP_EN)) +#define MMS_DELETE_SEM_RSP_LFUN m_no_log_resp +#define MMS_DELETE_SEM_REQ_LFUN m_log_delsem_req +#else +#define MMS_DELETE_SEM_RSP_LFUN m_no_log_resp +#define MMS_DELETE_SEM_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_REP_SEMSTAT_EN & (REQ_EN | RESP_EN)) +#define MMS_REP_SEMSTAT_RSP_LFUN m_log_rsstat_resp +#define MMS_REP_SEMSTAT_REQ_LFUN m_log_rsstat_req +#else +#define MMS_REP_SEMSTAT_RSP_LFUN m_no_log_resp +#define MMS_REP_SEMSTAT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_REP_SEMPOOL_EN & (REQ_EN | RESP_EN)) +#define MMS_REP_SEMPOOL_RSP_LFUN m_log_rspool_resp +#define MMS_REP_SEMPOOL_REQ_LFUN m_log_rspool_req +#else +#define MMS_REP_SEMPOOL_RSP_LFUN m_no_log_resp +#define MMS_REP_SEMPOOL_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_REP_SEMENTRY_EN & (REQ_EN | RESP_EN)) +#define MMS_REP_SEMENTRY_RSP_LFUN m_log_rsentry_resp +#define MMS_REP_SEMENTRY_REQ_LFUN m_log_rsentry_req +#else +#define MMS_REP_SEMENTRY_RSP_LFUN m_no_log_resp +#define MMS_REP_SEMENTRY_REQ_LFUN m_no_log_req +#endif + + +/************************************************************************/ +/* DOMAIN MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_INIT_DWN_EN & (REQ_EN | RESP_EN)) +#define MMS_INIT_DWN_RSP_LFUN m_no_log_resp +#define MMS_INIT_DWN_REQ_LFUN m_log_initdown_req +#else +#define MMS_INIT_DWN_RSP_LFUN m_no_log_resp +#define MMS_INIT_DWN_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_DWN_LOAD_EN & (REQ_EN | RESP_EN)) +#define MMS_DWN_LOAD_RSP_LFUN m_log_download_resp +#define MMS_DWN_LOAD_REQ_LFUN m_log_download_req +#else +#define MMS_DWN_LOAD_RSP_LFUN m_no_log_resp +#define MMS_DWN_LOAD_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_TERM_DWN_EN & (REQ_EN | RESP_EN)) +#define MMS_TERM_DWN_RSP_LFUN m_no_log_resp +#define MMS_TERM_DWN_REQ_LFUN m_log_termdown_req +#else +#define MMS_TERM_DWN_RSP_LFUN m_no_log_resp +#define MMS_TERM_DWN_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_INIT_UPL_EN & (REQ_EN | RESP_EN)) +#define MMS_INIT_UPL_RSP_LFUN m_log_initupl_resp +#define MMS_INIT_UPL_REQ_LFUN m_log_initupl_req +#else +#define MMS_INIT_UPL_RSP_LFUN m_no_log_resp +#define MMS_INIT_UPL_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_UP_LOAD_EN & (REQ_EN | RESP_EN)) +#define MMS_UP_LOAD_RSP_LFUN m_log_upload_resp +#define MMS_UP_LOAD_REQ_LFUN m_log_upload_req +#else +#define MMS_UP_LOAD_RSP_LFUN m_no_log_resp +#define MMS_UP_LOAD_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_TERM_UPL_EN & (REQ_EN | RESP_EN)) +#define MMS_TERM_UPL_RSP_LFUN m_no_log_resp +#define MMS_TERM_UPL_REQ_LFUN m_log_termupl_req +#else +#define MMS_TERM_UPL_RSP_LFUN m_no_log_resp +#define MMS_TERM_UPL_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_RDDWN_EN & (REQ_EN | RESP_EN)) +#define MMS_RDDWN_RSP_LFUN m_no_log_resp +#define MMS_RDDWN_REQ_LFUN m_log_rddwn_req +#else +#define MMS_RDDWN_RSP_LFUN m_no_log_resp +#define MMS_RDDWN_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_RDUPL_EN & (REQ_EN | RESP_EN)) +#define MMS_RDUPL_RSP_LFUN m_no_log_resp +#define MMS_RDUPL_REQ_LFUN m_log_rdupl_req +#else +#define MMS_RDUPL_RSP_LFUN m_no_log_resp +#define MMS_RDUPL_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_LOAD_DOM_EN & (REQ_EN | RESP_EN)) +#define MMS_LOAD_DOM_RSP_LFUN m_no_log_resp +#define MMS_LOAD_DOM_REQ_LFUN m_log_loaddom_req +#else +#define MMS_LOAD_DOM_RSP_LFUN m_no_log_resp +#define MMS_LOAD_DOM_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_STR_DOM_EN & (REQ_EN | RESP_EN)) +#define MMS_STR_DOM_RSP_LFUN m_no_log_resp +#define MMS_STR_DOM_REQ_LFUN m_log_storedom_req +#else +#define MMS_STR_DOM_RSP_LFUN m_no_log_resp +#define MMS_STR_DOM_REQ_LFUN m_no_log_req +#endif + + +#if (MMS_DEL_DOM_EN & (REQ_EN | RESP_EN)) +#define MMS_DEL_DOM_RSP_LFUN m_no_log_resp +#define MMS_DEL_DOM_REQ_LFUN m_log_deldom_req +#else +#define MMS_DEL_DOM_RSP_LFUN m_no_log_resp +#define MMS_DEL_DOM_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GET_DOM_EN & (REQ_EN | RESP_EN)) +#define MMS_GET_DOM_RSP_LFUN m_log_getdom_resp +#define MMS_GET_DOM_REQ_LFUN m_log_getdom_req +#else +#define MMS_GET_DOM_RSP_LFUN m_no_log_resp +#define MMS_GET_DOM_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* PROGRAM INVOCATION MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_CRE_PI_EN & (REQ_EN | RESP_EN)) +#define MMS_CRE_PI_RSP_LFUN m_no_log_resp +#define MMS_CRE_PI_REQ_LFUN m_log_crepi_req +#else +#define MMS_CRE_PI_RSP_LFUN m_no_log_resp +#define MMS_CRE_PI_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEL_PI_EN & (REQ_EN | RESP_EN)) +#define MMS_DEL_PI_RSP_LFUN m_no_log_resp +#define MMS_DEL_PI_REQ_LFUN m_log_delpi_req +#else +#define MMS_DEL_PI_RSP_LFUN m_no_log_resp +#define MMS_DEL_PI_REQ_LFUN m_no_log_req +#endif + +#if (MMS_START_EN & (REQ_EN | RESP_EN)) +#define MMS_START_RSP_LFUN m_no_log_resp +#define MMS_START_REQ_LFUN m_log_start_req +#else +#define MMS_START_RSP_LFUN m_no_log_resp +#define MMS_START_REQ_LFUN m_no_log_req +#endif + +#if (MMS_STOP_EN & (REQ_EN | RESP_EN)) +#define MMS_STOP_RSP_LFUN m_no_log_resp +#define MMS_STOP_REQ_LFUN m_log_stop_req +#else +#define MMS_STOP_RSP_LFUN m_no_log_resp +#define MMS_STOP_REQ_LFUN m_no_log_req +#endif + +#if (MMS_RESUME_EN & (REQ_EN | RESP_EN)) +#define MMS_RESUME_RSP_LFUN m_no_log_resp +#define MMS_RESUME_REQ_LFUN m_log_resume_req +#else +#define MMS_RESUME_RSP_LFUN m_no_log_resp +#define MMS_RESUME_REQ_LFUN m_no_log_req +#endif + +#if (MMS_RESET_EN & (REQ_EN | RESP_EN)) +#define MMS_RESET_RSP_LFUN m_no_log_resp +#define MMS_RESET_REQ_LFUN m_log_reset_req +#else +#define MMS_RESET_RSP_LFUN m_no_log_resp +#define MMS_RESET_REQ_LFUN m_no_log_req +#endif + +#if (MMS_KILL_EN & (REQ_EN | RESP_EN)) +#define MMS_KILL_RSP_LFUN m_no_log_resp +#define MMS_KILL_REQ_LFUN m_log_kill_req +#else +#define MMS_KILL_RSP_LFUN m_no_log_resp +#define MMS_KILL_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GET_PI_EN & (REQ_EN | RESP_EN)) +#define MMS_GET_PI_RSP_LFUN m_log_getpi_resp +#define MMS_GET_PI_REQ_LFUN m_log_getpi_req +#else +#define MMS_GET_PI_RSP_LFUN m_no_log_resp +#define MMS_GET_PI_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* EVENT MANAGEMENT - CONFIRMED SERVICES */ +/************************************************************************/ + +#if (MMS_DEFEC_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFEC_RSP_LFUN m_no_log_resp +#define MMS_DEFEC_REQ_LFUN m_log_defec_req +#else +#define MMS_DEFEC_RSP_LFUN m_no_log_resp +#define MMS_DEFEC_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DELEC_EN & (REQ_EN | RESP_EN)) +#define MMS_DELEC_RSP_LFUN m_log_delec_resp +#define MMS_DELEC_REQ_LFUN m_log_delec_req +#else +#define MMS_DELEC_RSP_LFUN m_no_log_resp +#define MMS_DELEC_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETECA_EN & (REQ_EN | RESP_EN)) +#define MMS_GETECA_RSP_LFUN m_log_geteca_resp +#define MMS_GETECA_REQ_LFUN m_log_geteca_req +#else +#define MMS_GETECA_RSP_LFUN m_no_log_resp +#define MMS_GETECA_REQ_LFUN m_no_log_req +#endif + +#if (MMS_REPECS_EN & (REQ_EN | RESP_EN)) +#define MMS_REPECS_RSP_LFUN m_log_repecs_resp +#define MMS_REPECS_REQ_LFUN m_log_repecs_req +#else +#define MMS_REPECS_RSP_LFUN m_no_log_resp +#define MMS_REPECS_REQ_LFUN m_no_log_req +#endif + +#if (MMS_ALTECM_EN & (REQ_EN | RESP_EN)) +#define MMS_ALTECM_RSP_LFUN m_no_log_resp +#define MMS_ALTECM_REQ_LFUN m_log_altecm_req +#else +#define MMS_ALTECM_RSP_LFUN m_no_log_resp +#define MMS_ALTECM_REQ_LFUN m_no_log_req +#endif + +#if (MMS_TRIGE_EN & (REQ_EN | RESP_EN)) +#define MMS_TRIGE_RSP_LFUN m_no_log_resp +#define MMS_TRIGE_REQ_LFUN m_log_trige_req +#else +#define MMS_TRIGE_RSP_LFUN m_no_log_resp +#define MMS_TRIGE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEFEA_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFEA_RSP_LFUN m_no_log_resp +#define MMS_DEFEA_REQ_LFUN m_log_defea_req +#else +#define MMS_DEFEA_RSP_LFUN m_no_log_resp +#define MMS_DEFEA_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DELEA_EN & (REQ_EN | RESP_EN)) +#define MMS_DELEA_RSP_LFUN m_log_delea_resp +#define MMS_DELEA_REQ_LFUN m_log_delea_req +#else +#define MMS_DELEA_RSP_LFUN m_no_log_resp +#define MMS_DELEA_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETEAA_EN & (REQ_EN | RESP_EN)) +#define MMS_GETEAA_RSP_LFUN m_log_geteaa_resp +#define MMS_GETEAA_REQ_LFUN m_log_geteaa_req +#else +#define MMS_GETEAA_RSP_LFUN m_no_log_resp +#define MMS_GETEAA_REQ_LFUN m_no_log_req +#endif + +#if (MMS_REPEAS_EN & (REQ_EN | RESP_EN)) +#define MMS_REPEAS_RSP_LFUN m_log_repeas_resp +#define MMS_REPEAS_REQ_LFUN m_log_repeas_req +#else +#define MMS_REPEAS_RSP_LFUN m_no_log_resp +#define MMS_REPEAS_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DEFEE_EN & (REQ_EN | RESP_EN)) +#define MMS_DEFEE_RSP_LFUN m_no_log_resp +#define MMS_DEFEE_REQ_LFUN m_log_defee_req +#else +#define MMS_DEFEE_RSP_LFUN m_no_log_resp +#define MMS_DEFEE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_DELEE_EN & (REQ_EN | RESP_EN)) +#define MMS_DELEE_RSP_LFUN m_log_delee_resp +#define MMS_DELEE_REQ_LFUN m_log_delee_req +#else +#define MMS_DELEE_RSP_LFUN m_no_log_resp +#define MMS_DELEE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_ALTEE_EN & (REQ_EN | RESP_EN)) +#define MMS_ALTEE_RSP_LFUN m_log_altee_resp +#define MMS_ALTEE_REQ_LFUN m_log_altee_req +#else +#define MMS_ALTEE_RSP_LFUN m_no_log_resp +#define MMS_ALTEE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_REPEES_EN & (REQ_EN | RESP_EN)) +#define MMS_REPEES_RSP_LFUN m_log_repees_resp +#define MMS_REPEES_REQ_LFUN m_log_repees_req +#else +#define MMS_REPEES_RSP_LFUN m_no_log_resp +#define MMS_REPEES_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETEEA_EN & (REQ_EN | RESP_EN)) +#define MMS_GETEEA_RSP_LFUN m_log_geteea_resp +#define MMS_GETEEA_REQ_LFUN m_log_geteea_req +#else +#define MMS_GETEEA_RSP_LFUN m_no_log_resp +#define MMS_GETEEA_REQ_LFUN m_no_log_req +#endif + +#if (MMS_ACKEVNOT_EN & (REQ_EN | RESP_EN)) +#define MMS_ACKEVNOT_RSP_LFUN m_no_log_resp +#define MMS_ACKEVNOT_REQ_LFUN m_log_ackevnot_req +#else +#define MMS_ACKEVNOT_RSP_LFUN m_no_log_resp +#define MMS_ACKEVNOT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETAS_EN & (REQ_EN | RESP_EN)) +#define MMS_GETAS_RSP_LFUN m_log_getas_resp +#define MMS_GETAS_REQ_LFUN m_log_getas_req +#else +#define MMS_GETAS_RSP_LFUN m_no_log_resp +#define MMS_GETAS_REQ_LFUN m_no_log_req +#endif + +#if (MMS_GETAES_EN & (REQ_EN | RESP_EN)) +#define MMS_GETAES_RSP_LFUN m_log_getaes_resp +#define MMS_GETAES_REQ_LFUN m_log_getaes_req +#else +#define MMS_GETAES_RSP_LFUN m_no_log_resp +#define MMS_GETAES_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* JOURNAL MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_JREAD_EN & (REQ_EN | RESP_EN)) +#define MMS_JREAD_RSP_LFUN m_log_jread_resp +#define MMS_JREAD_REQ_LFUN m_log_jread_req +#else +#define MMS_JREAD_RSP_LFUN m_no_log_resp +#define MMS_JREAD_REQ_LFUN m_no_log_req +#endif + +#if (MMS_JWRITE_EN & (REQ_EN | RESP_EN)) +#define MMS_JWRITE_RSP_LFUN m_no_log_resp +#define MMS_JWRITE_REQ_LFUN m_log_jwrite_req +#else +#define MMS_JWRITE_RSP_LFUN m_no_log_resp +#define MMS_JWRITE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_JINIT_EN & (REQ_EN | RESP_EN)) +#define MMS_JINIT_RSP_LFUN m_log_jinit_resp +#define MMS_JINIT_REQ_LFUN m_log_jinit_req +#else +#define MMS_JINIT_RSP_LFUN m_no_log_resp +#define MMS_JINIT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_JSTAT_EN & (REQ_EN | RESP_EN)) +#define MMS_JSTAT_RSP_LFUN m_log_jstat_resp +#define MMS_JSTAT_REQ_LFUN m_log_jstat_req +#else +#define MMS_JSTAT_RSP_LFUN m_no_log_resp +#define MMS_JSTAT_REQ_LFUN m_no_log_req +#endif + +#if (MMS_JCREATE_EN & (REQ_EN | RESP_EN)) +#define MMS_JCREATE_RSP_LFUN m_no_log_resp +#define MMS_JCREATE_REQ_LFUN m_log_jcreate_req +#else +#define MMS_JCREATE_RSP_LFUN m_no_log_resp +#define MMS_JCREATE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_JDELETE_EN & (REQ_EN | RESP_EN)) +#define MMS_JDELETE_RSP_LFUN m_no_log_resp +#define MMS_JDELETE_REQ_LFUN m_log_jdelete_req +#else +#define MMS_JDELETE_RSP_LFUN m_no_log_resp +#define MMS_JDELETE_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/* FILE MANAGEMENT SERVICES */ +/************************************************************************/ + +#if (MMS_OBTAINFILE_EN & (REQ_EN | RESP_EN)) +#define MMS_OBTAINFILE_RSP_LFUN m_no_log_resp +#define MMS_OBTAINFILE_REQ_LFUN m_log_obtfile_req +#else +#define MMS_OBTAINFILE_RSP_LFUN m_no_log_resp +#define MMS_OBTAINFILE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_FOPEN_EN & (REQ_EN | RESP_EN)) +#define MMS_FOPEN_RSP_LFUN m_log_fopen_resp +#define MMS_FOPEN_REQ_LFUN m_log_fopen_req +#else +#define MMS_FOPEN_RSP_LFUN m_no_log_resp +#define MMS_FOPEN_REQ_LFUN m_no_log_req +#endif + +#if (MMS_FREAD_EN & (REQ_EN | RESP_EN)) +#define MMS_FREAD_RSP_LFUN m_log_fread_resp +#define MMS_FREAD_REQ_LFUN m_log_fread_req +#else +#define MMS_FREAD_RSP_LFUN m_no_log_resp +#define MMS_FREAD_REQ_LFUN m_no_log_req +#endif + +#if (MMS_FCLOSE_EN & (REQ_EN | RESP_EN)) +#define MMS_FCLOSE_RSP_LFUN m_no_log_resp +#define MMS_FCLOSE_REQ_LFUN m_log_fclose_req +#else +#define MMS_FCLOSE_RSP_LFUN m_no_log_resp +#define MMS_FCLOSE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_FRENAME_EN & (REQ_EN | RESP_EN)) +#define MMS_FRENAME_RSP_LFUN m_no_log_resp +#define MMS_FRENAME_REQ_LFUN m_log_frename_req +#else +#define MMS_FRENAME_RSP_LFUN m_no_log_resp +#define MMS_FRENAME_REQ_LFUN m_no_log_req +#endif + +#if (MMS_FDELETE_EN & (REQ_EN | RESP_EN)) +#define MMS_FDELETE_RSP_LFUN m_no_log_resp +#define MMS_FDELETE_REQ_LFUN m_log_fdelete_req +#else +#define MMS_FDELETE_RSP_LFUN m_no_log_resp +#define MMS_FDELETE_REQ_LFUN m_no_log_req +#endif + +#if (MMS_FDIR_EN & (REQ_EN | RESP_EN)) +#define MMS_FDIR_RSP_LFUN m_log_fdir_resp +#define MMS_FDIR_REQ_LFUN m_log_fdir_req +#else +#define MMS_FDIR_RSP_LFUN m_no_log_resp +#define MMS_FDIR_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/************************************************************************/ +/* UNCONFIRMED SERVICES FROM VARIABLE ACCESS, VMD SUPPORT AND EVENT */ +/* MANAGEMENT SERVICES */ +/************************************************************************/ +#if (MMS_INFO_EN & (REQ_EN | RESP_EN)) +#define MMS_INFO_REQ_LFUN m_log_info_req +#define MMS_INFO_RSP_LFUN m_no_log_resp +#else +#define MMS_INFO_RSP_LFUN m_no_log_resp +#define MMS_INFO_REQ_LFUN m_no_log_req +#endif + +#if (MMS_USTATUS_EN & (REQ_EN | RESP_EN)) +#define MMS_USTATUS_REQ_LFUN m_log_ustatus_req +#define MMS_USTATUS_RSP_LFUN m_no_log_resp +#else +#define MMS_USTATUS_RSP_LFUN m_no_log_resp +#define MMS_USTATUS_REQ_LFUN m_no_log_req +#endif + +#if (MMS_EVNOT_EN & (REQ_EN | RESP_EN)) +#define MMS_EVNOT_REQ_LFUN m_log_evnot_req +#define MMS_EVNOT_RSP_LFUN m_no_log_resp +#else +#define MMS_EVNOT_RSP_LFUN m_no_log_resp +#define MMS_EVNOT_REQ_LFUN m_no_log_req +#endif + +/************************************************************************/ +/************************************************************************/ +/* ENVIRONMENT & GENERAL MANAGEMENT */ +/************************************************************************/ + +#define MMS_CONCLUDE_RSP_LFUN m_no_log_resp +#define MMS_CONCLUDE_REQ_LFUN m_no_log_req + +#if (MMS_CANCEL_EN & (REQ_EN | RESP_EN)) +#define MMS_CANCEL_RSP_LFUN m_no_log_resp +#define MMS_CANCEL_REQ_LFUN m_no_log_req +#else +#define MMS_CANCEL_RSP_LFUN m_no_log_resp +#define MMS_CANCEL_REQ_LFUN m_no_log_req +#endif + +#if (MMS_INIT_EN & (REQ_EN | RESP_EN)) +#define MMS_INIT_RSP_LFUN m_log_init_info +#define MMS_INIT_REQ_LFUN m_log_init_info +#else +#define MMS_INIT_RSP_LFUN m_no_log_resp +#define MMS_INIT_REQ_LFUN m_no_log_req +#endif + + +/************************************************************************/ +/************************************************************************/ +/* initialize the REQUEST/INDICATION LOG table, opcode is index */ +/************************************************************************/ + +ST_VOID (*m_req_log_fun_tbl [MAX_MMSOP_DIS+1]) (ST_VOID *) = + { + (ST_VOID (*)(ST_VOID *)) MMS_STATUS_REQ_LFUN, /* 00 STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_GETNAMES_REQ_LFUN, /* 01 GET_NAMLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_IDENT_REQ_LFUN, /* 02 IDENTIFY */ + (ST_VOID (*)(ST_VOID *)) MMS_RENAME_REQ_LFUN, /* 03 RENAME */ + (ST_VOID (*)(ST_VOID *)) MMS_READ_REQ_LFUN, /* 04 READ */ + (ST_VOID (*)(ST_VOID *)) MMS_WRITE_REQ_LFUN, /* 05 WRITE */ + (ST_VOID (*)(ST_VOID *)) MMS_GETVAR_REQ_LFUN, /* 06 GET_VARDEF */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFVAR_REQ_LFUN, /* 07 DEF_VARNAM */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFSCAT_REQ_LFUN, /* 08 DEF_SCATTERED */ + (ST_VOID (*)(ST_VOID *)) MMS_GETSCAT_REQ_LFUN, /* 09 GET_SCATTERED */ + (ST_VOID (*)(ST_VOID *)) MMS_DELVAR_REQ_LFUN, /* 10 DEL_VARNAM */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFVLIST_REQ_LFUN, /* 11 DEF_VARLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_GETVLIST_REQ_LFUN, /* 12 GET_VARLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_DELVLIST_REQ_LFUN, /* 13 DEL_VARLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFTYPE_REQ_LFUN, /* 14 DEF_TYPENAM */ + (ST_VOID (*)(ST_VOID *)) MMS_GETTYPE_REQ_LFUN, /* 15 GET_TYPEDEF */ + (ST_VOID (*)(ST_VOID *)) MMS_DELTYPE_REQ_LFUN, /* 16 DEL_TYPENAM */ + (ST_VOID (*)(ST_VOID *)) MMS_INPUT_REQ_LFUN, /* 17 INPUT */ + (ST_VOID (*)(ST_VOID *)) MMS_OUTPUT_REQ_LFUN, /* 18 OUTPUT */ + (ST_VOID (*)(ST_VOID *)) MMS_TAKECTRL_REQ_LFUN, /* 19 TAKE_CONTROL */ + (ST_VOID (*)(ST_VOID *)) MMS_RELCTRL_REQ_LFUN, /* 20 REL_CONTROL */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFINE_SEM_REQ_LFUN, /* 21 DEF_SEMAPHORE */ + (ST_VOID (*)(ST_VOID *)) MMS_DELETE_SEM_REQ_LFUN, /* 22 DEL_SEMAPHORE */ + (ST_VOID (*)(ST_VOID *)) MMS_REP_SEMSTAT_REQ_LFUN, /* 23 REP_SEM_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_REP_SEMPOOL_REQ_LFUN, /* 24 REP_SEM_POOL_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_REP_SEMENTRY_REQ_LFUN, /* 25 REP_SEM_ENTRY_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_INIT_DWN_REQ_LFUN, /* 26 INIT_DOWNLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_DWN_LOAD_REQ_LFUN, /* 27 DOWN_LOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_TERM_DWN_REQ_LFUN, /* 28 TERM_DOWNLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_INIT_UPL_REQ_LFUN, /* 29 INIT_UPLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_UP_LOAD_REQ_LFUN, /* 30 UP_LOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_TERM_UPL_REQ_LFUN, /* 31 TERM_UPLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_RDDWN_REQ_LFUN, /* 32 REQ_DOWNLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_RDUPL_REQ_LFUN, /* 33 REQ_UPLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_LOAD_DOM_REQ_LFUN, /* 34 LOAD_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_STR_DOM_REQ_LFUN, /* 35 STORE_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_DEL_DOM_REQ_LFUN, /* 36 DELETE_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_GET_DOM_REQ_LFUN, /* 37 GET_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_CRE_PI_REQ_LFUN, /* 38 CREATE_PROGRAM_INVOCATION*/ + (ST_VOID (*)(ST_VOID *)) MMS_DEL_PI_REQ_LFUN, /* 39 DEL_PROGRAM_INVOCATION */ + (ST_VOID (*)(ST_VOID *)) MMS_START_REQ_LFUN, /* 40 START */ + (ST_VOID (*)(ST_VOID *)) MMS_STOP_REQ_LFUN, /* 41 STOP */ + (ST_VOID (*)(ST_VOID *)) MMS_RESUME_REQ_LFUN, /* 42 RESUME */ + (ST_VOID (*)(ST_VOID *)) MMS_RESET_REQ_LFUN, /* 43 RESET */ + (ST_VOID (*)(ST_VOID *)) MMS_KILL_REQ_LFUN, /* 44 KILL */ + (ST_VOID (*)(ST_VOID *)) MMS_GET_PI_REQ_LFUN, /* 45 GET_PROGRAM_INVOCATION */ + (ST_VOID (*)(ST_VOID *)) MMS_OBTAINFILE_REQ_LFUN, /* 46 OBTAIN_FILE */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFEC_REQ_LFUN, /* 47 DEFINE EVENT CONDITION */ + (ST_VOID (*)(ST_VOID *)) MMS_DELEC_REQ_LFUN, /* 48 DELETE EVENT CONDITION */ + (ST_VOID (*)(ST_VOID *)) MMS_GETECA_REQ_LFUN, /* 49 GET EVENT CONDITION ATTR */ + (ST_VOID (*)(ST_VOID *)) MMS_REPECS_REQ_LFUN, /* 50 REPORT EVENT COND STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_ALTECM_REQ_LFUN, /* 51 ALTER EV COND MONITORING */ + (ST_VOID (*)(ST_VOID *)) MMS_TRIGE_REQ_LFUN, /* 52 TRIGGER EVENT */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFEA_REQ_LFUN, /* 53 DEFINE EVENT ACTION */ + (ST_VOID (*)(ST_VOID *)) MMS_DELEA_REQ_LFUN, /* 54 DELETE EVENT ACTION */ + (ST_VOID (*)(ST_VOID *)) MMS_GETEAA_REQ_LFUN, /* 55 GET EV ACTION ATTRIBUTES */ + (ST_VOID (*)(ST_VOID *)) MMS_REPEAS_REQ_LFUN, /* 56 REPORT EV ACTION STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFEE_REQ_LFUN, /* 57 DEFINE EVENT ENROLLMENT */ + (ST_VOID (*)(ST_VOID *)) MMS_DELEE_REQ_LFUN, /* 58 DELETE EVENT ENROLLMENT */ + (ST_VOID (*)(ST_VOID *)) MMS_ALTEE_REQ_LFUN, /* 59 ALTER EVENT ENROLLMENT */ + (ST_VOID (*)(ST_VOID *)) MMS_REPEES_REQ_LFUN, /* 60 REPORT ENROLL ATTRIBUTES */ + (ST_VOID (*)(ST_VOID *)) MMS_GETEEA_REQ_LFUN, /* 61 GET ENROLLMENT STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_ACKEVNOT_REQ_LFUN, /* 62 ACK_EVENT_NOTIFICATION */ + (ST_VOID (*)(ST_VOID *)) MMS_GETAS_REQ_LFUN, /* 63 GET_ALARM_SUMMARY */ + (ST_VOID (*)(ST_VOID *)) MMS_GETAES_REQ_LFUN, /* 64 GET ALARM ENROLLMENT SUM */ + (ST_VOID (*)(ST_VOID *)) MMS_JREAD_REQ_LFUN, /* 65 READ_JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JWRITE_REQ_LFUN, /* 66 WRITE_JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JINIT_REQ_LFUN, /* 67 INITIALIZE_JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JSTAT_REQ_LFUN, /* 68 REPORT_JOURNAL_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_JCREATE_REQ_LFUN, /* 69 CREATE JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JDELETE_REQ_LFUN, /* 70 DELETE JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_GETCL_REQ_LFUN, /* 71 GET CAPABILITY LIST */ + (ST_VOID (*)(ST_VOID *)) MMS_FOPEN_REQ_LFUN, /* 72 FILE_OPEN */ + (ST_VOID (*)(ST_VOID *)) MMS_FREAD_REQ_LFUN, /* 73 FILE_READ */ + (ST_VOID (*)(ST_VOID *)) MMS_FCLOSE_REQ_LFUN, /* 74 FILE_CLOSE */ + (ST_VOID (*)(ST_VOID *)) MMS_FRENAME_REQ_LFUN, /* 75 FILE_RENAME */ + (ST_VOID (*)(ST_VOID *)) MMS_FDELETE_REQ_LFUN, /* 76 FILE_DELETE */ + (ST_VOID (*)(ST_VOID *)) MMS_FDIR_REQ_LFUN, /* 77 FILE_DIR */ + (ST_VOID (*)(ST_VOID *)) MMS_USTATUS_REQ_LFUN, /* 78 UNSOLICITED_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_INFO_REQ_LFUN, /* 79 INFO_RPT */ + (ST_VOID (*)(ST_VOID *)) MMS_EVNOT_REQ_LFUN, /* 80 EVENT NOTIFICATION */ + (ST_VOID (*)(ST_VOID *)) m_no_log_req, /* 81 ATTACH TO EVENT COND */ + (ST_VOID (*)(ST_VOID *)) m_no_log_req, /* 82 ATTACH TO SEMAPHORE */ + (ST_VOID (*)(ST_VOID *)) MMS_CONCLUDE_REQ_LFUN, /* 83 CONCLUDE */ + (ST_VOID (*)(ST_VOID *)) MMS_CANCEL_REQ_LFUN, /* 84 CANCEL */ + (ST_VOID (*)(ST_VOID *)) MMS_INIT_REQ_LFUN /* 85 INITIATE */ + }; + +/************************************************************************/ +/* initialize the RESPONSE/CONFIRM LOG table, opcode is index */ +/************************************************************************/ +ST_VOID (*m_resp_log_fun_tbl [MAX_MMSOP_DIS+1]) (ST_VOID *) = + { + (ST_VOID (*)(ST_VOID *)) MMS_STATUS_RSP_LFUN, /* 00 STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_GETNAMES_RSP_LFUN, /* 01 GET_NAMLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_IDENT_RSP_LFUN, /* 02 IDENTIFY */ + (ST_VOID (*)(ST_VOID *)) MMS_RENAME_RSP_LFUN, /* 03 RENAME */ + (ST_VOID (*)(ST_VOID *)) MMS_READ_RSP_LFUN, /* 04 READ */ + (ST_VOID (*)(ST_VOID *)) MMS_WRITE_RSP_LFUN, /* 05 WRITE */ + (ST_VOID (*)(ST_VOID *)) MMS_GETVAR_RSP_LFUN, /* 06 GET_VARDEF */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFVAR_RSP_LFUN, /* 07 DEF_VARNAM */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFSCAT_RSP_LFUN, /* 08 DEF_SCATTERED */ + (ST_VOID (*)(ST_VOID *)) MMS_GETSCAT_RSP_LFUN, /* 09 GET_SCATTERED */ + (ST_VOID (*)(ST_VOID *)) MMS_DELVAR_RSP_LFUN, /* 10 DEL_VARNAM */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFVLIST_RSP_LFUN, /* 11 DEF_VARLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_GETVLIST_RSP_LFUN, /* 12 GET_VARLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_DELVLIST_RSP_LFUN, /* 13 DEL_VARLIST */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFTYPE_RSP_LFUN, /* 14 DEF_TYPENAM */ + (ST_VOID (*)(ST_VOID *)) MMS_GETTYPE_RSP_LFUN, /* 15 GET_TYPEDEF */ + (ST_VOID (*)(ST_VOID *)) MMS_DELTYPE_RSP_LFUN, /* 16 DEL_TYPENAM */ + (ST_VOID (*)(ST_VOID *)) MMS_INPUT_RSP_LFUN, /* 17 INPUT */ + (ST_VOID (*)(ST_VOID *)) MMS_OUTPUT_RSP_LFUN, /* 18 OUTPUT */ + (ST_VOID (*)(ST_VOID *)) MMS_TAKECTRL_RSP_LFUN, /* 19 TAKE_CONTROL */ + (ST_VOID (*)(ST_VOID *)) MMS_RELCTRL_RSP_LFUN, /* 20 REL_CONTROL */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFINE_SEM_RSP_LFUN, /* 21 DEF_SEMAPHORE */ + (ST_VOID (*)(ST_VOID *)) MMS_DELETE_SEM_RSP_LFUN, /* 22 DEL_SEMAPHORE */ + (ST_VOID (*)(ST_VOID *)) MMS_REP_SEMSTAT_RSP_LFUN, /* 23 REP_SEM_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_REP_SEMPOOL_RSP_LFUN, /* 24 REP_SEM_POOL_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_REP_SEMENTRY_RSP_LFUN, /* 25 REP_SEM_ENTRY_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_INIT_DWN_RSP_LFUN, /* 26 INIT_DOWNLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_DWN_LOAD_RSP_LFUN, /* 27 DOWN_LOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_TERM_DWN_RSP_LFUN, /* 28 TERM_DOWNLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_INIT_UPL_RSP_LFUN, /* 29 INIT_UPLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_UP_LOAD_RSP_LFUN, /* 30 UP_LOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_TERM_UPL_RSP_LFUN, /* 31 TERM_UPLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_RDDWN_RSP_LFUN, /* 32 REQ_DOWNLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_RDUPL_RSP_LFUN, /* 33 REQ_UPLOAD */ + (ST_VOID (*)(ST_VOID *)) MMS_LOAD_DOM_RSP_LFUN, /* 34 LOAD_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_STR_DOM_RSP_LFUN, /* 35 STORE_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_DEL_DOM_RSP_LFUN, /* 36 DELETE_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_GET_DOM_RSP_LFUN, /* 37 GET_DOMAIN */ + (ST_VOID (*)(ST_VOID *)) MMS_CRE_PI_RSP_LFUN, /* 38 CREATE_PROGRAM_INVOCATION*/ + (ST_VOID (*)(ST_VOID *)) MMS_DEL_PI_RSP_LFUN, /* 39 DEL_PROGRAM_INVOCATION */ + (ST_VOID (*)(ST_VOID *)) MMS_START_RSP_LFUN, /* 40 START */ + (ST_VOID (*)(ST_VOID *)) MMS_STOP_RSP_LFUN, /* 41 STOP */ + (ST_VOID (*)(ST_VOID *)) MMS_RESUME_RSP_LFUN, /* 42 RESUME */ + (ST_VOID (*)(ST_VOID *)) MMS_RESET_RSP_LFUN, /* 43 RESET */ + (ST_VOID (*)(ST_VOID *)) MMS_KILL_RSP_LFUN, /* 44 KILL */ + (ST_VOID (*)(ST_VOID *)) MMS_GET_PI_RSP_LFUN, /* 45 GET_PROGRAM_INVOCATION */ + (ST_VOID (*)(ST_VOID *)) MMS_OBTAINFILE_RSP_LFUN, /* 46 OBTAIN_FILE */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFEC_RSP_LFUN, /* 47 DEFINE EVENT CONDITION */ + (ST_VOID (*)(ST_VOID *)) MMS_DELEC_RSP_LFUN, /* 48 DELETE EVENT CONDITION */ + (ST_VOID (*)(ST_VOID *)) MMS_GETECA_RSP_LFUN, /* 49 GET EVENT CONDITION ATTR */ + (ST_VOID (*)(ST_VOID *)) MMS_REPECS_RSP_LFUN, /* 50 REPORT EVENT COND STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_ALTECM_RSP_LFUN, /* 51 ALTER EV COND MONITORING */ + (ST_VOID (*)(ST_VOID *)) MMS_TRIGE_RSP_LFUN, /* 52 TRIGGER EVENT */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFEA_RSP_LFUN, /* 53 DEFINE EVENT ACTION */ + (ST_VOID (*)(ST_VOID *)) MMS_DELEA_RSP_LFUN, /* 54 DELETE EVENT ACTION */ + (ST_VOID (*)(ST_VOID *)) MMS_GETEAA_RSP_LFUN, /* 55 GET EV ACTION ATTRIBUTES */ + (ST_VOID (*)(ST_VOID *)) MMS_REPEAS_RSP_LFUN, /* 56 REPORT EV ACTION STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_DEFEE_RSP_LFUN, /* 57 DEFINE EVENT ENROLLMENT */ + (ST_VOID (*)(ST_VOID *)) MMS_DELEE_RSP_LFUN, /* 58 DELETE EVENT ENROLLMENT */ + (ST_VOID (*)(ST_VOID *)) MMS_ALTEE_RSP_LFUN, /* 59 ALTER EVENT ENROLLMENT */ + (ST_VOID (*)(ST_VOID *)) MMS_REPEES_RSP_LFUN, /* 60 REPORT ENROLL ATTRIBUTES */ + (ST_VOID (*)(ST_VOID *)) MMS_GETEEA_RSP_LFUN, /* 61 GET ENROLLMENT STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_ACKEVNOT_RSP_LFUN, /* 62 ACK_EVENT_NOTIFICATION */ + (ST_VOID (*)(ST_VOID *)) MMS_GETAS_RSP_LFUN, /* 63 GET_ALARM_SUMMARY */ + (ST_VOID (*)(ST_VOID *)) MMS_GETAES_RSP_LFUN, /* 64 GET ALARM ENROLLMENT SUM */ + (ST_VOID (*)(ST_VOID *)) MMS_JREAD_RSP_LFUN, /* 65 READ_JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JWRITE_RSP_LFUN, /* 66 WRITE_JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JINIT_RSP_LFUN, /* 67 INITIALIZE_JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JSTAT_RSP_LFUN, /* 68 REPORT_JOURNAL_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_JCREATE_RSP_LFUN, /* 69 CREATE JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_JDELETE_RSP_LFUN, /* 70 DELETE JOURNAL */ + (ST_VOID (*)(ST_VOID *)) MMS_GETCL_RSP_LFUN, /* 71 GET CAPABILITY LIST */ + (ST_VOID (*)(ST_VOID *)) MMS_FOPEN_RSP_LFUN, /* 72 FILE_OPEN */ + (ST_VOID (*)(ST_VOID *)) MMS_FREAD_RSP_LFUN, /* 73 FILE_READ */ + (ST_VOID (*)(ST_VOID *)) MMS_FCLOSE_RSP_LFUN, /* 74 FILE_CLOSE */ + (ST_VOID (*)(ST_VOID *)) MMS_FRENAME_RSP_LFUN, /* 75 FILE_RENAME */ + (ST_VOID (*)(ST_VOID *)) MMS_FDELETE_RSP_LFUN, /* 76 FILE_DELETE */ + (ST_VOID (*)(ST_VOID *)) MMS_FDIR_RSP_LFUN, /* 77 FILE_DIR */ + (ST_VOID (*)(ST_VOID *)) MMS_USTATUS_RSP_LFUN, /* 78 UNSOLICITED_STATUS */ + (ST_VOID (*)(ST_VOID *)) MMS_INFO_RSP_LFUN, /* 79 INFO_RPT */ + (ST_VOID (*)(ST_VOID *)) MMS_EVNOT_RSP_LFUN, /* 80 EVENT NOTIFICATION */ + (ST_VOID (*)(ST_VOID *)) m_no_log_resp, /* 81 ATTACH TO EVENT COND */ + (ST_VOID (*)(ST_VOID *)) m_no_log_resp, /* 82 ATTACH TO SEMAPHORE */ + (ST_VOID (*)(ST_VOID *)) MMS_CONCLUDE_RSP_LFUN, /* 83 CONCLUDE */ + (ST_VOID (*)(ST_VOID *)) MMS_CANCEL_RSP_LFUN, /* 84 CANCEL */ + (ST_VOID (*)(ST_VOID *)) MMS_INIT_RSP_LFUN /* 85 INITIATE */ + }; + + +/************************************************************************/ +#endif /* MLOG_ENABLE */ +/************************************************************************/ diff --git a/mms/mmsop_en.h b/mms/mmsop_en.h new file mode 100644 index 0000000..2a68320 --- /dev/null +++ b/mms/mmsop_en.h @@ -0,0 +1,190 @@ +/* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:51 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mmsop_en.h,v 1.1 2018/11/24 06:54:51 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1986 - 1997, All Rights Reserved. */ +/* */ +/* MODULE NAME : mmsop_en.h */ +/* PRODUCT(S) : MMSEASE, MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* This module contains the operation enable switches used to */ +/* configure the decode system, the user service system, & the */ +/* supported services bit strings. */ +/* */ +/* Note that by enabling (or disabling) only the desired MMS */ +/* operations, a limited subset may be created (the subset */ +/* creation module is mmsop_en.c), thus allowing the creation of */ +/* a smaller executable because: */ +/* 1) references to the various MMS-EASE functions are removed */ +/* and therefore are not included from the library, and */ +/* 2) operation specific user application code is eliminated. */ +/* */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 10/15/99 GLB 02 Added file Rename & Obtain File */ +/* 08/18/97 MDE 01 Added parameter support defines */ +/* 04/02/97 DTL 7.00 MMSEASE 7.0 release. See MODL70.DOC for */ +/* history. */ +/************************************************************************/ + +#ifndef MMSOP_EN_INCLUDED +#define MMSOP_EN_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mms_def2.h" /* for REQ_RESP_EN, etc. */ + +/************************************************************************/ +/* define the opcode enable switches */ +/************************************************************************/ +#define MMS_INIT_EN REQ_EN +#define MMS_CONCLUDE_EN REQ_EN +#define MMS_CANCEL_EN REQ_RESP_DIS + +#define MMS_STATUS_EN REQ_EN +#define MMS_USTATUS_EN REQ_RESP_DIS +#define MMS_GETNAMES_EN REQ_EN +#define MMS_IDENT_EN REQ_RESP_EN +#define MMS_RENAME_EN REQ_RESP_DIS +#define MMS_GETCL_EN REQ_RESP_DIS +#define MMS_VMD_EN 0 + +#define MMS_NAMED_DOM_EN 0 +#define MMS_MV_DWN_EN REQ_RESP_DIS /* VM Upload */ +#define MMS_INIT_DWN_EN REQ_RESP_DIS +#define MMS_DWN_LOAD_EN REQ_RESP_DIS +#define MMS_TERM_DWN_EN REQ_RESP_DIS +#define MMS_MV_UPL_EN REQ_RESP_DIS /* VM Download */ +#define MMS_INIT_UPL_EN REQ_RESP_DIS +#define MMS_UP_LOAD_EN REQ_RESP_DIS +#define MMS_TERM_UPL_EN REQ_RESP_DIS +#define MMS_RDDWN_EN REQ_RESP_DIS +#define MMS_RDUPL_EN REQ_RESP_DIS +#define MMS_LOAD_DOM_EN REQ_RESP_DIS +#define MMS_STR_DOM_EN REQ_RESP_DIS +#define MMS_DEL_DOM_EN REQ_RESP_DIS +#define MMS_GET_DOM_EN REQ_EN + +#define MMS_CRE_PI_EN REQ_RESP_DIS +#define MMS_DEL_PI_EN REQ_RESP_DIS +#define MMS_START_EN REQ_RESP_DIS +#define MMS_STOP_EN REQ_RESP_DIS +#define MMS_RESUME_EN REQ_RESP_DIS +#define MMS_RESET_EN REQ_RESP_DIS +#define MMS_KILL_EN REQ_RESP_DIS +#define MMS_GET_PI_EN REQ_RESP_DIS + +#define MMS_VA_EN 0 +#define MMS_MV_READ_EN REQ_RESP_DIS /* VM Read variable(s) */ +#define MMS_MV_RDVARS_EN REQ_RESP_DIS /* General VM Rd var's */ +#define MMS_READ_EN REQ_EN +#define MMS_MV_WRITE_EN REQ_RESP_DIS /* VM Write variable(s) */ +#define MMS_MV_WRVARS_EN REQ_RESP_DIS /* General VM WR var's */ +#define MMS_WRITE_EN REQ_EN +#define MMS_INFO_EN RESP_EN +#define MMS_GETVAR_EN REQ_EN +#define MMS_DEFVAR_EN REQ_RESP_DIS +#define MMS_DEFSCAT_EN REQ_RESP_DIS +#define MMS_GETSCAT_EN REQ_RESP_DIS +#define MMS_DELVAR_EN REQ_RESP_DIS +#define MMS_DEFVLIST_EN REQ_EN +#define MMS_GETVLIST_EN REQ_EN +#define MMS_DELVLIST_EN REQ_EN +#define MMS_MV_DEFTYPE_EN REQ_RESP_DIS /* VM DefineType */ +#define MMS_DEFTYPE_EN REQ_RESP_DIS +#define MMS_GETTYPE_EN REQ_RESP_DIS +#define MMS_DELTYPE_EN REQ_RESP_DIS + +#define MMS_TAKECTRL_EN REQ_RESP_DIS +#define MMS_RELCTRL_EN REQ_RESP_DIS +#define MMS_DEFINE_SEM_EN REQ_RESP_DIS +#define MMS_DELETE_SEM_EN REQ_RESP_DIS +#define MMS_REP_SEMSTAT_EN REQ_RESP_DIS +#define MMS_REP_SEMPOOL_EN REQ_RESP_DIS +#define MMS_REP_SEMENTRY_EN REQ_RESP_DIS + +#define MMS_JREAD_EN REQ_EN +#define MMS_JWRITE_EN REQ_RESP_DIS +#define MMS_JINIT_EN REQ_EN +#define MMS_JSTAT_EN REQ_EN +#define MMS_JCREATE_EN REQ_RESP_DIS +#define MMS_JDELETE_EN REQ_RESP_DIS + +#define MMS_DEFEC_EN REQ_RESP_DIS +#define MMS_DELEC_EN REQ_RESP_DIS +#define MMS_GETECA_EN REQ_RESP_DIS +#define MMS_REPECS_EN REQ_RESP_DIS +#define MMS_ALTECM_EN REQ_RESP_DIS +#define MMS_TRIGE_EN REQ_RESP_DIS +#define MMS_DEFEA_EN REQ_RESP_DIS +#define MMS_DELEA_EN REQ_RESP_DIS +#define MMS_GETEAA_EN REQ_RESP_DIS +#define MMS_REPEAS_EN REQ_RESP_DIS +#define MMS_DEFEE_EN REQ_RESP_DIS +#define MMS_DELEE_EN REQ_RESP_DIS +#define MMS_GETEEA_EN REQ_RESP_DIS +#define MMS_REPEES_EN REQ_RESP_DIS +#define MMS_ALTEE_EN REQ_RESP_DIS +#define MMS_EVNOT_EN REQ_RESP_DIS +#define MMS_ACKEVNOT_EN REQ_RESP_DIS +#define MMS_GETAS_EN REQ_RESP_DIS +#define MMS_GETAES_EN REQ_RESP_DIS + +#define MMS_INPUT_EN REQ_RESP_DIS +#define MMS_OUTPUT_EN REQ_RESP_DIS + +#define MMS_MV_FOPEN_EN REQ_RESP_DIS /* VM FileOpen */ +#define MMS_MV_FREAD_EN REQ_RESP_DIS /* VM FileRead */ +#define MMS_MV_FCLOSE_EN REQ_RESP_DIS /* VM FileClose */ +#define MMS_MV_FCOPY_EN REQ_RESP_DIS /* VM FileCopy */ +#define MMS_OBTAINFILE_EN REQ_EN +#define MMS_FOPEN_EN REQ_RESP_EN +#define MMS_FREAD_EN REQ_RESP_EN +#define MMS_FCLOSE_EN REQ_RESP_EN +#define MMS_FRENAME_EN REQ_EN +#define MMS_FDELETE_EN REQ_EN +#define MMS_FDIR_EN REQ_EN + + +/************************************************************************/ +/************************************************************************/ +/* PARAMETER SUPPORTED BITSTRING VALUES */ +/************************************************************************/ + +#define MPARAM_STR1 0x80 /* 0x80 arrays */ +#define MPARAM_STR2 0x40 /* 0x40 structures */ +#define MPARAM_VNAM 0x20 /* 0x20 named variables */ +#define MPARAM_VALT 0x10 /* 0x10 alternate access */ +#define MPARAM_VADR 0x08 /* 0x08 address formed variables */ +#define MPARAM_VSCA 0x00 /* 0x04 scattered access */ +#define MPARAM_TPY 0x02 /* 0x02 third party */ +#define MPARAM_VLIS 0x01 /* 0x01 variable list */ +#define MPARAM_REAL 0x00 /* 0x80 real data type */ +#define MPARAM_AKEC 0x00 /* 0x40 ack event cond. */ +#define MPARAM_CEI 0x00 /* 0x20 cond. eval. interval */ + +#define MPARAM0 MPARAM_STR1 | MPARAM_STR2 | MPARAM_VNAM | MPARAM_VALT |\ + MPARAM_VADR | MPARAM_VSCA | MPARAM_TPY | MPARAM_VLIS +#define MPARAM1 MPARAM_REAL | MPARAM_AKEC | MPARAM_CEI + + +#ifdef __cplusplus +} +#endif + +#endif /* MMSOP_EN_INCLUDED */ + diff --git a/mms/mvl_acse.c b/mms/mvl_acse.c new file mode 100644 index 0000000..29c54bb --- /dev/null +++ b/mms/mvl_acse.c @@ -0,0 +1,2392 @@ +/* +* @version: $Revision: 1.2 $ +* @date: $Date: 2018/12/19 08:59:51 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mvl_acse.c,v 1.2 2018/12/19 08:59:51 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1986 - 2004, All Rights Reserved */ +/* */ +/* MODULE NAME : mvl_acse.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* NONE */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 07/13/05 MDE 104 Fixed crash caused using mvl_init_ind_hold */ +/* 06/07/05 MDE 103 Fixed deadlock caused by mvl_init_ind_hold */ +/* 05/10/05 JRB 102 Call new mvl_init_aa_obj_ctrl to init struct */ +/* to control AA-Specific object creation */ +/* (no longer done by Foundry). */ +/* 05/04/05 MDE 101 Added mvl_init_ind_hold */ +/* 04/28/05 MDE 100 Added user_conn_id check on abort ind */ +/* 04/06/05 MDE 99 Added test probes */ +/* 03/09/05 MDE 98 Set stats startTime */ +/* 08/11/04 JRB 97 Del global funct ptr u_mvl_connect_ind_fun. */ +/* Fix mvl_abort_req(_ex) returns (ST_RET). */ +/* 07/14/04 MDE 96 Set mvl_net_info->acse_conn_id on init req */ +/* 07/08/04 JRB 95 Del unused global var mvl_local_cl_ar_name. */ +/* 06/07/04 EJV 94 Removed call to a_free_security_info */ +/* 04/09/04 MDE 93 Removed call to a_free_security_info */ +/* 01/21/04 EJV 92 u_a_associate_ind: added a_free_security_info*/ +/* added reinfo.auth_info.auth_pres = SD_FALSE*/ +/* 01/20/04 MDE 91 Added logging */ +/* 11/07/03 JRB 90 Add mmsop_en_version1. */ +/* 08/10/03 EJV 89 ACSE_AUTH_ENABLED code wo/defines */ +/* Reworked mvl_net_info_to_chan. */ +/* Removed defs from around find_rem_dib_entry()*/ +/* For MAP30_ACSE use a_get_chan(). */ +/* 07/02/03 JRB 88 _mvl_net_service set activityFlag if more */ +/* events on list (so user keeps calling). */ +/* 06/16/03 EJV 87 Removed m_match.h, s_match.h includes. */ +/* Renamed the match funcs & chg arg. */ +/* 06/10/03 MDE 86 Added address matching */ +/* 04/14/03 JRB 85 Eliminate compiler warnings. */ +/* 12/18/02 ASK 84 Only check authentication on POSITIVE connect*/ +/* confirm */ +/* 10/30/02 JRB 83 mvl_init_audt_addr: check remote tp_type. */ +/* _mvl_send_msg: do lock around a_data_req */ +/* call to make it thread-safe. */ +/* Chg all connID, bindID to ST_LONG to avoid */ +/* compile errors on 64-bit systems. */ +/* 10/11/02 ASK 82 Added mvla_initiate_req_ex, */ +/* u_mvl_connect_ind_ex, and */ +/* u_mvl_connect_cnf_ex functions for ACSE */ +/* authentication. */ +/* 07/19/02 ASK 81 Fix net_info variable in _mvl_send_msg */ +/* 07/17/02 MDE 80 Added mvl_conn_filtered_logging to send */ +/* 07/10/02 JRB 79 Add maxpend_ind, numpend_ind. */ +/* 07/09/02 MDE 78 Fixed bad free for bad decode of init resp */ +/* 05/24/02 JRB 77 Put back MVL_COMM_EVENT linked list. */ +/* Occasionally copp_event gets 2 events, one */ +/* from TP0 and one from TP4. */ +/* 05/17/02 JRB 76 mvla_init..: set *req_out=NULL if freed */ +/* so user CAN'T free it again. */ +/* 05/13/02 MDE 75 Don't scan unbound mvl_net_info */ +/* 05/13/02 MDE 74 Now clean up requests for release conf */ +/* 05/03/02 MDE 73 Added mvl_add_bind_ctrl, associated changes */ +/* 04/29/02 MDE 72 Added MLOG for initiate */ +/* 04/29/02 JRB 71 DON'T re-use MVL_NET_INFO until req_pend_list*/ +/* is empty, assert if pend_ind is not empty. */ +/* 03/07/02 MDE 70 mvla_set_init_ar now takes NULL */ +/* 03/04/02 JRB 69 Start with clean "temp_bind_ctrl" so garbage */ +/* doesn't get copied. */ +/* Return error if num_call*>0 but not supported*/ +/* 02/25/02 MDE 68 More changes to MVL_CFG_INFO */ +/* 02/20/02 MDE 67 Changes for new MVL_CFG_INFO, multiple bind */ +/* 02/14/02 RKR 66 call a_associate_reqm if Marben stack */ +/* 02/08/02 JRB 65 Pass MVL_CFG_INFO struct to mvl_start_acse. */ +/* Del mvl_local_ar_name,mvl_set_num_connections*/ +/* 01/30/02 JRB 64 Add args to copp_initialize (same as MAP30..)*/ +/* Del call to a_set_msgsize. */ +/* Make sure mmsl_max_msg_size, mvl_num_calling,*/ +/* mvl_num_called are set. */ +/* Use MMS_INIT_EN instead of MVL_NUM_CALL*. */ +/* Del use of COACSE define. */ +/* Del mvl_max_comm_event (not used). */ +/* Merge mvl_init, _mvl_init_conn_ctrl into */ +/* mvl_start_acse. */ +/* Replace mvl_init_cl_netinfo funct with */ +/* mvl_init_audt_addr. */ +/* Del u_a_unit_data_ind & all use of stack_sel.*/ +/* 01/09/02 JRB 63 Del all use of clpp_bind & bind id. */ +/* Del unused u_cla_except callback function. */ +/* 12/04/01 MDE 62 Change to work with MAP30_ACSE */ +/* 11/30/01 GLB 61 changed MVL_LOG_ERR1 to MVL_LOG_ERR0 */ +/* 11/28/01 MDE 60 mvl_set_num_connections,mvl_set_max_msg_size */ +/* 11/21/01 MDE 59 mvl_loc_ar_name now auto set */ +/* 11/21/01 MDE 58 Safer num channel operation */ +/* 11/05/01 JRB 57 mvl_wait_req_done now returns ST_RET. */ +/* 09/21/01 JRB 56 Alloc global bufs only once at startup. */ +/* Fix M_FREE context. */ +/* 07/31/01 MDE 55 Added mvl_conn_filtered_logging */ +/* 05/21/01 MDE 54 Free NET_INFO */ +/* 03/13/01 JRB 53 Check for (MMS_INIT_EN & REQ_EN). */ +/* 02/26/01 MDE 52 Moved m_smem_ctxt to mem_chks.c */ +/* 11/28/00 EJV 51 Changes to interface with Marben stack SUIC */ +/* (see MAP30_ACSE define): */ +/* Use SUIC find_loc_..., find_rem_dib_entry. */ +/* Added param in copp_initialize(). */ +/* Added param in mvla_initiate_req(). */ +/* Changed params in copp_bind(). */ +/* 10/25/00 JRB 50 Del MVL_COMM_EVENT linked list. Only one used*/ +/* Del call to _mvl_free_req_pend. */ +/* 09/22/00 MDE 49 Changed index init */ +/* 08/21/00 RKR 48 Changed prototype of mvl_init_cl_netinfo */ +/* 08/23/00 MDE 47 Call '_mvl_set_net_req_done' on aborts too */ +/* 05/15/00 MDE 46 Added MMS statistics */ +/* 04/27/00 JRB 45 Fixed calloc (0) problem */ +/* 04/14/00 JRB 44 Lint cleanup. */ +/* 04/12/00 MDE 43 Added AA resize, MVL_STATISTICS */ +/* 03/15/00 JRB 42 Del #ifdef MVL_REQ_BUF_ENABLED: not used. */ +/* 03/09/00 MDE 41 Added _mvl_init_conn_ctrl */ +/* 01/21/00 MDE 40 Now use MEM_SMEM for dynamic memory */ +/* 12/20/99 GLB 39 Remove extra initialization and add asserts */ +/* 11/23/99 MDE 38 Added mvla_check_req_que (from mvl_serv.c) */ +/* 10/20/99 NAV 37 Add maxpend_req support */ +/* 11/03/99 RKR 36 Set aborted pend req results to DISCONN */ +/* 10/29/99 GLB 35 Added check for lack of connection */ +/* 09/07/99 MDE 34 Added _mvlu_rpt_disconnect_rcvd_fun */ +/* 07/30/99 JRB 33 Added MVL_GOOSE_SUPPORT define use */ +/* Chg ma_clbind_ctrl from static to global. */ +/* 07/14/99 JRB 32 On assoc ind, save acse_conn_id first. */ +/* 04/13/99 MDE 31 Added '_mvla_initiate_locDe' */ +/* 04/07/99 MDE 30 Fixed mvla_initiate_req return code */ +/* 04/01/99 MDE 29 Eliminated connection handling memory leaks */ +/* 04/01/99 MDE 28 Changes to decode buffer allocation scheme */ +/* 03/18/99 MDE 27 Made # connection limits changable runtime */ +/* 03/08/99 MDE 26 Added ICCP support */ +/* 12/08/98 MDE 25 Cleanup on request control handling */ +/* 12/08/98 MDE 24 Allow user to initiate w/o supplying a */ +/* 'resp_info' buffer. */ +/* 11/16/98 MDE 23 Conclude/Release cleanup, misc cleanup */ +/* 10/22/98 JRB 22 mvl_start_acse init mvl_debug_sel. Other lint*/ +/* 09/21/98 MDE 21 Minor lint cleanup */ +/* 08/25/98 MDE 20 Fixed bind/unbind bug for CLACSE */ +/* 08/14/98 MDE 19 Removed !ALLOW_COMPLEX_NET_EVENTS code */ +/* 08/14/98 MDE 18 Updated 'u_a_data_ind' parameters as reqd */ +/* 07/20/98 JRB 17 If MVL_NUM_CALLED not defined, reject all */ +/* associate indications. */ +/* 07/16/98 MDE 16 Addded 'mvl_dib_entry_to_app_ref' */ +/* 07/06/98 JRB 15 mvl_init_cl_netinfo use new DIB_ENTRY and */ +/* init rem_mac_valid so it sends to ALL-ES. */ +/* 06/18/98 JRB 14 Bind to TP4 and TCP if tp_type=TP_TYPE_TPX. */ +/* 02/10/98 MDE 13 Added 'index' to connection control. */ +/* 12/29/97 JRB 12 Call c?pp_terminate if bind fails. */ +/* 12/22/97 MDE 11 Changed '_mvl_net_service' to report activity */ +/* 09/18/97 MDE 10 Now call 'a_set_msgsize' */ +/* 02/07/97 MDE 09 Changed to use new MMS-EASE opcode defines */ +/* 12/13/96 MDE 08 Now support CLACSE, other enhancements */ +/* 11/18/96 MDE 07 Minor name cleanup, some CLACSE stuff */ +/* 11/15/96 MDE 06 Global variable work */ +/* 11/11/96 MDE 05 Added async functions, other cleanup */ +/* 10/31/96 MDE 04 Added ALLOW_COMPLEX_NET_EVENTS code */ +/* 08/19/96 MDE 03 Now save all remote node's initiate info */ +/* 07/22/96 MDE 02 Changes towards A-Unit-Data support */ +/* 01/21/94 MDE 01 Initial */ +/************************************************************************/ +#include +#include "rdb_client.h" +#include "glbtypes.h" +#include "sysincs.h" +#include "glbsem.h" + +#include "mmsdefs.h" +#include "mms_pvar.h" +#include "mms_vvar.h" +#include "mms_err.h" +#include "mms_pcon.h" +#include "asn1defs.h" +#include "slog.h" +#include "tp4api.h" +#include "mvl_acse.h" +#include "mvl_defs.h" +#include "mvl_log.h" +#include "mloguser.h" +#include "mmsop_en.h" + +#if defined(MAP30_ACSE) +#include "suicacse.h" + +/* To limit the number of Marben stack files in the \mmslite\inc we */ +/* prototype few referenced SUIC functions here. */ +DIB_ENTRY *find_loc_dib_entry (ST_CHAR *name); +DIB_ENTRY *find_dib_entry (ST_CHAR *name); +#elif defined(LEAN_T) +#include "acse2.h" +#endif + +#if defined(_S_TEST_PROBES) +#include "stestprb.h" +#endif + +/************************************************************************/ +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ +/************************************************************************/ + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +/************************************************************************/ + +MVL_MMS_STATISTICS mvl_mms_statistics; + +/************************************************************************/ + +#define NEGIOTIATE_INITIATE_PARAM +#define MVL_MMSOP_RELEASE 512 /* Add a MMS opcode define ... */ + +/************************************************************************/ +/* Global variables - Connection Oriented Only */ +/* The user must fill in a table of DIB entries for local and remote */ +/* nodes of interest. This can be done by the user via the 'init_dirser'*/ +/* function, can be hard coded, etc.. */ + +#if !defined(MAP30_ACSE) /* For MAP30_ACSE use SUIC function instead */ +ST_INT num_loc_dib_entries; +DIB_ENTRY *loc_dib_table; +ST_INT num_rem_dib_entries; +DIB_ENTRY *rem_dib_table; +#endif + +DIB_ENTRY *_mvla_initiate_locDe; +NET_BIND_CTRL *_mvla_initiate_bc; + +/* Our connection controls - we support multiple called and/or calling */ +/* simultanious connections. */ + +MVL_NET_INFO *mvl_calling_conn_ctrl; +MVL_NET_INFO *mvl_called_conn_ctrl; + +/* Other user configurable parameters */ +#ifndef MMS_INIT_EN +#error MMS_INIT_EN not defined. Must include mmsop_en.h +#endif +#if (MMS_INIT_EN & RESP_EN) +INIT_INFO *mvl_init_resp_info; +#endif + +ST_VOID (*u_mvl_disc_ind_fun) (MVL_NET_INFO *cc, ST_INT discType); +ST_VOID (*_mvlu_rpt_disconnect_rcvd_fun)(MVL_NET_INFO *netInfo); + +/************************************************************************/ +/* This variable is set SD_TRUE when the ACSE interface is viable */ +ST_INT mvl_acse_ok; + +/************************************************************************/ +/* These arrays are created in mmsop_en.c */ +extern SD_CONST ST_UCHAR m_param[2]; +extern SD_CONST ST_UCHAR m_service_resp[11]; + +/************************************************************************/ +/************************************************************************/ +/* Bind Control */ + + +NET_BIND_CTRL ma_clbind_ctrl; /* to save clpp_bind info. */ + +/* These variables are used in making some asynchronous ACSE functions */ +/* work in a blocking mode */ +static ST_INT ma_cmd_done; +static ST_INT ma_cmd_rslt; + +/************************************************************************/ + +MVL_CFG_INFO *mvl_cfg_info; + +/************************************************************************/ +/* MMS COMM EVENT CONTROL MANAGEMENT */ + +static MVL_COMM_EVENT *mvl_comm_event_up_head; /* ptr to linked list */ + +/************************************************************************/ +/* MVL_NET_INFO handling for incoming A-Unit Data */ + +#if defined(CLACSE) +ST_INT16 mvl_max_net_info = 10; +static ST_INT16 mvl_net_info_count; +static MVL_NET_INFO *mvl_net_info_avail_head; + +static MVL_NET_INFO *mvl_get_net_info (ST_VOID); +static ST_VOID mvl_free_net_info (MVL_NET_INFO *netInfo); +#endif + +/************************************************************************/ + +typedef struct + { + DBL_LNK l; + ST_LONG u_bind_id; + ST_LONG acse_conn_id; + AARQ_APDU *info; + } MVL_ASSOC_IND; +MVL_ASSOC_IND *mvlAssocIndList; + +ST_BOOLEAN mvl_init_ind_hold; + +/************************************************************************/ + +/* Internal functions */ +static ST_VOID ma_wait_req_done (ST_RET *retOut); +#if (MMS_INIT_EN & RESP_EN) +static MVL_NET_INFO *ma_get_called_conn_ctrl (NET_BIND_CTRL *); +#endif +#if (MMS_INIT_EN & REQ_EN) +static MVL_NET_INFO *ma_get_calling_conn_ctrl (NET_BIND_CTRL *); +#endif +static ST_VOID copp_unbind_sync (ST_LONG copp_bind_id); +static ST_RET ma_bind (NET_BIND_CTRL *bc, ST_BOOLEAN activate); + +static MVL_COMM_EVENT *mvl_get_com_event (ST_VOID); + +/************************************************************************/ +/************************************************************************/ +/* _mvl_net_service */ +/************************************************************************/ + +ST_BOOLEAN _mvl_net_service (MVL_COMM_EVENT **eventOut) + { +ST_BOOLEAN activityFlag; +MVL_ASSOC_IND *mvlAssocInd; + + *eventOut = NULL; + if (mvl_acse_ok != SD_TRUE) + return (SD_FALSE); + + S_LOCK_COMMON_RESOURCES (); + +/* If we have a delayed initiate indication (ICCP Lite redundancy), */ +/* handle it now */ + if (mvlAssocIndList && !mvl_init_ind_hold) + { + mvlAssocInd = list_get_first (&mvlAssocIndList); + u_a_associate_ind (mvlAssocInd->u_bind_id, + mvlAssocInd->acse_conn_id, + mvlAssocInd->info); + chk_free (mvlAssocInd); + S_UNLOCK_COMMON_RESOURCES (); + return (SD_TRUE); + } + +/* May cause the 'acse' user function to be called if something is */ +/* going on that we need to know about. If so, the functions will */ +/* get the event and put them onto the 'mvl_comm_event_up_head' list */ + + activityFlag = copp_event (); + /* Occasionally copp_event gets 2 events, one from TP0 and one from TP4,*/ + /* so they are put on this linked list. "Usually" only one on list. */ + if (mvl_comm_event_up_head) + *eventOut = (MVL_COMM_EVENT *) list_get_first((ST_VOID **) &mvl_comm_event_up_head); + + if (mvl_comm_event_up_head != NULL) + { + /* more events on linked list */ + activityFlag=SD_TRUE; /* force it so user knows to call again */ + } + + S_UNLOCK_COMMON_RESOURCES (); + return (activityFlag); + } + +/************************************************************************/ +/* mvl_get_com_event */ +/************************************************************************/ +/* This function is used to get a MVL_COMM_EVENT control buffer to be */ +/* passed up to the caller of '_mvl_net_service'. */ + +static MVL_COMM_EVENT *mvl_get_com_event (ST_VOID) + { +MVL_COMM_EVENT *commEvent; + + S_LOCK_COMMON_RESOURCES (); + commEvent = (MVL_COMM_EVENT *) M_CALLOC (MSMEM_COM_EVENT, 1, sizeof (MVL_COMM_EVENT)); + if (commEvent == NULL) + { + MVL_LOG_ERR0 ("Error: No MVL_COMM_EVENT available"); + S_UNLOCK_COMMON_RESOURCES (); + return (NULL); + } + + list_add_last((ST_VOID **) &mvl_comm_event_up_head, (ST_VOID *) commEvent); + S_UNLOCK_COMMON_RESOURCES (); + return (commEvent); + } + +/************************************************************************/ +/* _mvl_free_comm_event */ +/************************************************************************/ + +ST_VOID _mvl_free_comm_event (MVL_COMM_EVENT *event) + { + S_LOCK_COMMON_RESOURCES (); + if (event->event_type == MMS_MSG_RCVD) + { + M_FREE (MSMEM_RXPDU, event->u.mms.pdu); + + if (event->u.mms.dec_rslt.data_pres) + { + M_FREE (MSMEM_DEC_OS_INFO, event->u.mms.dec_rslt.data_ptr); + } + } + + M_FREE (MSMEM_COM_EVENT, event); + S_UNLOCK_COMMON_RESOURCES (); + } + +/************************************************************************/ +/* mvl_set_max_msg_size */ +/************************************************************************/ + +ST_VOID mvl_set_max_msg_size (ST_INT max_msg_size) + { + mvl_cfg_info->max_msg_size = max_msg_size; + mmsl_enc_buf_size = max_msg_size + ASN1_MAX_ELEMENT_OVERHEAD; + if (mmsl_enc_buf != NULL) + M_FREE (MSMEM_STARTUP, mmsl_enc_buf); + + mmsl_enc_buf = M_MALLOC (MSMEM_STARTUP, mmsl_enc_buf_size); + } + +/************************************************************************/ +/* mvl_init_aa_obj_ctrl */ +/* Init struct to control AA-Specific object creation (var and nvl). */ +/* Init one MVL_AA_OBJ_CTRL struct for one connection. */ +/* NOTE: if OBSOLETE_AA_OBJ_INIT, this initialization is done by Foundry.*/ +/************************************************************************/ +#if !defined(OBSOLETE_AA_OBJ_INIT) +static MVL_AA_OBJ_CTRL *mvl_init_aa_obj_ctrl () + { +MVL_AA_OBJ_CTRL *aa_obj; + aa_obj = (MVL_AA_OBJ_CTRL *) M_CALLOC (MSMEM_STARTUP, 1, sizeof(MVL_AA_OBJ_CTRL)); + + /* Set up for dynamic creation of AA-Specific Variables. */ + aa_obj->max_num_var_assoc = mvl_max_dyn.aa_vars; + aa_obj->num_var_assoc = 0; + if (aa_obj->max_num_var_assoc) + aa_obj->var_assoc_tbl = (MVL_VAR_ASSOC **) M_CALLOC (MSMEM_STARTUP, aa_obj->max_num_var_assoc, sizeof (MVL_VAR_ASSOC *)); + + /* Set up for dynamic creation of AA-Specific NamedVariableLists (NVL). */ + aa_obj->max_num_nvlist = mvl_max_dyn.aa_nvls; + aa_obj->num_nvlist = 0; + if (aa_obj->max_num_nvlist) + aa_obj->nvlist_tbl = (MVL_NVLIST_CTRL **) M_CALLOC (MSMEM_STARTUP, aa_obj->max_num_nvlist, sizeof (MVL_NVLIST_CTRL *)); + return (aa_obj); + } +#endif /* #if !defined(OBSOLETE_AA_OBJ_INIT) */ + +/************************************************************************/ +/* mvl_start_acse */ +/************************************************************************/ + +ST_INT mvl_start_acse (MVL_CFG_INFO *cfgInfo) + { +NET_BIND_CTRL *bind_ctrl_src; +NET_BIND_CTRL *bind_ctrl_dest; +NET_BIND_CTRL temp_bind_ctrl; +ST_INT mvl_cfg_info_size; +ST_INT ret; +ST_INT i; +ST_INT index = 0; +extern int mmsop_en_version1; + + mmsop_en_version1=0; /* value of this var means nothing, but it */ + /* causes error if you link to older mmsop_en.c */ + + MVL_LOG_ACSE0 ("ACSE: Starting"); + + mvl_debug_sel |= MVLLOG_ERR; /* Always enable error logging. */ + +/* Here we will make the MVL configuration information persistant */ +#if defined(MAP30_ACSE) + if (cfgInfo->use_bind_ctrl != SD_TRUE) +#endif + { /* Create the required bind control structures, if not supplied */ + /* Use memset to start with clean structure */ + memset (&temp_bind_ctrl, 0, sizeof (NET_BIND_CTRL)); /* CRITICAL*/ + strcpy (temp_bind_ctrl.ar_name, cfgInfo->local_ar_name); + temp_bind_ctrl.num_calling = cfgInfo->num_calling; + temp_bind_ctrl.num_called = cfgInfo->num_called; + cfgInfo->bind_ctrl = &temp_bind_ctrl; + cfgInfo->max_bind_ctrl = 1; + cfgInfo->num_bind_ctrl = 1; + } + +/* OK, now copy the MVL configuration info */ + mvl_cfg_info_size = sizeof (MVL_CFG_INFO) + + (cfgInfo->max_bind_ctrl * sizeof (NET_BIND_CTRL)); + mvl_cfg_info = chk_calloc (1, mvl_cfg_info_size); + *mvl_cfg_info = *cfgInfo; + + if (mvl_cfg_info->max_bind_ctrl == 0) + mvl_cfg_info->max_bind_ctrl = mvl_cfg_info->num_bind_ctrl; + + mvl_cfg_info->calling_used = 0; + mvl_cfg_info->called_used = 0; + + mvl_cfg_info->bind_ctrl = (NET_BIND_CTRL *) (mvl_cfg_info + 1); + bind_ctrl_dest = mvl_cfg_info->bind_ctrl; + bind_ctrl_src = cfgInfo->bind_ctrl; + for (i = 0; i < mvl_cfg_info->num_bind_ctrl; ++i) + { + *bind_ctrl_dest = *bind_ctrl_src; + ++bind_ctrl_src; + ++bind_ctrl_dest; + } + +/* Make sure max msg size has been set. */ + if (mvl_cfg_info->max_msg_size == 0) + { + MVL_LOG_ERR0 ("Max MMS message size must be set"); + return (SD_FAILURE); + } + mvl_set_max_msg_size (mvl_cfg_info->max_msg_size); /* save to global & alloc bufs*/ + +/* Initialize function pointers for MMS allocation. */ + m_calloc_os_fun = _mvl_calloc_os; + m_realloc_os_fun = _mvl_realloc_os; + m_free_os_fun = _mvl_free_os; + +#if !(MMS_INIT_EN & REQ_EN) + if (mvl_cfg_info->num_calling != 0) + { + MVL_LOG_ERR0 ("num_calling > 0 is illegal because Initiate.Req is NOT enabled"); + return (SD_FAILURE); + } +#endif +#if !(MMS_INIT_EN & RESP_EN) + if (mvl_cfg_info->num_called != 0) + { + MVL_LOG_ERR0 ("num_called > 0 is illegal because Initiate.Resp is NOT enabled"); + return (SD_FAILURE); + } +#endif + +/* Make sure "num_calling" AND/OR "num_called" has been set. */ + if (mvl_cfg_info->num_calling == 0 && mvl_cfg_info->num_called == 0) + { + MVL_LOG_ERR0 ("num_calling AND num_called both 0, must set at least one." ); + return (SD_FAILURE); + } + +/* Alloc & fill in array of "calling" connection control structures. */ +#if (MMS_INIT_EN & REQ_EN) + if (mvl_cfg_info->num_calling != 0) + mvl_calling_conn_ctrl = M_CALLOC (MSMEM_GEN, mvl_cfg_info->num_calling, sizeof (MVL_NET_INFO)); + for (i = 0; i < mvl_cfg_info->num_calling; ++i) + { + mvl_calling_conn_ctrl[i].index = index++; +#if !defined(OBSOLETE_AA_OBJ_INIT) + mvl_calling_conn_ctrl[i].aa_objs = mvl_init_aa_obj_ctrl (); +#endif /* #if !defined(OBSOLETE_AA_OBJ_INIT) */ + } +#endif + +/* Alloc & fill in array of "called" connection control structures. */ +#if (MMS_INIT_EN & RESP_EN) + if (mvl_cfg_info->num_called != 0) + mvl_called_conn_ctrl = M_CALLOC (MSMEM_GEN, mvl_cfg_info->num_called, sizeof (MVL_NET_INFO)); + for (i = 0; i < mvl_cfg_info->num_called; ++i) + { + mvl_called_conn_ctrl[i].index = index++; +#if !defined(OBSOLETE_AA_OBJ_INIT) + mvl_called_conn_ctrl[i].aa_objs = mvl_init_aa_obj_ctrl (); +#endif /* #if !defined(OBSOLETE_AA_OBJ_INIT) */ + } +#endif + +/* Initialize Connection Oriented OSI Stack. */ + ret = copp_initialize (mvl_cfg_info->num_calling + mvl_cfg_info->num_called, mmsl_enc_buf_size); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR1 ("Error: copp_initialize returned error '0x%x'", ret); + return (ret); + } + +/* Initialize Connectionless OSI Stack. */ +#if defined(CLACSE) + ret = clpp_initialize (); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR1 ("Error: clpp_initialize returned error '0x%x'", ret); + return (ret); + } +#endif + +/* Bind local AR names */ + for (i = 0; i < mvl_cfg_info->num_bind_ctrl; ++i) + { + ret = ma_bind (&mvl_cfg_info->bind_ctrl[i], SD_TRUE); + if (ret != SD_SUCCESS) + return (ret); + } + +/* Binding not necessary for CLACSE. */ + +/* Initialize all mms objects (generated by foundry). */ + if (ret == SD_SUCCESS) + mvl_init_mms_objs (); + + if (ret == SD_SUCCESS) + mvl_acse_ok = SD_TRUE; + else + { + copp_terminate (); +#if defined(CLACSE) + clpp_terminate (); +#endif + } + + MVL_LOG_ACSE1 ("ACSE: Start complete, returning '0x%x'", ret); + mvl_mms_statistics.startTime = sGetMsTime (); + + return (ret); + } + +/************************************************************************/ +/* mvl_end_acse */ +/************************************************************************/ + +ST_INT mvl_end_acse (ST_VOID) + { +NET_BIND_CTRL *bc; +ST_INT i; + + MVL_LOG_ACSE0 ("ACSE: Ending"); + +/* Unbind all */ + for (i = 0; i < mvl_cfg_info->num_bind_ctrl; ++i) + { + bc = &mvl_cfg_info->bind_ctrl[i]; +#ifdef LEAN_T + if (bc->copp_bind_id_tcp) + copp_unbind_sync (bc->copp_bind_id_tcp); + if (bc->copp_bind_id_tp4) + copp_unbind_sync (bc->copp_bind_id_tp4); +#else /* !LEAN_T */ + copp_unbind_sync (bc->copp_bind_id); +#endif /* !LEAN_T */ + } + +/* Shut down the ACSE interface, as well as it's subsystems */ + + copp_terminate (); +#if defined(CLACSE) + clpp_terminate (); +#endif + + MVL_LOG_ACSE0 ("ACSE: Ended"); + return (SD_SUCCESS); + } + +/************************************************************************/ +/* _mvl_send_msg */ +/************************************************************************/ + +ST_INT _mvl_send_msg (ST_UCHAR *pdu, ST_INT pdu_len, MVL_NET_INFO *net_info) + { +ST_INT ret; + +/* See if we are supposed to log ACSE data for this connection */ + if (mvl_conn_filtered_logging == SD_FALSE || net_info->log_enable) + { + MVL_LOG_ACSEDATA2 ("ACSE: Sending %d bytes on MVL_NET_INFO 0x%08lx", + pdu_len, net_info); + MVL_LOG_ACSEDATAH (pdu_len, pdu); + } + + ret = SD_FAILURE; + +#if (MMS_INIT_EN != REQ_RESP_DIS) + if (net_info->conn_active == SD_FALSE) + { /* no connection */ + ret = MVL_ERR_CNF_DISCONNECTED; /* more precise error code */ + MVL_LOG_NERR1 ("ACSE: no connection '0x%x'", ret); + } + else + { /* valid connection */ + S_LOCK_COMMON_RESOURCES (); + ret = a_data_req (net_info->acse_conn_id, pdu_len, pdu); + S_UNLOCK_COMMON_RESOURCES (); + if (ret != SD_SUCCESS) + { + MVL_LOG_NERR1 ("ACSE: a_data_req error '0x%x'", ret); + } + } +#endif + return (ret); + } + +/************************************************************************/ +/************************************************************************/ +/* DIRECTORY SERVICES FUNCTIONS */ +/************************************************************************/ +/************************************************************************/ +/* find_loc_dib_entry */ +/************************************************************************/ +#if !defined(MAP30_ACSE) /* For MAP30_ACSE use SUIC function instead */ +DIB_ENTRY *find_loc_dib_entry (ST_CHAR *name) + { +ST_INT i; +DIB_ENTRY *de; + + for (i = 0; i < num_loc_dib_entries; i++) + { + de = &loc_dib_table[i]; + if (!strcmp (de->name, name)) + return (de); + } + return (NULL); + } +#endif /* !defined(MAP30_ACSE) */ + +/************************************************************************/ +/* find_rem_dib_entry */ +/************************************************************************/ + +DIB_ENTRY *find_rem_dib_entry (ST_CHAR *name) + { +#if !defined(MAP30_ACSE) +ST_INT i; +#endif +DIB_ENTRY *de; + +#if defined(MAP30_ACSE) + /* For Marben stack use SUIC function */ + de = find_dib_entry (name); /* searches first loc then rem tables */ + return (de); +#else /* !defined(MAP30_ACSE) */ + for (i = 0; i < num_rem_dib_entries; i++) + { + de = &rem_dib_table[i]; + if (!strcmp (de->name, name)) + return (de); + } + return (NULL); +#endif /* !defined(MAP30_ACSE) */ + } + +/************************************************************************/ +/* mvl_dib_entry_to_app_ref */ +/************************************************************************/ + +ST_VOID mvl_dib_entry_to_app_ref (DIB_ENTRY *de, APP_REF *appRef) + { +ST_INT i; + + appRef->form = APP_REF_FORM2; + appRef->ap_title_pres = de->AP_title_pres; + if (appRef->ap_title_pres == SD_TRUE) + { + appRef->ap_title.form_2.num_comps = de->AP_title.num_comps; + for (i = 0; i < de->AP_title.num_comps; ++i) + appRef->ap_title.form_2.comps[i] = de->AP_title.comps[i]; + } + appRef->ap_invoke_pres = de->AP_inv_id_pres; + appRef->ap_invoke = de->AP_invoke_id; + appRef->ae_qual_pres = de->AE_qual_pres; + appRef->ae_qual.form_2 = de->AE_qual; + appRef->ae_invoke_pres = de->AE_inv_id_pres; + appRef->ae_invoke = de->AE_invoke_id; + } + +/************************************************************************/ +/************************************************************************/ +#if (MMS_INIT_EN != REQ_RESP_DIS) /* COACSE SPECIFIC FUNCTIONS */ +/************************************************************************/ + +ST_RET mvla_set_init_ar (ST_CHAR *ar_name) + { +NET_BIND_CTRL *bc; +ST_INT i; + +/* See if user want's to use the default AR */ + if (ar_name == NULL) + { + _mvla_initiate_bc = NULL; + return (SD_SUCCESS); + } + + for (i = 0; i < mvl_cfg_info->num_bind_ctrl; ++i) + { + bc = &mvl_cfg_info->bind_ctrl[i]; + if (!strcmp (ar_name, bc->ar_name)) + { + _mvla_initiate_bc = bc; + return (SD_SUCCESS); + } + } + return (SD_FAILURE); + } + +#if (MMS_INIT_EN & REQ_EN) + +/************************************************************************/ +/* mvl_initiate_req */ +/************************************************************************/ + +ST_INT mvl_initiate_req (ST_CHAR *remAr, + INIT_INFO *req_info, + INIT_INFO *resp_info, + MVL_NET_INFO **net_info_out) + { +MVL_REQ_PEND *req; +ST_INT rc; + + if (_mvl_comm_serve_active == SD_TRUE) + { + MVL_LOG_NERR0 ("Error: mvl_comm_serv active"); + return (SD_FAILURE); + } + + rc = mvla_initiate_req (remAr, req_info, resp_info, net_info_out, &req); + if (rc != SD_SUCCESS) + return (rc); + + rc = mvl_wait_req_done (req); + if (rc != SD_SUCCESS) + { + MVL_LOG_NERR0 ("ACSE: Initiate failed"); + } + + mvl_free_req_ctrl (req); /* we are done with this req ctrl */ + return (rc); + } + +/************************************************************************/ +/* mvla_initiate_req */ +/************************************************************************/ + +ST_INT mvla_initiate_req (ST_CHAR *remAr, + INIT_INFO *req_info, + INIT_INFO *resp_info, + MVL_NET_INFO **net_info_out, + MVL_REQ_PEND **req_out) + { +ST_INT rc; + + rc = mvla_initiate_req_ex (remAr, req_info, resp_info, net_info_out, + req_out, NULL, NULL); + + return rc; + } + +/************************************************************************/ +/* mvla_initiate_req_ex */ +/************************************************************************/ + + +ST_INT mvla_initiate_req_ex (ST_CHAR *remAr, + INIT_INFO *req_info, + INIT_INFO *resp_info, + MVL_NET_INFO **net_info_out, + MVL_REQ_PEND **req_out, + ACSE_AUTH_INFO *auth_info, + S_SEC_ENCRYPT_CTRL *encrypt_info) + { +ST_INT rc; +MVL_NET_INFO *cc; +DIB_ENTRY *locDe; +DIB_ENTRY *remDe; +AARQ_APDU aarq_apdu; +ST_LONG acse_conn_id; +MVL_REQ_PEND *req; + + *req_out = NULL; /* make sure it's initialized */ + + MVL_LOG_ACSE1 ("ACSE: Initiate Request to '%s'", remAr); + + /* Get a calling connection control structure */ + + cc = ma_get_calling_conn_ctrl (_mvla_initiate_bc); + if (!cc) + { + MVL_LOG_ERR0 ("Error - Could not get calling MVL_NET_INFO"); + return (MVL_ERR_NO_CONN_CTRL); + } + MVL_LOG_CACSE1 ("Using MVL_NET_INFO %08lx", cc); + + req = _mvl_get_req_ctrl (cc, MMSOP_INITIATE); + if (!req) + { + cc->in_use = SD_FALSE; + return (MVL_ERR_NO_REQ_CTRL); + } + *req_out = req; + req->invoke_id = -1; + + rc = mpl_init (req_info); + if (rc == SD_SUCCESS) + { + /* We can log here if so desired */ + /* if ((mms_debug_sel & MMS_LOG_REQ) && ml_log_req_info_fun != NULL) + (*ml_log_req_info_fun) (0, MMSOP_INITIATE, req_info);*/ + + /* Save the output pointer in the MMS request control element */ + req->u.init.resp_info = resp_info; + + /* Save our initiate request information ... */ + memcpy (&cc->locl_init_info, req_info, sizeof (INIT_INFO)); + + /* Retrieve the DIB_ENTRY's for local and remote. These are used to set */ + /* the AARQ_APDU information */ + if (_mvla_initiate_locDe != NULL) + locDe = _mvla_initiate_locDe; + else + locDe = cc->bind_ctrl->de; + + remDe = find_rem_dib_entry (remAr); + if (remDe) + { + /* Now set up all AARQ_APDU information based on DIB_ENTRY information */ + +#if !defined(MAP30_ACSE) /* most info not needed for Lite over Marben stack */ + /* AP Context is MMS */ + aarq_apdu.ASO_context_name_pres = SD_TRUE; + aarq_apdu.ASO_context_name.num_comps = 5; + aarq_apdu.ASO_context_name.comps[0] = 1; + aarq_apdu.ASO_context_name.comps[1] = 0; + aarq_apdu.ASO_context_name.comps[2] = 9506; + aarq_apdu.ASO_context_name.comps[3] = 2; + aarq_apdu.ASO_context_name.comps[4] = 3; + + /* Calling AE Title */ + aarq_apdu.calling_ae_title.AP_title_pres = locDe->AP_title_pres; + memcpy (&aarq_apdu.calling_ae_title.AP_title, + &locDe->AP_title, + sizeof (MMS_OBJ_ID)); + + aarq_apdu.calling_ae_title.AE_qual_pres = locDe->AE_qual_pres; + aarq_apdu.calling_ae_title.AE_qual = locDe->AE_qual; + aarq_apdu.calling_ae_title.AP_inv_id_pres = locDe->AP_inv_id_pres; + aarq_apdu.calling_ae_title.AP_inv_id = locDe->AP_invoke_id; + aarq_apdu.calling_ae_title.AE_qual_pres = locDe->AE_qual_pres; + aarq_apdu.calling_ae_title.AE_qual = locDe->AE_qual; + aarq_apdu.calling_ae_title.AE_inv_id_pres = locDe->AE_inv_id_pres; + aarq_apdu.calling_ae_title.AE_inv_id = locDe->AE_invoke_id; + + /* Called AE Title */ + aarq_apdu.called_ae_title.AP_title_pres = remDe->AP_title_pres; + memcpy (&aarq_apdu.called_ae_title.AP_title, + &remDe->AP_title, + sizeof (MMS_OBJ_ID)); + + aarq_apdu.called_ae_title.AE_qual_pres = remDe->AE_qual_pres; + aarq_apdu.called_ae_title.AE_qual = remDe->AE_qual; + aarq_apdu.called_ae_title.AP_inv_id_pres = remDe->AP_inv_id_pres; + aarq_apdu.called_ae_title.AP_inv_id = remDe->AP_invoke_id; + aarq_apdu.called_ae_title.AE_qual_pres = remDe->AE_qual_pres; + aarq_apdu.called_ae_title.AE_qual = remDe->AE_qual; + aarq_apdu.called_ae_title.AE_inv_id_pres = remDe->AE_inv_id_pres; + aarq_apdu.called_ae_title.AE_inv_id = remDe->AE_invoke_id; +#endif /* !defined(MAP30_ACSE) */ + +#ifdef REDUCED_STACK + /* For Reduced Stack, the presentation address consists only of the */ + /* ADLC address. */ + aarq_apdu.called_paddr.adlcAddr = remDe->adlcAddr; +#endif + +#ifdef LEAN_T + /* For Trim 7, the presentation address has all the parts */ + memcpy (&aarq_apdu.called_paddr, &remDe->pres_addr, sizeof (PRES_ADDR)); +#endif + + /* ACSE Authentication */ + if(auth_info != NULL) + memcpy (&aarq_apdu.auth_info, auth_info, sizeof (ACSE_AUTH_INFO)); + else + aarq_apdu.auth_info.auth_pres = SD_FALSE; + /* copy encryption info */ + if (encrypt_info != NULL) + memcpy (&aarq_apdu.encrypt_ctrl, encrypt_info, sizeof (S_SEC_ENCRYPT_CTRL)); + else + aarq_apdu.encrypt_ctrl.encryptMode = S_SEC_ENCRYPT_NONE; + + /* User Data */ + aarq_apdu.user_info.ptr = mmsl_msg_start; + aarq_apdu.user_info.len = mmsl_msg_len; + + MVL_LOG_ACSEDATAH (mmsl_msg_len, mmsl_msg_start); + + /* Send the associate request */ +#if defined(MAP30_ACSE) + acse_conn_id = a_associate_reqm (cc->bind_ctrl->copp_bind_id, + (ST_LONG) cc, &aarq_apdu, + cc->bind_ctrl->ar_name, remAr); +#elif defined(LEAN_T) + if (remDe->pres_addr.tp_type == TP_TYPE_TCP) + acse_conn_id = a_associate_req (cc->bind_ctrl->copp_bind_id_tcp, (ST_LONG) cc, &aarq_apdu); + else + acse_conn_id = a_associate_req (cc->bind_ctrl->copp_bind_id_tp4, (ST_LONG) cc, &aarq_apdu); +#else + acse_conn_id = a_associate_req (cc->bind_ctrl->copp_bind_id, (ST_LONG) cc, &aarq_apdu); +#endif + if (!acse_conn_id) + { + MVL_LOG_NERR0 ("ACSE: a_associate_req failed"); + rc = MVL_ERR_ASSOC_REQ; + } + else + ++mvl_mms_statistics.callingConn; + } + else + { + MVL_LOG_NERR1 ("ACSE: Remote name '%s' not found", remAr); + rc = MVLE_REMOTE_NAME; + } + } + else + { + MVL_LOG_NERR1 ("ACSE: mpl_init error '0x%x'", rc); + } + + if (rc == SD_SUCCESS) + { + *net_info_out = cc; + cc->acse_conn_id = acse_conn_id; + } + else + { + cc->in_use = SD_FALSE; + mvl_free_req_ctrl (req); + *req_out = NULL; /* So user CANNOT free it too. */ + } + +/* All is good, return the connection control too */ + return (rc); + } +/************************************************************************/ +#endif /* #if (MMS_INIT_EN & REQ_EN) */ +/************************************************************************/ + +/************************************************************************/ +/* mvl_abort_req */ +/* mvl_abort_req_ex */ +/************************************************************************/ + +ST_RET mvl_abort_req (MVL_NET_INFO *cc) + { + return (mvl_abort_req_ex (cc, SD_FALSE, 0)); + } + + +ST_RET mvl_abort_req_ex (MVL_NET_INFO *cc, + ST_BOOLEAN diagnostic_pres, + ST_ACSE_AUTH diagnostic) + { +ABRT_APDU abrtinfo; +ST_RET ret; + + MVL_LOG_ACSE1 ("ACSE: sending abort for MVL_NET_INFO %08lx", cc); + + abrtinfo.source = 0; /* user */ + abrtinfo.diagnostic_pres = diagnostic_pres; + abrtinfo.diagnostic = diagnostic; + abrtinfo.user_info.len = 0; + + ret = a_abort_req (cc->acse_conn_id, &abrtinfo); + if (ret == SD_SUCCESS) + { + ++mvl_mms_statistics.localAbort; + cc->in_use = SD_FALSE; + cc->conn_active = SD_FALSE; + if (_mvlu_rpt_disconnect_rcvd_fun != NULL) + (*_mvlu_rpt_disconnect_rcvd_fun)(cc); + _mvl_set_net_req_done (NULL, cc, MVL_ERR_CNF_DISCONNECTED); + } + else + { + MVL_LOG_NERR1 ("ACSE: Abort error '0x%x'", ret); + echo_warn1("ACSE: Abort error '0x%x'\n", ret); + } + return (ret); + } + +/************************************************************************/ +/* mvl_release_req */ +/* mvla_release_req */ +/************************************************************************/ + +ST_INT mvl_release_req (MVL_NET_INFO *cc) + { + MVL_LOG_ERR0 ("ACSE: Using obsolete function 'mvl_release_req'"); + return (SD_FAILURE); + } + +ST_INT mvla_release_req (MVL_NET_INFO *cc, MVL_REQ_PEND **req_out) + { + MVL_LOG_ERR0 ("ACSE: Using obsolete function 'mvla_release_req'"); + return (SD_FAILURE); + } + +/************************************************************************/ +/* _mvla_release */ +/************************************************************************/ +/* Called from conclude confirm */ + +ST_VOID _mvl_release (MVL_REQ_PEND *req) + { +RLRQ_APDU rlinfo; +ST_INT ret; +MVL_NET_INFO *net_info; + + net_info = req->net_info; + req->op = MVL_MMSOP_RELEASE; /* Change the opcode in the req ctrl */ + + MVL_LOG_ACSE1 ("ACSE: sending release for MVL_NET_INFO %08lx", net_info); + + rlinfo.reason_pres = SD_TRUE; + rlinfo.reason = 1; + rlinfo.user_info.len = 0; + ret = a_release_req (net_info->acse_conn_id, &rlinfo); + if (ret != SD_SUCCESS) + { + MVL_LOG_NERR1 ("ACSE: Release error '0x%x'", ret); + _mvl_set_req_done (req, SD_FAILURE); + } + else + ++mvl_mms_statistics.clientConcl; + } + +/************************************************************************/ +/************************************************************************/ +/* mvl_add_bind_ctrl */ +/************************************************************************/ + +ST_RET mvl_add_bind_ctrl (NET_BIND_CTRL *bc) + { +NET_BIND_CTRL *mvlBc; +ST_BOOLEAN activate; +ST_INT i; +ST_RET rc; + +/* First let's check to see if we have room for one more */ + if (mvl_cfg_info->num_bind_ctrl >= mvl_cfg_info->max_bind_ctrl) + { + MVL_LOG_NERR0 ("Error: no availble bind control"); + return (SD_FAILURE); + } + +/* Let's see if this local AR has already been activated */ + activate = SD_TRUE; + for (i = 0; i < mvl_cfg_info->num_bind_ctrl; ++i) + { + if (!strcmp (mvl_cfg_info->bind_ctrl[i].ar_name, bc->ar_name)) + { + activate = SD_FALSE; + break; + } + } + +/* OK, now we can copy the bind control information */ + + mvlBc = &mvl_cfg_info->bind_ctrl[mvl_cfg_info->num_bind_ctrl]; + *mvlBc = *bc; + ++mvl_cfg_info->num_bind_ctrl; + + rc = ma_bind (mvlBc, activate); + return (rc); + } + +/************************************************************************/ +/* mvl_bind */ +/************************************************************************/ + +static ST_RET ma_bind (NET_BIND_CTRL *bc, ST_BOOLEAN activate) + { +#if !defined(MAP30_ACSE) +DIB_ENTRY *de; +PRES_ADDR loc_pres_addr; +#endif +ST_INT ret; +ST_INT numConn; +MVL_NET_INFO *ni; +ST_INT j; + + MVL_LOG_ACSE1 ("ACSE: binding local name '%s'", bc->ar_name); + +#if !defined(MAP30_ACSE) +/* Locate the local DIB entry for this name, so we can find the addr */ + de = find_loc_dib_entry (bc->ar_name); + if (!de) + { + MVL_LOG_ERR1 ("Error: Local AR name '%s' not found", bc->ar_name); + return (MVLE_LOCAL_NAME); + } + bc->de = de; +#endif + + if (((bc->num_calling + mvl_cfg_info->calling_used) > mvl_cfg_info->num_calling) || + ((bc->num_called + mvl_cfg_info->called_used) > mvl_cfg_info->num_called)) + { + MVL_LOG_ERR0 ("Error: not enough connections"); + return (MVLE_NUM_CONNECTIONS); + } + numConn = bc->num_calling + bc->num_called; + +#ifdef REDUCED_STACK +/* For Reduced Stack, the presentation address consists only of the */ +/* ADLC address. */ + loc_pres_addr.adlcAddr = de->adlcAddr; +/* We make the binds synchronous */ + ma_cmd_done = SD_FALSE; + ma_cmd_rslt = REQ_INCOMPLETE; + ret = copp_bind ((ST_LONG) bc, &loc_pres_addr, SD_FALSE, numConn); + ma_wait_req_done (&ret); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR2 ("Error: copp_bind (TCP) of AR '%s' returned '0x%x'", + bc->ar_name, ret); + return (ret); + } +#endif + +#ifdef LEAN_T +/* For Trim 7, the presentation address has all the parts */ + memcpy (&loc_pres_addr, &de->pres_addr, sizeof (PRES_ADDR)); + if (de->pres_addr.tp_type == TP_TYPE_TPX) + { /* do 2 binds */ + /* Bind for TP4 (overwrite the "tp_type" in loc_pres_addr). */ + bc->tp_type = loc_pres_addr.tp_type = TP_TYPE_TP4; + ma_cmd_done = SD_FALSE; + ma_cmd_rslt = REQ_INCOMPLETE; + ret = copp_bind ((ST_LONG) bc, &loc_pres_addr, SD_FALSE, numConn); + ma_wait_req_done (&ret); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR2 ("Error: copp_bind (TP4) of AR '%s' returned '0x%x'", + bc->ar_name, ret); + return (ret); + } + + /* Bind for TCP (overwrite the "tp_type" in loc_pres_addr). */ + bc->tp_type = loc_pres_addr.tp_type = TP_TYPE_TCP; + ret = copp_bind ((ST_LONG) bc, &loc_pres_addr, SD_FALSE, numConn); + ma_wait_req_done (&ret); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR2 ("Error: copp_bind (TCP) of AR '%s' returned '0x%x'", + bc->ar_name, ret); + return (ret); + } + } + else /* Not TPX */ + { + bc->tp_type = loc_pres_addr.tp_type; + ma_cmd_done = SD_FALSE; + ma_cmd_rslt = REQ_INCOMPLETE; + ret = copp_bind ((ST_LONG) bc, &loc_pres_addr, SD_FALSE, numConn); + ma_wait_req_done (&ret); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR2 ("Error: copp_bind of AR '%s' returned '0x%x'", + bc->ar_name, ret); + return (ret); + } + } +#endif + +#if defined(MAP30_ACSE) + ma_cmd_done = SD_FALSE; + ma_cmd_rslt = REQ_INCOMPLETE; + ret = _copp_bind ((ST_LONG) bc, bc->ar_name, bc->num_calling, bc->num_called, activate); + ma_wait_req_done (&ret); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR2 ("Error: copp_bind of AR '%s' failed '0x%x'", + bc->ar_name, ret); + return (ret); + } +#endif /* defined(MAP30_ACSE) */ + + MVL_LOG_ACSE0 ("ACSE: bind OK"); + + +/* OK, now attach the bind controls to the MVL_NET_INFO */ + ni = mvl_called_conn_ctrl + mvl_cfg_info->called_used; + for (j = 0; j < bc->num_called; ++j, ++ni) + ni->bind_ctrl = bc; + + ni = mvl_calling_conn_ctrl + mvl_cfg_info->calling_used; + for (j = 0; j < bc->num_calling; ++j, ++ni) + ni->bind_ctrl = bc; + + mvl_cfg_info->calling_used += bc->num_calling; + mvl_cfg_info->called_used += bc->num_called; + return (ret); + } + +/************************************************************************/ +/* copp_unbind_sync */ +/************************************************************************/ + +static ST_VOID copp_unbind_sync (ST_LONG copp_bind_id) + { +ST_RET ret; + + ma_cmd_done = SD_FALSE; + ma_cmd_rslt = REQ_INCOMPLETE; + ret = copp_unbind (copp_bind_id); + if (ret != SD_SUCCESS) + { + MVL_LOG_ERR1 ("Error: unbind result '0x%x'", ret); + } + else /* Now just wait for the 'confirm' function to be called */ + ma_wait_req_done (&ret); + } + +/************************************************************************/ +/* COACSE USER FUNCTIONS */ +/************************************************************************/ +/************************************************************************/ +/* u_copp_bind_cnf */ +/************************************************************************/ + +ST_VOID u_copp_bind_cnf (ST_LONG user_bind_id, ST_LONG copp_bind_id, ST_INT result) + { +NET_BIND_CTRL *bc; + +/* Save the acse interface's bind ID for future use */ + bc = (NET_BIND_CTRL *) user_bind_id; +#ifdef LEAN_T + if (bc->tp_type == TP_TYPE_TP4) + bc->copp_bind_id_tp4 = copp_bind_id; + else + bc->copp_bind_id_tcp = copp_bind_id; +#else + bc->copp_bind_id = copp_bind_id; +#endif + +/* Allow sync binds to complete */ + ma_cmd_done = SD_TRUE; + ma_cmd_rslt = result; + } + +/************************************************************************/ +/* u_copp_unbind_cnf */ +/************************************************************************/ + +ST_VOID u_copp_unbind_cnf (ST_LONG user_bind_id) + { +/* Allow the request function to complete */ + ma_cmd_done = SD_TRUE; + ma_cmd_rslt = SD_SUCCESS; + } + +/************************************************************************/ +/* u_a_associate_ind */ +/************************************************************************/ + +ST_VOID u_a_associate_ind (ST_LONG u_bind_id, ST_LONG acse_conn_id, + AARQ_APDU *info) + { +#if (MMS_INIT_EN & RESP_EN) + +MMSDEC_INFO rslt; +INIT_INFO *init_req; +INIT_INFO init_resp; +MVL_NET_INFO *cc; +#if !defined(ICCP_LITE) +ST_ACSE_AUTH auth_ret; +#endif +ST_INT ret; +AARE_APDU reinfo; +ST_INT accept; +ST_BOOLEAN free_dec_info; +MVL_ASSOC_IND *mvlAssocInd; +AARQ_APDU *reqinfo; +ST_UCHAR *user_info_buf; + + if (mvl_init_ind_hold) + { + /* Can't rely on this data being persistent */ + /* Allocate buffer big enough for the control structure, */ + /* the AARQ info, and the user data */ + mvlAssocInd = chk_malloc (sizeof (MVL_ASSOC_IND) + + sizeof (AARQ_APDU) + + info->user_info.len); + mvlAssocInd->u_bind_id = u_bind_id; + mvlAssocInd->acse_conn_id = acse_conn_id; + + /* Copy the AARQ data */ + reqinfo = (AARQ_APDU *) (mvlAssocInd + 1); + *reqinfo = *info; + mvlAssocInd->info = reqinfo; + + /* Copy the user data, set the pointer to it */ + user_info_buf = (ST_UCHAR *) (reqinfo + 1); + reqinfo->user_info.ptr = user_info_buf; + memcpy (user_info_buf, info->user_info.ptr, info->user_info.len); + + list_add_last (&mvlAssocIndList, mvlAssocInd); + return; + } + +#if defined(_S_TEST_PROBES) + if (_sTestProbeEnabled(_MI_TEST_INITIATE_IND_NO_RESPOND)) + { + echo_warn ("TEST: Initiate indication, do not respond"); + return; + } +#endif + + ++mvl_mms_statistics.calledConn; + + MVL_LOG_ACSE0 ("ACSE: Associate Indication received"); + MVL_LOG_ACSEDATAH (info->user_info.len, info->user_info.ptr); + + free_dec_info = SD_FALSE; + +/* Assume the worst ... */ + accept = SD_FALSE; + reinfo.user_info.len = 0; + reinfo.auth_info.auth_pres = SD_FALSE; + +/* Get a 'called' connection control structure, if one is available */ + cc = ma_get_called_conn_ctrl ((NET_BIND_CTRL *) u_bind_id); + if (cc) + { + MVL_LOG_CACSE1 ("Using MVL_NET_INFO %08lx", cc); + + /* Copy the whole AARQ Info struct, for the user to see */ + memcpy (&cc->ass_ind_info, info, sizeof (AARQ_APDU)); + + /* IMPORTANT: Save the ACSE connection ID before calling user funtions.*/ + cc->acse_conn_id = acse_conn_id; + + /* We need to parse the MMS Initiate PDU */ + free_dec_info = SD_TRUE; + _ms_mms_decode (info->user_info.ptr, info->user_info.len, &rslt); + if (rslt.err_code == NO_DECODE_ERR && rslt.type == MMSINITREQ) + { + init_req = (INIT_INFO *) rslt.data_ptr; + init_req->mms_p_context_pres = SD_TRUE; + + /* We can log here if so desired */ + if ((mms_debug_sel & MMS_LOG_IND) && ml_log_ind_info_fun != NULL) + (*ml_log_ind_info_fun) (0, MMSOP_INITIATE, init_req); + +/* OK, we handle telling the user differently depending on whether this */ +/* is ICCP Lite, and whether ACSE Authentication is in use or not */ +#ifdef ICCP_LITE + ret = mi_connect_ind_fun (cc, init_req, &reinfo.auth_info); +#else + /* Let the user have a look to see if they want to accept */ + auth_ret = u_mvl_connect_ind_ex(cc, init_req, + &cc->ass_ind_info.auth_info, /* partner authentication */ + &reinfo.auth_info); /* ret rsp authentication */ + /* User did not like something about the authentication */ + if (auth_ret != ACSE_AUTH_SUCCESS) + { + MVL_LOG_ACSE1 ("ACSE: ACSE Authentication failure. Reason: %d", auth_ret); + mvl_abort_req_ex (cc, SD_TRUE, auth_ret); + return; + } + ret = SD_SUCCESS; /* User is OK with it */ +#endif /* ICCP_LITE */ + + if (ret == SD_SUCCESS) + { + /* Build an initiate response PDU, negiotiating the calling init */ + /* parameters vs. what we support */ + +#ifdef NEGIOTIATE_INITIATE_PARAM + /* Start with the default initiate response info */ + memcpy (&init_resp, mvl_init_resp_info, sizeof (INIT_INFO)); + if (init_req->version < init_resp.version)/* thiers is lower */ + init_resp.version = init_req->version; /* accept lower version */ + if (init_req->max_segsize_pres) + { + if (init_req->max_segsize < init_resp.max_segsize) + init_resp.max_segsize = init_req->max_segsize; + } + if (init_req->maxreq_calling < init_resp.maxreq_calling) + init_resp.maxreq_calling = init_req->maxreq_calling; + if (init_req->maxreq_called < init_resp.maxreq_called) + init_resp.maxreq_called = init_req->maxreq_called; + if (init_req->max_nest_pres) + { + if (init_req->max_nest < init_resp.max_nest) + init_resp.max_nest = init_req->max_nest; + } + /* These 'supported' bitstring parameters are set up in mmsop_en.c */ + memcpy (init_resp.serv_supp, m_service_resp, 11); + init_resp.param_supp[0] = m_param[0] & init_req->param_supp[0]; + init_resp.param_supp[1] = m_param[1] & init_req->param_supp[1]; +#else + /* Just send back what the user wants to send */ + memcpy (&init_resp, mvl_init_resp_info, sizeof (INIT_INFO)); +#endif + + ret = mpl_init_resp (&init_resp); + if (ret == SD_SUCCESS) + { + /* We can log here if so desired */ + if ((mms_debug_sel & MMS_LOG_RESP) && ml_log_resp_info_fun != NULL) + (*ml_log_resp_info_fun) (0, MMSOP_INITIATE, &init_resp); + + accept = SD_TRUE; + + cc->conn_active = SD_TRUE; + + /* Save the remote node's initiate information */ + memcpy (&cc->rem_init_info, init_req, sizeof (INIT_INFO)); + memcpy (&cc->locl_init_info, &init_resp, sizeof (INIT_INFO)); + cc->max_pdu_size = (ST_INT) init_resp.max_segsize; + /* NOTE: maxreq_calling = num of outstanding indications */ + /* allowed at the calling app (similar for maxreq_called). */ + cc->maxpend_req = init_resp.maxreq_calling; + cc->maxpend_ind = init_resp.maxreq_called; + cc->numpend_req = 0; + cc->numpend_ind = 0; + } + } + + if (ret != SD_SUCCESS) + { + MVL_LOG_NERR0 ("ACSE: User does not want connection"); + ret = mpl_init_err (8, 0); + cc->in_use = SD_FALSE; + } + + if (ret == SD_SUCCESS) + { + reinfo.user_info.len = mmsl_msg_len; + reinfo.user_info.ptr = mmsl_msg_start; + } + } + else + { + MVL_LOG_NERR0 ("ACSE: Initiate indication PDU parse error"); + free_dec_info = SD_FALSE; + cc->in_use = SD_FALSE; + } + } + else + { + MVL_LOG_ERR0 ("Error - Could not get called MVL_NET_INFO"); + } + +/* Initiate Response (or error) PDU is built, or len set to 0. */ +/* Set the remaining ACSE parameters and send the response */ + +/* Use the calling context as the responding, to be friendly */ + reinfo.ASO_context_name_pres = info->ASO_context_name_pres; + memcpy (&reinfo.ASO_context_name, &info->ASO_context_name, + sizeof (MMS_OBJ_ID)); + +/* For now, just reflect the ACSE indication information */ +/* Note that it may (or may not) be more appropriate to use the 'local' */ +/* DIB_ENTRY info for this purpose. */ + memcpy (&reinfo.responding_ae_title, &info->called_ae_title, + sizeof (AE_TITLE)); + + + if (accept) + { + MVL_LOG_ACSE0 ("Accepting the connection"); + reinfo.result = 0; /* ACCEPT */ + reinfo.result_source_diag_pres = SD_FALSE; + } + else + { + MVL_LOG_ACSE0 ("Rejecting the connection"); + reinfo.result = 1; /* REJECT */ + reinfo.result_source_diag_pres = SD_TRUE; + reinfo.result_source = 1; + reinfo.result_diag = 9; + } + + /* Send ACSE response */ + MVL_LOG_ACSEDATAH (reinfo.user_info.len, reinfo.user_info.ptr); + ret = a_associate_rsp (acse_conn_id, (ST_LONG) cc, &reinfo); + if (ret != SD_SUCCESS) + { + MVL_LOG_NERR1 ("ACSE: a_associate_rsp error '0x%x", ret); + if (cc != NULL) + cc->in_use = SD_FALSE; + ++mvl_mms_statistics.calledConnFail; + } + else + ++mvl_mms_statistics.calledConnOK; + + + if (free_dec_info == SD_TRUE) + M_FREE (MSMEM_DEC_OS_INFO, _mms_dec_info); + +#else /* !(MMS_INIT_EN & RESP_EN) */ + +AARE_APDU reinfo; +ST_LONG user_conn_id; +ST_INT ret; + + ++mvl_mms_statistics.calledConn; + +/* Incoming connections not supported, so Reject the association. */ + MVL_LOG_ACSE0 ("ACSE: Associate Indication received. Rejecting."); + +/* Just use the ASO-context from the request in the response. */ + reinfo.ASO_context_name_pres = info->ASO_context_name_pres; + memcpy (&reinfo.ASO_context_name, &info->ASO_context_name, + sizeof (MMS_OBJ_ID)); + +/* Just use the called AE-Title as the responding AE-Title. */ + memcpy (&reinfo.responding_ae_title, &info->called_ae_title, + sizeof (AE_TITLE)); + + /* Reject */ + reinfo.result = 1; /* Rejected-permanent */ + reinfo.result_source_diag_pres = SD_TRUE; + reinfo.result_source = 1; /* Source = user. */ + reinfo.result_diag = 1; /* no-reason-given */ + /* No User Information */ + reinfo.user_info.len = 0; + reinfo.user_info.ptr = NULL; + reinfo.auth_info.auth_pres = SD_FALSE; + + user_conn_id = 0; /* id doesn't matter because rejecting */ + if ((ret = a_associate_rsp (acse_conn_id, user_conn_id, &reinfo))!=SD_SUCCESS) + { + MVL_LOG_ERR1 ("Error sending a_associate_rsp. Error = %d", ret); + } + ++mvl_mms_statistics.calledConnFail; +#endif /* !(MMS_INIT_EN & RESP_EN) */ + } + + +/************************************************************************/ +/* u_a_associate_cnf */ +/************************************************************************/ + +ST_VOID u_a_associate_cnf (ST_LONG acse_conn_id, ST_LONG user_conn_id, + AARE_APDU *info) + { +#if (MMS_INIT_EN & REQ_EN) +MMSDEC_INFO rslt; +MVL_NET_INFO *cc; +INIT_INFO *init_resp; +MVL_REQ_PEND *req; +ST_BOOLEAN free_dec_info; +ST_RET result; +ST_ACSE_AUTH auth_ret; + +/* Need to save off the ACSE interface's connection ID for future use */ + cc = (MVL_NET_INFO *) user_conn_id; + cc->acse_conn_id = acse_conn_id; + + MVL_LOG_ACSE1 ("ACSE: associate confirm for MVL_NET_INFO %08lx", cc); + + req = _mvl_find_req_ctrl (cc, MMSOP_INITIATE, -1); + if (!req) + { + MVL_LOG_ERR0 ("ACSE: Associate Confirm - no matching req ctrl"); + info->result = SD_FAILURE; /* Cause disconnect */ + cc->in_use = SD_FALSE; + return; + } + + /* Only check ACSE authentication if this is a positive connect confirm */ + if (info->result == SD_SUCCESS) + { + auth_ret = u_mvl_connect_cnf_ex(cc, info); + + /* User did not like something about the authentication */ + if(auth_ret != ACSE_AUTH_SUCCESS) + { + MVL_LOG_ACSE1 ("ACSE: ACSE Authentication failure. Reason: %d", auth_ret); + mvl_abort_req_ex (cc, SD_TRUE, auth_ret); + return; + } + } + + free_dec_info = SD_FALSE; + result = info->result; + + if (info->result == SD_SUCCESS) + { + cc->conn_active = SD_TRUE; + + MVL_LOG_ACSEDATAH (info->user_info.len, info->user_info.ptr); + + /* OK, now we need to parse the MMS Initiate PDU */ + free_dec_info = SD_TRUE; + _ms_mms_decode (info->user_info.ptr, info->user_info.len, &rslt); + if (rslt.err_code == NO_DECODE_ERR) + { + switch (rslt.type) + { + case MMSINITRESP : + init_resp = (INIT_INFO *) rslt.data_ptr; + init_resp->mms_p_context_pres = SD_TRUE; + + /* We can log here if so desired */ + /* if ((mms_debug_sel & MMS_LOG_CONF) && ml_log_conf_info_fun != NULL) + (*ml_log_conf_info_fun) (0, MMSOP_INITIATE, init_resp);*/ + + if (req->u.init.resp_info != NULL) + memcpy (req->u.init.resp_info, init_resp, sizeof (INIT_INFO)); + + memcpy (&cc->rem_init_info, init_resp, sizeof (INIT_INFO)); + MVL_LOG_CACSE0 ("ACSE: initiate confirm OK"); + cc->max_pdu_size = init_resp->max_segsize; + /* NOTE: maxreq_calling = num of outstanding indications */ + /* allowed at the calling app (similar for maxreq_called). */ + cc->maxpend_req = init_resp->maxreq_called; + cc->maxpend_ind = init_resp->maxreq_calling; + cc->numpend_req = 0; + cc->numpend_ind = 0; + ++mvl_mms_statistics.callingConnOk; + break; + + case MMSINITERR : + result = SD_FAILURE; + cc->in_use = SD_FALSE; + MVL_LOG_NERR0 ("ACSE: initiate confirm error"); + ++mvl_mms_statistics.callingConnFail; + break; + + default : + MVL_LOG_NERR1 ("ACSE: associate confirm PDU wrong type (%d)", + rslt.type); + result = SD_FAILURE; + cc->in_use = SD_FALSE; + info->result = SD_FAILURE; /* Cause disconnect */ + ++mvl_mms_statistics.callingConnFail; + break; + } + } + else /* PDU decode error, abort the connection */ + { + MVL_LOG_NERR0 ("ACSE: associate confirm PDU Decode Error"); + result = SD_FAILURE; + info->result = SD_FAILURE; /* Cause disconnect */ + cc->in_use = SD_FALSE; + ++mvl_mms_statistics.callingConnFail; + } + } + else + { + MVL_LOG_NERR0 ("ACSE: associate confirm result != SD_SUCCESS"); + cc->in_use = SD_FALSE; + ++mvl_mms_statistics.callingConnFail; + } + + _mvl_set_req_done (req, result); + + if (free_dec_info == SD_TRUE && rslt.data_pres) + M_FREE (MSMEM_DEC_OS_INFO, rslt.data_ptr); +#endif + } + +/************************************************************************/ +/* u_a_data_ind */ +/************************************************************************/ + +ST_VOID u_a_data_ind (ST_LONG user_conn_id, ST_UINT data_len, ST_UCHAR *data) + { +MVL_NET_INFO *ni; +MVL_COMM_EVENT *commEvent; + + ni = (MVL_NET_INFO *) user_conn_id; + +/* See if we are supposed to log ACSE data for this connection */ + if (mvl_conn_filtered_logging == SD_FALSE || ni->log_enable) + { + MVL_LOG_ACSEDATA2 ("ACSE: Rx'd %d bytes on MVL_NET_INFO 0x%08lx", + data_len, ni); + MVL_LOG_ACSEDATAH (data_len, data); + } + + commEvent = mvl_get_com_event (); + if (!commEvent) + { + MVL_LOG_ERR0 ("ACSE: Error - could not get MVL_COMM_EVENT"); + u_a_except (user_conn_id, SD_FAILURE, __FILE__, __LINE__); + return; + } + + commEvent->event_type = MMS_MSG_RCVD; + commEvent->net_info = ni; + commEvent->u.mms.pdu_len = data_len; + commEvent->u.mms.pdu = (ST_UCHAR *) M_MALLOC (MSMEM_RXPDU,data_len); + memcpy (commEvent->u.mms.pdu, data, data_len); + } + +/************************************************************************/ +/* u_a_release_ind */ +/************************************************************************/ + +ST_VOID u_a_release_ind (ST_LONG user_conn_id, RLRQ_APDU *info) + { +RLRE_APDU reinfo; +MVL_NET_INFO *cc; + + cc = (MVL_NET_INFO *) user_conn_id; + MVL_LOG_ACSE1 ("ACSE: Release Indication received on MVL_NET_INFO 0x%08lx", cc); + ++mvl_mms_statistics.serverConcl; + + cc->conn_active = SD_FALSE; + cc->in_use = SD_FALSE; + if (_mvlu_rpt_disconnect_rcvd_fun != NULL) + (*_mvlu_rpt_disconnect_rcvd_fun)(cc); + + reinfo.reason_pres = SD_TRUE; + reinfo.reason = 1; + +/* Send no data on the release response */ + reinfo.user_info.len = 0; + reinfo.user_info.ptr = NULL; + a_release_rsp (cc->acse_conn_id, &reinfo); + +/* Set any outstanding requests to 'done' */ + _mvl_set_net_req_done (NULL, cc, SD_FAILURE); + +#ifdef ICCP_LITE + if (cc->mi_in_use) + mi_release_ind_fun (cc); + else + { + if (u_mvl_disc_ind_fun) + (*u_mvl_disc_ind_fun) (cc, MVL_ACSE_RELEASE_IND); + } +#else + if (u_mvl_disc_ind_fun) + (*u_mvl_disc_ind_fun) (cc, MVL_ACSE_RELEASE_IND); +#endif + + cc->maxpend_req = 0; + cc->numpend_req = 0; + } + +/************************************************************************/ +/* u_a_abort_ind */ +/************************************************************************/ + +ST_VOID u_a_abort_ind (ST_LONG user_conn_id, ABRT_APDU *info) + { +MVL_NET_INFO *cc; +MVL_ASSOC_IND *mvlAssocInd; +ST_BOOLEAN conn_active; + + cc = (MVL_NET_INFO *) user_conn_id; + MVL_LOG_ACSE1 ("ACSE: Abort Indication received on MVL_NET_INFO 0x%08lx", cc); + +/* This can happen if we have not responded to an initiate indication */ +/* In this case, just flush the initiate indication hold list */ + if (cc == NULL) + { + while (mvlAssocIndList) + { + mvlAssocInd = list_get_first (&mvlAssocIndList); + chk_free (mvlAssocInd); + } + return; + } + + ++mvl_mms_statistics.remoteAbort; + +/* Verify we can safely use this as a MVL_NET_INFO */ + if (user_conn_id == -1L) + return; + + conn_active = cc->conn_active; + cc->conn_active = SD_FALSE; + cc->in_use = SD_FALSE; + if (_mvlu_rpt_disconnect_rcvd_fun != NULL) + (*_mvlu_rpt_disconnect_rcvd_fun)(cc); + +/* Set any outstanding requests to 'done' */ + _mvl_set_net_req_done (NULL, cc, MVL_ERR_CNF_DISCONNECTED); + if (conn_active == SD_TRUE) + { +#ifdef ICCP_LITE + if (cc->mi_in_use == SD_TRUE) + mi_abort_ind_fun (cc); + else + { + if (u_mvl_disc_ind_fun) + (*u_mvl_disc_ind_fun) (cc, MVL_ACSE_ABORT_IND); + } +#else + if (u_mvl_disc_ind_fun) + (*u_mvl_disc_ind_fun) (cc, MVL_ACSE_ABORT_IND); +#endif + } + + cc->maxpend_req = 0; + cc->numpend_req = 0; + } + +/************************************************************************/ +/* u_a_release_cnf */ +/************************************************************************/ + +ST_VOID u_a_release_cnf (ST_LONG user_conn_id, RLRE_APDU *info) + { +MVL_NET_INFO *cc; +MVL_REQ_PEND *req; + + + cc = (MVL_NET_INFO *) user_conn_id; + + MVL_LOG_ACSE1 ("ACSE: release confirm received for MVL_NET_INFO %08lx", cc); + +/* Find the conclude request */ + req = _mvl_find_req_ctrl (cc, MVL_MMSOP_RELEASE, -1); + if (!req) + { + MVL_LOG_ERR0 ("ACSE: Release Confirm - no matching req ctrl"); + return; + } + +/* Set any outstanding requests to 'done' */ + _mvl_set_net_req_done (req, cc, MVL_ERR_CNF_DISCONNECTED); + + cc->conn_active = SD_FALSE; + cc->in_use = SD_FALSE; + if (_mvlu_rpt_disconnect_rcvd_fun != NULL) + (*_mvlu_rpt_disconnect_rcvd_fun)(cc); + + _mvl_set_req_done (req, SD_SUCCESS); + cc->maxpend_req = 0; + cc->numpend_req = 0; + } + +/************************************************************************/ +/* u_a_except */ +/************************************************************************/ + +ST_VOID u_a_except (ST_LONG user_conn_id, ST_INT code, + ST_CHAR *filename, ST_INT line) + { + MVL_LOG_ERR2 ("ACSE: Error - Exception, code 0x%x, MVL_NET_INFO %08lx", + code, user_conn_id); + MVL_LOG_CERR2 ("File %s, Line %d", filename, line); + mvl_acse_ok = SD_FALSE; + } + +/************************************************************************/ +/* CONNECTION CONTROL RELATED STUFF */ +/************************************************************************/ +/* ma_get_called_conn_ctrl */ +/************************************************************************/ + +#if (MMS_INIT_EN & RESP_EN) + +static MVL_NET_INFO *ma_get_called_conn_ctrl (NET_BIND_CTRL *bc) + { +MVL_NET_INFO *ni; +ST_INT i; + + ni = mvl_called_conn_ctrl; + for (i = 0; i < mvl_cfg_info->called_used; ++i, ++ni) + { + /* CRITICAL: don't reuse 'ni' until req_pend_list cleaned up from */ + /* last conn. May be waiting for user to call mvl_free_req_ctrl. */ + if (!ni->in_use && ni->req_pend_list==NULL) + { + if (bc == NULL || !strcmp (bc->ar_name, ni->bind_ctrl->ar_name)) + { + ni->in_use = SD_TRUE; + ni->conn_active = SD_FALSE; + return (ni); + } + } + } + return (NULL); + } + +#endif + +/************************************************************************/ +/* ma_get_calling_conn_ctrl */ +/************************************************************************/ +#if (MMS_INIT_EN & REQ_EN) + +static MVL_NET_INFO *ma_get_calling_conn_ctrl (NET_BIND_CTRL *bc) + { +MVL_NET_INFO *ni; +ST_INT i; + + ni = mvl_calling_conn_ctrl; + for (i = 0; i < mvl_cfg_info->calling_used; ++i, ++ni) + { + /* CRITICAL: don't reuse 'ni' until req_pend_list cleaned up from */ + /* last conn. May be waiting for user to call mvl_free_req_ctrl. */ + if (!ni->in_use && ni->req_pend_list==NULL) + { + if (bc == NULL || !strcmp (bc->ar_name, ni->bind_ctrl->ar_name)) + { + ni->in_use = SD_TRUE; + ni->conn_active = SD_FALSE; + return (ni); + } + } + } + return (NULL); + } +#endif + + +/************************************************************************/ +#endif /* End of COACSE specific functions */ +/************************************************************************/ + +/************************************************************************/ +/************************************************************************/ +#if defined(CLACSE) /* CONNECTIONLESS ACSE FUNCTIONS */ +/************************************************************************/ + +/************************************************************************/ +/* mvl_get_com_event */ +/************************************************************************/ +/* This function is used to get a MVL_COMM_EVENT control buffer to be */ +/* passed up to the caller of '_mvl_net_service'. */ + +static MVL_NET_INFO *mvl_get_net_info (ST_VOID) + { +MVL_NET_INFO *netInfo; + +#if 1 + netInfo = (MVL_NET_INFO *) M_CALLOC (MSMEM_NETINFO, 1, sizeof (MVL_NET_INFO)); + if (netInfo == NULL) + { + MVL_LOG_ERR0 ("Error: No MVL_NET_INFO available"); + return (NULL); + } +#else + if (mvl_net_info_avail_head) + netInfo = (MVL_NET_INFO *) list_get_first((ST_VOID **) &mvl_net_info_avail_head); + else + { + if (mvl_net_info_count >= mvl_max_net_info) + { + MVL_LOG_ERR0 ("Error: No MVL_NET_INFO available"); + return (NULL); + } + ++mvl_net_info_count; + netInfo = (MVL_NET_INFO *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_NET_INFO)); + } +#endif + + return (netInfo); + } + +/************************************************************************/ +/* mvl_init_audt_addr */ +/* User must pass pointer (AUDT_APDU *) to their struct. */ +/* This function fills in the addressing info in the struct. */ +/************************************************************************/ + +ST_RET mvl_init_audt_addr (AUDT_APDU *audt, ST_CHAR *locArName, ST_CHAR *remArName) + { +DIB_ENTRY *locDe; +DIB_ENTRY *remDe; + +/* Retrieve the DIB_ENTRY's for local and remote. These are used to set */ +/* the AUDT_APDU information */ + + locDe = find_loc_dib_entry (locArName); + if (!locDe) + { + MVL_LOG_NERR1 ("ACSE: Local name '%s' not found", locArName); + return (MVLE_LOCAL_NAME); + } + + remDe = find_rem_dib_entry (remArName); + if (!remDe) + { + MVL_LOG_NERR1 ("ACSE: Remote name '%s' not found", remArName); + return (MVLE_REMOTE_NAME); + } + + if (remDe->pres_addr.tp_type != TP_TYPE_TP4) /* must be TP4 (need NSAP) */ + { + MVL_LOG_NERR1 ("ACSE: Remote name '%s' is not TP4 Transport type", remArName); + return (MVLE_REMOTE_NAME); + } + + /* AP Context is MMS */ + audt->ASO_context_name_pres = SD_TRUE; + audt->ASO_context_name.num_comps = 5; + audt->ASO_context_name.comps[0] = 1; + audt->ASO_context_name.comps[1] = 0; + audt->ASO_context_name.comps[2] = 9506; + audt->ASO_context_name.comps[3] = 2; + audt->ASO_context_name.comps[4] = 3; + +/* Calling Addressing information */ + audt->calling_ae_title.AP_title_pres = locDe->AP_title_pres; + memcpy (&audt->calling_ae_title.AP_title, &locDe->AP_title, + sizeof (MMS_OBJ_ID)); + + audt->calling_ae_title.AE_qual_pres = locDe->AE_qual_pres; + audt->calling_ae_title.AE_qual = locDe->AE_qual; + audt->calling_ae_title.AP_inv_id_pres = locDe->AP_inv_id_pres; + audt->calling_ae_title.AP_inv_id = locDe->AP_invoke_id; + audt->calling_ae_title.AE_qual_pres = locDe->AE_qual_pres; + audt->calling_ae_title.AE_qual = locDe->AE_qual; + audt->calling_ae_title.AE_inv_id_pres = locDe->AE_inv_id_pres; + audt->calling_ae_title.AE_inv_id = locDe->AE_invoke_id; + + memcpy (&audt->calling_paddr, &locDe->pres_addr, sizeof (PRES_ADDR)); + +/* Called Addressing information */ + audt->called_ae_title.AP_title_pres = remDe->AP_title_pres; + memcpy (&audt->called_ae_title.AP_title, &remDe->AP_title, + sizeof (MMS_OBJ_ID)); + audt->called_ae_title.AE_qual_pres = remDe->AE_qual_pres; + audt->called_ae_title.AE_qual = remDe->AE_qual; + audt->called_ae_title.AP_inv_id_pres = remDe->AP_inv_id_pres; + audt->called_ae_title.AP_inv_id = remDe->AP_invoke_id; + audt->called_ae_title.AE_qual_pres = remDe->AE_qual_pres; + audt->called_ae_title.AE_qual = remDe->AE_qual; + audt->called_ae_title.AE_inv_id_pres = remDe->AE_inv_id_pres; + audt->called_ae_title.AE_inv_id = remDe->AE_invoke_id; + + memcpy (&audt->called_paddr, &remDe->pres_addr, sizeof (PRES_ADDR)); + + audt->rem_mac_valid = SD_FALSE; /* CRITICAL: must send to ALL-ES MAC*/ + + return (SD_SUCCESS); + } + +/************************************************************************/ +/* mvl_free_net_info */ +/************************************************************************/ + +static ST_VOID mvl_free_net_info (MVL_NET_INFO *netInfo) + { +#if 1 + M_FREE (MSMEM_NETINFO, netInfo); +#else + list_add_last((ST_VOID **) &mvl_net_info_avail_head, (ST_VOID *) netInfo); +#endif + } + +/************************************************************************/ +#endif /* End of CLACSE specific functions */ +/************************************************************************/ + +/************************************************************************/ +/************************************************************************/ +/* UTILITY FUNCTIONS */ +/************************************************************************/ +/* ma_wait_req_done */ +/************************************************************************/ + +static ST_VOID ma_wait_req_done (ST_RET *retOut) + { +/* See if the call failed */ + if (*retOut != SD_SUCCESS) + return; + +/* Now just wait for the 'confirm' function to be called */ + while (ma_cmd_done != SD_TRUE) + { + copp_event (); + if (u_mvl_check_timeout && (*u_mvl_check_timeout)()) + break; + } + +/* OK, the function is done or the user gave up */ + if (ma_cmd_done == SD_TRUE) + *retOut = ma_cmd_rslt; + else + { /* User timeout */ + if (ma_cmd_rslt != SD_SUCCESS) + *retOut = ma_cmd_rslt; + else + *retOut = SD_FAILURE; + } + } + +/************************************************************************/ +/************************************************************************/ +/* AA OBJECT HANDLING FUNCTIONS */ +/* These functions must be here because the sizeof MVL_NET_INFO */ +/* varies depending on the stack selection. */ +/************************************************************************/ +/************************************************************************/ +/* mvl_aa_resize */ +/************************************************************************/ + +ST_VOID mvl_aa_resize (ST_INT max_num_var, ST_INT max_num_nvl, + ST_INT max_num_jou) + { +MVL_AA_OBJ_CTRL *aa_objs; +ST_INT i; + +/* Do AA specific variables */ + for (i = 0; i < mvl_cfg_info->num_called; ++i) + { + aa_objs = (MVL_AA_OBJ_CTRL *) mvl_called_conn_ctrl[i].aa_objs; + if (aa_objs == NULL) + { + aa_objs = mvl_called_conn_ctrl[i].aa_objs = + (MVL_AA_OBJ_CTRL *) M_CALLOC (NULL, 1, sizeof(MVL_AA_OBJ_CTRL)); + } + mvl_aa_resize_conn (aa_objs, max_num_var, max_num_nvl, max_num_jou); + } + + for (i = 0; i < mvl_cfg_info->num_calling; ++i) + { + aa_objs = (MVL_AA_OBJ_CTRL *) mvl_calling_conn_ctrl[i].aa_objs; + if (aa_objs == NULL) + { + aa_objs = mvl_calling_conn_ctrl[i].aa_objs = + (MVL_AA_OBJ_CTRL *) M_CALLOC (NULL, 1, sizeof(MVL_AA_OBJ_CTRL)); + } + mvl_aa_resize_conn (aa_objs, max_num_var, max_num_nvl, max_num_jou); + } + } + +/************************************************************************/ +/* _mvl_clear_aa_objs */ +/************************************************************************/ + +ST_VOID _mvl_clear_aa_objs (MVL_AA_OBJ_CTRL *aa_objs) + { +ST_INT i; + +/* Delete NVL's. We need to delete the 'entries' pointer table for each */ +/* NVL, then delete the table of NVL's. */ + if (aa_objs->max_num_nvlist) + { + for (i = 0; i < aa_objs->num_nvlist; ++i) + mvl_nvl_destroy (aa_objs->nvlist_tbl[i]); + } + +/* Delete the variable association table. */ + if (aa_objs->max_num_var_assoc) + { + for (i = 0; i < aa_objs->num_var_assoc; ++i) + M_FREE (MSMEM_GEN, aa_objs->var_assoc_tbl[i]); + } + +/* Delete the Journal control table. */ + if (aa_objs->max_num_jou) + { + for (i = 0; i < aa_objs->num_jou; ++i) + M_FREE (MSMEM_GEN, aa_objs->jou_tbl[i]); + } + + aa_objs->num_var_assoc = 0; + aa_objs->num_nvlist = 0; + aa_objs->num_jou = 0; + } + +/************************************************************************/ + +ST_VOID mvl_aa_resize_conn (MVL_AA_OBJ_CTRL *aa_objs, ST_INT max_num_var, ST_INT max_num_nvl, + ST_INT max_num_jou) + { + if (max_num_var < aa_objs->num_var_assoc) + { + MVL_LOG_NERR0 ("Resizing VMD: new max VA is less than current"); + max_num_var = aa_objs->num_var_assoc; + } + if (max_num_nvl < aa_objs->num_nvlist) + { + MVL_LOG_NERR0 ("Resizing VMD: new max NVL is less than current"); + max_num_nvl = aa_objs->num_nvlist; + } + if (max_num_jou < aa_objs->num_jou) + { + MVL_LOG_NERR0 ("Resizing VMD: new max JOU is less than current"); + max_num_jou = aa_objs->num_jou; + } + + _mvl_resize_ptr_tbl (&(aa_objs->max_num_var_assoc), + (ST_VOID ***)&(aa_objs->var_assoc_tbl), max_num_var); + _mvl_resize_ptr_tbl (&(aa_objs->max_num_nvlist), + (ST_VOID ***)&(aa_objs->nvlist_tbl), max_num_nvl); + _mvl_resize_ptr_tbl (&(aa_objs->max_num_jou), + (ST_VOID ***)&(aa_objs->jou_tbl), max_num_jou); + } + +/************************************************************************/ +/************************************************************************/ +/* mvl_match_remote_ar */ +/************************************************************************/ + +ST_RET mvl_match_remote_ar (DIB_MATCH_CTRL *matchCtrl, MVL_NET_INFO *cc, + DIB_ENTRY **dib_entry_out) + { +#if defined(MAP30_ACSE) +ST_INT chan; + + if (a_get_chan (cc->acse_conn_id, &chan) == SD_SUCCESS) + return (dib_match_remote_ar (matchCtrl, chan, dib_entry_out)); + else + return (SD_FAILURE); +#else + return (dib_match_remote_ar (matchCtrl, &cc->ass_ind_info, dib_entry_out)); +#endif + } + + +/************************************************************************/ +/* mvl_match_local_ar */ +/************************************************************************/ + +ST_RET mvl_match_local_ar (DIB_MATCH_CTRL *matchCtrl, MVL_NET_INFO *cc, + DIB_ENTRY **dib_entry_out) + { +#if defined(MAP30_ACSE) +ST_INT chan; + + if (a_get_chan (cc->acse_conn_id, &chan) == SD_SUCCESS) + return (dib_match_local_ar (matchCtrl, chan, dib_entry_out)); + else + return (SD_FAILURE); +#else + return (dib_match_local_ar (matchCtrl, &cc->ass_ind_info, dib_entry_out)); +#endif + } + +/************************************************************************/ +/* mvl_cmp_local_addr */ +/************************************************************************/ + +ST_INT mvl_cmp_local_addr (DIB_MATCH_CTRL *matchCtrl, MVL_NET_INFO *cc, + DIB_ENTRY *dib_entry) + { +#if defined(MAP30_ACSE) +ST_INT chan; + + if (a_get_chan (cc->acse_conn_id, &chan) == SD_SUCCESS) + return (dib_cmp_local_addr (matchCtrl, chan, dib_entry)); + else + return (DIB_MATCH_NOT); +#else + return (dib_cmp_local_addr (matchCtrl, &cc->ass_ind_info, dib_entry)); +#endif + } + +/************************************************************************/ +/* mvl_cmp_remote_addr */ +/************************************************************************/ + +ST_INT mvl_cmp_remote_addr (DIB_MATCH_CTRL *matchCtrl, MVL_NET_INFO *cc, + DIB_ENTRY *dib_entry) + { +#if defined(MAP30_ACSE) +ST_INT chan; + + if (a_get_chan (cc->acse_conn_id, &chan) == SD_SUCCESS) + return (dib_cmp_remote_addr (matchCtrl, chan, dib_entry)); + else + return (DIB_MATCH_NOT); +#else + return (dib_cmp_remote_addr (matchCtrl, &cc->ass_ind_info, dib_entry)); +#endif + } + + +/************************************************************************/ +/* mvl_net_info_to_chan */ +/************************************************************************/ + +ST_RET mvl_net_info_to_chan (MVL_NET_INFO *cc, ST_INT *chanOut) + { +#if defined(MAP30_ACSE) + return (a_get_chan (cc->acse_conn_id, chanOut)); +#else + return (SD_FAILURE); +#endif + } + diff --git a/mms/mvlop_en.c b/mms/mvlop_en.c new file mode 100644 index 0000000..07a3113 --- /dev/null +++ b/mms/mvlop_en.c @@ -0,0 +1,928 @@ +/* +* @version: $Revision: 1.2 $ +* @date: $Date: 2018/12/20 06:00:55 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: mvlop_en.c,v 1.2 2018/12/20 06:00:55 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 1994 - 1996, All Rights Reserved */ +/* */ +/* MODULE NAME : mvlop_en.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* mvl_cancel_ind_rcvd */ +/* mvl_concl_ind_rcvd */ +/* mvl_concl_conf_rcvd */ +/* mvl_ind_rcvd */ +/* mvl_conf_rcvd */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------ */ +/* 11/12/07 MDE 17 Added _mvl_getpath, changed _mvl_tmpnam */ +/* 08/12/05 JRB 16 Add #error if unsupported service enabled. */ +/* 10/20/03 JRB 15 Fix print formats. */ +/* 02/04/03 MDE 14 Added _mvl_tmpnam */ +/* 07/09/02 MDE 13 Add maxpend_ind support */ +/* 05/21/01 MDE 12 Now check return from indication ctrl alloc */ +/* 03/15/01 JRB 11 Added call to _mvl_process_ustatus_ind. */ +/* 10/25/00 JRB 10 Added #ifdef ICCP_LITE. */ +/* 09/25/00 JRB 09 Added server support for Domain & PI services*/ +/* 09/25/00 JRB 08 Total rewrite without function pointers. */ +/************************************************************************/ + +#include "glbtypes.h" +#include "sysincs.h" + +#include "mmsdefs.h" +#include "mvl_defs.h" +#include "mmsop_en.h" + +#include "mvl_log.h" + +#if defined(ICCP_LITE) +#include "mi.h" +#endif + +/************************************************************************/ +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ +/************************************************************************/ + +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +/************************************************************************/ +/* mvl_cancel_ind_rcvd */ +/* A MMS Cancel Indication has been received. Process it. */ +/************************************************************************/ +ST_VOID mvl_cancel_ind_rcvd (MVL_COMM_EVENT *event) + { +#if (MMS_CANCEL_EN & RESP_EN) + _mvl_process_cancel_ind (event); +#else + _mvl_send_reject (event); +#endif + } + +/************************************************************************/ +/* mvl_concl_ind_rcvd */ +/* A MMS Conclude Indication has been received. Process it. */ +/************************************************************************/ +ST_VOID mvl_concl_ind_rcvd (MVL_COMM_EVENT *event) + { +#if (MMS_CONCLUDE_EN & RESP_EN) + _mvl_process_concl_ind (event); +#else + _mvl_send_reject (event); +#endif + } + +/************************************************************************/ +/* mvl_concl_conf_rcvd */ +/* A MMS Conclude Confirm has been received. Process it. */ +/************************************************************************/ +ST_VOID mvl_concl_conf_rcvd (MVL_REQ_PEND *req_pend) + { +#if (MMS_CONCLUDE_EN & REQ_EN) + _mvl_process_concl_conf (req_pend); +#else + _mvl_conf_reject (req_pend); +#endif + } + +/************************************************************************/ +/* mvl_ind_rcvd */ +/* A MMS request has been received. This is where the real action */ +/* takes place, and the response is generated */ +/* NOTE: if a service is NOT enabled, the "switch" falls through to the */ +/* default case which sends a reject. */ +/************************************************************************/ + +ST_VOID mvl_ind_rcvd (MVL_COMM_EVENT *event) + { +MVL_IND_PEND *indCtrl; + + /* Information Reports & Unsol Status are special cases. Process first.*/ + /* 1. "event" used instead of "indCtrl". */ + /* 2. Keep different statistics. */ + if (event->u.mms.dec_rslt.op == MMSOP_INFO_RPT) + { +#if (MMS_INFO_EN & RESP_EN) +#if defined(ICCP_LITE) + _mic_process_info_ind (event); +#else + _mvl_process_info_ind (event); +#endif +#else + _mvl_send_reject (event); +#endif + ++mvl_mms_statistics.clientInfoRpt; + return; /* do not continue */ + } + else if (event->u.mms.dec_rslt.op == MMSOP_USTATUS) + { +#if (MMS_USTATUS_EN & RESP_EN) + _mvl_process_ustatus_ind (event); +#else + _mvl_send_reject (event); +#endif + ++mvl_mms_statistics.clientUstatus; + return; /* do not continue */ + } + + ++mvl_mms_statistics.serverInd; + indCtrl = (MVL_IND_PEND *) M_CALLOC (MSMEM_IND_CTRL, 1, sizeof (MVL_IND_PEND)); + if (indCtrl == NULL) + { + MVL_LOG_NERR0 ("Could not allocate indication control, rejecting"); + _mvl_send_reject (event); + return; + } + + indCtrl->op = event->u.mms.dec_rslt.op; + indCtrl->event = event; + list_add_first(&(event->net_info->pend_ind),indCtrl); + ++event->net_info->numpend_ind; + + switch (event->u.mms.dec_rslt.op) + { +#if (MMS_READ_EN & RESP_EN) + case MMSOP_READ : +#if defined(ICCP_LITE) + _mis_process_read_ind (indCtrl); +#else + _mvl_process_read_ind (indCtrl); +#endif + break; +#endif +#if (MMS_WRITE_EN & RESP_EN) + case MMSOP_WRITE : +#if defined(ICCP_LITE) + _mis_process_write_ind (indCtrl); +#else + _mvl_process_write_ind (indCtrl); +#endif + break; +#endif + +/* case MMSOP_INFO_RPT : handled before switch. */ + +#if (MMS_IDENT_EN & RESP_EN) + case MMSOP_IDENTIFY : + _mvl_process_ident_ind (indCtrl); + break; +#endif +#if (MMS_STATUS_EN & RESP_EN) + case MMSOP_STATUS : + _mvl_process_status_ind (indCtrl); + break; +#endif +#if (MMS_GETNAMES_EN & RESP_EN) + case MMSOP_GET_NAMLIST: +#if defined(ICCP_LITE) + _mis_process_getnam_ind (indCtrl); +#else + _mvl_process_getnam_ind (indCtrl); +#endif + break; +#endif +#if (MMS_GETVAR_EN & RESP_EN) + case MMSOP_GET_VAR: +#if defined(ICCP_LITE) + _mis_process_getvaa_ind (indCtrl); +#else + _mvl_process_getvaa_ind (indCtrl); +#endif + break; +#endif +#if (MMS_GETVLIST_EN & RESP_EN) + case MMSOP_GET_VLIST: +#if defined(ICCP_LITE) + _mis_process_getvla_ind (indCtrl); +#else + _mvl_process_getvla_ind (indCtrl); +#endif + break; +#endif +#if (MMS_FDIR_EN & RESP_EN) + case MMSOP_FILE_DIR: + _mvl_process_fdir_ind (indCtrl); + break; +#endif +#if (MMS_FOPEN_EN & RESP_EN) + case MMSOP_FILE_OPEN: + _mvl_process_fopen_ind (indCtrl); + break; +#endif +#if (MMS_FREAD_EN & RESP_EN) + case MMSOP_FILE_READ: + _mvl_process_fread_ind (indCtrl); + break; +#endif +#if (MMS_FCLOSE_EN & RESP_EN) + case MMSOP_FILE_CLOSE: + _mvl_process_fclose_ind (indCtrl); + break; +#endif +#if (MMS_FDELETE_EN & RESP_EN) + case MMSOP_FILE_DELETE: + _mvl_process_fdelete_ind (indCtrl); + break; +#endif +#if (MMS_OBTAINFILE_EN & RESP_EN) + case MMSOP_OBTAIN_FILE: + _mvl_process_obtfile_ind (indCtrl); + break; +#endif +#if (MMS_FRENAME_EN & RESP_EN) + case MMSOP_FILE_RENAME: + _mvl_process_frename_ind (indCtrl); + break; +#endif +#if (MMS_DEFVLIST_EN & RESP_EN) + case MMSOP_DEF_VLIST: +#if defined(ICCP_LITE) + _mis_process_defvl_ind (indCtrl); +#else + _mvl_process_defvlist_ind (indCtrl); +#endif + break; +#endif +#if (MMS_DELVLIST_EN & RESP_EN) + case MMSOP_DEL_VLIST: +#if defined(ICCP_LITE) + _mis_process_delvlist_ind (indCtrl); +#else + _mvl_process_delvlist_ind (indCtrl); +#endif + break; +#endif +#if (MMS_JINIT_EN & RESP_EN) + case MMSOP_INIT_JOURNAL: + _mvl_process_jinit_ind (indCtrl); + break; +#endif +#if (MMS_JREAD_EN & RESP_EN) + case MMSOP_READ_JOURNAL: + _mvl_process_jread_ind (indCtrl); + break; +#endif +#if (MMS_JSTAT_EN & RESP_EN) + case MMSOP_STAT_JOURNAL: + _mvl_process_jstat_ind (indCtrl); + break; +#endif +#if (MMS_INIT_DWN_EN & RESP_EN) + case MMSOP_INIT_DOWNLOAD: /* initiate download sequence */ + _mvl_process_initdown_ind (indCtrl); + break; +#endif +#if (MMS_DWN_LOAD_EN & RESP_EN) + case MMSOP_DOWN_LOAD: /* download segment */ + _mvl_process_download_ind (indCtrl); + break; +#endif +#if (MMS_TERM_DWN_EN & RESP_EN) + case MMSOP_TERM_DOWNLOAD: /* terminate download sequence */ + _mvl_process_termdown_ind (indCtrl); + break; +#endif +#if (MMS_INIT_UPL_EN & RESP_EN) + case MMSOP_INIT_UPLOAD: /* initiate upload sequence */ + _mvl_process_initupl_ind (indCtrl); + break; +#endif +#if (MMS_UP_LOAD_EN & RESP_EN) + case MMSOP_UP_LOAD: /* upload segment */ + _mvl_process_upload_ind (indCtrl); + break; +#endif +#if (MMS_TERM_UPL_EN & RESP_EN) + case MMSOP_TERM_UPLOAD: /* terminate upload sequence */ + _mvl_process_termupl_ind (indCtrl); + break; +#endif +#if (MMS_DEL_DOM_EN & RESP_EN) + case MMSOP_DELETE_DOMAIN: /* delete domain */ + _mvl_process_deldom_ind (indCtrl); + break; +#endif +#if (MMS_GET_DOM_EN & RESP_EN) + case MMSOP_GET_DOM_ATTR: /* get domain attribute */ + _mvl_process_getdom_ind (indCtrl); + break; +#endif +#if (MMS_CRE_PI_EN & RESP_EN) + case MMSOP_CREATE_PI: /* create program invocation */ + _mvl_process_crepi_ind (indCtrl); + break; +#endif +#if (MMS_DEL_PI_EN & RESP_EN) + case MMSOP_DELETE_PI: /* delete program invocation */ + _mvl_process_delpi_ind (indCtrl); + break; +#endif +#if (MMS_START_EN & RESP_EN) + case MMSOP_START: /* start */ + _mvl_process_start_ind (indCtrl); + break; +#endif +#if (MMS_STOP_EN & RESP_EN) + case MMSOP_STOP: /* stop */ + _mvl_process_stop_ind (indCtrl); + break; +#endif +#if (MMS_RESUME_EN & RESP_EN) + case MMSOP_RESUME: /* resume */ + _mvl_process_resume_ind (indCtrl); + break; +#endif +#if (MMS_RESET_EN & RESP_EN) + case MMSOP_RESET: /* reset */ + _mvl_process_reset_ind (indCtrl); + break; +#endif +#if (MMS_KILL_EN & RESP_EN) + case MMSOP_KILL: /* kill */ + _mvl_process_kill_ind (indCtrl); + break; +#endif +#if (MMS_GET_PI_EN & RESP_EN) + case MMSOP_GET_PI_ATTR: /* get program invocation attribute */ + _mvl_process_getpi_ind (indCtrl); + break; +#endif +#if (MMS_GETCL_EN & RESP_EN) + case MMSOP_GET_CAP_LIST: /* get capability list */ + _mvl_process_getcl_ind (indCtrl); + break; +#endif + default : + _mvl_ind_reject (indCtrl); + break; + } + } + +/************************************************************************/ +/* mvl_conf_rcvd */ +/* A MMS response has been received. This is where the real action */ +/* takes place, and the response data is interpreted */ +/* NOTE: if a service is NOT enabled, the "switch" falls through to the */ +/* default case which sends a reject. */ +/************************************************************************/ + +ST_VOID mvl_conf_rcvd (MVL_COMM_EVENT *event) + { +MVL_REQ_PEND *req_pend; +ST_UINT32 id; +ST_INT op; + + ++mvl_mms_statistics.clientReqOk; + + id = event->u.mms.dec_rslt.id; + op = event->u.mms.dec_rslt.op; + + event->net_info->numpend_req--; + +/* First find the associated request control structure */ + req_pend = _mvl_find_req_ctrl (event->net_info, op, id); + + if (!req_pend) + { + MVL_LOG_NERR1 ("%s Confirmation : mvl_find_req_ctrl failed", + mms_op_string [event->u.mms.dec_rslt.op]); + _mvl_free_comm_event (event); /* All done with this event */ + return; + } + + /* Save "event" in req_pend. Free from mvl_free_req_ctrl. */ + /* This allows user code to use any data in event without copying it. */ + req_pend->event = event; + + switch (event->u.mms.dec_rslt.op) + { +#if (MMS_READ_EN & REQ_EN) + case MMSOP_READ : +#if defined(ICCP_LITE) + _mic_process_read_conf (req_pend); +#else + _mvl_process_read_conf (req_pend); +#endif + break; +#endif +#if (MMS_WRITE_EN & REQ_EN) + case MMSOP_WRITE : + _mvl_process_write_conf (req_pend); + break; +#endif +#if (MMS_IDENT_EN & REQ_EN) + case MMSOP_IDENTIFY : + _mvl_process_ident_conf (req_pend); + break; +#endif +#if (MMS_FOPEN_EN & REQ_EN) + case MMSOP_FILE_OPEN : + _mvl_process_fopen_conf (req_pend); + break; +#endif +#if (MMS_FREAD_EN & REQ_EN) + case MMSOP_FILE_READ : + _mvl_process_fread_conf (req_pend); + break; +#endif +#if (MMS_FCLOSE_EN & REQ_EN) + case MMSOP_FILE_CLOSE : + _mvl_process_fclose_conf (req_pend); + break; +#endif +#if (MMS_FDIR_EN & REQ_EN) + case MMSOP_FILE_DIR : + _mvl_process_fdir_conf (req_pend); + break; +#endif +#if (MMS_FDELETE_EN & REQ_EN) + case MMSOP_FILE_DELETE : + _mvl_process_fdelete_conf (req_pend); + break; +#endif +#if (MMS_FRENAME_EN & REQ_EN) + case MMSOP_FILE_RENAME : + _mvl_process_frename_conf (req_pend); + break; +#endif +#if (MMS_OBTAINFILE_EN & REQ_EN) + case MMSOP_OBTAIN_FILE : + _mvl_process_obtfile_conf (req_pend); + break; +#endif +#if (MMS_JINIT_EN & REQ_EN) + case MMSOP_INIT_JOURNAL : + _mvl_process_jinit_conf (req_pend); + break; +#endif +#if (MMS_JREAD_EN & REQ_EN) + case MMSOP_READ_JOURNAL : + _mvl_process_jread_conf (req_pend); + break; +#endif +#if (MMS_JWRITE_EN & REQ_EN) + case MMSOP_WRITE_JOURNAL : + _mvl_process_jwrite_conf (req_pend); + break; +#endif +#if (MMS_JSTAT_EN & REQ_EN) + case MMSOP_STAT_JOURNAL : + _mvl_process_jstat_conf (req_pend); + break; +#endif +#if (MMS_DEFVLIST_EN & REQ_EN) + case MMSOP_DEF_VLIST : + _mvl_process_defvlist_conf (req_pend); + break; +#endif +#if (MMS_GETVLIST_EN & REQ_EN) + case MMSOP_GET_VLIST : + _mvl_process_getvlist_conf (req_pend); + break; +#endif +#if (MMS_DELVLIST_EN & REQ_EN) + case MMSOP_DEL_VLIST : + _mvl_process_delvlist_conf (req_pend); + break; +#endif +#if (MMS_GETVAR_EN & REQ_EN) + case MMSOP_GET_VAR : + _mvl_process_getvar_conf (req_pend); + break; +#endif +#if (MMS_GETNAMES_EN & REQ_EN) + case MMSOP_GET_NAMLIST : + _mvl_process_getnam_conf (req_pend); + break; +#endif +#if (MMS_STATUS_EN & REQ_EN) + case MMSOP_STATUS : + _mvl_process_status_conf (req_pend); + break; +#endif +#if (MMS_INIT_DWN_EN & REQ_EN) + case MMSOP_INIT_DOWNLOAD: /* initiate download sequence */ + _mvl_process_initdown_conf (req_pend); + break; +#endif +#if (MMS_DWN_LOAD_EN & REQ_EN) + case MMSOP_DOWN_LOAD: /* download segment */ + _mvl_process_download_conf (req_pend); + break; +#endif +#if (MMS_TERM_DWN_EN & REQ_EN) + case MMSOP_TERM_DOWNLOAD: /* terminate download sequence */ + _mvl_process_termdown_conf (req_pend); + break; +#endif +#if (MMS_INIT_UPL_EN & REQ_EN) + case MMSOP_INIT_UPLOAD: /* initiate upload sequence */ + _mvl_process_initupl_conf (req_pend); + break; +#endif +#if (MMS_UP_LOAD_EN & REQ_EN) + case MMSOP_UP_LOAD: /* upload segment */ + _mvl_process_upload_conf (req_pend); + break; +#endif +#if (MMS_TERM_UPL_EN & REQ_EN) + case MMSOP_TERM_UPLOAD: /* terminate upload sequence */ + _mvl_process_termupl_conf (req_pend); + break; +#endif +#if (MMS_DEL_DOM_EN & REQ_EN) + case MMSOP_DELETE_DOMAIN: /* delete domain */ + _mvl_process_deldom_conf (req_pend); + break; +#endif +#if (MMS_GET_DOM_EN & REQ_EN) + case MMSOP_GET_DOM_ATTR: /* get domain attributes */ + _mvl_process_getdom_conf (req_pend); + break; +#endif +#if (MMS_CRE_PI_EN & REQ_EN) + case MMSOP_CREATE_PI: /* create program invocation */ + _mvl_process_crepi_conf (req_pend); + break; +#endif +#if (MMS_DEL_PI_EN & REQ_EN) + case MMSOP_DELETE_PI: /* delete program invocation */ + _mvl_process_delpi_conf (req_pend); + break; +#endif +#if (MMS_START_EN & REQ_EN) + case MMSOP_START: /* start */ + _mvl_process_start_conf (req_pend); + break; +#endif +#if (MMS_STOP_EN & REQ_EN) + case MMSOP_STOP: /* stop */ + _mvl_process_stop_conf (req_pend); + break; +#endif +#if (MMS_RESUME_EN & REQ_EN) + case MMSOP_RESUME: /* resume */ + _mvl_process_resume_conf (req_pend); + break; +#endif +#if (MMS_RESET_EN & REQ_EN) + case MMSOP_RESET: /* reset */ + _mvl_process_reset_conf (req_pend); + break; +#endif +#if (MMS_KILL_EN & REQ_EN) + case MMSOP_KILL: /* kill */ + _mvl_process_kill_conf (req_pend); + break; +#endif +#if (MMS_GET_PI_EN & REQ_EN) + case MMSOP_GET_PI_ATTR: /* get program invocation attribute */ + _mvl_process_getpi_conf (req_pend); + break; +#endif +#if (MMS_GETCL_EN & REQ_EN) + case MMSOP_GET_CAP_LIST: /* get capability list */ + _mvl_process_getcl_conf (req_pend); + break; +#endif + default : + /* This should never happen. It means we sent a "Request" but we */ + /* don't support the "Confirm" for it. */ + MVL_LOG_ERR1 ("Error: Confirm received for unsupported service '%s'", + mms_op_string [event->u.mms.dec_rslt.op]); + _mvl_conf_reject (req_pend); + break; + } + + _mvl_set_req_done (req_pend, req_pend->result); + } + + +/************************************************************************/ +/************************************************************************/ +/* _mvl_tmpnam */ +/************************************************************************/ +/* For applications that do file activity, we need this function */ + +#if (MMS_FOPEN_EN & REQ_EN) || (MMS_FOPEN_EN & RESP_EN) + + +#define MAX_TEMP_FILE_NUM 0xFFFF +#define MAX_TEMP_FILE_TRIES 0xFFFF + +ST_CHAR *mvl_tmpfile_path; + +//ST_RET _mvl_tmpnam (ST_CHAR *dest, ST_CHAR *tmpfile_path) +// { +//static ST_INT nextId = 0; +//ST_INT i; +//FILE *fp; +//ST_CHAR *p; +//ST_INT pathLen; +// +// if (dest == NULL) +// return (SD_FAILURE); +// +///* If the user did not pass in a path, use the global path */ +// if (tmpfile_path == NULL) +// tmpfile_path = mvl_tmpfile_path; +// +///* Default is to use the current working directory */ +// dest[0] = 0; +// p = dest; +// +///* See if user has path they want to use */ +// if (tmpfile_path != NULL) +// { +// pathLen = strlen (tmpfile_path); +// if (pathLen > MVL_MAX_TMPFILE_PATH) +// { +// MVL_LOG_NERR0 ("Error: temp file path too long, using working dir"); +// } +// else +// { +// strcpy (dest, tmpfile_path); +// p = dest + pathLen; +// } +// } +// +// for (i = 0; i < MAX_TEMP_FILE_TRIES; ++i) +// { +// apr_snprintf (p,sizeof(p), "TMP%04x.TMP", nextId); +// if (++nextId >= MAX_TEMP_FILE_NUM) +// nextId = 0; +// +// fp = fopen (dest,"r"); /* See if already present */ +// if (!fp) /* nope. */ +// return (SD_SUCCESS); +// else /* file is present, try again */ +// fclose (fp); +// } +// return (SD_FAILURE); +// } + +/************************************************************************/ +/* _mvl_getpath */ +/************************************************************************/ + +ST_VOID _mvl_getpath (ST_CHAR *file_spec, ST_CHAR *dest) + { +ST_INT i; + + strcpy (dest, file_spec); + i = strlen (dest); + while (i > 0) + { + if ((dest[i-1] == '/') || + (dest[i-1] == '\\') || + (dest[i-1] == ':')) + { + dest[i] = 0; + break; + } + --i; + } + if (i == 0) + dest[0] = 0; + } + +#endif /* #if (MMS_FOPEN_EN & REQ_EN) || (MMS_FOPEN_EN & RESP_EN) */ + +/************************************************************************/ +/* These checks make sure that user doesn't try to enable a MMS */ +/* service that is not supported. */ +/************************************************************************/ +#if (MMS_CANCEL_EN & REQ_EN) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_RENAME_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_DWN_EN != REQ_RESP_DIS) /* VM Upload */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_INIT_DWN_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DWN_LOAD_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_TERM_DWN_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_UPL_EN != REQ_RESP_DIS) /* VM Download */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_INIT_UPL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_UP_LOAD_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_TERM_UPL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_RDDWN_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_RDUPL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_LOAD_DOM_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_STR_DOM_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEL_DOM_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_CRE_PI_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEL_PI_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_START_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_STOP_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_RESUME_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_RESET_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_KILL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GET_PI_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_MV_READ_EN != REQ_RESP_DIS) /* VM Read variable(s) */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_RDVARS_EN != REQ_RESP_DIS) /* General VM Rd var's */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_WRITE_EN != REQ_RESP_DIS) /* VM Write variable(s) */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_WRVARS_EN != REQ_RESP_DIS) /* General VM WR var's */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEFVAR_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEFSCAT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETSCAT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DELVAR_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_DEFTYPE_EN != REQ_RESP_DIS) /* VM DefineType */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEFTYPE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETTYPE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DELTYPE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_TAKECTRL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_RELCTRL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEFINE_SEM_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DELETE_SEM_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_REP_SEMSTAT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_REP_SEMPOOL_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_REP_SEMENTRY_EN!= REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_JWRITE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_JCREATE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_JDELETE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_DEFEC_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DELEC_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETECA_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_REPECS_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_ALTECM_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_TRIGE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEFEA_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DELEA_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETEAA_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_REPEAS_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DEFEE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_DELEE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETEEA_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_REPEES_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_ALTEE_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_EVNOT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_ACKEVNOT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETAS_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_GETAES_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_INPUT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif +#if (MMS_OUTPUT_EN != REQ_RESP_DIS) +#error Unsupported service must not be enabled. +#endif + +#if (MMS_MV_FOPEN_EN != REQ_RESP_DIS) /* VM FileOpen */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_FREAD_EN != REQ_RESP_DIS) /* VM FileRead */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_FCLOSE_EN != REQ_RESP_DIS) /* VM FileClose */ +#error Unsupported service must not be enabled. +#endif +#if (MMS_MV_FCOPY_EN != REQ_RESP_DIS) /* VM FileCopy */ +#error Unsupported service must not be enabled. +#endif diff --git a/mms/myftp.cpp b/mms/myftp.cpp new file mode 100644 index 0000000..b05a054 --- /dev/null +++ b/mms/myftp.cpp @@ -0,0 +1,90 @@ + +#include +#include +#include "../misc/ftp.h" +#include +using namespace std; + +#include "db_interface.h" + +static int demo() +{ + //¼ + CFTP ftpclient; + int err; + err = ftpclient.ftp_connect("192.168.1.103"); + //err = ftpclient.ftp_connect("103.1.168.192"); + if(err){ + puts("connect ftp server failed"); + exit(-1); + } + puts("connect ok"); + err = ftpclient.ftp_login("root","9.9cyj"); + if(err){ + puts("login failed"); + exit(-1); + } + puts("login ok"); + err = ftpclient.ftp_download("loc_download.txt","/etc/jcf_vesion.txt"); + if(err){ + puts("download failed"); + exit(-1); + } + puts("download ok"); + err = ftpclient.ftp_upload("../comtrade/mms2db_template.csv","/22/njcn/","mms2db_template.csv"); + if(err){ + puts("upload failed"); + exit(-1); + } + remove(""); + puts("upload ok"); + err = ftpclient.ftp_quit(); + if(err){ + puts("quit failed"); + exit(-1); + } + puts("you quit"); + return 0; +} + +int my_ftp_upload(char* ip,char* user,char* pwd, char* localfile,char* remotepath,char* remotefilename) +{ + //¼ + CFTP ftpclient; + int err; + + err = ftpclient.ftp_connect(ip); + if(err){ + puts("connect ftp server failed"); + return(-1); + } + puts("ftp connect ok"); + + //err = ftpclient.ftp_login("njcn","Pq54321"); + err = ftpclient.ftp_login(user,pwd); + if(err){ + puts("ftp login failed"); + return(-1); + } + puts("ftp login ok"); + + err = ftpclient.ftp_upload(localfile,remotepath,remotefilename); + if(err){ + puts("ftp upload failed"); + return(-1); + } + puts("ftp upload ok"); + + remove(localfile); + + err = ftpclient.ftp_quit(); + if(err){ + puts("ftp quit failed"); + return(-1); + } + puts("ftp quit"); + return 0; +} + + + diff --git a/mms/oracle_process.cpp b/mms/oracle_process.cpp new file mode 100644 index 0000000..02f62b4 --- /dev/null +++ b/mms/oracle_process.cpp @@ -0,0 +1,124 @@ +/** +* @file: $RCSfile: oracle_process.cpp,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:51 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: oracle_process.cpp,v 1.1 2018/11/24 06:54:51 lizhongming Exp $ +* +*/ + + + +#include +using namespace std; +#include + +#define OTL_ORA11G +#include "otlv4.h" // include the OTL 4 header file + +otl_connect db; // connect object + +int OTLConnect (const char* pszConnStr) +{ + try + { + otl_connect::otl_initialize(); // initialize OCI environment + db.rlogon(pszConnStr); + //db.auto_commit_off ( ); + printf ( "CONNECT: OK!\n" ); + } + catch(otl_exception& p) + { // intercept OTL exceptions + printf ( "Connect Error: (%s) (%s) (%s)\n",p.msg, p.stm_text, p.var_info ); + return -1; + } + return 0; +} + +int OTLDisconnect() +{ + //db.commit ( ); + db.logoff(); + printf ( "DISCONNECT: OK!\n" ); + return 0; +} + + + +void insert() + // insert rows into table +{ + otl_stream o(50, // buffer size + "insert into test_tab values(:f1,:f2)", + // SQL statement + db // connect object + ); + char tmp[32]; + for(int i=1;i<=100;++i){ + sprintf(tmp,"Name%d",i); + // the old way (operators >>() / <<()) is available as always: + o<=:f and f1<=:f*2", + // SELECT statement + db // connect object + ); + // create select stream + + float f1=0; + char f2[31]; + // the old way (operators >>() / <<()) is available as always: + i<<8; // assigning :f = 8 + // C++98/03 compiler + while(!i.eof()){ // while not end-of-data + i>>f1>>f2; + cout<<"f1="< + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 32000 + 4 + 0 + + + + 50 + 1 + 120 + 5 + 49 00 01 53 49 53 43 09 01 01 + + + + + 1024 + 4 + 4 + 8 + 4 + 10 + 120 + 10 + 2 + 2 + + + 1024 + 8 + 50 + + + + + + local1 + 1 3 9999 33 + 33 + 00 00 00 01 + 00 01 + 00 01 + TCP + + + + local1cl + 1 3 9999 33 + 33 + 00 00 00 02 + 00 01 + 00 01 + TCP + + + + + + remote1 + 1 3 9999 23 + 23 + 00 00 00 01 + 00 01 + 00 01 + 127.0.0.1 + + + + + + + diff --git a/mms/parse_xml.c b/mms/parse_xml.c new file mode 100644 index 0000000..4712cca --- /dev/null +++ b/mms/parse_xml.c @@ -0,0 +1,291 @@ +/** + * @file: $RCSfile: parse_xml.c,v $ + * @brief: $xml + * + * @version: $Revision: 1.5 $ + * @date: $Date: 2018/12/29 03:18:14 $ + * @author: $Author: lizhongming $ + * @state: $State: Exp $ + * + * @latest: $Id: parse_xml.c,v 1.5 2018/12/29 03:18:14 lizhongming Exp $ + */ +#include +#include "rdb_client.h" +#include "xmltools.h" + +//int comtrade_remain_file_num = 2147483647; +int comtrade_remain_file_num = 0; + +//extern rdb_t* g_rdb ; +extern node_t* g_node ; +extern char g_my_conf_fname[256]; +extern apr_pool_t* g_init_pool; +extern apr_pool_t* g_run_pool; +extern pt61850app_t* g_pt61850app; +//extern apr_time_t g_file_valid_time; +//extern byte_t g_file_name_len; +//extern byte_t g_file_time_from; + + +apr_status_t app_get_private_config(const char *myfilename) +{ + //apr_status_t rv = APR_SUCCESS; + char *v = NULL; + char *str = NULL; + + assert(myfilename); + + if (xml_get_elem(myfilename, "//pt61850netd/mmsOpTimeout/",&v) == APR_SUCCESS) { + if((str = strtok(v,","))) + g_pt61850app->mmsOpTimeout = atoi(str); + } + else { + echo_warn("Read xml error. error at mmsOpTimeout.\n"); + return APR_EBADDATE; + } + + if (xml_get_elem(myfilename, "//pt61850netd/giTime/",&v) == APR_SUCCESS) { + if((str = strtok(v,","))) + g_pt61850app->giTime = atoi(str); + } + else { + echo_warn("Read xml error. error at giTime.\n"); + return APR_EBADDATE; + } + + if (xml_get_elem(myfilename, "//pt61850netd/cliAsuffixFrom/",&v) == APR_SUCCESS) { + if((str = strtok(v,","))) + g_pt61850app->rptSuffix[0][0] = atoi(str); + } + else { + echo_warn("Read xml error. error at cliAsuffixFrom .\n"); + return APR_EBADDATE; + } + if (xml_get_elem(myfilename, "//pt61850netd/cliAsuffixTo/",&v) == APR_SUCCESS) { + if((str = strtok(v,","))) + g_pt61850app->rptSuffix[0][1] = atoi(str); + } + else { + echo_warn("Read xml error. error at cliAsuffixTo .\n"); + return APR_EBADDATE; + } + + + if (xml_get_elem(myfilename, "//pt61850netd/accPath/",&v) == APR_SUCCESS) { + if((str = strtok(v,","))) + strcpy(g_pt61850app->accPath,str_trim_both(str," \t\'" ) ); + } + else { + echo_warn("Read xml error. error at accPath .\n"); + return APR_EBADDATE; + } + + if (xml_get_elem(myfilename, "//pt61850netd/comtrade_remain_file_num/",&v) == APR_SUCCESS) { + if((str = strtok(v,","))) + comtrade_remain_file_num = atoi(str); + } + + return APR_SUCCESS; +} + + + +//************ ReportControl.xml ***************// +#define REPORTCONTROL_FILE_PATH CONFIG_FILEPATH + +/* + +104,1,2 +*/ +int init_rptctrl_by_count(LD_info_t* LD_info,int rptcount) +{ + int j,i; + LD_info->rptcount = rptcount; + LD_info->rptinfo = apr_pcalloc( g_init_pool,rptcount*sizeof(rptinfo_t*) ); + for(j=0; jrptinfo[j] = apr_pcalloc( g_init_pool,sizeof(rptinfo_t) ); + LD_info->rptinfo[j]->LD_info = LD_info; + LD_info->rptinfo[j]->m_LastRegisterFailedTime = sGetMsTime() -10*60*1000; + LD_info->rptinfo[j]->m_LastUnRegisterFailedTime = sGetMsTime() -10*60*1000; + LD_info->rptinfo[j]->IntgPd = 60; + LD_info->rptinfo[j]->m_rcb_info = NULL; + LD_info->rptinfo[j]->rpt_registered = FALSE; + LD_info->rptinfo[j]->m_curRptSuffix = -1; + for(i=0; i<8; i++) + LD_info->rptinfo[j]->m_EntryID[i] = 0xff; + } + + return 0; +} + +//ReportControl: װID,CPUID,ID,RCBName, intgPd, dchg, qchg, dupd, period ,gi, ʵǷӺ׺, +// seqNum, timeStamp, reasonCode, dataSet, dataRef, bufOvfl, entryID, configRef, segmentation +//104,1,1,brcbDin,60,1,0,0,1,0,yes,1,1,0,1,1,1,1,1,0 +int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf) +{ + char *str = NULL; + char *tmp_str = NULL; + rptinfo_t *rptinfo; + + assert( (rptno+1) <= LD_info->rptcount ) ; + rptinfo = LD_info->rptinfo[rptno]; + if(!(str = strtok(buf,","))) + return 1; + + rptinfo->rptNo = rptno;//CZY 2023-08-16 WW 2022-11-14 ӱţжϱǷ꣬Խݴ + + tmp_str = apr_pstrdup(g_init_pool,str); + rptinfo->rptID = str_trim_both(tmp_str," \t\'" ); + if((str = strtok(NULL,","))) rptinfo->IntgPd = atoi(str); else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&rptinfo->TrgOpt, TRGOPS_BITNUM_DATA_CHANGE); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&rptinfo->TrgOpt, TRGOPS_BITNUM_QUALITY_CHANGE); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&rptinfo->TrgOpt, TRGOPS_BITNUM_DATA_UPDATE); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&rptinfo->TrgOpt, TRGOPS_BITNUM_INTEGRITY); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&rptinfo->TrgOpt, TRGOPS_BITNUM_GENERAL_INTERROGATION); + }else return 1; + if(!(str = strtok(NULL,","))) + return 1; + tmp_str = apr_pstrdup(g_init_pool,str); + if (strcmp("yes", str_trim_both(tmp_str," \t\'" ) )==0 ) + rptinfo->instanceNeedSuffix = TRUE; + else + rptinfo->instanceNeedSuffix = FALSE; + + // seqNum, timeStamp, reasonCode, dataSet, dataRef, bufOvfl, entryID, configRef, segmentation + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_SQNUM); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_TIMESTAMP); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_REASON); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_DATSETNAME); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_DATAREF); + }else return 1; + if((str = strtok(NULL,","))) { //only valid in RCB_TYPE_IEC_BRCB + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_BUFOVFL); + }else return 1; + if((str = strtok(NULL,","))) { //only valid in RCB_TYPE_IEC_BRCB + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_ENTRYID); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_CONFREV); + }else return 1; + if((str = strtok(NULL,","))) { + //SUBSEQNUM is only set by the server, so don't try to set it. + if ( atoi(str) ) BSTR_BIT_SET_ON(rptinfo->OptFlds, OPTFLD_BITNUM_SUBSEQNUM); + }else return 1; + if((str = strtok(NULL,","))) { + rptinfo->report_PQ_type = atoi(str); + }else return 1; + + if ((str = strtok(NULL, ","))) { //CZY 2023-08-16 WW 2022-11-14䱨־ + rptinfo->flickerflag = atoi(str); + if (rptinfo->flickerflag == 0) { + LD_info->rptRecvFlag += 0x01 << rptno; + printf(" LD_info->rptRecvFlag=%d \n", LD_info->rptRecvFlag); + } + else if(rptinfo->flickerflag == 2) + { + LD_info->rptPstRecvFlag += 0x01 << rptno; + printf(" LD_info->rptPstRecvFlag=%d \n", LD_info->rptPstRecvFlag); + } + } + else return 1; + + return 0; +} + + +////////////////////////////////////////////////////////// +//************ LogControl.xml ***************// + +/* + +104,1,2 +*/ +int init_logctrl_by_count(LD_info_t* LD_info,int logcount) +{ + int j; + LD_info->logcount = logcount; + LD_info->loginfo = apr_pcalloc(g_init_pool, logcount * sizeof(loginfo_t*)); //new loginfo_t*[logcount]; + for(j=0; jloginfo[j] = apr_pcalloc(g_init_pool, sizeof(loginfo_t));//new loginfo_t[1]; + LD_info->loginfo[j]->LD_info = LD_info; + + LD_info->loginfo[j]->IntgPd = 600; + //LD_info->loginfo[j]->m_lcb_info = NULL; + } + + return 0; +} + +// +// 106,2,1,LLN0$LG$lcStatisticData,dsStatisticData,PQM1,0,600000,1,0,0,0 +// 106,2,2,LLN0$LG$lcFlickerData,dsFlickerData,PQM1,0,600000,1,0,0,0 +int fill_logctrl_by_cfg(LD_info_t* LD_info,int logno,char *buf,char* devtype) +{ + char *str = NULL; + char *tmp_str = NULL; + loginfo_t *loginfo; + + assert( (logno+1) <= LD_info->logcount ) ; + loginfo = LD_info->loginfo[logno]; + + if(!(str = strtok(buf,","))) + return 1; + tmp_str = apr_pstrdup(g_init_pool,str); + loginfo->lcbName = str_trim_both(tmp_str," \t\'" ); + + if(!(str = strtok(NULL,","))) + return 1; + tmp_str = apr_pstrdup(g_init_pool,str); + loginfo->datasetName = str_trim_both(tmp_str," \t\'" ); + + if(!(str = strtok(NULL,","))) + return 1; + //tmp_str = apr_pstrdup(g_init_pool,str); + apr_snprintf(loginfo->logName,sizeof(loginfo->logName), devtype,LD_info->cpuno);//PQM1 + + if((str = strtok(NULL,","))) loginfo->reasonCode = atoi(str); else return 1; + if((str = strtok(NULL,","))) loginfo->IntgPd = atoi(str); else return 1; + + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&loginfo->TrgOpt, TRGOPS_BITNUM_DATA_CHANGE); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&loginfo->TrgOpt, TRGOPS_BITNUM_QUALITY_CHANGE); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&loginfo->TrgOpt, TRGOPS_BITNUM_DATA_UPDATE); + }else return 1; + if((str = strtok(NULL,","))) { + if ( atoi(str) ) BSTR_BIT_SET_ON(&loginfo->TrgOpt, TRGOPS_BITNUM_INTEGRITY); + }else return 1; + + loginfo->start_time = apr_time_now();// - apr_time_from_sec(600);// + loginfo->end_time = apr_time_now(); + //loginfo->last_checktime = 0.0f;//-160*1000;//0.0f; + loginfo->need_steady = 0; + loginfo->need_voltage = 0; + + //printf(" loginfo->logName=%s \n", loginfo->logName); + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/mms/rdb_client.c b/mms/rdb_client.c new file mode 100644 index 0000000..4c5572c --- /dev/null +++ b/mms/rdb_client.c @@ -0,0 +1,591 @@ +/** + * @file: $RCSfile: rdb_client.c,v $ + * @brief: $PROFIBUS SSRTDB + * + * @version: $Revision: 1.11 $ + * @date: $Date: 2020/10/28 05:21:18 $ + * @author: $Author: lizhongming $ + * @state: $State: Exp $ + * + * @latest: $Id: rdb_client.c,v 1.11 2020/10/28 05:21:18 lizhongming Exp $ + */ +#include + +#include "rdb_client.h" +#include "db_interface.h" +#include "node.h" +#include //lnk20250114̨ӻ + +/*lnk10-10 *///////////////////////////////// +extern int HTTP_PORT; +extern int SOCKET_PORT; +extern int G_TEST_FLAG; +extern int g_front_seg_index; +extern int g_front_seg_num; + +#include "../include/rocketmq/SimpleProducer.h" +//////////////////////////////////////////// +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR* SD_CONST thisFileName = __FILE__; +#endif + +extern RPT_TYPEIDS g_rpt_typeids; +//ied_info_t *my_info; + +extern apr_pool_t* g_root_pool; +uint8_t set_mx_q; +//rdb_t *g_rdb = NULL; +node_t* g_node = NULL; +extern char g_my_conf_fname[256]; +apr_pool_t* g_init_pool; +apr_pool_t* g_run_pool; +apr_pool_t* g_temp_dev_pool; + +//lnk20250114̨ӻ +pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + +extern char g_onlyIP[255]; //ֱijIPΪ +//Ϊ +uint8_t set_mx_q; + +pt61850app_t* g_pt61850app; + +//application_t g_sysfile_app; //ϵͳļӦϢṹ +//int g_sysfile_appid = -1; +//char *g_sysfile_filedir; +//byte_t g_Master; +//byte_t g_protect_file; //0:ٻ¼ļ 1:ٻ¼ļ +//apr_time_t g_file_valid_time; //ֻٻָʱеļӣ +//byte_t g_file_name_len; //ļ洢󳤶ȣĬΪ40Ϊ0ʱʾⳤ +//byte_t g_file_time_from; //ļЧʱȡֵδ0ļ1ȡϵͳʱ + +static void* APR_THREAD_FUNC rtdb_worker(apr_thread_t* thd, void* data); + +static apr_status_t pt61850app_init(); +//static apr_status_t app_process_command(command_t *cmd); + +/////////////////////////////////////////////////////////////////////////////// +extern int three_secs_enabled; + +/////////////////////////////////////////////////////////////////////////////// + +//WW 2023-08-22 start +int server_socket = -1; +extern int g_iOTLFlag; +//WW 2023-08-22 end +/////////////////////////////////////////////////////////////////////////////// + +static apr_status_t pt61850app_init() +{ + apr_status_t rv; + if ((g_pt61850app = apr_pcalloc(g_run_pool, sizeof(pt61850app_t))) == NULL) + return APR_ENOMEM; + + rv = apr_pool_create(&(g_pt61850app->tmp_pool), g_root_pool); + if (rv != APR_SUCCESS) { + return rv; + } + g_pt61850app->chnl_counts = 0; + + g_pt61850app->initNum = 0; + + return APR_SUCCESS; +} + +static apr_status_t allocate_LD_chnl_ext_mem() +{ + int iedno, cpuno, chnl_no; + ied_t* ied; + ied_usr_t* ied_usr; + chnl_usr_t* chnl_usr; + + g_pt61850app->chnl_counts = 0; + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = apr_pcalloc(g_init_pool, sizeof(ied_usr_t)); + ied->usr_ext = ied_usr; + if (ied_usr == NULL) + return APR_ENOMEM; + ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000 * 0.5; + ied_usr->LD_info = apr_pcalloc(g_init_pool, ied->cpucount * sizeof(LD_info_t)); + if (ied_usr->LD_info == NULL) + return APR_ENOMEM; + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { + ied_usr->LD_info[cpuno].ied = ied; + ied_usr->LD_info[cpuno].cpuno = ied->cpuinfo[cpuno].addr; + ied_usr->LD_info[cpuno].ht_fcd = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno].ht_full_fcda = apr_hash_make(g_init_pool); + ied_usr->LD_info[cpuno].rptcount = 0; + } + + for (chnl_no = 0; chnl_no < ied->chncount; chnl_no++) { + chnl_usr = apr_pcalloc(g_init_pool, sizeof(chnl_usr_t)); + ied->channel[chnl_no].connect = chnl_usr; + chnl_usr->chnl = &(ied->channel[chnl_no]); + chnl_usr->chnl_id = chnl_no; + chnl_usr->m_state = CHANNEL_DISCONNECTED; + chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + } + g_pt61850app->chnl_counts += ied->chncount; + } + return APR_SUCCESS; +} + +static apr_status_t read_DEV_idx_from_db() +{ + int ret; + int iedno, cpuno; + ied_t* ied; + ied_usr_t* ied_usr; + LD_info_t* LD_info; + loginfo_t* loginfo = NULL; + int len, tmp; + + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = GET_IEDEXT_ADDR(ied); + //read_DEV_Index_from_db(ied->channel[0].addr, &ied_usr->dev_idx); + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info->LD_name == NULL) + continue; + len = strlen(LD_info->LD_name); + tmp = LD_info->LD_name[len - 1] - '0'; + LD_info->line_id = ied_usr->dev_idx * 10 + tmp; + //ret = read_line_infos_from_db(LD_info->line_id, &LD_info->SubV_Index,&LD_info->Dev_Index,&LD_info->Sub_Index,&LD_info->GD_Index); + if (ret != TRUE) + LD_info->line_id = -1; + if (LD_info->loginfo) { + loginfo = LD_info->loginfo[0]; + //read_updatetime_from_db(ied->channel[0].addr, &loginfo->start_time); + } + } + } + return APR_SUCCESS; +} + +apr_status_t init_rdb() +{ + apr_status_t rv; + // driver_t* driver; + rv = apr_pool_create(&g_init_pool, g_root_pool); + if (rv != APR_SUCCESS) { + return rv; + } + rv = apr_pool_create(&g_run_pool, g_root_pool); + if (rv != APR_SUCCESS) { + return rv; + } + rv = apr_pool_create(&g_temp_dev_pool, g_root_pool); + if (rv != APR_SUCCESS) { + return rv; + } + + g_node = apr_pcalloc(g_run_pool, sizeof(node_t)); + if (rv != APR_SUCCESS) { + return rv; + } + //my_info = apr_pcalloc(g_run_pool,sizeof(ied_info_t)); + rv = pt61850app_init(); + if (rv != APR_SUCCESS) { + return rv; + } + + /*rv = parse_json_cfg(); + if ( rv != APR_SUCCESS) { + echo_errg("Failed to parse json define xml file! \n"); + return rv; + }*/ + + init_config(); + GetServerIndexFromDB(); +/*lnk10-10*/ + //Ӳwebӿ + //rv = parse_device_web_test_ext(); + //rv = parse_device_web_test_dev(); + //rv = parse_device_web_test_front_read(); + //rv = parse_device_web_test_front_write(); + rv = parse_device_cfg_web(); + + //rv = parse_device_cfg(); + //rv = parse_device_cfg_json(); + //rv = parse_device_cfg_pg(); + if (rv != APR_SUCCESS) { + echo_errg("Parsed device config xml file with error,try to run! \n"); + return rv; + } +/*lnk10-10*/ + //rv = parse_line_cfg_web(); ϲն̨ + + //rv = parse_line_cfg(); + //rv = parse_line_cfg_pg(); + + /*lnk10-10*/ + rv = parse_model_cfg_web(); + if (rv != APR_SUCCESS) { + echo_errg("Parsed model with error,try to run! \n"); + return rv; + } + + + //OTL_Select_xmlModel(); //xmlģݿȡ + Set_xml_nodeinfo();//xmlģ + + rv = parse_rpt_log_ini();//ʼ + if (rv != APR_SUCCESS) { + echo_errg("Failed to parse report log define ini file! \n"); + return rv; + } + + if (app_get_private_config(g_my_conf_fname) != APR_SUCCESS) { + echo_errg("Failed when processing private configuration\n"); + return APR_EGENERAL; + } + init_rem_dib_table(); + return APR_SUCCESS; +} + +extern int SOCKETENABLE; +extern int HTTPENABLE; +/*--------------------------- Լʼ -----------------------------------*/ +apr_status_t run_protocol() +{ + apr_status_t rv; + apr_thread_t* rtdb_thread; + // apr_thread_t* mms_thread; + static apr_threadattr_t* worker_attr = NULL; + + init_MMS(); + + if (worker_attr == NULL) + if ((rv = apr_threadattr_create(&worker_attr, g_run_pool)) != APR_SUCCESS) + return rv; + + if ((rv = apr_threadattr_detach_set(worker_attr, 1)) != APR_SUCCESS) + return rv; + + if ((rv = apr_threadattr_stacksize_set(worker_attr, 1920 * 1024)) != APR_SUCCESS) + return rv; + + rv = apr_threadattr_guardsize_set(worker_attr, 4096); + if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) + return rv; + + if ((rv = apr_thread_create(&rtdb_thread, worker_attr, rtdb_worker, NULL, g_run_pool)) != APR_SUCCESS) + return rv; + + try_start_kafka_thread(); + + //lnk20241213mq߳ + try_start_mqconsumer_thread(); + + ///////////////////WW 2023-08-22 ݿWebSocket߳ + if (g_onlyIP[0] != 0 || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_ALL_DATA_BASE_NODE_ID) + { + printf("g_onlyIP[0] != 0!\n\a"); + } + else + { + printf("g_onlyIP[0] == 0!\n\a"); + if(1 == SOCKETENABLE) + { + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket == -1) { + printf("Web Socket failed,error msg=%s\n\a", strerror(errno)); + exit(1); + } + + int ServerPort = 13000;//WW Ҫݿıжȡ + if (g_node_id == STAT_DATA_BASE_NODE_ID)//ͳƲɼ + ServerPort = SOCKET_PORT + STAT_DATA_BASE_NODE_ID + g_front_seg_index; + else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {// + ServerPort = SOCKET_PORT + RECALL_HIS_DATA_BASE_NODE_ID + g_front_seg_index; + } + else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3ɼ + ServerPort = SOCKET_PORT + THREE_SECS_DATA_BASE_NODE_ID + g_front_seg_index; + } + else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//̬¼ + ServerPort = SOCKET_PORT + SOE_COMTRADE_BASE_NODE_ID + g_front_seg_index; + } + + struct sockaddr_in server_sockaddr; + memset(&server_sockaddr, 0, sizeof(server_sockaddr)); + + server_sockaddr.sin_family = AF_INET; + server_sockaddr.sin_port = htons(ServerPort); + server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(server_socket, (struct sockaddr*)&server_sockaddr, sizeof(server_sockaddr)) == -1) + { + printf("bind failed, error msg = %s\n\a", strerror(errno)); + printf("bind ServerPort is = %s\n\a", ServerPort); + exit(1); + } + + if (listen(server_socket, 20) == -1) + { + printf("listen server_socket= %d,ServerPort= %d failed,error msg = %s\n\a", server_socket, ServerPort, strerror(errno)); + exit(1); + } + printf("\n listen server_socket= %d,ServerPort= %d,wait for Web Socket client connecting......\n", server_socket, ServerPort); + + printf("try_start_socket_thread \n"); + try_start_socket_thread(); + } + if(HTTPENABLE) + { + //lnk20241029http߳/////////////////////////////////////////////////////////////////////////////////////////////// + if (g_node_id == STAT_DATA_BASE_NODE_ID)//ͳƲɼ + HTTP_PORT = HTTP_PORT + STAT_DATA_BASE_NODE_ID + g_front_seg_index; + else if (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) {// + HTTP_PORT = HTTP_PORT + RECALL_HIS_DATA_BASE_NODE_ID + g_front_seg_index; + } + else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID) {//3ɼ + HTTP_PORT = HTTP_PORT + THREE_SECS_DATA_BASE_NODE_ID + g_front_seg_index; + } + else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) {//̬¼ + HTTP_PORT = HTTP_PORT + SOE_COMTRADE_BASE_NODE_ID + g_front_seg_index; + } + printf("try_start_web_http_thread \n"); + try_start_web_http_thread(); + printf("try_start_http_thread \n"); + try_start_http_thread(); + //lnk20241029http߳/////////////////////////////////////////////////////////////////////////////////////////////////// + } + } + + if (1 == G_TEST_FLAG) { + //lnkmqģ + printf("try_start_mqtest_thread \n"); + try_start_mqtest_thread(0,NULL); + } + + if (1 == g_iOTLFlag) { + printf("try_start_sql_thread \n"); + try_start_sql_thread(); + } + else + printf("sql_thread ignore \n"); + + + printf("try_start_ontimer_thread \n"); + try_start_ontimer_thread(); + + + + //OTLTestSelect();//ݿ + + + ///////////////////WW end + + return APR_SUCCESS; +} + +extern uint32_t g_dead_lock_counter; +extern uint32_t g_thread_blocked_times; +/*--------------------------- ʵʱ߳ -----------------------------------*/ +static void* APR_THREAD_FUNC rtdb_worker(apr_thread_t* thd, void* data) +{ + // apr_event_t event; + // command_t cmd[1]; + // int i =0; + + /* Maintenance the clients request */ + while (1) { + + /*÷rocketmqϢ lnk10-10*/ + //producer_send0(); + + doCommService();//61850Ϣ + check_3s_config();//3ݽ̶ȡ3봥 + + pthread_mutex_lock(&mtx); + CheckNextNotConnectedChannel();//гӽж״̬ + pthread_mutex_unlock(&mtx); + + pthread_mutex_lock(&mtx); + CheckAllConnectedChannel();//桢־١ + pthread_mutex_unlock(&mtx); + + //check_recall_config();//ٽ̶ȡϢ + create_recall_xml();//ɴxmlļ + + check_ledger_update();//lnk20250113ȡ̨˸£̨˸ + + //Check_Recall_Config(); + /*if ((g_protect_file) && (g_pt61850app->initNum>=MIN_INIT_NUM) ) { + tryCallWaveList_in_AllIeds(); + }*/ + //clear_old_comtrade_files(); + check_disk_quota();//жϴ̿ռ + apr_pool_clear(g_pt61850app->tmp_pool);//ʱ + g_dead_lock_counter = 0; + g_thread_blocked_times = 0;//߳ + } + + echo_msg("rtdb worker thread terminated..."); +} + +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// + +void Set_val_from_61850rpt(element_t* elem, double v) +{ + GET_DOTEXT_ADDR(elem)->DataStatus |= VALUE_REACHED; + GET_DOTEXT_ADDR(elem)->m_v = v; +} + +int Set_q_from_61850rpt(char* q) +{ + int quality = 0; + if (q[0] == '0' && q[1] == '0') + quality = 0; + else + quality = 1; + return quality; + //set_rpt_QualityFlag(quality); +} + +#define TIME_T_2036 (66*365* SECONDS_PER_DAY) + + +apr_time_t convert_btod_to_apr_time(MMS_BTOD* btod) +{ + MMS_BTIME6 btime6; + btime6.day = btod->day; + btime6.ms = btod->ms; + return convert_btime6_to_apr_time(&btime6); +} + +apr_time_t convert_btime6_to_apr_time(MMS_BTIME6* bTime6) +{ + apr_time_t ticks; + if ((TIME_T_1984_JAN_1 + (bTime6->day * SECONDS_PER_DAY)) > TIME_T_2036) { + echo_warn("ʱ󣬳2036꣡"); + } + ticks = TIME_T_1984_JAN_1; + ticks += (bTime6->day * SECONDS_PER_DAY); + ticks *= 1000; + ticks += bTime6->ms; + ticks *= 1000; + return ticks; +} + + + + +/* +61850 +λ ֵ +0-1 Good 00 + Invalid 01 + Reserved 10 + Questionable11 +2 Overflow +3 OutofRange +4 BadReference +5 Oscillatory +6 Failure +7 OldData +8 Inconsistent +9 Inaccurate +10 Source 0(process)/1(Substituted) +11 Test +12 OperatorBlocked +*/ +/* +60870 +λ ֵ +0 +1 +2 +3 +4 +5 ȡ +6 ǵǰֵ +7 Ч +*/ +byte_t get_mx_q_from_61850(char* q_61850) +{ + QDS q; + + q.bits = 0; + if (set_mx_q) { + if (!strlen(q_61850)) { + return q.bits; + } + if (!strcmp("0000000000000", q_61850)) { + return q.bits; + } + if (q_61850[0] == '0' && q_61850[1] == '1') + q.parts.IV = 1; + + if (q_61850[0] == '1' && q_61850[1] == '1' && q_61850[7] == '1') + q.parts.NT = 1; + + if (q_61850[2] == '1') + q.parts.OV = 1; + + if (q_61850[12] == '1') + q.parts.BL = 1; + + if (q_61850[10] == '1') + q.parts.SB = 1; + } + + return q.bits; +} + +/* +60870 +λ ֵ +0 +1 +2 +3 +4 +5 ȡ +6 ǵǰֵ +7 Ч +*/ +byte_t get_st_q_from_61850(char* q_61850) +{ + SIQ q; + + q.bits = 0; + if (!strlen(q_61850)) { + return q.bits; + } + if (!strcmp("0000000000000", q_61850)) { + return q.bits; + } + if (q_61850[0] == '0' && q_61850[1] == '1') + q.parts.IV = 1; + + if (q_61850[0] == '1' && q_61850[1] == '1' && q_61850[7] == '1') + q.parts.NT = 1; + + if (q_61850[12] == '1') + q.parts.BL = 1; + + if (q_61850[10] == '1') + q.parts.SB = 1; + + return q.bits; +} + +byte_t get_pulse_q_from_61850(char* q_61850) +{ + if (!strlen(q_61850)) { + return 0; + } + if (q_61850[0] == '0' && q_61850[1] == '1') + return 1; + else + return 0; +} + + +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// diff --git a/mms/rdb_client.h b/mms/rdb_client.h new file mode 100644 index 0000000..600eb62 --- /dev/null +++ b/mms/rdb_client.h @@ -0,0 +1,509 @@ +/** + * @file iec103ttylink.h + * @brief IEC61850 rdb ͷļ + * + * @version $Revision: 1.18 $ + * @date $Date: 2018/12/29 12:30:29 $ + * @author $Author: lizhongming $ + * @state $State: Exp $ + * @latest $Id: rdb_client.h,v 1.18 2018/12/29 12:30:29 lizhongming Exp $ + */ + +#ifndef _RDB_CLIENT_H_XSDFSDFSEFS15156SFS +#define _RDB_CLIENT_H_XSDFSDFSEFS15156SFS + +#include "interface.h" +#include "ied.h" +#include "node.h" + +//lnk20250113Ӱ̨˶ͷļ +#include "../json/save2json.h" +#include + +//ļЧʱȡֵ +#define FROM_FILE_NAME (0) +#define FROM_SYSTEM (1) + +//ͨļŵĿ¼ +#define GENERAL_PREFIX "0_0" +#define GENERAL_PATH "0_0\\19700101\\00" + +//iec report ݵ״̬ +#define VALUE_REACHED (0x01) // ״̬ңֵյ +#define Q_REACHED (0x02) // յ +#define T_REACHED (0x04) // ʱյ +#define REASON_REACHED (0x08) // ԭյ + +//CHANNELSTATE macro defines +#define CHANNEL_CONNECTING (0x01) // +#define CHANNEL_CONNECTED (0x02) // +#define CHANNEL_DISCONNECTING (0x03) // +#define CHANNEL_DISCONNECTED (0x04) // + + +#define RELAY_SELECT (0x01) // +#define RELAY_RUN (0x02) // +#define RELAY_CANCEL (0x03) // + +#define MIN_INIT_NUM (10) //·ȫʼٴΪԽٻ¼ļ +#define NEXT_CONNECT_TIME (10000) //һʧܺ´ʱ10*1000=10s + +#define MAX_SAME_FCDNAME_OBJECTS (500) // for PQװãij64 2016-5-10 //һFCDֳɶĸ һ ACT󣬷ֳgeneralphsabc + +/** ======================㽭涼˳չͬڹ============================ */ +/* +16:ֵʽբ +17:ͬںբ +18:ͬںբ +19:ѹբ +CHECK_BY_SETTING CHECK_U Ӧ˳Ʊͬңصĵһңص +CHECK_NOTHING CHECK_SYN Ӧ˳Ʊͬңصĵڶңص +*/ +#define CHECK_START_QU 16 +#define CHECK_BY_SETTING 0 +#define CHECK_NOTHING 1 +#define CHECK_SYN 2 +#define CHECK_U 3 + +#define DEFAULT_EDIT_FXDAREANO (0x80FE) /**< Ĭϱ༭ֵ */ +#define FIXED_AREA_GRP_DOT2_EDIT_AREA (2) /**< ֵ->༭ֵ */ + +extern unsigned int g_node_id; + +typedef struct element_usr_t element_usr_t; +typedef struct rptinfo_t rptinfo_t; +typedef struct loginfo_t loginfo_t; +typedef struct LD_info_t LD_info_t; +typedef struct ied_usr_t ied_usr_t; +typedef struct chnl_usr_t chnl_usr_t; +typedef struct autorecall_t autorecall_t; + +typedef struct ied_info_t ied_info_t; +////////////////////////////////////////////////////////// +struct autorecall_t { + long long start; + long long end; + int need_steady; //lnk20241030Ӳ̬̬־ + int need_voltage; +}; +////////////////////////////////////////////////////////// +struct ied_info_t{ + char time[50][20]; + unsigned char name[50][128]; + char value[50][20]; +}; +//lnk20250113̨˸½ṹ/////////////////////////////// +#define MAX_UPDATEA_NUM 300 +typedef struct trigger_update_xml_t trigger_update_xml_t; +struct trigger_update_xml_t{ + int work_update_num; + int new_update_num; + int delete_update_num; + int modify_update_num; + terminal work_updates[MAX_UPDATEA_NUM]; + terminal new_updates[MAX_UPDATEA_NUM]; + terminal delete_updates[MAX_UPDATEA_NUM]; + terminal modify_updates[MAX_UPDATEA_NUM]; +}; + +////////////////////////////////////////////////////////// +#define MAX_TRIGGER_NUM 300 +typedef struct trigger_t trigger_t; +struct trigger_t{ + int dev_idx; + int line_id; + int real_data; + int soe_data; + int limit; + int count; +}; +typedef struct trigger_3s_xml_t trigger_3s_xml_t; +struct trigger_3s_xml_t{ + int work_trigger_num; + int new_trigger_num; + int delete_trigger_num; + int modify_trigger_num; + trigger_t work_triggers[MAX_TRIGGER_NUM]; + trigger_t new_triggers[MAX_TRIGGER_NUM]; + trigger_t delete_triggers[MAX_TRIGGER_NUM]; + trigger_t modify_triggers[MAX_TRIGGER_NUM]; +}; + +///////////////////////////////// +#define MAX_RECALL_NUM 300 +typedef struct recall_t recall_t; +struct recall_t{ + char* line_id; + long long start_time; //ٻ־ʼʱ + long long end_time; //ٻ־ʱ + int need_steady; + int need_voltage; +}; +typedef struct recall_xml_t recall_xml_t; +struct recall_xml_t{ + int work_recall_num; + int new_recall_num; + recall_t work_recalls[MAX_RECALL_NUM]; + recall_t new_recalls[MAX_RECALL_NUM]; +}; + +///////////////////////////////////////////////////////////// +struct element_usr_t{ + char* FCD_ref; + char* FCDA_ref; + char* Full_FCDA_ref; + + double m_v; + char q[14]; //q use 13 bits + systime_t tm; + char reason[7]; // reserve 1 bit, use 5 bits + uint32_t DataStatus; + + int m_num_same_FCD_Objects; +// element_t* m_pSameFCDObjects[MAX_SAME_FCDNAME_OBJECTS]; + + int num_same_FCDA_Objects; +// element_t* pSame_FCDA_Objects[MAX_SAME_FCDNAME_OBJECTS]; + + byte_t is_phase_soe; + byte_t last_soe_status; +}; + +struct rptinfo_t{ + char* rptID; + byte_t instanceNeedSuffix; //ʵǷӺ׺ + byte_t TrgOpt; + byte_t OptFlds [2]; /* 10 bit bitstring but only allow write of 9 bits*/ + uint32_t IntgPd; //ʱ䣨룩 + int report_PQ_type; //ǰͣͳơʵʱsoe¼͵ + + LD_info_t* LD_info; + + int rpt_registered; //Ƿעɹ + byte_t chnl_id; //δעᣬ´ͼעᱨͨ + //עᣬDZעᱨͨ + + RCB_INFO * m_rcb_info; + double m_LastDataTime; //ϴյݵʱ + double m_LastGITime; //ϴGIʱ + double m_LastRegisterFailedTime; //ϴעʧܵʱ + double m_LastUnRegisterFailedTime; //ϴȡעʧܵʱ + byte_t m_EntryID[8]; + int m_curRptSuffix; + int count; //յݵĴ + int rptNo;//CZY 2023-08-17 WW 2022-11-14ӱƥռ + int flickerflag;//CZY 2023-08-17 WW 2022-11-14־ + + int pstflag;//CZY 2023-08-17 WW 2022-11-14Ӷ־ + +}; + +struct loginfo_t{ + char* lcbName; + char* datasetName; + char logName[32]; + uint32_t IntgPd; //ʱ䣨룩 + byte_t reasonCode; + byte_t TrgOpt; + + LD_info_t* LD_info; + //LCB_INFO * m_lcb_info; + apr_time_t start_time; //ٻ־ʼʱ + apr_time_t end_time; //ٻ־ʱ + + //double last_checktime; + int need_steady; + int need_voltage; +}; + +#define QVVR_NUM (256) + +#define QVVR_DATA_NOT_USED (0) +#define QVVR_DATA_RECEIVED (1) +#define QVVR_DATA_PAIRED (2) + +typedef struct QVVR_t QVVR_t; +struct QVVR_t{ + int used_status; + int QVVR_start; + int QVVR_type; + long long QVVR_time; + float QVVR_PerTime; + float QVVR_Amg; + char QVVR_Rptname[128]; + + uint32_t timestamp; +}; +struct LD_info_t{ + char name[256]; + ied_t *ied; + byte_t cpuno; + char *LD_name; + apr_hash_t *ht_fcd; /**< FCD object hash element */ + apr_hash_t *ht_full_fcda; /**< FCDA object hash element */ + int rptcount; /**< report */ + rptinfo_t **rptinfo; /**< rptinfo_t* */ + int read_flag ; //CZY 2023-02-28 жǷ񽫼ǷЧ + + char mp_id[256];//CZY 2023-08-20 룬8afaa + char terminal_code[256];//CZY 2023-08-20 ն˱ + //int ld_ins;//CZY 2023-08-20 ߼豸ʵţ1 + char voltage_level[256];//CZY 2023-08-20 ѹȼ30 + char v_wiring_type[256];//CZY 2023-08-20 ѹ߷ʽ01-ͣ02- + long long time; //CZY 2023-08-20 ʱ() ̨˸ʱ䣬1691656669 + int update_flag;//CZY 2023-08-20 ̨˸±־ 0:keep 2:delete 4:update 8:add + char monitor_status[64]; //lnk20241031״̬ +// + int rptRecvFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,rptRecvFlag=Ч + int rptRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,ÿյrptRecvFlagһжǷ + int rptPstRecvFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,rptRecvFlag=Ч + int rptPstRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14жϱǷ,ÿյrptRecvFlagһжǷ +// +//ʹ + int iUnitOfTime;//CZY 2023-08-17 WW 202212715:43:34 װ¼ʱ䵥λл(0-ms; 1-s) + int iStatOfTime;//CZY 2023-08-17 WW 202212715:48:33 ͳʱ 0-ʱ 1-UTCʱ + int iJournalTime;//CZY 2023-08-17 WW 202212715:52:32 ־ʱ(0-UTCʱ(־¼ļΪUTCʱ); 1-ʱ(־ʱ䡢¼ļUTCʱ עĴ+8Сʱȡ־)) +//ʹ +//־ + int logcount; /**< log */ + loginfo_t **loginfo; /**< loginfo_t* */ +//־ +// + int autorecallflag; + int autorecallcount; + autorecall_t **autorecall; +// +//ʹ + uint32_t group; //add by rzx +//ʹ +//ʵʱ + int line_id; +//ʵʱ +//¼ + int FltNum[256]; +//¼ +//ʵʱ + int real_data; + int soe_data; + int limit; + int count; +//ʵʱ +//ʹ + int SubV_Index; + int Dev_Index; + int Sub_Index; + int GD_Index; +//ʹ + //process QVVR + QVVR_t qvvr[QVVR_NUM]; + int qvvr_idx; + //̬ + //process RDRE + int RDRE_FltNum; + //¼ +}; + +struct ied_usr_t{ + LD_info_t *LD_info; /**< LD */ + int dev_idx; /**< 豸 */ + char dev_type[256]; /**< 豸 */ + char dev_key[256]; /**< 豸Կ */ + char dev_series[256]; /**< 豸ʶ */ + int dev_flag; /**< 豸־ */ + void *cookie; + double last_call_wavelist_time ; //ϴ¼бʱ + + char terminal_id[256];//CZY 2023-08-20 նid8afaa9a15707483a0157262f8e78077d + char org_name[256];//CZY 2023-08-20 λϾ˾ + char maint_name[256];//CZY 2023-08-20 άλϾ˾ + char station_name[256];//CZY 2023-08-20 վ220kV̨ɽ + char tmnl_factory[256];//CZY 2023-08-20 ն˳ңϾԶɷ޹˾ + long long time; //CZY 2023-08-20 ʱ() ̨˸ʱ䣬1691656669 + char tmnl_status[256];//CZY 2023-08-30 ״̬ + char terminal_code[256];//CZY 2023-08-30 ն˱ + int update_flag;//CZY 2023-08-20 ̨˸±־ 0:keep 2:delete 4:update 8:add + +}; + + +struct chnl_usr_t{ + byte_t chnl_id; + char ip_str[20]; + channel_t *chnl; /**< Ӧchannel ָ */ + MVL_NET_INFO *net_info; + MVL_REQ_PEND *m_reqCtrl; //MVL_REQ_PEND + + int m_state; + double m_StartConnectingTime; //οʼ connect ʱ + double m_StartDisconnectingTime; //οʼ disconnect ʱ + double m_ClosedMsTime; //ϴͨرʱ + double m_LastPosRespTime; //ϴο϶Ӧʱ + int m_NegRespTimes; // ۼƷӦ +}; + + + +typedef struct pt61850app_t pt61850app_t; +struct pt61850app_t +{ +// rdb_t *rdb; + node_t *node; +// driver_t *driver; + //byte_t IsMaster; //ǰ״̬ + + //////////////////////////// + uint32_t mmsOpTimeout; //mmsдȵĽʱʱ + //uint32_t relayTimeout; //ңصȴңŷصijʱʱ + uint32_t giTime; //ܲѯʱ + int rptSuffix[2][2]; //ƿ׺ + //char ftp_srv_ip[16]; + //char ftpsrv_path[64]; + //char ftp_user[32]; + //char ftp_password[32]; + char accPath[65]; //װ¼ļ· + //char RcdMadeAddStr[65]; //¼ңŵַ + //uint8_t change_file_name; //ʱǷ޸ļ + uint32_t chnl_counts; + chnl_usr_t **chnl_usr; + apr_pool_t *tmp_pool; // ʱpool + //·ȫʼΪԽٻ¼ļȷװóʼһκʼٻļ + uint8_t initNum; + //ٻļͣΪ0ֻٻӦĿ¼µ¼ļΪ1ٻӦĿ¼µļչ + //uint8_t call_file_type; + //ǰǷֵЧ + uint8_t check_dgtVal;//0У0 +}; + +//Ϊ +extern uint8_t set_mx_q; + +#ifdef _OS_WIN32_ +#pragma pack(push,1) +#endif + + +#ifdef _OS_WIN32_ +#pragma pack(pop) +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +char* str_trim_both(char* temp,const char* pattern) ; + +element_usr_t* GET_DOTEXT_ADDR(element_t *elem); + +ied_usr_t* GET_IEDEXT_ADDR(ied_t *ied); + +ST_RET mms_jread (loginfo_t *loginfo,MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_name,ST_CHAR *logName, apr_time_t start_time,apr_time_t end_time,ST_INT iTimeout, ST_CHAR* ip) ; + +LD_info_t* find_LD_from_cpuId(ied_t* ied,byte_t cpuId); +LD_info_t* find_LD_from_IEDLDName(ied_t* ied, char *IEDLDName); +LD_info_t* find_LD_from_cpuCount_and_LEDRs(ied_t* ied, byte_t cpuCount); + +LD_info_t* find_LD_from_IEDLDName_in_report(ied_t* ied, char *IEDLDName); + +LD_info_t* find_LD_from_element(element_t* elem); + +rptinfo_t* find_rptinfo_from_net_rcb_info(MVL_NET_INFO *net_info,RCB_INFO *rcb_info); + +rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO *rcb_info); + +void get_rpt_inst_name(rptinfo_t *rptinfo, char * rpt_inst_name ); +/** +* @brief ʼrdb +* @return ɹ APR_SUCCESS +*/ +apr_status_t init_rdb(); + +/** +* @brief Լ߳ +* @return ɹ APR_SUCCESS +*/ +apr_status_t run_protocol(); + +void Set_val_from_61850rpt(element_t* elem,double v); +int Set_q_from_61850rpt(char* q); + +apr_status_t init_rem_dib_table(); + +void CheckNextNotConnectedChannel(); +//WW 2023-08-22 +int HandleReceiveMessage(int socketClient, char buffer[256]); +int ExecuteWebCommand(LD_info_t *LD_info, int iType); +int SendMessageToWeb(int socketClient, int iErrorCode); //Web Socketͻ˷Ϣ +//WW 2023-08-22 end +void CheckAllConnectedChannel() ; + +void check_3s_config(); +void check_recall_config(); +void create_recall_xml(); +void check_disk_quota(); + +apr_status_t prepare_call_cn_wavelist(LD_info_t *LD_info, int FltNum ); + +apr_status_t call_cn_wavelist(LD_info_t *LD_info); + +void strip_file_name_tail_to_ms(char *fileName); + +//////////for pq ////////////////////////////////////////// + +ied_t* find_ied_from_dev_idx(int dev_idx); +ied_t* find_ied_from_dev_code(char dev_idx[]); + +LD_info_t* find_LD_info_from_line_id(ied_t* ied, int line_id); +LD_info_t* find_LD_info_only_from_line_id(int line_id); +LD_info_t* find_LD_info_from_mp_id(ied_t* ied, char* mp_id); +LD_info_t* find_LD_info_only_from_mp_id(char* mp_id); + +////////////////////////////////lnk20250115 +int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml); +extern const int MAX_CPUNO; +extern int stringToInt(const char* str, int* result); +extern bool isCharPtrEmpty(const char* str); +extern int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml); +extern int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_index); +extern void print_trigger_update_xml(const trigger_update_xml_t* trigger_update); +//////////////////////////////// +int parse_3s_xml(trigger_3s_xml_t* trigger_3s_xml); +int create_3s_xml(trigger_3s_xml_t* trigger_3s_xml); +int get_real_report_count(LD_info_t *LD_info); + +int delete_recall_xml(char* id); +int parse_recall_xml(recall_xml_t* recall_xml,char *id); +void process_recall_config(recall_xml_t* recall_xml); +int remove_recall_xml(); + +int init_rptctrl_by_count(LD_info_t* LD_info,int rptcount); +int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf); +int init_logctrl_by_count(LD_info_t* LD_info,int logcount); +int fill_logctrl_by_cfg(LD_info_t* LD_info,int logno,char *buf,char* devtype); + +////////////////////////////////////////////////////////// +void processQVVR_start(LD_info_t* LD_info); +void processQVVR_time(LD_info_t* LD_info, long long Time); +void processQVVR_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v); +void processQVVR_end(LD_info_t* LD_info); + +void processRDRE_start(LD_info_t* LD_info); +void processRDRE_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v); +void processRDRE_end(LD_info_t* LD_info); + +int extract_timestamp_from_cfg_file(char *comtrade_fn,long long *start_tm,long long *trig_tm); + +int parse_file_names(char *file_match_str,char **filenames,int filenum,int *cfg_idx,int *dat_idx,char *file_base_name,char *file_yyyymm); + +int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm); +QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm); + +////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif /* _RDB_CLIENT_H_XSDFSDFSEFS15156SFS */ diff --git a/mms/rdb_ext_utils.c b/mms/rdb_ext_utils.c new file mode 100644 index 0000000..cdad907 --- /dev/null +++ b/mms/rdb_ext_utils.c @@ -0,0 +1,615 @@ +/** + * @file: $RCSfile: rdb_ext_utils.c,v $ + * @brief: $ rdb usr_extĽṹһЩߺ + * + * @version: $Revision: 1.11 $ + * @date: $Date: 2018/12/23 12:39:52 $ + * @author: $Author: lizhongming $ + * @state: $State: Exp $ + * + * @latest: $Id: rdb_ext_utils.c,v 1.11 2018/12/23 12:39:52 lizhongming Exp $ + */ +#include +#include "rdb_client.h" +#include "xmltools.h" +#include "db_interface.h" +//extern rdb_t* g_rdb ; +extern node_t* g_node ; +extern char g_my_conf_fname[256]; +extern apr_pool_t* g_init_pool; +extern apr_pool_t* g_run_pool; +extern pt61850app_t* g_pt61850app; +//extern int g_sysfile_appid; +//extern char *g_sysfile_filedir; +//int my_index =0; +//extern ied_info_t *my_info; +//extern byte_t g_file_name_len; +//extern byte_t g_file_time_from; +////////////////////////str ////////////////////////// + +char* str_trim_both(char* temp,const char* pattern) +{ // pattern such as " \t" or " \t\'" + unsigned int i,j; + for(i=0;i=0;j--) { + if ( strchr(pattern,temp[j]) ) + temp[j] = 0; + else + break; + } + return(temp); +} + + +////////////////////////rdb 61850ṹ ////////////////////////// + +ied_usr_t* GET_IEDEXT_ADDR(ied_t *ied) +{ + assert(ied); + return (ied_usr_t* )ied->usr_ext; +} + +element_usr_t* GET_DOTEXT_ADDR(element_t *elem) +{ + element_usr_t *elem_usr; + assert(elem); + if (elem->usr_ext == NULL) { + elem_usr = apr_pcalloc(g_init_pool,sizeof(element_usr_t)); + elem_usr->last_soe_status = 99; + elem->usr_ext = elem_usr; + } + return (element_usr_t* )elem->usr_ext; +} + +LD_info_t* find_LD_from_cpuCount_and_LEDRs(ied_t* ied, byte_t cpuCount) +{ + LD_info_t *LD_info = NULL; + element_t *elem = NULL; + + LD_info = & (GET_IEDEXT_ADDR(ied)->LD_info[cpuCount]); + + elem = apr_hash_get(LD_info->ht_fcd, "LLN0$CO$LEDRs", APR_HASH_KEY_STRING); + if (elem) + return LD_info; + else + return NULL; +} + +LD_info_t* find_LD_from_cpuId(ied_t* ied,byte_t cpuId) +{ + int cpuno; + LD_info_t* LD_info = NULL; + assert(ied); + for(cpuno=0 ; cpunocpucount; cpuno++) { + if ( ied->cpuinfo[cpuno].addr != cpuId ) + continue; + LD_info = & (GET_IEDEXT_ADDR(ied)->LD_info[cpuno]) ; + } + return LD_info; +} + +LD_info_t* find_LD_from_IEDLDName(ied_t* ied, char *IEDLDName) +{ + int cpuno; + LD_info_t* LD_info = NULL; + assert(ied); + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = & (GET_IEDEXT_ADDR(ied)->LD_info[cpuno]) ; + if(LD_info->LD_name){ + if (strcmp(LD_info->LD_name, IEDLDName)==0) + return LD_info; + } + } + return NULL; +} + +LD_info_t* find_LD_from_IEDLDName_in_report(ied_t* ied, char *IEDLDName) +{ + ST_CHAR * DomName; + LD_info_t* LD_info = NULL; + + DomName = IEDLDName; //strtok (DataReference, "/");/* extract domain name */ + LD_info = find_LD_from_IEDLDName(ied, DomName); + assert(LD_info); + return LD_info; +} + + +LD_info_t* find_LD_from_element(element_t* elem) +{ + return find_LD_from_cpuId(elem->ied, (elem->grp->id>>8)&0xff ) ; +} + + + +RCB_INFO* FindRcbInfo(MVL_NET_INFO *net_info,ST_CHAR *dom_name, ST_CHAR *rcb_name) +{ + ied_t *ied; + ied_usr_t *ied_usr; + chnl_usr_t *chnl_usr; + LD_info_t *LD_info; + rptinfo_t *rptinfo = NULL; + int cpuno,rpt_no; + char rpt_inst_name[65]; + + chnl_usr = net_info->user_ext; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (!LD_info->LD_name) + continue; + if ( strcmp(LD_info->LD_name,dom_name)!=0 ) + continue; + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { + rptinfo = LD_info->rptinfo[rpt_no]; + get_rpt_inst_name(rptinfo,rpt_inst_name); + if ( strcmp(rpt_inst_name,rcb_name)==0 ) { + if (rptinfo->rpt_registered) + return rptinfo->m_rcb_info; + else + return NULL; + } + } + } + + return NULL; +} +//////////////////////////////////////// +//WW 2023-08-29 rcb_infodev_type󶨲Ǻͼ󶨣޸Ĺ򣬱ƥ +rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO *rcb_info) +{ + ied_t *ied; + ied_usr_t *ied_usr; + chnl_usr_t *chnl_usr; + LD_info_t *LD_info; + rptinfo_t *rptinfo = NULL; + int cpuno,rpt_no; + + chnl_usr = net_info->user_ext; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { + rptinfo = LD_info->rptinfo[rpt_no]; + printf("%d rptinfo %s,rcbinfo %s ", rpt_no, rptinfo->rptID, rcb_info->RptID); + if (strcmp(rcb_info->RptID,rptinfo->rptID)==0)//WW ޸Ϊƥַ + return rptinfo; + } + } + return NULL; +} +//WW 2023-08-29 ע +//////////////////////////////////////// + +//////////////////////////////////////// +//WW 2023-08-29 ע +rptinfo_t* find_rptinfo_from_net_rcb_info(MVL_NET_INFO *net_info,RCB_INFO *rcb_info) +{ + ied_t *ied; + ied_usr_t *ied_usr; + chnl_usr_t *chnl_usr; + LD_info_t *LD_info; + rptinfo_t *rptinfo = NULL; + int cpuno,rpt_no; + + chnl_usr = net_info->user_ext; + ied = chnl_usr->chnl->ied; + ied_usr = GET_IEDEXT_ADDR(ied); + + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { + rptinfo = LD_info->rptinfo[rpt_no]; + if (rcb_info==rptinfo->m_rcb_info) + return rptinfo; + } + } + return NULL; +} +//////////////////////////////////////// +//WW 2023-08-29 ע end +void get_rpt_inst_name(rptinfo_t *rptinfo, char * rpt_inst_name ) +{ + strcpy(rpt_inst_name,rptinfo->rptID); + if (rptinfo->instanceNeedSuffix) { + char rpt_suffix_str[8]; + apr_snprintf(rpt_suffix_str,sizeof(rpt_suffix_str),"%02d",rptinfo->m_curRptSuffix); + strcat(rpt_inst_name,rpt_suffix_str); + } +} + + +void strip_file_name_tail_to_ms(char *fileName) +{ + char *p = NULL; + + assert(fileName); + assert(strlen(fileName)<128); + assert(strlen(fileName)>0); + p = fileName; + while(*p != '.') { + p++; + } + while((p>fileName)&&(*p<0x30 || *p>0x39)) { + p--; + } + *++p = '\0'; +} + +static void _cut_file_name(char *fileName, byte_t len) +{ + size_t full_len = strlen(fileName); + + if (full_len<=len) + return; + else { + memmove(fileName, fileName+(full_len-len), len); + *(fileName+len) = '\0'; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ied_t* find_ied_from_dev_idx(int dev_idx) +{ + ied_t *ied = NULL; + int iedno; + ied_usr_t *ied_usr = NULL; + + for(iedno=0; iednon_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = (ied_usr_t*)ied->usr_ext; + if (ied_usr && ied_usr->dev_idx == dev_idx ) + return ied; + } + return NULL; +} + +ied_t* find_ied_from_dev_code(char dev_idx[]) +{ + ied_t* ied = NULL; + int iedno; + ied_usr_t* ied_usr = NULL; + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = (ied_usr_t*)ied->usr_ext; + if (ied_usr && strcmp(ied_usr->terminal_code, dev_idx) == 0) { + return ied; + } + + } + return NULL; +} + +//lnk20250114ͨնidն +ied_t* find_ied_from_terminal_id(char terminal_id[]) +{ + ied_t* ied = NULL; + int iedno; + ied_usr_t* ied_usr = NULL; + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = (ied_usr_t*)ied->usr_ext; + if (ied_usr && strcmp(ied_usr->terminal_id, terminal_id) == 0) { + return ied; + } + + } + return NULL; +} + +LD_info_t* find_LD_info_from_line_id(ied_t* ied, int line_id) +{ + LD_info_t *LD_info = NULL; + ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + int cpuno; + + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info && LD_info->line_id==line_id) + return LD_info; + } + return NULL; +} + +LD_info_t* find_LD_info_only_from_line_id(int line_id) +{ + ied_t *ied = NULL; + int iedno; + LD_info_t *LD_info = NULL; + + for(iedno=0; iednon_clients; iedno++) { + ied = g_node->clients[iedno]; + if (ied) { + LD_info = find_LD_info_from_line_id(ied,line_id); + if (LD_info) + return LD_info; + } + } + return NULL; +} + +LD_info_t* find_LD_info_from_mp_id(ied_t* ied, char* mp_id) +{ + LD_info_t* LD_info = NULL; + ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); + int cpuno; + + for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info && strcmp(LD_info->mp_id, mp_id) == 0) + return LD_info; + } + return NULL; +} + +LD_info_t* find_LD_info_only_from_mp_id(char* mp_id) +{ + ied_t* ied = NULL; + int iedno; + LD_info_t* LD_info = NULL; + + for (iedno = 0; iedno < g_node->n_clients; iedno++) { + ied = g_node->clients[iedno]; + if (ied) { + LD_info = find_LD_info_from_mp_id(ied, mp_id); + if (LD_info) + return LD_info; + } + } + return NULL; +} + +void clear_all_LD_real_soe_report_shoud_register() +{ + ied_t *ied = NULL; + int iedno; + ied_usr_t *ied_usr = NULL; + LD_info_t *LD_info = NULL; + int cpuno; + + for(iedno=0; iednon_clients; iedno++) { + ied = g_node->clients[iedno]; + ied_usr = (ied_usr_t*)ied->usr_ext; + for(cpuno=0 ; cpunocpucount; cpuno++) { + LD_info = &(ied_usr->LD_info[cpuno]); + if (LD_info ) { + LD_info->real_data = 0; + LD_info->soe_data = 0; + } + } + } +} + +void clear_rpt_counter_by_trigger(trigger_t *trigger) +{ + ied_t *ied; + LD_info_t *LD_info; + int rpt_no; + rptinfo_t *rptinfo = NULL; + + trigger->count = 0; + ied = find_ied_from_dev_idx(trigger->dev_idx); + if (!ied) + return; + LD_info = find_LD_info_from_line_id(ied,trigger->line_id); + if (!LD_info) + return; + LD_info->count = 0; + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { + rptinfo = LD_info->rptinfo[rpt_no]; + rptinfo->count = 0; + } +} + +int get_real_report_count(LD_info_t *LD_info) +{ + int rpt_no; + rptinfo_t *rptinfo = NULL; + + for(rpt_no=0 ; rpt_norptcount; rpt_no++) { + rptinfo = LD_info->rptinfo[rpt_no]; + //if (rptinfo->report_PQ_type & REPORT_TYPE_REAL)//бжϱ + if (rptinfo->report_PQ_type)//ϲжʵʱݣҪж + return rptinfo->count; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////ѹ///////////////////////////// +void processQVVR_start(LD_info_t* LD_info) +{ + int i; + + for (i=0;iqvvr[i].used_status==QVVR_DATA_NOT_USED) { + LD_info->qvvr_idx = i; //ûʹãʹ + break; + } + } + if (i>=QVVR_NUM) { //Ѿʹõһ + uint32_t timestamp = LD_info->qvvr[0].timestamp;//һʱ + LD_info->qvvr_idx = 0;//ӵһ㿪ʼ¼ + echo_warn1("QVVR data memory is full,to replace the oldest,line_id=%d \n",LD_info->line_id); + for (i=1;iqvvr[i].timestampqvvr_idx = i; + timestamp = LD_info->qvvr[i].timestamp; + } + } + } + + LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_RECEIVED;//Ϊյ̬ + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 0; //δ + LD_info->qvvr[LD_info->qvvr_idx].timestamp = apr_time_sec(apr_time_now());//¼ǰʱΪ̬ʱ + printf("\n~~~~~~~~~~~~~~~~~ processQVVR_start: line_id=%d \n",LD_info->line_id); +} + +void processQVVR_time(LD_info_t* LD_info, long long Time) +{ + LD_info->qvvr[LD_info->qvvr_idx].QVVR_time = Time; + printf("\n~~~~~~~~~~~~~~~~~ processQVVR_time: line_id=%d ,Time=%lld \n",LD_info->line_id,Time); +} + + +void processQVVR_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v) +{ + if ( strstr(FULL_FCDA_Name,"VarStr$stVal") ) { + LD_info->qvvr[LD_info->qvvr_idx].QVVR_start = (v>0.99) ? 1:0; + } + else if ( strstr(FULL_FCDA_Name,"VVaTm$mag$f") ) + LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime = v; + else if ( strstr(FULL_FCDA_Name,"VVa$mag$f") ) + LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg = v; + else { + if ( strstr(FULL_FCDA_Name,"DipStr$stVal") && (v>0.99) ) //ѹݽ + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1; + else if ( strstr(FULL_FCDA_Name,"SwlStr$stVal") && (v>0.99) ) //ѹ + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 2; + else if ( strstr(FULL_FCDA_Name,"IntrStr$stVal") && (v>0.99) ) //ѹж + LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 3; + } + + if (strstr(FULL_FCDA_Name, "QVVR")) { + apr_snprintf(LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname, sizeof(LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname), "%s", FULL_FCDA_Name);//terminal_code + } + + printf("\n~~~~~~~~~~~~~~~~~ processQVVR_data: line_id=%d ,mms_str=%s,v=%f \n",LD_info->line_id,FULL_FCDA_Name,v); + +} + + +void processQVVR_end(LD_info_t* LD_info) +{ + //lnk20241227lnk̬¼ֱϱ¼¼DZ߻ϱһθļ·ﲻļ· + ied_t *ied = LD_info->ied; + ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + int ret; + long long end_tm = (long long)(LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime*1000) + LD_info->qvvr[LD_info->qvvr_idx].QVVR_time; //ʱdzʱӴʱ + ret = transfer_json_qvvr_data(g_node_id, //ûʹ + LD_info->line_id, // + LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg, LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime, LD_info->qvvr[LD_info->qvvr_idx].QVVR_time, end_tm, LD_info->qvvr[LD_info->qvvr_idx].QVVR_type, //ֵʱ䡢ʼʱ䡢ʱ䡢̬ + "", "", //ļ·Ϊ + LD_info->mp_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname, ied_usr->dev_type);//ţļͼ̬¼ƥϵ̬ն + if(!ret)//ʧ + { + printf("\n~~~~~~~~~~~~~~~~~ QVVR_json_data send error: line_id=%d \n",LD_info->line_id); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + int find_paired = FALSE; + int i; + + if (LD_info->qvvr[LD_info->qvvr_idx].QVVR_start)//ݴʱFCDAVarStr$stValQVVR_startΪ1˳ + return; + + for (i=0;iqvvr_idx) //㵱ǰλ + continue; + if (LD_info->qvvr[i].used_status != QVVR_DATA_RECEIVED)//ûյλ + continue; + //ijλõIJҲûж/λõIJͺ͵ǰλõIJһ + if ( (LD_info->qvvr[i].QVVR_type==0)||(LD_info->qvvr[i].QVVR_type==LD_info->qvvr[LD_info->qvvr_idx].QVVR_type) ) { + LD_info->qvvr[i].used_status = QVVR_DATA_PAIRED; //ƥ + LD_info->qvvr[i].QVVR_type = LD_info->qvvr[LD_info->qvvr_idx].QVVR_type; + LD_info->qvvr[i].QVVR_PerTime = LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime; + LD_info->qvvr[i].QVVR_Amg = LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg; //¼ǰIJݵҵĵλϣȷ¼µͬ͵¼ + + LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //ǰλͷ + find_paired = TRUE; + break; + } + } + + if (find_paired == FALSE) { + LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //ȫûƥֱͷ㣬´¼ֱʹ + printf("\nERROR:~~~~~~~~~~~~~ processQVVR qvvr returned to 0,but found no data to pair!, line_id=%d,QVVR_type=%d \n", + LD_info->line_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_type); + } + + printf("\n~~~~~~~~~~~~~~~~~ processQVVR_end: line_id=%d \n",LD_info->line_id); +} + +// ܣݴʱtrig_tmƥ QVVR ݡ +// +// - LD_infoָ LD_info_t ͽṹָ룬 QVVR ݡ +// - trig_tmʱ QVVR еʱƥ䡣 +// +// - ƥ QVVR ݵָ롣ûҵƥ QVVR ݣ򷵻 NULL +// ֵ +// - ҵ QVVR ݣָݵָ롣 +// - ûҵ QVVR ݣ NULL +QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info, long long trig_tm) +{ + long long diff; // ڼʱ + int i; // ѭ + + // LD_info е QVVR + for (i = 0; i < QVVR_NUM; i++) { + // 㵱ǰ QVVR ݵʱ봥ʱ֮IJ + diff = abs(LD_info->qvvr[i].QVVR_time - trig_tm); + + // QVVR ݵ״̬ ""QVVR_DATA_PAIREDʱСڵ 1λ룩 + if ((LD_info->qvvr[i].used_status == QVVR_DATA_PAIRED) && (diff <= 1)) { + // ƥ䣬ظ QVVR ݵָ + return &(LD_info->qvvr[i]); + } + } + + // ûҵƥ QVVR ݣ NULL + return NULL; +} +#if 0 +QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm) +{ + long long diff; + int i; + + for (i=0;iqvvr[i].QVVR_time-trig_tm); + if ( (LD_info->qvvr[i].used_status==QVVR_DATA_PAIRED) && (diff<=1) ) { + return &(LD_info->qvvr[i]); + } + } + return NULL; +} +#endif +////////////////////¼ļ///////////////////////////// + +void processRDRE_start(LD_info_t* LD_info) +{ + LD_info->RDRE_FltNum = -1; + printf("\n~~~~~~RDRE~~~~~~ processRDRE_start: line_id=%d \n",LD_info->line_id); +} + +void processRDRE_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v) +{ + if ( strstr(FULL_FCDA_Name,"FltNum$stVal") ) + LD_info->RDRE_FltNum = (int)(v+0.4); + + printf("\n~~~~~~RDRE~~~~~~ processRDRE_data: line_id=%d ,mms_str=%s,v=%f \n",LD_info->line_id,FULL_FCDA_Name,v); +} + +void processRDRE_end(LD_info_t* LD_info) +{ + if (LD_info->RDRE_FltNum<=0) + return; + + prepare_call_cn_wavelist(LD_info,LD_info->RDRE_FltNum); + printf("\n~~~~~~RDRE~~~~~~ processRDRE_end: line_id=%d \n",LD_info->line_id); +} + +////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/mms/reject.c b/mms/reject.c new file mode 100644 index 0000000..31afd49 --- /dev/null +++ b/mms/reject.c @@ -0,0 +1,73 @@ +/** +* @file: $RCSfile: reject.c,v $ +* @brief: $IEC 61850 Protocol +* +* @version: $Revision: 1.1 $ +* @date: $Date: 2018/11/24 06:54:51 $ +* @author: $Author: lizhongming $ +* @state: $State: Exp $ +* +* @latest: $Id: reject.c,v 1.1 2018/11/24 06:54:51 lizhongming Exp $ +* +*/ +/************************************************************************/ +/* SISCO SOFTWARE MODULE HEADER *****************************************/ +/************************************************************************/ +/* (c) Copyright Systems Integration Specialists Company, Inc., */ +/* 2005 - 2005, All Rights Reserved */ +/* */ +/* MODULE NAME : reject.c */ +/* PRODUCT(S) : MMSEASE-LITE */ +/* */ +/* MODULE DESCRIPTION : */ +/* Default reject indication function. This module may be linked */ +/* to any application, or the function may be copied to a user */ +/* module and modified as needed. */ +/* */ +/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ +/* u_mvl_reject_ind */ +/* */ +/* MODIFICATION LOG : */ +/* Date Who Rev Comments */ +/* -------- --- ------ ------------------------------------------- */ +/* 09/07/05 JRB 01 Created */ +/************************************************************************/ +#include "glbtypes.h" +#include "sysincs.h" +#include "mvl_defs.h" +#include "mvl_acse.h" +#include "mvl_log.h" + +/************************************************************************/ +/* For debug version, use a static pointer to avoid duplication of */ +/* __FILE__ strings. */ +/************************************************************************/ +#ifdef DEBUG_SISCO +SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; +#endif + +/************************************************************************/ +/* u_mvl_reject_ind */ +/************************************************************************/ +ST_VOID u_mvl_reject_ind (MVL_NET_INFO *net_info, REJECT_RESP_INFO *rej_info) + { + if (rej_info->rej_class == MMS_REJ_CLASS_CONFIRMED_REQUEST_PDU && + rej_info->rej_code == MMS_REJ_CODE_CONFIRMED_REQUEST_PDU_UNRECOGNIZED_SERVICE) + { /* This is most common case. Provide extra information in log msgs.*/ + if (rej_info->detected_here) + MVL_LOG_ERR0 ("MMS Reject sent, unrecognized service. Check MMS services enabled here."); + else + MVL_LOG_ERR0 ("MMS Reject received, unrecognized service. Check MMS services enabled on remote device."); + } + else + { + /* NOTE: for all other cases, it is best to abort the connection */ + /* but it is not done in this callback function because no good */ + /* way to inform main application that abort occurred. */ + /* DEBUG: should there be extra handshaking in MVL_NET_INFO struct? */ + if (rej_info->detected_here) + MVL_LOG_ERR0 ("Reject sent."); + else + MVL_LOG_ERR0 ("Reject received."); + } + } diff --git a/mms/rpt.odf b/mms/rpt.odf new file mode 100644 index 0000000..4477976 --- /dev/null +++ b/mms/rpt.odf @@ -0,0 +1,28 @@ +############################################################# +#Copyright 1998-2003, Systems Integration Specialists Company, Inc. +# All Rights Reserved +############################################################# +# 12/17/03 JRB For 61850-8-1 FDIS, chg RTYP_BVSTR9 to RTYP_BVSTR10, +# add RTYP_BSTR9 for client. +# 10/09/03 JRB Add RTYP_INT32U for IntgPd. +# 03/13/03 JRB Overhaul. Use RTYP_ prefix for all RPT related types. + +#NOTE: These types are used directly in reporting code, and also in +# other ODF files to define Report Control Blocks (RCBs). +# It is CRITICAL that the same type is used in both places. +":TKU", "RTYP_BOOL", "", "UCAreporttypes" +":TKU", "RTYP_BTIME6", "", "UCAreporttypes" +":TKU", "RTYP_BSTR6", "Bstring6", "UCAreporttypes" +":TKU", "RTYP_BSTR8", "Bstring8", "UCAreporttypes" +":TKU", "RTYP_BSTR9", "Bstring9", "Client needs for writing OptFlds" +":TKU", "RTYP_BVSTR6", "Bvstring6", "UCAreporttypes" +":TKU", "RTYP_BVSTR8", "Bvstring8", "UCAreporttypes" +":TKU", "RTYP_BVSTR10", "Bvstring10", "UCAreporttypes" +":TKU", "RTYP_INT8U", "", "UCAreporttypes" +":TKU", "RTYP_INT16U", "", "UCAreporttypes" +":TKU", "RTYP_OSTR8", "Ostring8", "UCAreporttypes" +":TKU", "RTYP_VSTR32", "", "UCAreporttypes" +":TKU", "RTYP_VSTR65", "", "UCAreporttypes" + +#NOTE: Client needs this for IntgPd. +":TKU", "RTYP_INT32U", "", "UCAreporttypes" diff --git a/mms/ver_conf.h b/mms/ver_conf.h new file mode 100644 index 0000000..0125228 --- /dev/null +++ b/mms/ver_conf.h @@ -0,0 +1,40 @@ + +#ifndef VER_CONF_H_KHCYDOPFRUYDIYFIHUIVUGUGG +#define VER_CONF_H_KHCYDOPFRUYDIYFIHUIVUGUGG +#include "stdio.h" + +const char* PROGRAM_VERSION = "1.0.2.7"; +const char* PROGRAM_CREATE_TIME="2024-09-18"; +int getVersion(int argc,const char ** argv); + +int getVersion(int argc,const char ** argv) +{ + const char *str; + if (argc > 1) { + str = argv[1]; + if (strcmp(str,"--version")== 0 ) { + printf ("Version: pt61850netd_pqfe_%s_%s \n", PROGRAM_VERSION, PROGRAM_CREATE_TIME); + printf (" Memo: changed after the epri integerated test!\n"); + printf (" changed after the epri data detail verified!\n"); + printf (" add the special communication log!\n"); + printf (" optimize the 3s file process with webservice,avoid conflict!\n"); + printf (" support the dev_flag configured by ini file\n"); + printf (" add json create log when jump out, and detail log when first 10k datas\n"); + printf (" support qvvr send 2 topics when recv report\n"); + printf (" not write the period secs when register report\n"); + printf (" only create LF when 2 hours\n"); + printf (" add watchdog to working thread\n"); + printf (" support one ip ,multi port when connect to ied\n"); + printf(" 2024-02-26 add recall\n"); + printf(" 2024-03-08 add recall\n"); + printf(" 2024-03-26 remove Rregister rpt\n"); + printf(" 2024-04-04 Compatible recall time\n"); + printf(" 2024-09-18 monitor report clear cache\n"); + exit(0); + } + } + return 0; +}; + +#endif //VER_CONF_H_KHCYDOPFRUYDIYFIHUIVUGUGG + diff --git a/mms/version.txt b/mms/version.txt new file mode 100644 index 0000000..08ea287 --- /dev/null +++ b/mms/version.txt @@ -0,0 +1,14 @@ +4.0.cn.180529 [OS_VERSION] + +޸ʱ: 2018.05.29 + +汾䶯˵: +1.ӱʵһڿԶתѡעᣬùе61850õĹԼ˽õġAʵ׺ѡñʵķΧʽ [ʵ1],[ʵ2] , 512 ʾõıʵ 05,06,07,08,09,10,11,12 +2. ִUPDATEOVERLIMITQVVRĴʱoracle otl쳣ʱֻӡΪ˳ +3. PQ_DeviceݿԭIP1IP2IP3IP4ĸֶκϲһIPֶΣΪַ +4. QualityFlagֵɱеһӦQƷʣд룬ֻдλҲ00-Ʒ 01-Ʒ +5.޸ʹøȫݿ¼ +6.UPDATEEVENTCOUNT ̵EventReasonEventTypeMyGUIDUUID +7.֧ԶݹϺţٻ¼ļȻftp +8. ܿŻдʵʱ + diff --git a/pt61850netd_pqfe.pro b/pt61850netd_pqfe.pro new file mode 100644 index 0000000..0d89544 --- /dev/null +++ b/pt61850netd_pqfe.pro @@ -0,0 +1,146 @@ +TEMPLATE = app +TARGET = pt61850netd_pqfe +DEPENDPATH += . + +INCLUDEPATH += . ./source/include ./source/include/mmslite ./source/include/pg_inst ./source/include/curl ./source/include/oss_sdk ./source/include/roketmq + + +QMAKE_ORIG_TARGET = $(TARGET) + +QT += core xml network +CONFIG += thread + +DEFINES += _CRT_SECURE_NO_WARNINGS +DEFINES += MMS_LITE LINUX=2 MOSI LEAN_T TP0_ENABLED +DEFINES += CLIENT _DEBUG _REENTRANT _GNU_SOURCE _LARGEFILE64_SOURCE + +win32 { + DEFINES -= UNICODE + DEFINES += _AFXDLL + CONFIG += console +} + +win32 { + # RC_FILE=pt61850netd_pqfe.rc + SOURCES += source/mms/event.c + INCLUDEPATH += ./source/include/apr + QMAKE_LFLAGS += /NODEFAULTLIB:libcmt.lib + LIBS += -L./lib -L./lib/mmslite -lws2_32 + CONFIG(debug, debug|release) { + DEFINES += DEBUG_SISCO + MMS_LIB_SUFFIX = _ld.lib + QMAKE_POST_LINK = $$QMAKE_COPY debug\\*.exe ..\\..\\usr_bin\\jspqfe_home\\bin + } + else{ + MMS_LIB_SUFFIX = _n.lib + QMAKE_POST_LINK = $$QMAKE_COPY release\\*.exe ..\\..\\usr_bin\\jspqfe_home\\bin + } + LIBS += ositcps$$MMS_LIB_SUFFIX \ + mvl$$MMS_LIB_SUFFIX \ + mmsle$$MMS_LIB_SUFFIX \ + mmsl$$MMS_LIB_SUFFIX \ + asn1$$MMS_LIB_SUFFIX \ + mem$$MMS_LIB_SUFFIX \ + meml$$MMS_LIB_SUFFIX \ + slog$$MMS_LIB_SUFFIX \ + utility$$MMS_LIB_SUFFIX \ + ssec0$$MMS_LIB_SUFFIX + LIBS += -llibapr-1 -llibaprutil-1 -llibjclite +} + +unix { + include(fe_common.pri) + SOURCES += source/mms/event2.c + INCLUDEPATH += ./source/include/apr-linux + LIBS += -L/FeProject/lib + LIBS += -L/FeProject/lib/pgodbc + DEFINES += DEBUG_SISCO + VERSION = 1.0.0 + + CONFIG(debug, debug|release) { + + } else { + + } + LIBS += -lrt -lpthread + MMS_LIB_SUFFIX = _ld.a + LIBS += /FeProject/lib/mmslite/ositcps$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/mvl$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/mmsle$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/mmsl$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/asn1l$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/mem$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/slog$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/util$$MMS_LIB_SUFFIX \ + /FeProject/lib/mmslite/ssec0$$MMS_LIB_SUFFIX \ + /FeProject/lib/pgodbc/psqlodbc.so \ + /FeProject/lib/libcurl.so \ + /FeProject/lib/liboss_c_sdk.so.3.0.0 \ + /FeProject/lib/libmxml.so \ + /FeProject/lib/librocketmq.so \ + /FeProject/lib/libhttprun.so + LIBS += -lapr-1 -laprutil-1 -ljclite + LIBS += -lrdkafka++ + LIBS += -lhttprun +} + +#install +{ + target.path = ../../bin + INSTALLS += target +} + +# Input + +HEADERS += source/mms/db_interface.h \ + source/include/otlv4.h \ + source/mms/mmsclient.h \ + source/mms/mmsop_en.h \ + source/mms/rdb_client.h \ + source/mms/ver_conf.h \ +# source/misc/csv_parser.h \ +# source/misc/ftp.h \ +# source/misc/gb_to_utf8.h \ +# source/misc/utf8_to_gb.h \ + source/misc/SM4.h \ + source/json/save2json.h \ + source/json/mms_json_inter.h \ + source/json/rdkafka.h \ + source/json/rdkafkacpp.h \ + source/json/kafka_producer.h \ + source/json/cjson.h \ + source/include/rocketmq/SimpleProducer.h +SOURCES += source/mms/main.c \ + source/mms/clntobj.c \ + source/mms/logcfgx.c \ + source/mms/mms_process.c \ + source/mms/mmscli_rpt.c \ + source/mms/mmsclient.c \ + source/mms/mmslvar.c \ + source/mms/mmsop_en.c \ + source/mms/mvl_acse.c \ + source/mms/mvlop_en.c \ + source/mms/parse_xml.c \ + source/mms/rdb_client.c \ + source/mms/rdb_ext_utils.c \ + source/mms/reject.c \ + source/mms/mmscli_log.c \ +# source/mms/myftp.cpp \ +# source/misc/csv_parser.cpp \ +# source/misc/ftp.cpp \ +# source/misc/gb_to_utf8.c \ +# source/misc/utf8_to_gb.c \ + source/misc/SM4.cpp \ + source/misc/my_encrypt.cpp \ + source/json/save2json.cpp \ + source/cfg_parse/cfg_parser.cpp \ + source/json/kafka_producer.cpp \ + source/json/create_json.cpp \ + source/json/cjson.c \ + source/cfg_parse/oss_aliyun.cpp \ + source/cfg_parse/obs_huaweiyun.cpp \ + source/cfg_parse/datahub.cpp \ + source/cfg_parse/nacos.cpp \ + source/cfg_parse/base64.cpp \ + source/cfg_parse/uds_huaweiyun.cpp \ + source/cfg_parse/SimpleProducer.cpp diff --git a/pt61850netd_pqfe.vcxproj b/pt61850netd_pqfe.vcxproj new file mode 100644 index 0000000..dabd9f7 --- /dev/null +++ b/pt61850netd_pqfe.vcxproj @@ -0,0 +1,557 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {9F7DB508-D915-4090-93C1-0D2402D6BEB4} + pt61850netdpqfe + 10.0 + + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + + + Console + + + + + Level3 + Disabled + true + true + + + Console + + + + + Level3 + MaxSpeed + true + true + true + true + + + Console + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + Console + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pt61850netd_pqfe.vcxproj.filters b/pt61850netd_pqfe.vcxproj.filters new file mode 100644 index 0000000..3c69318 --- /dev/null +++ b/pt61850netd_pqfe.vcxproj.filters @@ -0,0 +1,1308 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {180633ca-dd2a-4bb4-982a-a6d5a4a03490} + + + {cc587d54-0264-4808-9287-c0b06ff5e928} + + + {447bd9f0-a338-4213-9d2d-a0bbec2017de} + + + {7cc61ffb-3a12-4ecd-9cfe-f2c6cbb5504a} + + + {3bdf74ca-b646-44f5-9e46-3295f9e6543f} + + + {4af0c31c-dbf7-4f4d-8559-d2431b1d1847} + + + {93d05a33-8ad0-4b7d-a57c-019f823613b7} + + + {cf9dc835-1ddd-4804-8029-6410d9b54d09} + + + {68c3aec4-8aa0-40af-a2a8-9d547a174114} + + + {0bfe48b5-914f-488c-aed8-f5241e31b1d8} + + + {fbc8959b-6771-48bd-9e4a-fd79a2195103} + + + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\mmslite + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + + + + + + 源文件\cfg_parse + + + 源文件\json + + + 源文件\json + + + 源文件\json + + + 源文件\misc + + + 源文件\misc + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\json + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\cfg_parse + + + 源文件\cfg_parse + + + 源文件\cfg_parse + + + 源文件\cfg_parse + + + 源文件\cfg_parse + + + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\apr-linux + + + 源文件\include\mmslite\mmsop_en + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\include\mmslite + + + 源文件\json + + + 源文件\json + + + 源文件\json + + + 源文件\json + + + 源文件\json + + + 源文件\misc + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\mms + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\include + + + 源文件\json + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\curl + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + 源文件\include\oss_sdk + + + + + 源文件\mms + + + 源文件\mms + + + + + 源文件\mms + + + \ No newline at end of file diff --git a/pt61850netd_pqfe.vcxproj.user b/pt61850netd_pqfe.vcxproj.user new file mode 100644 index 0000000..0581d90 --- /dev/null +++ b/pt61850netd_pqfe.vcxproj.user @@ -0,0 +1,9 @@ + + + + WindowsLocalDebugger + + + true + + \ No newline at end of file diff --git a/rocketmq/Arg_helper.h b/rocketmq/Arg_helper.h new file mode 100644 index 0000000..bc28962 --- /dev/null +++ b/rocketmq/Arg_helper.h @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef _ARG_HELPER_H_ +#define _ARG_HELPER_H_ + +#include +#include +#include "RocketMQClient.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API Arg_helper { + public: + Arg_helper(int argc, char* argv[]); + Arg_helper(std::string arg_str_); + std::string get_option(int idx_) const; + bool is_enable_option(std::string opt_) const; + std::string get_option_value(std::string opt_) const; + + private: + std::vector m_args; +}; + +} // namespace rocketmq + +#endif //& msgs); + virtual SendResult send(std::vector& msgs, const MQMessageQueue& mq); + virtual void send(MQMessage& msg, SendCallback* pSendCallback, bool bSelectActiveBroker = false); + virtual void send(MQMessage& msg, const MQMessageQueue& mq, SendCallback* pSendCallback); + virtual void send(MQMessage& msg, MessageQueueSelector* selector, void* arg, SendCallback* pSendCallback); + virtual void sendOneway(MQMessage& msg, bool bSelectActiveBroker = false); + virtual void sendOneway(MQMessage& msg, const MQMessageQueue& mq); + virtual void sendOneway(MQMessage& msg, MessageQueueSelector* selector, void* arg); + + const std::string& getNamesrvAddr() const; + void setNamesrvAddr(const std::string& namesrvAddr); + + void setSessionCredentials(const std::string& accessKey, + const std::string& secretKey, + const std::string& accessChannel); + const SessionCredentials& getSessionCredentials() const; + + const std::string& getNamesrvDomain() const; + void setNamesrvDomain(const std::string& namesrvDomain); + + const std::string& getNameSpace() const; + void setNameSpace(const std::string& nameSpace); + + const std::string& getGroupName() const; + void setGroupName(const std::string& groupname); + + const std::string& getInstanceName() const; + void setInstanceName(const std::string& instanceName); + + /** + * Log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default + * log file num is 3, each log size is 100M + **/ + void setLogLevel(elogLevel inputLevel); + elogLevel getLogLevel(); + void setLogPath(const std::string& logPath); + void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit + + int getSendMsgTimeout() const; + void setSendMsgTimeout(int sendMsgTimeout); + + /* + * If msgBody size is large than compressMsgBodyOverHowmuch + * rocketmq cpp will compress msgBody according to compressLevel + */ + int getCompressMsgBodyOverHowmuch() const; + void setCompressMsgBodyOverHowmuch(int compressMsgBodyOverHowmuch); + int getCompressLevel() const; + void setCompressLevel(int compressLevel); + + int getMaxMessageSize() const; + void setMaxMessageSize(int maxMessageSize); + + int getRetryTimes() const; + void setRetryTimes(int times); + + int getRetryTimes4Async() const; + void setRetryTimes4Async(int times); + + /** Set TcpTransport pull thread num, which dermine the num of threads to + * distribute network data, + * 1. its default value is CPU num, it must be setted before producer/consumer + * start, minimum value is CPU num; + * 2. this pullThread num must be tested on your environment to find the best + * value for RT of sendMsg or delay time of consume msg before you change it; + * 3. producer and consumer need different pullThread num, if set this num, + * producer and consumer must set different instanceName. + **/ + void setTcpTransportPullThreadNum(int num); + int getTcpTransportPullThreadNum() const; + + /** Timeout of tcp connect, it is same meaning for both producer and consumer; + * 1. default value is 3000ms + * 2. input parameter could only be milliSecond, suggestion value is + * 1000-3000ms; + **/ + void setTcpTransportConnectTimeout(uint64_t timeout); // ms + uint64_t getTcpTransportConnectTimeout() const; + + /** Timeout of tryLock tcpTransport before sendMsg/pullMsg, if timeout, + * returns NULL + * 1. paremeter unit is ms, default value is 3000ms, the minimun value is 1000ms + * suggestion value is 3000ms; + * 2. if configured with value smaller than 1000ms, the tryLockTimeout value + * will be setted to 1000ms + **/ + void setTcpTransportTryLockTimeout(uint64_t timeout); // ms + uint64_t getTcpTransportTryLockTimeout() const; + + void setUnitName(std::string unitName); + const std::string& getUnitName() const; + void setMessageTrace(bool messageTrace); + bool getMessageTrace() const; + + void setEnableSsl(bool enableSsl); + bool getEnableSsl() const; + + void setSslPropertyFile(const std::string& sslPropertyFile); + const std::string& getSslPropertyFile() const; + + private: + DefaultMQProducerImpl* impl; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/DefaultMQPullConsumer.h b/rocketmq/DefaultMQPullConsumer.h new file mode 100644 index 0000000..048072d --- /dev/null +++ b/rocketmq/DefaultMQPullConsumer.h @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __DEFAULTMQPULLCONSUMER_H__ +#define __DEFAULTMQPULLCONSUMER_H__ + +#include +#include +#include "AsyncCallback.h" +#include "ConsumeType.h" +#include "MQClient.h" +#include "MQMessage.h" +#include "MQMessageExt.h" +#include "MQMessageQueue.h" +#include "MQueueListener.h" +#include "PullResult.h" +#include "RocketMQClient.h" +#include "SessionCredentials.h" + +namespace rocketmq { +class SubscriptionData; +class DefaultMQPullConsumerImpl; +class ROCKETMQCLIENT_API DefaultMQPullConsumer { + public: + DefaultMQPullConsumer(const std::string& groupname); + virtual ~DefaultMQPullConsumer(); + + virtual void start(); + virtual void shutdown(); + virtual std::string version(); + + const std::string& getNamesrvAddr() const; + void setNamesrvAddr(const std::string& namesrvAddr); + + void setSessionCredentials(const std::string& accessKey, + const std::string& secretKey, + const std::string& accessChannel); + const SessionCredentials& getSessionCredentials() const; + + const std::string& getNamesrvDomain() const; + void setNamesrvDomain(const std::string& namesrvDomain); + + const std::string& getInstanceName() const; + void setInstanceName(const std::string& instanceName); + + const std::string& getNameSpace() const; + void setNameSpace(const std::string& nameSpace); + + const std::string& getGroupName() const; + void setGroupName(const std::string& groupname); + + void setEnableSsl(bool enableSsl); + bool getEnableSsl() const; + + void setSslPropertyFile(const std::string& sslPropertyFile); + const std::string& getSslPropertyFile() const; + + /** + * Log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default + * log file num is 3, each log size is 100M + **/ + void setLogLevel(elogLevel inputLevel); + elogLevel getLogLevel(); + void setLogPath(const std::string& logPath); + void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit + + virtual void fetchSubscribeMessageQueues(const std::string& topic, std::vector& mqs); + + /** + * Pull message from specified queue, if no msg in queue, return directly + * + * @param mq + * specify the pulled queue + * @param subExpression + * set filter expression for pulled msg, broker will filter msg actively + * Now only OR operation is supported, eg: "tag1 || tag2 || tag3" + * if subExpression is setted to "null" or "*", all msg will be subscribed + * @param offset + * specify the started pull offset + * @param maxNums + * specify max msg num by per pull + * @return + * PullResult + */ + virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums); + virtual void pull(const MQMessageQueue& mq, + const std::string& subExpression, + int64 offset, + int maxNums, + PullCallback* pPullCallback); + + /** + * Pull msg from specified queue, if no msg, broker will suspend the pull request 20s + * + * @param mq + * specify the pulled queue + * @param subExpression + * set filter expression for pulled msg, broker will filter msg actively + * Now only OR operation is supported, eg: "tag1 || tag2 || tag3" + * if subExpression is setted to "null" or "*", all msg will be subscribed + * @param offset + * specify the started pull offset + * @param maxNums + * specify max msg num by per pull + * @return + * accroding to PullResult + */ + virtual PullResult pullBlockIfNotFound(const MQMessageQueue& mq, + const std::string& subExpression, + int64 offset, + int maxNums); + virtual void pullBlockIfNotFound(const MQMessageQueue& mq, + const std::string& subExpression, + int64 offset, + int maxNums, + PullCallback* pPullCallback); + + void persistConsumerOffset(); + void persistConsumerOffsetByResetOffset(); + void updateTopicSubscribeInfo(const std::string& topic, std::vector& info); + ConsumeFromWhere getConsumeFromWhere(); + void getSubscriptions(std::vector&); + void updateConsumeOffset(const MQMessageQueue& mq, int64 offset); + void removeConsumeOffset(const MQMessageQueue& mq); + + void registerMessageQueueListener(const std::string& topic, MQueueListener* pListener); + + int64 fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore); + + void fetchMessageQueuesInBalance(const std::string& topic, std::vector mqs); + + void persistConsumerOffset4PullConsumer(const MQMessageQueue& mq); + + private: + DefaultMQPullConsumerImpl* impl; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/DefaultMQPushConsumer.h b/rocketmq/DefaultMQPushConsumer.h new file mode 100644 index 0000000..1cf9722 --- /dev/null +++ b/rocketmq/DefaultMQPushConsumer.h @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __DEFAULTMQPUSHCONSUMER_H__ +#define __DEFAULTMQPUSHCONSUMER_H__ + +#include +#include "AsyncCallback.h" +#include "ConsumeType.h" +#include "MQClient.h" +#include "MQMessageListener.h" +#include "MQMessageQueue.h" +#include "SessionCredentials.h" + +namespace rocketmq { +class DefaultMQPushConsumerImpl; +class ROCKETMQCLIENT_API DefaultMQPushConsumer { + public: + DefaultMQPushConsumer(const std::string& groupname); + + virtual ~DefaultMQPushConsumer(); + + virtual void start(); + virtual void shutdown(); + virtual std::string version(); + + const std::string& getNamesrvAddr() const; + void setNamesrvAddr(const std::string& namesrvAddr); + + void setSessionCredentials(const std::string& accessKey, + const std::string& secretKey, + const std::string& accessChannel); + const SessionCredentials& getSessionCredentials() const; + + void subscribe(const std::string& topic, const std::string& subExpression); + + void registerMessageListener(MQMessageListener* pMessageListener); + MessageListenerType getMessageListenerType(); + + MessageModel getMessageModel() const; + void setMessageModel(MessageModel messageModel); + + void setConsumeFromWhere(ConsumeFromWhere consumeFromWhere); + ConsumeFromWhere getConsumeFromWhere(); + + const std::string& getNamesrvDomain() const; + void setNamesrvDomain(const std::string& namesrvDomain); + + const std::string& getInstanceName() const; + void setInstanceName(const std::string& instanceName); + + const std::string& getNameSpace() const; + void setNameSpace(const std::string& nameSpace); + + const std::string& getGroupName() const; + void setGroupName(const std::string& groupname); + + void setEnableSsl(bool enableSsl); + bool getEnableSsl() const; + + void setSslPropertyFile(const std::string& sslPropertyFile); + const std::string& getSslPropertyFile() const; + + /** + * Log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default + * log file num is 3, each log size is 100M + **/ + void setLogLevel(elogLevel inputLevel); + elogLevel getLogLevel(); + void setLogPath(const std::string& logPath); + void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit + + void setConsumeThreadCount(int threadCount); + int getConsumeThreadCount() const; + + void setMaxReconsumeTimes(int maxReconsumeTimes); + int getMaxReconsumeTimes() const; + + void setPullMsgThreadPoolCount(int threadCount); + int getPullMsgThreadPoolCount() const; + + void setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize); + int getConsumeMessageBatchMaxSize() const; + + /** + * Set max cache msg size perQueue in memory if consumer could not consume msgs + * immediately + * default maxCacheMsgSize perQueue is 1000, set range is:1~65535 + **/ + void setMaxCacheMsgSizePerQueue(int maxCacheSize); + int getMaxCacheMsgSizePerQueue() const; + + /** Set TcpTransport pull thread num, which dermine the num of threads to + * distribute network data, + * 1. its default value is CPU num, it must be setted before producer/consumer + * start, minimum value is CPU num; + * 2. this pullThread num must be tested on your environment to find the best + * value for RT of sendMsg or delay time of consume msg before you change it; + * 3. producer and consumer need different pullThread num, if set this num, + * producer and consumer must set different instanceName. + **/ + void setTcpTransportPullThreadNum(int num); + int getTcpTransportPullThreadNum() const; + + /** Timeout of tcp connect, it is same meaning for both producer and consumer; + * 1. default value is 3000ms + * 2. input parameter could only be milliSecond, suggestion value is + * 1000-3000ms; + **/ + void setTcpTransportConnectTimeout(uint64_t timeout); // ms + uint64_t getTcpTransportConnectTimeout() const; + + /** Timeout of tryLock tcpTransport before sendMsg/pullMsg, if timeout, + * returns NULL + * 1. paremeter unit is ms, default value is 3000ms, the minimun value is 1000ms + * suggestion value is 3000ms; + * 2. if configured with value smaller than 1000ms, the tryLockTimeout value + * will be setted to 1000ms + **/ + void setTcpTransportTryLockTimeout(uint64_t timeout); // ms + uint64_t getTcpTransportTryLockTimeout() const; + + void setUnitName(std::string unitName); + const std::string& getUnitName() const; + + void setAsyncPull(bool asyncFlag); + void setMessageTrace(bool messageTrace); + bool getMessageTrace() const; + + private: + DefaultMQPushConsumerImpl* impl; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/MQClient.h b/rocketmq/MQClient.h new file mode 100644 index 0000000..db48d20 --- /dev/null +++ b/rocketmq/MQClient.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __MQADMIN_H__ +#define __MQADMIN_H__ + +namespace rocketmq { + +enum elogLevel { + eLOG_LEVEL_FATAL = 1, + eLOG_LEVEL_ERROR = 2, + eLOG_LEVEL_WARN = 3, + eLOG_LEVEL_INFO = 4, + eLOG_LEVEL_DEBUG = 5, + eLOG_LEVEL_TRACE = 6, + eLOG_LEVEL_LEVEL_NUM = 7 +}; + +} // namespace rocketmq +#endif diff --git a/rocketmq/MQClientException.h b/rocketmq/MQClientException.h new file mode 100644 index 0000000..883cd64 --- /dev/null +++ b/rocketmq/MQClientException.h @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __MQCLIENTEXCEPTION_H__ +#define __MQCLIENTEXCEPTION_H__ + +#include +#include +#include +#include +#include +#include "RocketMQClient.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API MQException : public std::exception { + public: + MQException(const std::string& msg, int error, const char* file, int line) throw() + : m_error(error), m_line(line), m_file(file) { + try { + std::stringstream ss; + ss << "msg: " << msg << ",error:" << error << ",in file <" << file << "> line:" << line; + m_msg = ss.str(); + } catch (...) { + } + } + + MQException(const std::string& msg, int error, const char* file, const char* type, int line) throw() + : m_error(error), m_line(line), m_file(file), m_type(type) { + try { + std::stringstream ss; + ss << "msg: " << msg << ",error:" << error << ",in file <" << file << "> line:" << line; + m_msg = ss.str(); + } catch (...) { + } + } + + virtual ~MQException() throw() {} + const char* what() const throw() { return m_msg.c_str(); } + int GetError() const throw() { return m_error; } + virtual const char* GetType() const throw() { return m_type.c_str(); } + int GetLine() { return m_line; } + const char* GetFile() { return m_file.c_str(); } + + protected: + int m_error; + int m_line; + std::string m_msg; + std::string m_file; + std::string m_type; +}; + +inline std::ostream& operator<<(std::ostream& os, const MQException& e) { + os << "Type: " << e.GetType() << " , " << e.what(); + return os; +} + +#define DEFINE_MQCLIENTEXCEPTION(name) \ + class ROCKETMQCLIENT_API name : public MQException { \ + public: \ + name(const std::string& msg, int error, const char* file, int line) throw() \ + : MQException(msg, error, file, #name, line) {} \ + virtual const char* GetType() const throw() { return m_type.c_str(); } \ + }; + +DEFINE_MQCLIENTEXCEPTION(MQClientException) +DEFINE_MQCLIENTEXCEPTION(MQBrokerException) +DEFINE_MQCLIENTEXCEPTION(InterruptedException) +DEFINE_MQCLIENTEXCEPTION(RemotingException) +DEFINE_MQCLIENTEXCEPTION(UnknownHostException) + +#define THROW_MQEXCEPTION(e, msg, err) throw e(msg, err, __FILE__, __LINE__) +#define NEW_MQEXCEPTION(e, msg, err) e(msg, err, __FILE__, __LINE__) + +} // namespace rocketmq +#endif diff --git a/rocketmq/MQMessage.h b/rocketmq/MQMessage.h new file mode 100644 index 0000000..dd2f7c0 --- /dev/null +++ b/rocketmq/MQMessage.h @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __MESSAGE_H__ +#define __MESSAGE_H__ + +#include +#include +#include +#include +#include "RocketMQClient.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API MQMessage { + public: + MQMessage(); + MQMessage(const std::string& topic, const std::string& body); + MQMessage(const std::string& topic, const std::string& tags, const std::string& body); + MQMessage(const std::string& topic, const std::string& tags, const std::string& keys, const std::string& body); + MQMessage(const std::string& topic, + const std::string& tags, + const std::string& keys, + const int flag, + const std::string& body, + bool waitStoreMsgOK); + + virtual ~MQMessage(); + MQMessage(const MQMessage& other); + MQMessage& operator=(const MQMessage& other); + + void setProperty(const std::string& name, const std::string& value); + const std::string& getProperty(const std::string& name) const; + + const std::string& getTopic() const; + void setTopic(const std::string& topic); + void setTopic(const char* body, int len); + + const std::string& getTags() const; + void setTags(const std::string& tags); + + const std::string& getKeys() const; + void setKeys(const std::string& keys); + void setKeys(const std::vector& keys); + + int getDelayTimeLevel() const; + void setDelayTimeLevel(int level); + + bool isWaitStoreMsgOK() const; + void setWaitStoreMsgOK(bool waitStoreMsgOK); + + int getFlag() const; + void setFlag(int flag); + + int getSysFlag() const; + void setSysFlag(int sysFlag); + + const std::string& getBody() const; + + void setBody(const char* body, int len); + void setBody(const std::string& body); + + void setTransactionId(const std::string& id) { m_transactionId = id; } + std::string getTransactionId() const { return m_transactionId; } + + std::map getProperties() const; + void setProperties(std::map& properties); + + const std::string toString() const { + std::stringstream ss; + std::string tags = getTags(); + ss << "Message [topic=" << m_topic << ", flag=" << m_flag << ", tag=" << tags << "]"; + return ss.str(); + } + + protected: + friend class MQDecoder; + void setPropertyInternal(const std::string& name, const std::string& value); + void setPropertiesInternal(std::map& properties); + + void Init(const std::string& topic, + const std::string& tags, + const std::string& keys, + const int flag, + const std::string& body, + bool waitStoreMsgOK); + + public: + static const std::string PROPERTY_KEYS; + static const std::string PROPERTY_TAGS; + static const std::string PROPERTY_WAIT_STORE_MSG_OK; + static const std::string PROPERTY_DELAY_TIME_LEVEL; + static const std::string PROPERTY_RETRY_TOPIC; + static const std::string PROPERTY_REAL_TOPIC; + static const std::string PROPERTY_REAL_QUEUE_ID; + static const std::string PROPERTY_TRANSACTION_PREPARED; + static const std::string PROPERTY_PRODUCER_GROUP; + static const std::string PROPERTY_MIN_OFFSET; + static const std::string PROPERTY_MAX_OFFSET; + + static const std::string PROPERTY_BUYER_ID; + static const std::string PROPERTY_ORIGIN_MESSAGE_ID; + static const std::string PROPERTY_TRANSFER_FLAG; + static const std::string PROPERTY_CORRECTION_FLAG; + static const std::string PROPERTY_MQ2_FLAG; + static const std::string PROPERTY_RECONSUME_TIME; + static const std::string PROPERTY_MSG_REGION; + static const std::string PROPERTY_TRACE_SWITCH; + static const std::string PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX; + static const std::string PROPERTY_MAX_RECONSUME_TIMES; + static const std::string PROPERTY_CONSUME_START_TIMESTAMP; + static const std::string PROPERTY_TRANSACTION_PREPARED_QUEUE_OFFSET; + static const std::string PROPERTY_TRANSACTION_CHECK_TIMES; + static const std::string PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS; + + static const std::string KEY_SEPARATOR; + + protected: + int m_sysFlag; + + private: + std::string m_topic; + int m_flag; + std::string m_body; + std::string m_transactionId; + std::map m_properties; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/MQMessageExt.h b/rocketmq/MQMessageExt.h new file mode 100644 index 0000000..194043e --- /dev/null +++ b/rocketmq/MQMessageExt.h @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __MESSAGEEXT_H__ +#define __MESSAGEEXT_H__ + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#include "MQMessage.h" +#include "RocketMQClient.h" + +namespace rocketmq { +// +#include "MQMessageExt.h" +#include "MQMessageQueue.h" + +namespace rocketmq { +//& msgs) = 0; + virtual MessageListenerType getMessageListenerType() { return messageListenerDefaultly; } +}; + +class ROCKETMQCLIENT_API MessageListenerOrderly : public MQMessageListener { + public: + virtual ~MessageListenerOrderly() {} + virtual ConsumeStatus consumeMessage(const std::vector& msgs) = 0; + virtual MessageListenerType getMessageListenerType() { return messageListenerOrderly; } +}; + +class ROCKETMQCLIENT_API MessageListenerConcurrently : public MQMessageListener { + public: + virtual ~MessageListenerConcurrently() {} + virtual ConsumeStatus consumeMessage(const std::vector& msgs) = 0; + virtual MessageListenerType getMessageListenerType() { return messageListenerConcurrently; } +}; + +} // namespace rocketmq +#endif diff --git a/rocketmq/MQMessageQueue.h b/rocketmq/MQMessageQueue.h new file mode 100644 index 0000000..abb1c00 --- /dev/null +++ b/rocketmq/MQMessageQueue.h @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __MQMESSAGEQUEUE_H__ +#define __MQMESSAGEQUEUE_H__ + +#include +#include +#include +#include "RocketMQClient.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API MQMessageQueue { + public: + MQMessageQueue(); + MQMessageQueue(const std::string& topic, const std::string& brokerName, int queueId); + MQMessageQueue(const MQMessageQueue& other); + MQMessageQueue& operator=(const MQMessageQueue& other); + + std::string getTopic() const; + void setTopic(const std::string& topic); + + std::string getBrokerName() const; + void setBrokerName(const std::string& brokerName); + + int getQueueId() const; + void setQueueId(int queueId); + + bool operator==(const MQMessageQueue& mq) const; + bool operator<(const MQMessageQueue& mq) const; + int compareTo(const MQMessageQueue& mq) const; + + const std::string toString() const { + std::stringstream ss; + ss << "MessageQueue [topic=" << m_topic << ", brokerName=" << m_brokerName << ", queueId=" << m_queueId << "]"; + + return ss.str(); + } + + private: + std::string m_topic; + std::string m_brokerName; + int m_queueId; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/MQSelector.h b/rocketmq/MQSelector.h new file mode 100644 index 0000000..fd9dfbc --- /dev/null +++ b/rocketmq/MQSelector.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef _MQSELECTOR_H_ +#define _MQSELECTOR_H_ +#include "MQMessage.h" +#include "MQMessageQueue.h" +#include "RocketMQClient.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API MessageQueueSelector { + public: + virtual ~MessageQueueSelector() {} + virtual MQMessageQueue select(const std::vector& mqs, const MQMessage& msg, void* arg) = 0; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/MQueueListener.h b/rocketmq/MQueueListener.h new file mode 100644 index 0000000..9f93781 --- /dev/null +++ b/rocketmq/MQueueListener.h @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __MESSAGEQUEUELISTENER_H__ +#define __MESSAGEQUEUELISTENER_H__ + +#include +#include "RocketMQClient.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API MQueueListener { + public: + virtual ~MQueueListener() {} + virtual void messageQueueChanged(const std::string& topic, + std::vector& mqAll, + std::vector& mqDivided) = 0; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/PullResult.h b/rocketmq/PullResult.h new file mode 100644 index 0000000..1182172 --- /dev/null +++ b/rocketmq/PullResult.h @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __PULLRESULT_H__ +#define __PULLRESULT_H__ + +#include +#include "MQMessageExt.h" +#include "RocketMQClient.h" + +namespace rocketmq { +enum PullStatus { + FOUND, + NO_NEW_MSG, + NO_MATCHED_MSG, + OFFSET_ILLEGAL, + BROKER_TIMEOUT // indicate pull request timeout or received NULL response +}; + +static const char* EnumStrings[] = {"FOUND", "NO_NEW_MSG", "NO_MATCHED_MSG", "OFFSET_ILLEGAL", "BROKER_TIMEOUT"}; + +class ROCKETMQCLIENT_API PullResult { + public: + PullResult(); + PullResult(PullStatus status); + PullResult(PullStatus pullStatus, int64 nextBeginOffset, int64 minOffset, int64 maxOffset); + + PullResult(PullStatus pullStatus, + int64 nextBeginOffset, + int64 minOffset, + int64 maxOffset, + const std::vector& src); + + virtual ~PullResult(); + + std::string toString() { + std::stringstream ss; + ss << "PullResult [ pullStatus=" << EnumStrings[pullStatus] << ", nextBeginOffset=" << nextBeginOffset + << ", minOffset=" << minOffset << ", maxOffset=" << maxOffset << ", msgFoundList=" << msgFoundList.size() + << " ]"; + return ss.str(); + } + + public: + PullStatus pullStatus; + int64 nextBeginOffset; + int64 minOffset; + int64 maxOffset; + std::vector msgFoundList; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/RocketMQClient.h b/rocketmq/RocketMQClient.h new file mode 100644 index 0000000..5449d65 --- /dev/null +++ b/rocketmq/RocketMQClient.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __ROCKETMQCLIENT_H__ +#define __ROCKETMQCLIENT_H__ + +#ifdef WIN32 +#ifdef ROCKETMQCLIENT_EXPORTS +#ifdef _WINDLL +#define ROCKETMQCLIENT_API __declspec(dllexport) +#else +#define ROCKETMQCLIENT_API +#endif +#else +#ifdef ROCKETMQCLIENT_IMPORT +#define ROCKETMQCLIENT_API __declspec(dllimport) +#else +#define ROCKETMQCLIENT_API +#endif +#endif +#else +#define ROCKETMQCLIENT_API +#endif + +/** A platform-independent 8-bit signed integer type. */ +typedef signed char int8; +/** A platform-independent 8-bit unsigned integer type. */ +typedef unsigned char uint8; +/** A platform-independent 16-bit signed integer type. */ +typedef signed short int16; +/** A platform-independent 16-bit unsigned integer type. */ +typedef unsigned short uint16; +/** A platform-independent 32-bit signed integer type. */ +typedef signed int int32; +/** A platform-independent 32-bit unsigned integer type. */ +typedef unsigned int uint32; +/** A platform-independent 64-bit integer type. */ +typedef long long int64; +/** A platform-independent 64-bit unsigned integer type. */ +typedef unsigned long long uint64; + +#endif diff --git a/rocketmq/SendResult.h b/rocketmq/SendResult.h new file mode 100644 index 0000000..6bfa431 --- /dev/null +++ b/rocketmq/SendResult.h @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#ifndef __SENDRESULT_H__ +#define __SENDRESULT_H__ + +#include "MQMessageQueue.h" +#include "RocketMQClient.h" + +namespace rocketmq { + +enum SendStatus { SEND_OK, SEND_FLUSH_DISK_TIMEOUT, SEND_FLUSH_SLAVE_TIMEOUT, SEND_SLAVE_NOT_AVAILABLE }; + +class ROCKETMQCLIENT_API SendResult { + public: + SendResult(); + SendResult(const SendStatus& sendStatus, + const std::string& msgId, + const std::string& offsetMsgId, + const MQMessageQueue& messageQueue, + int64 queueOffset); + SendResult(const SendStatus& sendStatus, + const std::string& msgId, + const std::string& offsetMsgId, + const MQMessageQueue& messageQueue, + int64 queueOffset, + const std::string& regionId); + + virtual ~SendResult(); + SendResult(const SendResult& other); + SendResult& operator=(const SendResult& other); + + void setTransactionId(const std::string& id) { m_transactionId = id; } + + std::string getTransactionId() { return m_transactionId; } + + const std::string& getMsgId() const; + const std::string& getOffsetMsgId() const; + + const std::string& getRegionId() const; + void setRegionId(const std::string& regionId); + SendStatus getSendStatus() const; + MQMessageQueue getMessageQueue() const; + int64 getQueueOffset() const; + std::string toString() const; + + private: + SendStatus m_sendStatus; + std::string m_msgId; + std::string m_offsetMsgId; + MQMessageQueue m_messageQueue; + int64 m_queueOffset; + std::string m_transactionId; + std::string m_regionId; +}; + +} // namespace rocketmq +#endif diff --git a/rocketmq/SessionCredentials.h b/rocketmq/SessionCredentials.h new file mode 100644 index 0000000..e035160 --- /dev/null +++ b/rocketmq/SessionCredentials.h @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __SESSIONCREDENTIALS_H__ +#define __SESSIONCREDENTIALS_H__ + +#include "RocketMQClient.h" + +namespace rocketmq { + +class SessionCredentials { + public: + static const std::string AccessKey; + static const std::string SecretKey; + static const std::string Signature; + static const std::string SignatureMethod; + static const std::string ONSChannelKey; + + SessionCredentials(std::string input_accessKey, std::string input_secretKey, const std::string& input_authChannel) + : accessKey(input_accessKey), secretKey(input_secretKey), authChannel(input_authChannel) {} + SessionCredentials() : authChannel("ALIYUN") {} + ~SessionCredentials() {} + + std::string getAccessKey() const { return accessKey; } + + void setAccessKey(std::string input_accessKey) { accessKey = input_accessKey; } + + std::string getSecretKey() const { return secretKey; } + + void setSecretKey(std::string input_secretKey) { secretKey = input_secretKey; } + + std::string getSignature() const { return signature; } + + void setSignature(std::string input_signature) { signature = input_signature; } + + std::string getSignatureMethod() const { return signatureMethod; } + + void setSignatureMethod(std::string input_signatureMethod) { signatureMethod = input_signatureMethod; } + + std::string getAuthChannel() const { return authChannel; } + + void setAuthChannel(std::string input_channel) { authChannel = input_channel; } + + bool isValid() const { + if (accessKey.empty() || secretKey.empty() || authChannel.empty()) + return false; + + return true; + } + + private: + std::string accessKey; + std::string secretKey; + std::string signature; + std::string signatureMethod; + std::string authChannel; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/SimpleProducer.h b/rocketmq/SimpleProducer.h new file mode 100644 index 0000000..0765a6f --- /dev/null +++ b/rocketmq/SimpleProducer.h @@ -0,0 +1,15 @@ +#include "../json/mms_json_inter.h" +#include "../include/rocketmq/CProducer.h" +#include "../include/rocketmq/CMessage.h" +#include "../include/rocketmq/CSendResult.h" +/*添加测试函数lnk10-10*/ +void producer_send0(); +void StartSendMessage(CProducer* producer); +void StartSendMessage(CProducer* producer,const char* strbody); +void producer_send(const char* strbody); +void rocketmq_producer_send(const char* strbody,const char* topic); +void rocketmq_StartSendMessage(CProducer* producer,const char* strbody,std::string topic); +void rocketmq_test(); +void my_rocketmq_send(Ckafka_data_t& data); + +////////////////////////////////////////////////////// \ No newline at end of file diff --git a/rocketmq/TransactionListener.h b/rocketmq/TransactionListener.h new file mode 100644 index 0000000..6756e96 --- /dev/null +++ b/rocketmq/TransactionListener.h @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __TRANSACTIONLISTENER_H__ +#define __TRANSACTIONLISTENER_H__ + +#include "MQMessage.h" +#include "MQMessageExt.h" +#include "TransactionSendResult.h" + +namespace rocketmq { +class ROCKETMQCLIENT_API TransactionListener { + public: + virtual ~TransactionListener() {} + /** + * When send transactional prepare(half) message succeed, this method will be invoked to execute local transaction. + * + * @param msg Half(prepare) message + * @param arg Custom business parameter + * @return Transaction state + */ + virtual LocalTransactionState executeLocalTransaction(const MQMessage& msg, void* arg) = 0; + + /** + * When no response to prepare(half) message. broker will send check message to check the transaction status, and this + * method will be invoked to get local transaction status. + * + * @param msg Check message + * @return Transaction state + */ + virtual LocalTransactionState checkLocalTransaction(const MQMessageExt& msg) = 0; +}; +} // namespace rocketmq +#endif diff --git a/rocketmq/TransactionMQProducer.h b/rocketmq/TransactionMQProducer.h new file mode 100644 index 0000000..784de6c --- /dev/null +++ b/rocketmq/TransactionMQProducer.h @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __TRANSACTIONMQPRODUCER_H__ +#define __TRANSACTIONMQPRODUCER_H__ + +#include +#include +#include "MQClient.h" +#include "MQMessage.h" +#include "MQMessageExt.h" +#include "SessionCredentials.h" +#include "TransactionListener.h" +#include "TransactionSendResult.h" + +namespace rocketmq { +class TransactionMQProducerImpl; +class ROCKETMQCLIENT_API TransactionMQProducer { + public: + TransactionMQProducer(const std::string& producerGroup); + virtual ~TransactionMQProducer(); + + void start(); + void shutdown(); + std::string version(); + + const std::string& getNamesrvAddr() const; + void setNamesrvAddr(const std::string& namesrvAddr); + const std::string& getNamesrvDomain() const; + void setNamesrvDomain(const std::string& namesrvDomain); + const std::string& getInstanceName() const; + void setInstanceName(const std::string& instanceName); + + const std::string& getNameSpace() const; + void setNameSpace(const std::string& nameSpace); + const std::string& getGroupName() const; + void setGroupName(const std::string& groupname); + void setSessionCredentials(const std::string& accessKey, + const std::string& secretKey, + const std::string& accessChannel); + const SessionCredentials& getSessionCredentials() const; + + void setUnitName(std::string unitName); + const std::string& getUnitName() const; + + int getSendMsgTimeout() const; + void setSendMsgTimeout(int sendMsgTimeout); + void setTcpTransportPullThreadNum(int num); + int getTcpTransportPullThreadNum() const; + + void setTcpTransportConnectTimeout(uint64_t timeout); // ms + uint64_t getTcpTransportConnectTimeout() const; + + void setTcpTransportTryLockTimeout(uint64_t timeout); // ms + uint64_t getTcpTransportTryLockTimeout() const; + + int getCompressMsgBodyOverHowmuch() const; + void setCompressMsgBodyOverHowmuch(int compressMsgBodyOverHowmuch); + int getCompressLevel() const; + void setCompressLevel(int compressLevel); + + int getMaxMessageSize() const; + void setMaxMessageSize(int maxMessageSize); + + void setLogLevel(elogLevel inputLevel); + elogLevel getLogLevel(); + void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit + void setMessageTrace(bool messageTrace); + bool getMessageTrace() const; + std::shared_ptr getTransactionListener(); + void setTransactionListener(TransactionListener* listener); + TransactionSendResult sendMessageInTransaction(MQMessage& msg, void* arg); + void checkTransactionState(const std::string& addr, + const MQMessageExt& message, + long tranStateTableOffset, + long commitLogOffset, + const std::string& msgId, + const std::string& transactionId, + const std::string& offsetMsgId); + + private: + TransactionMQProducerImpl* impl; +}; +} // namespace rocketmq + +#endif diff --git a/rocketmq/TransactionSendResult.h b/rocketmq/TransactionSendResult.h new file mode 100644 index 0000000..0bb1e48 --- /dev/null +++ b/rocketmq/TransactionSendResult.h @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef __TRANSACTIONSENDRESULT_H__ +#define __TRANSACTIONSENDRESULT_H__ + +#include "SendResult.h" + +namespace rocketmq { + +enum LocalTransactionState { COMMIT_MESSAGE, ROLLBACK_MESSAGE, UNKNOWN }; + +class ROCKETMQCLIENT_API TransactionSendResult : public SendResult { + public: + TransactionSendResult() {} + + TransactionSendResult(const SendStatus& sendStatus, + const std::string& msgId, + const std::string& offsetMsgId, + const MQMessageQueue& messageQueue, + int64 queueOffset) + : SendResult(sendStatus, msgId, offsetMsgId, messageQueue, queueOffset) {} + + LocalTransactionState getLocalTransactionState() { return m_localTransactionState; } + + void setLocalTransactionState(LocalTransactionState localTransactionState) { + m_localTransactionState = localTransactionState; + } + + private: + LocalTransactionState m_localTransactionState; +}; +} // namespace rocketmq +#endif \ No newline at end of file diff --git a/set_process.sh b/set_process.sh new file mode 100644 index 0000000..a331b83 --- /dev/null +++ b/set_process.sh @@ -0,0 +1,259 @@ +##!/bin/bash + +# @file: set_process.sh +# @brief: 系统应用添加进程脚本 +# @version: 1.0 +# @date: 2024/12/31 10:22:43 +# @author: lunankun + +#前置all的重置或者新增都是由稳态的第一个进程来处理,所有进程收到这条消息后先判断自己的进程号是否是1,而且是稳态,否则不处理,所有操作均由这个进程完成, + +# 设置日志文件路径 +LOGFILE="$FEP_ENV/dat/log/start_fe.log" + +# 输出当前时间并打印进程停止信息 +echo "" ; echo "" +echo "****** `date "+%F %R:%S"` start setting Processes after 3 sec ******" +echo "" >>"$LOGFILE" +echo "" >>"$LOGFILE" +echo "****** `date "+%F %R:%S"` start setting Processes after 3 sec ******" >>"$LOGFILE" + +# 函数检查并处理日志文件大小 +check_log_file() { + if [ -n "$1" ]; then + FILE_SIZE=0 + FILE_SIZE=$(du "$1" | awk '{print $1}') + + if [ $FILE_SIZE -ge 5120 ]; then + if [ -f "$1".3 ]; then + rm -f "$1".3 + fi + if [ -f "$1".2 ]; then + mv "$1".2 "$1".3 + fi + if [ -f "$1".1 ]; then + mv "$1".1 "$1".2 + fi + mv "$1" "$1".1 + fi + fi +} + + +# 调用检查日志文件大小的函数 +check_log_file $LOGFILE + +# 定义查找并杀死进程的函数 +kill_process_by_name() { + PROCESS_NAME=$1 + PID=$(ps -ef | grep "$PROCESS_NAME" | grep -v "grep" | awk '{print $2}') + + if [ -n "$PID" ]; then + echo "Found process '$PROCESS_NAME' with PID: $PID" + echo "Killing process..." + kill -9 $PID + if [ $? -eq 0 ]; then + echo "Process '$PROCESS_NAME' killed successfully." + else + echo "Failed to kill the process '$PROCESS_NAME'." + fi + else + echo "Process '$PROCESS_NAME' not found." + fi +} + +# 功能块开始 +handle_reset() { + # 功能:reset + # 进程号:$1 + # 进程类型:$2 + if [ "$1" -ge 1 ] && [ "$1" -lt 10 ]; then + if [ "$2" == "all" ]; then + + # 关闭旧的看门狗进程 + kill_process_by_name "/FeProject/bin/fe_watchdog" + + # 关闭旧的 stat 进程 + kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_stat_data" + + # 关闭旧的 recall 进程 + kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_recallhis_data" + + # 关闭旧的 3s 进程 + kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_3s_data" + + # 关闭旧的 comtrade 进程 + kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_soe_comtrade" + + #关闭进程后等待一段时间,防止端口占用 + #sleep 5 + + # 清空 runtime.cf 中的所有进程配置 + sed -i '/cfg_stat_data/d' /home/pq/FeProject/etc/runtime.cf + sed -i '/cfg_recallhis_data/d' /home/pq/FeProject/etc/runtime.cf + sed -i '/cfg_3s_data/d' /home/pq/FeProject/etc/runtime.cf + sed -i '/cfg_soe_comtrade/d' /home/pq/FeProject/etc/runtime.cf + sed -i '/fe_watchdog/d' /home/pq/FeProject/etc/runtime.cf + + # 根据进程号添加对应进程配置 + if [ "$1" -eq 1 ]; then + #看门狗固定放在第一个,防止stop时会把要杀死的进程重启 + sed -i "2a\\$(printf '/FeProject/bin/ ^ fe_watchdog -m 8192 ^ ^ ^ 1 ^ IGNORE_RESTART ^\n')" /home/pq/FeProject/etc/runtime.cf + # 进程号为 1,按固定格式添加 + sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s 1_1^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf + sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s 1_1^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf + sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_3s_data^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf + sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_soe_comtrade^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf + + else + #看门狗固定放在第一个,防止stop时会把要杀死的进程重启 + sed -i "2a\\$(printf '/FeProject/bin/ ^ fe_watchdog -m 8192 ^ ^ ^ 1 ^ IGNORE_RESTART ^\n')" /home/pq/FeProject/etc/runtime.cf + # 进程号大于 1,按 -s ${i}_ 格式添加 + for i in $(seq 1 $1); do + # 在 runtime.cf 中插入对应的配置行,直接插入变量替换结果 + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s ${i}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s ${i}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + done + #以下部分没有多进程 + sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_3s_data^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf + sed -i "2a\\$(printf '/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_soe_comtrade^ ^ ^ 1 ^ ^\n')" /home/pq/FeProject/etc/runtime.cf + + fi + + # 确保文件已被写入并刷新 + sync + + # 重新启动服务 + + /home/pq/FeProject/boot/start_fe.sh + + echo "****** reset all in $1******" >>"$LOGFILE" + elif [ "$2" == "stat" ]; then + # 清空 runtime.cf 中包含 cfg_stat_data 的行 + sed -i '/cfg_stat_data/d' /home/pq/FeProject/etc/runtime.cf + + # 根据进程号来添加新的进程配置 + for i in $(seq 1 $1); do + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s ${i}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + done + + # 关闭旧的看门狗进程 + kill_process_by_name "/FeProject/bin/fe_watchdog" + + # 关闭旧的 stat 进程 + kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_stat_data" + + #sleep 5 + + # 启动服务不影响其他功能的进程 + /home/pq/FeProject/boot/start_fe.sh + + echo "****** reset stat in $1******" >>"$LOGFILE" + elif [ "$2" == "recall" ]; then + # 清空 runtime.cf 中包含 cfg_recallhis_data 的行 + sed -i '/cfg_recallhis_data/d' /home/pq/FeProject/etc/runtime.cf + + # 根据进程号来添加新的进程配置 + for i in $(seq 1 $1); do + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s ${i}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + done + + # 关闭旧的看门狗进程 + kill_process_by_name "/FeProject/bin/fe_watchdog" + # 关闭旧的 recall 进程 + kill_process_by_name "/FeProject/bin/pt61850netd_pqfe -d cfg_recallhis_data" + + #sleep 5 + + # 启动服务不影响其他功能的进程 + /home/pq/FeProject/boot/start_fe.sh + + echo "****** reset recall in $1******" >>"$LOGFILE" + else + echo "****** process reset type null ******" + echo "****** process reset type null ******" >>"$LOGFILE" + fi + else + # 如果 $1 不在 1 到 10 之间,记录错误日志 + echo "****** Error: Invalid process number '$1'. It must be between 1 and 10. ******" + echo "****** Error: Invalid process number '$1'. It must be between 1 and 10. ******" >>"$LOGFILE" + fi +} + +handle_add() { + # 功能:add + # 进程号:$1 + # 进程类型:$2 + + + if [ "$1" -gt 1 ] && [ "$1" -lt 10 ]; then + # 如果 $1 在 1 和 10 之间,进入处理逻辑 + if [ "$2" == "all" ]; then + # 检查是否已存在该条目,避免重复添加 + if ! grep -q "/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s ${1}_${1}^" /home/pq/FeProject/etc/runtime.cf; then + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s ${1}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + fi + + if ! grep -q "/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s ${1}_${1}^" /home/pq/FeProject/etc/runtime.cf; then + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s ${1}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + fi + elif [ "$2" == "stat" ]; then + # 检查是否已存在该条目,避免重复添加 + if ! grep -q "/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s ${1}_${1}^" /home/pq/FeProject/etc/runtime.cf; then + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_stat_data -s ${1}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + fi + elif [ "$2" == "recall" ]; then + # 检查是否已存在该条目,避免重复添加 + if ! grep -q "/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s ${1}_${1}^" /home/pq/FeProject/etc/runtime.cf; then + sed -i "2a/FeProject/bin/ ^ pt61850netd_pqfe -d cfg_recallhis_data -s ${1}_${1}^ ^ ^ 1 ^ ^" /home/pq/FeProject/etc/runtime.cf + fi + else + echo "****** process add type null ******" + echo "****** process add type null ******" >> "$LOGFILE" + fi + + # 关闭旧的看门狗进程 + kill_process_by_name "/FeProject/bin/fe_watchdog" + + #sleep 5 + + # 启动服务,不影响正在运行的进程 + /home/pq/FeProject/boot/start_fe.sh + + else + # 如果 $1 不在 1 到 10 之间,记录错误日志 + echo "****** Error: Invalid process number '$1'. It must be between 1 and 10. ******" + echo "****** Error: Invalid process number '$1'. It must be between 1 and 10. ******" >> "$LOGFILE" + fi + + echo "****** add $2 -- $1******" >>"$LOGFILE" +} + +# 获取当前脚本的进程ID +CURRENT_PID=$$ + +# 检查是否有其他的set_process.sh脚本正在运行,排除当前脚本 +if pgrep -f "set_process.sh" | grep -v "^$CURRENT_PID$" > /dev/null; then + echo "set_process.sh is already running. Exiting..." + echo "set_process.sh is already running. Exiting..." >>"$LOGFILE" + exit 1 +fi + +#脚本应该等待3秒钟 +sleep 3 + +# 根据入参判断是 reset 还是 add +if [ "$1" == "reset" ]; then + handle_reset $2 $3 +elif [ "$1" == "add" ]; then + handle_add $2 $3 +else + echo "Invalid option. Usage: $0 {reset|add} {process_number} {process_type}" + exit 1 +fi + +# 获取当前时间并记录进程添加成功的日志 +DT=$(date "+%F %R:%S.%N") +echo "****** ${DT:0:23} set Processes Successfully ******" +echo "" >>"$LOGFILE" +echo "****** ${DT:0:23} set Processes Successfully ******" >>"$LOGFILE" diff --git a/x64/Debug/pt61850netd_pqfe.Build.CppClean.log b/x64/Debug/pt61850netd_pqfe.Build.CppClean.log new file mode 100644 index 0000000..e69de29 diff --git a/x64/Debug/pt61850netd_pqfe.log b/x64/Debug/pt61850netd_pqfe.log new file mode 100644 index 0000000..96f1b9d --- /dev/null +++ b/x64/Debug/pt61850netd_pqfe.log @@ -0,0 +1 @@ +D:\Personal Program\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppBuild.targets(456,5): error MSB8020: 无法找到 Visual Studio 2019 的生成工具(平台工具集 =“v142”)。若要使用 v142 生成工具进行生成,请安装 Visual Studio 2019 生成工具。或者,可以升级到当前 Visual Studio 工具,方式是通过选择“项目”菜单或右键单击该解决方案,然后选择“重定解决方案目标”。 diff --git a/x64/Debug/pt61850netd_pqfe.vcxproj.FileListAbsolute.txt b/x64/Debug/pt61850netd_pqfe.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29