mirror of
https://github.com/Motion-Project/motion.git
synced 2026-02-07 13:31:38 -05:00
552 lines
16 KiB
C++
552 lines
16 KiB
C++
/*
|
|
* This file is part of MotionPlus.
|
|
*
|
|
* MotionPlus is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MotionPlus 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MotionPlus. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "motionplus.hpp"
|
|
#include "camera.hpp"
|
|
#include "conf.hpp"
|
|
#include "logger.hpp"
|
|
#include "util.hpp"
|
|
#include "webu.hpp"
|
|
#include "webu_ans.hpp"
|
|
#include "webu_html.hpp"
|
|
#include "webu_json.hpp"
|
|
#include "webu_post.hpp"
|
|
#include "webu_file.hpp"
|
|
#include "webu_common.hpp"
|
|
#include "webu_stream.hpp"
|
|
#include "webu_mpegts.hpp"
|
|
#include "video_v4l2.hpp"
|
|
|
|
/* Initialize the MHD answer */
|
|
static void *webu_mhd_init(void *cls, const char *uri, struct MHD_Connection *connection)
|
|
{
|
|
(void)connection;
|
|
ctx_motapp *p_app =(ctx_motapp *)cls;
|
|
cls_webu_ans *webua;
|
|
|
|
mythreadname_set("wc", 0, NULL);
|
|
|
|
webua = new cls_webu_ans(p_app, uri);
|
|
|
|
return webua;
|
|
}
|
|
|
|
/* Clean up our variables when the MHD connection closes */
|
|
static void webu_mhd_deinit(void *cls, struct MHD_Connection *connection
|
|
, void **con_cls, enum MHD_RequestTerminationCode toe)
|
|
{
|
|
(void)connection;
|
|
(void)cls;
|
|
(void)toe;
|
|
cls_webu_ans *webua =(cls_webu_ans *) *con_cls;
|
|
|
|
if (webua != nullptr) {
|
|
if (webua->req_file != nullptr) {
|
|
myfclose(webua->req_file);
|
|
webua->req_file = nullptr;
|
|
}
|
|
delete webua;
|
|
webua = nullptr;
|
|
}
|
|
}
|
|
|
|
/* Answer the connection request for the webcontrol*/
|
|
static mhdrslt mhd_answer(void *cls
|
|
, struct MHD_Connection *connection
|
|
, const char *url, const char *method, const char *version
|
|
, const char *upload_data, size_t *upload_data_size
|
|
, void **ptr)
|
|
{
|
|
(void)cls;
|
|
(void)url;
|
|
(void)version;
|
|
|
|
cls_webu_ans *webua =(cls_webu_ans *) *ptr;
|
|
|
|
return webua->answer_main(connection, method, upload_data, upload_data_size);
|
|
}
|
|
|
|
/* Validate that the MHD version installed can process basic authentication */
|
|
void cls_webu::mhd_features_basic()
|
|
{
|
|
#if MHD_VERSION < 0x00094400
|
|
(void)mhdst;
|
|
#else
|
|
mhdrslt retcd;
|
|
retcd = MHD_is_feature_supported (MHD_FEATURE_BASIC_AUTH);
|
|
if (retcd == MHD_YES) {
|
|
MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,_("Basic authentication: available"));
|
|
} else {
|
|
if (app->cfg->webcontrol_auth_method == "basic") {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Basic authentication: disabled"));
|
|
app->cfg->webcontrol_auth_method = "none";
|
|
} else {
|
|
MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("Basic authentication: disabled"));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Validate that the MHD version installed can process digest authentication */
|
|
void cls_webu::mhd_features_digest()
|
|
{
|
|
#if MHD_VERSION < 0x00094400
|
|
(void)mhdst;
|
|
#else
|
|
mhdrslt retcd;
|
|
retcd = MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH);
|
|
if (retcd == MHD_YES) {
|
|
MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,_("Digest authentication: available"));
|
|
} else {
|
|
if (app->cfg->webcontrol_auth_method == "digest") {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Digest authentication: disabled"));
|
|
app->cfg->webcontrol_auth_method = "none";
|
|
} else {
|
|
MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("Digest authentication: disabled"));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Validate that the MHD version installed can process IPV6 */
|
|
void cls_webu::mhd_features_ipv6()
|
|
{
|
|
#if MHD_VERSION < 0x00094400
|
|
if (mhdst->ipv6) {
|
|
MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("libmicrohttpd libary too old ipv6 disabled"));
|
|
if (mhdst->ipv6) {
|
|
mhdst->ipv6 = 0;
|
|
}
|
|
}
|
|
#else
|
|
mhdrslt retcd;
|
|
retcd = MHD_is_feature_supported (MHD_FEATURE_IPv6);
|
|
if (retcd == MHD_YES) {
|
|
MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,_("IPV6: available"));
|
|
} else {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("IPV6: disabled"));
|
|
if (mhdst->ipv6) {
|
|
mhdst->ipv6 = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Validate that the MHD version installed can process tls */
|
|
void cls_webu::mhd_features_tls()
|
|
{
|
|
#if MHD_VERSION < 0x00094400
|
|
if (mhdst->tls_use) {
|
|
MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("libmicrohttpd libary too old SSL/TLS disabled"));
|
|
mhdst->tls_use = false;
|
|
}
|
|
#else
|
|
mhdrslt retcd;
|
|
retcd = MHD_is_feature_supported (MHD_FEATURE_SSL);
|
|
if (retcd == MHD_YES) {
|
|
MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,_("SSL/TLS: available"));
|
|
} else {
|
|
if (mhdst->tls_use) {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("SSL/TLS: disabled"));
|
|
mhdst->tls_use = false;
|
|
} else {
|
|
MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("SSL/TLS: disabled"));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Validate the features that MHD can support */
|
|
void cls_webu::mhd_features()
|
|
{
|
|
mhd_features_basic();
|
|
mhd_features_digest();
|
|
mhd_features_ipv6();
|
|
mhd_features_tls();
|
|
}
|
|
|
|
/* Load a either the key or cert file for MHD*/
|
|
void cls_webu::mhd_loadfile(std::string fname,std::string &filestr)
|
|
{
|
|
/* This needs conversion to c++ stream */
|
|
FILE *infile;
|
|
size_t read_size, file_size;
|
|
long retcd;
|
|
char *file_char;
|
|
|
|
filestr = "";
|
|
if (fname != "") {
|
|
infile = myfopen(fname.c_str() , "rbe");
|
|
if (infile != NULL) {
|
|
fseek(infile, 0, SEEK_END);
|
|
retcd = ftell(infile);
|
|
if (retcd > 0 ) {
|
|
file_size = (size_t)retcd;
|
|
file_char = (char*)mymalloc(file_size +1);
|
|
fseek(infile, 0, SEEK_SET);
|
|
read_size = fread(file_char, file_size, 1, infile);
|
|
if (read_size > 0 ) {
|
|
file_char[file_size] = 0;
|
|
filestr.assign(file_char, file_size);
|
|
} else {
|
|
MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO
|
|
,_("Error reading file for SSL/TLS support."));
|
|
}
|
|
free(file_char);
|
|
}
|
|
myfclose(infile);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Validate that we have the files needed for tls*/
|
|
void cls_webu::mhd_checktls()
|
|
{
|
|
if (mhdst->tls_use) {
|
|
if ((app->cfg->webcontrol_cert == "") || (mhdst->tls_cert == "")) {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
,_("SSL/TLS requested but no cert file provided. SSL/TLS disabled"));
|
|
mhdst->tls_use = false;
|
|
}
|
|
if ((app->cfg->webcontrol_key == "") || (mhdst->tls_key == "")) {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
,_("SSL/TLS requested but no key file provided. SSL/TLS disabled"));
|
|
mhdst->tls_use = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the initialization function for MHD to call upon getting a connection */
|
|
void cls_webu::mhd_opts_init()
|
|
{
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_URI_LOG_CALLBACK;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = (intptr_t)webu_mhd_init;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = app;
|
|
mhdst->mhd_opt_nbr++;
|
|
}
|
|
|
|
/* Set the MHD option on the function to call when the connection closes */
|
|
void cls_webu::mhd_opts_deinit()
|
|
{
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_NOTIFY_COMPLETED;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = (intptr_t)webu_mhd_deinit;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = NULL;
|
|
mhdst->mhd_opt_nbr++;
|
|
|
|
}
|
|
|
|
/* Set the MHD option on acceptable connections */
|
|
void cls_webu::mhd_opts_localhost()
|
|
{
|
|
if (app->cfg->webcontrol_localhost) {
|
|
if (mhdst->ipv6) {
|
|
memset(&mhdst->lpbk_ipv6, 0, sizeof(struct sockaddr_in6));
|
|
mhdst->lpbk_ipv6.sin6_family = AF_INET6;
|
|
mhdst->lpbk_ipv6.sin6_port = htons((uint16_t)app->cfg->webcontrol_port);
|
|
mhdst->lpbk_ipv6.sin6_addr = in6addr_loopback;
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_SOCK_ADDR;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 0;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = (struct sosockaddr *)(&mhdst->lpbk_ipv6);
|
|
mhdst->mhd_opt_nbr++;
|
|
|
|
} else {
|
|
memset(&mhdst->lpbk_ipv4, 0, sizeof(struct sockaddr_in));
|
|
mhdst->lpbk_ipv4.sin_family = AF_INET;
|
|
mhdst->lpbk_ipv4.sin_port = htons((uint16_t)app->cfg->webcontrol_port);
|
|
mhdst->lpbk_ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_SOCK_ADDR;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 0;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = (struct sockaddr *)(&mhdst->lpbk_ipv4);
|
|
mhdst->mhd_opt_nbr++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the mhd digest options */
|
|
void cls_webu::mhd_opts_digest()
|
|
{
|
|
if (app->cfg->webcontrol_auth_method == "digest") {
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_DIGEST_AUTH_RANDOM;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = sizeof(wb_digest_rand);
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = wb_digest_rand;
|
|
mhdst->mhd_opt_nbr++;
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_NONCE_NC_SIZE;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 300;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = NULL;
|
|
mhdst->mhd_opt_nbr++;
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_CONNECTION_TIMEOUT;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = (unsigned int) 120;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = NULL;
|
|
mhdst->mhd_opt_nbr++;
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the MHD options needed when we want TLS connections */
|
|
void cls_webu::mhd_opts_tls()
|
|
{
|
|
if (mhdst->tls_use) {
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_HTTPS_MEM_CERT;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 0;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = (void *)mhdst->tls_cert.c_str();
|
|
mhdst->mhd_opt_nbr++;
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_HTTPS_MEM_KEY;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 0;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = (void *)mhdst->tls_key.c_str();
|
|
mhdst->mhd_opt_nbr++;
|
|
}
|
|
|
|
}
|
|
|
|
/* Set all the MHD options based upon the configuration parameters*/
|
|
void cls_webu::mhd_opts()
|
|
{
|
|
mhdst->mhd_opt_nbr = 0;
|
|
|
|
mhd_checktls();
|
|
mhd_opts_deinit();
|
|
mhd_opts_init();
|
|
mhd_opts_localhost();
|
|
mhd_opts_digest();
|
|
mhd_opts_tls();
|
|
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_END;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 0;
|
|
mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = NULL;
|
|
mhdst->mhd_opt_nbr++;
|
|
|
|
}
|
|
|
|
/* Set the mhd start up flags */
|
|
void cls_webu::mhd_flags()
|
|
{
|
|
mhdst->mhd_flags = MHD_USE_THREAD_PER_CONNECTION;
|
|
|
|
if (mhdst->ipv6) {
|
|
mhdst->mhd_flags = mhdst->mhd_flags | MHD_USE_DUAL_STACK;
|
|
}
|
|
|
|
if (mhdst->tls_use) {
|
|
mhdst->mhd_flags = mhdst->mhd_flags | MHD_USE_SSL;
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the values for the action commands */
|
|
void cls_webu::init_actions()
|
|
{
|
|
std::string parm_vl;
|
|
|
|
wb_actions = new ctx_params;
|
|
wb_actions->update_params = true;
|
|
util_parms_parse(wb_actions
|
|
,"webcontrol_actions", app->cfg->webcontrol_actions);
|
|
|
|
if (app->cfg->webcontrol_parms == 0) {
|
|
parm_vl = "off";
|
|
} else {
|
|
parm_vl = "on";
|
|
}
|
|
|
|
util_parms_add_default(wb_actions,"event",parm_vl);
|
|
util_parms_add_default(wb_actions,"snapshot",parm_vl);
|
|
util_parms_add_default(wb_actions,"pause",parm_vl);
|
|
util_parms_add_default(wb_actions,"restart",parm_vl);
|
|
util_parms_add_default(wb_actions,"stop",parm_vl);
|
|
util_parms_add_default(wb_actions,"config_write",parm_vl);
|
|
util_parms_add_default(wb_actions,"camera_add",parm_vl);
|
|
util_parms_add_default(wb_actions,"camera_delete",parm_vl);
|
|
util_parms_add_default(wb_actions,"config",parm_vl);
|
|
util_parms_add_default(wb_actions,"ptz",parm_vl);
|
|
util_parms_add_default(wb_actions,"movies","on");
|
|
util_parms_add_default(wb_actions,"action_user",parm_vl);
|
|
}
|
|
|
|
void cls_webu::start_daemon_port1()
|
|
{
|
|
mhdst = new ctx_mhdstart;
|
|
|
|
mhd_loadfile(app->cfg->webcontrol_cert, mhdst->tls_cert);
|
|
mhd_loadfile(app->cfg->webcontrol_key, mhdst->tls_key);
|
|
mhdst->ipv6 = app->cfg->webcontrol_ipv6;
|
|
mhdst->tls_use = app->cfg->webcontrol_tls;
|
|
|
|
mhdst->mhd_ops =(struct MHD_OptionItem*)mymalloc(sizeof(struct MHD_OptionItem) * WEBUI_MHD_OPTS);
|
|
mhd_features();
|
|
mhd_opts();
|
|
mhd_flags();
|
|
|
|
wb_daemon = MHD_start_daemon (
|
|
mhdst->mhd_flags
|
|
, (uint16_t)app->cfg->webcontrol_port
|
|
, NULL, NULL
|
|
, &mhd_answer, app
|
|
, MHD_OPTION_ARRAY, mhdst->mhd_ops
|
|
, MHD_OPTION_END);
|
|
|
|
free(mhdst->mhd_ops);
|
|
if (wb_daemon == nullptr) {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Unable to start MHD"));
|
|
} else {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
,_("Started webcontrol on port %d")
|
|
,app->cfg->webcontrol_port);
|
|
}
|
|
delete mhdst;
|
|
mhdst = nullptr;
|
|
}
|
|
|
|
void cls_webu::start_daemon_port2()
|
|
{
|
|
if ((app->cfg->webcontrol_port2 == 0 ) ||
|
|
(app->cfg->webcontrol_port2 == app->cfg->webcontrol_port)) {
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
, _("Starting secondary webcontrol on port %d")
|
|
, app->cfg->webcontrol_port2);
|
|
|
|
mhdst = new ctx_mhdstart;
|
|
|
|
mhd_loadfile(app->cfg->webcontrol_cert, mhdst->tls_cert);
|
|
mhd_loadfile(app->cfg->webcontrol_key, mhdst->tls_key);
|
|
mhdst->ipv6 = app->cfg->webcontrol_ipv6;
|
|
mhdst->tls_use = false;
|
|
|
|
if (app->cfg->webcontrol_tls) {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
, _("TLS will be disabled on webcontrol port %d")
|
|
, app->cfg->webcontrol_port2);
|
|
}
|
|
|
|
mhdst->mhd_ops =(struct MHD_OptionItem*)mymalloc(sizeof(struct MHD_OptionItem)*WEBUI_MHD_OPTS);
|
|
mhd_opts();
|
|
mhd_flags();
|
|
|
|
wb_daemon2 = MHD_start_daemon (
|
|
mhdst->mhd_flags
|
|
, (uint16_t)app->cfg->webcontrol_port2
|
|
, NULL, NULL
|
|
, &mhd_answer, app
|
|
, MHD_OPTION_ARRAY, mhdst->mhd_ops
|
|
, MHD_OPTION_END);
|
|
|
|
free(mhdst->mhd_ops);
|
|
if (wb_daemon2 == nullptr) {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Unable to start port2 MHD"));
|
|
} else {
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
,_("Started webcontrol on port %d")
|
|
,app->cfg->webcontrol_port2);
|
|
}
|
|
|
|
delete mhdst;
|
|
mhdst = nullptr;
|
|
|
|
}
|
|
|
|
void cls_webu::webu_start()
|
|
{
|
|
unsigned int randnbr;
|
|
wb_daemon = nullptr;
|
|
wb_daemon2 = nullptr;
|
|
wb_finish = false;
|
|
wb_clients.clear();
|
|
|
|
memset(wb_digest_rand, 0, sizeof(wb_digest_rand));
|
|
|
|
if (app->cfg->webcontrol_port == 0 ) {
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO
|
|
, _("Starting webcontrol on port %d")
|
|
, app->cfg->webcontrol_port);
|
|
|
|
wb_headers = new ctx_params;
|
|
wb_headers->update_params = true;
|
|
util_parms_parse(wb_headers
|
|
, "webcontrol_headers", app->cfg->webcontrol_headers);
|
|
|
|
init_actions();
|
|
|
|
srand((unsigned int)time(NULL));
|
|
randnbr = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0));
|
|
snprintf(wb_digest_rand, sizeof(wb_digest_rand),"%d",randnbr);
|
|
|
|
start_daemon_port1();
|
|
|
|
start_daemon_port2();
|
|
cnct_cnt = 0;
|
|
|
|
}
|
|
|
|
void cls_webu::webu_stop()
|
|
{
|
|
int chkcnt;
|
|
|
|
wb_finish = true;
|
|
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Closing webcontrol"));
|
|
|
|
chkcnt = 0;
|
|
while ((chkcnt < 1000) && (cnct_cnt >0)) {
|
|
SLEEP(0, 5000000);
|
|
chkcnt++;
|
|
}
|
|
|
|
if (chkcnt>=1000){
|
|
MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Excessive wait closing webcontrol"));
|
|
}
|
|
|
|
if (wb_daemon != nullptr) {
|
|
MHD_stop_daemon (wb_daemon);
|
|
wb_daemon = nullptr;
|
|
}
|
|
|
|
if (wb_daemon2 != nullptr) {
|
|
MHD_stop_daemon (wb_daemon2);
|
|
wb_daemon2 = nullptr;
|
|
}
|
|
|
|
delete wb_actions;
|
|
delete wb_headers;
|
|
|
|
}
|
|
|
|
cls_webu::cls_webu(ctx_motapp *p_app)
|
|
{
|
|
app = p_app;
|
|
webu_start();
|
|
}
|
|
|
|
cls_webu::~cls_webu()
|
|
{
|
|
webu_stop();
|
|
}
|