X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/c963a109219ed101fa42f501b16f90d7b7b4f3f2..d903c02d2bba584ff806ae9d00973fa4418f77b8:/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp diff --git a/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp b/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp index f6f97f5f..d28ece17 100644 --- a/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp +++ b/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp @@ -14,234 +14,229 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * Date: 27.10.2002 - */ - /* * Author : Boris Mikhailenko + * Author : Maxim Mamontov */ - /* - $Revision: 1.22 $ - $Date: 2010/10/04 20:24:14 $ - $Author: faust $ - */ +#include "conn.h" + +#include "stg/common.h" +#include "stg/logger.h" -#include +#include +#include +#include +#include +#include +#include -#include "configproto.h" +#include +#include +#include +#include -//----------------------------------------------------------------------------- -void ParseXMLStart(void *data, const char *el, const char **attr) +namespace { -CONFIGPROTO * cp = static_cast(data); -if (cp->currParser) +struct IsFinished : public std::unary_function +{ + result_type operator()(const argument_type & arg) { - cp->currParser->SetAnswerList(&cp->answerList); - cp->currParser->SetCurrAdmin(*cp->currAdmin); - cp->currParser->ParseStart(data, el, attr); + return (arg->IsDone() && !arg->IsKeepAlive()) || !arg->IsOk(); } -else +}; + +struct RemoveConn : public std::unary_function +{ + result_type operator()(const argument_type & arg) { - for (unsigned int i = 0; i < cp->dataParser.size(); i++) - { - cp->dataParser[i]->SetAnswerList(&cp->answerList); - cp->dataParser[i]->SetCurrAdmin(*cp->currAdmin); - cp->dataParser[i]->Reset(); - if (cp->dataParser[i]->ParseStart(data, el, attr) == 0) - { - cp->currParser = cp->dataParser[i]; - break; - } - else - { - cp->dataParser[i]->Reset(); - } - } + delete arg; } +}; + } -//----------------------------------------------------------------------------- -void ParseXMLEnd(void *data, const char *el) + +CONFIGPROTO::CONFIGPROTO(PLUGIN_LOGGER & l) + : m_settings(NULL), + m_admins(NULL), + m_tariffs(NULL), + m_users(NULL), + m_port(0), + m_running(false), + m_stopped(true), + m_logger(l), + m_listenSocket(-1) { -CONFIGPROTO * cp = static_cast(data); -if (cp->currParser) - { - if (cp->currParser->ParseEnd(data, el) == 0) - { - cp->currParser = NULL; - } - } -else - { - for (unsigned int i = 0; i < cp->dataParser.size(); i++) - { - if (cp->dataParser[i]->ParseEnd(data, el) == 0) - { - break; - } - } - } + std::for_each(m_conns.begin(), m_conns.end(), RemoveConn()); } -//----------------------------------------------------------------------------- -CONFIGPROTO::CONFIGPROTO() - : adminIP(0), - port(0), - nonstop(1), - state(0), - currAdmin(), - WriteServLog(GetStgLogger()), - listenSocket(0), - admins(NULL), - currParser(NULL) + +int CONFIGPROTO::Prepare() { -dataParser.push_back(&parserGetServInfo); + sigset_t sigmask, oldmask; + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGINT); + sigaddset(&sigmask, SIGTERM); + sigaddset(&sigmask, SIGUSR1); + sigaddset(&sigmask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); -dataParser.push_back(&parserGetUsers); -dataParser.push_back(&parserGetUser); -dataParser.push_back(&parserChgUser); -dataParser.push_back(&parserAddUser); -dataParser.push_back(&parserDelUser); -dataParser.push_back(&parserCheckUser); -dataParser.push_back(&parserSendMessage); + m_listenSocket = socket(PF_INET, SOCK_STREAM, 0); -dataParser.push_back(&parserGetTariffs); -dataParser.push_back(&parserAddTariff); -dataParser.push_back(&parserDelTariff); -dataParser.push_back(&parserChgTariff); + if (m_listenSocket < 0) + { + m_errorStr = std::string("Cannot create listen socket: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + return -1; + } -dataParser.push_back(&parserGetAdmins); -dataParser.push_back(&parserChgAdmin); -dataParser.push_back(&parserDelAdmin); -dataParser.push_back(&parserAddAdmin); + struct sockaddr_in listenAddr; + listenAddr.sin_family = PF_INET; + listenAddr.sin_port = htons(m_port); + listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); // TODO: arbitrary address -xmlParser = XML_ParserCreate(NULL); + int dummy = 1; -if (!xmlParser) + if (setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &dummy, 4) != 0) { - WriteServLog("Couldn't allocate memory for parser."); - exit(1); + m_errorStr = std::string("Failed to set SO_REUSEADDR to the listen socket: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + return -1; } -} -//----------------------------------------------------------------------------- -CONFIGPROTO::~CONFIGPROTO() -{ -XML_ParserFree(xmlParser); -} -//----------------------------------------------------------------------------- -int CONFIGPROTO::ParseCommand() -{ -list::iterator n; -int done = 0; -char str[9]; -int len; + if (bind(m_listenSocket, reinterpret_cast(&listenAddr), sizeof(listenAddr)) == -1) + { + m_errorStr = std::string("Cannot bind listen socket: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + return -1; + } + + if (listen(m_listenSocket, 64) == -1) // TODO: backlog length + { + m_errorStr = std::string("Failed to start listening for connections: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + return -1; + } -if (requestList.empty()) + m_running = true; + m_stopped = false; return 0; +} -n = requestList.begin(); +int CONFIGPROTO::Stop() +{ + m_running = false; + for (int i = 0; i < 5 && !m_stopped; ++i) + { + struct timespec ts = {0, 200000000}; + nanosleep(&ts, NULL); + } -strncpy(str, (*n).c_str(), 8); -str[8] = 0; + if (!m_stopped) + { + m_errorStr = "Cannot stop listenign thread."; + m_logger(m_errorStr); + return -1; + } -XML_ParserReset(xmlParser, NULL); -XML_SetElementHandler(xmlParser, ParseXMLStart, ParseXMLEnd); -XML_SetUserData(xmlParser, this); + shutdown(m_listenSocket, SHUT_RDWR); + close(m_listenSocket); + return 0; +} -while(nonstop) +void CONFIGPROTO::Run() +{ + while (m_running) { - strncpy(str, (*n).c_str(), 8); - str[8] = 0; - len = strlen(str); + fd_set fds; - n++; - if (n == requestList.end()) - done = 1; - n--; + BuildFDSet(fds); - if (XML_Parse(xmlParser, (*n).c_str(), len, done) == XML_STATUS_ERROR) - { - WriteServLog("Invalid configuration request"); - printfd(__FILE__, "Parse error at line %d:\n%s\n", - XML_GetCurrentLineNumber(xmlParser), - XML_ErrorString(XML_GetErrorCode(xmlParser))); - if (currParser) - { - printfd(__FILE__, "Parser reset\n"); - currParser->Reset(); - currParser = NULL; - } + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500000; - return -1; + int res = select(MaxFD() + 1, &fds, NULL, NULL, &tv); + if (res < 0) + { + m_errorStr = std::string("'select' is failed: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + break; } + if (!m_running) + break; + if (res > 0) + HandleEvents(fds); - if (done) - return 0; - - n++; + CleanupConns(); } - -return 0; + m_stopped = true; } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetPort(uint16_t p) + +int CONFIGPROTO::MaxFD() const { -port = p; + int maxFD = m_listenSocket; + for (size_t i = 0; i < m_conns.size(); ++i) + if (maxFD < m_conns[i]->Sock()) + maxFD = m_conns[i]->Sock(); + return maxFD; } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetAdmins(ADMINS * a) -{ -admins = a; -for (unsigned int i = 0; i < dataParser.size(); i++) - { - dataParser[i]->SetAdmins(a); - } -} -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetUsers(USERS * u) +void CONFIGPROTO::BuildFDSet(fd_set & fds) const { -for (unsigned int i = 0; i < dataParser.size(); i++) - { - dataParser[i]->SetUsers(u); - } - + for (size_t i = 0; i < m_conns.size(); ++i) + FD_SET(m_conns[i]->Sock(), &fds); } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetTariffs(TARIFFS * t) + +void CONFIGPROTO::CleanupConns() { -for (unsigned int i = 0; i < dataParser.size(); i++) - { - dataParser[i]->SetTariffs(t); - } + std::vector::iterator pos; + pos = std::remove_if(m_conns.begin(), m_conns.end(), IsFinished()); + if (pos == m_conns.end()) + return; + std::for_each(pos, m_conns.end(), RemoveConn()); + m_conns.erase(pos, m_conns.end()); } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetStore(STORE * s) + +void CONFIGPROTO::HandleEvents(const fd_set & fds) { -for (unsigned int i = 0; i < dataParser.size(); i++) + if (FD_ISSET(m_listenSocket, &fds)) + AcceptConnection(); + else { - dataParser[i]->SetStore(s); + for (size_t i = 0; i < m_conns.size(); ++i) + if (FD_ISSET(m_conns[i]->Sock(), &fds)) + m_conns[i]->Read(); } } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetStgSettings(const SETTINGS * s) + +void CONFIGPROTO::AcceptConnection() { -for (unsigned int i = 0; i < dataParser.size(); i++) + struct sockaddr_in outerAddr; + socklen_t outerAddrLen(sizeof(outerAddr)); + int sock = accept(m_listenSocket, reinterpret_cast(&outerAddr), &outerAddrLen); + + if (sock < 0) { - dataParser[i]->SetStgSettings(s); + m_errorStr = std::string("Failed to accept connection: '") + strerror(errno) + "'."; + printfd(__FILE__, "%s", m_errorStr.c_str()); + m_logger(m_errorStr); + return; } + + assert(m_settings != NULL); + assert(m_admins != NULL); + assert(m_users != NULL); + assert(m_tariffs != NULL); + + m_conns.push_back(new STG::Conn(*m_settings, *m_admins, *m_users, *m_tariffs, sock, outerAddr)); + + printfd(__FILE__, "New connection from %s:%d\n", inet_ntostring(m_conns.back()->IP()).c_str(), m_conns.back()->Port()); } -//----------------------------------------------------------------------------- -const string & CONFIGPROTO::GetStrError() const -{ -return errorStr; -} -//----------------------------------------------------------------------------- -uint32_t CONFIGPROTO::GetAdminIP() const +/* +void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip) { -return adminIP; + m_logger("Admin's connection failed. IP %s", inet_ntostring(ip).c_str()); } -//----------------------------------------------------------------------------- +*/