X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/c65b73de5dfbbb54f7b977a9fcd72d1abbb1e827..9b30fa9ff418407450a497d998039f648bf72128:/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp?ds=inline diff --git a/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp b/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp index 502ff6d5..567c537a 100644 --- a/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp +++ b/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp @@ -14,225 +14,294 @@ * 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 "configproto.h" +#include "conn.h" -#include "parser.h" +#include "parser_server_info.h" +#include "parser_admins.h" +#include "parser_tariffs.h" +#include "parser_users.h" +#include "parser_message.h" #include "parser_auth_by.h" -#include "parser_user_info.h" -#include "stg/users.h" -#include "stg/admins.h" -#include "stg/tariffs.h" -#include "stg/logger.h" #include "stg/common.h" +#include "stg/logger.h" -#include +#include +#include +#include +#include +#include +#include +#include -#include "configproto.h" +#include +#include +#include +#include + +namespace SP = STG::PARSER; -//----------------------------------------------------------------------------- -void ParseXMLStart(void *data, const char *el, const char **attr) +CONFIGPROTO::CONFIGPROTO(PLUGIN_LOGGER & l) + : m_settings(NULL), + m_admins(NULL), + m_tariffs(NULL), + m_users(NULL), + m_store(NULL), + m_port(0), + m_bindAddress("0.0.0.0"), + m_running(false), + m_stopped(true), + m_logger(l), + m_listenSocket(-1) { -CONFIGPROTO * cp = static_cast(data); +} -if (cp->currParser) +CONFIGPROTO::~CONFIGPROTO() +{ + std::deque::iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + delete *it; +} + +int CONFIGPROTO::Prepare() +{ + sigset_t sigmask, oldmask; + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGINT); + sigaddset(&sigmask, SIGTERM); + sigaddset(&sigmask, SIGUSR1); + sigaddset(&sigmask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); + + m_listenSocket = socket(PF_INET, SOCK_STREAM, 0); + + if (m_listenSocket < 0) { - cp->currParser->SetCurrAdmin(*cp->currAdmin); - cp->currParser->ParseStart(data, el, attr); + m_errorStr = std::string("Cannot create listen socket: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + return -1; } -else + + int dummy = 1; + + if (setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &dummy, 4) != 0) { - for (size_t i = 0; i < cp->dataParser.size(); i++) - { - 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(); - } - } + m_errorStr = std::string("Failed to set SO_REUSEADDR to the listen socket: '") + strerror(errno) + "'."; + m_logger(m_errorStr); + return -1; + } + + if (!Bind()) + 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; } + + RegisterParsers(); + + m_running = true; + m_stopped = false; + return 0; } -//----------------------------------------------------------------------------- -void ParseXMLEnd(void *data, const char *el) + +int CONFIGPROTO::Stop() { -CONFIGPROTO * cp = static_cast(data); -if (cp->currParser) + m_running = false; + for (int i = 0; i < 5 && !m_stopped; ++i) { - if (cp->currParser->ParseEnd(data, el) == 0) - { - cp->dataAnswer = cp->currParser->GetAnswer(); - cp->currParser = NULL; - } + struct timespec ts = {0, 200000000}; + nanosleep(&ts, NULL); + } + + if (!m_stopped) + { + m_errorStr = "Cannot stop listenign thread."; + m_logger(m_errorStr); + return -1; } -else + + shutdown(m_listenSocket, SHUT_RDWR); + close(m_listenSocket); + return 0; +} + +void CONFIGPROTO::Run() +{ + while (m_running) { - for (size_t i = 0; i < cp->dataParser.size(); i++) + 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) { - if (cp->dataParser[i]->ParseEnd(data, el) == 0) - { - cp->dataAnswer = cp->currParser->GetAnswer(); - cp->currParser = NULL; + m_errorStr = std::string("'select' is failed: '") + strerror(errno) + "'."; + printfd(__FILE__, "%s\n", m_errorStr.c_str()); + m_logger(m_errorStr); break; - } } + if (!m_running) + break; + if (res > 0) + HandleEvents(fds); + + CleanupConns(); } + m_stopped = true; } -//----------------------------------------------------------------------------- -CONFIGPROTO::CONFIGPROTO(PLUGIN_LOGGER & l) - : answerList(), - requestList(), - adminIP(0), - adminLogin(), - adminPassword(), - port(0), - thrReciveSendConf(), - nonstop(true), - state(0), - currAdmin(NULL), - logger(l), - listenSocket(-1), - parserGetServInfo(), - parserGetUsers(), - parserGetUser(), - parserChgUser(), - parserAddUser(), - parserDelUser(), - parserCheckUser(), - parserSendMessage(), - parserAuthBy(), - parserGetAdmins(), - parserAddAdmin(), - parserDelAdmin(), - parserChgAdmin(), - parserGetTariffs(), - parserAddTariff(), - parserDelTariff(), - parserChgTariff(), - admins(NULL), - currParser(NULL), - dataParser(), - xmlParser(), - errorStr() + +bool CONFIGPROTO::Bind() { -dataParser.push_back(new PARSER_GET_SERVER_INFO); - -dataParser.push_back(new PARSER_GET_USERS); -dataParser.push_back(new PARSER_GET_USER); -dataParser.push_back(new PARSER_CHG_USER); -dataParser.push_back(new PARSER_ADD_USER); -dataParser.push_back(new PARSER_DEL_USER); -dataParser.push_back(new PARSER_CHECK_USER); -dataParser.push_back(new PARSER_SEND_MESSAGE); -dataParser.push_back(new PARSER_AUTH_BY); -dataParser.push_back(new PARSER_USER_INFO); - -dataParser.push_back(new PARSER_GET_TARIFFS); -dataParser.push_back(new PARSER_ADD_TARIFF); -dataParser.push_back(new PARSER_DEL_TARIFF); -dataParser.push_back(new PARSER_CHG_TARIFF); - -dataParser.push_back(new PARSER_GET_ADMINS); -dataParser.push_back(new PARSER_CHG_ADMIN); -dataParser.push_back(new PARSER_DEL_ADMIN); -dataParser.push_back(new PARSER_ADD_ADMIN); - -xmlParser = XML_ParserCreate(NULL); - -if (!xmlParser) + const hostent * he = gethostbyname(m_bindAddress.c_str()); + if (he == NULL) { - logger("Couldn't allocate memory for parser."); - exit(1); + m_errorStr = "Failed to resolve name '" + m_bindAddress + "': '" + hstrerror(h_errno) + "'."; + printfd(__FILE__, "%s\n", m_errorStr.c_str()); + m_logger(m_errorStr); + return false; } + char ** ptr = he->h_addr_list; + while (*ptr != NULL) + { + struct sockaddr_in listenAddr; + listenAddr.sin_family = PF_INET; + listenAddr.sin_port = htons(m_port); + listenAddr.sin_addr.s_addr = *reinterpret_cast(*ptr); + + printfd(__FILE__, "Trying to bind to %s:%d\n", inet_ntostring(listenAddr.sin_addr.s_addr).c_str(), m_port); + + if (bind(m_listenSocket, reinterpret_cast(&listenAddr), sizeof(listenAddr)) == 0) + return true; + + m_errorStr = std::string("Cannot bind listen socket: '") + strerror(errno) + "'."; + printfd(__FILE__, "%s\n", m_errorStr.c_str()); + m_logger(m_errorStr); + + ++ptr; + } + + return false; } -//----------------------------------------------------------------------------- -CONFIGPROTO::~CONFIGPROTO() -{ -for (size_t i = 0; i < dataParser.size(); ++i) - delete dataParser[i]; -XML_ParserFree(xmlParser); -} -//----------------------------------------------------------------------------- -int CONFIGPROTO::ParseCommand() -{ -std::list::iterator n; -int done = 0; -char str[9]; -if (requestList.empty()) - return 0; +void CONFIGPROTO::RegisterParsers() +{ + assert(m_settings != NULL); + assert(m_store != NULL); + assert(m_admins != NULL); + assert(m_users != NULL); + assert(m_tariffs != NULL); -n = requestList.begin(); + SP::GET_SERVER_INFO::FACTORY::Register(m_registry, *m_settings, *m_users, *m_tariffs); -strncpy(str, (*n).c_str(), 8); -str[8] = 0; + SP::GET_ADMINS::FACTORY::Register(m_registry, *m_admins); + SP::ADD_ADMIN::FACTORY::Register(m_registry, *m_admins); + SP::DEL_ADMIN::FACTORY::Register(m_registry, *m_admins); + SP::CHG_ADMIN::FACTORY::Register(m_registry, *m_admins); -XML_ParserReset(xmlParser, NULL); -XML_SetElementHandler(xmlParser, ParseXMLStart, ParseXMLEnd); -XML_SetUserData(xmlParser, this); + SP::GET_TARIFFS::FACTORY::Register(m_registry, *m_tariffs); + SP::ADD_TARIFF::FACTORY::Register(m_registry, *m_tariffs); + SP::DEL_TARIFF::FACTORY::Register(m_registry, *m_tariffs, *m_users); + SP::CHG_TARIFF::FACTORY::Register(m_registry, *m_tariffs); -while(nonstop) - { - strncpy(str, (*n).c_str(), 8); - str[8] = 0; - size_t len = strlen(str); + SP::GET_USERS::FACTORY::Register(m_registry, *m_users); + SP::GET_USER::FACTORY::Register(m_registry, *m_users); + SP::ADD_USER::FACTORY::Register(m_registry, *m_users); + SP::DEL_USER::FACTORY::Register(m_registry, *m_users); + SP::CHG_USER::FACTORY::Register(m_registry, *m_users, *m_store, *m_tariffs); + SP::CHECK_USER::FACTORY::Register(m_registry, *m_users); - ++n; - if (n == requestList.end()) - done = 1; - --n; + SP::SEND_MESSAGE::FACTORY::Register(m_registry, *m_users); - if (XML_Parse(xmlParser, (*n).c_str(), static_cast(len), done) == XML_STATUS_ERROR) - { - logger("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; - } + SP::AUTH_BY::FACTORY::Register(m_registry, *m_users); +} - return -1; - } +int CONFIGPROTO::MaxFD() const +{ + int maxFD = m_listenSocket; + std::deque::const_iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + if (maxFD < (*it)->Sock()) + maxFD = (*it)->Sock(); + return maxFD; +} - if (done) - return 0; +void CONFIGPROTO::BuildFDSet(fd_set & fds) const +{ + FD_ZERO(&fds); + FD_SET(m_listenSocket, &fds); + std::deque::const_iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + FD_SET((*it)->Sock(), &fds); +} - ++n; - } +void CONFIGPROTO::CleanupConns() +{ + std::deque::iterator pos; + for (pos = m_conns.begin(); pos != m_conns.end(); ++pos) + if (((*pos)->IsDone() && !(*pos)->IsKeepAlive()) || !(*pos)->IsOk()) + { + delete *pos; + *pos = NULL; + } -return 0; + pos = std::remove(m_conns.begin(), m_conns.end(), static_cast(NULL)); + m_conns.erase(pos, m_conns.end()); } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetPort(uint16_t p) + +void CONFIGPROTO::HandleEvents(const fd_set & fds) { -port = p; + if (FD_ISSET(m_listenSocket, &fds)) + AcceptConnection(); + else + { + std::deque::iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + if (FD_ISSET((*it)->Sock(), &fds)) + (*it)->Read(); + } } -//----------------------------------------------------------------------------- -void CONFIGPROTO::SetAdmins(ADMINS * a) + +void CONFIGPROTO::AcceptConnection() { -admins = a; + struct sockaddr_in outerAddr; + socklen_t outerAddrLen(sizeof(outerAddr)); + int sock = accept(m_listenSocket, reinterpret_cast(&outerAddr), &outerAddrLen); + + if (sock < 0) + { + m_errorStr = std::string("Failed to accept connection: '") + strerror(errno) + "'."; + printfd(__FILE__, "%s\n", m_errorStr.c_str()); + m_logger(m_errorStr); + return; + } + + assert(m_admins != NULL); + + try + { + m_conns.push_back(new STG::Conn(m_registry, *m_admins, sock, outerAddr, m_logger)); + printfd(__FILE__, "New connection from %s:%d. Total connections: %d\n", inet_ntostring(m_conns.back()->IP()).c_str(), m_conns.back()->Port(), m_conns.size()); + } + catch (const STG::Conn::Error & error) + { + // Unlikely. + m_logger(std::string("Failed to create new client connection: '") + error.what() + "'."); + } } -//-----------------------------------------------------------------------------