-/*
- * 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
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
#include "radius.h"
+#include "server.h"
+#include "radproto/error.h"
-#include "stg/store.h"
-#include "stg/users.h"
-#include "stg/plugin_creator.h"
-
-#include <csignal>
-#include <cerror>
-#include <cstring>
-
-namespace
-{
+#include "stg/common.h"
-PLUGIN_CREATOR<RADIUS> creator;
+#include <boost/asio.hpp>
+#include <string>
+#include <iterator>
+#include <iostream>
-}
+using STG::RADIUS;
+using STG::RAD_SETTINGS;
-extern "C" PLUGIN * GetPlugin()
+extern "C" STG::Plugin* GetPlugin()
{
- return creator.GetPlugin();
+ static RADIUS plugin;
+ return &plugin;
}
-RADIUS::RADIUS()
- : m_running(false),
- m_stopped(true),
- m_users(NULL),
- m_store(NULL),
- m_logger(GetPluginLogger(GetStgLogger(), "radius"))
-{
-}
+RAD_SETTINGS::RAD_SETTINGS()
+ : m_port(1812),
+ m_dictionaries("/usr/share/freeradius/dictionary")
+{}
-int RADIUS::ParseSettings()
+int RAD_SETTINGS::ParseSettings(const ModuleSettings & s)
{
- try {
- m_config = STG::Config(m_settings);
- return 0;
- } catch (const std::runtime_error& ex) {
- m_logger("Failed to parse settings. %s", ex.what());
- return -1;
- }
-}
+ ParamValue pv;
+ int p;
-int RADIUS::Start()
-{
- if (m_running)
- return 0;
+ pv.param = "Port";
+ auto pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+ if (pvi != s.moduleParams.end() && !pvi->value.empty())
+ {
+ if (ParseIntInRange(pvi->value[0], 2, 65535, &p) != 0)
+ {
+ m_errorStr = "Cannot parse parameter \'Port\': " + m_errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+ return -1;
+ }
+ m_port = static_cast<uint16_t>(p);
+ }
- int res = pthread_create(&m_thread, NULL, run, this);
- if (res == 0)
- return 0;
+ pv.param = "Secret";
+ pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+ if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ m_errorStr = "Parameter \'Secret\' not found.";
+ printfd(__FILE__, "Parameter 'Secret' not found\n");
+ m_secret = "";
+ }
+ else
+ {
+ m_secret = pvi->value[0];
+ }
- m_error = strerror(res);
- m_logger("Failed to create thread: '" + m_error + "'.");
- return -1;
+ pv.param = "Dictionaries";
+ pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+ if (pvi != s.moduleParams.end() && !pvi->value.empty())
+ m_dictionaries = pvi->value[0];
+ return 0;
}
-int RADIUS::Stop()
+RADIUS::RADIUS()
+ : m_running(false),
+ m_logger(PluginLogger::get("radius"))
{
- if (m_stopped)
- return 0;
+}
- m_running = false;
+int RADIUS::Run(std::stop_token token)
+{
+ SetRunning(true);
- for (size_t i = 0; i < 25 && !m_stopped; i++) {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
+ try
+ {
+ boost::asio::io_service ioService;
+ Server server(ioService, m_radSettings.GetSecret(), m_radSettings.GetPort(), m_radSettings.GetDictionaries());
+ ioService.run();
}
-
- if (m_stopped) {
- pthread_join(m_thread, NULL);
- return 0;
+ catch (const std::exception& e)
+ {
+ m_errorStr = "Exception in RADIUS::Run(): " + std::string(e.what());
+ m_logger("Exception in RADIUS:: Run(): %s", e.what());
+ printfd(__FILE__, "Exception in RADIUS:: Run(). Message: '%s'\n", e.what());
}
- m_error = "Failed to stop thread.";
- m_logger(m_error);
- return -1;
+ SetRunning(false);
+ return 0;
}
-//-----------------------------------------------------------------------------
-void* RADIUS::run(void* d)
-{
- sigset_t signalSet;
- sigfillset(&signalSet);
- pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
- static_cast<RADIUS *>(d)->runImpl();
+int RADIUS::ParseSettings()
+{
+ auto ret = m_radSettings.ParseSettings(m_settings);
+ if (ret != 0)
+ m_errorStr = m_radSettings.GetStrError();
- return NULL;
+ return ret;
}
-void RADIUS::runImpl()
+std::string RADIUS::GetVersion() const
{
- m_running = true;
-
- while (m_running) {
- fd_set fds;
-
- buildFDSet(fds);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 500000;
-
- int res = select(maxFD() + 1, &fds, NULL, NULL, &tv);
- if (res < 0)
- {
- m_error = std::string("'select' is failed: '") + strerror(errno) + "'.";
- m_logger(m_error);
- break;
- }
-
- if (!m_running)
- break;
-
- if (res > 0)
- handleEvents(fds);
-
- cleanupConns();
- }
-
- m_stopped = true;
+ return "Radius v.1.0";
}
-int RADIUS::maxFD() const
+int RADIUS::Start()
{
- int maxFD = m_listenSocket;
- std::deque<STG::Conn *>::const_iterator it;
- for (it = m_conns.begin(); it != m_conns.end(); ++it)
- if (maxFD < (*it)->sock())
- maxFD = (*it)->sock();
- return maxFD;
+ m_thread = std::jthread([this](auto token){ Run(std::move(token)); });
+ return 0;
}
-void RADIUS::buildFDSet(fd_set & fds) const
+int RADIUS::Stop()
{
- FD_ZERO(&fds);
- FD_SET(m_listenSocket, &fds);
- std::deque<STG::Conn *>::const_iterator it;
- for (it = m_conns.begin(); it != m_conns.end(); ++it)
- FD_SET((*it)->sock(), &fds);
+ if (!m_thread.joinable())
+ return 0;
+
+ m_thread.request_stop();
+
+ m_thread.join();
+ return 0;
}
-void RADIUS::cleanupConns()
+bool RADIUS::IsRunning()
{
- std::deque<STG::Conn *>::iterator pos;
- for (pos = m_conns.begin(); pos != m_conns.end(); ++pos)
- if (((*pos)->isDone() && !(*pos)->isKeepAlive()) || !(*pos)->isOk()) {
- delete *pos;
- *pos = NULL;
- }
-
- pos = std::remove(m_conns.begin(), m_conns.end(), static_cast<STG::Conn *>(NULL));
- m_conns.erase(pos, m_conns.end());
+ const std::lock_guard lock(m_mutex);
+ return m_running;
}
-void RADIUS::handleEvents(const fd_set & fds)
+void RADIUS::SetRunning(bool val)
{
- if (FD_ISSET(m_listenSocket, &fds))
- acceptConnection();
- else
- {
- std::deque<STG::Conn *>::iterator it;
- for (it = m_conns.begin(); it != m_conns.end(); ++it)
- if (FD_ISSET((*it)->sock(), &fds))
- (*it)->read();
- }
+ const std::lock_guard lock(m_mutex);
+ m_running = val;
}