Browse Source

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>
lilik-openwrt-22.03
Peter Stadler 4 years ago
parent
commit
2d359a4556
13 changed files with 421 additions and 281 deletions
  1. +17
    -4
      net/nginx-util/Makefile
  2. +11
    -8
      net/nginx-util/src/CMakeLists.txt
  3. +10
    -12
      net/nginx-util/src/nginx-ssl-util.hpp
  4. +3
    -1
      net/nginx-util/src/nginx-util.cpp
  5. +29
    -8
      net/nginx-util/src/nginx-util.hpp
  6. +45
    -31
      net/nginx-util/src/px5g-openssl.hpp
  7. +7
    -7
      net/nginx-util/src/px5g.cpp
  8. +25
    -19
      net/nginx-util/src/regex-pcre.hpp
  9. +34
    -39
      net/nginx-util/src/test-nginx-util-root.sh
  10. +23
    -13
      net/nginx-util/src/test-nginx-util.sh
  11. +6
    -6
      net/nginx-util/src/test-px5g.sh
  12. +148
    -0
      net/nginx-util/src/ubus-cxx.cpp
  13. +63
    -133
      net/nginx-util/src/ubus-cxx.hpp

+ 17
- 4
net/nginx-util/Makefile View File

@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=nginx-util
PKG_VERSION:=1.3
PKG_RELEASE:=2
PKG_VERSION:=1.4
PKG_RELEASE:=1
PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at>
include $(INCLUDE_DIR)/package.mk
@ -11,6 +11,7 @@ include $(INCLUDE_DIR)/cmake.mk
CMAKE_OPTIONS+= -DUBUS=y
CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION)
define Package/nginx-util/default
SECTION:=net
CATEGORY:=Network
@ -19,63 +20,75 @@ define Package/nginx-util/default
DEPENDS:=+libstdcpp +libubus +libubox +libpthread
endef
define Package/nginx-util
$(Package/nginx-util/default)
CONFLICTS:=nginx-ssl-util-nopcre nginx-ssl-util
endef
define Package/nginx-ssl-util/default
$(Package/nginx-util/default)
TITLE+= including SSL
DEPENDS+= +libopenssl
CONFLICTS:=,nginx-util
CONFLICTS:=nginx-util,
endef
define Package/nginx-ssl-util
$(Package/nginx-ssl-util/default)
TITLE+= (using PCRE)
DEPENDS+= +libpcre
CONFLICTS+= ,nginx-ssl-util-nopcre
CONFLICTS+= nginx-ssl-util-nopcre,
endef
define Package/nginx-ssl-util-nopcre
$(Package/nginx-ssl-util/default)
TITLE+= (using <regex>)
CONFLICTS+= nginx-ssl-util
endef
define Package/nginx-util/description
Utility that builds dynamically LAN listen directives for Nginx.
endef
Package/nginx-ssl-util/default/description = $(Package/nginx-util/description)\
Furthermore, it manages SSL directives for its server parts and can create \
corresponding (self-signed) certificates.
Package/nginx-ssl-util/description = \
$(Package/nginx-ssl-util/default/description) \
It uses the PCRE library for performance.
Package/nginx-ssl-util-nopcre/description = \
$(Package/nginx-ssl-util/default/description) \
It uses the standard regex library of C++.
define Package/nginx-util/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-util $(1)/usr/bin/nginx-util
endef
define Package/nginx-ssl-util/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util $(1)/usr/bin/nginx-util
endef
define Package/nginx-ssl-util-nopcre/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util-nopcre \
$(1)/usr/bin/nginx-util
endef
$(eval $(call BuildPackage,nginx-util))
$(eval $(call BuildPackage,nginx-ssl-util))
$(eval $(call BuildPackage,nginx-ssl-util-nopcre))

+ 11
- 8
net/nginx-util/src/CMakeLists.txt View File

@ -5,15 +5,8 @@ SET(CMAKE_CXX_STANDARD 17)
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(-Wno-unused-parameter -Wmissing-declarations)
ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations -Wshadow)
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
@ -22,6 +15,14 @@ IF(UBUS)
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)
TARGET_COMPILE_DEFINITIONS(nginx-util PUBLIC -DNO_SSL)
TARGET_LINK_LIBRARIES(nginx-util ${ubox} ${ubus} pthread)
@ -38,6 +39,8 @@ INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin)
ELSE()
ADD_COMPILE_DEFINITIONS(VERSION=0)
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-root.sh test-nginx-util-root.sh COPYONLY)


+ 10
- 12
net/nginx-util/src/nginx-ssl-util.hpp View File

@ -1,8 +1,6 @@
#ifndef __NGINX_SSL_UTIL_HPP
#define __NGINX_SSL_UTIL_HPP
#include <thread>
#ifdef NO_PCRE
#include <regex>
namespace rgx = std;
@ -147,7 +145,7 @@ constexpr auto _end = _Line{
template<char clim='\0'>
constexpr auto _capture = _Line{
static constexpr auto _capture = _Line{
[](const std::string & param, const std::string & /*begin*/) -> std::string
{ 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.
static const auto CRON_CMD = Line::build
< _space, _escape<NGINX_UTIL>, _space, _escape<ADD_SSL_FCT,'\''>, _space,
_capture<>, _newline >();
<_space, _escape<NGINX_UTIL>, _space, _escape<ADD_SSL_FCT,'\''>, _space,
_capture<>, _newline>();
static const auto NGX_SERVER_NAME =
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>();
static const auto NGX_INCLUDE_LAN_LISTEN_DEFAULT = Line::build
< _begin, _escape<_include>, _space,
_escape<LAN_LISTEN_DEFAULT, '\''>, _end >();
<_begin, _escape<_include>, _space,
_escape<LAN_LISTEN_DEFAULT, '\''>, _end>();
static const auto NGX_INCLUDE_LAN_SSL_LISTEN = Line::build
<_begin, _escape<_include>, _space, _escape<LAN_SSL_LISTEN, '\''>, _end>();
static const auto NGX_INCLUDE_LAN_SSL_LISTEN_DEFAULT = Line::build
< _begin, _escape<_include>, _space,
_escape<LAN_SSL_LISTEN_DEFAULT, '\''>, _end >();
<_begin, _escape<_include>, _space,
_escape<LAN_SSL_LISTEN_DEFAULT, '\''>, _end>();
static const auto NGX_SSL_CRT = Line::build
<_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: "};
errmsg += "cannot add SSL directives to " + name + ".conf, missing: ";
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: "};
errmsg += "Cron unavailable to re-create the ssl certificate for ";
errmsg += name + "\n";
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
} // else active with or without instances:
#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: "};
errmsg += "cannot delete SSL directives from " + name + ".conf, missing: ";
errmsg += NGX_SERVER_NAME.STR(name, "\n ") + "\n";
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}


+ 3
- 1
net/nginx-util/src/nginx-util.cpp View File

@ -1,3 +1,5 @@
#include <iostream>
#include "nginx-util.hpp"
#ifndef NO_SSL
@ -121,7 +123,7 @@ void get_env()
auto main(int argc, char * argv[]) -> int
{
// 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{
std::array<std::string_view, 2>{"init_lan", ""},


+ 29
- 8
net/nginx-util/src/nginx-util.hpp View File

@ -4,12 +4,14 @@
#include <array>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <string_view>
#include <thread>
#include <unistd.h>
#include <vector>
#ifndef NO_UBUS
#include "ubus-cxx.hpp"
@ -61,15 +63,34 @@ void get_env();
void write_file(const std::string_view & name, const std::string & str,
const std::ios_base::openmode flag)
{
std::ofstream file(name.data(), flag);
if (!file.good()) {
throw std::ofstream::failure(
"write_file error: cannot open " + std::string{name});
auto tmp = std::string{name};
if ( (flag & std::ios::ate) == 0 && (flag & std::ios::app) == 0 ) {
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 (";
errmsg += std::to_string(errno) + "): " + std::strerror(errno);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}


+ 45
- 31
net/nginx-util/src/px5g-openssl.hpp View File

@ -8,9 +8,11 @@
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <stdexcept>
#include <string>
#include <unistd.h>
static constexpr auto rsa_min_modulus_bits = 512;
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,
const time_t seconds, const bool use_pem) -> bool
{
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"));
X509 * x509 = nullptr;
@ -71,7 +82,7 @@ auto checkend(const std::string & crtpath,
if (x509==nullptr) {
std::string errmsg{"checkend error: unable to load certificate\n"};
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;
@ -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 "};
errmsg += std::to_string(curve) + "\n";
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);
@ -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 "};
errmsg += std::to_string(curve) + "\n";
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};
auto tmp = static_cast<char *>(static_cast<void *>(eckey));
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), tmp)) {
// 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(), eckey)) {
EC_KEY_free(eckey);
std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"};
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
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 ("};
errmsg += std::to_string(keysize) + ") out of range [512..";
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();
if (bignum == nullptr) {
std::string errmsg{"gen_rsakey error: cannot get big number struct\n"};
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
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(exponent) + "\n";
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};
auto tmp = static_cast<char *>(static_cast<void *>(rsa));
if (!EVP_PKEY_assign_RSA(pkey.get(), tmp)) {
// EVP_PKEY_assign_RSA is a macro casting rsa to char *:
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
if (!EVP_PKEY_assign_RSA(pkey.get(), rsa)) {
RSA_free(rsa);
std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"};
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
return pkey;
@ -190,20 +201,21 @@ void write_key(const EVP_PKEY_ptr & pkey,
{
BIO * bio = nullptr;
if (keypath.empty()) {
bio = BIO_new_fp( stdout, BIO_NOCLOSE | (use_pem ? BIO_FP_TEXT : 0) );
if (keypath.empty()) { bio = _BIO_new_fp(stdout, use_pem); }
} 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;
// 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.
if (fd >= 0) {
auto fp = fdopen(fd, (use_pem ? "w" : "wb") );
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)
}
else { close(fd); }
@ -216,7 +228,7 @@ void write_key(const EVP_PKEY_ptr & pkey,
errmsg += keypath.empty() ? "stdout" : keypath;
errmsg += "\n";
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
int len = 0;
@ -249,7 +261,7 @@ void write_key(const EVP_PKEY_ptr & pkey,
errmsg += keypath.empty() ? "stdout" : keypath;
errmsg += "\n";
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) {
std::string errmsg{"subject2name error: cannot create X509 name \n"};
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
if (subject.empty()) { return name; }
@ -287,19 +299,21 @@ auto subject2name(const std::string & subject) -> X509_NAME_ptr
if (nid == NID_undef) {
// skip unknown entries (silently?).
} else {
auto val = static_cast<const unsigned char *>(
static_cast<const void *>(&subject[prev]) );
auto val = // X509_NAME_add_entry_by_NID wants it unsigned:
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
reinterpret_cast<const unsigned char *>(&subject[prev]);
auto len = i - prev;
if ( X509_NAME_add_entry_by_NID(name.get(), nid, MBSTRING_ASC,
val, len, -1, 0)
if ( X509_NAME_add_entry_by_NID(name.get(), nid,
MBSTRING_ASC, //NOLINT(hicpp-signed-bitwise) is macro
val, len, -1, 0)
== 0 )
{
std::string errmsg{"subject2name error: cannot add "};
errmsg += "/" + type +"="+ subject.substr(prev, len) +"\n";
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
}
chr = '=';
@ -320,7 +334,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
if (x509 == nullptr) {
std::string errmsg{"selfsigned error: cannot create X509 structure\n"};
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)
@ -329,7 +343,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
std::string errmsg{"selfsigned error: cannot set "};
errmsg += what + " in X509 certificate\n";
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"); }
@ -380,7 +394,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
}
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"));
int len = 0;
@ -399,7 +413,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
errmsg += crtpath.empty() ? "stdout" : crtpath;
errmsg += "\n";
ERR_print_errors_cb(print_error, &errmsg);
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}
}


+ 7
- 7
net/nginx-util/src/px5g.cpp View File

@ -118,7 +118,7 @@ auto checkend(const argv_view & argv) -> int
} catch (...) {
auto errmsg = std::string{"checkend error: invalid time "};
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);
@ -126,7 +126,7 @@ auto checkend(const argv_view & argv) -> int
if (num!=static_cast<intmax_t>(seconds)) {
auto errmsg = std::string{"checkend error: time too big "};
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) {
throw std::runtime_error
("eckey error: more than one main option");
} // else:
} //else:
has_main_option = true;
curve = parse_curve(argv[i]);
@ -223,7 +223,7 @@ void rsakey(const argv_view & argv)
if (has_main_option) {
throw std::runtime_error("rsakey error: more than one keysize");
} // else:
} //else:
has_main_option = true;
try {
@ -231,7 +231,7 @@ void rsakey(const argv_view & argv)
} catch (...) {
std::string errmsg{"rsakey error: invalid keysize "};
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 (...) {
std::string errmsg{"selfsigned error: not a number for -days "};
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 (...) {
std::string errmsg{"selfsigned error: invalid keysize "};
errmsg += argv[i].substr(4);
std::throw_with_nested(std::runtime_error(errmsg.c_str()));
std::throw_with_nested(std::runtime_error(errmsg));
}
} else {
throw std::runtime_error("selfsigned error: invalid algorithm");


+ 25
- 19
net/nginx-util/src/regex-pcre.hpp View File

@ -1,5 +1,3 @@
// implementing *some* <regex> functions using pcre for performance:
#ifndef __REGEXP_PCRE_HPP
#define __REGEXP_PCRE_HPP
@ -11,6 +9,9 @@
namespace rgx {
/* partially implement the std::regex interface using PCRE for performance
* (=> pass "match" as non-const reference)
*/
namespace regex_constants {
@ -130,8 +131,8 @@ class smatch {
friend auto regex_search(std::string::const_iterator begin,
std::string::const_iterator end,
smatch & match,
const regex & rgx);
smatch & match, //NOLINT(google-runtime-references)
const regex & rgx); // match std::regex interface.
private:
@ -188,14 +189,15 @@ auto regex_replace(const std::string & subj,
const std::string & insert);
inline auto regex_search(const std::string & subj, smatch & match,
const regex & rgx);
inline auto regex_search(const std::string & subj,
smatch & match, //NOLINT(google-runtime-references)
const regex & rgx); // match std::regex interface.
auto regex_search(std::string::const_iterator begin,
std::string::const_iterator end,
smatch & match,
const regex & rgx);
smatch & match, //NOLINT(google-runtime-references)
const regex & rgx); // match std::regex interface.
@ -260,12 +262,10 @@ auto smatch::format(const std::string & fmt) const {
index = pos + 1;
char chr = fmt[index++];
int n = 0;
static const auto BASE = 10;
switch(chr) {
case '&': // match
ret += this->str(0);
ret += str(0);
break;
case '`': // prefix
@ -276,14 +276,20 @@ auto smatch::format(const std::string & fmt) const {
ret.append(begin+vec[1], end);
break;
default: // number => submatch
while (isdigit(chr) != 0) {
n = BASE*n + chr - '0';
chr = fmt[index++];
}
ret += n>0 ? str(n) : std::string{"$"};
default:
if (isdigit(chr) != 0) { // one or two digits => submatch:
int num = chr - '0';
chr = fmt[index];
if (isdigit(chr) != 0) { // second digit:
++index;
static const auto base = 10;
num = num*base + chr - '0';
}
ret += str(num);
break;
} //else:
ret += '$';
[[fallthrough]];
case '$': // escaped


+ 34
- 39
net/nginx-util/src/test-nginx-util-root.sh View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
PRINT_PASSED=2
@ -37,7 +37,7 @@ setpoint_add_ssl() {
local indent="\n$1"
local name="$2"
local default=""
[ "${name}" == "${LAN_NAME}" ] && default=".default"
[ "${name}" = "${LAN_NAME}" ] && default=".default"
local prefix="${CONF_DIR}${name}"
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 "
if [ $? -eq $2 ]
test() {
eval "$1 2>/dev/null >/dev/null"
if [ "$?" -eq "$2" ]
then
[ "${PRINT_PASSED}" -gt 0 ] \
&& 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)
test '[ -n "${NGINX_CONF}" ]' 0
@ -101,21 +108,21 @@ test '[ -n "${SSL_SESSION_TIMEOUT_ARG}" ]' 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_SERVER_NAME="server_name * '\$' *;"
NGX_SSL_CRT="ssl_certificate '\$.crt';"
NGX_SSL_KEY="ssl_certificate_key '\$.key';"
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}';"
cat > ${LAN_NAME}.sans <<EOF
cat > "${LAN_NAME}.sans" <<EOF
# default_server for the LAN addresses getting the IPs by:
# ifstatus lan | jsonfilter -e '@["ipv4-address","ipv6-address"].*.address'
server {
@ -196,56 +203,44 @@ EOF
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}")"
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}
do test 'setpoint_add_ssl " " '${conf%:*} ${conf#*:}
do test 'setpoint_add_ssl " " '"${conf%:*}" "${conf#*:}"
done
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
test '[ "${ADD_SSL_FCT}" == "add_ssl" ] ' 0
test '[ "${ADD_SSL_FCT}" = "add_ssl" ] ' 0
for conf in ${CONFS}; do
name=${conf%:*}
cp ${name}.sans ${name}.conf
test '${NGINX_UTIL} add_ssl '${name} ${conf#*:}
(test '[ "$(cat '${name}'.conf)" == "$(cat '${name}'.with)" ]' 0 >/dev/null)
[ "$?" -gt 0 ] && {
echo "created ${name}.conf:"; cat "${name}.conf"
echo "differs from setpoint:"; cat "${name}.with"
exit 1
}
name="${conf%:*}"
cp "${name}.sans" "${name}.conf"
test '"${NGINX_UTIL}" add_ssl '"${name}" "${conf#*:}"
test_setpoint "${name}.conf" "$(cat "${name}.with")"
done
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting ${NGINX_UTIL} del_ssl ...\n"
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s del_ssl ...\n" "${NGINX_UTIL}"
sed -i "/server {/a\\ include '${LAN_LISTEN}';" minimal.sans
for conf in ${CONFS}; do
name=${conf%:*}
cp ${name}.with ${name}.conf
test '${NGINX_UTIL} del_ssl '${name} ${conf#*:}
(test '[ "$(cat '${name}'.conf)" == "$(cat '${name}'.sans)" ]' 0 >/dev/null)
[ "$?" -gt 0 ] && {
echo "created ${name}.conf:"; cat "${name}.conf"
echo "differs from setpoint:"; cat "${name}.sans"
exit 1
}
name="${conf%:*}"
cp "${name}.with" "${name}.conf"
test '"${NGINX_UTIL}" del_ssl '"${name}" "${conf#*:}"
test_setpoint "${name}.conf" "$(cat "${name}.sans")"
done

+ 23
- 13
net/nginx-util/src/test-nginx-util.sh View File

@ -1,38 +1,48 @@
#!/bin/bash
#!/bin/sh
printf "Initializing tests ...\n"
fakechroot=""
[ -x /usr/bin/fakechroot ] && fakechroot="/usr/bin/fakechroot" \
[ -x "/usr/bin/fakechroot" ] && fakechroot="/usr/bin/fakechroot" \
|| [ "$(id -u)" -eq 0 ] || { \
printf "Error: Testing needs fakechroot or whoami=root for chroot."
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"
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
echo $?
"${fakechroot}" /bin/chroot "${TMPROOT}" \
/bin/sh -c "/usr/bin/test-nginx-util-root.sh" ||
{
echo "!!! Error: $?"
rm -r "${TMPROOT}"
exit 1
}
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}"

+ 6
- 6
net/nginx-util/src/test-px5g.sh View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
PRINT_PASSED=2
@ -8,7 +8,7 @@ OPENSSL_PEM="$(mktemp)"
OPENSSL_DER="$(mktemp)"
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 \
-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)
function test() {
test() {
eval "$1 >/dev/null "
if [ $? -eq $2 ]
if [ $? -eq "$2" ]
then
[ "${PRINT_PASSED}" -gt 0 ] \
&& 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 -pkeyopt ec_paramgen_curve:secp384r1 \
| openssl x509 -checkend 0 ' 0
test './px5g selfsigned -subj $SUBJECT | openssl x509 -noout \
-subject -nameopt compat | grep -q subject=$SUBJECT 2>/dev/null' 0
test './px5g selfsigned -subj "$SUBJECT" | openssl x509 -noout \
-subject -nameopt compat | grep -q subject="$SUBJECT" 2>/dev/null' 0
test './px5g selfsigned -out /dev/null -keyout /proc/self/fd/1 \
| openssl rsa -check 2>/dev/null ' 0


+ 148
- 0
net/nginx-util/src/ubus-cxx.cpp View 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;
}

+ 63
- 133
net/nginx-util/src/ubus-cxx.hpp View File

@ -1,114 +1,23 @@
#ifndef _UBUS_CXX_HPP
#define _UBUS_CXX_HPP
extern "C" { //TODO(pst): remove when in upstream
#include <libubus.h>
}
#include <cassert>
#include <libubus.h>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
#ifndef NDEBUG
#include <iostream>
#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 {
static constexpr int call_timeout = 500;
using msg_ptr = std::shared_ptr<const blob_attr>;
using strings = std::vector<std::string>;
@ -130,7 +39,7 @@ inline auto concat(strings dest, strings src, Strings ...more)
template<class S, class ...Strings>
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)...);
}
@ -186,7 +95,7 @@ public:
}
inline iterator(iterator &&) = default;
inline iterator(iterator &&) noexcept = default;
inline iterator(const iterator &) = delete;
@ -208,7 +117,8 @@ public:
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:
inline explicit message(msg_ptr message, strings filter={""})
: msg{std::move(message)}, keys{std::move(filter)} {}
inline explicit message(msg_ptr message_ptr, strings filter={""})
: msg{std::move(message_ptr)}, keys{std::move(filter)} {}
inline message(message &&) = default;
@ -268,42 +178,41 @@ public:
class ubus {
class lock_shared_resources {
private:
static std::mutex buffering;
static std::mutex inuse;
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 std::unique_ptr<ubus_context, decltype(ubus_freeing)>
lazy_ctx{ubus_connect(nullptr), ubus_freeing};
if (!lazy_ctx) { // it could be available on a later call:
static std::mutex connecting;
connecting.lock();
if (!lazy_ctx) { lazy_ctx.reset(ubus_connect(nullptr)); }
connecting.unlock();
lazy_ctx.reset(ubus_connect(nullptr));
if (!lazy_ctx) {
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;
@ -322,28 +232,37 @@ public:
static std::unique_ptr<blob_buf, decltype(blob_buf_freeing)>
created_to_free_on_the_end_of_life{&buf, blob_buf_freeing};
buffering.lock();
blob_buf_init(&buf, 0);
return &buf;
}
static void unlock_shared_blob_buf() { buffering.unlock(); }
inline ~lock_shared_resources() { inuse.unlock(); }
};
inline ~ubus() = delete;
};
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); }
auto call(const char * path, const char * method="", int timeout=500);
// ------------------------- implementation: ----------------------------------
std::mutex ubus::buffering;
std::mutex lock_shared_resources::inuse;
inline auto iterator::operator++() -> iterator &
@ -363,7 +282,10 @@ inline auto iterator::operator++() -> iterator &
++i;
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 {
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;
int err = ubus_lookup_id(ctx, path, &id);
if (err==0) { // call
ubus_request req{};
ubus_request request{};
auto buf = ubus::lock_and_get_shared_blob_buf();
err = ubus_invoke_async(ctx, id, method, buf->head, &req);
ubus::unlock_shared_blob_buf();
auto buf = shared.get_blob_buf();
err = set_arguments(buf);
if (err==0) {
err = ubus_invoke_async(ctx, id, method, buf->head, &request);
}
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
* 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; }
@ -427,15 +357,15 @@ inline auto call(const char * path, const char * method, const int timeout)
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";
errmsg += " (" + std::to_string(err) + ") " + path + " " + method;
throw std::runtime_error(errmsg.c_str());
throw std::runtime_error(errmsg);
}


Loading…
Cancel
Save