Skip to content

Commit

Permalink
Merge PR #572
Browse files Browse the repository at this point in the history
  • Loading branch information
sm0svx committed Mar 30, 2024
2 parents b89ffa9 + 08ea2f3 commit 5636dff
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 5 deletions.
18 changes: 17 additions & 1 deletion src/async/core/AsyncPty.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
\verbatim
Async - A library for programming event driven applications
Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2024 Tobias Blomberg / SM0SVX
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -180,6 +180,22 @@ class Pty : public sigc::trackable
*/
ssize_t write(const void *buf, size_t count);

/**
* @brief Write a string to the PTY
* @param str A string to write
* @return On success, the number of bytes written is returned (zero
* indicates nothing was written). On error, -1 is returned,
* and errno is set appropriately.
*
* Use this function to write a string to the PTY. If the slave end of the
* PTY is not open, the written string will just be discarded and the
* string length is used as the return value.
*/
ssize_t write(const std::string& str)
{
return write(str.c_str(), str.size());
}

/**
* @brief Check if the PTY is open or not
* @return Returns \em true if the PTY has been successfully opened
Expand Down
10 changes: 10 additions & 0 deletions src/doc/man/svxreflector.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@ the risk of some client overwhelming the reflector with requests causing
disturbances in the reflector operation.

Example: HTTP_SRV_PORT=8080
.TP
.B COMMAND_PTY
Configure a path for a pseudo tty device to send runtime commands to the
svxreflector. The device may be defined as COMMAND_PTY=/dev/shm/reflector_ctrl.
To change the value of a configuration variable you may send a command to the
device like this:

echo "CFG section varname value" > /dev/shm/reflector_ctrl
e.g.
echo "CFG GLOBAL SQL_TIMEOUT_BLOCKTIME 60" > /dev/shm/reflector_ctrl
.
.SS USERS and PASSWORDS sections
.
Expand Down
110 changes: 108 additions & 2 deletions src/svxlink/reflector/Reflector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
\verbatim
SvxReflector - An audio reflector for connecting SvxLink Servers
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2024 Tobias Blomberg / SM0SVX
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -44,6 +44,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <AsyncTcpServer.h>
#include <AsyncUdpSocket.h>
#include <AsyncApplication.h>
#include <AsyncPty.h>
#include <common.h>


Expand Down Expand Up @@ -123,7 +124,7 @@ namespace {

Reflector::Reflector(void)
: m_srv(0), m_udp_sock(0), m_tg_for_v1_clients(1), m_random_qsy_lo(0),
m_random_qsy_hi(0), m_random_qsy_tg(0), m_http_server(0)
m_random_qsy_hi(0), m_random_qsy_tg(0), m_http_server(0), m_cmd_pty(0)
{
TGHandler::instance()->talkerUpdated.connect(
mem_fun(*this, &Reflector::onTalkerUpdated));
Expand All @@ -140,6 +141,8 @@ Reflector::~Reflector(void)
m_udp_sock = 0;
delete m_srv;
m_srv = 0;
delete m_cmd_pty;
m_cmd_pty = 0;
m_client_con_map.clear();
ReflectorClient::cleanup();
delete TGHandler::instance();
Expand Down Expand Up @@ -226,6 +229,26 @@ bool Reflector::initialize(Async::Config &cfg)
sigc::mem_fun(*this, &Reflector::httpClientDisconnected));
}

// Path for command PTY
string pty_path;
m_cfg->getValue("GLOBAL", "COMMAND_PTY", pty_path);
if (!pty_path.empty())
{
m_cmd_pty = new Pty(pty_path);
if ((m_cmd_pty == nullptr) || !m_cmd_pty->open())
{
std::cerr << "*** ERROR: Could not open command PTY '" << pty_path
<< "' as specified in configuration variable "
"GLOBAL/COMMAND_PTY" << std::endl;
return false;
}
m_cmd_pty->setLineBuffered(true);
m_cmd_pty->dataReceived.connect(
mem_fun(*this, &Reflector::ctrlPtyDataReceived));
}

m_cfg->valueUpdated.connect(sigc::mem_fun(*this, &Reflector::cfgUpdated));

return true;
} /* Reflector::initialize */

Expand Down Expand Up @@ -783,6 +806,89 @@ uint32_t Reflector::nextRandomQsyTg(void)
} /* Reflector::nextRandomQsyTg */


void Reflector::ctrlPtyDataReceived(const void *buf, size_t count)
{
const char* ptr = reinterpret_cast<const char*>(buf);
const std::string cmdline(ptr, ptr + count);
//std::cout << "### Reflector::ctrlPtyDataReceived: " << cmdline
// << std::endl;
std::istringstream ss(cmdline);
std::ostringstream errss;
std::string cmd;
if (!(ss >> cmd))
{
errss << "Invalid PTY command '" << cmdline << "'";
goto write_status;
}

if (cmd == "CFG")
{
std::string section, tag, value;
if (!(ss >> section >> tag >> value) || !ss.eof())
{
errss << "Invalid PTY command '" << cmdline << "'. "
"Usage: CFG <section> <tag> <value>";
goto write_status;
}
m_cfg->setValue(section, tag, value);
}
else
{
errss << "Unknown PTY command '" << cmdline
<< "'. Valid commands are: CFG";
}

write_status:
if (!errss.str().empty())
{
std::cerr << "*** ERROR: " << errss.str() << std::endl;
m_cmd_pty->write(std::string("ERR:") + errss.str() + "\n");
return;
}
m_cmd_pty->write("OK\n");
} /* Reflector::ctrlPtyDataReceived */


void Reflector::cfgUpdated(const std::string& section, const std::string& tag)
{
std::string value;
if (!m_cfg->getValue(section, tag, value))
{
std::cout << "*** ERROR: Failed to read updated configuration variable '"
<< section << "/" << tag << "'" << std::endl;
return;
}

if (section == "GLOBAL")
{
if (tag == "SQL_TIMEOUT_BLOCKTIME")
{
unsigned t = TGHandler::instance()->sqlTimeoutBlocktime();
if (!SvxLink::setValueFromString(t, value))
{
std::cout << "*** ERROR: Failed to set updated configuration "
"variable '" << section << "/" << tag << "'" << std::endl;
return;
}
TGHandler::instance()->setSqlTimeoutBlocktime(t);
//std::cout << "### New value for " << tag << "=" << t << std::endl;
}
else if (tag == "SQL_TIMEOUT")
{
unsigned t = TGHandler::instance()->sqlTimeout();
if (!SvxLink::setValueFromString(t, value))
{
std::cout << "*** ERROR: Failed to set updated configuration "
"variable '" << section << "/" << tag << "'" << std::endl;
return;
}
TGHandler::instance()->setSqlTimeout(t);
//std::cout << "### New value for " << tag << "=" << t << std::endl;
}
}
} /* Reflector::cfgUpdated */


/*
* This file has not been truncated
*/
Expand Down
6 changes: 5 additions & 1 deletion src/svxlink/reflector/Reflector.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
\verbatim
SvxReflector - An audio reflector for connecting SvxLink Servers
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2024 Tobias Blomberg / SM0SVX
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -72,6 +72,7 @@ namespace Async
{
class UdpSocket;
class Config;
class Pty;
};

class ReflectorMsg;
Expand Down Expand Up @@ -198,6 +199,7 @@ class Reflector : public sigc::trackable
uint32_t m_random_qsy_hi;
uint32_t m_random_qsy_tg;
Async::TcpServer<Async::HttpServerConnection>* m_http_server;
Async::Pty* m_cmd_pty;

Reflector(const Reflector&);
Reflector& operator=(const Reflector&);
Expand All @@ -215,6 +217,8 @@ class Reflector : public sigc::trackable
Async::HttpServerConnection::DisconnectReason reason);
void onRequestAutoQsy(uint32_t from_tg);
uint32_t nextRandomQsyTg(void);
void ctrlPtyDataReceived(const void *buf, size_t count);
void cfgUpdated(const std::string& section, const std::string& tag);

}; /* class Reflector */

Expand Down
7 changes: 6 additions & 1 deletion src/svxlink/reflector/TGHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
\verbatim
SvxReflector - An audio reflector for connecting SvxLink Servers
Copyright (C) 2003-2021 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2024 Tobias Blomberg / SM0SVX
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -142,8 +142,13 @@ class TGHandler : public sigc::trackable
*/
void setConfig(const Async::Config* cfg) { m_cfg = cfg; }

unsigned sqlTimeout(void) const { return m_sql_timeout; }
void setSqlTimeout(unsigned sql_timeout) { m_sql_timeout = sql_timeout; }

unsigned sqlTimeoutBlocktime(void) const
{
return m_sql_timeout_blocktime;
}
void setSqlTimeoutBlocktime(unsigned sql_timeout_blocktime);

bool switchTo(ReflectorClient *client, uint32_t tg);
Expand Down
1 change: 1 addition & 0 deletions src/svxlink/reflector/svxreflector.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ LISTEN_PORT=5300
TG_FOR_V1_CLIENTS=999
#RANDOM_QSY_RANGE=12399:100
#HTTP_SRV_PORT=8080
COMMAND_PTY=/dev/shm/reflector_ctrl

[USERS]
#SM0ABC-1=MyNodes
Expand Down

0 comments on commit 5636dff

Please sign in to comment.