mirror of
https://github.com/emqx/neuron.git
synced 2026-10-18 13:41:22 +08:00
feat(restful): remove license api
This commit is contained in:
+1
-2
@@ -107,8 +107,6 @@ set(NEURON_SOURCES
|
||||
src/adapter/driver/cache.c
|
||||
src/adapter/driver/driver.c
|
||||
plugins/restful/handle.c
|
||||
plugins/restful/license.c
|
||||
plugins/restful/license_handle.c
|
||||
plugins/restful/log_handle.c
|
||||
plugins/restful/normal_handle.c
|
||||
plugins/restful/rw_handle.c
|
||||
@@ -131,6 +129,7 @@ add_executable(neuron)
|
||||
target_sources(neuron PRIVATE ${NEURON_SOURCES})
|
||||
target_include_directories(neuron PRIVATE include/neuron src plugins)
|
||||
target_link_libraries(neuron dl neuron-base sqlite3 -lm)
|
||||
target_link_options(neuron PRIVATE "LINKER:--export-dynamic")
|
||||
|
||||
#copy file for run
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/zlog.conf DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "datatag_handle.h"
|
||||
#include "group_config_handle.h"
|
||||
#include "http.h"
|
||||
#include "license_handle.h"
|
||||
#include "log_handle.h"
|
||||
#include "normal_handle.h"
|
||||
#include "plugin_handle.h"
|
||||
@@ -95,9 +94,6 @@ struct neu_rest_handler cors_handler[] = {
|
||||
{
|
||||
.url = "/api/v2/node/state",
|
||||
},
|
||||
{
|
||||
.url = "/api/v2/license",
|
||||
},
|
||||
{
|
||||
.url = "/api/v2/version",
|
||||
},
|
||||
@@ -114,6 +110,11 @@ struct neu_rest_handler api_handlers[] = {
|
||||
.url = "/api/v2/hwtoken",
|
||||
.value.dst_url = "http://127.0.0.1:7003/api/v2/hwtoken",
|
||||
},
|
||||
{
|
||||
.type = NEU_REST_HANDLER_PROXY,
|
||||
.url = "/api/v2/license",
|
||||
.value.dst_url = "http://127.0.0.1:7003/api/v2/license",
|
||||
},
|
||||
{
|
||||
.method = NEU_REST_METHOD_POST,
|
||||
.type = NEU_REST_HANDLER_FUNCTION,
|
||||
@@ -290,18 +291,6 @@ struct neu_rest_handler api_handlers[] = {
|
||||
.url = "/api/v2/level",
|
||||
.value.handler = handle_log_level,
|
||||
},
|
||||
{
|
||||
.method = NEU_REST_METHOD_POST,
|
||||
.type = NEU_REST_HANDLER_FUNCTION,
|
||||
.url = "/api/v2/license",
|
||||
.value.handler = handle_set_license,
|
||||
},
|
||||
{
|
||||
.method = NEU_REST_METHOD_GET,
|
||||
.type = NEU_REST_HANDLER_FUNCTION,
|
||||
.url = "/api/v2/license",
|
||||
.value.handler = handle_get_license,
|
||||
},
|
||||
{
|
||||
.method = NEU_REST_METHOD_GET,
|
||||
.type = NEU_REST_HANDLER_FUNCTION,
|
||||
|
||||
@@ -1,417 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#define NEURON_LOG_LABEL "license"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "errcodes.h"
|
||||
#include "utils/log.h"
|
||||
|
||||
#include "license.h"
|
||||
|
||||
const char root_cert_pub_key[] = "-----BEGIN PUBLIC KEY-----\n\
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyJgH+BvEJIStYvyw1keQ\n\
|
||||
/ixVPJ4GGjlP7lTKnZL3mqZyPXQUEaLnRmcQ3/ra8xYQPcfMReynqmrYmT45/eD2\n\
|
||||
tK7rdXTzYfOWoU0cXNQMaQS7be1bLF4QrAEbJhEsgkjX9rP30mrzZCjRRnkQtWmi\n\
|
||||
4DNBU4qOl6Ee9aAS5aY+L7DW646J47Tyc7gAA4sdZw04KGBXnSyXzyBvPaf+QByO\n\
|
||||
rOXUxBcxehHN/Ox41/duYFXSR40U6lyp49NYJ6yEUVWSp4oxsrkcgqyegNKXdW1D\n\
|
||||
8oqJXzxalbh/RB8YYlX+Ae377gEBlLefPFdSEYDRN/ajs3UIeqde6i20lVyDPIjE\n\
|
||||
cQIDAQAB\n\
|
||||
-----END PUBLIC KEY-----";
|
||||
|
||||
static const uint32_t mon_yday[2][12] = {
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
|
||||
};
|
||||
|
||||
static int isleap(int year)
|
||||
{
|
||||
return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
|
||||
}
|
||||
|
||||
static uint64_t mktimestamp(struct tm dt)
|
||||
{
|
||||
uint64_t ret;
|
||||
int i = 0;
|
||||
|
||||
ret = ((uint64_t) dt.tm_year - 1970) * 365 * 24 * 3600;
|
||||
ret +=
|
||||
(mon_yday[isleap(dt.tm_year)][dt.tm_mon] + dt.tm_mday - 1) * 24 * 3600;
|
||||
ret += dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
|
||||
|
||||
for (i = 1970; i < dt.tm_year; i++) {
|
||||
if (isleap(i)) {
|
||||
ret += 24 * 3600;
|
||||
}
|
||||
}
|
||||
if (ret > 4107715199) { // 2100-02-29 23:59:59
|
||||
ret += 24 * 3600;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static uint64_t get_asn1_ts(ASN1_TIME *time)
|
||||
{
|
||||
struct tm t;
|
||||
const char *str = (const char *) time->data;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
if (time->type == V_ASN1_UTCTIME) { /* two digit year */
|
||||
sscanf(str, "%2d%2d%2d%2d%2d%2dZ", &t.tm_year, &t.tm_mon, &t.tm_mday,
|
||||
&t.tm_hour, &t.tm_min, &t.tm_sec);
|
||||
t.tm_year += 2000;
|
||||
} else if (time->type == V_ASN1_GENERALIZEDTIME) { /* four digit year */
|
||||
sscanf(str, "%4d%2d%2d%2d%2d%2dZ", &t.tm_year, &t.tm_mon, &t.tm_mday,
|
||||
&t.tm_hour, &t.tm_min, &t.tm_sec);
|
||||
}
|
||||
|
||||
t.tm_mon -= 1;
|
||||
/* Note: we did not adjust the time based on time zone information */
|
||||
return mktimestamp(t);
|
||||
}
|
||||
|
||||
static int scan_bitvec(uint8_t vec[], size_t size, const char *hex)
|
||||
{
|
||||
if ('0' == *hex && 'x' == tolower(*(hex + 1))) {
|
||||
hex += 2;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
size_t len = strlen(hex);
|
||||
|
||||
while (i < len && i / 2 < size) {
|
||||
char c = hex[len - 1 - i];
|
||||
uint8_t v = 0;
|
||||
if ('0' <= c && c <= '9') {
|
||||
v = c - '0';
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
v = 10 + c - 'a';
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
v = 10 + c - 'A';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
vec[i / 2] += v << ((i & 0x01) * 4);
|
||||
++i;
|
||||
}
|
||||
|
||||
return (i == len) ? 0 : -1;
|
||||
}
|
||||
|
||||
void print_bitvec(char *s, size_t size, uint8_t vec[], size_t n)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (size_t j = n; j-- > 0 && i < size;) {
|
||||
if (0 != j && 0 == vec[j]) {
|
||||
continue;
|
||||
}
|
||||
uint8_t h = (vec[j] & 0xF0) >> 4;
|
||||
uint8_t l = vec[j] & 0x0F;
|
||||
s[i++] = (h < 10) ? ('0' + h) : ('A' + h - 10);
|
||||
if (i < size) {
|
||||
s[i++] = (l < 10) ? ('0' + l) : ('A' + l - 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < size) {
|
||||
s[i] = '\0';
|
||||
} else if (size > 0) {
|
||||
s[size - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const g_license_type_str_map_[] = {
|
||||
[LICENSE_TYPE_TRIAL] = "trial",
|
||||
[LICENSE_TYPE_RETAIL] = "retail",
|
||||
[LICENSE_TYPE_SME] = "small-enterprise",
|
||||
};
|
||||
|
||||
static const char *const g_plugin_bit_str_map[] = {
|
||||
[PLUGIN_BIT_MODBUS_PLUS_TCP] = "modbus-plus-tcp",
|
||||
[PLUGIN_BIT_MODBUS_RTU] = "modbus-rtu",
|
||||
[PLUGIN_BIT_OPCUA] = "opcua",
|
||||
[PLUGIN_BIT_S7COMM] = "s7comm",
|
||||
[PLUGIN_BIT_FINS] = "fins",
|
||||
[PLUGIN_BIT_QNA3E] = "QnA3E",
|
||||
[PLUGIN_BIT_IEC60870_5_104] = "IEC60870-5-104",
|
||||
[PLUGIN_BIT_KNX] = "KNXnet/IP",
|
||||
[PLUGIN_BIT_NONA11] = "NONA11",
|
||||
[PLUGIN_BIT_DLT645_2007] = "DLT645-2007",
|
||||
[PLUGIN_BIT_BACNET] = "BACnet/IP",
|
||||
[PLUGIN_BIT_MAX] = NULL,
|
||||
};
|
||||
|
||||
static license_type_e scan_licese_type(const char *s)
|
||||
{
|
||||
license_type_e t = LICENSE_TYPE_MAX;
|
||||
for (int i = 0; i < LICENSE_TYPE_MAX; ++i) {
|
||||
if (0 == strcmp(s, g_license_type_str_map_[i])) {
|
||||
t = (license_type_e) i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int extract_license(const char *license_fname, const char *pub_key,
|
||||
license_t *license)
|
||||
{
|
||||
BIO * certbio = NULL;
|
||||
BIO * keybio = NULL;
|
||||
X509 * cert = NULL;
|
||||
X509_NAME * subj = NULL;
|
||||
X509_NAME * issuer = NULL;
|
||||
X509_NAME_ENTRY *entry = NULL;
|
||||
EVP_PKEY * pkey = NULL;
|
||||
const STACK_OF(X509_EXTENSION) * ext_list;
|
||||
ASN1_OBJECT * obj;
|
||||
ASN1_STRING * str;
|
||||
ASN1_TIME * not_before, *not_after;
|
||||
X509_EXTENSION * ext;
|
||||
char buf[100];
|
||||
const unsigned char *value;
|
||||
int i;
|
||||
int rv = 0;
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
struct stat statbuf;
|
||||
if (-1 == stat(license_fname, &statbuf)) {
|
||||
rv = NEU_ERR_LICENSE_NOT_FOUND;
|
||||
goto final;
|
||||
}
|
||||
|
||||
/* load emqx certificate */
|
||||
certbio = BIO_new(BIO_s_file());
|
||||
if (0 == BIO_read_filename(certbio, license_fname)) {
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
goto final;
|
||||
}
|
||||
if (!(cert = PEM_read_bio_X509(certbio, NULL, NULL, NULL))) {
|
||||
nlog_warn("loading certificate into memory");
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
goto final;
|
||||
}
|
||||
|
||||
/* load public key */
|
||||
keybio = BIO_new(BIO_s_mem());
|
||||
BIO_puts(keybio, pub_key);
|
||||
if (!(pkey = PEM_read_bio_PUBKEY(keybio, NULL, NULL, NULL))) {
|
||||
nlog_warn("loading pubkey into memory");
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
/* Verify the certificates */
|
||||
if (X509_verify(cert, pkey) == 0) {
|
||||
nlog_warn("certification verification failure");
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
goto final;
|
||||
}
|
||||
|
||||
not_before = X509_get_notBefore(cert);
|
||||
not_after = X509_get_notAfter(cert);
|
||||
license->since_ = get_asn1_ts(not_before);
|
||||
license->until_ = get_asn1_ts(not_after);
|
||||
nlog_info("certificate expire date: %s", not_after->data);
|
||||
|
||||
subj = X509_get_subject_name(cert);
|
||||
for (i = 0; i < X509_NAME_entry_count(subj); i++) {
|
||||
entry = X509_NAME_get_entry(subj, i);
|
||||
str = X509_NAME_ENTRY_get_data(entry);
|
||||
value = ASN1_STRING_get0_data(str);
|
||||
nlog_info("certificate subject: %s", value);
|
||||
}
|
||||
|
||||
issuer = X509_get_issuer_name(cert);
|
||||
for (i = 0; i < X509_NAME_entry_count(issuer); i++) {
|
||||
entry = X509_NAME_get_entry(issuer, i);
|
||||
str = X509_NAME_ENTRY_get_data(entry);
|
||||
value = ASN1_STRING_get0_data(str);
|
||||
nlog_info("certificate issuer: %s", value);
|
||||
}
|
||||
|
||||
/* extract the certificate's extensions */
|
||||
|
||||
ext_list = X509_get0_extensions(cert);
|
||||
if (sk_X509_EXTENSION_num(ext_list) <= 0) {
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
goto final;
|
||||
}
|
||||
|
||||
for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
|
||||
ext = sk_X509_EXTENSION_value(ext_list, i);
|
||||
obj = X509_EXTENSION_get_object(ext);
|
||||
str = X509_EXTENSION_get_data(ext);
|
||||
OBJ_obj2txt(buf, sizeof buf, obj, 1);
|
||||
value = ASN1_STRING_get0_data(str);
|
||||
nlog_info("certificate OID: %s => %s", buf, &value[2]);
|
||||
|
||||
const char *val = (char *) &value[2];
|
||||
|
||||
if (0 == strcmp(buf, LICENSE_KEY_TYPE)) {
|
||||
license->type_ = scan_licese_type(val);
|
||||
if (LICENSE_TYPE_MAX == license->type_) {
|
||||
zlog_error(neuron, "invalid license type:`%s`", val);
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
}
|
||||
} else if (0 == strcmp(buf, LICENSE_KEY_MAX_NODES)) {
|
||||
license->max_nodes_ = strtoul(val, NULL, 0);
|
||||
} else if (0 == strcmp(buf, LICENSE_KEY_MAX_NODE_TAGS)) {
|
||||
license->max_node_tags_ = strtoul(val, NULL, 0);
|
||||
} else if (0 == strcmp(buf, LICENSE_KEY_PLUGIN_FLAG)) {
|
||||
if (0 !=
|
||||
scan_bitvec(license->plugin_flag_,
|
||||
sizeof(license->plugin_flag_), val)) {
|
||||
zlog_error(neuron, "fail to scan license plugin flag:`%s`",
|
||||
val);
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nlog_info("certification verification success");
|
||||
|
||||
final:
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
if (certbio)
|
||||
BIO_free_all(certbio);
|
||||
if (keybio)
|
||||
BIO_free_all(keybio);
|
||||
return rv;
|
||||
}
|
||||
|
||||
const char *license_type_str(license_type_e t)
|
||||
{
|
||||
return g_license_type_str_map_[t];
|
||||
}
|
||||
|
||||
const char *plugin_bit_str(plugin_bit_e b)
|
||||
{
|
||||
return g_plugin_bit_str_map[b];
|
||||
}
|
||||
|
||||
void license_print(license_t *license)
|
||||
{
|
||||
struct tm tm = {};
|
||||
char start[16] = {};
|
||||
char end[16] = {};
|
||||
time_t since = license->since_;
|
||||
time_t until = license->until_;
|
||||
const char *fmt = "%Y%m%dT%H%M%S";
|
||||
|
||||
gmtime_r(&since, &tm);
|
||||
strftime(start, sizeof(start), fmt, &tm);
|
||||
gmtime_r(&until, &tm);
|
||||
strftime(end, sizeof(end), fmt, &tm);
|
||||
|
||||
char flag[sizeof(license->plugin_flag_) * 2 + 1] = {};
|
||||
print_bitvec(flag, sizeof(flag), license->plugin_flag_,
|
||||
sizeof(license->plugin_flag_));
|
||||
|
||||
nlog_info("license `%s` for %s, from %s to %s, max_nodes:%" PRIu32
|
||||
", max_node_tags:%" PRIu32 ", flag:0x%s",
|
||||
license->fname_, license_type_str(license->type_), start, end,
|
||||
license->max_nodes_, license->max_node_tags_, flag);
|
||||
}
|
||||
|
||||
void license_init(license_t *license)
|
||||
{
|
||||
// no associate license file
|
||||
// no plugins enabled
|
||||
// expired license period
|
||||
memset(license, 0, sizeof(*license));
|
||||
license->since_ = 1;
|
||||
}
|
||||
|
||||
void license_fini(license_t *license)
|
||||
{
|
||||
free(license->fname_);
|
||||
}
|
||||
|
||||
license_t *license_new()
|
||||
{
|
||||
license_t *license = malloc(sizeof(*license));
|
||||
if (NULL == license) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
license_init(license);
|
||||
|
||||
return license;
|
||||
}
|
||||
|
||||
void license_free(license_t *license)
|
||||
{
|
||||
if (NULL == license) {
|
||||
return;
|
||||
}
|
||||
|
||||
license_fini(license);
|
||||
free(license);
|
||||
}
|
||||
|
||||
int license_read(license_t *license, const char *fname)
|
||||
{
|
||||
if (NULL == license || NULL == fname) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
license_t lic;
|
||||
license_init(&lic);
|
||||
|
||||
lic.fname_ = strdup(fname);
|
||||
if (NULL == lic.fname_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rv = extract_license(fname, root_cert_pub_key, &lic);
|
||||
if (0 != rv) {
|
||||
license_fini(&lic);
|
||||
return rv;
|
||||
}
|
||||
|
||||
license_print(&lic);
|
||||
|
||||
free(license->fname_);
|
||||
*license = lic;
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#ifndef LICENSE_H
|
||||
#define LICENSE_H
|
||||
|
||||
#define LICENSE_FNAME "neuron.lic"
|
||||
|
||||
// License type
|
||||
// Type: string
|
||||
// - "trial"
|
||||
// - "retail"
|
||||
// - "small-enterprise"
|
||||
#define LICENSE_KEY_TYPE "1.3.6.1.4.1.52509.10"
|
||||
|
||||
// Max number of nodes.
|
||||
// Type: integer, non-negative
|
||||
#define LICENSE_KEY_MAX_NODES "1.3.6.1.4.1.52509.11"
|
||||
|
||||
// Max number of tags per node.
|
||||
// Type: integer, non-negative
|
||||
#define LICENSE_KEY_MAX_NODE_TAGS "1.3.6.1.4.1.52509.12"
|
||||
|
||||
// Bit flag indicating which plugins are enabled.
|
||||
// Type: integer
|
||||
//
|
||||
// MSB LSB
|
||||
// ..., 63, 62, ... 3, 2, 1, 0
|
||||
// ^----many others--------------^ ^ ^ ^
|
||||
// | | |
|
||||
// opcua----------------------------+ | |
|
||||
// modbus_rtu--------------------------+ |
|
||||
// modbus_plus_tcp------------------------+
|
||||
//
|
||||
#define LICENSE_KEY_PLUGIN_FLAG "1.3.6.1.4.1.52509.13"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "errcodes.h"
|
||||
|
||||
typedef enum {
|
||||
LICENSE_TYPE_TRIAL = 0, // trial
|
||||
LICENSE_TYPE_RETAIL = 1, // retail
|
||||
LICENSE_TYPE_SME = 2, // small enterprise
|
||||
LICENSE_TYPE_MAX,
|
||||
} license_type_e;
|
||||
|
||||
const char *license_type_str(license_type_e t);
|
||||
|
||||
typedef enum {
|
||||
PLUGIN_BIT_MODBUS_PLUS_TCP = 0,
|
||||
PLUGIN_BIT_MODBUS_RTU = 1,
|
||||
PLUGIN_BIT_OPCUA = 2,
|
||||
PLUGIN_BIT_S7COMM = 3,
|
||||
PLUGIN_BIT_FINS = 4,
|
||||
PLUGIN_BIT_QNA3E = 5,
|
||||
PLUGIN_BIT_IEC60870_5_104 = 6,
|
||||
PLUGIN_BIT_KNX = 7,
|
||||
PLUGIN_BIT_NONA11 = 8,
|
||||
PLUGIN_BIT_DLT645_2007 = 9,
|
||||
PLUGIN_BIT_BACNET = 10,
|
||||
PLUGIN_BIT_MAX,
|
||||
} plugin_bit_e;
|
||||
|
||||
const char *plugin_bit_str(plugin_bit_e);
|
||||
|
||||
// Representing a single license.
|
||||
typedef struct {
|
||||
license_type_e type_; // license type
|
||||
char * fname_; // license file name
|
||||
uint64_t since_; // not before
|
||||
uint64_t until_; // not after
|
||||
uint32_t max_nodes_; // max number of nodes
|
||||
uint32_t max_node_tags_; // max number of tags per node
|
||||
uint8_t plugin_flag_[200 / 8]; // plugin enable/disable bits
|
||||
} license_t;
|
||||
|
||||
// Initialize to be expired with no file.
|
||||
void license_init(license_t *license);
|
||||
void license_fini(license_t *license);
|
||||
|
||||
// Create new expired license associated with no file.
|
||||
license_t *license_new();
|
||||
void license_free(license_t *license);
|
||||
// Read from license file.
|
||||
int license_read(license_t *license, const char *license_fname);
|
||||
|
||||
// Get associated license file name.
|
||||
static inline const char *license_get_file_name(const license_t *license)
|
||||
{
|
||||
return license->fname_;
|
||||
}
|
||||
|
||||
static inline license_type_e license_get_type(const license_t *license)
|
||||
{
|
||||
return license->type_;
|
||||
}
|
||||
|
||||
// Get license expiry date.
|
||||
static inline uint64_t license_not_before(const license_t *license)
|
||||
{
|
||||
return license->since_;
|
||||
}
|
||||
|
||||
// Get license expiry date.
|
||||
static inline uint64_t license_not_after(const license_t *license)
|
||||
{
|
||||
return license->until_;
|
||||
}
|
||||
|
||||
// Check if the license is expired according to the current time.
|
||||
static inline bool license_is_expired(const license_t *license)
|
||||
{
|
||||
uint64_t now = time(NULL);
|
||||
return now < license->since_ || license->until_ < now;
|
||||
}
|
||||
|
||||
static inline uint64_t license_get_max_nodes(const license_t *license)
|
||||
{
|
||||
return license->max_nodes_;
|
||||
}
|
||||
|
||||
static inline uint64_t license_get_max_node_tags(const license_t *license)
|
||||
{
|
||||
return license->max_node_tags_;
|
||||
}
|
||||
|
||||
static inline bool license_is_plugin_enabled(const license_t *license,
|
||||
plugin_bit_e bit)
|
||||
{
|
||||
return license->plugin_flag_[bit >> 3] & (1 << (bit & 0x07));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,356 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "argparse.h"
|
||||
#include "errcodes.h"
|
||||
#include "parser/neu_json_license.h"
|
||||
#include "plugin.h"
|
||||
#include "utils/asprintf.h"
|
||||
#include "utils/log.h"
|
||||
#include "json/neu_json_error.h"
|
||||
#include "json/neu_json_fn.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "http.h"
|
||||
#include "license.h"
|
||||
#include "license_handle.h"
|
||||
|
||||
static int set_license(const char *lic_str);
|
||||
int backup_license_file(const char *lic_fname);
|
||||
int get_plugin_names(const license_t *lic, UT_array *plugin_names);
|
||||
|
||||
static inline char *get_license_path()
|
||||
{
|
||||
char *s = NULL;
|
||||
neu_asprintf(&s, "persistence/%s", LICENSE_FNAME);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int copy_file(const char *from, const char *to)
|
||||
{
|
||||
int rv = 0;
|
||||
char * buf = NULL;
|
||||
FILE * fp = NULL;
|
||||
struct stat statbuf = {};
|
||||
|
||||
if (0 != stat(from, &statbuf)) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
buf = malloc(statbuf.st_size);
|
||||
if (NULL == buf) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
fp = fopen(from, "rb");
|
||||
if (NULL == fp) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((size_t) statbuf.st_size != fread(buf, 1, statbuf.st_size, fp)) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = fopen(to, "w");
|
||||
if (NULL == fp) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((size_t) statbuf.st_size != fwrite(buf, 1, statbuf.st_size, fp)) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
free(buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int copy_license_file_if_necessary()
|
||||
{
|
||||
struct stat statbuf = {};
|
||||
char * license_path = get_license_path();
|
||||
|
||||
if (NULL == license_path) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (0 == stat(license_path, &statbuf)) {
|
||||
free(license_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlog_warn("license `%s` not found", license_path);
|
||||
|
||||
char *fallback_path = NULL;
|
||||
neu_asprintf(&fallback_path, "%s/%s", g_config_dir, LICENSE_FNAME);
|
||||
if (NULL == fallback_path) {
|
||||
free(license_path);
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (0 != stat(fallback_path, &statbuf)) {
|
||||
// no fallback license file
|
||||
free(license_path);
|
||||
free(fallback_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlog_warn("fallback to `%s`", fallback_path);
|
||||
int rv = copy_file(fallback_path, license_path);
|
||||
|
||||
free(license_path);
|
||||
free(fallback_path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void handle_get_license(nng_aio *aio)
|
||||
{
|
||||
int rv = 0;
|
||||
char * license_path = NULL;
|
||||
license_t lic = {};
|
||||
neu_json_get_license_resp_t resp = {};
|
||||
time_t since = 0;
|
||||
time_t until = 0;
|
||||
char valid_since[20] = {};
|
||||
char valid_until[20] = {};
|
||||
struct tm tm = {};
|
||||
UT_array * plugin_names = NULL;
|
||||
char * result = NULL;
|
||||
|
||||
VALIDATE_JWT(aio);
|
||||
|
||||
utarray_new(plugin_names, &ut_ptr_icd);
|
||||
|
||||
license_path = get_license_path();
|
||||
if (NULL == license_path) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
license_init(&lic);
|
||||
rv = license_read(&lic, license_path);
|
||||
if (0 != rv) {
|
||||
goto final;
|
||||
}
|
||||
|
||||
since = license_not_before(&lic);
|
||||
gmtime_r(&since, &tm);
|
||||
if (0 ==
|
||||
strftime(valid_since, sizeof(valid_since), "%Y-%m-%d %H:%M:%S", &tm)) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
until = license_not_after(&lic);
|
||||
gmtime_r(&until, &tm);
|
||||
if (0 ==
|
||||
strftime(valid_until, sizeof(valid_until), "%Y-%m-%d %H:%M:%S", &tm)) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
resp.license_type = (char *) license_type_str(license_get_type(&lic));
|
||||
resp.valid = !license_is_expired(&lic);
|
||||
resp.valid_since = valid_since;
|
||||
resp.valid_until = valid_until;
|
||||
resp.max_nodes = license_get_max_nodes(&lic);
|
||||
resp.max_node_tags = license_get_max_node_tags(&lic);
|
||||
|
||||
rv = get_plugin_names(&lic, plugin_names);
|
||||
if (0 != rv) {
|
||||
goto final;
|
||||
}
|
||||
resp.n_enabled_plugin = utarray_len(plugin_names);
|
||||
resp.enabled_plugins =
|
||||
calloc(resp.n_enabled_plugin,
|
||||
sizeof(neu_json_get_license_resp_enabled_plugin_t));
|
||||
utarray_foreach(plugin_names, char **, p_name)
|
||||
{
|
||||
int index = utarray_eltidx(plugin_names, p_name);
|
||||
resp.enabled_plugins[index] = *p_name;
|
||||
}
|
||||
|
||||
final:
|
||||
if (0 == rv) {
|
||||
neu_json_encode_by_fn(&resp, neu_json_encode_get_license_resp, &result);
|
||||
} else {
|
||||
neu_json_error_resp_t error_code = { .error = rv };
|
||||
neu_json_encode_by_fn(&error_code, neu_json_encode_error_resp, &result);
|
||||
}
|
||||
http_response(aio, rv, result);
|
||||
free(result);
|
||||
license_fini(&lic);
|
||||
utarray_free(plugin_names);
|
||||
free(resp.enabled_plugins);
|
||||
free(license_path);
|
||||
}
|
||||
|
||||
void handle_set_license(nng_aio *aio)
|
||||
{
|
||||
REST_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_set_license_req_t, neu_json_decode_set_license_req, {
|
||||
NEU_JSON_RESPONSE_ERROR(set_license(req->license), {
|
||||
http_response(aio, error_code.error, result_error);
|
||||
});
|
||||
});
|
||||
}
|
||||
static inline bool file_exists(const char *const path)
|
||||
{
|
||||
struct stat buf = { 0 };
|
||||
return -1 != stat(path, &buf);
|
||||
}
|
||||
|
||||
static int set_license(const char *lic_str)
|
||||
{
|
||||
int rv = 0;
|
||||
size_t len = 0;
|
||||
char * license_path = NULL;
|
||||
char * fname_tmp = NULL;
|
||||
FILE * fp = NULL;
|
||||
license_t new_lic = {};
|
||||
|
||||
license_path = get_license_path();
|
||||
if (NULL == license_path) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (0 > neu_asprintf(&fname_tmp, "%s.tmp", license_path)) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
len = strlen(lic_str);
|
||||
if (len > 15000) {
|
||||
// the license file won't exceed 15KB
|
||||
rv = NEU_ERR_LICENSE_INVALID;
|
||||
goto final;
|
||||
}
|
||||
|
||||
fp = fopen(fname_tmp, "w");
|
||||
if (NULL == fp) {
|
||||
nlog_error("unable to create license tmp file `%s`", fname_tmp);
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
rv = fputs(lic_str, fp);
|
||||
|
||||
if (rv < 0) {
|
||||
nlog_error("unable to write license to file `%s`", fname_tmp);
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
fflush(fp);
|
||||
|
||||
license_init(&new_lic);
|
||||
rv = license_read(&new_lic, fname_tmp);
|
||||
license_fini(&new_lic);
|
||||
if (0 != rv) {
|
||||
nlog_error("bad license string");
|
||||
goto final;
|
||||
}
|
||||
|
||||
if (license_is_expired(&new_lic)) {
|
||||
nlog_error("expired license string");
|
||||
rv = NEU_ERR_LICENSE_EXPIRED;
|
||||
goto final;
|
||||
}
|
||||
|
||||
if (file_exists(license_path) && 0 > backup_license_file(license_path)) {
|
||||
nlog_error("unable to backup license file `%s`", license_path);
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
if (0 > rename(fname_tmp, license_path)) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto final;
|
||||
}
|
||||
|
||||
neu_plugin_t * plugin = neu_rest_get_plugin();
|
||||
neu_reqresp_head_t head = { .type = NEU_REQ_UPDATE_LICENSE };
|
||||
rv = neu_plugin_op(plugin, head, NULL);
|
||||
if (0 != rv) {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
final:
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
remove(fname_tmp);
|
||||
free(license_path);
|
||||
free(fname_tmp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int backup_license_file(const char *lic_fname)
|
||||
{
|
||||
struct tm tm = { .tm_isdst = -1 };
|
||||
time_t now = time(NULL);
|
||||
const char *suffix = ".bak";
|
||||
size_t len =
|
||||
strlen(lic_fname) + strlen(suffix) + 15 + 1; // 15 for timestamp
|
||||
char *fname_bak = malloc(len);
|
||||
|
||||
if (NULL == fname_bak) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
size_t n = snprintf(fname_bak, len, "%s%s", lic_fname, suffix);
|
||||
|
||||
gmtime_r(&now, &tm);
|
||||
if (0 == strftime(fname_bak + n, len - n, ".%Y%m%d%H%M%S", &tm)) {
|
||||
free(fname_bak);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rv = link(lic_fname, fname_bak);
|
||||
free(fname_bak);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int get_plugin_names(const license_t *lic, UT_array *plugin_names)
|
||||
{
|
||||
for (plugin_bit_e b = PLUGIN_BIT_MODBUS_PLUS_TCP; b < PLUGIN_BIT_MAX; ++b) {
|
||||
if (license_is_plugin_enabled(lic, b)) {
|
||||
const char *s = plugin_bit_str(b);
|
||||
if (NULL == s) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
utarray_push_back(plugin_names, &s);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#ifndef _NEU_LICENSE_HANDLE_H_
|
||||
#define _NEU_LICENSE_HANDLE_H_
|
||||
|
||||
#include <nng/nng.h>
|
||||
|
||||
int copy_license_file_if_necessary();
|
||||
void handle_get_license(nng_aio *aio);
|
||||
void handle_set_license(nng_aio *aio);
|
||||
|
||||
#endif
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "group_config_handle.h"
|
||||
#include "handle.h"
|
||||
#include "http.h"
|
||||
#include "license_handle.h"
|
||||
#include "plugin_handle.h"
|
||||
#include "proxy.h"
|
||||
#include "rest.h"
|
||||
@@ -146,12 +145,6 @@ static neu_plugin_t *dashb_plugin_open(void)
|
||||
const struct neu_rest_handler *rest_handlers = NULL;
|
||||
const struct neu_rest_handler *cors = NULL;
|
||||
|
||||
// copy license file for backward compatibility
|
||||
if (0 != copy_license_file_if_necessary()) {
|
||||
free(plugin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
neu_plugin_common_init(&plugin->common);
|
||||
|
||||
plugin->handle_ctx = neu_rest_init_ctx(plugin);
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
/*
|
||||
* DO NOT EDIT THIS FILE MANUALLY!
|
||||
* It was automatically generated by `json-autotype`.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "json/json.h"
|
||||
|
||||
#include "neu_json_license.h"
|
||||
|
||||
int neu_json_encode_get_license_resp(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
neu_json_get_license_resp_t *resp = (neu_json_get_license_resp_t *) param;
|
||||
|
||||
void *enabled_plugin_array = neu_json_array();
|
||||
neu_json_get_license_resp_enabled_plugin_t *p_enabled_plugin =
|
||||
resp->enabled_plugins;
|
||||
for (int i = 0; i < resp->n_enabled_plugin; i++) {
|
||||
neu_json_elem_t enabled_plugin_elems[] = { {
|
||||
.name = NULL,
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = *p_enabled_plugin,
|
||||
} };
|
||||
enabled_plugin_array = neu_json_encode_array_value(
|
||||
enabled_plugin_array, enabled_plugin_elems,
|
||||
NEU_JSON_ELEM_SIZE(enabled_plugin_elems));
|
||||
p_enabled_plugin++;
|
||||
}
|
||||
|
||||
neu_json_elem_t resp_elems[] = { {
|
||||
.name = "valid_until",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = resp->valid_until,
|
||||
},
|
||||
{
|
||||
.name = "valid_since",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = resp->valid_since,
|
||||
},
|
||||
{
|
||||
.name = "valid",
|
||||
.t = NEU_JSON_BOOL,
|
||||
.v.val_bool = resp->valid,
|
||||
},
|
||||
{
|
||||
.name = "max_nodes",
|
||||
.t = NEU_JSON_INT,
|
||||
.v.val_int = resp->max_nodes,
|
||||
},
|
||||
{
|
||||
.name = "max_node_tags",
|
||||
.t = NEU_JSON_INT,
|
||||
.v.val_int = resp->max_node_tags,
|
||||
},
|
||||
{
|
||||
.name = "license_type",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = resp->license_type,
|
||||
},
|
||||
{
|
||||
.name = "error",
|
||||
.t = NEU_JSON_INT,
|
||||
.v.val_int = resp->error,
|
||||
},
|
||||
{
|
||||
.name = "enabled_plugins",
|
||||
.t = NEU_JSON_OBJECT,
|
||||
.v.val_object = enabled_plugin_array,
|
||||
} };
|
||||
ret = neu_json_encode_field(json_object, resp_elems,
|
||||
NEU_JSON_ELEM_SIZE(resp_elems));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int neu_json_decode_set_license_req(char * buf,
|
||||
neu_json_set_license_req_t **result)
|
||||
{
|
||||
int ret = 0;
|
||||
neu_json_set_license_req_t *req =
|
||||
calloc(1, sizeof(neu_json_set_license_req_t));
|
||||
if (NULL == req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = { {
|
||||
.name = "license",
|
||||
.t = NEU_JSON_STR,
|
||||
} };
|
||||
ret = neu_json_decode(buf, NEU_JSON_ELEM_SIZE(req_elems), req_elems);
|
||||
if (ret != 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
req->license = req_elems[0].v.val_str;
|
||||
|
||||
*result = req;
|
||||
return ret;
|
||||
|
||||
decode_fail:
|
||||
free(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void neu_json_decode_set_license_req_free(neu_json_set_license_req_t *req)
|
||||
{
|
||||
|
||||
free(req->license);
|
||||
|
||||
free(req);
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
/*
|
||||
* DO NOT EDIT THIS FILE MANUALLY!
|
||||
* It was automatically generated by `json-autotype`.
|
||||
*/
|
||||
|
||||
#ifndef _NEU_JSON_API_NEU_JSON_LICENSE_H_
|
||||
#define _NEU_JSON_API_NEU_JSON_LICENSE_H_
|
||||
|
||||
#include "json/json.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef char *neu_json_get_license_resp_enabled_plugin_t;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
int n_enabled_plugin;
|
||||
neu_json_get_license_resp_enabled_plugin_t *enabled_plugins;
|
||||
int64_t max_node_tags;
|
||||
char * license_type;
|
||||
int64_t error;
|
||||
char * valid_until;
|
||||
char * valid_since;
|
||||
int64_t max_nodes;
|
||||
} neu_json_get_license_resp_t;
|
||||
|
||||
int neu_json_encode_get_license_resp(void *json_object, void *param);
|
||||
|
||||
typedef struct {
|
||||
char *license;
|
||||
} neu_json_set_license_req_t;
|
||||
|
||||
int neu_json_decode_set_license_req(char * buf,
|
||||
neu_json_set_license_req_t **result);
|
||||
void neu_json_decode_set_license_req_free(neu_json_set_license_req_t *req);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user