nginx-util: fix issues and cleanup
* fix regex capture (to conform std) * fix issues for Clang/libcxx (warnings/includes) * fix CONFLICTS in the Makefile * use /bin/sh in host scripts and shellcheck them * add callback for setting arguments in ubus::call Signed-off-by: Peter Stadler <peter.stadler@student.uibk.ac.at>
This commit is contained in:
parent
5e6b871e9e
commit
2d359a4556
13 changed files with 421 additions and 281 deletions
|
@ -1,8 +1,8 @@
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=nginx-util
|
PKG_NAME:=nginx-util
|
||||||
PKG_VERSION:=1.3
|
PKG_VERSION:=1.4
|
||||||
PKG_RELEASE:=2
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at>
|
PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at>
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
@ -11,6 +11,7 @@ include $(INCLUDE_DIR)/cmake.mk
|
||||||
CMAKE_OPTIONS+= -DUBUS=y
|
CMAKE_OPTIONS+= -DUBUS=y
|
||||||
CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION)
|
CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION)
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util/default
|
define Package/nginx-util/default
|
||||||
SECTION:=net
|
SECTION:=net
|
||||||
CATEGORY:=Network
|
CATEGORY:=Network
|
||||||
|
@ -19,63 +20,75 @@ define Package/nginx-util/default
|
||||||
DEPENDS:=+libstdcpp +libubus +libubox +libpthread
|
DEPENDS:=+libstdcpp +libubus +libubox +libpthread
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util
|
define Package/nginx-util
|
||||||
$(Package/nginx-util/default)
|
$(Package/nginx-util/default)
|
||||||
CONFLICTS:=nginx-ssl-util-nopcre nginx-ssl-util
|
CONFLICTS:=nginx-ssl-util-nopcre nginx-ssl-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util/default
|
define Package/nginx-ssl-util/default
|
||||||
$(Package/nginx-util/default)
|
$(Package/nginx-util/default)
|
||||||
TITLE+= including SSL
|
TITLE+= including SSL
|
||||||
DEPENDS+= +libopenssl
|
DEPENDS+= +libopenssl
|
||||||
CONFLICTS:=,nginx-util
|
CONFLICTS:=nginx-util,
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util
|
define Package/nginx-ssl-util
|
||||||
$(Package/nginx-ssl-util/default)
|
$(Package/nginx-ssl-util/default)
|
||||||
TITLE+= (using PCRE)
|
TITLE+= (using PCRE)
|
||||||
DEPENDS+= +libpcre
|
DEPENDS+= +libpcre
|
||||||
CONFLICTS+= ,nginx-ssl-util-nopcre
|
CONFLICTS+= nginx-ssl-util-nopcre,
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util-nopcre
|
define Package/nginx-ssl-util-nopcre
|
||||||
$(Package/nginx-ssl-util/default)
|
$(Package/nginx-ssl-util/default)
|
||||||
TITLE+= (using <regex>)
|
TITLE+= (using <regex>)
|
||||||
CONFLICTS+= nginx-ssl-util
|
CONFLICTS+= nginx-ssl-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util/description
|
define Package/nginx-util/description
|
||||||
Utility that builds dynamically LAN listen directives for Nginx.
|
Utility that builds dynamically LAN listen directives for Nginx.
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
Package/nginx-ssl-util/default/description = $(Package/nginx-util/description)\
|
Package/nginx-ssl-util/default/description = $(Package/nginx-util/description)\
|
||||||
Furthermore, it manages SSL directives for its server parts and can create \
|
Furthermore, it manages SSL directives for its server parts and can create \
|
||||||
corresponding (self-signed) certificates.
|
corresponding (self-signed) certificates.
|
||||||
|
|
||||||
|
|
||||||
Package/nginx-ssl-util/description = \
|
Package/nginx-ssl-util/description = \
|
||||||
$(Package/nginx-ssl-util/default/description) \
|
$(Package/nginx-ssl-util/default/description) \
|
||||||
It uses the PCRE library for performance.
|
It uses the PCRE library for performance.
|
||||||
|
|
||||||
|
|
||||||
Package/nginx-ssl-util-nopcre/description = \
|
Package/nginx-ssl-util-nopcre/description = \
|
||||||
$(Package/nginx-ssl-util/default/description) \
|
$(Package/nginx-ssl-util/default/description) \
|
||||||
It uses the standard regex library of C++.
|
It uses the standard regex library of C++.
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util/install
|
define Package/nginx-util/install
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-util $(1)/usr/bin/nginx-util
|
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-util $(1)/usr/bin/nginx-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util/install
|
define Package/nginx-ssl-util/install
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util $(1)/usr/bin/nginx-util
|
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util $(1)/usr/bin/nginx-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util-nopcre/install
|
define Package/nginx-ssl-util-nopcre/install
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util-nopcre \
|
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util-nopcre \
|
||||||
$(1)/usr/bin/nginx-util
|
$(1)/usr/bin/nginx-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
$(eval $(call BuildPackage,nginx-util))
|
$(eval $(call BuildPackage,nginx-util))
|
||||||
$(eval $(call BuildPackage,nginx-ssl-util))
|
$(eval $(call BuildPackage,nginx-ssl-util))
|
||||||
$(eval $(call BuildPackage,nginx-ssl-util-nopcre))
|
$(eval $(call BuildPackage,nginx-ssl-util-nopcre))
|
||||||
|
|
|
@ -5,15 +5,8 @@ SET(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
INCLUDE(CheckFunctionExists)
|
INCLUDE(CheckFunctionExists)
|
||||||
|
|
||||||
IF(UBUS)
|
|
||||||
FIND_PATH(ubus_include_dir libubus.h)
|
|
||||||
FIND_LIBRARY(ubox NAMES ubox)
|
|
||||||
FIND_LIBRARY(ubus NAMES ubus)
|
|
||||||
INCLUDE_DIRECTORIES(${ubus_include_dir})
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
ADD_DEFINITIONS(-Os -Wall -Werror -Wextra -g3)
|
ADD_DEFINITIONS(-Os -Wall -Werror -Wextra -g3)
|
||||||
ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations)
|
ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations -Wshadow)
|
||||||
|
|
||||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||||
|
|
||||||
|
@ -22,6 +15,14 @@ IF(UBUS)
|
||||||
|
|
||||||
ADD_COMPILE_DEFINITIONS(VERSION=${VERSION})
|
ADD_COMPILE_DEFINITIONS(VERSION=${VERSION})
|
||||||
|
|
||||||
|
FIND_PATH(ubus_include_dir libubus.h)
|
||||||
|
FIND_LIBRARY(ubus NAMES ubus)
|
||||||
|
INCLUDE_DIRECTORIES(${ubus_include_dir})
|
||||||
|
|
||||||
|
FIND_PATH(ubox_include_dir libubox/blobmsg.h)
|
||||||
|
FIND_LIBRARY(ubox NAMES ubox)
|
||||||
|
INCLUDE_DIRECTORIES(${ubox_include_dir})
|
||||||
|
|
||||||
ADD_EXECUTABLE(nginx-util nginx-util.cpp)
|
ADD_EXECUTABLE(nginx-util nginx-util.cpp)
|
||||||
TARGET_COMPILE_DEFINITIONS(nginx-util PUBLIC -DNO_SSL)
|
TARGET_COMPILE_DEFINITIONS(nginx-util PUBLIC -DNO_SSL)
|
||||||
TARGET_LINK_LIBRARIES(nginx-util ${ubox} ${ubus} pthread)
|
TARGET_LINK_LIBRARIES(nginx-util ${ubox} ${ubus} pthread)
|
||||||
|
@ -38,6 +39,8 @@ INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
ELSE()
|
ELSE()
|
||||||
|
|
||||||
|
ADD_COMPILE_DEFINITIONS(VERSION=0)
|
||||||
|
|
||||||
CONFIGURE_FILE(test-px5g.sh test-px5g.sh COPYONLY)
|
CONFIGURE_FILE(test-px5g.sh test-px5g.sh COPYONLY)
|
||||||
CONFIGURE_FILE(test-nginx-util.sh test-nginx-util.sh COPYONLY)
|
CONFIGURE_FILE(test-nginx-util.sh test-nginx-util.sh COPYONLY)
|
||||||
CONFIGURE_FILE(test-nginx-util-root.sh test-nginx-util-root.sh COPYONLY)
|
CONFIGURE_FILE(test-nginx-util-root.sh test-nginx-util-root.sh COPYONLY)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#ifndef __NGINX_SSL_UTIL_HPP
|
#ifndef __NGINX_SSL_UTIL_HPP
|
||||||
#define __NGINX_SSL_UTIL_HPP
|
#define __NGINX_SSL_UTIL_HPP
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#ifdef NO_PCRE
|
#ifdef NO_PCRE
|
||||||
#include <regex>
|
#include <regex>
|
||||||
namespace rgx = std;
|
namespace rgx = std;
|
||||||
|
@ -147,7 +145,7 @@ constexpr auto _end = _Line{
|
||||||
|
|
||||||
|
|
||||||
template<char clim='\0'>
|
template<char clim='\0'>
|
||||||
constexpr auto _capture = _Line{
|
static constexpr auto _capture = _Line{
|
||||||
[](const std::string & param, const std::string & /*begin*/) -> std::string
|
[](const std::string & param, const std::string & /*begin*/) -> std::string
|
||||||
{ return '\'' + param + '\''; },
|
{ return '\'' + param + '\''; },
|
||||||
|
|
||||||
|
@ -211,8 +209,8 @@ constexpr std::string_view _ssl_session_timeout = "ssl_session_timeout";
|
||||||
// * Use constexpr---not available for strings or char * for now---look at lib.
|
// * Use constexpr---not available for strings or char * for now---look at lib.
|
||||||
|
|
||||||
static const auto CRON_CMD = Line::build
|
static const auto CRON_CMD = Line::build
|
||||||
< _space, _escape<NGINX_UTIL>, _space, _escape<ADD_SSL_FCT,'\''>, _space,
|
<_space, _escape<NGINX_UTIL>, _space, _escape<ADD_SSL_FCT,'\''>, _space,
|
||||||
_capture<>, _newline >();
|
_capture<>, _newline>();
|
||||||
|
|
||||||
static const auto NGX_SERVER_NAME =
|
static const auto NGX_SERVER_NAME =
|
||||||
Line::build<_begin, _escape<_server_name>, _space, _capture<';'>, _end>();
|
Line::build<_begin, _escape<_server_name>, _space, _capture<';'>, _end>();
|
||||||
|
@ -221,15 +219,15 @@ static const auto NGX_INCLUDE_LAN_LISTEN = Line::build
|
||||||
<_begin, _escape<_include>, _space, _escape<LAN_LISTEN,'\''>, _end>();
|
<_begin, _escape<_include>, _space, _escape<LAN_LISTEN,'\''>, _end>();
|
||||||
|
|
||||||
static const auto NGX_INCLUDE_LAN_LISTEN_DEFAULT = Line::build
|
static const auto NGX_INCLUDE_LAN_LISTEN_DEFAULT = Line::build
|
||||||
< _begin, _escape<_include>, _space,
|
<_begin, _escape<_include>, _space,
|
||||||
_escape<LAN_LISTEN_DEFAULT, '\''>, _end >();
|
_escape<LAN_LISTEN_DEFAULT, '\''>, _end>();
|
||||||
|
|
||||||
static const auto NGX_INCLUDE_LAN_SSL_LISTEN = Line::build
|
static const auto NGX_INCLUDE_LAN_SSL_LISTEN = Line::build
|
||||||
<_begin, _escape<_include>, _space, _escape<LAN_SSL_LISTEN, '\''>, _end>();
|
<_begin, _escape<_include>, _space, _escape<LAN_SSL_LISTEN, '\''>, _end>();
|
||||||
|
|
||||||
static const auto NGX_INCLUDE_LAN_SSL_LISTEN_DEFAULT = Line::build
|
static const auto NGX_INCLUDE_LAN_SSL_LISTEN_DEFAULT = Line::build
|
||||||
< _begin, _escape<_include>, _space,
|
<_begin, _escape<_include>, _space,
|
||||||
_escape<LAN_SSL_LISTEN_DEFAULT, '\''>, _end >();
|
_escape<LAN_SSL_LISTEN_DEFAULT, '\''>, _end>();
|
||||||
|
|
||||||
static const auto NGX_SSL_CRT = Line::build
|
static const auto NGX_SSL_CRT = Line::build
|
||||||
<_begin, _escape<_ssl_certificate>, _space, _capture<';'>, _end>();
|
<_begin, _escape<_ssl_certificate>, _space, _capture<';'>, _end>();
|
||||||
|
@ -346,7 +344,7 @@ void add_ssl_directives_to(const std::string & name, const bool isdefault)
|
||||||
auto errmsg = std::string{"add_ssl_directives_to error: "};
|
auto errmsg = std::string{"add_ssl_directives_to error: "};
|
||||||
errmsg += "cannot add SSL directives to " + name + ".conf, missing: ";
|
errmsg += "cannot add SSL directives to " + name + ".conf, missing: ";
|
||||||
errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n";
|
errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n";
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -476,7 +474,7 @@ void use_cron_to_recreate_certificate(const std::string & name)
|
||||||
std::string errmsg{"use_cron_to_recreate_certificate error: "};
|
std::string errmsg{"use_cron_to_recreate_certificate error: "};
|
||||||
errmsg += "Cron unavailable to re-create the ssl certificate for ";
|
errmsg += "Cron unavailable to re-create the ssl certificate for ";
|
||||||
errmsg += name + "\n";
|
errmsg += name + "\n";
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
} // else active with or without instances:
|
} // else active with or without instances:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -586,7 +584,7 @@ void del_ssl_directives_from(const std::string & name, const bool isdefault)
|
||||||
auto errmsg = std::string{"del_ssl_directives_from error: "};
|
auto errmsg = std::string{"del_ssl_directives_from error: "};
|
||||||
errmsg += "cannot delete SSL directives from " + name + ".conf, missing: ";
|
errmsg += "cannot delete SSL directives from " + name + ".conf, missing: ";
|
||||||
errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n";
|
errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n";
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "nginx-util.hpp"
|
#include "nginx-util.hpp"
|
||||||
|
|
||||||
#ifndef NO_SSL
|
#ifndef NO_SSL
|
||||||
|
@ -121,7 +123,7 @@ void get_env()
|
||||||
auto main(int argc, char * argv[]) -> int
|
auto main(int argc, char * argv[]) -> int
|
||||||
{
|
{
|
||||||
// TODO(pst): use std::span when available:
|
// TODO(pst): use std::span when available:
|
||||||
auto args = std::basic_string_view{argv, static_cast<size_t>(argc)};
|
auto args = std::basic_string_view<char *>{argv, static_cast<size_t>(argc)};
|
||||||
|
|
||||||
auto cmds = std::array{
|
auto cmds = std::array{
|
||||||
std::array<std::string_view, 2>{"init_lan", ""},
|
std::array<std::string_view, 2>{"init_lan", ""},
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#ifndef NO_UBUS
|
#ifndef NO_UBUS
|
||||||
#include "ubus-cxx.hpp"
|
#include "ubus-cxx.hpp"
|
||||||
|
@ -61,15 +63,34 @@ void get_env();
|
||||||
void write_file(const std::string_view & name, const std::string & str,
|
void write_file(const std::string_view & name, const std::string & str,
|
||||||
const std::ios_base::openmode flag)
|
const std::ios_base::openmode flag)
|
||||||
{
|
{
|
||||||
std::ofstream file(name.data(), flag);
|
auto tmp = std::string{name};
|
||||||
if (!file.good()) {
|
|
||||||
throw std::ofstream::failure(
|
if ( (flag & std::ios::ate) == 0 && (flag & std::ios::app) == 0 ) {
|
||||||
"write_file error: cannot open " + std::string{name});
|
tmp += ".tmp-XXXXXX";
|
||||||
|
auto fd = mkstemp(&tmp[0]);
|
||||||
|
if (fd==-1 || close(fd)!=0)
|
||||||
|
{ throw std::runtime_error("write_file error: cannot access " + tmp); }
|
||||||
}
|
}
|
||||||
|
|
||||||
file<<str<<std::flush;
|
try {
|
||||||
|
std::ofstream file(tmp.data(), flag);
|
||||||
|
if (!file.good()) {
|
||||||
|
throw std::ofstream::failure
|
||||||
|
("write_file error: cannot open " + std::string{tmp});
|
||||||
|
}
|
||||||
|
|
||||||
file.close();
|
file<<str<<std::flush;
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
} catch(...) {
|
||||||
|
if (tmp!=name) { remove(tmp.c_str()); } //remove can fail.
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename(tmp.c_str(), name.data()) != 0) {
|
||||||
|
throw std::runtime_error
|
||||||
|
("write_file error: cannot move " + tmp + " to " + name.data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,7 +134,7 @@ auto call(const char * program, S... args) -> pid_t
|
||||||
|
|
||||||
std::string errmsg = "call error: cannot fork (";
|
std::string errmsg = "call error: cannot fork (";
|
||||||
errmsg += std::to_string(errno) + "): " + std::strerror(errno);
|
errmsg += std::to_string(errno) + "): " + std::strerror(errno);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
static constexpr auto rsa_min_modulus_bits = 512;
|
static constexpr auto rsa_min_modulus_bits = 512;
|
||||||
|
|
||||||
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
|
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
|
||||||
|
@ -52,11 +54,20 @@ inline auto print_error(const char * str, const size_t /*len*/, void * errmsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// wrapper for clang-tidy:
|
||||||
|
inline auto _BIO_new_fp(FILE * stream, const bool use_pem,
|
||||||
|
const bool close=false) -> BIO *
|
||||||
|
{
|
||||||
|
return BIO_new_fp( stream, //NOLINTNEXTLINE(hicpp-signed-bitwise) macros:
|
||||||
|
(use_pem ? BIO_FP_TEXT : 0) | (close ? BIO_CLOSE : BIO_NOCLOSE) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
auto checkend(const std::string & crtpath,
|
auto checkend(const std::string & crtpath,
|
||||||
const time_t seconds, const bool use_pem) -> bool
|
const time_t seconds, const bool use_pem) -> bool
|
||||||
{
|
{
|
||||||
BIO * bio = crtpath.empty() ?
|
BIO * bio = crtpath.empty() ?
|
||||||
BIO_new_fp(stdin, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0)) :
|
_BIO_new_fp(stdin, use_pem) :
|
||||||
BIO_new_file(crtpath.c_str(), (use_pem ? "r" : "rb"));
|
BIO_new_file(crtpath.c_str(), (use_pem ? "r" : "rb"));
|
||||||
|
|
||||||
X509 * x509 = nullptr;
|
X509 * x509 = nullptr;
|
||||||
|
@ -71,7 +82,7 @@ auto checkend(const std::string & crtpath,
|
||||||
if (x509==nullptr) {
|
if (x509==nullptr) {
|
||||||
std::string errmsg{"checkend error: unable to load certificate\n"};
|
std::string errmsg{"checkend error: unable to load certificate\n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t checktime = time(nullptr) + seconds;
|
time_t checktime = time(nullptr) + seconds;
|
||||||
|
@ -91,7 +102,7 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
||||||
std::string errmsg{"gen_eckey error: cannot build group for curve id "};
|
std::string errmsg{"gen_eckey error: cannot build group for curve id "};
|
||||||
errmsg += std::to_string(curve) + "\n";
|
errmsg += std::to_string(curve) + "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
|
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
|
||||||
|
@ -115,18 +126,18 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
||||||
std::string errmsg{"gen_eckey error: cannot build key with curve id "};
|
std::string errmsg{"gen_eckey error: cannot build key with curve id "};
|
||||||
errmsg += std::to_string(curve) + "\n";
|
errmsg += std::to_string(curve) + "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
||||||
|
|
||||||
auto tmp = static_cast<char *>(static_cast<void *>(eckey));
|
// EVP_PKEY_assign_EC_KEY is a macro casting eckey to char *:
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), tmp)) {
|
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey)) {
|
||||||
EC_KEY_free(eckey);
|
EC_KEY_free(eckey);
|
||||||
std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"};
|
std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkey;
|
return pkey;
|
||||||
|
@ -139,14 +150,14 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
||||||
std::string errmsg{"gen_rsakey error: RSA keysize ("};
|
std::string errmsg{"gen_rsakey error: RSA keysize ("};
|
||||||
errmsg += std::to_string(keysize) + ") out of range [512..";
|
errmsg += std::to_string(keysize) + ") out of range [512..";
|
||||||
errmsg += std::to_string(OPENSSL_RSA_MAX_MODULUS_BITS) + "]";
|
errmsg += std::to_string(OPENSSL_RSA_MAX_MODULUS_BITS) + "]";
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
auto bignum = BN_new();
|
auto bignum = BN_new();
|
||||||
|
|
||||||
if (bignum == nullptr) {
|
if (bignum == nullptr) {
|
||||||
std::string errmsg{"gen_rsakey error: cannot get big number struct\n"};
|
std::string errmsg{"gen_rsakey error: cannot get big number struct\n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rsa = RSA_new();
|
auto rsa = RSA_new();
|
||||||
|
@ -167,18 +178,18 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
||||||
errmsg += std::to_string(keysize) + " and exponent ";
|
errmsg += std::to_string(keysize) + " and exponent ";
|
||||||
errmsg += std::to_string(exponent) + "\n";
|
errmsg += std::to_string(exponent) + "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
||||||
|
|
||||||
auto tmp = static_cast<char *>(static_cast<void *>(rsa));
|
// EVP_PKEY_assign_RSA is a macro casting rsa to char *:
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
if (!EVP_PKEY_assign_RSA(pkey.get(), tmp)) {
|
if (!EVP_PKEY_assign_RSA(pkey.get(), rsa)) {
|
||||||
RSA_free(rsa);
|
RSA_free(rsa);
|
||||||
std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"};
|
std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkey;
|
return pkey;
|
||||||
|
@ -190,20 +201,21 @@ void write_key(const EVP_PKEY_ptr & pkey,
|
||||||
{
|
{
|
||||||
BIO * bio = nullptr;
|
BIO * bio = nullptr;
|
||||||
|
|
||||||
if (keypath.empty()) {
|
if (keypath.empty()) { bio = _BIO_new_fp(stdout, use_pem); }
|
||||||
bio = BIO_new_fp( stdout, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0) );
|
|
||||||
|
|
||||||
} else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") );
|
else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") );
|
||||||
|
|
||||||
static constexpr auto mask = 0600;
|
static constexpr auto mask = 0600;
|
||||||
// auto fd = open(keypath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mask);
|
// auto fd = open(keypath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mask);
|
||||||
|
// creat has no cloexec, alt. triggers cppcoreguidelines-pro-type-vararg
|
||||||
|
//NOLINTNEXTLINE(android-cloexec-creat)
|
||||||
auto fd = creat(keypath.c_str(), mask); // the same without va_args.
|
auto fd = creat(keypath.c_str(), mask); // the same without va_args.
|
||||||
|
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
auto fp = fdopen(fd, (use_pem ? "w" : "wb") );
|
auto fp = fdopen(fd, (use_pem ? "w" : "wb") );
|
||||||
|
|
||||||
if (fp != nullptr) {
|
if (fp != nullptr) {
|
||||||
bio = BIO_new_fp(fp, BIO_CLOSE | (use_pem ? BIO_FP_TEXT : 0));
|
bio = _BIO_new_fp(fp, use_pem, true);
|
||||||
if (bio == nullptr) { fclose(fp); } // (fp owns fd)
|
if (bio == nullptr) { fclose(fp); } // (fp owns fd)
|
||||||
}
|
}
|
||||||
else { close(fd); }
|
else { close(fd); }
|
||||||
|
@ -216,7 +228,7 @@ void write_key(const EVP_PKEY_ptr & pkey,
|
||||||
errmsg += keypath.empty() ? "stdout" : keypath;
|
errmsg += keypath.empty() ? "stdout" : keypath;
|
||||||
errmsg += "\n";
|
errmsg += "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
@ -249,7 +261,7 @@ void write_key(const EVP_PKEY_ptr & pkey,
|
||||||
errmsg += keypath.empty() ? "stdout" : keypath;
|
errmsg += keypath.empty() ? "stdout" : keypath;
|
||||||
errmsg += "\n";
|
errmsg += "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +277,7 @@ auto subject2name(const std::string & subject) -> X509_NAME_ptr
|
||||||
if (!name) {
|
if (!name) {
|
||||||
std::string errmsg{"subject2name error: cannot create X509 name \n"};
|
std::string errmsg{"subject2name error: cannot create X509 name \n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subject.empty()) { return name; }
|
if (subject.empty()) { return name; }
|
||||||
|
@ -287,19 +299,21 @@ auto subject2name(const std::string & subject) -> X509_NAME_ptr
|
||||||
if (nid == NID_undef) {
|
if (nid == NID_undef) {
|
||||||
// skip unknown entries (silently?).
|
// skip unknown entries (silently?).
|
||||||
} else {
|
} else {
|
||||||
auto val = static_cast<const unsigned char *>(
|
auto val = // X509_NAME_add_entry_by_NID wants it unsigned:
|
||||||
static_cast<const void *>(&subject[prev]) );
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
reinterpret_cast<const unsigned char *>(&subject[prev]);
|
||||||
|
|
||||||
auto len = i - prev;
|
auto len = i - prev;
|
||||||
|
|
||||||
if ( X509_NAME_add_entry_by_NID(name.get(), nid, MBSTRING_ASC,
|
if ( X509_NAME_add_entry_by_NID(name.get(), nid,
|
||||||
val, len, -1, 0)
|
MBSTRING_ASC, //NOLINT(hicpp-signed-bitwise) is macro
|
||||||
|
val, len, -1, 0)
|
||||||
== 0 )
|
== 0 )
|
||||||
{
|
{
|
||||||
std::string errmsg{"subject2name error: cannot add "};
|
std::string errmsg{"subject2name error: cannot add "};
|
||||||
errmsg += "/" + type +"="+ subject.substr(prev, len) +"\n";
|
errmsg += "/" + type +"="+ subject.substr(prev, len) +"\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chr = '=';
|
chr = '=';
|
||||||
|
@ -320,7 +334,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
||||||
if (x509 == nullptr) {
|
if (x509 == nullptr) {
|
||||||
std::string errmsg{"selfsigned error: cannot create X509 structure\n"};
|
std::string errmsg{"selfsigned error: cannot create X509 structure\n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto freeX509_and_throw = [&x509](const std::string & what)
|
auto freeX509_and_throw = [&x509](const std::string & what)
|
||||||
|
@ -329,7 +343,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
||||||
std::string errmsg{"selfsigned error: cannot set "};
|
std::string errmsg{"selfsigned error: cannot set "};
|
||||||
errmsg += what + " in X509 certificate\n";
|
errmsg += what + " in X509 certificate\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (X509_set_version(x509, 2) == 0) { freeX509_and_throw("version"); }
|
if (X509_set_version(x509, 2) == 0) { freeX509_and_throw("version"); }
|
||||||
|
@ -380,7 +394,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
||||||
}
|
}
|
||||||
|
|
||||||
BIO * bio = crtpath.empty() ?
|
BIO * bio = crtpath.empty() ?
|
||||||
BIO_new_fp(stdout, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0)) :
|
_BIO_new_fp(stdout, use_pem) :
|
||||||
BIO_new_file(crtpath.c_str(), (use_pem ? "w" : "wb"));
|
BIO_new_file(crtpath.c_str(), (use_pem ? "w" : "wb"));
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
@ -399,7 +413,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
||||||
errmsg += crtpath.empty() ? "stdout" : crtpath;
|
errmsg += crtpath.empty() ? "stdout" : crtpath;
|
||||||
errmsg += "\n";
|
errmsg += "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ auto checkend(const argv_view & argv) -> int
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
auto errmsg = std::string{"checkend error: invalid time "};
|
auto errmsg = std::string{"checkend error: invalid time "};
|
||||||
errmsg += argv[i];
|
errmsg += argv[i];
|
||||||
std::throw_with_nested(std::runtime_error(errmsg.c_str()));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
seconds = static_cast<time_t>(num);
|
seconds = static_cast<time_t>(num);
|
||||||
|
@ -126,7 +126,7 @@ auto checkend(const argv_view & argv) -> int
|
||||||
if (num!=static_cast<intmax_t>(seconds)) {
|
if (num!=static_cast<intmax_t>(seconds)) {
|
||||||
auto errmsg = std::string{"checkend error: time too big "};
|
auto errmsg = std::string{"checkend error: time too big "};
|
||||||
errmsg += argv[i];
|
errmsg += argv[i];
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ void eckey(const argv_view & argv)
|
||||||
if (has_main_option) {
|
if (has_main_option) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error
|
||||||
("eckey error: more than one main option");
|
("eckey error: more than one main option");
|
||||||
} // else:
|
} //else:
|
||||||
has_main_option = true;
|
has_main_option = true;
|
||||||
|
|
||||||
curve = parse_curve(argv[i]);
|
curve = parse_curve(argv[i]);
|
||||||
|
@ -223,7 +223,7 @@ void rsakey(const argv_view & argv)
|
||||||
|
|
||||||
if (has_main_option) {
|
if (has_main_option) {
|
||||||
throw std::runtime_error("rsakey error: more than one keysize");
|
throw std::runtime_error("rsakey error: more than one keysize");
|
||||||
} // else:
|
} //else:
|
||||||
has_main_option = true;
|
has_main_option = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -231,7 +231,7 @@ void rsakey(const argv_view & argv)
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::string errmsg{"rsakey error: invalid keysize "};
|
std::string errmsg{"rsakey error: invalid keysize "};
|
||||||
errmsg += argv[i];
|
errmsg += argv[i];
|
||||||
std::throw_with_nested(std::runtime_error(errmsg.c_str()));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ void selfsigned(const argv_view & argv)
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::string errmsg{"selfsigned error: not a number for -days "};
|
std::string errmsg{"selfsigned error: not a number for -days "};
|
||||||
errmsg += argv[i].substr(4);
|
errmsg += argv[i].substr(4);
|
||||||
std::throw_with_nested(std::runtime_error(errmsg.c_str()));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ void selfsigned(const argv_view & argv)
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::string errmsg{"selfsigned error: invalid keysize "};
|
std::string errmsg{"selfsigned error: invalid keysize "};
|
||||||
errmsg += argv[i].substr(4);
|
errmsg += argv[i].substr(4);
|
||||||
std::throw_with_nested(std::runtime_error(errmsg.c_str()));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("selfsigned error: invalid algorithm");
|
throw std::runtime_error("selfsigned error: invalid algorithm");
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// implementing *some* <regex> functions using pcre for performance:
|
|
||||||
|
|
||||||
#ifndef __REGEXP_PCRE_HPP
|
#ifndef __REGEXP_PCRE_HPP
|
||||||
#define __REGEXP_PCRE_HPP
|
#define __REGEXP_PCRE_HPP
|
||||||
|
|
||||||
|
@ -11,6 +9,9 @@
|
||||||
|
|
||||||
|
|
||||||
namespace rgx {
|
namespace rgx {
|
||||||
|
/* partially implement the std::regex interface using PCRE for performance
|
||||||
|
* (=> pass "match" as non-const reference)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace regex_constants {
|
namespace regex_constants {
|
||||||
|
@ -130,8 +131,8 @@ class smatch {
|
||||||
|
|
||||||
friend auto regex_search(std::string::const_iterator begin,
|
friend auto regex_search(std::string::const_iterator begin,
|
||||||
std::string::const_iterator end,
|
std::string::const_iterator end,
|
||||||
smatch & match,
|
smatch & match, //NOLINT(google-runtime-references)
|
||||||
const regex & rgx);
|
const regex & rgx); // match std::regex interface.
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -188,14 +189,15 @@ auto regex_replace(const std::string & subj,
|
||||||
const std::string & insert);
|
const std::string & insert);
|
||||||
|
|
||||||
|
|
||||||
inline auto regex_search(const std::string & subj, smatch & match,
|
inline auto regex_search(const std::string & subj,
|
||||||
const regex & rgx);
|
smatch & match, //NOLINT(google-runtime-references)
|
||||||
|
const regex & rgx); // match std::regex interface.
|
||||||
|
|
||||||
|
|
||||||
auto regex_search(std::string::const_iterator begin,
|
auto regex_search(std::string::const_iterator begin,
|
||||||
std::string::const_iterator end,
|
std::string::const_iterator end,
|
||||||
smatch & match,
|
smatch & match, //NOLINT(google-runtime-references)
|
||||||
const regex & rgx);
|
const regex & rgx); // match std::regex interface.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,12 +262,10 @@ auto smatch::format(const std::string & fmt) const {
|
||||||
index = pos + 1;
|
index = pos + 1;
|
||||||
|
|
||||||
char chr = fmt[index++];
|
char chr = fmt[index++];
|
||||||
int n = 0;
|
|
||||||
static const auto BASE = 10;
|
|
||||||
switch(chr) {
|
switch(chr) {
|
||||||
|
|
||||||
case '&': // match
|
case '&': // match
|
||||||
ret += this->str(0);
|
ret += str(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '`': // prefix
|
case '`': // prefix
|
||||||
|
@ -276,14 +276,20 @@ auto smatch::format(const std::string & fmt) const {
|
||||||
ret.append(begin+vec[1], end);
|
ret.append(begin+vec[1], end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // number => submatch
|
default:
|
||||||
while (isdigit(chr) != 0) {
|
if (isdigit(chr) != 0) { // one or two digits => submatch:
|
||||||
n = BASE*n + chr - '0';
|
int num = chr - '0';
|
||||||
chr = fmt[index++];
|
chr = fmt[index];
|
||||||
}
|
if (isdigit(chr) != 0) { // second digit:
|
||||||
|
++index;
|
||||||
ret += n>0 ? str(n) : std::string{"$"};
|
static const auto base = 10;
|
||||||
|
num = num*base + chr - '0';
|
||||||
|
}
|
||||||
|
ret += str(num);
|
||||||
|
break;
|
||||||
|
} //else:
|
||||||
|
|
||||||
|
ret += '$';
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case '$': // escaped
|
case '$': // escaped
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
PRINT_PASSED=2
|
PRINT_PASSED=2
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ setpoint_add_ssl() {
|
||||||
local indent="\n$1"
|
local indent="\n$1"
|
||||||
local name="$2"
|
local name="$2"
|
||||||
local default=""
|
local default=""
|
||||||
[ "${name}" == "${LAN_NAME}" ] && default=".default"
|
[ "${name}" = "${LAN_NAME}" ] && default=".default"
|
||||||
local prefix="${CONF_DIR}${name}"
|
local prefix="${CONF_DIR}${name}"
|
||||||
|
|
||||||
local CONF="$(grep -vE "$(_regex "${NGX_INCLUDE}" \
|
local CONF="$(grep -vE "$(_regex "${NGX_INCLUDE}" \
|
||||||
|
@ -74,10 +74,17 @@ setpoint_add_ssl() {
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
test_setpoint() {
|
||||||
|
[ "$(cat "$1")" = "$2" ] && return
|
||||||
|
echo "$1:"; cat "$1"
|
||||||
|
echo "differs from setpoint:"; echo "$2"
|
||||||
|
[ "${PRINT_PASSED}" -gt 1 ] && pst_exit 1
|
||||||
|
}
|
||||||
|
|
||||||
function test() {
|
|
||||||
eval "$1 2>/dev/null >/dev/null "
|
test() {
|
||||||
if [ $? -eq $2 ]
|
eval "$1 2>/dev/null >/dev/null"
|
||||||
|
if [ "$?" -eq "$2" ]
|
||||||
then
|
then
|
||||||
[ "${PRINT_PASSED}" -gt 0 ] \
|
[ "${PRINT_PASSED}" -gt 0 ] \
|
||||||
&& printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) passed."
|
&& printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) passed."
|
||||||
|
@ -88,7 +95,7 @@ function test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} get_env ...\n"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s get_env ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
eval $("${NGINX_UTIL}" get_env)
|
eval $("${NGINX_UTIL}" get_env)
|
||||||
test '[ -n "${NGINX_CONF}" ]' 0
|
test '[ -n "${NGINX_CONF}" ]' 0
|
||||||
|
@ -101,21 +108,21 @@ test '[ -n "${SSL_SESSION_TIMEOUT_ARG}" ]' 0
|
||||||
test '[ -n "${ADD_SSL_FCT}" ]' 0
|
test '[ -n "${ADD_SSL_FCT}" ]' 0
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in ${CONF_DIR} ...\n"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in %s ...\n" "${CONF_DIR}"
|
||||||
|
|
||||||
mkdir -p ${CONF_DIR}
|
mkdir -p "${CONF_DIR}"
|
||||||
|
|
||||||
cd ${CONF_DIR}
|
cd "${CONF_DIR}" || exit 2
|
||||||
|
|
||||||
NGX_INCLUDE="include '\$';"
|
NGX_INCLUDE="include '\$';"
|
||||||
NGX_SERVER_NAME="server_name * '\$' *;"
|
NGX_SERVER_NAME="server_name * '\$' *;"
|
||||||
NGX_SSL_CRT="ssl_certificate '\$.crt';"
|
NGX_SSL_CRT="ssl_certificate '\$.crt';"
|
||||||
NGX_SSL_KEY="ssl_certificate_key '\$.key';"
|
NGX_SSL_KEY="ssl_certificate_key '\$.key';"
|
||||||
NGX_SSL_SESSION_CACHE="ssl_session_cache '$(echo "${SSL_SESSION_CACHE_ARG}" \
|
NGX_SSL_SESSION_CACHE="ssl_session_cache '$(echo "${SSL_SESSION_CACHE_ARG}" \
|
||||||
| sed -E "s/$(__esc_regex ${LAN_NAME})/\$/")';"
|
| sed -E "s/$(__esc_regex "${LAN_NAME}")/\$/")';"
|
||||||
NGX_SSL_SESSION_TIMEOUT="ssl_session_timeout '${SSL_SESSION_TIMEOUT_ARG}';"
|
NGX_SSL_SESSION_TIMEOUT="ssl_session_timeout '${SSL_SESSION_TIMEOUT_ARG}';"
|
||||||
|
|
||||||
cat > ${LAN_NAME}.sans <<EOF
|
cat > "${LAN_NAME}.sans" <<EOF
|
||||||
# default_server for the LAN addresses getting the IPs by:
|
# default_server for the LAN addresses getting the IPs by:
|
||||||
# ifstatus lan | jsonfilter -e '@["ipv4-address","ipv6-address"].*.address'
|
# ifstatus lan | jsonfilter -e '@["ipv4-address","ipv6-address"].*.address'
|
||||||
server {
|
server {
|
||||||
|
@ -196,56 +203,44 @@ EOF
|
||||||
CONFS="${CONFS} tab:0"
|
CONFS="${CONFS} tab:0"
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} init_lan ...\n"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s init_lan ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
mkdir -p "$(dirname "${LAN_LISTEN}")"
|
mkdir -p "$(dirname "${LAN_LISTEN}")"
|
||||||
|
|
||||||
cp ${LAN_NAME}.sans ${LAN_NAME}.conf
|
cp "${LAN_NAME}.sans" "${LAN_NAME}.conf"
|
||||||
|
|
||||||
test '${NGINX_UTIL} init_lan' 0
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nSetup files in ${CONF_DIR} ...\n"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nSetup files in %s ...\n" "${CONF_DIR}"
|
||||||
|
|
||||||
for conf in ${CONFS}
|
for conf in ${CONFS}
|
||||||
do test 'setpoint_add_ssl " " '${conf%:*} ${conf#*:}
|
do test 'setpoint_add_ssl " " '"${conf%:*}" "${conf#*:}"
|
||||||
done
|
done
|
||||||
|
|
||||||
test 'setpoint_add_ssl "\t" tab' 0 # fixes wrong indentation.
|
test 'setpoint_add_ssl "\t" tab' 0 # fixes wrong indentation.
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} add_ssl ...\n"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s add_ssl ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
cp different_name.sans different_name.with
|
cp different_name.sans different_name.with
|
||||||
|
|
||||||
test '[ "${ADD_SSL_FCT}" == "add_ssl" ] ' 0
|
test '[ "${ADD_SSL_FCT}" = "add_ssl" ] ' 0
|
||||||
|
|
||||||
for conf in ${CONFS}; do
|
for conf in ${CONFS}; do
|
||||||
name=${conf%:*}
|
name="${conf%:*}"
|
||||||
cp ${name}.sans ${name}.conf
|
cp "${name}.sans" "${name}.conf"
|
||||||
test '${NGINX_UTIL} add_ssl '${name} ${conf#*:}
|
test '"${NGINX_UTIL}" add_ssl '"${name}" "${conf#*:}"
|
||||||
(test '[ "$(cat '${name}'.conf)" == "$(cat '${name}'.with)" ]' 0 >/dev/null)
|
test_setpoint "${name}.conf" "$(cat "${name}.with")"
|
||||||
[ "$?" -gt 0 ] && {
|
|
||||||
echo "created ${name}.conf:"; cat "${name}.conf"
|
|
||||||
echo "differs from setpoint:"; cat "${name}.with"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s del_ssl ...\n" "${NGINX_UTIL}"
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} del_ssl ...\n"
|
|
||||||
|
|
||||||
sed -i "/server {/a\\ include '${LAN_LISTEN}';" minimal.sans
|
sed -i "/server {/a\\ include '${LAN_LISTEN}';" minimal.sans
|
||||||
|
|
||||||
for conf in ${CONFS}; do
|
for conf in ${CONFS}; do
|
||||||
name=${conf%:*}
|
name="${conf%:*}"
|
||||||
cp ${name}.with ${name}.conf
|
cp "${name}.with" "${name}.conf"
|
||||||
test '${NGINX_UTIL} del_ssl '${name} ${conf#*:}
|
test '"${NGINX_UTIL}" del_ssl '"${name}" "${conf#*:}"
|
||||||
(test '[ "$(cat '${name}'.conf)" == "$(cat '${name}'.sans)" ]' 0 >/dev/null)
|
test_setpoint "${name}.conf" "$(cat "${name}.sans")"
|
||||||
[ "$?" -gt 0 ] && {
|
|
||||||
echo "created ${name}.conf:"; cat "${name}.conf"
|
|
||||||
echo "differs from setpoint:"; cat "${name}.sans"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,48 @@
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
printf "Initializing tests ...\n"
|
printf "Initializing tests ...\n"
|
||||||
|
|
||||||
fakechroot=""
|
fakechroot=""
|
||||||
|
|
||||||
[ -x /usr/bin/fakechroot ] && fakechroot="/usr/bin/fakechroot" \
|
[ -x "/usr/bin/fakechroot" ] && fakechroot="/usr/bin/fakechroot" \
|
||||||
|| [ "$(id -u)" -eq 0 ] || { \
|
|| [ "$(id -u)" -eq 0 ] || { \
|
||||||
printf "Error: Testing needs fakechroot or whoami=root for chroot."
|
printf "Error: Testing needs fakechroot or whoami=root for chroot."
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
TMPROOT=$(mktemp -d /tmp/test-nginx-util-XXXXXX)
|
TMPROOT="$(mktemp -d "/tmp/test-nginx-util-XXXXXX")"
|
||||||
|
|
||||||
ln -s /bin ${TMPROOT}/bin
|
ln -s /bin "${TMPROOT}/bin"
|
||||||
|
|
||||||
mkdir -p ${TMPROOT}/usr/bin/
|
mkdir -p "${TMPROOT}/usr/bin/"
|
||||||
|
|
||||||
cp ./test-nginx-util-root.sh ${TMPROOT}/usr/bin/
|
cp "./test-nginx-util-root.sh" "${TMPROOT}/usr/bin/"
|
||||||
|
|
||||||
|
|
||||||
printf "\n\n******* Testing nginx-ssl-util-noubus *******\n"
|
printf "\n\n******* Testing nginx-ssl-util-noubus *******\n"
|
||||||
|
|
||||||
cp ./nginx-ssl-util-noubus ${TMPROOT}/usr/bin/nginx-util
|
cp "./nginx-ssl-util-noubus" "${TMPROOT}/usr/bin/nginx-util"
|
||||||
|
|
||||||
${fakechroot} /bin/chroot ${TMPROOT} /bin/sh -c /usr/bin/test-nginx-util-root.sh
|
"${fakechroot}" /bin/chroot "${TMPROOT}" \
|
||||||
|
/bin/sh -c "/usr/bin/test-nginx-util-root.sh" ||
|
||||||
echo $?
|
{
|
||||||
|
echo "!!! Error: $?"
|
||||||
|
rm -r "${TMPROOT}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
printf "\n\n******* Testing nginx-ssl-util-nopcre-noubus *******\n"
|
printf "\n\n******* Testing nginx-ssl-util-nopcre-noubus *******\n"
|
||||||
|
|
||||||
cp ./nginx-ssl-util-nopcre-noubus ${TMPROOT}/usr/bin/nginx-util
|
cp "./nginx-ssl-util-nopcre-noubus" "${TMPROOT}/usr/bin/nginx-util"
|
||||||
|
|
||||||
${fakechroot} /bin/chroot ${TMPROOT} /bin/sh -c /usr/bin/test-nginx-util-root.sh
|
"${fakechroot}" /bin/chroot "${TMPROOT}" \
|
||||||
|
/bin/sh -c "/usr/bin/test-nginx-util-root.sh" ||
|
||||||
|
{
|
||||||
|
echo "!!! Error: $?"
|
||||||
|
rm -r "${TMPROOT}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rm -r ${TMPROOT}
|
rm -r "${TMPROOT}"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
PRINT_PASSED=2
|
PRINT_PASSED=2
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ OPENSSL_PEM="$(mktemp)"
|
||||||
OPENSSL_DER="$(mktemp)"
|
OPENSSL_DER="$(mktemp)"
|
||||||
|
|
||||||
NONCE=$(dd if=/dev/urandom bs=1 count=4 2>/dev/null | hexdump -e '1/1 "%02x"')
|
NONCE=$(dd if=/dev/urandom bs=1 count=4 2>/dev/null | hexdump -e '1/1 "%02x"')
|
||||||
SUBJECT=/C="ZZ"/ST="Somewhere"/L="None"/O="OpenWrt'$NONCE'"/CN="OpenWrt"
|
SUBJECT="/C=ZZ/ST=Somewhere/L=None/O=OpenWrt'$NONCE'/CN=OpenWrt"
|
||||||
|
|
||||||
openssl req -x509 -nodes -days 1 -keyout /dev/null 2>/dev/null \
|
openssl req -x509 -nodes -days 1 -keyout /dev/null 2>/dev/null \
|
||||||
-out "$OPENSSL_PEM" -subj "$SUBJECT" \
|
-out "$OPENSSL_PEM" -subj "$SUBJECT" \
|
||||||
|
@ -18,9 +18,9 @@ openssl req -x509 -nodes -days 1 -keyout /dev/null 2>/dev/null \
|
||||||
|| ( printf "error: generating DER certificate with openssl"; return 1)
|
|| ( printf "error: generating DER certificate with openssl"; return 1)
|
||||||
|
|
||||||
|
|
||||||
function test() {
|
test() {
|
||||||
eval "$1 >/dev/null "
|
eval "$1 >/dev/null "
|
||||||
if [ $? -eq $2 ]
|
if [ $? -eq "$2" ]
|
||||||
then
|
then
|
||||||
[ "${PRINT_PASSED}" -gt 0 ] \
|
[ "${PRINT_PASSED}" -gt 0 ] \
|
||||||
&& printf "%-72s%-1s\n" "$1" ">/dev/null (-> $2?) passed."
|
&& printf "%-72s%-1s\n" "$1" ">/dev/null (-> $2?) passed."
|
||||||
|
@ -130,8 +130,8 @@ test './px5g selfsigned -newkey rsa:666 | openssl x509 -checkend 0 ' 0
|
||||||
test './px5g selfsigned -newkey ec | openssl x509 -checkend 0 ' 0
|
test './px5g selfsigned -newkey ec | openssl x509 -checkend 0 ' 0
|
||||||
test './px5g selfsigned -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 \
|
test './px5g selfsigned -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 \
|
||||||
| openssl x509 -checkend 0 ' 0
|
| openssl x509 -checkend 0 ' 0
|
||||||
test './px5g selfsigned -subj $SUBJECT | openssl x509 -noout \
|
test './px5g selfsigned -subj "$SUBJECT" | openssl x509 -noout \
|
||||||
-subject -nameopt compat | grep -q subject=$SUBJECT 2>/dev/null' 0
|
-subject -nameopt compat | grep -q subject="$SUBJECT" 2>/dev/null' 0
|
||||||
test './px5g selfsigned -out /dev/null -keyout /proc/self/fd/1 \
|
test './px5g selfsigned -out /dev/null -keyout /proc/self/fd/1 \
|
||||||
| openssl rsa -check 2>/dev/null ' 0
|
| openssl rsa -check 2>/dev/null ' 0
|
||||||
|
|
||||||
|
|
148
net/nginx-util/src/ubus-cxx.cpp
Normal file
148
net/nginx-util/src/ubus-cxx.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ubus-cxx.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
inline void example_for_checking_if_there_is_a_key()
|
||||||
|
{
|
||||||
|
if (ubus::call("service", "list").filter("cron")) {
|
||||||
|
std::cout<<"Cron is active (with or without instances) "<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void example_for_getting_values()
|
||||||
|
{
|
||||||
|
auto lan_status = ubus::call("network.interface.lan", "status");
|
||||||
|
for (auto t : lan_status.filter("ipv6-address", "", "address")) {
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
auto x = const_cast<blob_attr *>(t);
|
||||||
|
std::cout<<"["<<blobmsg_get_string(x)<<"] ";
|
||||||
|
}
|
||||||
|
for (auto t : lan_status.filter("ipv4-address", "").filter("address")) {
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
auto x = const_cast<blob_attr *>(t);
|
||||||
|
std::cout<<blobmsg_get_string(x)<<" ";
|
||||||
|
}
|
||||||
|
std::cout<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void example_for_sending_message()
|
||||||
|
{
|
||||||
|
auto set_arg = [](blob_buf * buf) -> int
|
||||||
|
{ return blobmsg_add_string(buf, "config", "nginx"); };
|
||||||
|
for (auto t : ubus::call("uci", "get", set_arg).filter("values")) {
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
auto x = const_cast<blob_attr *>(t);
|
||||||
|
std::cout<<blobmsg_get_string(x)<<"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void example_for_exploring()
|
||||||
|
{
|
||||||
|
ubus::strings keys{"ipv4-address", "", ""};
|
||||||
|
for (auto t : ubus::call("network.interface.lan", "status").filter(keys)) {
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
auto x = const_cast<blob_attr *>(t);
|
||||||
|
std::cout<<blobmsg_name(x)<<": ";
|
||||||
|
switch (blob_id(x)) {
|
||||||
|
case BLOBMSG_TYPE_UNSPEC: std::cout<<"[unspecified]"; break;
|
||||||
|
case BLOBMSG_TYPE_ARRAY: std::cout<<"[array]"; break;
|
||||||
|
case BLOBMSG_TYPE_TABLE: std::cout<<"[table]"; break;
|
||||||
|
case BLOBMSG_TYPE_STRING: std::cout<<blobmsg_get_string(x); break;
|
||||||
|
case BLOBMSG_TYPE_INT64: std::cout<<blobmsg_get_u64(x); break;
|
||||||
|
case BLOBMSG_TYPE_INT32: std::cout<<blobmsg_get_u32(x); break;
|
||||||
|
case BLOBMSG_TYPE_INT16: std::cout<<blobmsg_get_u16(x); break;
|
||||||
|
case BLOBMSG_TYPE_BOOL: std::cout<<blobmsg_get_bool(x); break;
|
||||||
|
case BLOBMSG_TYPE_DOUBLE: std::cout<<blobmsg_get_double(x); break;
|
||||||
|
default: std::cout<<"[unknown]";
|
||||||
|
}
|
||||||
|
std::cout<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void example_for_recursive_exploring()
|
||||||
|
{ // output like from the original ubus call:
|
||||||
|
const auto explore = [](auto message) -> void
|
||||||
|
{
|
||||||
|
auto end = message.end();
|
||||||
|
auto explore_internal =
|
||||||
|
[&end](auto & explore_ref, auto it, size_t depth=1) -> void
|
||||||
|
{
|
||||||
|
std::cout<<std::endl;
|
||||||
|
bool first = true;
|
||||||
|
for (; it!=end; ++it) {
|
||||||
|
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
auto attr = const_cast<blob_attr *>(*it);
|
||||||
|
if (first) { first = false; }
|
||||||
|
else { std::cout<<",\n"; }
|
||||||
|
std::cout<<std::string(depth, '\t');
|
||||||
|
std::string name = blobmsg_name(attr);
|
||||||
|
if (!name.empty()) { std::cout<<"\""<<name<<"\": "; }
|
||||||
|
switch (blob_id(attr)) {
|
||||||
|
case BLOBMSG_TYPE_UNSPEC: std::cout<<"(unspecified)"; break;
|
||||||
|
case BLOBMSG_TYPE_ARRAY:
|
||||||
|
std::cout<<"[";
|
||||||
|
explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
||||||
|
std::cout<<"\n"<<std::string(depth, '\t')<<"]";
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_TABLE:
|
||||||
|
std::cout<<"{";
|
||||||
|
explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
||||||
|
std::cout<<"\n"<<std::string(depth, '\t')<<"}";
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_STRING:
|
||||||
|
std::cout<<"\""<<blobmsg_get_string(attr)<<"\"";
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_INT64:
|
||||||
|
std::cout<<blobmsg_get_u64(attr);
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_INT32:
|
||||||
|
std::cout<<blobmsg_get_u32(attr);
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_INT16:
|
||||||
|
std::cout<<blobmsg_get_u16(attr);
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_BOOL:
|
||||||
|
std::cout<<(blobmsg_get_bool(attr) ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_DOUBLE:
|
||||||
|
std::cout<<blobmsg_get_double(attr);
|
||||||
|
break;
|
||||||
|
default: std::cout<<"(unknown)"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::cout<<"{";
|
||||||
|
explore_internal(explore_internal, message.begin());
|
||||||
|
std::cout<<"\n}"<<std::endl;
|
||||||
|
};
|
||||||
|
explore(ubus::call("network.interface.lan", "status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto main() -> int {
|
||||||
|
|
||||||
|
try {
|
||||||
|
example_for_checking_if_there_is_a_key();
|
||||||
|
|
||||||
|
example_for_getting_values();
|
||||||
|
|
||||||
|
example_for_sending_message();
|
||||||
|
|
||||||
|
example_for_exploring();
|
||||||
|
|
||||||
|
example_for_recursive_exploring();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (const std::exception & e) { std::cerr<<e.what()<<std::endl; }
|
||||||
|
|
||||||
|
catch (...) { perror("main error"); }
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -1,114 +1,23 @@
|
||||||
#ifndef _UBUS_CXX_HPP
|
#ifndef _UBUS_CXX_HPP
|
||||||
#define _UBUS_CXX_HPP
|
#define _UBUS_CXX_HPP
|
||||||
|
|
||||||
extern "C" { //TODO(pst): remove when in upstream
|
|
||||||
#include <libubus.h>
|
|
||||||
}
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <libubus.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// // example for checking if there is a key:
|
|
||||||
// if (ubus::call("service", "list", 1000).filter("cron")) {
|
|
||||||
// std::cout<<"Cron is active (with or without instances) "<<std::endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // example for getting values:
|
|
||||||
// auto lan_status = ubus::call("network.interface.lan", "status");
|
|
||||||
// for (auto x : lan_status.filter("ipv6-address", "", "address")) {
|
|
||||||
// std::cout<<"["<<blobmsg_get_string(x)<<"] ";
|
|
||||||
// }
|
|
||||||
// for (auto x : lan_status.filter("ipv4-address", "").filter("address")) {
|
|
||||||
// std::cout<<blobmsg_get_string(x)<<" ";
|
|
||||||
// }
|
|
||||||
// std::cout<<std::endl;
|
|
||||||
|
|
||||||
// // example for exploring:
|
|
||||||
// ubus::strings keys{"ipv4-address", "", ""};
|
|
||||||
// for (auto x : ubus::call("network.interface.lan", "status").filter(keys)) {
|
|
||||||
// std::cout<<blobmsg_name(x)<<": ";
|
|
||||||
// switch (blob_id(x)) {
|
|
||||||
// case BLOBMSG_TYPE_UNSPEC: std::cout<<"[unspecified]"; break;
|
|
||||||
// case BLOBMSG_TYPE_ARRAY: std::cout<<"[array]"; break;
|
|
||||||
// case BLOBMSG_TYPE_TABLE: std::cout<<"[table]"; break;
|
|
||||||
// case BLOBMSG_TYPE_STRING: std::cout<<blobmsg_get_string(x); break;
|
|
||||||
// case BLOBMSG_TYPE_INT64: std::cout<<blobmsg_get_u64(x); break;
|
|
||||||
// case BLOBMSG_TYPE_INT32: std::cout<<blobmsg_get_u32(x); break;
|
|
||||||
// case BLOBMSG_TYPE_INT16: std::cout<<blobmsg_get_u16(x); break;
|
|
||||||
// case BLOBMSG_TYPE_BOOL: std::cout<<blobmsg_get_bool(x); break;
|
|
||||||
// case BLOBMSG_TYPE_DOUBLE: std::cout<<blobmsg_get_double(x); break;
|
|
||||||
// default: std::cout<<"[unknown]";
|
|
||||||
// }
|
|
||||||
// std::cout<<std::endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // example for recursive exploring (output like from the original ubus call)
|
|
||||||
// const auto explore = [](auto message) -> void
|
|
||||||
// {
|
|
||||||
// auto end = message.end();
|
|
||||||
// auto explore_internal =
|
|
||||||
// [&end](auto & explore_ref, auto it, size_t depth=1) -> void
|
|
||||||
// {
|
|
||||||
// std::cout<<std::endl;
|
|
||||||
// bool first = true;
|
|
||||||
// for (; it!=end; ++it) {
|
|
||||||
// auto * attr = *it;
|
|
||||||
// if (first) { first = false; }
|
|
||||||
// else { std::cout<<",\n"; }
|
|
||||||
// std::cout<<std::string(depth, '\t');
|
|
||||||
// std::string name = blobmsg_name(attr);
|
|
||||||
// if (name != "") { std::cout<<"\""<<name<<"\": "; }
|
|
||||||
// switch (blob_id(attr)) {
|
|
||||||
// case BLOBMSG_TYPE_UNSPEC: std::cout<<"(unspecified)"; break;
|
|
||||||
// case BLOBMSG_TYPE_ARRAY:
|
|
||||||
// std::cout<<"[";
|
|
||||||
// explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
|
||||||
// std::cout<<"\n"<<std::string(depth, '\t')<<"]";
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_TABLE:
|
|
||||||
// std::cout<<"{";
|
|
||||||
// explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
|
||||||
// std::cout<<"\n"<<std::string(depth, '\t')<<"}";
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_STRING:
|
|
||||||
// std::cout<<"\""<<blobmsg_get_string(attr)<<"\"";
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_INT64:
|
|
||||||
// std::cout<<blobmsg_get_u64(attr);
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_INT32:
|
|
||||||
// std::cout<<blobmsg_get_u32(attr);
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_INT16:
|
|
||||||
// std::cout<<blobmsg_get_u16(attr);
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_BOOL:
|
|
||||||
// std::cout<<(blobmsg_get_bool(attr) ? "true" : "false");
|
|
||||||
// break;
|
|
||||||
// case BLOBMSG_TYPE_DOUBLE:
|
|
||||||
// std::cout<<blobmsg_get_double(attr);
|
|
||||||
// break;
|
|
||||||
// default: std::cout<<"(unknown)"; break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// std::cout<<"{";
|
|
||||||
// explore_internal(explore_internal, message.begin());
|
|
||||||
// std::cout<<"\n}"<<std::endl;
|
|
||||||
// };
|
|
||||||
// explore(ubus::call("network.interface.lan", "status"));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace ubus {
|
namespace ubus {
|
||||||
|
|
||||||
|
static constexpr int call_timeout = 500;
|
||||||
|
|
||||||
using msg_ptr = std::shared_ptr<const blob_attr>;
|
using msg_ptr = std::shared_ptr<const blob_attr>;
|
||||||
|
|
||||||
using strings = std::vector<std::string>;
|
using strings = std::vector<std::string>;
|
||||||
|
@ -130,7 +39,7 @@ inline auto concat(strings dest, strings src, Strings ...more)
|
||||||
template<class S, class ...Strings>
|
template<class S, class ...Strings>
|
||||||
inline auto concat(strings dest, S src, Strings ...more)
|
inline auto concat(strings dest, S src, Strings ...more)
|
||||||
{
|
{
|
||||||
dest.push_back(std::move(src));
|
dest.emplace_back(std::move(src));
|
||||||
return concat(std::move(dest), std::move(more)...);
|
return concat(std::move(dest), std::move(more)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +95,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline iterator(iterator &&) = default;
|
inline iterator(iterator &&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
inline iterator(const iterator &) = delete;
|
inline iterator(const iterator &) = delete;
|
||||||
|
@ -208,7 +117,8 @@ public:
|
||||||
auto operator++() -> iterator &;
|
auto operator++() -> iterator &;
|
||||||
|
|
||||||
|
|
||||||
inline ~iterator() { if (cur.get()==this) { static_cast<void>(cur.release()); } }
|
inline ~iterator()
|
||||||
|
{ if (cur.get()==this) { static_cast<void>(cur.release()); } }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -225,8 +135,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
inline explicit message(msg_ptr message, strings filter={""})
|
inline explicit message(msg_ptr message_ptr, strings filter={""})
|
||||||
: msg{std::move(message)}, keys{std::move(filter)} {}
|
: msg{std::move(message_ptr)}, keys{std::move(filter)} {}
|
||||||
|
|
||||||
|
|
||||||
inline message(message &&) = default;
|
inline message(message &&) = default;
|
||||||
|
@ -268,42 +178,41 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ubus {
|
class lock_shared_resources {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static std::mutex buffering;
|
static std::mutex inuse;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
inline ubus() = delete;
|
|
||||||
|
inline lock_shared_resources() { inuse.lock(); }
|
||||||
|
|
||||||
|
|
||||||
inline ubus(ubus &&) = delete;
|
inline lock_shared_resources(lock_shared_resources &&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
inline ubus(const ubus &) = delete;
|
inline lock_shared_resources(const lock_shared_resources &) = delete;
|
||||||
|
|
||||||
|
|
||||||
inline auto operator=(ubus &&) -> auto && = delete;
|
inline auto operator=(const lock_shared_resources &) -> auto & = delete;
|
||||||
|
|
||||||
|
|
||||||
inline auto operator=(const ubus &) -> auto & = delete;
|
inline auto operator=(lock_shared_resources &&) -> auto && = delete;
|
||||||
|
|
||||||
|
|
||||||
static auto get_context() -> ubus_context *
|
//NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||||
|
inline auto get_context() -> ubus_context * // is member to enforce inuse.
|
||||||
{
|
{
|
||||||
static auto ubus_freeing = [] (ubus_context * ctx) { ubus_free(ctx); };
|
static auto ubus_freeing = [] (ubus_context * ctx) { ubus_free(ctx); };
|
||||||
static std::unique_ptr<ubus_context, decltype(ubus_freeing)>
|
static std::unique_ptr<ubus_context, decltype(ubus_freeing)>
|
||||||
lazy_ctx{ubus_connect(nullptr), ubus_freeing};
|
lazy_ctx{ubus_connect(nullptr), ubus_freeing};
|
||||||
|
|
||||||
if (!lazy_ctx) { // it could be available on a later call:
|
if (!lazy_ctx) { // it could be available on a later call:
|
||||||
static std::mutex connecting;
|
|
||||||
|
|
||||||
connecting.lock();
|
lazy_ctx.reset(ubus_connect(nullptr));
|
||||||
if (!lazy_ctx) { lazy_ctx.reset(ubus_connect(nullptr)); }
|
|
||||||
connecting.unlock();
|
|
||||||
|
|
||||||
if (!lazy_ctx) {
|
if (!lazy_ctx) {
|
||||||
throw std::runtime_error("ubus error: cannot connect context");
|
throw std::runtime_error("ubus error: cannot connect context");
|
||||||
|
@ -314,7 +223,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static auto lock_and_get_shared_blob_buf() -> blob_buf *
|
//NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||||
|
inline auto get_blob_buf() -> blob_buf * // is member to enforce inuse.
|
||||||
{
|
{
|
||||||
static blob_buf buf;
|
static blob_buf buf;
|
||||||
|
|
||||||
|
@ -322,28 +232,37 @@ public:
|
||||||
static std::unique_ptr<blob_buf, decltype(blob_buf_freeing)>
|
static std::unique_ptr<blob_buf, decltype(blob_buf_freeing)>
|
||||||
created_to_free_on_the_end_of_life{&buf, blob_buf_freeing};
|
created_to_free_on_the_end_of_life{&buf, blob_buf_freeing};
|
||||||
|
|
||||||
buffering.lock();
|
|
||||||
blob_buf_init(&buf, 0);
|
blob_buf_init(&buf, 0);
|
||||||
|
|
||||||
return &buf;
|
return &buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void unlock_shared_blob_buf() { buffering.unlock(); }
|
inline ~lock_shared_resources() { inuse.unlock(); }
|
||||||
|
|
||||||
|
|
||||||
inline ~ubus() = delete;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
auto call(const char * path, const char * method="", int timeout=500);
|
template<class F>
|
||||||
|
auto call(const char * path, const char * method, F set_arguments,
|
||||||
|
int timeout=call_timeout) -> message;
|
||||||
|
|
||||||
|
|
||||||
|
inline auto call(const char * path, const char * method,
|
||||||
|
int timeout=call_timeout) -> message
|
||||||
|
{ return call(path, method, [](blob_buf * /*buf*/) { return 0; }, timeout); }
|
||||||
|
|
||||||
|
|
||||||
|
inline auto call(const char * path, int timeout=call_timeout) -> message
|
||||||
|
{ return call(path, "", timeout); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------- implementation: ----------------------------------
|
// ------------------------- implementation: ----------------------------------
|
||||||
|
|
||||||
|
|
||||||
std::mutex ubus::buffering;
|
std::mutex lock_shared_resources::inuse;
|
||||||
|
|
||||||
|
|
||||||
inline auto iterator::operator++() -> iterator &
|
inline auto iterator::operator++() -> iterator &
|
||||||
|
@ -363,7 +282,10 @@ inline auto iterator::operator++() -> iterator &
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
auto tmp = cur.release();
|
auto tmp = cur.release();
|
||||||
cur = std::unique_ptr<iterator>{new iterator(tmp)};
|
|
||||||
|
struct new_iterator : public iterator // use private constructor:
|
||||||
|
{ explicit new_iterator(iterator * par) : iterator{par} {} };
|
||||||
|
cur = std::make_unique<new_iterator>(tmp);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -392,31 +314,39 @@ inline auto iterator::operator++() -> iterator &
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline auto call(const char * path, const char * method, const int timeout)
|
template<class F>
|
||||||
|
inline auto call(const char * path, const char * method, F set_arguments,
|
||||||
|
int timeout) -> message
|
||||||
{
|
{
|
||||||
auto ctx = ubus::get_context();
|
|
||||||
|
auto shared = lock_shared_resources{};
|
||||||
|
|
||||||
|
auto ctx = shared.get_context();
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
int err = ubus_lookup_id(ctx, path, &id);
|
int err = ubus_lookup_id(ctx, path, &id);
|
||||||
|
|
||||||
if (err==0) { // call
|
if (err==0) { // call
|
||||||
ubus_request req{};
|
ubus_request request{};
|
||||||
|
|
||||||
auto buf = ubus::lock_and_get_shared_blob_buf();
|
auto buf = shared.get_blob_buf();
|
||||||
err = ubus_invoke_async(ctx, id, method, buf->head, &req);
|
err = set_arguments(buf);
|
||||||
ubus::unlock_shared_blob_buf();
|
if (err==0) {
|
||||||
|
err = ubus_invoke_async(ctx, id, method, buf->head, &request);
|
||||||
|
}
|
||||||
|
|
||||||
if (err==0) {
|
if (err==0) {
|
||||||
|
|
||||||
msg_ptr msg;
|
msg_ptr message_ptr;
|
||||||
|
|
||||||
/* Cannot capture anything (msg), the lambda would be another type.
|
/* Cannot capture message_ptr, the lambda would be another type.
|
||||||
* Pass a location where to save the message as priv pointer when
|
* Pass a location where to save the message as priv pointer when
|
||||||
* invoking and get it back here:
|
* invoking and get it back here:
|
||||||
*/
|
*/
|
||||||
req.priv = &msg;
|
request.priv = &message_ptr;
|
||||||
|
|
||||||
req.data_cb = [](ubus_request * req, int /*type*/, blob_attr * msg)
|
request.data_cb =
|
||||||
|
[](ubus_request * req, int /*type*/, blob_attr * msg)
|
||||||
{
|
{
|
||||||
if (req==nullptr || msg==nullptr) { return; }
|
if (req==nullptr || msg==nullptr) { return; }
|
||||||
|
|
||||||
|
@ -427,15 +357,15 @@ inline auto call(const char * path, const char * method, const int timeout)
|
||||||
if (!*saved) { throw std::bad_alloc(); }
|
if (!*saved) { throw std::bad_alloc(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
err = ubus_complete_request(ctx, &req, timeout);
|
err = ubus_complete_request(ctx, &request, timeout);
|
||||||
|
|
||||||
if (err==0) { return message{msg}; }
|
if (err==0) { return message{message_ptr}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string errmsg = "ubus::call error: cannot invoke";
|
std::string errmsg = "ubus::call error: cannot invoke";
|
||||||
errmsg += " (" + std::to_string(err) + ") " + path + " " + method;
|
errmsg += " (" + std::to_string(err) + ") " + path + " " + method;
|
||||||
throw std::runtime_error(errmsg.c_str());
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue