include_directories ( include )
add_subdirectory ( libs )
-
-if ( BUILD_RSCRIPTD )
- add_subdirectory ( rscriptd )
-endif ( BUILD_RSCRIPTD )
-
-if ( BUILD_SGAUTH )
- add_subdirectory ( sgauth )
-endif ( BUILD_SGAUTH )
-
-if ( BUILD_SGCONF )
- add_subdirectory ( sgconf )
-endif ( BUILD_SGCONF )
-
-if ( BUILD_STG )
- add_subdirectory ( stargazer )
-endif ( BUILD_STG )
+add_subdirectory ( projects )
if ( BUILD_TESTS )
add_subdirectory ( tests )
endif ( BUILD_TESTS )
-
-add_custom_target (cppcheck COMMAND cppcheck --enable=all --std=c++14 ${CMAKE_SOURCE_DIR}/rlm_stg ${CMAKE_SOURCE_DIR}/rscriptd ${CMAKE_SOURCE_DIR}/sgauth ${CMAKE_SOURCE_DIR}/sgconf ${CMAKE_SOURCE_DIR}/sgconv ${CMAKE_SOURCE_DIR}/stargazer)
exit -1
fi
-STGPATH="$BASEPATH/stg/build/stargazer"
+STGPATH="$BASEPATH/stg/build/projects/stargazer"
cp "stuff/stargazer-files.conf" "$STGPATH/stargazer.conf"
cp "stuff/rules" "$STGPATH/"
BASEPATH=$1
-SGCONFPATH="$BASEPATH/stg/build/sgconf"
+SGCONFPATH="$BASEPATH/stg/build/projects/sgconf"
printf "Check initial admin list... "
BASEPATH=$1
-SGCONFPATH="$BASEPATH/stg/build/sgconf"
+SGCONFPATH="$BASEPATH/stg/build/projects/sgconf"
printf "Check server info... "
BASEPATH=$1
-SGCONFPATH="$BASEPATH/stg/build/sgconf"
+SGCONFPATH="$BASEPATH/stg/build/projects/sgconf"
printf "Check initial service list... "
--- /dev/null
+set ( CPP_FILES main.cpp listener.cpp pidfile.cpp )
+
+set ( THREADS_PREFER_PTHREAD_FLAG ON )
+find_package ( Threads REQUIRED )
+
+add_executable ( rscriptd ${CPP_FILES} )
+
+target_link_libraries ( rscriptd scriptexecuter conffiles logger crypto common Threads::Threads )
+
+# TODO: install
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include <arpa/inet.h>
+#include <sys/uio.h> // readv
+#include <sys/types.h> // for historical versions of BSD
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <csignal>
+#include <cerrno>
+#include <ctime>
+#include <cstring>
+#include <sstream>
+#include <algorithm>
+
+#include "stg/scriptexecuter.h"
+#include "stg/locker.h"
+#include "stg/common.h"
+#include "stg/const.h"
+#include "listener.h"
+
+void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password);
+void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
+
+//-----------------------------------------------------------------------------
+LISTENER::LISTENER()
+ : WriteServLog(STG::Logger::get()),
+ port(0),
+ running(false),
+ receiverStopped(true),
+ processorStopped(true),
+ userTimeout(0),
+ listenSocket(0),
+ version("rscriptd listener v.1.2")
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+void LISTENER::SetPassword(const std::string & p)
+{
+password = p;
+printfd(__FILE__, "Encryption initiated with password \'%s\'\n", password.c_str());
+InitEncrypt(&ctxS, password);
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Start()
+{
+printfd(__FILE__, "LISTENER::Start()\n");
+running = true;
+
+if (PrepareNet())
+ {
+ return true;
+ }
+
+if (receiverStopped)
+ {
+ if (pthread_create(&receiverThread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ return true;
+ }
+ }
+
+if (processorStopped)
+ {
+ if (pthread_create(&processorThread, NULL, RunProcessor, this))
+ {
+ errorStr = "Cannot create thread.";
+ return true;
+ }
+ }
+
+errorStr = "";
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Stop()
+{
+running = false;
+
+printfd(__FILE__, "LISTENER::Stop()\n");
+
+struct timespec ts = {0, 500000000};
+nanosleep(&ts, NULL);
+
+if (!processorStopped)
+ {
+ //5 seconds to thread stops itself
+ for (int i = 0; i < 25 && !processorStopped; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+ //after 5 seconds waiting thread still running. now killing it
+ if (!processorStopped)
+ {
+ //TODO pthread_cancel()
+ if (pthread_kill(processorThread, SIGINT))
+ {
+ errorStr = "Cannot kill thread.";
+ return true;
+ }
+ printfd(__FILE__, "LISTENER killed Timeouter\n");
+ }
+ }
+
+if (!receiverStopped)
+ {
+ //5 seconds to thread stops itself
+ for (int i = 0; i < 25 && !receiverStopped; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+ //after 5 seconds waiting thread still running. now killing it
+ if (!receiverStopped)
+ {
+ //TODO pthread_cancel()
+ if (pthread_kill(receiverThread, SIGINT))
+ {
+ errorStr = "Cannot kill thread.";
+ return true;
+ }
+ printfd(__FILE__, "LISTENER killed Run\n");
+ }
+ }
+
+pthread_join(receiverThread, NULL);
+pthread_join(processorThread, NULL);
+
+pthread_mutex_destroy(&mutex);
+
+FinalizeNet();
+
+std::for_each(users.begin(), users.end(), DisconnectUser(*this));
+
+printfd(__FILE__, "LISTENER::Stoped successfully.\n");
+
+return false;
+}
+//-----------------------------------------------------------------------------
+void * LISTENER::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+LISTENER * listener = static_cast<LISTENER *>(d);
+
+listener->Runner();
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::Runner()
+{
+receiverStopped = false;
+
+while (running)
+ {
+ RecvPacket();
+ }
+
+receiverStopped = true;
+}
+//-----------------------------------------------------------------------------
+void * LISTENER::RunProcessor(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+LISTENER * listener = static_cast<LISTENER *>(d);
+
+listener->ProcessorRunner();
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::ProcessorRunner()
+{
+processorStopped = false;
+
+while (running)
+ {
+ struct timespec ts = {0, 500000000};
+ nanosleep(&ts, NULL);
+ if (!pending.empty())
+ ProcessPending();
+ ProcessTimeouts();
+ }
+
+processorStopped = true;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::PrepareNet()
+{
+listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (listenSocket < 0)
+ {
+ errorStr = "Cannot create socket.";
+ return true;
+ }
+
+struct sockaddr_in listenAddr;
+listenAddr.sin_family = AF_INET;
+listenAddr.sin_port = htons(port);
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+if (bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0)
+ {
+ errorStr = "LISTENER: Bind failed.";
+ return true;
+ }
+
+printfd(__FILE__, "LISTENER::PrepareNet() >>>> Start successfull.\n");
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::FinalizeNet()
+{
+close(listenSocket);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::RecvPacket()
+{
+struct iovec iov[2];
+
+char buffer[RS_MAX_PACKET_LEN];
+RS::PACKET_HEADER packetHead;
+
+iov[0].iov_base = reinterpret_cast<char *>(&packetHead);
+iov[0].iov_len = sizeof(packetHead);
+iov[1].iov_base = buffer;
+iov[1].iov_len = sizeof(buffer) - sizeof(packetHead);
+
+size_t dataLen = 0;
+while (dataLen < sizeof(buffer))
+ {
+ if (!WaitPackets(listenSocket))
+ {
+ if (!running)
+ return false;
+ continue;
+ }
+ int portion = readv(listenSocket, iov, 2);
+ if (portion < 0)
+ {
+ return true;
+ }
+ dataLen += portion;
+ }
+
+if (CheckHeader(packetHead))
+ {
+ printfd(__FILE__, "Invalid packet or incorrect protocol version!\n");
+ return true;
+ }
+
+std::string userLogin((char *)packetHead.login);
+PendingData data;
+data.login = userLogin;
+data.ip = ntohl(packetHead.ip);
+data.id = ntohl(packetHead.id);
+
+if (packetHead.packetType == RS_ALIVE_PACKET)
+ {
+ data.type = PendingData::ALIVE;
+ }
+else if (packetHead.packetType == RS_CONNECT_PACKET)
+ {
+ data.type = PendingData::CONNECT;
+ if (GetParams(buffer, data))
+ {
+ return true;
+ }
+ }
+else if (packetHead.packetType == RS_DISCONNECT_PACKET)
+ {
+ data.type = PendingData::DISCONNECT;
+ if (GetParams(buffer, data))
+ {
+ return true;
+ }
+ }
+
+STG_LOCKER lock(&mutex);
+pending.push_back(data);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::GetParams(char * buffer, UserData & data)
+{
+RS::PACKET_TAIL packetTail;
+
+Decrypt(&ctxS, (char *)&packetTail, buffer, sizeof(packetTail) / 8);
+
+if (strncmp((char *)packetTail.magic, RS_ID, RS_MAGIC_LEN))
+ {
+ printfd(__FILE__, "Invalid crypto magic\n");
+ return true;
+ }
+
+std::ostringstream params;
+params << "\"" << data.login << "\" "
+ << inet_ntostring(data.ip) << " "
+ << data.id << " "
+ << (char *)packetTail.params;
+
+data.params = params.str();
+
+return false;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::ProcessPending()
+{
+std::list<PendingData>::iterator it(pending.begin());
+size_t count = 0;
+printfd(__FILE__, "Pending: %d\n", pending.size());
+while (it != pending.end() && count < 256)
+ {
+ std::vector<AliveData>::iterator uit(
+ std::lower_bound(
+ users.begin(),
+ users.end(),
+ it->login)
+ );
+ if (it->type == PendingData::CONNECT)
+ {
+ printfd(__FILE__, "Connect packet\n");
+ if (uit == users.end() || uit->login != it->login)
+ {
+ printfd(__FILE__, "Connect new user '%s'\n", it->login.c_str());
+ // Add new user
+ Connect(*it);
+ users.insert(uit, AliveData(static_cast<UserData>(*it)));
+ }
+ else if (uit->login == it->login)
+ {
+ printfd(__FILE__, "Update existing user '%s'\n", it->login.c_str());
+ // Update already existing user
+ time(&uit->lastAlive);
+ uit->params = it->params;
+ }
+ else
+ {
+ printfd(__FILE__, "Hmmm... Strange connect for '%s'\n", it->login.c_str());
+ }
+ }
+ else if (it->type == PendingData::ALIVE)
+ {
+ printfd(__FILE__, "Alive packet\n");
+ if (uit != users.end() && uit->login == it->login)
+ {
+ printfd(__FILE__, "Alive user '%s'\n", it->login.c_str());
+ // Update existing user
+ time(&uit->lastAlive);
+ }
+ else
+ {
+ printfd(__FILE__, "Alive user '%s' is not found\n", it->login.c_str());
+ }
+ }
+ else if (it->type == PendingData::DISCONNECT)
+ {
+ printfd(__FILE__, "Disconnect packet\n");
+ if (uit != users.end() && uit->login == it->login.c_str())
+ {
+ printfd(__FILE__, "Disconnect user '%s'\n", it->login.c_str());
+ // Disconnect existing user
+ uit->params = it->params;
+ Disconnect(*uit);
+ users.erase(uit);
+ }
+ else
+ {
+ printfd(__FILE__, "Cannot find user '%s' for disconnect\n", it->login.c_str());
+ }
+ }
+ else
+ {
+ printfd(__FILE__, "Unknown packet type\n");
+ }
+ ++it;
+ ++count;
+ }
+STG_LOCKER lock(&mutex);
+pending.erase(pending.begin(), it);
+}
+//-----------------------------------------------------------------------------
+void LISTENER::ProcessTimeouts()
+{
+const std::vector<AliveData>::iterator it(
+ std::stable_partition(
+ users.begin(),
+ users.end(),
+ IsNotTimedOut(userTimeout)
+ )
+ );
+
+if (it != users.end())
+ {
+ printfd(__FILE__, "Total users: %d, users to disconnect: %d\n", users.size(), std::distance(it, users.end()));
+
+ std::for_each(
+ it,
+ users.end(),
+ DisconnectUser(*this)
+ );
+
+ users.erase(it, users.end());
+ }
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Connect(const UserData & data) const
+{
+printfd(__FILE__, "Connect %s\n", data.login.c_str());
+if (access(scriptOnConnect.c_str(), X_OK) == 0)
+ {
+ if (ScriptExec((scriptOnConnect + " " + data.params).c_str()))
+ {
+ WriteServLog("Script %s cannot be executed for an unknown reason.", scriptOnConnect.c_str());
+ return true;
+ }
+ }
+else
+ {
+ WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
+ return true;
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Disconnect(const UserData & data) const
+{
+printfd(__FILE__, "Disconnect %s\n", data.login.c_str());
+if (access(scriptOnDisconnect.c_str(), X_OK) == 0)
+ {
+ if (ScriptExec((scriptOnDisconnect + " " + data.params).c_str()))
+ {
+ WriteServLog("Script %s cannot be executed for an unknown reson.", scriptOnDisconnect.c_str());
+ return true;
+ }
+ }
+else
+ {
+ WriteServLog("Script %s cannot be executed. File not found.", scriptOnDisconnect.c_str());
+ return true;
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::CheckHeader(const RS::PACKET_HEADER & header) const
+{
+if (strncmp((char *)header.magic, RS_ID, RS_MAGIC_LEN))
+ {
+ return true;
+ }
+if (strncmp((char *)header.protoVer, "02", RS_PROTO_VER_LEN))
+ {
+ return true;
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+inline
+void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password)
+{
+unsigned char keyL[PASSWD_LEN];
+memset(keyL, 0, PASSWD_LEN);
+strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+}
+//-----------------------------------------------------------------------------
+inline
+void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
+{
+if (dst != src)
+ memcpy(dst, src, len8 * 8);
+
+for (int i = 0; i < len8; i++)
+ Blowfish_Decrypt(ctx, (uint32_t *)(dst + i * 8), (uint32_t *)(dst + i * 8 + 4));
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include <pthread.h>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <functional>
+#include <cstdint>
+
+#include "stg/blowfish.h"
+#include "stg/rs_packets.h"
+#include "stg/logger.h"
+
+struct UserData
+{
+ std::string params;
+ std::string login;
+ uint32_t ip;
+ uint32_t id;
+};
+
+struct PendingData : public UserData
+{
+ enum {CONNECT, ALIVE, DISCONNECT} type;
+};
+
+struct AliveData : public UserData
+{
+ explicit AliveData(const UserData & data)
+ : UserData(data),
+ lastAlive(time(NULL))
+ {};
+ bool operator<(const std::string & rvalue) const { return login < rvalue; };
+ time_t lastAlive;
+};
+
+class IsNotTimedOut : public std::unary_function<const AliveData &, bool> {
+ public:
+ explicit IsNotTimedOut(double to) : timeout(to), now(time(NULL)) {}
+ bool operator()(const AliveData & data) const
+ {
+ return difftime(now, data.lastAlive) < timeout;
+ }
+ private:
+ double timeout;
+ time_t now;
+};
+
+class LISTENER
+{
+public:
+ LISTENER();
+ ~LISTENER(){};
+
+ void SetPort(uint16_t p) { port = p; };
+ void SetPassword(const std::string & p);
+ void SetUserTimeout(int t) { userTimeout = t; };
+ void SetScriptOnConnect(const std::string & script) { scriptOnConnect = script; };
+ void SetScriptOnDisconnect(const std::string & script) { scriptOnDisconnect = script; };
+
+ bool Start();
+ bool Stop();
+ bool IsRunning() const { return !receiverStopped && !processorStopped; };
+
+ const std::string & GetStrError() const { return errorStr; };
+ const std::string & GetVersion() const { return version; };
+
+private:
+ // Threading stuff
+ static void * Run(void * self);
+ static void * RunProcessor(void * self);
+ void Runner();
+ void ProcessorRunner();
+ // Networking stuff
+ bool PrepareNet();
+ bool FinalizeNet();
+ bool RecvPacket();
+ // Parsing stuff
+ bool CheckHeader(const RS::PACKET_HEADER & header) const;
+ bool GetParams(char * buffer, UserData & data);
+ // Processing stuff
+ void ProcessPending();
+ void ProcessTimeouts();
+ bool Disconnect(const UserData & data) const;
+ bool Connect(const UserData & data) const;
+
+ BLOWFISH_CTX ctxS;
+ STG::Logger& WriteServLog;
+
+ mutable std::string errorStr;
+ std::string scriptOnConnect;
+ std::string scriptOnDisconnect;
+ std::string password;
+ uint16_t port;
+
+ bool running;
+ bool receiverStopped;
+ bool processorStopped;
+ std::vector<AliveData> users;
+ std::list<PendingData> pending;
+ int userTimeout;
+
+ pthread_t receiverThread;
+ pthread_t processorThread;
+ pthread_mutex_t mutex;
+
+ int listenSocket;
+
+ std::string version;
+
+ friend class DisconnectUser;
+};
+
+class DisconnectUser : public std::unary_function<const UserData &, void> {
+ public:
+ explicit DisconnectUser(LISTENER & l) : listener(l) {};
+ void operator()(const UserData & data)
+ {
+ listener.Disconnect(data);
+ };
+ private:
+ LISTENER & listener;
+};
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.19 $
+ $Author: faust $
+ $Date: 2010/09/10 06:37:45 $
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h> // creat
+#include <unistd.h>
+
+#include <cstdlib>
+#include <cstdio>
+#include <csignal>
+#include <cerrno>
+#include <cstring> // strerror
+#include <set>
+
+#include "stg/common.h"
+#include "stg/logger.h"
+#include "stg/scriptexecuter.h"
+#include "stg/conffiles.h"
+#include "stg/version.h"
+#include "listener.h"
+#include "pidfile.h"
+
+#ifdef DEBUG
+# define MAIN_DEBUG 1
+# define NO_DAEMON 1
+#endif
+
+#define START_FILE "/._ST_ART_ED_"
+
+std::set<pid_t> executersPid;
+volatile time_t stgTime = time(NULL);
+
+//-----------------------------------------------------------------------------
+void KillExecuters()
+{
+std::set<pid_t>::iterator pid;
+pid = executersPid.begin();
+while (pid != executersPid.end())
+ {
+ printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
+ kill(*pid, SIGUSR1);
+ ++pid;
+ }
+}
+//-----------------------------------------------------------------------------
+#if defined(LINUX) || defined(DARWIN)
+int StartScriptExecuter(char * procName, int msgKey, int * msgID)
+#else
+int StartScriptExecuter(char *, int msgKey, int * msgID)
+#endif
+{
+auto & WriteServLog = STG::Logger::get();
+
+if (*msgID == -11) // If msgID == -11 - first call. Create queue
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
+
+ if (*msgID == -1)
+ {
+ *msgID = msgget(msgKey, 0);
+ if (*msgID == -1)
+ {
+ WriteServLog("Message queue not created.");
+ return -1;
+ }
+ else
+ {
+ msgctl(*msgID, IPC_RMID, NULL);
+ }
+ }
+ else
+ {
+ WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
+ break;
+ }
+ }
+ }
+
+pid_t executerPid = fork();
+
+switch (executerPid)
+ {
+ case -1: // Failure
+ WriteServLog("Fork error!");
+ return -1;
+
+ case 0: // Child
+ //close(0);
+ //close(1);
+ //close(2);
+ //setsid();
+#if defined(LINUX) || defined(DARWIN)
+ Executer(*msgID, executerPid, procName);
+#else
+ Executer(*msgID, executerPid);
+#endif
+ return 1;
+
+ default: // Parent
+ if (executersPid.empty())
+#if defined(LINUX) || defined(DARWIN)
+ Executer(*msgID, executerPid, NULL);
+#else
+ Executer(*msgID, executerPid);
+#endif
+ executersPid.insert(executerPid);
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void StopScriptExecuter(int msgID)
+{
+auto & WriteServLog = STG::Logger::get();
+
+for (int i = 0; i < 5; ++i)
+ {
+ struct msqid_ds data;
+ if (msgctl(msgID, IPC_STAT, &data))
+ {
+ int e = errno;
+ printfd(__FILE__, "StopScriptExecuter() - msgctl for IPC_STAT failed: '%s'\n", strerror(e));
+ WriteServLog( "Failed to check queue emptiness: '%s'", strerror(e));
+ break;
+ }
+
+ WriteServLog("Messages in queue: %d", data.msg_qnum);
+
+ if (data.msg_qnum == 0)
+ break;
+
+ struct timespec ts = {1, 0};
+ nanosleep(&ts, NULL);
+ }
+
+if (msgctl(msgID, IPC_RMID, NULL))
+ {
+ int e = errno;
+ printfd(__FILE__, "StopScriptExecuter() - msgctl for IPC_STAT failed: '%s'\n", strerror(e));
+ WriteServLog("Failed to remove queue: '%s'", strerror(e));
+ }
+else
+ {
+ WriteServLog("Queue removed successfully.");
+ }
+
+KillExecuters();
+}
+//-----------------------------------------------------------------------------
+#ifdef NO_DAEMON
+int ForkAndWait(const std::string &)
+#else
+int ForkAndWait(const std::string & confDir)
+#endif
+{
+#ifndef NO_DAEMON
+pid_t childPid = fork();
+
+switch (childPid)
+ {
+ case -1: // Failure
+ return -1;
+ break;
+
+ case 0: // Child
+ //close(0);
+ close(1);
+ close(2);
+ setsid();
+ break;
+
+ default: // Parent
+ exit(1);
+ break;
+ }
+#endif
+return 0;
+}
+//-----------------------------------------------------------------------------
+int main(int argc, char * argv[])
+{
+CONFIGFILE * cfg = NULL;
+LISTENER * listener = NULL;
+int msgID = -11;
+int execNum = 0;
+int execMsgKey = 0;
+
+std::string logFileName;
+std::string confDir;
+std::string password;
+std::string onConnect;
+std::string onDisconnect;
+int port;
+int userTimeout;
+
+if (getuid())
+ {
+ printf("You must be root. Exit.\n");
+ exit(1);
+ }
+
+if (argc == 2)
+ cfg = new CONFIGFILE(argv[1]);
+else
+ cfg = new CONFIGFILE("/etc/rscriptd/rscriptd.conf");
+
+if (cfg->Error())
+ {
+ auto & WriteServLog = STG::Logger::get();
+ WriteServLog.setFileName("/var/log/rscriptd.log");
+ WriteServLog("Error reading config file!");
+ delete cfg;
+ return EXIT_FAILURE;
+ }
+
+cfg->ReadString("LogFileName", &logFileName, "/var/log/rscriptd.log");
+cfg->ReadInt("ExecutersNum", &execNum, 1);
+cfg->ReadInt("ExecMsgKey", &execMsgKey, 5555);
+cfg->ReadString("ConfigDir", &confDir, "/etc/rscriptd");
+cfg->ReadString("Password", &password, "");
+cfg->ReadInt("Port", &port, 5555);
+cfg->ReadInt("UserTimeout", &userTimeout, 60);
+cfg->ReadString("ScriptOnConnect", &onConnect, "/etc/rscriptd/OnConnect");
+cfg->ReadString("ScriptOnDisconnect", &onDisconnect, "/etc/rscriptd/OnDisconnect");
+
+if (ForkAndWait(confDir) < 0)
+ {
+ auto & WriteServLog = STG::Logger::get();
+ WriteServLog("Fork error!");
+ delete cfg;
+ return EXIT_FAILURE;
+ }
+
+auto & WriteServLog = STG::Logger::get();
+PIDFile pidFile("/var/run/rscriptd.pid");
+WriteServLog.setFileName(logFileName);
+WriteServLog("rscriptd v. %s", SERVER_VERSION);
+
+for (int i = 0; i < execNum; i++)
+ {
+ int ret = StartScriptExecuter(argv[0], execMsgKey, &msgID);
+ if (ret < 0)
+ {
+ STG::Logger::get()("Start Script Executer error!");
+ delete cfg;
+ return EXIT_FAILURE;
+ }
+ if (ret == 1)
+ {
+ delete cfg;
+ return EXIT_SUCCESS;
+ }
+ }
+
+listener = new LISTENER();
+listener->SetPort(port);
+listener->SetPassword(password);
+listener->SetUserTimeout(userTimeout);
+listener->SetScriptOnConnect(onConnect);
+listener->SetScriptOnDisconnect(onDisconnect);
+
+listener->Start();
+
+WriteServLog("rscriptd started successfully.");
+WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+while (true)
+ {
+ sigfillset(&signalSet);
+ int sig = 0;
+ printfd(__FILE__, "Before sigwait\n");
+ sigwait(&signalSet, &sig);
+ printfd(__FILE__, "After sigwait. Signal: %d\n", sig);
+ bool stop = false;
+ switch (sig)
+ {
+ case SIGTERM:
+ stop = true;
+ break;
+ case SIGINT:
+ stop = true;
+ break;
+ default:
+ WriteServLog("Ignore signel %d", sig);
+ break;
+ }
+ if (stop)
+ break;
+ }
+
+listener->Stop();
+
+WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+StopScriptExecuter(msgID);
+
+WriteServLog("rscriptd stopped successfully.");
+WriteServLog("---------------------------------------------");
+
+delete listener;
+delete cfg;
+return EXIT_SUCCESS;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ $Revision: 1.1 $
+ $Date: 2010/02/11 12:32:25 $
+ $Author: faust $
+ */
+
+/*
+ * An implementation of RAII pid-file writer
+ */
+
+#include <fstream>
+#include <unistd.h>
+
+#include "pidfile.h"
+
+PIDFile::PIDFile(const std::string & fn)
+ : fileName(fn)
+{
+if (fileName != "")
+ {
+ std::ofstream pf(fileName.c_str());
+ pf << getpid() << std::endl;
+ pf.close();
+ }
+}
+
+PIDFile::~PIDFile()
+{
+if (fileName != "")
+ {
+ unlink(fileName.c_str());
+ }
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Header file for RAII pid-file writer
+ */
+
+/*
+ $Revision: 1.1 $
+ $Date: 2010/02/11 12:32:25 $
+ $Author: faust $
+ */
+
+#ifndef __PID_FILE_H__
+#define __PID_FILE_H__
+
+#include <string>
+
+class PIDFile {
+public:
+ explicit PIDFile(const std::string & fn);
+ ~PIDFile();
+private:
+ std::string fileName;
+};
+
+#endif
--- /dev/null
+################################################################################
+# Rscriptd Configuration file #
+################################################################################
+
+# LOG file name
+# Parameter: optional
+# Value: file path
+# Default: /var/log/rscriptd.log
+LogFileName = /var/log/rscriptd.log
+
+# Amount of rscriptd-exec processes.
+# These processes are responsible for the execution of scripts
+# OnConnect and OnDisconnect.
+# Amount of processes means how many scripts can be executed simultaneously.
+# Recommend to leave 1 to avoid errors when executing scripts
+# Parameter: optional
+# Value: 1 ... 1024
+# Default: 1
+ExecutersNum = 1
+
+# Message queue identifier for the script executer.
+# It may be changed if there're a needs to run multiple copies of rscriptd.
+# Warning: If you do not understand it, do not touch this setting!
+# Parameter: optional
+# Value: 0 ... 2 ^ 32
+# Default: 5555
+# ExecMsgKey = 5555
+
+# The path to directory where config files are
+# Parameter: optional
+# Value: directory path
+# Default: /etc/rscriptd
+ConfigDir = /etc/rscriptd
+
+# Defines password for the encryption exchange between
+# Stargazer server and rscriptd.
+# Parameter: optional
+# Value: any
+# Default: 123456
+Password = 123456
+
+# Defines port number for communication between
+# Stargazer server and rscriptd.
+# Parameter: optional
+# Value: 1 ... 65535
+# Default: 9999
+Port = 9999
+
+# User timeout. If Stargazer does not respond during this time,
+# the user will be disconnected.
+# Parameter: optional
+# Values: 5 ... 600
+# Default: 60
+UserTimeout = 60
+
+# Defines file which runs when user gets access
+# Parameter: optional
+# Value: file path
+# Default: /etc/rscriptd/OnConnect
+ScriptOnConnect = /etc/rscriptd/OnConnect
+
+# Defines file which runs when user loses access
+# Parameter: optional
+# Value: file path
+# Default: /etc/rscriptd/OnDisconnect
+ScriptOnDisconnect = /etc/rscriptd/OnDisconnect
+
+################################################################################
--- /dev/null
+css.h
+sgauth
--- /dev/null
+set ( CPP_FILES main.cpp settings_impl.cpp web.cpp )
+
+set ( THREADS_PREFER_PTHREAD_FLAG ON )
+find_package ( Threads REQUIRED )
+find_package ( Intl REQUIRED )
+
+file ( READ sgauth.css CSS_DATA )
+configure_file ( css.h.in css.h ESCAPE_QUOTES @ONLY )
+
+set ( CMAKE_INCLUDE_CURRENT_DIR ON )
+
+include_directories ( ${Intl_INCLUDE_DIRS} )
+
+add_executable ( sgauth ${CPP_FILES} )
+
+target_link_libraries ( sgauth conffiles ia crypto common ${Intl_LIBRARIES} Threads::Threads )
+
+# TODO: install
--- /dev/null
+#pragma once
+
+namespace SGAuth
+{
+
+const auto css = R"EOR(
+@CSS_DATA@
+)EOR";
+
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.13 $
+ $Date: 2010/04/14 09:01:29 $
+ $Author: faust $
+ */
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <csignal>
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include <vector>
+
+#include "stg/ia.h"
+#include "stg/common.h"
+#include "web.h"
+#include "settings_impl.h"
+
+int mes;
+char infoText[256];
+char messageText[256];
+
+const int winKOI = 0;
+
+IA_CLIENT_PROT * clnp;
+WEB * web = NULL;
+
+time_t stgTime;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void Usage()
+{
+printf("sgauth <path_to_config>\n");
+}
+//-----------------------------------------------------------------------------
+void SetDirName(const std::vector<std::string> & dn, void *)
+{
+for (int j = 0; j < DIR_NUM; j++)
+ {
+ if (winKOI)
+ {
+ std::string dir;
+ KOIToWin(dn[j], &dir);
+ if (web)
+ web->SetDirName(dir, j);
+ }
+ else
+ {
+ if (web)
+ web->SetDirName(dn[j], j);
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+void StatUpdate(const LOADSTAT & ls, void *)
+{
+if (web)
+ web->UpdateStat(ls);
+}
+//-----------------------------------------------------------------------------
+void StatusChanged(int, void *)
+{
+}
+//-----------------------------------------------------------------------------
+void ShowMessage(const std::string & message, int i, int, int, void *)
+{
+if (web)
+ web->AddMessage(message, i);
+}
+//-----------------------------------------------------------------------------
+void ShowError(const std::string & message, int, void *)
+{
+if (web)
+ web->AddMessage(message, 0);
+}
+//-----------------------------------------------------------------------------
+void CatchUSR1(int)
+{
+if (clnp->GetAuthorized())
+ {
+ std::cout << "Connect" << std::endl;
+ clnp->Connect();
+ }
+}
+//-----------------------------------------------------------------------------
+void CatchUSR2(int)
+{
+std::cout << "Disconnect" << std::endl;
+clnp->Disconnect();
+}
+//-----------------------------------------------------------------------------
+void CatchTERM(int)
+{
+std::cout << "Terminated" << std::endl;
+clnp->Disconnect();
+sleep(2);
+exit(0);
+}
+//-----------------------------------------------------------------------------
+static void SetSignalHandlers()
+{
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR1);
+newsa.sa_handler = CatchUSR1;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR1, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR2);
+newsa.sa_handler = CatchUSR2;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR2, &newsa, &oldsa);
+
+return;
+}
+//-----------------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+SETTINGS_IMPL settings;
+
+if (argc == 2)
+ {
+ settings.SetConfFile(argv[1]);
+ }
+else
+ {
+ // Usage
+ }
+
+if (settings.ReadSettings())
+ {
+ printf("ReadSettingsError\n");
+ printf("%s\n", settings.GetStrError().c_str());
+ exit(-1);
+ }
+settings.Print();
+
+if (settings.GetDaemon())
+ {
+ switch (fork())
+ {
+ case -1:
+ exit(1);
+ break;
+
+ case 0:
+ setsid();
+ break;
+
+ default:
+ exit(0);
+ break;
+ }
+ }
+
+clnp = new IA_CLIENT_PROT(settings.GetServerName(), settings.GetServerPort(), settings.GetLocalName(), settings.GetLocalPort());
+
+if (!settings.GetNoWeb())
+ {
+ web = new WEB();
+ web->SetRefreshPagePeriod(settings.GetRefreshPeriod());
+ web->SetListenAddr(settings.GetListenWebIP());
+ web->Start();
+ }
+
+clnp->SetLogin(settings.GetLogin());
+clnp->SetPassword(settings.GetPassword());
+
+clnp->SetStatusChangedCb(StatusChanged, NULL);
+clnp->SetInfoCb(ShowMessage, NULL);
+clnp->SetErrorCb(ShowError, NULL);
+clnp->SetDirNameCb(SetDirName, NULL);
+clnp->SetStatChangedCb(StatUpdate, NULL);
+clnp->SetReconnect(settings.GetReconnect());
+
+clnp->Start();
+
+SetSignalHandlers();
+
+#ifdef LINUX
+for (int i = 1; i < argc; i++)
+ memset(argv[i], 0, strlen(argv[i]));
+
+if(argc > 1)
+ strcpy(argv[1], "Connecting...");
+#endif
+
+#ifdef FREEBSD
+setproctitle("Connecting...");
+#endif
+clnp->Connect();
+
+while (1)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+
+ char state[20];
+
+ if (clnp->GetAuthorized())
+ {
+ if (settings.GetShowPid())
+ sprintf(state, "On %d", getpid());
+ else
+ strcpy(state, "Online");
+ }
+ else
+ {
+ if (settings.GetShowPid())
+ sprintf(state, "Off %d", getpid());
+ else
+ strcpy(state, "Offline");
+ }
+
+ #ifdef LINUX
+ for (int i = 1; i < argc; i++)
+ memset(argv[i], 0, strlen(argv[i]));
+ if(argc > 1)
+ strcpy(argv[1], state);
+ #endif
+
+ #ifdef FREEBSD
+ setproctitle(state);
+ #endif
+
+ #ifdef FREEBSD_5
+ setproctitle(state);
+ #endif
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 <iostream>
+#include <cstring>
+
+#include "stg/common.h"
+#include "stg/conffiles.h"
+#include "settings_impl.h"
+
+SETTINGS_IMPL::SETTINGS_IMPL()
+ : port(0),
+ localPort(0),
+ listenWebIP(0),
+ refreshPeriod(0),
+ daemon(false),
+ noWeb(false),
+ reconnect(false),
+ showPid(false),
+ confFile("/etc/sgauth.conf")
+{
+}
+//-----------------------------------------------------------------------------
+int SETTINGS_IMPL::ReadSettings()
+{
+CONFIGFILE cf(confFile);
+
+if (cf.Error())
+ {
+ strError = "Cannot read file '" + confFile + "'";
+ return -1;
+ }
+
+cf.ReadString("Login", &login, "/?--?--?*");
+if (login == "/?--?--?*")
+ {
+ strError = "Parameter 'Login' not found.";
+ return -1;
+ }
+
+cf.ReadString("Password", &password, "/?--?--?*");
+if (login == "/?--?--?*")
+ {
+ strError = "Parameter 'Password' not found.";
+ return -1;
+ }
+
+cf.ReadString("ServerName", &serverName, "?*?*?");
+if (serverName == "?*?*?")
+ {
+ strError = "Parameter 'ServerName' not found.";
+ return -1;
+ }
+
+std::string temp;
+cf.ReadString("ListenWebIP", &temp, "127.0.0.1");
+listenWebIP = inet_strington(temp);
+if (listenWebIP == 0)
+ {
+ strError = "Parameter 'ListenWebIP' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("ServerPort", &temp, "5555");
+if (ParseIntInRange(temp, 1, 65535, &port))
+ {
+ strError = "Parameter 'ServerPort' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("LocalName", &localName, "");
+
+cf.ReadString("LocalPort", &temp, "0");
+if (ParseIntInRange(temp, 0, 65535, &localPort))
+ {
+ strError = "Parameter 'LocalPort' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("RefreshPeriod", &temp, "5");
+if (ParseIntInRange(temp, 1, 24*3600, &refreshPeriod))
+ {
+ strError = "Parameter 'RefreshPeriod' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("Reconnect", &temp, "yes");
+if (ParseYesNo(temp, &reconnect))
+ {
+ strError = "Parameter 'Reconnect' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("Daemon", &temp, "yes");
+if (ParseYesNo(temp, &daemon))
+ {
+ strError = "Parameter 'Daemon' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("ShowPid", &temp, "no");
+if (ParseYesNo(temp, &showPid))
+ {
+ strError = "Parameter 'ShowPid' is not valid.";
+ return -1;
+ }
+
+cf.ReadString("DisableWeb", &temp, "no");
+if (ParseYesNo(temp, &noWeb))
+ {
+ strError = "Parameter 'DisableWeb' is not valid.";
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void SETTINGS_IMPL::Print() const
+{
+std::cout << "Login = " << login << "\n"
+ << "Password = " << password << "\n"
+ << "Ip = " << serverName << "\n"
+ << "Port = " << port << "\n"
+ << "LocalPort = " << localPort << "\n"
+ << "ListenWebIP = " << inet_ntostring(listenWebIP) << "\n"
+ << "RefreshPeriod = " << refreshPeriod << "\n"
+ << "Daemon = " << daemon << "\n"
+ << "DisableWeb = " << noWeb << "\n"
+ << "Reconnect = " << reconnect << "\n"
+ << "ShowPid = " << showPid << std::endl;
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#ifndef SETTINGS_IMPL_H
+#define SETTINGS_IMPL_H
+
+#include <string>
+#include <cstdint>
+
+class SETTINGS_IMPL {
+public:
+ SETTINGS_IMPL();
+ ~SETTINGS_IMPL() {}
+ int Reload() { return 0; }
+ void SetConfFile(const std::string & cf) { confFile = cf; }
+ int ReadSettings();
+
+ const std::string & GetStrError() const { return strError; }
+
+ const std::string & GetServerName() const { return serverName; }
+ uint16_t GetServerPort() const { return port; }
+ const std::string & GetLocalName() const { return localName; }
+ uint16_t GetLocalPort() const { return localPort; }
+
+ const std::string & GetLogin() const { return login; }
+ const std::string & GetPassword() const { return password; }
+
+ bool GetDaemon() const { return daemon; }
+ bool GetShowPid() const { return showPid; }
+ bool GetNoWeb() const { return noWeb; }
+ bool GetReconnect() const { return reconnect; }
+ int GetRefreshPeriod() const { return refreshPeriod; }
+ uint32_t GetListenWebIP() const { return listenWebIP; }
+
+ void Print() const;
+
+private:
+ std::string login;
+ std::string password;
+ std::string serverName;
+ int port;
+ std::string localName;
+ int localPort;
+ uint32_t listenWebIP;
+ int refreshPeriod;
+
+ bool daemon;
+ bool noWeb;
+ bool reconnect;
+ bool showPid;
+
+ std::string confFile;
+ std::string strError;
+};
+
+#endif
--- /dev/null
+################################################################################
+# Sgauth Configuration file #
+################################################################################
+
+# Stargazer server
+# Parameter: required
+# Values: IP address or DNS name
+# Default:
+ServerName = 192.168.1.2
+
+# Port on which Stargazer interacts with sgauth
+# Parameter: optional
+# Value: 1 ... 65535
+# Default: 5555
+ServerPort = 5555
+
+# User's login in Stargazer
+# Parameter: required
+# Value: any
+# Default:
+Login = test
+
+# Local host to bind
+# Parameter: optional
+# Values: IP address or DNS name
+# Default: 0.0.0.0
+LocalName = localhost
+
+# Port on which sgauth interacts with Stargazer
+# Parameter: optional
+# Value: 1 ... 65535
+# Default: 0
+LocalPort = 12345
+
+# User's password in Stargazer
+# Parameter: required
+# Value: any
+# Default:
+Password = 123456
+
+# Defines whether sgauth should try to reestablish connection to Stargazer
+# if it was lost
+# Parameter: optional
+# Value: yes, no
+# Default: yes
+Reconnect = yes
+
+# Defines whether sgauth should run as daemon
+# Parameter: optional
+# Value: yes, no
+# Default: yes
+Daemon = yes
+
+# Web-page refresh period in built-in webserver
+# Parameter: optional
+# Value: any numeric (minutes)
+# Default: 10
+RefreshPeriod = 10
+
+# Defines whether sgauth should use built-in webserver
+# Parameter: optional
+# Value: yes, no
+# Default: no
+DisableWeb = no
+
+# Defines address on which sgauth's built-in webserver will listen
+# Parameter: optional
+# Value: IP address or DNS name
+# Default: 127.0.0.1
+ListenWebIP = 127.0.0.1
+
+# Defines whether sgauth should show its process ID
+# Parameter: optional
+# Value: yes, no
+# Default: no
+ShowPid = no
+
+################################################################################
--- /dev/null
+H3
+{
+color: black;
+}
+
+body
+{
+background-color: silver;
+}
+
+#TraffTable
+{
+background-color: white;
+}
+
+#TraffTableCaptionRow
+{
+background-color: silver;
+}
+
+#TraffTableCaptionCellC,
+#TraffTableUMCellC,
+#TraffTableDMCellC,
+#TraffTableUSCellC,
+#TraffTableDSCellC
+{
+background-color: silver;
+}
+
+#TraffTableDMRow,
+#TraffTableDSRow
+{
+background-color: #f2f0cc;
+}
+
+#TraffTableUMRow,
+#TraffTableUSRow
+{
+background-color: white;
+}
+
+#ConnectionStateOnline
+{
+color: green;
+font-size: 20px
+}
+
+#ConnectionStateOffline
+{
+color: red;
+font-size: 20px
+}
+
+p
+{
+padding: 2px;
+margin: 0px;
+}
+
+#MessagesTable
+{
+background-color: white;
+}
+
+#MessagesTableRowC
+{
+background-color: silver;
+}
+
+
+#MessagesTableRow0,
+#MessagesTableRow2,
+#MessagesTableRow4,
+#MessagesTableRow6,
+#MessagesTableRow8
+{
+background-color: #f2f0cc;
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.7 $
+ $Date: 2010/03/15 12:58:17 $
+ */
+
+#include <libintl.h>
+
+#include <csignal>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+
+#include "stg/common.h"
+#include "stg/ia.h"
+#include "web.h"
+
+extern WEB * web;
+extern IA_CLIENT_PROT * clnp;
+
+#define LISTEN_PORT (5580)
+
+#include "css.h"
+
+//---------------------------------------------------------------------------
+#ifndef WIN32
+void * RunWeb(void *)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+#else
+unsigned long WINAPI RunWeb(void *)
+{
+#endif
+while (1)
+ web->Run();
+return NULL;
+}
+//---------------------------------------------------------------------------
+WEB::WEB()
+ : res(0),
+ listenSocket(0),
+ outerSocket(0),
+ refreshPeriod(0),
+ listenWebAddr(0)
+{
+#ifdef WIN32
+res = WSAStartup(MAKEWORD(2,0), &wsaData);
+#endif
+
+for (int i = 0; i < DIR_NUM; i++)
+ dirName[i] = "-";
+
+refreshPeriod = 5;
+
+memset(&ls, 0, sizeof(ls));
+}
+//---------------------------------------------------------------------------
+void WEB::Start()
+{
+#ifdef WIN32
+unsigned long pt;
+CreateThread(
+ NULL, // pointer to thread security attributes
+ 16384, // initial thread stack size, in bytes
+ RunWeb, // pointer to thread function
+ NULL, // argument for new thread
+ 0, // CREATE_SUSPENDED, // creation flags
+ &pt // pointer to returned thread identifier
+ );
+#else
+pthread_create(&thread, NULL, RunWeb, NULL);
+#endif
+}
+//---------------------------------------------------------------------------
+void WEB::PrepareNet()
+{
+listenSocket = socket(PF_INET, SOCK_STREAM, 0);
+
+struct sockaddr_in listenAddr;
+listenAddr.sin_family = AF_INET;
+listenAddr.sin_port = htons(LISTEN_PORT);
+listenAddr.sin_addr.s_addr = listenWebAddr;
+
+#ifndef WIN32
+int lng = 1;
+if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
+ {
+ printf("Setsockopt Fail\n");
+ printf(">>> Error %s\n", strerror(errno));
+ }
+#else
+//??? TODO
+#endif
+
+
+res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
+
+if (res == -1)
+ {
+ printf("Bind failed.\n");
+ exit(0);
+ }
+
+res = listen(listenSocket, 0);
+if (res == -1)
+ {
+ printf("Listen failed.\n");
+ exit(0);
+ }
+}
+//---------------------------------------------------------------------------
+void WEB::SetRefreshPagePeriod(int p)
+{
+refreshPeriod = p;
+if (refreshPeriod <= 0 || refreshPeriod > 24*3600)
+ refreshPeriod = 5;
+}
+//---------------------------------------------------------------------------
+void WEB::SetListenAddr(uint32_t ip)
+{
+listenWebAddr = ip;
+}
+//---------------------------------------------------------------------------
+void WEB::Run()
+{
+PrepareNet();
+char recvBuffer[4096];
+while (1)
+ {
+ struct sockaddr_in outerAddr;
+
+ #ifndef WIN32
+ socklen_t outerAddrLen = sizeof(outerAddr);
+ #else
+ int outerAddrLen = sizeof(outerAddr);
+ #endif
+
+ outerSocket = accept(listenSocket, (struct sockaddr*)&outerAddr, &outerAddrLen);
+ if (outerSocket == -1)
+ {
+ printf(">>> Error %s\n", strerror(errno));
+ continue;
+ }
+ recv(outerSocket, recvBuffer, sizeof(recvBuffer), 0);
+
+ if (strncmp(recvBuffer, "GET /sgauth.css", strlen("GET /sgauth.css")) == 0)
+ {
+ SendCSS();
+ //printf("(1) recvBuffer=%s\n", recvBuffer);
+ }
+ else if (strncmp(recvBuffer, "GET /disconnect", strlen("GET /disconnect")) == 0)
+ {
+ clnp->Disconnect();
+ Redirect("/");
+ //printf("(2) recvBuffer=%s\n", recvBuffer);
+ }
+ else if (strncmp(recvBuffer, "GET /connect", strlen("GET /connect")) == 0)
+ {
+ clnp->Connect();
+ Redirect("/");
+ //printf("(3) recvBuffer=%s\n", recvBuffer);
+ }
+ else if (strncmp(recvBuffer, "GET /exit", strlen("GET /exit")) == 0)
+ {
+ Redirect("/");
+ clnp->Disconnect();
+ #ifdef WIN32
+ Sleep(1000);
+ #else
+ struct timespec ts = {1, 0};
+ nanosleep(&ts, NULL);
+ #endif
+ exit(0);
+ }
+ else
+ {
+ SendReply();
+ //printf("(4) recvBuffer=%s\n", recvBuffer);
+ }
+
+ #ifdef WIN32
+ closesocket(outerSocket);
+ #else
+ close(outerSocket);
+ #endif
+ }
+}
+//---------------------------------------------------------------------------
+int WEB::Redirect(const char * url)
+{
+const char * redirect =
+ "HTTP/1.0 200 OK\n"
+ "Content-Type: text/html\n"
+ "Connection: close"
+ "\n\n"
+ "<html>\n"
+ "<head>\n"
+ "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;%s\">\n"
+ "</head>\n"
+ "<body>\n"
+ "</body></html>\n\n";
+
+char buff[2000];
+sprintf(buff, redirect, url);
+send(outerSocket, buff, strlen(buff), 0);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int WEB::SendReply()
+{
+int j, rowNum;
+
+const char * replyHeader =
+ "HTTP/1.0 200 OK\n"
+ "Content-Type: text/html\n"
+ "Connection: close"
+ "\n\n"
+ "<html>\n"
+ "<head>\n"
+ "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">\n"
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">\n"
+ "<title>sgauth</title>\n"
+ "<link rel=\"Stylesheet\" href=\"sgauth.css\">"
+ "</head>\n"
+ "<body>\n"
+ "<H3>Stargazer</H3><p>\n";
+
+const char * replyFooter = "</body></html>\n\n";
+
+char replyHeaderBuffer[2000];
+sprintf(replyHeaderBuffer, replyHeader, refreshPeriod);
+
+send(outerSocket, replyHeaderBuffer, strlen(replyHeaderBuffer), 0);
+
+char str[512];
+
+int st = clnp->GetAuthorized();
+
+sprintf(str, "<a href=\"connect\">%s</a><p>\n", gettext("Connect"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<a href=\"disconnect\">%s</a><p>\n", gettext("Disconnect"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<a href=\"/\">%s</a><p>\n", gettext("Refresh"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<a href=\"exit\">%s</a><p>\n", gettext("Exit"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<div id=\"%s\">%s</div><p>\n" , st ? "ConnectionStateOnline":"ConnectionStateOffline", st ? "Online":"Offline");
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<div id=\"Cash\">%s: %.3f</div><p>\n" , gettext("Cash"), ls.cash / 1000.0);
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<div id=\"Prepaid Traffic\">%s: %s</div><p>\n" ,
+ gettext("PrepaidTraffic"),
+ ls.freeMb[0] == 'C' ? ls.freeMb + 1 : ls.freeMb);
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<TABLE id=\"TraffTable\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str, " <TR id=\"TraffTableCaptionRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str, " <TD id=\"TraffTableCaptionCellC\"> </TD>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+ {
+ if (dirName[j][0] == 0)
+ continue;
+ std::string s;
+ KOIToWin(dirName[j], &s);// +++++++++ sigsegv ========== TODO too long dir name crashes sgauth
+ sprintf(str, " <TD id=\"TraffTableCaptionCell%d\">%s</TD>\n", rowNum++, s.c_str());
+ send(outerSocket, str, strlen(str), 0);
+ }
+
+sprintf(str," </TR>\n");
+send(outerSocket, str, strlen(str), 0);
+
+sprintf(str," <TR id=\"TraffTableUMRow\">\n");
+send(outerSocket, str, strlen(str), 0);
+
+sprintf(str," <TD id=\"TraffTableUMCellC\">%s</TD>\n", gettext("Month Upload"));
+send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+ {
+ if (dirName[j][0] == 0)
+ continue;
+ sprintf(str," <TD id=\"TraffTableUMCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.mu[j], ST_F));
+ res = send(outerSocket, str, strlen(str), 0);
+ }
+
+sprintf(str," </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str," <TR id=\"TraffTableDMRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str," <TD id=\"TraffTableDMCellC\">%s</TD>\n", gettext("Month Download"));
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+ {
+ if (dirName[j][0] == 0)
+ continue;
+ sprintf(str," <TD id=\"TraffTableDMCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.md[j], ST_F));
+ res = send(outerSocket, str, strlen(str), 0);
+ }
+sprintf(str," </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+
+sprintf(str," <TR id=\"TraffTableUSRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str," <TD id=\"TraffTableUSCellC\">%s</TD>\n", gettext("Session Upload"));
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+ {
+ if (dirName[j][0] == 0)
+ continue;
+ sprintf(str," <TD id=\"TraffTableUSCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.su[j], ST_F));
+ res = send(outerSocket, str, strlen(str), 0);
+ }
+
+sprintf(str," </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str," <TR id=\"TraffTableDSRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str," <TD id=\"TraffTableDSCellC\">%s</TD>\n", gettext("Session Download"));
+res = send(outerSocket, str, strlen(str), 0);
+
+for (j = 0; j < DIR_NUM; j++)
+ {
+ if (dirName[j][0] == 0)
+ continue;
+ sprintf(str," <TD id=\"TraffTableDSCell%d\">%s</TD>\n", j, IntToKMG(ls.sd[j], ST_F));
+ res = send(outerSocket, str, strlen(str), 0);
+ }
+
+sprintf(str," </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str,"</TABLE>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+if (!messages.empty())
+ {
+ sprintf(str," <TABLE id=\"MessagesTable\">\n");
+ res = send(outerSocket, str, strlen(str), 0);
+
+ sprintf(str," <TR id=\"MessagesTableRowC\">\n");
+ send(outerSocket, str, strlen(str), 0);
+ sprintf(str," <TD>Date</TD>\n");
+ send(outerSocket, str, strlen(str), 0);
+ sprintf(str," <TD>Text</TD>\n");
+ send(outerSocket, str, strlen(str), 0);
+ sprintf(str," </TR>\n");
+ send(outerSocket, str, strlen(str), 0);
+
+ std::list<STG_MESSAGE>::reverse_iterator it;
+ it = messages.rbegin();
+ while (it != messages.rend())
+ {
+ sprintf(str," <TR id=\"MessagesTableRow%d\">\n", rowNum);
+ send(outerSocket, str, strlen(str), 0);
+ sprintf(str," <TD>%s</TD>\n", it->recvTime.c_str());
+ send(outerSocket, str, strlen(str), 0);
+ sprintf(str," <TD>%s</TD>\n", it->msg.c_str());
+ send(outerSocket, str, strlen(str), 0);
+ sprintf(str," </TR>\n");
+ send(outerSocket, str, strlen(str), 0);
+ ++it;
+ ++rowNum;
+ }
+
+ sprintf(str," </TABLE>\n");
+ res = send(outerSocket, str, strlen(str), 0);
+ }
+
+time_t t = time(NULL);
+sprintf(str,"Îáíîâëåíî: %s</b>" , ctime(&t));
+res = send(outerSocket, str, strlen(str), 0);
+
+send(outerSocket, replyFooter, strlen(replyFooter), 0);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int WEB::SendCSS()
+{
+const char * replyHeader =
+ "HTTP/1.0 200 OK\n"
+ "Content-Type: text/css\n"
+ "Connection: close\n\n";
+
+const char * replyFooter= "\n\n";
+
+send(outerSocket, replyHeader, strlen(replyHeader), 0);
+send(outerSocket, SGAuth::css, strlen(SGAuth::css), 0);
+send(outerSocket, replyFooter, strlen(replyFooter), 0);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+void WEB::SetDirName(const std::string & dn, int n)
+{
+web->dirName[n] = dn;
+}
+//---------------------------------------------------------------------------
+void WEB::AddMessage(const std::string & message, int type)
+{
+time_t t = time(NULL);
+STG_MESSAGE m;
+
+m.msg = message;
+m.type = type;
+m.recvTime = ctime(&t);
+
+messages.push_back(m);
+
+if (messages.size() > MAX_MESSAGES)
+ messages.pop_front();
+
+}
+//---------------------------------------------------------------------------
+void WEB::UpdateStat(const LOADSTAT & ls)
+{
+memcpy((void*)&(WEB::ls), &ls, sizeof(LOADSTAT));
+}
+//---------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.3 $
+ $Date: 2007/12/17 08:39:08 $
+ */
+
+#ifndef WIN32
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#else
+#include <winsock2.h>
+#endif
+
+#include <string>
+#include <list>
+
+#include "stg/const.h"
+#include "stg/ia_packets.h"
+
+#define MAX_MESSAGES (10)
+//-----------------------------------------------------------------------------
+struct STG_MESSAGE
+{
+std::string msg;
+std::string recvTime;
+int type;
+};
+//-----------------------------------------------------------------------------
+class WEB
+{
+public:
+ WEB();
+ void Run();
+ void SetDirName(const std::string & dn, int n);
+ void SetRefreshPagePeriod(int p);
+ void SetListenAddr(uint32_t ip);
+ void AddMessage(const std::string & message, int type);
+ void UpdateStat(const LOADSTAT & ls);
+ void Start();
+private:
+ void PrepareNet();
+ int SendReply();
+ int SendCSS();
+ int Redirect(const char * url);
+
+ #ifdef WIN32
+ WSADATA wsaData;
+ #else
+ pthread_t thread;
+ #endif
+
+ std::string dirName[DIR_NUM];
+ int res;
+ int listenSocket;
+ int outerSocket;
+ int refreshPeriod;
+
+ uint32_t listenWebAddr;
+ LOADSTAT ls;
+
+ std::list<STG_MESSAGE> messages;
+};
+//-----------------------------------------------------------------------------
--- /dev/null
+find_package ( EXPAT REQUIRED )
+
+set ( CPP_FILES main.cpp options.cpp api_action.cpp actions.cpp admins.cpp tariffs.cpp users.cpp services.cpp corps.cpp info.cpp xml.cpp )
+
+set ( THREADS_PREFER_PTHREAD_FLAG ON )
+find_package ( Threads REQUIRED )
+
+add_executable ( sgconf ${CPP_FILES} )
+
+target_link_libraries ( sgconf srvconf crypto common EXPAT::EXPAT )
+
+# TODO: install
--- /dev/null
+Compiling:
+> ./build
+
+
--- /dev/null
+1. No default value for server.
+2. No default value for port.
--- /dev/null
+/*
+ * 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>
+ */
+
+#ifndef __STG_SGCONF_ACTION_H__
+#define __STG_SGCONF_ACTION_H__
+
+#include <string>
+#include <map>
+#include <stdexcept>
+
+namespace SGCONF
+{
+
+class OPTION_BLOCK;
+struct PARSER_STATE;
+struct CONFIG;
+
+class ACTION
+{
+ public:
+ virtual ~ACTION() {}
+
+ virtual ACTION * Clone() const = 0;
+ virtual std::string ParamDescription() const = 0;
+ virtual std::string DefaultDescription() const = 0;
+ virtual OPTION_BLOCK & Suboptions() = 0;
+ virtual PARSER_STATE Parse(int argc, char ** argv, void * data = NULL) = 0;
+ virtual void ParseValue(const std::string &) {}
+
+ class ERROR : public std::runtime_error
+ {
+ public:
+ ERROR(const std::string & message)
+ : std::runtime_error(message.c_str()) {}
+ };
+};
+
+} // namespace SGCONF
+
+#endif
--- /dev/null
+/*
+ * 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>
+ */
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "action.h"
+#include "options.h"
+#include "parser_state.h"
+
+#include "stg/common.h"
+#include "stg/optional.h"
+
+#include <string>
+
+#include <cassert>
+
+namespace SGCONF
+{
+
+typedef void (* FUNC0)();
+
+template <typename F>
+class FUNC0_ACTION : public ACTION
+{
+ public:
+ FUNC0_ACTION(const F & func) : m_func(func) {}
+
+ virtual ACTION * Clone() const { return new FUNC0_ACTION<F>(*this); }
+
+ virtual std::string ParamDescription() const { return ""; }
+ virtual std::string DefaultDescription() const { return ""; }
+ virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+ virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/)
+ {
+ m_func();
+ return PARSER_STATE(true, argc, argv);
+ }
+
+ private:
+ F m_func;
+ OPTION_BLOCK m_suboptions;
+};
+
+template <typename F>
+inline
+FUNC0_ACTION<F> * MakeFunc0Action(F func)
+{
+return new FUNC0_ACTION<F>(func);
+}
+
+template <typename T>
+class PARAM_ACTION : public ACTION
+{
+ public:
+ PARAM_ACTION(STG::Optional<T> & param,
+ const T & defaultValue,
+ const std::string & paramDescription)
+ : m_param(param),
+ m_defaltValue(defaultValue),
+ m_description(paramDescription),
+ m_hasDefault(true)
+ {}
+ PARAM_ACTION(STG::Optional<T> & param)
+ : m_param(param),
+ m_hasDefault(false)
+ {}
+ PARAM_ACTION(STG::Optional<T> & param,
+ const std::string & paramDescription)
+ : m_param(param),
+ m_description(paramDescription),
+ m_hasDefault(false)
+ {}
+
+ virtual ACTION * Clone() const { return new PARAM_ACTION<T>(*this); }
+
+ virtual std::string ParamDescription() const { return m_description; }
+ virtual std::string DefaultDescription() const;
+ virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+ virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
+ virtual void ParseValue(const std::string & value);
+
+ private:
+ STG::Optional<T> & m_param;
+ T m_defaltValue;
+ std::string m_description;
+ bool m_hasDefault;
+ OPTION_BLOCK m_suboptions;
+};
+
+template <typename T>
+inline
+std::string PARAM_ACTION<T>::DefaultDescription() const
+{
+return m_hasDefault ? " (default: '" + std::to_string(m_defaltValue) + "')"
+ : "";
+}
+
+template <>
+inline
+std::string PARAM_ACTION<std::string>::DefaultDescription() const
+{
+return m_hasDefault ? " (default: '" + m_defaltValue + "')"
+ : "";
+}
+
+template <typename T>
+inline
+PARSER_STATE PARAM_ACTION<T>::Parse(int argc, char ** argv, void * /*data*/)
+{
+if (argc == 0 ||
+ argv == NULL ||
+ *argv == NULL)
+ throw ERROR("Missing argument.");
+T value;
+if (str2x(*argv, value))
+ throw ERROR(std::string("Bad argument: '") + *argv + "'");
+m_param = value;
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+template <>
+inline
+PARSER_STATE PARAM_ACTION<bool>::Parse(int argc, char ** argv, void * /*data*/)
+{
+m_param = true;
+return PARSER_STATE(false, argc, argv);
+}
+
+template <typename T>
+inline
+void PARAM_ACTION<T>::ParseValue(const std::string & stringValue)
+{
+if (stringValue.empty())
+ throw ERROR("Missing value.");
+T value;
+if (str2x(stringValue, value))
+ throw ERROR(std::string("Bad value: '") + stringValue + "'");
+m_param = value;
+}
+
+template <>
+inline
+void PARAM_ACTION<std::string>::ParseValue(const std::string & stringValue)
+{
+m_param = stringValue;
+}
+
+template <>
+inline
+PARSER_STATE PARAM_ACTION<std::string>::Parse(int argc, char ** argv, void * /*data*/)
+{
+if (argc == 0 ||
+ argv == NULL ||
+ *argv == NULL)
+ throw ERROR("Missing argument.");
+m_param = *argv;
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(STG::Optional<T> & param,
+ const T & defaultValue,
+ const std::string & paramDescription)
+{
+return new PARAM_ACTION<T>(param, defaultValue, paramDescription);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(STG::Optional<T> & param)
+{
+return new PARAM_ACTION<T>(param);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(STG::Optional<T> & param,
+ const std::string & paramDescription)
+{
+return new PARAM_ACTION<T>(param, paramDescription);
+}
+
+class KV_ACTION : public ACTION
+{
+ public:
+ KV_ACTION(const std::string & name,
+ const std::string & paramDescription)
+ : m_name(name),
+ m_description(paramDescription)
+ {}
+
+ virtual ACTION * Clone() const { return new KV_ACTION(*this); }
+
+ virtual std::string ParamDescription() const { return m_description; }
+ virtual std::string DefaultDescription() const { return ""; }
+ virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+ virtual PARSER_STATE Parse(int argc, char ** argv, void * data);
+
+ private:
+ std::string m_name;
+ std::string m_description;
+ OPTION_BLOCK m_suboptions;
+};
+
+inline
+PARSER_STATE KV_ACTION::Parse(int argc, char ** argv, void * data)
+{
+if (argc == 0 ||
+ argv == NULL ||
+ *argv == NULL)
+ throw ERROR("Missing argument.");
+assert(data != NULL && "Expecting container pointer.");
+std::map<std::string, std::string> & kvs = *static_cast<std::map<std::string, std::string>*>(data);
+kvs[m_name] = *argv;
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+inline
+KV_ACTION * MakeKVAction(const std::string & name,
+ const std::string & paramDescription)
+{
+return new KV_ACTION(name, paramDescription);
+}
+
+} // namespace SGCONF
--- /dev/null
+#include "admins.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+#include "utils.h"
+
+#include "stg/servconf.h"
+#include "stg/servconf_types.h"
+#include "stg/admin_conf.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+#include <cstdint>
+#include <cassert>
+
+namespace
+{
+
+std::string Indent(size_t level, bool dash = false)
+{
+if (level == 0)
+ return "";
+return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
+}
+
+std::string PrivToString(const STG::Priv& priv)
+{
+return std::string("") +
+ (priv.corpChg ? "1" : "0") +
+ (priv.serviceChg ? "1" : "0") +
+ (priv.tariffChg ? "1" : "0") +
+ (priv.adminChg ? "1" : "0") +
+ (priv.userAddDel ? "1" : "0") +
+ (priv.userPasswd ? "1" : "0") +
+ (priv.userCash ? "1" : "0") +
+ (priv.userConf ? "1" : "0") +
+ (priv.userStat ? "1" : "0");
+}
+
+void PrintAdmin(const STG::GetAdmin::Info & info, size_t level = 0)
+{
+std::cout << Indent(level, true) << "login: " << info.login << "\n"
+ << Indent(level) << "priviledges: " << PrivToString(info.priv) << "\n";
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetAdminParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "password"));
+params.push_back(SGCONF::API_ACTION::PARAM("priv", "<priv>", "priviledges"));
+return params;
+}
+
+void ConvPriv(const std::string & value, STG::Optional<STG::Priv> & res)
+{
+if (value.length() != 9)
+ throw SGCONF::ACTION::ERROR("Priviledges value should be a 9-digits length binary number.");
+STG::Priv priv;
+priv.corpChg = (value[0] == '0' ? 0 : 1);
+priv.serviceChg = (value[1] == '0' ? 0 : 1);
+priv.tariffChg = (value[2] == '0' ? 0 : 1);
+priv.adminChg = (value[3] == '0' ? 0 : 1);
+priv.userAddDel = (value[4] == '0' ? 0 : 1);
+priv.userPasswd = (value[5] == '0' ? 0 : 1);
+priv.userCash = (value[6] == '0' ? 0 : 1);
+priv.userConf = (value[7] == '0' ? 0 : 1);
+priv.userStat = (value[8] == '0' ? 0 : 1);
+res = priv;
+}
+
+void SimpleCallback(bool result,
+ const std::string & reason,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Success.\n";
+}
+
+void GetAdminsCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetAdmin::Info> & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get admin list. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Admins:\n";
+for (size_t i = 0; i < info.size(); ++i)
+ PrintAdmin(info[i], 1);
+}
+
+void GetAdminCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetAdmin::Info> & info,
+ void * data)
+{
+assert(data != NULL && "Expecting pointer to std::string with the admin's login.");
+const std::string & login = *static_cast<const std::string *>(data);
+if (!result)
+ {
+ std::cerr << "Failed to get admin. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+for (size_t i = 0; i < info.size(); ++i)
+ if (info[i].login == login)
+ PrintAdmin(info[i]);
+}
+
+
+bool GetAdminsFunction(const SGCONF::CONFIG & config,
+ const std::string & /*arg*/,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetAdmins(GetAdminsCallback, NULL) == STG::st_ok;
+}
+
+bool GetAdminFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+// STG currently doesn't support <GetAdmin login="..."/>.
+// So get a list of admins and filter it. 'data' param holds a pointer to 'login'.
+std::string login(arg);
+return proto.GetAdmins(GetAdminCallback, &login) == STG::st_ok;
+}
+
+bool DelAdminFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.DelAdmin(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddAdminFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::AdminConfOpt conf;
+conf.login = arg;
+SGCONF::MaybeSet(options, "priv", conf.priv, ConvPriv);
+SGCONF::MaybeSet(options, "password", conf.password);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.AddAdmin(arg, conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgAdminFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::AdminConfOpt conf;
+conf.login = arg;
+SGCONF::MaybeSet(options, "priv", conf.priv, ConvPriv);
+SGCONF::MaybeSet(options, "password", conf.password);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.ChgAdmin(conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendAdminsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetAdminParams());
+blocks.Add("Admin management options")
+ .Add("get-admins", SGCONF::MakeAPIAction(commands, GetAdminsFunction), "\tget admin list")
+ .Add("get-admin", SGCONF::MakeAPIAction(commands, "<login>", GetAdminFunction), "get admin")
+ .Add("add-admin", SGCONF::MakeAPIAction(commands, "<login>", params, AddAdminFunction), "add admin")
+ .Add("del-admin", SGCONF::MakeAPIAction(commands, "<login>", DelAdminFunction), "del admin")
+ .Add("chg-admin", SGCONF::MakeAPIAction(commands, "<login>", params, ChgAdminFunction), "change admin");
+}
--- /dev/null
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendAdminsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+} // namespace SGCONF
--- /dev/null
+#include "api_action.h"
+
+#include "actions.h"
+#include "parser_state.h"
+
+SGCONF::PARSER_STATE SGCONF::API_ACTION::Parse(int argc, char ** argv, void * /*data*/)
+{
+PARSER_STATE state(false, argc, argv);
+if (!m_argument.empty())
+ {
+ if (argc == 0 ||
+ argv == NULL ||
+ *argv == NULL)
+ throw ERROR("Missing argument.");
+ m_argument = *argv;
+ --state.argc;
+ ++state.argv;
+ }
+state = m_suboptions.Parse(state.argc, state.argv, &m_params);
+m_commands.Add(m_funPtr, m_argument, m_params);
+return state;
+}
+
+SGCONF::API_ACTION::API_ACTION(COMMANDS & commands,
+ const std::string & paramDescription,
+ bool needArgument,
+ const std::vector<PARAM> & params,
+ API_FUNCTION funPtr)
+ : m_commands(commands),
+ m_description(paramDescription),
+ m_argument(needArgument ? "1" : ""), // Hack
+ m_funPtr(funPtr)
+{
+std::vector<PARAM>::const_iterator it(params.begin());
+while (it != params.end())
+ {
+ m_suboptions.Add(it->name, MakeKVAction(it->name, it->shortDescr), it->longDescr);
+ ++it;
+ }
+}
--- /dev/null
+#ifndef __STG_SGCONF_API_ACTION_H__
+#define __STG_SGCONF_API_ACTION_H__
+
+#include "action.h"
+
+#include "options.h"
+
+#include <string>
+#include <map>
+#include <vector>
+
+namespace SGCONF
+{
+
+typedef bool (* API_FUNCTION) (const CONFIG &,
+ const std::string &,
+ const std::map<std::string, std::string> &);
+
+class COMMAND
+{
+ public:
+ COMMAND(API_FUNCTION funPtr,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+ : m_funPtr(funPtr),
+ m_arg(arg),
+ m_options(options)
+ {}
+ bool Execute(const SGCONF::CONFIG & config) const
+ {
+ return m_funPtr(config, m_arg, m_options);
+ }
+
+ private:
+ API_FUNCTION m_funPtr;
+ std::string m_arg;
+ std::map<std::string, std::string> m_options;
+};
+
+class COMMANDS
+{
+ public:
+ void Add(API_FUNCTION funPtr,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options) { m_commands.push_back(COMMAND(funPtr, arg, options)); }
+ bool Execute(const SGCONF::CONFIG & config) const
+ {
+ std::vector<COMMAND>::const_iterator it(m_commands.begin());
+ bool res = true;
+ while (it != m_commands.end() && res)
+ {
+ res = res && it->Execute(config);
+ ++it;
+ }
+ return res;
+ }
+ private:
+ std::vector<COMMAND> m_commands;
+};
+
+class API_ACTION : public ACTION
+{
+ public:
+ struct PARAM
+ {
+ PARAM(const std::string & n,
+ const std::string & s,
+ const std::string & l)
+ : name(n),
+ shortDescr(s),
+ longDescr(l)
+ {}
+ std::string name;
+ std::string shortDescr;
+ std::string longDescr;
+ };
+
+ API_ACTION(COMMANDS & commands,
+ const std::string & paramDescription,
+ bool needArgument,
+ const std::vector<PARAM> & params,
+ API_FUNCTION funPtr);
+ API_ACTION(COMMANDS & commands,
+ const std::string & paramDescription,
+ bool needArgument,
+ API_FUNCTION funPtr)
+ : m_commands(commands),
+ m_description(paramDescription),
+ m_argument(needArgument ? "1" : ""), // Hack
+ m_funPtr(funPtr)
+ {}
+
+ virtual ACTION * Clone() const { return new API_ACTION(*this); }
+
+ virtual std::string ParamDescription() const { return m_description; }
+ virtual std::string DefaultDescription() const { return ""; }
+ virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+ virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
+
+ private:
+ COMMANDS & m_commands;
+ std::string m_description;
+ std::string m_argument;
+ OPTION_BLOCK m_suboptions;
+ std::map<std::string, std::string> m_params;
+ API_FUNCTION m_funPtr;
+};
+
+inline
+ACTION * MakeAPIAction(COMMANDS & commands,
+ const std::string & paramDescription,
+ const std::vector<API_ACTION::PARAM> & params,
+ API_FUNCTION funPtr)
+{
+return new API_ACTION(commands, paramDescription, true, params, funPtr);
+}
+
+inline
+ACTION * MakeAPIAction(COMMANDS & commands,
+ const std::vector<API_ACTION::PARAM> & params,
+ API_FUNCTION funPtr)
+{
+return new API_ACTION(commands, "", false, params, funPtr);
+}
+
+inline
+ACTION * MakeAPIAction(COMMANDS & commands,
+ const std::string & paramDescription,
+ API_FUNCTION funPtr)
+{
+return new API_ACTION(commands, paramDescription, true, funPtr);
+}
+
+inline
+ACTION * MakeAPIAction(COMMANDS & commands,
+ API_FUNCTION funPtr)
+{
+return new API_ACTION(commands, "", false, funPtr);
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/common.h"
+#include "stg/optional.h"
+
+#include <string>
+#include <cstdint>
+
+namespace SGCONF
+{
+
+struct CONFIG
+{
+ STG::Optional<std::string> configFile;
+ STG::Optional<std::string> server;
+ STG::Optional<uint16_t> port;
+ STG::Optional<std::string> localAddress;
+ STG::Optional<uint16_t> localPort;
+ STG::Optional<std::string> userName;
+ STG::Optional<std::string> userPass;
+ STG::Optional<bool> showConfig;
+
+ CONFIG & operator=(const CONFIG & rhs)
+ {
+ if (!rhs.configFile.empty())
+ configFile = rhs.configFile;
+ if (!rhs.server.empty())
+ server = rhs.server;
+ if (!rhs.port.empty())
+ port = rhs.port;
+ if (!rhs.localAddress.empty())
+ localAddress = rhs.localAddress;
+ if (!rhs.localPort.empty())
+ localPort = rhs.localPort;
+ if (!rhs.userName.empty())
+ userName = rhs.userName;
+ if (!rhs.userPass.empty())
+ userPass = rhs.userPass;
+ if (!rhs.showConfig.empty())
+ showConfig = rhs.showConfig;
+ return *this;
+ }
+
+ std::string Serialize() const
+ {
+ std::string res;
+ if (!configFile.empty())
+ res += "configFile: '" + configFile.data() + "'\n";
+ if (!server.empty())
+ res += "server: '" + server.data() + "'\n";
+ if (!port.empty())
+ res += "port: " + std::to_string(port.data()) + "\n";
+ if (!localAddress.empty())
+ res += "local address: '" + localAddress.data() + "'\n";
+ if (!localPort.empty())
+ res += "local port: " + std::to_string(localPort.data()) + "\n";
+ if (!userName.empty())
+ res += "userName: '" + userName.data() + "'\n";
+ if (!userPass.empty())
+ res += "userPass: '" + userPass.data() + "\n";
+ return res;
+ }
+};
+
+} // namespace SGCONF
--- /dev/null
+#include "corps.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+#include "utils.h"
+
+#include "stg/servconf.h"
+#include "stg/servconf_types.h"
+#include "stg/corp_conf.h"
+#include "stg/common.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+namespace
+{
+
+std::string Indent(size_t level, bool dash = false)
+{
+if (level == 0)
+ return "";
+return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
+}
+
+void PrintCorp(const STG::GetCorp::Info & info, size_t level = 0)
+{
+std::cout << Indent(level, true) << "name: " << info.name << "\n"
+ << Indent(level) << "cash: " << info.cash << "\n";
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetCorpParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("cash", "<cash>", "\tcorporation's cash"));
+return params;
+}
+
+void SimpleCallback(bool result,
+ const std::string & reason,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Success.\n";
+}
+
+void GetCorpsCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetCorp::Info> & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get corp list. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Corps:\n";
+for (size_t i = 0; i < info.size(); ++i)
+ PrintCorp(info[i], 1);
+}
+
+void GetCorpCallback(bool result,
+ const std::string & reason,
+ const STG::GetCorp::Info & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get corp. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+PrintCorp(info);
+}
+
+bool GetCorpsFunction(const SGCONF::CONFIG & config,
+ const std::string & /*arg*/,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetCorporations(GetCorpsCallback, NULL) == STG::st_ok;
+}
+
+bool GetCorpFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetCorp(arg, GetCorpCallback, NULL) == STG::st_ok;
+}
+
+bool DelCorpFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.DelCorp(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddCorpFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::CorpConfOpt conf;
+conf.name = arg;
+SGCONF::MaybeSet(options, "cash", conf.cash);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.AddCorp(arg, conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgCorpFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::CorpConfOpt conf;
+conf.name = arg;
+SGCONF::MaybeSet(options, "cash", conf.cash);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.ChgCorp(conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendCorpsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetCorpParams());
+blocks.Add("Corporation management options")
+ .Add("get-corps", SGCONF::MakeAPIAction(commands, GetCorpsFunction), "\tget corporation list")
+ .Add("get-corp", SGCONF::MakeAPIAction(commands, "<name>", GetCorpFunction), "get corporation")
+ .Add("add-corp", SGCONF::MakeAPIAction(commands, "<name>", params, AddCorpFunction), "add corporation")
+ .Add("del-corp", SGCONF::MakeAPIAction(commands, "<name>", DelCorpFunction), "delete corporation")
+ .Add("chg-corp", SGCONF::MakeAPIAction(commands, "<name>", params, ChgCorpFunction), "change corporation");
+}
--- /dev/null
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendCorpsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+} // namespace SGCONF
--- /dev/null
+#include "info.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+
+#include "stg/servconf.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+#include <expat.h>
+
+namespace
+{
+
+void PrintInfo(const STG::ServerInfo::Info& info)
+{
+ std::cout << "Server version: '" << info.version << "'\n"
+ << "Number of tariffs: " << info.tariffNum << "\n"
+ << "Tariff subsystem version: " << info.tariffType << "\n"
+ << "Number of users: " << info.usersNum << "\n"
+ << "UName: '" << info.uname << "\n"
+ << "Number of directions: " << info.dirNum << "\n"
+ << "Dirs:\n";
+ for (size_t i = 0; i < info.dirName.size(); ++i)
+ std::cout << "\t - '" << info.dirName[i] << "'\n";
+}
+
+void InfoCallback(bool result, const std::string & reason, const STG::ServerInfo::Info & info, void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get server info. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+PrintInfo(info);
+}
+
+bool InfoFunction(const SGCONF::CONFIG & config,
+ const std::string& /*arg*/,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.ServerInfo(InfoCallback, NULL) == STG::st_ok;
+}
+
+}
+
+void SGCONF::AppendServerInfoBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+blocks.Add("Server info")
+ .Add("server-info", SGCONF::MakeAPIAction(commands, InfoFunction), "\tget server info");
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendServerInfoBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "xml.h"
+#include "admins.h"
+#include "tariffs.h"
+#include "users.h"
+#include "services.h"
+#include "corps.h"
+#include "info.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "actions.h"
+#include "config.h"
+
+#include <string>
+#include <iostream>
+
+#include <cstdlib> // getenv
+#include <cstring> // str*
+
+#include <unistd.h> // access
+#include <libgen.h> // basename
+
+namespace
+{
+
+template <typename T>
+struct nullary_function
+{
+typedef T result_type;
+};
+
+template <typename F>
+class binder0 : public nullary_function<typename F::result_type>
+{
+ public:
+ binder0(const F & func, const typename F::argument_type & arg)
+ : m_func(func), m_arg(arg) {}
+ typename F::result_type operator()() const { return m_func(m_arg); }
+ private:
+ F m_func;
+ typename F::argument_type m_arg;
+};
+
+template <typename F>
+inline
+binder0<F> bind0(const F & func, const typename F::argument_type & arg)
+{
+return binder0<F>(func, arg);
+}
+
+template <typename A, typename R>
+class FUNC1_ADAPTER : public std::unary_function<A, R>
+{
+ public:
+ FUNC1_ADAPTER(R (*func)(A)) : m_func(func) {}
+ const R operator()(A arg) const { return (m_func)(arg); }
+ private:
+ R (*m_func)(A);
+};
+
+template <typename C, typename A, typename R>
+class METHOD1_ADAPTER : public std::unary_function<A, R>
+{
+ public:
+ METHOD1_ADAPTER(R (C::* func)(A), C & obj) : m_func(func), m_obj(obj) {}
+ R operator()(A arg) { return (m_obj.*m_func)(arg); }
+ private:
+ R (C::* m_func)(A);
+ C & m_obj;
+};
+
+template <typename C, typename A, typename R>
+class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
+{
+ public:
+ CONST_METHOD1_ADAPTER(R (C::* func)(A) const, C & obj) : m_func(func), m_obj(obj) {}
+ R operator()(A arg) const { return (m_obj.*m_func)(arg); }
+ private:
+ R (C::* m_func)(A) const;
+ C & m_obj;
+};
+
+template <typename A, typename R>
+FUNC1_ADAPTER<A, R> Func1Adapt(R (func)(A))
+{
+return FUNC1_ADAPTER<A, R>(func);
+}
+
+template <typename C, typename A, typename R>
+METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
+{
+return METHOD1_ADAPTER<C, A, R>(func, obj);
+}
+
+template <typename C, typename A, typename R>
+CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
+{
+return CONST_METHOD1_ADAPTER<C, A, R>(func, obj);
+}
+
+void Version(const std::string & self)
+{
+std::cout << self << ", version: 2.0.0.\n";
+}
+
+void ReadUserConfigFile(SGCONF::OPTION_BLOCK & block)
+{
+std::vector<std::string> paths;
+const char * configHome = getenv("XDG_CONFIG_HOME");
+if (configHome == NULL)
+ {
+ const char * home = getenv("HOME");
+ if (home == NULL)
+ return;
+ paths.push_back(std::string(home) + "/.config/sgconf/sgconf.conf");
+ paths.push_back(std::string(home) + "/.sgconf/sgconf.conf");
+ }
+else
+ paths.push_back(std::string(configHome) + "/sgconf/sgconf.conf");
+for (std::vector<std::string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
+ if (access(it->c_str(), R_OK) == 0)
+ {
+ block.ParseFile(*it);
+ return;
+ }
+}
+
+} // namespace anonymous
+
+namespace SGCONF
+{
+
+class CONFIG_ACTION : public ACTION
+{
+ public:
+ CONFIG_ACTION(SGCONF::CONFIG & config,
+ const std::string & paramDescription)
+ : m_config(config),
+ m_description(paramDescription)
+ {}
+
+ virtual ACTION * Clone() const { return new CONFIG_ACTION(*this); }
+
+ virtual std::string ParamDescription() const { return m_description; }
+ virtual std::string DefaultDescription() const { return ""; }
+ virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+ virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
+
+ private:
+ SGCONF::CONFIG & m_config;
+ std::string m_description;
+ OPTION_BLOCK m_suboptions;
+
+ void ParseCredentials(const std::string & credentials);
+ void ParseHostAndPort(const std::string & hostAndPort);
+};
+
+
+PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv, void * /*data*/)
+{
+if (argc == 0 ||
+ argv == NULL ||
+ *argv == NULL)
+ throw ERROR("Missing argument.");
+char * pos = strchr(*argv, '@');
+if (pos != NULL)
+ {
+ ParseCredentials(std::string(*argv, pos));
+ ParseHostAndPort(std::string(pos + 1));
+ }
+else
+ {
+ ParseHostAndPort(std::string(*argv));
+ }
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+void CONFIG_ACTION::ParseCredentials(const std::string & credentials)
+{
+std::string::size_type pos = credentials.find_first_of(':');
+if (pos != std::string::npos)
+ {
+ m_config.userName = credentials.substr(0, pos);
+ m_config.userPass = credentials.substr(pos + 1);
+ }
+else
+ {
+ m_config.userName = credentials;
+ }
+}
+
+void CONFIG_ACTION::ParseHostAndPort(const std::string & hostAndPort)
+{
+std::string::size_type pos = hostAndPort.find_first_of(':');
+if (pos != std::string::npos)
+ {
+ m_config.server = hostAndPort.substr(0, pos);
+ uint16_t port = 0;
+ if (str2x(hostAndPort.substr(pos + 1), port))
+ throw ERROR("Invalid port value: '" + hostAndPort.substr(pos + 1) + "'");
+ m_config.port = port;
+ }
+else
+ {
+ m_config.server = hostAndPort;
+ }
+}
+
+inline
+CONFIG_ACTION * MakeParamAction(SGCONF::CONFIG & config,
+ const std::string & paramDescription)
+{
+return new CONFIG_ACTION(config, paramDescription);
+}
+
+} // namespace SGCONF
+
+//-----------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+std::string self(basename(argv[0]));
+SGCONF::CONFIG config;
+SGCONF::COMMANDS commands;
+
+SGCONF::OPTION_BLOCKS blocks;
+blocks.Add("General options")
+ .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), "<config file>"), "override default config file")
+ .Add("h", "help", SGCONF::MakeFunc0Action(bind0(Method1Adapt(&SGCONF::OPTION_BLOCKS::Help, blocks), 0)), "\t\tshow this help and exit")
+ //.Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "\t\tshow full help and exit")
+ .Add("v", "version", SGCONF::MakeFunc0Action(bind0(Func1Adapt(Version), self)), "\t\tshow version information and exit");
+SGCONF::OPTION_BLOCK & block = blocks.Add("Connection options")
+ .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "<address>"), "\t\thost to connect")
+ .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "\t\tport to connect")
+ .Add("local-address", SGCONF::MakeParamAction(config.localAddress, std::string(""), "<address>"), "\tlocal address to bind")
+ .Add("local-port", SGCONF::MakeParamAction(config.localPort, uint16_t(0), "<port>"), "\t\tlocal port to bind")
+ .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "\tadministrative login")
+ .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "\tpassword for the administrative login")
+ .Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
+blocks.Add("Debug options")
+ .Add("show-config", SGCONF::MakeParamAction(config.showConfig), "\tshow config and exit");
+SGCONF::AppendXMLOptionBlock(commands, blocks);
+SGCONF::AppendServerInfoBlock(commands, blocks);
+SGCONF::AppendAdminsOptionBlock(commands, blocks);
+SGCONF::AppendTariffsOptionBlock(commands, blocks);
+SGCONF::AppendUsersOptionBlock(commands, blocks);
+SGCONF::AppendServicesOptionBlock(commands, blocks);
+SGCONF::AppendCorpsOptionBlock(commands, blocks);
+
+SGCONF::PARSER_STATE state(false, argc, argv);
+
+try
+{
+state = blocks.Parse(--argc, ++argv); // Skipping self name
+}
+catch (const SGCONF::OPTION::ERROR& ex)
+{
+std::cerr << ex.what() << "\n";
+return -1;
+}
+
+if (state.stop)
+ return 0;
+
+if (state.argc > 0)
+ {
+ std::cerr << "Unknown option: '" << *state.argv << "'\n";
+ return -1;
+ }
+
+try
+{
+SGCONF::CONFIG configOverride(config);
+
+if (config.configFile.empty())
+ {
+ const char * mainConfigFile = "/etc/sgconf/sgconf.conf";
+ if (access(mainConfigFile, R_OK) == 0)
+ block.ParseFile(mainConfigFile);
+ ReadUserConfigFile(block);
+ }
+else
+ {
+ block.ParseFile(config.configFile.data());
+ }
+
+config = configOverride;
+
+if (!config.showConfig.empty() && config.showConfig.data())
+ {
+ std::cout << config.Serialize() << std::endl;
+ return 0;
+ }
+return commands.Execute(config) ? 0 : -1;
+}
+catch (const std::exception& ex)
+{
+std::cerr << ex.what() << "\n";
+return -1;
+}
+}
+//-----------------------------------------------------------------------------
+
+namespace
+{
+
+/*void UsageTariffs(bool full)
+{
+std::cout << "Tariffs management options:\n"
+ << "\t--get-tariffs\t\t\t\tget a list of tariffs (subsequent options will define what to show)\n";
+if (full)
+ std::cout << "\t\t--name\t\t\t\tshow tariff's name\n"
+ << "\t\t--fee\t\t\t\tshow tariff's fee\n"
+ << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
+ << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
+ << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
+ << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
+std::cout << "\t--get-tariff\t\t\t\tget the information about tariff\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the tariff to show\n"
+ << "\t\t--fee\t\t\t\tshow tariff's fee\n"
+ << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
+ << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
+ << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
+ << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
+std::cout << "\t--add-tariff\t\t\t\tadd a new tariff\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the tariff to add\n"
+ << "\t\t--fee <fee>\t\t\tstariff's fee\n"
+ << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
+ << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
+ << "\t\t--traff-type <type>\t\twhat type of traffi will be accounted by the tariff\n"
+ << "\t\t--times <times>\t\t\tslash-separated list of \"day\" time-spans (in form \"hh:mm-hh:mm\") for each direction\n"
+ << "\t\t--prices-day-a <prices>\t\tslash-separated list of prices for \"day\" traffic before threshold for each direction\n"
+ << "\t\t--prices-night-a <prices>\tslash-separated list of prices for \"night\" traffic before threshold for each direction\n"
+ << "\t\t--prices-day-b <prices>\t\tslash-separated list of prices for \"day\" traffic after threshold for each direction\n"
+ << "\t\t--prices-night-b <prices>\tslash-separated list of prices for \"night\" traffic after threshold for each direction\n"
+ << "\t\t--single-prices <yes|no>\tslash-separated list of \"single price\" flags for each direction\n"
+ << "\t\t--no-discounts <yes|no>\t\tslash-separated list of \"no discount\" flags for each direction\n"
+ << "\t\t--thresholds <thresholds>\tslash-separated list of thresholds (in Mb) for each direction\n\n";
+std::cout << "\t--del-tariff\t\t\t\tdelete an existing tariff\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the tariff to delete\n\n";
+std::cout << "\t--chg-tariff\t\t\t\tchange an existing tariff\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the tariff to change\n"
+ << "\t\t--fee <fee>\t\t\tstariff's fee\n"
+ << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
+ << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
+ << "\t\t--traff-type <type>\t\twhat type of traffix will be accounted by the tariff\n"
+ << "\t\t--dir <N>\t\t\tnumber of direction data to change\n"
+ << "\t\t\t--time <time>\t\t\"day\" time-span (in form \"hh:mm-hh:mm\")\n"
+ << "\t\t\t--price-day-a <price>\tprice for \"day\" traffic before threshold\n"
+ << "\t\t\t--price-night-a <price>\tprice for \"night\" traffic before threshold\n"
+ << "\t\t\t--price-day-b <price>\tprice for \"day\" traffic after threshold\n"
+ << "\t\t\t--price-night-b <price>\tprice for \"night\" traffic after threshold\n"
+ << "\t\t\t--single-price <yes|no>\t\"single price\" flag\n"
+ << "\t\t\t--no-discount <yes|no>\t\"no discount\" flag\n"
+ << "\t\t\t--threshold <threshold>\tthreshold (in Mb)\n\n";
+}
+//-----------------------------------------------------------------------------
+void UsageUsers(bool full)
+{
+std::cout << "Users management options:\n"
+ << "\t--get-users\t\t\t\tget a list of users (subsequent options will define what to show)\n";
+if (full)
+ std::cout << "\n\n";
+std::cout << "\t--get-user\t\t\t\tget the information about user\n";
+if (full)
+ std::cout << "\n\n";
+std::cout << "\t--add-user\t\t\t\tadd a new user\n";
+if (full)
+ std::cout << "\n\n";
+std::cout << "\t--del-user\t\t\t\tdelete an existing user\n";
+if (full)
+ std::cout << "\n\n";
+std::cout << "\t--chg-user\t\t\t\tchange an existing user\n";
+if (full)
+ std::cout << "\n\n";
+std::cout << "\t--check-user\t\t\t\tcheck credentials is valid\n";
+if (full)
+ std::cout << "\n\n";
+std::cout << "\t--send-message\t\t\t\tsend a message to a user\n";
+if (full)
+ std::cout << "\n\n";
+}
+//-----------------------------------------------------------------------------
+void UsageServices(bool full)
+{
+std::cout << "Services management options:\n"
+ << "\t--get-services\t\t\t\tget a list of services (subsequent options will define what to show)\n";
+if (full)
+ std::cout << "\t\t--name\t\t\t\tshow service's name\n"
+ << "\t\t--comment\t\t\tshow a comment to the service\n"
+ << "\t\t--cost\t\t\t\tshow service's cost\n"
+ << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
+std::cout << "\t--get-service\t\t\t\tget the information about service\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the service to show\n"
+ << "\t\t--comment\t\t\tshow a comment to the service\n"
+ << "\t\t--cost\t\t\t\tshow service's cost\n"
+ << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
+std::cout << "\t--add-service\t\t\t\tadd a new service\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the service to add\n"
+ << "\t\t--comment <comment>\t\ta comment to the service\n"
+ << "\t\t--cost <cost>\t\t\tservice's cost\n"
+ << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
+std::cout << "\t--del-service\t\t\t\tdelete an existing service\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the service to delete\n\n";
+std::cout << "\t--chg-service\t\t\t\tchange an existing service\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the service to change\n"
+ << "\t\t--comment <comment>\t\ta comment to the service\n"
+ << "\t\t--cost <cost>\t\t\tservice's cost\n"
+ << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
+}
+//-----------------------------------------------------------------------------
+void UsageCorporations(bool full)
+{
+std::cout << "Corporations management options:\n"
+ << "\t--get-corporations\t\t\tget a list of corporations (subsequent options will define what to show)\n";
+if (full)
+ std::cout << "\t\t--name\t\t\t\tshow corporation's name\n"
+ << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
+std::cout << "\t--get-corp\t\t\t\tget the information about corporation\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the corporation to show\n"
+ << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
+std::cout << "\t--add-corp\t\t\t\tadd a new corporation\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the corporation to add\n"
+ << "\t\t--cash <cash>\t\t\tinitial corporation's cash (default: \"0\")\n\n";
+std::cout << "\t--del-corp\t\t\t\tdelete an existing corporation\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the corporation to delete\n\n";
+std::cout << "\t--chg-corp\t\t\t\tchange an existing corporation\n";
+if (full)
+ std::cout << "\t\t--name <name>\t\t\tname of the corporation to change\n"
+ << "\t\t--add-cash <amount>[:<message>]\tadd cash to the corporation's account and optional comment message\n"
+ << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
+}*/
+
+} // namespace anonymous
--- /dev/null
+/*
+ * 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 "options.h"
+
+#include "action.h"
+#include "parser_state.h"
+
+#include "stg/common.h"
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include <functional>
+#include <algorithm>
+
+#include <unistd.h>
+
+namespace
+{
+
+template <class C>
+void ReadConfigFile(const std::string & filePath, void (C::* callback)(const std::string&, const std::string&), C * obj)
+{
+std::ifstream stream(filePath.c_str());
+std::string line;
+size_t num = 0;
+while (std::getline(stream, line))
+ {
+ ++num;
+ line = Trim(line);
+ std::string::size_type pos = line.find_first_of('#');
+ if (pos != std::string::npos)
+ line = line.substr(0, pos);
+ if (line.empty())
+ continue;
+ pos = line.find_first_of('=');
+ if (pos == std::string::npos)
+ {
+ std::ostringstream error;
+ error << "Bad file format, missing '=' in '" << filePath << ":" << num << "'.";
+ throw std::runtime_error(error.str().c_str());
+ }
+ (obj->*callback)(Trim(line.substr(0, pos)), Trim(line.substr(pos + 1, line.length() - pos - 1)));
+ }
+}
+
+} // namespace anonymous
+
+using SGCONF::OPTION;
+using SGCONF::OPTION_BLOCK;
+using SGCONF::OPTION_BLOCKS;
+using SGCONF::ACTION;
+using SGCONF::PARSER_STATE;
+
+OPTION::OPTION(const std::string & shortName,
+ const std::string & longName,
+ ACTION * action,
+ const std::string & description)
+ : m_shortName(shortName),
+ m_longName(longName),
+ m_action(action),
+ m_description(description)
+{
+}
+
+OPTION::OPTION(const std::string & longName,
+ ACTION * action,
+ const std::string & description)
+ : m_longName(longName),
+ m_action(action),
+ m_description(description)
+{
+}
+
+OPTION::OPTION(const OPTION & rhs)
+ : m_shortName(rhs.m_shortName),
+ m_longName(rhs.m_longName),
+ m_action(rhs.m_action->Clone()),
+ m_description(rhs.m_description)
+{
+}
+
+OPTION::~OPTION()
+{
+delete m_action;
+}
+
+OPTION & OPTION::operator=(const OPTION & rhs)
+{
+m_shortName = rhs.m_shortName;
+m_longName = rhs.m_longName;
+m_action = rhs.m_action->Clone();
+m_description = rhs.m_description;
+return *this;
+}
+
+void OPTION::Help(size_t level) const
+{
+if (!m_action)
+ throw ERROR("Option is not defined.");
+std::string indent(level, '\t');
+std::cout << indent;
+if (!m_shortName.empty())
+ std::cout << "-" << m_shortName << ", ";
+std::cout << "--" << m_longName << " " << m_action->ParamDescription()
+ << "\t" << m_description << m_action->DefaultDescription() << "\n";
+m_action->Suboptions().Help(level);
+}
+
+bool OPTION::Check(const char * arg) const
+{
+if (arg == NULL)
+ return false;
+
+if (*arg++ != '-')
+ return false;
+
+if (*arg == '-')
+{
+ return m_longName == arg + 1;
+}
+
+return m_shortName == arg;
+}
+
+PARSER_STATE OPTION::Parse(int argc, char ** argv, void * data)
+{
+if (!m_action)
+ throw ERROR("Option is not defined.");
+try
+ {
+ return m_action->Parse(argc, argv, data);
+ }
+catch (const ACTION::ERROR & ex)
+ {
+ if (m_longName.empty())
+ throw ERROR("-" + m_shortName + ": " + ex.what());
+ else
+ throw m_shortName.empty() ? ERROR("--" + m_longName + ": " + ex.what())
+ : ERROR("--" + m_longName + ", -" + m_shortName + ": " + ex.what());
+ }
+}
+
+void OPTION::ParseValue(const std::string & value)
+{
+if (!m_action)
+ throw ERROR("Option is not defined.");
+try
+ {
+ return m_action->ParseValue(value);
+ }
+catch (const ACTION::ERROR & ex)
+ {
+ throw ERROR(m_longName + ": " + ex.what());
+ }
+}
+
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & shortName,
+ const std::string & longName,
+ ACTION * action,
+ const std::string & description)
+{
+m_options.push_back(OPTION(shortName, longName, action, description));
+return *this;
+}
+
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & longName,
+ ACTION * action,
+ const std::string & description)
+{
+m_options.push_back(OPTION(longName, action, description));
+return *this;
+}
+
+void OPTION_BLOCK::Help(size_t level) const
+{
+if (m_options.empty())
+ return;
+if (!m_description.empty())
+ std::cout << m_description << ":\n";
+std::for_each(m_options.begin(),
+ m_options.end(),
+ [&level](const auto& opt){ opt.Help(level + 1); });
+}
+
+PARSER_STATE OPTION_BLOCK::Parse(int argc, char ** argv, void * data)
+{
+PARSER_STATE state(false, argc, argv);
+if (state.argc == 0)
+ return state;
+while (state.argc > 0 && !state.stop)
+ {
+ const auto it = std::find_if(m_options.begin(), m_options.end(), [&state](const auto& opt){ return opt.Check(*state.argv); });
+ if (it != m_options.end())
+ state = it->Parse(--state.argc, ++state.argv, data);
+ else
+ break;
+ }
+return state;
+}
+
+void OPTION_BLOCK::ParseFile(const std::string & filePath)
+{
+if (access(filePath.c_str(), R_OK))
+ throw ERROR("File '" + filePath + "' does not exists.");
+ReadConfigFile(filePath, &OPTION_BLOCK::OptionCallback, this);
+}
+
+void OPTION_BLOCK::OptionCallback(const std::string & key, const std::string & value)
+{
+for (std::vector<OPTION>::iterator it = m_options.begin(); it != m_options.end(); ++it)
+ if (it->Name() == key)
+ it->ParseValue(value);
+}
+
+void OPTION_BLOCKS::Help(size_t level) const
+{
+std::list<OPTION_BLOCK>::const_iterator it(m_blocks.begin());
+while (it != m_blocks.end())
+ {
+ it->Help(level);
+ std::cout << "\n";
+ ++it;
+ }
+}
+
+PARSER_STATE OPTION_BLOCKS::Parse(int argc, char ** argv)
+{
+PARSER_STATE state(false, argc, argv);
+std::list<OPTION_BLOCK>::iterator it(m_blocks.begin());
+while (state.argc > 0 && !state.stop && it != m_blocks.end())
+ {
+ state = it->Parse(state.argc, state.argv);
+ ++it;
+ }
+return state;
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#ifndef __STG_SGCONF_OPTIONS_H__
+#define __STG_SGCONF_OPTIONS_H__
+
+#include <string>
+#include <vector>
+#include <list>
+#include <utility>
+#include <stdexcept>
+#include <cstddef> // size_t
+
+namespace SGCONF
+{
+
+class ACTION;
+struct PARSER_STATE;
+
+class OPTION
+{
+ public:
+ OPTION(const std::string & shortName,
+ const std::string & longName,
+ ACTION * action,
+ const std::string & description);
+ OPTION(const std::string & longName,
+ ACTION * action,
+ const std::string & description);
+ OPTION(const OPTION & rhs);
+ ~OPTION();
+
+ OPTION & operator=(const OPTION & rhs);
+
+ void Help(size_t level = 0) const;
+ PARSER_STATE Parse(int argc, char ** argv, void * data);
+ void ParseValue(const std::string & value);
+ bool Check(const char * arg) const;
+ const std::string & Name() const { return m_longName; }
+
+ class ERROR : public std::runtime_error
+ {
+ public:
+ ERROR(const std::string & message)
+ : std::runtime_error(message.c_str()) {}
+ };
+
+ private:
+ std::string m_shortName;
+ std::string m_longName;
+ ACTION * m_action;
+ std::string m_description;
+};
+
+class OPTION_BLOCK
+{
+ public:
+ OPTION_BLOCK() {}
+ OPTION_BLOCK(const std::string & description)
+ : m_description(description) {}
+ OPTION_BLOCK & Add(const std::string & shortName,
+ const std::string & longName,
+ ACTION * action,
+ const std::string & description);
+ OPTION_BLOCK & Add(const std::string & longName,
+ ACTION * action,
+ const std::string & description);
+
+ void Help(size_t level) const;
+
+ PARSER_STATE Parse(int argc, char ** argv, void * data = NULL);
+ void ParseFile(const std::string & filePath);
+
+ class ERROR : public std::runtime_error
+ {
+ public:
+ ERROR(const std::string & message)
+ : std::runtime_error(message.c_str()) {}
+ };
+
+ private:
+ std::vector<OPTION> m_options;
+ std::string m_description;
+
+ void OptionCallback(const std::string & key, const std::string & value);
+};
+
+class OPTION_BLOCKS
+{
+ public:
+ OPTION_BLOCK & Add(const std::string & description)
+ { m_blocks.push_back(OPTION_BLOCK(description)); return m_blocks.back(); }
+ void Add(const OPTION_BLOCK & block) { m_blocks.push_back(block); }
+ void Help(size_t level) const;
+ PARSER_STATE Parse(int argc, char ** argv);
+
+ private:
+ std::list<OPTION_BLOCK> m_blocks;
+};
+
+} // namespace SGCONF
+
+#endif
--- /dev/null
+/*
+ * 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>
+ */
+
+#ifndef __STG_SGCONF_PARSER_STATE_H__
+#define __STG_SGCONF_PARSER_STATE_H__
+
+namespace SGCONF
+{
+
+struct PARSER_STATE
+{
+ PARSER_STATE(bool s, int c, char ** v) : stop(s), argc(c), argv(v) {}
+ bool stop;
+ int argc;
+ char ** argv;
+};
+
+}
+
+#endif
--- /dev/null
+#include "services.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+#include "utils.h"
+
+#include "stg/servconf.h"
+#include "stg/servconf_types.h"
+#include "stg/service_conf.h"
+#include "stg/common.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+namespace
+{
+
+std::string Indent(size_t level, bool dash = false)
+{
+if (level == 0)
+ return "";
+return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
+}
+
+void PrintService(const STG::GetService::Info & info, size_t level = 0)
+{
+std::cout << Indent(level, true) << "name: " << info.name << "\n"
+ << Indent(level) << "cost: " << info.cost << "\n"
+ << Indent(level) << "payment day: " << static_cast<unsigned>(info.payDay) << "\n"
+ << Indent(level) << "comment: " << info.comment << "\n";
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetServiceParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("cost", "<cost>", "\tcost of the service"));
+params.push_back(SGCONF::API_ACTION::PARAM("pay-day", "<month day>", "payment day"));
+params.push_back(SGCONF::API_ACTION::PARAM("comment", "<text>", "comment"));
+return params;
+}
+
+void SimpleCallback(bool result,
+ const std::string & reason,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Success.\n";
+}
+
+void GetServicesCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetService::Info> & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get service list. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Services:\n";
+for (size_t i = 0; i < info.size(); ++i)
+ PrintService(info[i], 1);
+}
+
+void GetServiceCallback(bool result,
+ const std::string & reason,
+ const STG::GetService::Info & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get service. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+PrintService(info);
+}
+
+bool GetServicesFunction(const SGCONF::CONFIG & config,
+ const std::string & /*arg*/,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetServices(GetServicesCallback, NULL) == STG::st_ok;
+}
+
+bool GetServiceFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetService(arg, GetServiceCallback, NULL) == STG::st_ok;
+}
+
+bool DelServiceFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.DelService(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddServiceFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::ServiceConfOpt conf;
+conf.name = arg;
+SGCONF::MaybeSet(options, "cost", conf.cost);
+SGCONF::MaybeSet(options, "pay-day", conf.payDay);
+SGCONF::MaybeSet(options, "comment", conf.comment);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.AddService(arg, conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgServiceFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::ServiceConfOpt conf;
+conf.name = arg;
+SGCONF::MaybeSet(options, "cost", conf.cost);
+SGCONF::MaybeSet(options, "pay-day", conf.payDay);
+SGCONF::MaybeSet(options, "comment", conf.comment);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.ChgService(conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendServicesOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetServiceParams());
+blocks.Add("Service management options")
+ .Add("get-services", SGCONF::MakeAPIAction(commands, GetServicesFunction), "\tget service list")
+ .Add("get-service", SGCONF::MakeAPIAction(commands, "<name>", GetServiceFunction), "get service")
+ .Add("add-service", SGCONF::MakeAPIAction(commands, "<name>", params, AddServiceFunction), "add service")
+ .Add("del-service", SGCONF::MakeAPIAction(commands, "<name>", DelServiceFunction), "delete service")
+ .Add("chg-service", SGCONF::MakeAPIAction(commands, "<name>", params, ChgServiceFunction), "change service");
+}
--- /dev/null
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendServicesOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+} // namespace SGCONF
--- /dev/null
+#include "tariffs.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+#include "utils.h"
+
+#include "stg/servconf.h"
+#include "stg/servconf_types.h"
+#include "stg/tariff_conf.h"
+#include "stg/common.h"
+
+#include <iostream>
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <map>
+#include <cstdint>
+#include <cassert>
+
+namespace
+{
+
+std::string Indent(size_t level, bool dash = false)
+{
+if (level == 0)
+ return "";
+return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
+}
+
+std::string ChangePolicyToString(STG::Tariff::ChangePolicy changePolicy)
+{
+switch (changePolicy)
+ {
+ case STG::Tariff::ALLOW: return "allow";
+ case STG::Tariff::TO_CHEAP: return "to_cheap";
+ case STG::Tariff::TO_EXPENSIVE: return "to_expensive";
+ case STG::Tariff::DENY: return "deny";
+ }
+return "unknown";
+}
+
+std::string PeriodToString(STG::Tariff::Period period)
+{
+switch (period)
+ {
+ case STG::Tariff::DAY:
+ return "daily";
+ case STG::Tariff::MONTH:
+ return "monthly";
+ }
+return "unknown";
+}
+
+std::string TraffTypeToString(STG::Tariff::TraffType traffType)
+{
+switch (traffType)
+ {
+ case STG::Tariff::TRAFF_UP:
+ return "upload";
+ case STG::Tariff::TRAFF_DOWN:
+ return "download";
+ case STG::Tariff::TRAFF_UP_DOWN:
+ return "upload + download";
+ case STG::Tariff::TRAFF_MAX:
+ return "max(upload, download)";
+ }
+return "unknown";
+}
+
+void ConvPeriod(const std::string & value, STG::Optional<STG::Tariff::Period> & res)
+{
+std::string lowered = ToLower(value);
+if (lowered == "daily")
+ res = STG::Tariff::DAY;
+else if (lowered == "monthly")
+ res = STG::Tariff::MONTH;
+else
+ throw SGCONF::ACTION::ERROR("Period should be 'daily' or 'monthly'. Got: '" + value + "'");
+}
+
+void ConvChangePolicy(const std::string & value, STG::Optional<STG::Tariff::ChangePolicy> & res)
+{
+std::string lowered = ToLower(value);
+if (lowered == "allow")
+ res = STG::Tariff::ALLOW;
+else if (lowered == "to_cheap")
+ res = STG::Tariff::TO_CHEAP;
+else if (lowered == "to_expensive")
+ res = STG::Tariff::TO_EXPENSIVE;
+else if (lowered == "deny")
+ res = STG::Tariff::DENY;
+else
+ throw SGCONF::ACTION::ERROR("Change policy should be 'allow', 'to_cheap', 'to_expensive' or 'deny'. Got: '" + value + "'");
+}
+
+void ConvChangePolicyTimeout(const std::string & value, STG::Optional<time_t> & res)
+{
+struct tm brokenTime;
+if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
+ throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
+res = stg_timegm(&brokenTime);
+}
+
+void ConvTraffType(const std::string & value, STG::Optional<STG::Tariff::TraffType> & res)
+{
+std::string lowered = ToLower(value);
+lowered.erase(std::remove(lowered.begin(), lowered.end(), ' '), lowered.end());
+if (lowered == "upload")
+ res = STG::Tariff::TRAFF_UP;
+else if (lowered == "download")
+ res = STG::Tariff::TRAFF_DOWN;
+else if (lowered == "upload+download")
+ res = STG::Tariff::TRAFF_UP_DOWN;
+else if (lowered.substr(0, 3) == "max")
+ res = STG::Tariff::TRAFF_MAX;
+else
+ throw SGCONF::ACTION::ERROR("Traff type should be 'upload', 'download', 'upload + download' or 'max'. Got: '" + value + "'");
+}
+
+STG::DirPriceDataOpt ConvTimeSpan(const std::string & value)
+{
+size_t dashPos = value.find_first_of('-');
+if (dashPos == std::string::npos)
+ throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
+size_t fromColon = value.find_first_of(':');
+if (fromColon == std::string::npos || fromColon > dashPos)
+ throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
+size_t toColon = value.find_first_of(':', dashPos);
+if (toColon == std::string::npos)
+ throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
+STG::DirPriceDataOpt res;
+res.hDay = FromString<int>(value.substr(0, fromColon));
+if (res.hDay.data() < 0 || res.hDay.data() > 23)
+ throw SGCONF::ACTION::ERROR("Invalid 'from' hours. Got: '" + value.substr(0, fromColon) + "'");
+res.mDay = FromString<int>(value.substr(fromColon + 1, dashPos - fromColon - 1));
+if (res.mDay.data() < 0 || res.mDay.data() > 59)
+ throw SGCONF::ACTION::ERROR("Invalid 'from' minutes. Got: '" + value.substr(fromColon + 1, dashPos - fromColon - 1) + "'");
+res.hNight = FromString<int>(value.substr(dashPos + 1, toColon - dashPos - 1));
+if (res.hNight.data() < 0 || res.hNight.data() > 23)
+ throw SGCONF::ACTION::ERROR("Invalid 'to' hours. Got: '" + value.substr(dashPos + 1, toColon - dashPos - 1) + "'");
+res.mNight = FromString<int>(value.substr(toColon + 1, value.length() - toColon));
+if (res.mNight.data() < 0 || res.mNight.data() > 59)
+ throw SGCONF::ACTION::ERROR("Invalid 'to' minutes. Got: '" + value.substr(toColon + 1, value.length() - toColon) + "'");
+return res;
+}
+
+void splice(std::vector<STG::DirPriceDataOpt> & lhs, const std::vector<STG::DirPriceDataOpt> & rhs)
+{
+for (size_t i = 0; i < lhs.size() && i < rhs.size(); ++i)
+ lhs[i].splice(rhs[i]);
+}
+
+void ConvTimes(std::string value, std::vector<STG::DirPriceDataOpt> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvTimeSpan));
+}
+
+struct ConvPrice : public std::unary_function<std::string, STG::DirPriceDataOpt>
+{
+ typedef STG::Optional<double> (STG::DirPriceDataOpt::* MemPtr);
+ ConvPrice(MemPtr before, MemPtr after)
+ : m_before(before), m_after(after)
+ {}
+
+ STG::DirPriceDataOpt operator()(const std::string & value)
+ {
+ STG::DirPriceDataOpt res;
+ size_t slashPos = value.find_first_of('/');
+ if (slashPos == std::string::npos)
+ {
+ double price = 0;
+ if (str2x(value, price) < 0)
+ throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value + "'");
+ (res.*m_before) = (res.*m_after) = price;
+ res.noDiscount = true;
+ }
+ else
+ {
+ double price = 0;
+ if (str2x(value.substr(0, slashPos), price) < 0)
+ throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value.substr(0, slashPos) + "'");
+ (res.*m_before) = price;
+ if (str2x(value.substr(slashPos + 1, value.length() - slashPos), price) < 0)
+ throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
+ (res.*m_after) = price;
+ res.noDiscount = false;
+ }
+ return res;
+ }
+
+ MemPtr m_before;
+ MemPtr m_after;
+};
+
+void ConvDayPrices(std::string value, std::vector<STG::DirPriceDataOpt> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvPrice(&STG::DirPriceDataOpt::priceDayA, &STG::DirPriceDataOpt::priceDayB)));
+}
+
+void ConvNightPrices(std::string value, std::vector<STG::DirPriceDataOpt> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvPrice(&STG::DirPriceDataOpt::priceNightA, &STG::DirPriceDataOpt::priceNightB)));
+}
+
+STG::DirPriceDataOpt ConvThreshold(std::string value)
+{
+ STG::DirPriceDataOpt res;
+double threshold = 0;
+if (str2x(value, threshold) < 0)
+ throw SGCONF::ACTION::ERROR("Threshold should be a floating point value. Got: '" + value + "'");
+res.threshold = threshold;
+return res;
+}
+
+void ConvThresholds(std::string value, std::vector<STG::DirPriceDataOpt> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvThreshold));
+}
+
+std::string TimeToString(int h, int m)
+{
+std::ostringstream stream;
+stream << (h < 10 ? "0" : "") << h << ":"
+ << (m < 10 ? "0" : "") << m;
+return stream.str();
+}
+
+void PrintDirPriceData(size_t dir, const STG::DirPriceData & data, size_t level)
+{
+std::string night = TimeToString(data.hNight, data.mNight);
+std::string day = TimeToString(data.hDay, data.mDay);
+std::cout << Indent(level, true) << "dir: " << dir << "\n"
+ << Indent(level) << "'" << night << "' - '" << day << "': " << data.priceDayA << "/" << data.priceDayB << "\n"
+ << Indent(level) << "'" << day << "' - '" << night << "': " << data.priceNightA << "/" << data.priceNightB << "\n"
+ << Indent(level) << "threshold: " << data.threshold << "\n"
+ << Indent(level) << "single price: " << (data.singlePrice ? "yes" : "no") << "\n"
+ << Indent(level) << "discount: " << (data.noDiscount ? "no" : "yes") << "\n"; // Attention!
+}
+
+void PrintTariffConf(const STG::TariffConf & conf, size_t level)
+{
+std::cout << Indent(level, true) << "name: " << conf.name << "\n"
+ << Indent(level) << "fee: " << conf.fee << "\n"
+ << Indent(level) << "free mb: " << conf.free << "\n"
+ << Indent(level) << "passive cost: " << conf.passiveCost << "\n"
+ << Indent(level) << "traff type: " << TraffTypeToString(conf.traffType) << "\n"
+ << Indent(level) << "period: " << PeriodToString(conf.period) << "\n"
+ << Indent(level) << "change policy: " << ChangePolicyToString(conf.changePolicy) << "\n"
+ << Indent(level) << "change policy timeout: " << formatTime(conf.changePolicyTimeout) << "\n";
+}
+
+void PrintTariff(const STG::GetTariff::Info & info, size_t level = 0)
+{
+PrintTariffConf(info.tariffConf, level);
+std::cout << Indent(level) << "dir prices:\n";
+for (size_t i = 0; i < info.dirPrice.size(); ++i)
+ PrintDirPriceData(i, info.dirPrice[i], level + 1);
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetTariffParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("fee", "<fee>", "\t\ttariff fee"));
+params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traffic"));
+params.push_back(SGCONF::API_ACTION::PARAM("passive-cost", "<cost>", "\tpassive cost"));
+params.push_back(SGCONF::API_ACTION::PARAM("traff-type", "<type>", "\ttraffic type (up, down, up+down, max)"));
+params.push_back(SGCONF::API_ACTION::PARAM("period", "<period>", "\ttarification period (daily, monthly)"));
+params.push_back(SGCONF::API_ACTION::PARAM("change-policy", "<policy>", "tariff change policy (allow, to_cheap, to_expensive, deny)"));
+params.push_back(SGCONF::API_ACTION::PARAM("change-policy-timeout", "<yyyy-mm-dd hh:mm:ss>", "tariff change policy timeout"));
+params.push_back(SGCONF::API_ACTION::PARAM("times", "<hh:mm-hh:mm, ...>", "coma-separated day time-spans for each direction"));
+params.push_back(SGCONF::API_ACTION::PARAM("day-prices", "<price/price, ...>", "coma-separated day prices for each direction"));
+params.push_back(SGCONF::API_ACTION::PARAM("night-prices", "<price/price, ...>", "coma-separated night prices for each direction"));
+params.push_back(SGCONF::API_ACTION::PARAM("thresholds", "<threshold, ...>", "coma-separated thresholds for each direction"));
+return params;
+}
+
+void SimpleCallback(bool result,
+ const std::string & reason,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Success.\n";
+}
+
+void GetTariffsCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetTariff::Info> & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get tariff list. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Tariffs:\n";
+for (size_t i = 0; i < info.size(); ++i)
+ PrintTariff(info[i], 1);
+}
+
+void GetTariffCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetTariff::Info> & info,
+ void * data)
+{
+assert(data != NULL && "Expecting pointer to std::string with the tariff's name.");
+const std::string & name = *static_cast<const std::string *>(data);
+if (!result)
+ {
+ std::cerr << "Failed to get tariff. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+for (size_t i = 0; i < info.size(); ++i)
+ if (info[i].tariffConf.name == name)
+ PrintTariff(info[i]);
+}
+
+bool GetTariffsFunction(const SGCONF::CONFIG & config,
+ const std::string & /*arg*/,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetTariffs(GetTariffsCallback, NULL) == STG::st_ok;
+}
+
+bool GetTariffFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+// STG currently doesn't support <GetTariff name="..."/>.
+// So get a list of tariffs and filter it. 'data' param holds a pointer to 'name'.
+std::string name(arg);
+return proto.GetTariffs(GetTariffCallback, &name) == STG::st_ok;
+}
+
+bool DelTariffFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.DelTariff(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddTariffFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::TariffDataOpt conf;
+conf.tariffConf.name = arg;
+SGCONF::MaybeSet(options, "fee", conf.tariffConf.fee);
+SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
+SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
+SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
+SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
+SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
+SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
+SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
+SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
+SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
+SGCONF::MaybeSet(options, "thresholds", conf.dirPrice, ConvThresholds);
+for (size_t i = 0; i < conf.dirPrice.size(); ++i)
+ {
+ if (!conf.dirPrice[i].priceDayA.empty() &&
+ !conf.dirPrice[i].priceNightA.empty() &&
+ !conf.dirPrice[i].priceDayB.empty() &&
+ !conf.dirPrice[i].priceNightB.empty())
+ conf.dirPrice[i].singlePrice = conf.dirPrice[i].priceDayA.data() == conf.dirPrice[i].priceNightA.data() &&
+ conf.dirPrice[i].priceDayB.data() == conf.dirPrice[i].priceNightB.data();
+ }
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.AddTariff(arg, conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgTariffFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::TariffDataOpt conf;
+conf.tariffConf.name = arg;
+SGCONF::MaybeSet(options, "fee", conf.tariffConf.fee);
+SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
+SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
+SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
+SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
+SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
+SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
+SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
+SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
+SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
+SGCONF::MaybeSet(options, "thresholds", conf.dirPrice, ConvThresholds);
+for (size_t i = 0; i < conf.dirPrice.size(); ++i)
+ {
+ if (!conf.dirPrice[i].priceDayA.empty() &&
+ !conf.dirPrice[i].priceNightA.empty() &&
+ !conf.dirPrice[i].priceDayB.empty() &&
+ !conf.dirPrice[i].priceNightB.empty())
+ conf.dirPrice[i].singlePrice = conf.dirPrice[i].priceDayA.data() == conf.dirPrice[i].priceNightA.data() &&
+ conf.dirPrice[i].priceDayB.data() == conf.dirPrice[i].priceNightB.data();
+ }
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.ChgTariff(conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendTariffsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetTariffParams());
+blocks.Add("Tariff management options")
+ .Add("get-tariffs", SGCONF::MakeAPIAction(commands, GetTariffsFunction), "\tget tariff list")
+ .Add("get-tariff", SGCONF::MakeAPIAction(commands, "<name>", GetTariffFunction), "get tariff")
+ .Add("add-tariff", SGCONF::MakeAPIAction(commands, "<name>", params, AddTariffFunction), "add tariff")
+ .Add("del-tariff", SGCONF::MakeAPIAction(commands, "<name>", DelTariffFunction), "delete tariff")
+ .Add("chg-tariff", SGCONF::MakeAPIAction(commands, "<name>", params, ChgTariffFunction), "change tariff");
+}
--- /dev/null
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendTariffsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+} // namespace SGCONF
--- /dev/null
+#include "users.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+#include "utils.h"
+
+#include "stg/servconf.h"
+#include "stg/servconf_types.h"
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/user_ips.h"
+#include "stg/common.h"
+
+#include <iostream>
+#include <algorithm>
+#include <string>
+#include <map>
+
+namespace
+{
+
+std::string Indent(size_t level, bool dash = false)
+{
+if (level == 0)
+ return "";
+return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
+}
+
+void PrintUser(const STG::GetUser::Info & info, size_t level = 0)
+{
+std::cout << Indent(level, true) << "login: " << info.login << "\n"
+ << Indent(level) << "password: " << info.password << "\n"
+ << Indent(level) << "cash: " << info.cash << "\n"
+ << Indent(level) << "credit: " << info.credit << "\n"
+ << Indent(level) << "credit expire: " << TimeToString(info.creditExpire) << "\n"
+ << Indent(level) << "last cash add: " << info.lastCashAdd << "\n"
+ << Indent(level) << "last cash add time: " << TimeToString(info.lastCashAddTime) << "\n"
+ << Indent(level) << "prepaid traffic: " << info.prepaidTraff << "\n"
+ << Indent(level) << "disabled: " << (info.disabled ? "t" : "f") << "\n"
+ << Indent(level) << "passive: " << (info.passive ? "t" : "f") << "\n"
+ << Indent(level) << "disabled detail stat: " << (info.disableDetailStat ? "t" : "f") << "\n"
+ << Indent(level) << "connected: " << (info.connected ? "t" : "f") << "\n"
+ << Indent(level) << "always on-line: " << (info.alwaysOnline ? "t" : "f") << "\n"
+ << Indent(level) << "IP: " << inet_ntostring(info.ip) << "\n"
+ << Indent(level) << "IPs: " << info.ips << "\n"
+ << Indent(level) << "tariff: " << info.tariff << "\n"
+ << Indent(level) << "group: " << info.group << "\n"
+ << Indent(level) << "note: " << info.note << "\n"
+ << Indent(level) << "email: " << info.email << "\n"
+ << Indent(level) << "name: " << info.name << "\n"
+ << Indent(level) << "address: " << info.address << "\n"
+ << Indent(level) << "phone: " << info.phone << "\n"
+ << Indent(level) << "corporation: " << info.corp << "\n"
+ << Indent(level) << "last ping time: " << TimeToString(info.pingTime) << "\n"
+ << Indent(level) << "last activity time: " << TimeToString(info.lastActivityTime) << "\n"
+ << Indent(level) << "traffic:\n";
+for (size_t i = 0; i < DIR_NUM; ++i)
+ {
+ std::cout << Indent(level + 1, true) << "dir: " << i << "\n"
+ << Indent(level + 1) << "session upload: " << info.stat.su[i] << "\n"
+ << Indent(level + 1) << "session download: " << info.stat.sd[i] << "\n"
+ << Indent(level + 1) << "month upload: " << info.stat.mu[i] << "\n"
+ << Indent(level + 1) << "month download: " << info.stat.md[i] << "\n";
+ }
+std::cout << Indent(level) << "user data:\n";
+for (size_t i = 0; i < USERDATA_NUM; ++i)
+ std::cout << Indent(level + 1, true) << "user data " << i << ": " << info.userData[i] << "\n";
+if (!info.services.empty())
+ {
+ std::cout << Indent(level) << "services:\n";
+ for (size_t i = 0; i < info.services.size(); ++i)
+ std::cout << Indent(level + 1, true) << info.services[i] << "\n";
+ }
+if (!info.authBy.empty())
+ {
+ std::cout << Indent(level) << "auth by:\n";
+ for (size_t i = 0; i < info.authBy.size(); ++i)
+ std::cout << Indent(level + 1, true) << info.authBy[i] << "\n";
+ }
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetUserParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "\tuser's password"));
+params.push_back(SGCONF::API_ACTION::PARAM("cash-add", "<cash[:message]>", "cash to add (with optional comment)"));
+params.push_back(SGCONF::API_ACTION::PARAM("cash-set", "<cash[:message]>", "cash to set (with optional comment)"));
+params.push_back(SGCONF::API_ACTION::PARAM("credit", "<amount>", "\tuser's credit"));
+params.push_back(SGCONF::API_ACTION::PARAM("credit-expire", "<date>", "\tcredit expiration"));
+params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traffic"));
+params.push_back(SGCONF::API_ACTION::PARAM("disabled", "<flag>", "\tdisable user (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("passive", "<flag>", "\tmake user passive (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("disable-detail-stat", "<flag>", "disable detail stat (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("always-online", "<flag>", "\tmake user always online (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("ips", "<ips>", "\t\tcoma-separated list of ips"));
+params.push_back(SGCONF::API_ACTION::PARAM("tariff", "<tariff name>", "\tcurrent tariff"));
+params.push_back(SGCONF::API_ACTION::PARAM("next-tariff", "<tariff name>", "tariff starting from the next month"));
+params.push_back(SGCONF::API_ACTION::PARAM("group", "<group>", "\t\tuser's group"));
+params.push_back(SGCONF::API_ACTION::PARAM("note", "<note>", "\t\tuser's note"));
+params.push_back(SGCONF::API_ACTION::PARAM("email", "<email>", "\t\tuser's email"));
+params.push_back(SGCONF::API_ACTION::PARAM("name", "<real name>", "\tuser's real name"));
+params.push_back(SGCONF::API_ACTION::PARAM("address", "<address>", "\tuser's postal address"));
+params.push_back(SGCONF::API_ACTION::PARAM("phone", "<phone>", "\t\tuser's phone number"));
+params.push_back(SGCONF::API_ACTION::PARAM("corp", "<corp name>", "\tcorporation name"));
+params.push_back(SGCONF::API_ACTION::PARAM("session-traffic", "<up/dn, ...>", "coma-separated session upload and download"));
+params.push_back(SGCONF::API_ACTION::PARAM("month-traffic", "<up/dn, ...>", "coma-separated month upload and download"));
+params.push_back(SGCONF::API_ACTION::PARAM("user-data", "<value, ...>", "coma-separated user data values"));
+return params;
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetCheckParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "\tuser's password"));
+return params;
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetMessageParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("logins", "<login, ...>", "\tlist of logins to send a message"));
+params.push_back(SGCONF::API_ACTION::PARAM("text", "<text>", "\t\tmessage text"));
+return params;
+}
+
+void ConvBool(const std::string & value, STG::Optional<int> & res)
+{
+res = !value.empty() && value[0] == 'y';
+}
+
+void Splice(std::vector<STG::Optional<std::string> > & lhs, const std::vector<STG::Optional<std::string> > & rhs)
+{
+for (size_t i = 0; i < lhs.size() && i < rhs.size(); ++i)
+ lhs[i].splice(rhs[i]);
+}
+
+STG::Optional<std::string> ConvString(const std::string & value)
+{
+return STG::Optional<std::string>(value);
+}
+
+void ConvStringList(std::string value, std::vector<STG::Optional<std::string> > & res)
+{
+Splice(res, Split<std::vector<STG::Optional<std::string> > >(value, ',', ConvString));
+}
+
+void ConvServices(std::string value, STG::Optional<std::vector<std::string> > & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+res = Split<std::vector<std::string> >(value, ',');
+}
+
+void ConvCreditExpire(const std::string & value, STG::Optional<time_t> & res)
+{
+struct tm brokenTime;
+if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
+ throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
+res = stg_timegm(&brokenTime);
+}
+
+void ConvIPs(const std::string & value, STG::Optional<STG::UserIPs> & res)
+{
+res = STG::UserIPs::parse(value);
+}
+
+struct TRAFF
+{
+ uint64_t up;
+ uint64_t down;
+};
+
+TRAFF ConvTraff(const std::string & value)
+{
+TRAFF res;
+size_t slashPos = value.find_first_of('/');
+if (slashPos == std::string::npos)
+ throw SGCONF::ACTION::ERROR("Traffic record should be in format 'upload/download'. Got: '" + value + "'");
+
+if (str2x(value.substr(0, slashPos), res.up) < 0)
+ throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(0, slashPos) + "'");
+if (str2x(value.substr(slashPos + 1, value.length() - slashPos), res.down) < 0)
+ throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
+return res;
+}
+
+void ConvSessionTraff(std::string value, STG::UserStatOpt & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
+if (traff.size() != DIR_NUM)
+ throw SGCONF::ACTION::ERROR("There should be prcisely " + std::to_string(DIR_NUM) + " records of session traffic.");
+for (size_t i = 0; i < DIR_NUM; ++i)
+ {
+ res.sessionUp[i] = traff[i].up;
+ res.sessionDown[i] = traff[i].down;
+ }
+}
+
+void ConvMonthTraff(std::string value, STG::UserStatOpt & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
+if (traff.size() != DIR_NUM)
+ throw SGCONF::ACTION::ERROR("There should be prcisely " + std::to_string(DIR_NUM) + " records of month traffic.");
+for (size_t i = 0; i < DIR_NUM; ++i)
+ {
+ res.monthUp[i] = traff[i].up;
+ res.monthDown[i] = traff[i].down;
+ }
+}
+
+void ConvCashInfo(const std::string & value, STG::Optional<STG::CashInfo> & res)
+{
+STG::CashInfo info;
+size_t pos = value.find_first_of(':');
+if (pos == std::string::npos)
+ {
+ if (str2x(value, info.first) < 0)
+ throw SGCONF::ACTION::ERROR("Cash should be a double value. Got: '" + value + "'");
+ }
+else
+ {
+ if (str2x(value.substr(0, pos), info.first) < 0)
+ throw SGCONF::ACTION::ERROR("Cash should be a double value. Got: '" + value + "'");
+ info.second = value.substr(pos + 1);
+ }
+res = info;
+}
+
+void SimpleCallback(bool result,
+ const std::string & reason,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Success.\n";
+}
+
+void GetUsersCallback(bool result,
+ const std::string & reason,
+ const std::vector<STG::GetUser::Info> & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get user list. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Users:\n";
+for (size_t i = 0; i < info.size(); ++i)
+ PrintUser(info[i], 1);
+}
+
+void GetUserCallback(bool result,
+ const std::string & reason,
+ const STG::GetUser::Info & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get user. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+PrintUser(info);
+}
+
+void AuthByCallback(bool result,
+ const std::string & reason,
+ const std::vector<std::string> & info,
+ void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get authorizer list. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+std::cout << "Authorized by:\n";
+for (size_t i = 0; i < info.size(); ++i)
+ std::cout << Indent(1, true) << info[i] << "\n";
+}
+
+bool GetUsersFunction(const SGCONF::CONFIG & config,
+ const std::string & /*arg*/,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetUsers(GetUsersCallback, NULL) == STG::st_ok;
+}
+
+bool GetUserFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.GetUser(arg, GetUserCallback, NULL) == STG::st_ok;
+}
+
+bool DelUserFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.DelUser(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddUserFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::UserConfOpt conf;
+SGCONF::MaybeSet(options, "password", conf.password);
+SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
+SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
+SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
+SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
+SGCONF::MaybeSet(options, "tariff", conf.tariffName);
+SGCONF::MaybeSet(options, "address", conf.address);
+SGCONF::MaybeSet(options, "phone", conf.phone);
+SGCONF::MaybeSet(options, "email", conf.email);
+SGCONF::MaybeSet(options, "note", conf.note);
+SGCONF::MaybeSet(options, "name", conf.realName);
+SGCONF::MaybeSet(options, "corp", conf.corp);
+SGCONF::MaybeSet(options, "services", conf.services, ConvServices);
+SGCONF::MaybeSet(options, "group", conf.group);
+SGCONF::MaybeSet(options, "credit", conf.credit);
+SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
+SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
+SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
+SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
+STG::UserStatOpt stat;
+SGCONF::MaybeSet(options, "cash-set", stat.cashSet, ConvCashInfo);
+SGCONF::MaybeSet(options, "free", stat.freeMb);
+SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
+SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.AddUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgUserFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+STG::UserConfOpt conf;
+SGCONF::MaybeSet(options, "password", conf.password);
+SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
+SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
+SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
+SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
+SGCONF::MaybeSet(options, "tariff", conf.tariffName);
+SGCONF::MaybeSet(options, "address", conf.address);
+SGCONF::MaybeSet(options, "phone", conf.phone);
+SGCONF::MaybeSet(options, "email", conf.email);
+SGCONF::MaybeSet(options, "note", conf.note);
+SGCONF::MaybeSet(options, "name", conf.realName);
+SGCONF::MaybeSet(options, "corp", conf.corp);
+SGCONF::MaybeSet(options, "services", conf.services, ConvServices);
+SGCONF::MaybeSet(options, "group", conf.group);
+SGCONF::MaybeSet(options, "credit", conf.credit);
+SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
+SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
+SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
+SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
+STG::UserStatOpt stat;
+SGCONF::MaybeSet(options, "cash-add", stat.cashAdd, ConvCashInfo);
+SGCONF::MaybeSet(options, "cash-set", stat.cashSet, ConvCashInfo);
+SGCONF::MaybeSet(options, "free", stat.freeMb);
+SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
+SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.ChgUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool CheckUserFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & options)
+{
+std::map<std::string, std::string>::const_iterator it(options.find("password"));
+if (it == options.end())
+ throw SGCONF::ACTION::ERROR("Password is not specified.");
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.CheckUser(arg, it->second, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool SendMessageFunction(const SGCONF::CONFIG & config,
+ const std::string & /*arg*/,
+ const std::map<std::string, std::string> & options)
+{
+std::map<std::string, std::string>::const_iterator it(options.find("logins"));
+if (it == options.end())
+ throw SGCONF::ACTION::ERROR("Logins are not specified.");
+std::string logins = it->second;
+for (size_t i = 0; i < logins.length(); ++i)
+ if (logins[i] == ',')
+ logins[i] = ':';
+it = options.find("text");
+if (it == options.end())
+ throw SGCONF::ACTION::ERROR("Message text is not specified.");
+std::string text = it->second;
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.SendMessage(logins, text, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AuthByFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.AuthBy(arg, AuthByCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendUsersOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetUserParams());
+blocks.Add("User management options")
+ .Add("get-users", SGCONF::MakeAPIAction(commands, GetUsersFunction), "\tget user list")
+ .Add("get-user", SGCONF::MakeAPIAction(commands, "<login>", GetUserFunction), "get user")
+ .Add("add-user", SGCONF::MakeAPIAction(commands, "<login>", params, AddUserFunction), "add user")
+ .Add("del-user", SGCONF::MakeAPIAction(commands, "<login>", DelUserFunction), "delete user")
+ .Add("chg-user", SGCONF::MakeAPIAction(commands, "<login>", params, ChgUserFunction), "change user")
+ .Add("check-user", SGCONF::MakeAPIAction(commands, "<login>", GetCheckParams(), CheckUserFunction), "check user existance and credentials")
+ .Add("send-message", SGCONF::MakeAPIAction(commands, GetMessageParams(), SendMessageFunction), "send message")
+ .Add("auth-by", SGCONF::MakeAPIAction(commands, "<login>", AuthByFunction), "a list of authorizers user authorized by");
+}
--- /dev/null
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendUsersOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+}
--- /dev/null
+#pragma once
+
+#include "stg/common.h"
+#include "stg/optional.h"
+
+#include <string>
+#include <map>
+
+namespace SGCONF
+{
+
+template <typename T>
+inline
+void MaybeSet(const std::map<std::string, std::string> & options, const std::string & name, STG::Optional<T> & res)
+{
+std::map<std::string, std::string>::const_iterator it(options.find(name));
+if (it == options.end())
+ return;
+T value;
+if (str2x(it->second, value) < 0)
+ return;
+res = value;
+}
+
+template <typename T, typename F>
+inline
+void MaybeSet(const std::map<std::string, std::string> & options, const std::string & name, T & res, F conv)
+{
+std::map<std::string, std::string>::const_iterator it(options.find(name));
+if (it == options.end())
+ return;
+conv(it->second, res);
+}
+
+template <>
+inline
+void MaybeSet<std::string>(const std::map<std::string, std::string> & options, const std::string & name, STG::Optional<std::string> & res)
+{
+std::map<std::string, std::string>::const_iterator it(options.find(name));
+if (it == options.end())
+ return;
+res = it->second;
+}
+
+} // namespace SGCONF
--- /dev/null
+#include "xml.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+
+#include "stg/servconf.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+#include <expat.h>
+
+namespace
+{
+
+struct ParserState
+{
+size_t level;
+};
+
+std::string Indent(size_t level)
+{
+return std::string(level * 4, ' ');
+}
+
+std::string PrintAttr(const char ** attr)
+{
+std::string res;
+if (attr == NULL)
+ return res;
+while (*attr)
+ {
+ if (*(attr + 1) == NULL)
+ return res;
+ res += std::string(" ") + *attr + "=\"" + *(attr + 1) + "\"";
+ ++attr; ++attr;
+ }
+return res;
+}
+
+void Start(void * data, const char * el, const char ** attr)
+{
+ParserState * state = static_cast<ParserState *>(data);
+if (el != NULL)
+ std::cout << Indent(state->level) << "<" << el << PrintAttr(attr) << ">\n";
+++state->level;
+}
+
+void End(void * data, const char * el)
+{
+ParserState * state = static_cast<ParserState *>(data);
+--state->level;
+if (el != NULL)
+ std::cout << Indent(state->level) << "</" << el << ">\n";
+}
+
+void PrintXML(const std::string& xml)
+{
+ParserState state = { 0 };
+
+XML_Parser parser = XML_ParserCreate(NULL);
+XML_ParserReset(parser, NULL);
+XML_SetElementHandler(parser, Start, End);
+XML_SetUserData(parser, &state);
+
+if (XML_Parse(parser, xml.c_str(), xml.length(), true) == XML_STATUS_ERROR)
+ std::cerr << "XML parse error at line " << XML_GetCurrentLineNumber(parser)
+ << ": '" << XML_ErrorString(XML_GetErrorCode(parser)) << "'"
+ << std::endl;
+
+XML_ParserFree(parser);
+}
+
+void RawXMLCallback(bool result, const std::string & reason, const std::string & response, void * /*data*/)
+{
+if (!result)
+ {
+ std::cerr << "Failed to get raw XML response. Reason: '" << reason << "'." << std::endl;
+ return;
+ }
+PrintXML(response);
+}
+
+bool RawXMLFunction(const SGCONF::CONFIG & config,
+ const std::string & arg,
+ const std::map<std::string, std::string> & /*options*/)
+{
+STG::ServConf proto(config.server.data(),
+ config.port.data(),
+ config.localAddress.data(),
+ config.localPort.data(),
+ config.userName.data(),
+ config.userPass.data());
+return proto.RawXML(arg, RawXMLCallback, NULL) == STG::st_ok;
+}
+
+}
+
+void SGCONF::AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+blocks.Add("Raw XML")
+ .Add("r", "raw", SGCONF::MakeAPIAction(commands, "<xml>", RawXMLFunction), "\tmake raw XML request");
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+}
--- /dev/null
+set ( CPP_FILES main.cpp
+ admins_impl.cpp
+ users_impl.cpp
+ tariffs_impl.cpp
+ corps_impl.cpp
+ services_impl.cpp
+ user_impl.cpp
+ tariff_impl.cpp
+ eventloop.cpp
+ pidfile.cpp
+ plugin_runner.cpp
+ plugin_mgr.cpp
+ settings_impl.cpp
+ stg_timer.cpp
+ store_loader.cpp
+ traffcounter_impl.cpp
+ user_property.cpp )
+
+set ( THREADS_PREFER_PTHREAD_FLAG ON )
+find_package ( Threads REQUIRED )
+
+add_executable ( stargazer ${CPP_FILES} )
+
+target_link_libraries ( stargazer scriptexecuter dotconfpp logger common Threads::Threads ${CMAKE_DL_LIBS} )
+
+add_subdirectory ( plugins )
+
+# TODO: install
--- /dev/null
+Инсталяция и запуск.
+1. > ./build
+2. > make install
+3. Правка конфигурационных файлов
+4. > stargazer
+
--- /dev/null
+#ifndef __ACTIONS_H__
+#define __ACTIONS_H__
+
+// Usage:
+//
+// ACTIONS_LIST actionsList;
+// CLASS myClass;
+// DATA1 myData1;
+// DATA2 myData2;
+//
+// actionsList.Enqueue(myClass, &CLASS::myMethod1, myData1);
+// actionsList.Enqueue(myClass, &CLASS::myMethod2, myData2);
+//
+// actionsList.InvokeAll();
+
+#include <pthread.h>
+#include <vector>
+#include <functional>
+
+// Generalized actor type - a method of some class with one argument
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+struct ACTOR
+{
+typedef void (ACTIVE_CLASS::*TYPE)(DATA_TYPE);
+};
+
+// Abstract base action class for polymorphic action invocation
+class BASE_ACTION
+{
+public:
+ virtual ~BASE_ACTION() {}
+ virtual void Invoke() = 0;
+};
+
+// Concrete generalized action type - an actor with it's data and owner
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+class ACTION : public BASE_ACTION,
+ public std::unary_function<ACTIVE_CLASS &, void>
+{
+public:
+ ACTION(ACTIVE_CLASS & ac,
+ typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+ DATA_TYPE d)
+ : activeClass(ac), actor(a), data(d) {}
+ void Invoke();
+private:
+ ACTION(const ACTION<ACTIVE_CLASS, DATA_TYPE> & rvalue);
+ ACTION<ACTIVE_CLASS, DATA_TYPE> & operator=(const ACTION<ACTIVE_CLASS, DATA_TYPE> & rvalue);
+
+ ACTIVE_CLASS & activeClass;
+ typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE actor;
+ DATA_TYPE data;
+};
+
+// A list of an actions
+// All methods are thread-safe
+class ACTIONS_LIST : private std::vector<BASE_ACTION *>
+{
+public:
+ // Just a typedef for parent class
+ typedef std::vector<BASE_ACTION *> parent;
+
+ // Initialize mutex
+ ACTIONS_LIST();
+ // Delete actions and destroy mutex
+ virtual ~ACTIONS_LIST();
+
+ parent::iterator begin();
+ parent::iterator end();
+ parent::const_iterator begin() const;
+ parent::const_iterator end() const;
+
+ bool empty() const;
+ size_t size() const;
+ void swap(ACTIONS_LIST & list);
+
+ // Add an action to list
+ template <class ACTIVE_CLASS, typename DATA_TYPE>
+ void Enqueue(ACTIVE_CLASS & ac,
+ typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+ DATA_TYPE d);
+ // Invoke all actions in the list
+ void InvokeAll();
+private:
+ mutable pthread_mutex_t mutex;
+};
+
+#include "actions.inl.h"
+
+#endif
--- /dev/null
+#ifndef __ACTIONS_INL_H__
+#define __ACTIONS_INL_H__
+
+#include <algorithm>
+
+#include "stg/locker.h"
+
+// Polymorphick action invocation
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+inline
+void ACTION<ACTIVE_CLASS, DATA_TYPE>::Invoke()
+{
+(activeClass.*actor)(data);
+}
+
+inline
+ACTIONS_LIST::ACTIONS_LIST()
+ : mutex()
+{
+pthread_mutex_init(&mutex, NULL);
+}
+
+// Delete all actions before deleting list
+inline
+ACTIONS_LIST::~ACTIONS_LIST()
+{
+
+ {
+ STG_LOCKER lock(&mutex);
+
+ parent::iterator it(parent::begin());
+ while (it != parent::end())
+ {
+ delete *it++;
+ }
+ }
+
+pthread_mutex_destroy(&mutex);
+}
+
+inline
+ACTIONS_LIST::parent::iterator ACTIONS_LIST::begin()
+{
+STG_LOCKER lock(&mutex);
+return parent::begin();
+}
+
+inline
+ACTIONS_LIST::parent::iterator ACTIONS_LIST::end()
+{
+STG_LOCKER lock(&mutex);
+return parent::end();
+}
+
+inline
+ACTIONS_LIST::parent::const_iterator ACTIONS_LIST::begin() const
+{
+STG_LOCKER lock(&mutex);
+return parent::begin();
+}
+
+inline
+ACTIONS_LIST::parent::const_iterator ACTIONS_LIST::end() const
+{
+STG_LOCKER lock(&mutex);
+return parent::end();
+}
+
+inline
+bool ACTIONS_LIST::empty() const
+{
+STG_LOCKER lock(&mutex);
+return parent::empty();
+}
+
+inline
+size_t ACTIONS_LIST::size() const
+{
+STG_LOCKER lock(&mutex);
+return parent::size();
+}
+
+inline
+void ACTIONS_LIST::swap(ACTIONS_LIST & list)
+{
+STG_LOCKER lock(&mutex);
+parent::swap(list);
+}
+
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+inline
+void ACTIONS_LIST::Enqueue(ACTIVE_CLASS & ac,
+ typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+ DATA_TYPE d)
+{
+STG_LOCKER lock(&mutex);
+push_back(new ACTION<ACTIVE_CLASS, DATA_TYPE>(ac, a, d));
+}
+
+inline
+void ACTIONS_LIST::InvokeAll()
+{
+STG_LOCKER lock(&mutex);
+std::for_each(
+ parent::begin(),
+ parent::end(),
+ [](auto action){ action->Invoke(); });
+}
+
+#endif
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 27.10.2002
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include "admins_impl.h"
+
+#include "stg/common.h"
+
+using STG::AdminsImpl;
+
+//-----------------------------------------------------------------------------
+AdminsImpl::AdminsImpl(Store& st)
+ : m_stg(Priv(0xFFFF), "@stargazer", ""),
+ m_noAdmin(Priv(0xFFFF), "NO-ADMIN", ""),
+ m_store(st),
+ WriteServLog(Logger::get())
+{
+ read();
+}
+//-----------------------------------------------------------------------------
+int AdminsImpl::add(const std::string& login, const Admin& admin)
+{
+ if (!admin.priv().adminChg)
+ {
+ const std::string s = admin.logStr() + " Add administrator \'" + login + "\'. Access denied.";
+ m_strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ const auto it = find(login);
+
+ if (it != m_data.end())
+ {
+ m_strError = "Administrator \'" + login + "\' cannot not be added. Administrator already exists.";
+ WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
+ return -1;
+ }
+
+ m_data.push_back(Admin(Priv(0), login, {}));
+
+ if (m_store.AddAdmin(login) == 0)
+ {
+ WriteServLog("%s Administrator \'%s\' added.",
+ admin.logStr().c_str(), login.c_str());
+ return 0;
+ }
+
+ m_strError = "Administrator \'" + login + "\' was not added. Error: " + m_store.GetStrError();
+ WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
+
+ return -1;
+}
+//-----------------------------------------------------------------------------
+int AdminsImpl::del(const std::string& login, const Admin& admin)
+{
+ if (!admin.priv().adminChg)
+ {
+ const std::string s = admin.logStr() + " Delete administrator \'" + login + "\'. Access denied.";
+ m_strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ const auto it = find(login);
+
+ if (it == m_data.end())
+ {
+ m_strError = "Administrator \'" + login + "\' cannot be deleted. Administrator does not exist.";
+ WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
+ return -1;
+ }
+
+ m_data.erase(it);
+ if (m_store.DelAdmin(login) < 0)
+ {
+ m_strError = "Administrator \'" + login + "\' was not deleted. Error: " + m_store.GetStrError();
+ WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
+
+ return -1;
+ }
+
+ WriteServLog("%s Administrator \'%s\' deleted.", admin.logStr().c_str(), login.c_str());
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int AdminsImpl::change(const AdminConf& ac, const Admin& admin)
+{
+ if (!admin.priv().adminChg)
+ {
+ const std::string s = admin.logStr() + " Change administrator \'" + ac.login + "\'. Access denied.";
+ m_strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ const auto it = find(ac.login);
+
+ if (it == m_data.end())
+ {
+ m_strError = "Administrator \'" + ac.login + "\' cannot be changed " + ". Administrator does not exist.";
+ WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
+ return -1;
+ }
+
+ *it = ac;
+ if (m_store.SaveAdmin(ac))
+ {
+ WriteServLog("Cannot write admin %s.", ac.login.c_str());
+ WriteServLog("%s", m_store.GetStrError().c_str());
+ return -1;
+ }
+
+ WriteServLog("%s Administrator \'%s\' changed.",
+ admin.logStr().c_str(), ac.login.c_str());
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+void AdminsImpl::read()
+{
+ std::vector<std::string> logins;
+ if (m_store.GetAdminsList(&logins) < 0)
+ {
+ WriteServLog(m_store.GetStrError().c_str());
+ return;
+ }
+
+ std::vector<Admin> admins;
+ for (const auto& login : logins)
+ {
+ AdminConf ac(Priv(0), login, "");
+
+ if (m_store.RestoreAdmin(&ac, login))
+ {
+ WriteServLog(m_store.GetStrError().c_str());
+ return;
+ }
+
+ m_data.push_back(Admin(ac));
+ }
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_data.swap(admins);
+}
+//-----------------------------------------------------------------------------
+bool AdminsImpl::find(const std::string& login, Admin** admin)
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (m_data.empty())
+ {
+ printfd(__FILE__, "No admin in system!\n");
+ if (admin != nullptr)
+ *admin = &m_noAdmin;
+ return false;
+ }
+
+ auto it = find(login);
+
+ if (it != m_data.end())
+ {
+ if (admin != nullptr)
+ *admin = &(*it);
+ return false;
+ }
+
+ return true;
+}
+//-----------------------------------------------------------------------------
+bool AdminsImpl::exists(const std::string& login) const
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (m_data.empty())
+ {
+ printfd(__FILE__, "No admin in system!\n");
+ return true;
+ }
+
+ return find(login) != m_data.end();
+}
+//-----------------------------------------------------------------------------
+bool AdminsImpl::correct(const std::string& login, const std::string& password, Admin** admin)
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (m_data.empty())
+ {
+ printfd(__FILE__, "No admin in system!\n");
+ return true;
+ }
+
+ const auto it = find(login);
+
+ if (it == m_data.end() || it->password() != password)
+ return false;
+
+ if (admin != nullptr)
+ *admin = &(*it);
+
+ return true;
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 27.10.2002
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/admins.h"
+#include "stg/admin.h"
+#include "stg/store.h"
+#include "stg/logger.h"
+
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <mutex>
+
+namespace STG
+{
+
+class AdminsImpl : public Admins
+{
+ public:
+ explicit AdminsImpl(Store& st);
+
+ AdminsImpl(const AdminsImpl&) = delete;
+ AdminsImpl& operator=(const AdminsImpl&) = delete;
+
+ int add(const std::string& login, const Admin& admin) override;
+ int del(const std::string& login, const Admin& admin) override;
+ int change(const AdminConf& ac, const Admin& admin) override;
+ const Admin& sysAdmin() const override { return m_stg; }
+ const Admin& noAdmin() const override { return m_noAdmin; }
+ bool find(const std::string& login, Admin** admin) override;
+ bool exists(const std::string& login) const override;
+ bool correct(const std::string& login,
+ const std::string& password,
+ Admin** admin) override;
+
+ const std::string& strError() const override { return m_strError; }
+
+ size_t count() const override { return m_data.size(); }
+
+ void fmap(std::function<void (const Admin&)> callback) const
+ {
+ for (const auto& admin : m_data)
+ callback(admin);
+ }
+
+ private:
+ void read();
+ auto find(const std::string& login) { return std::find(m_data.begin(), m_data.end(), Admin(Priv(0), login, "")); }
+ auto find(const std::string& login) const { return std::find(m_data.begin(), m_data.end(), Admin(Priv(0), login, "")); }
+
+ Admin m_stg;
+ Admin m_noAdmin;
+ std::vector<Admin> m_data;
+ Store& m_store;
+ Logger& WriteServLog;
+ mutable std::mutex m_mutex;
+ std::string m_strError;
+};
+
+}
--- /dev/null
+/*
+ * 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 "corps_impl.h"
+
+#include "stg/admin.h"
+#include "stg/admin_conf.h"
+#include "stg/store.h"
+#include "stg/common.h"
+
+#include <algorithm>
+#include <cassert>
+
+using STG::CorporationsImpl;
+
+//-----------------------------------------------------------------------------
+CorporationsImpl::CorporationsImpl(Store * st)
+ : store(st),
+ WriteServLog(Logger::get()),
+ handle(0)
+{
+Read();
+}
+//-----------------------------------------------------------------------------
+int CorporationsImpl::Add(const CorpConf & corp, const Admin * admin)
+{
+std::lock_guard<std::mutex> lock(mutex);
+const auto& priv = admin->priv();
+
+if (!priv.corpChg)
+ {
+ std::string s = admin->logStr() + " Add corporation \'" + corp.name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+crp_iter si(find(data.begin(), data.end(), corp));
+
+if (si != data.end())
+ {
+ strError = "Corporation \'" + corp.name + "\' cannot not be added. Corporation already exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+
+ return -1;
+ }
+
+data.push_back(corp);
+
+if (store->AddCorp(corp.name) == 0)
+ {
+ WriteServLog("%s Corporation \'%s\' added.",
+ admin->logStr().c_str(), corp.name.c_str());
+ return 0;
+ }
+
+strError = "Corporation \'" + corp.name + "\' was not added. Error: " + store->GetStrError();
+WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+int CorporationsImpl::Del(const std::string & name, const Admin * admin)
+{
+std::lock_guard<std::mutex> lock(mutex);
+const auto& priv = admin->priv();
+
+if (!priv.corpChg)
+ {
+ std::string s = admin->logStr() + " Delete corporation \'" + name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+crp_iter si(find(data.begin(), data.end(), CorpConf(name)));
+
+if (si == data.end())
+ {
+ strError = "Corporation \'" + name + "\' cannot be deleted. Corporation does not exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+std::map<int, const_crp_iter>::iterator csi;
+csi = searchDescriptors.begin();
+while (csi != searchDescriptors.end())
+ {
+ if (csi->second == si)
+ (csi->second)++;
+ ++csi;
+ }
+
+data.erase(si);
+if (store->DelCorp(name) < 0)
+ {
+ strError = "Corporation \'" + name + "\' was not deleted. Error: " + store->GetStrError();
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+
+ return -1;
+ }
+
+WriteServLog("%s Corporation \'%s\' deleted.", admin->logStr().c_str(), name.c_str());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CorporationsImpl::Change(const CorpConf & corp, const Admin * admin)
+{
+std::lock_guard<std::mutex> lock(mutex);
+const auto& priv = admin->priv();
+
+if (!priv.corpChg)
+ {
+ std::string s = admin->logStr() + " Change corporation \'" + corp.name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+crp_iter si(find(data.begin(), data.end(), corp));
+
+if (si == data.end())
+ {
+ strError = "Corporation \'" + corp.name + "\' cannot be changed " + ". Corporation does not exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+*si = corp;
+if (store->SaveCorp(corp))
+ {
+ WriteServLog("Cannot write corporation %s.", corp.name.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ return -1;
+ }
+
+WriteServLog("%s Corporation \'%s\' changed.",
+ admin->logStr().c_str(), corp.name.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool CorporationsImpl::Read()
+{
+std::lock_guard<std::mutex> lock(mutex);
+std::vector<std::string> corpsList;
+if (store->GetCorpsList(&corpsList) < 0)
+ {
+ WriteServLog(store->GetStrError().c_str());
+ return true;
+ }
+
+for (size_t i = 0; i < corpsList.size(); i++)
+ {
+ CorpConf corp;
+
+ if (store->RestoreCorp(&corp, corpsList[i]))
+ {
+ WriteServLog(store->GetStrError().c_str());
+ return true;
+ }
+
+ data.push_back(corp);
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+bool CorporationsImpl::Find(const std::string & name, CorpConf * corp)
+{
+assert(corp != NULL && "Pointer to corporation is not null");
+
+std::lock_guard<std::mutex> lock(mutex);
+if (data.empty())
+ return false;
+
+crp_iter si(find(data.begin(), data.end(), CorpConf(name)));
+
+if (si != data.end())
+ {
+ *corp = *si;
+ return false;
+ }
+
+return true;
+}
+//-----------------------------------------------------------------------------
+bool CorporationsImpl::Exists(const std::string & name) const
+{
+std::lock_guard<std::mutex> lock(mutex);
+if (data.empty())
+ {
+ printfd(__FILE__, "no corporations in system!\n");
+ return true;
+ }
+
+const_crp_iter si(find(data.begin(), data.end(), CorpConf(name)));
+
+if (si != data.end())
+ return true;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+int CorporationsImpl::OpenSearch() const
+{
+std::lock_guard<std::mutex> lock(mutex);
+handle++;
+searchDescriptors[handle] = data.begin();
+return handle;
+}
+//-----------------------------------------------------------------------------
+int CorporationsImpl::SearchNext(int h, CorpConf * corp) const
+{
+std::lock_guard<std::mutex> lock(mutex);
+if (searchDescriptors.find(h) == searchDescriptors.end())
+ {
+ WriteServLog("CORPORATIONS. Incorrect search handle.");
+ return -1;
+ }
+
+if (searchDescriptors[h] == data.end())
+ return -1;
+
+*corp = *searchDescriptors[h]++;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CorporationsImpl::CloseSearch(int h) const
+{
+std::lock_guard<std::mutex> lock(mutex);
+if (searchDescriptors.find(h) != searchDescriptors.end())
+ {
+ searchDescriptors.erase(searchDescriptors.find(h));
+ return 0;
+ }
+
+WriteServLog("CORPORATIONS. Incorrect search handle.");
+return -1;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/corporations.h"
+#include "stg/corp_conf.h"
+#include "stg/locker.h"
+#include "stg/logger.h"
+
+#include <vector>
+#include <map>
+#include <string>
+#include <mutex>
+
+namespace STG
+{
+
+struct Admin;
+struct Store;
+
+class CorporationsImpl : public Corporations {
+public:
+ explicit CorporationsImpl(Store* st);
+
+ int Add(const CorpConf& corp, const Admin* admin) override;
+ int Del(const std::string& name, const Admin* admin) override;
+ int Change(const CorpConf& corp, const Admin* admin) override;
+ bool Find(const std::string& name, CorpConf* corp) override;
+ bool Exists(const std::string& name) const override;
+ const std::string& GetStrError() const override { return strError; }
+
+ size_t Count() const override { return data.size(); }
+
+ int OpenSearch() const override;
+ int SearchNext(int, CorpConf* corp) const override;
+ int CloseSearch(int) const override;
+
+private:
+ typedef std::vector<CorpConf>::iterator crp_iter;
+ typedef std::vector<CorpConf>::const_iterator const_crp_iter;
+
+ bool Read();
+
+ std::vector<CorpConf> data;
+ Store* store;
+ Logger& WriteServLog;
+ mutable std::map<int, const_crp_iter> searchDescriptors;
+ mutable unsigned int handle;
+ mutable std::mutex mutex;
+ std::string strError;
+};
+
+}
--- /dev/null
+#include <csignal>
+#include <cerrno>
+#include <cstring>
+
+#include "stg/locker.h"
+#include "stg/common.h"
+#include "eventloop.h"
+
+EVENT_LOOP::EVENT_LOOP()
+ : ACTIONS_LIST(),
+ _running(false),
+ _stopped(true),
+ _tid(),
+ _mutex(),
+ _condition()
+{
+pthread_mutex_init(&_mutex, NULL);
+pthread_cond_init(&_condition, NULL);
+}
+
+EVENT_LOOP::~EVENT_LOOP()
+{
+pthread_cond_destroy(&_condition);
+pthread_mutex_destroy(&_mutex);
+}
+
+bool EVENT_LOOP::Start()
+{
+_running = true;
+if (pthread_create(&_tid, NULL, Run, this))
+ {
+ printfd(__FILE__, "EVENT_LOOP::Start - Failed to create thread: '%s'\n", strerror(errno));
+ return true;
+ }
+return false;
+}
+
+bool EVENT_LOOP::Stop()
+{
+_running = false;
+// Wake up thread
+pthread_cond_signal(&_condition);
+// Wait until thread exit
+pthread_join(_tid, NULL);
+return false;
+}
+
+void * EVENT_LOOP::Run(void * self)
+{
+EVENT_LOOP * ev = static_cast<EVENT_LOOP *>(self);
+ev->Runner();
+return NULL;
+}
+
+void EVENT_LOOP::Runner()
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+_stopped = false;
+printfd(__FILE__, "EVENT_LOOP::Runner - Before start\n");
+while (_running)
+ {
+ {
+ STG_LOCKER lock(&_mutex);
+ // Check for any actions...
+ if (empty())
+ {
+ // ... and sleep until new actions added
+ printfd(__FILE__, "EVENT_LOOP::Runner - Sleeping until new actions arrived\n");
+ pthread_cond_wait(&_condition, &_mutex);
+ }
+ // Check for running after wake up
+ if (!_running)
+ {
+ // Don't process any actions if stopping
+ break;
+ }
+ }
+ // Create new empty actions list
+ ACTIONS_LIST local;
+ // Fast swap with current
+ swap(local);
+ // Invoke all current actions
+ printfd(__FILE__, "EVENT_LOOP::Runner - Invoke %d actions\n", local.size());
+ local.InvokeAll();
+ }
+printfd(__FILE__, "EVENT_LOOP::Runner - Before stop\n");
+_stopped = true;
+}
+
+namespace {
+
+pthread_mutex_t singletonMutex;
+
+}
+
+EVENT_LOOP & EVENT_LOOP_SINGLETON::GetInstance()
+{
+// Double-checking technique
+if (!_instance)
+ {
+ STG_LOCKER lock(&singletonMutex);
+ if (!_instance)
+ {
+ CreateInstance();
+ }
+ }
+return *_instance;
+}
+
+void EVENT_LOOP_SINGLETON::CreateInstance()
+{
+static EVENT_LOOP loop;
+_instance = &loop;
+}
+
+EVENT_LOOP * EVENT_LOOP_SINGLETON::_instance = NULL;
--- /dev/null
+#ifndef __EVENT_LOOP_H__
+#define __EVENT_LOOP_H__
+
+#include <pthread.h>
+
+#include "stg/noncopyable.h"
+#include "actions.h"
+
+class EVENT_LOOP : private NONCOPYABLE,
+ private ACTIONS_LIST
+{
+ public:
+ bool Start();
+ bool Stop();
+ bool IsRunning() const { return _running; }
+
+ template <class ACTIVE_CLASS, typename DATA_TYPE>
+ void Enqueue(ACTIVE_CLASS & ac,
+ typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+ DATA_TYPE d);
+
+ private:
+ bool _running;
+ bool _stopped;
+ pthread_t _tid;
+ pthread_mutex_t _mutex;
+ pthread_cond_t _condition;
+
+ EVENT_LOOP();
+ virtual ~EVENT_LOOP();
+
+ static void * Run(void *);
+ void Runner();
+
+ friend class EVENT_LOOP_SINGLETON;
+};
+
+class EVENT_LOOP_SINGLETON : private NONCOPYABLE
+{
+ public:
+ static EVENT_LOOP & GetInstance();
+
+ private:
+ static EVENT_LOOP * _instance;
+ static void CreateInstance();
+
+ EVENT_LOOP_SINGLETON() {}
+ ~EVENT_LOOP_SINGLETON() {}
+};
+
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+void EVENT_LOOP::Enqueue(ACTIVE_CLASS & ac,
+ typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+ DATA_TYPE d)
+{
+STG_LOCKER lock(&_mutex);
+// Add new action
+ACTIONS_LIST::Enqueue(ac, a, d);
+// Signal about new action
+pthread_cond_signal(&_condition);
+}
+
+#endif
--- /dev/null
+#! /bin/sh
+
+login=$1
+param=$2
+oldValue=$3
+newValue=$4
+
+#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
\ No newline at end of file
--- /dev/null
+#! /bin/sh
+
+#Этот скрипт вызывается в момент, когда пользователь
+#успешно прошел авторизацию на сервере. Задача скрипта - перестроить
+#файрвол так, что бы пользователь получил доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+
+#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
--- /dev/null
+#! /bin/sh
+
+# Этот скрипт вызывается в момент, когда пользователь
+# желает отключится от интернета или вышел таймаут у пользователя
+# и сервер сам отключает пользователя
+# Задача скрипта подобна задаче скрипта OnConnect - перестроить
+# файрвол так, что бы пользователю закрыть доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$5
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
--- /dev/null
+#! /bin/sh
+
+# Использование (неиспользование) этого скрипта дело вкуса.
+# Он не выполняет критических функций. Его задача автматизировать
+# действия характерные при добавлении пользователя сети, например добавлекние
+# пользователю почты
+
+# Login
+login=$1
+
+#echo "added user $login" >> /var/stargazer/add_del.log
+
+
+
--- /dev/null
+#! /bin/sh
+
+# Login
+login=$1
+
+#echo "deleted user $login" >> /var/stargazer/add_del.log
+
--- /dev/null
+# Enable the authorization module Always Online "mod_auth_ao.so"
+<Module auth_ao>
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the traffic capture module "mod_cap_ipq.so" using Berkeley Packet Filter
+<Module cap_bpf>
+ # Define interface(s) for traffic capture
+ iface = rl0
+ iface = rl1
+ iface = dc0
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the traffic capture module "mod_cap_divert.so" using Divert-sockets
+<Module cap_divert>
+ # Port for traffic
+ # Parameter: optional
+ # Value: 1 ... 65535
+ # Default: 15701
+ Port = 15701
+
+ # Disable packet forwarding
+ # Parameter: optional
+ # Value: yes, no
+ # Default: no
+ DisableForwarding = no
+</Module>
--- /dev/null
+# Enable the traffic capture module "mod_cap_ipq.so" using NetFlow protocol
+<Module cap_nf>
+ # Port for TCP connections
+ # Note: Parameters TCPPort and UDPPort can be equal
+ # Parameter: optional
+ # Value: 1 ... 65535
+ # Default: 9996
+ #TCPPort = 9996
+
+ # Port for UDP connections
+ # Note: Parameters TCPPort and UDPPort can be equal
+ # Parameter: optional
+ # Value: 1 ... 65535
+ # Default: 9996
+ UDPPort = 9996
+</Module>
--- /dev/null
+# Enable the authorization module InetAccess "mod_auth_ia.so"
+<Module auth_ia>
+ # Port on which the server interacts with authorizator
+ # Parameter: required
+ # Value: 1 ... 65535
+ # Default: 5555
+ Port = 5555
+
+ # The time interval between sending an alive query to the user
+ # and updating statistics
+ # Parameter: required
+ # Values: 5 ... 600 (seconds)
+ # Default: 60
+ UserDelay = 60
+
+ # User timeout. If authorizer does not respond during this time,
+ # the user will be disconnected
+ # Parameter: required
+ # Values: 5 ... 600
+ # Default: 60
+ UserTimeout = 65
+
+ # Define which information will be transmitted from the server to InetAccess
+ # as a residue of prepaid traffic
+ # FreeMb = 0 — amount of free megabytes in terms of cost of zero direction
+ # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
+ # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
+ # FreeMb = 2 — amount of free megabytes in terms of cost of the second direction
+ # ........................
+ # FreeMb = 9 — amount of free megabytes in terms of cost of the ninth direction
+ # FreeMb = cash - amount of money for which the user can download for free
+ # FreeMb = none - no transfer
+ # Default: cash
+ # Parameter: required
+ # Values: different, see above
+ # Default: cash
+ FreeMb = cash
+
+ # Enable protocol errors logging
+ # Parameter: optional
+ # Values: yes, no
+ # Default: no
+ # LogProtocolErrors = no
+</Module>
--- /dev/null
+# Enable the module that pings users "mod_ping.so"
+<Module ping>
+ # The time interval between pings
+ # Parameter: required
+ # Value: 10 ... 3600 (seconds)
+ # Default: 15
+ PingDelay = 15
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the interaction module for FreeRADIUS "mod_radius.so"
+<Module radius>
+ # FreeRADIUS password
+ # Parameter: required
+ # Values: any, supported by software
+ # Default: 123456
+ Password = 123456
+
+ # FreeRADIUS server
+ # Parameter: required
+ # Values: IP address or DNS name
+ # Default: 127.0.0.1
+ ServerIP = 127.0.0.1
+
+ # FreeRADIUS port
+ # Parameter: required
+ # Value: 1 ... 65535
+ # Default: 6666
+ Port = 6666
+
+ # List of services for which will be carried out FreeRADIUS authentication
+ # Note: Parameter can be blank
+ # Parameter: required
+ # Value: any, supported by software
+ # Default: Login-User
+ AuthServices = Login-User
+
+ # List of services for which will be carried out FreeRADIUS Accounting
+ # Note: Parameter can be blank
+ # Parameter: required
+ # Value: any, supported by software
+ # Default: Framed-User
+ AcctServices = Framed-User
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the module for remote execution of scripts OnConnect and OnDisconnect "mod_remote_script.so"
+<Module remote_script>
+ # The time interval between sending confirmations that the user is online
+ # Parametr: required
+ # Values: 10 ... 600 (seconds)
+ # Default: 60
+ SendPeriod = 15
+
+ # Define mapping between subnet(s) and remote server(s)
+ # File format: <subnet> <Router1> <Router2> ...
+ # Example:
+ # 192.168.1.0/24 192.168.1.7 192.168.1.8
+ # 192.168.2.0/24 192.168.2.5 192.168.2.6 192.168.2.7
+ # 192.168.3.0/24 192.168.3.5
+ # 192.168.4.0/24 192.168.4.5
+ # Parametr: required
+ # Values: file path
+ # Default: subnets
+ SubnetFile = subnets
+
+ # The password to encrypt packets between the stg-server and remote server
+ # Parameter: required
+ # Values: any
+ # Default: 123456
+ Password = 123456
+
+ # Define which user parameters are transferred to a remote server in addition to
+ # other parameters that transfered by default (ID, IP, Login, Cash, Dirs).
+ # Note: Parameter can be blank.
+ # Parameter: required
+ # Values: Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName,
+ # NextTariff, Address, Note, Group, Email, RealName, Credit, EnabledDirs,
+ # Userdata0...Userdata9
+ # Default: Cash Tariff EnabledDirs
+ UserParams = Cash Tariff EnabledDirs
+
+ # Port on which the server interacts with remote server
+ # Parameter: required
+ # Value: 1...65535
+ # Default: 9999
+ Port = 9999
+</Module>
--- /dev/null
+# Enable the configuration module ConfRPC "mod_conf_rpc.so"
+<Module conf_rpc>
+ # Port on which the server interacts with configurator
+ # Parameter: required
+ # Value: 1...65535
+ # Default:
+ Port = 8080
+
+ # Session timeout in seconds
+ # Parameter: required
+ # Value: positive integer
+ # Default: 1800
+ CookieTimeout = 1800
+</Module>
--- /dev/null
+# Enable the configuration module SgConfig "mod_conf_sg.so"
+<Module conf_sg>
+ # Port on which the server interacts with configurator
+ # Parameter: required
+ # Value: 1...65535
+ # Default: 5555
+ Port = 5555
+</Module>
\ No newline at end of file
--- /dev/null
+# Enables SMUX-peer for SNMPd.
+<Module smux>
+ # IP-address of a server to connect to
+ # Parameter: required
+ # Value: X.X.X.X
+ # Default: 127.0.0.1
+ Server = 127.0.0.1
+
+ # Port number on a server to connect to
+ # Parameter: required
+ # Value: 1 ... 65535
+ # Default: 199
+ Port = 199
+
+ # Password for authentication on a server
+ # Parameter: required
+ # Value: any text
+ Password =
+</Module>
--- /dev/null
+# Enables plain file backend.
+<StoreModule store_files>
+
+ # Working server directory, provides data on tariffs, users, administrators.
+ # Parameter: required
+ # Value: directory path
+ WorkDir = /var/stargazer
+
+ # Owner, group and permissions of the files of user statistics (stat)
+ # Parameter: required
+ # Values: any, supported by OS
+ ConfOwner = root
+ ConfGroup = root
+ ConfMode = 640
+
+ # Owner, group and permissions on user configuration files (conf)
+ # Parameter: required
+ # Values: any, supported by OS
+ StatOwner = root
+ StatGroup = root
+ StatMode = 640
+
+ # Owner, group and permissions for user log files (log)
+ # Parameter: required
+ # Values: any, supported by OS
+ UserLogOwner = root
+ UserLogGroup = root
+ UserLogMode = 640
+
+</StoreModule>
--- /dev/null
+# Enables Firebird backend.
+<StoreModule store_firebird>
+ # Database server address
+ # Parameter: optional
+ # Value: IP address or DNS name
+ # Default: localhost
+ # Server = localhost
+
+ # Path to the database on the server or its alias
+ # Parameter: optional
+ # Value: file path
+ # Default: /var/stg/stargazer.fdb
+ # Database = /var/stg/stargazer.fdb
+
+ # Database username
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: stg
+ # User = stg
+
+ # Database password
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: 123456
+ # Password = 123456
+
+ # The transaction isolation level
+ # Parameter: optional
+ # Values: concurrency, dirtyread, readcommitted, consistency
+ # Defalt: concurrency
+ # IsolationLevel = concurrency
+
+ # Responding to lock (optional, defaults to wait):
+ # Parameter: optional
+ # Values: wait, nowait
+ # Defalt: wait
+ # LockResolution = wait
+</StoreModule>
--- /dev/null
+# Enables MySQL backend.
+<StoreModule store_mysql>
+ # Database server address
+ # Parameter: required
+ # Value: IP address or DNS name
+ # Default: localhost
+ Server = localhost
+
+ # Database name
+ # Parameter: required
+ # Value: any, supported by database
+ # Default: stg
+ Database = stg
+
+ # Database username
+ # Parameter: required
+ # Value: any, supported by database
+ # Default: stg
+ User = stg
+
+ # Database password
+ # Parameter: required
+ # Value: any, supported by database
+ # Default: 123456
+ Password = 123456
+</StoreModule>
--- /dev/null
+# Enables PostgreSQL backend.
+<StoreModule store_postgresql>
+ # Database server address
+ # Parameter: optional
+ # Value: IP address or DNS name
+ # Default: localhost
+ # Server = localhost
+
+ # Database name
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: stargazer
+ # Database = stargazer
+
+ # Database username
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: stg
+ # User = stg
+
+ # Database password
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: 123456
+ # Password = 123456
+
+ # Number of tries to reconnect
+ # Parameter: optional
+ # Value: positive integer
+ # Default: 3
+ # Retries = 3
+</StoreModule>
--- /dev/null
+../conf-available.d/mod_ao.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_cap_bpf.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_ia.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_ping.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_sg.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/store_files.conf
\ No newline at end of file
--- /dev/null
+ALL 192.168.0.0/16 DIR1
+ALL 10.0.0.0/8 DIR2
+ALL 0.0.0.0/0 DIR0
\ No newline at end of file
--- /dev/null
+################################################################################
+# Stargazer Configuration file #
+################################################################################
+
+# LOG file name
+# Parameter: required
+# Value: file path
+# Default: /var/log/stargazer.log
+LogFile = /var/log/stargazer.log
+
+# PID file name
+# Parameter: optional
+# Value: file path
+# Default: /var/run/stargazer.pid
+PIDFile = /var/run/stargazer.pid
+
+# Traffic classification rules
+# Parameter: required
+# Value: file path
+# Default: /etc/stargazer/rules
+Rules = /etc/stargazer/rules
+
+# The time interval between writing detailed user's statistics into the database
+# Note: With a large number of users this value should be increased,
+# since writting into the database can take a long time.
+# Parameter: required
+# Values: 1 (hourly), 1/2 (every half hour), 1/4 (every 15 m), 1/6 (every 10 m)
+# Default: 1/2
+DetailStatWritePeriod = 1/2
+
+# The time interval between writing summary user's statistics into the database
+# Parameter: optional
+# Value: 1 ... 1440 (minutes)
+# Default: 10
+StatWritePeriod = 10
+
+# Day of charging fee
+# Note: 0 - The last day of the month
+# Parameter: required
+# Value: 0 ... 31
+# Default: 1
+DayFee = 1
+
+# When set to 'no' Stargazer will continue reading database after error and show all of them.
+# Parameter: optional
+# Values: yes, no
+# Default: yes
+# StopOnError = yes
+
+# Fee charged at the last (yes) or first (no) day of tariffication period.
+# Defines how the fee will be charged in the transition to the new tariff.
+# User has tariff A with fee 100. Changing it to tariff B with fee 200
+# will result in charging user's account at 100 if DayFeeIsLastDay = yes
+# and at 200, if DayFeeIsLastDay = no
+# Parameter: required
+# Values: yes, no
+# Default: no
+DayFeeIsLastDay = no
+
+# Day of changing delayed tariffs and resetting summary user's statistics.
+# Defines the edge of the tariffication period.
+# Parameter: required
+# Value: 0 ... 31. 0 - The last day of the month
+# Default: 1
+DayResetTraff = 1
+
+# Defines whether to charge fee daily (yes) or monthly (no)
+# Parameter: required
+# Values: yes, no
+# Default: no
+SpreadFee = no
+
+# Defines whether the user can access the internet if it has no cash,
+# but remained prepaid traffic
+# Parameter: required
+# Values: yes, no
+# Default: no
+FreeMbAllowInet = no
+
+# Defines what will be written in the traffic cost in detail_stat.
+# If user still has the prepaid traffic and WriteFreeMbTraffCost = no,
+# then the traffic cost willn't be written in detail_stat.
+# If user doestn't have prepaid traffic and WriteFreeMbTraffCost = no,
+# then the traffic cost will be written in detail_stat.
+# When WriteFreeMbTraffCost = yes the traffic cost will be recorded in any case.
+# Parameter: required
+# Values: yes, no
+# Default: yes
+WriteFreeMbTraffCost = yes
+
+# Charge a full monthly fee even if user was "frozen" a part
+# of the tariffication period
+# Parameter: optional
+# Values: yes, no
+# Default: no
+FullFee = no
+
+# Allow user to see and use a full cash (yes) or hide a part of it (no)
+# for the next fee charge
+# Parameter: optional
+# Values: yes, no
+# Default: yes
+# ShowFeeInCash=yes
+
+# The names of directions. Direction without names will not appear in
+# authorizer and configurator.
+# Note: Names consisting of several words should be quoted
+# Parameter: optional
+# Values:
+<DirNames>
+ DirName0 = Internet
+ DirName1 =
+ DirName2 =
+ DirName3 =
+ DirName4 =
+ DirName5 =
+ DirName6 =
+ DirName7 =
+ DirName8 =
+ DirName9 =
+</DirNames>
+
+# Amount of stg-exec processes.
+# These processes are responsible for the execution of scripts OnConnect,
+# OnDisconnect, etc.
+# Amount of processes means how many scripts can be executed simultaneously.
+# Recommend to leave 1 to avoid errors when executing scripts
+# Parameter: optional
+# Value: 1 ... 1024
+# Default: 1
+ExecutersNum = 1
+
+# Message queue identifier for the script executer.
+# It may be changed if there're a needs to run multiple copies of stargazer.
+# Warning: If you do not understand it, do not touch this setting!
+# Parameter: optional
+# Value: 0 ... 2 ^ 32
+# Default: 5555
+# ExecMsgKey = 5555
+
+# The path to directory with server modules
+# Parameter: required
+# Value: directory path
+# Default: /usr/lib/stg
+ModulesPath = /usr/lib/stg
+
+# Directory where the "monitor" files are located.
+# A blank files will be created in this directory. The modification time of such
+# files will be changed about once a minute. If server crashes or some of server
+# component hang, the files will stop refreshing, and on this basis we can define
+# the failure of the server and if necessary restart.
+# If option is omitted or blank, the monitoring is not performed.
+# Parameter: optional
+# Value: file path
+# Default: /var/stargazer/monitor
+#MonitorDir=/var/stargazer/monitor
+
+# Defines message maximum lifetime
+# Note: 0 - unlimited
+# Parameter: optional
+# Value: any numeric
+# Default: 0 (day)
+# MessagesTimeout = 0
+
+# Defines fee charging rules.
+# 0 - classic rules, allow fee charge even cash is negative;
+# 1 - disallow fee charge if cash value is negative;
+# 2 - disallow fee charge if there is not enought cash (cash < fee).
+# Parameter: optional
+# Value: 0 ... 2
+# Default: 0 (classic)
+# FeeChargeType = 0
+
+# Enable or disable reconnect on tariff change
+# Parameter: optional
+# Values: yes, no
+# Default: no
+# ReconnectOnTariffChange = no
+
+# Definest set of parameters passed to OnConnect and OnDisconnect scripts
+# This set is added to the end of the default param list, which are, respectively:
+# login, ip, cash, id, dirs
+# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
+# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
+# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
+# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
+# "userdata0" ... "userdata9".
+# Parameter: optional
+# Values: parameter names, case insensitive
+# Default:
+# ScriptParams =
+
+# Enable or disable writing session log
+# Parameter: optional
+# Values: yes, no
+# Default: no (session log is enabled)
+# DisableSessionLog = no
+
+# Filter for logging parameter changes
+# Defines which parameters will be logged to parameter log in database. Allows
+# to specify multiuple parameter names or asterisk (*), which means "log all params".
+# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
+# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
+# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
+# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
+# "userdata0" ... "userdata9".
+# Parameter: optional
+# Values: parameter names, case insensitive, or "*"
+# Default: *
+# FilterParamsLog = *
+
+################################################################################
+# Store module
+# Configure the module that works with the database server
+
+# Warning: Only one store module could be used at the same time!
+
+<IncludeFile "conf-enabled.d/store_*.conf">
+</IncludeFile>
+
+
+################################################################################
+# Other modules
+
+<Modules>
+
+ <IncludeFile "conf-enabled.d/mod_*.conf">
+ </IncludeFile>
+
+</Modules>
+################################################################################
--- /dev/null
+#!/sbin/runscript
+
+extra_commands="reload"
+
+DAEMON=/usr/sbin/stargazer
+STARGAZER_OPTS=""
+PIDFILE=/var/run/stargazer.pid
+
+depend() {
+ need net
+ use postgresql firebird mysql
+ provide stargazer
+}
+
+start() {
+ ebegin "Starting stargazer"
+ start-stop-daemon --start --quiet --pidfile ${PIDFILE} --exec ${DAEMON} -- ${STARGAZER_OPTS}
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping stargazer"
+ start-stop-daemon --stop --quiet --pidfile ${PIDFILE} --retry=INT/120/KILL/5
+ rm -f ${PIDFILE}
+ eend $?
+}
+
+reload() {
+ ebegin "Reloading stargazer rules"
+ start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE
+ return 0
+ eend $?
+}
--- /dev/null
+#!/bin/bash
+#
+# processname: stargazer
+# config: /etc/stargazer/stargazer.conf
+# pidfile: /var/run/stargazer.pid
+
+# Source function library.
+. /etc/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Source stargazer configureation.
+DAEMON=yes
+QUEUE=1h
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+[ -f /sbin/stargazer ] || exit 0
+
+RETVAL=0
+prog="stargazer"
+
+start() {
+ # Start daemons.
+
+ echo -n $"Starting $prog: "
+ /etc/stargazer/first 2> /dev/null
+ daemon /sbin/stargazer
+ RETVAL=$?
+ /etc/stargazer/last 2> /dev/null
+ echo
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/stargazer
+ return $RETVAL
+}
+
+stop() {
+ # Stop daemons.
+ echo -n $"Shutting down $prog: "
+ killproc stargazer
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/stargazer
+ return $RETVAL
+}
+
+# See how we were called.
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart|reload)
+ stop
+ start
+ RETVAL=$?
+ ;;
+ status)
+ status stargazer
+ RETVAL=$?
+ ;;
+ *)
+ echo $"Usage: $0 {start|stop|restart|status}"
+ exit 1
+esac
+
+exit $RETVAL
--- /dev/null
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: stargazer
+# Required-Start: $local_fs $remote_fs
+# Required-Stop: $local_fs $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: S 0 1 6
+# Short-Description: Stargazer initscript
+# Description: This file should be used to start and stop stargazer daemon
+### END INIT INFO
+
+# Author: Boris Mikhailenko <stg34@stg.dp.ua>
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/usr/sbin:/usr/bin:/sbin:/bin
+DESC="Billing system"
+NAME=stargazer
+DAEMON=/usr/sbin/$NAME
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+[ -f /etc/default/rcS ] && . /etc/default/rcS
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
+ || return 1
+
+ # ps x | grep $DAEMON | grep -v grep | cut -f1 -d" " > $PIDFILE
+
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
+ $DAEMON_ARGS \
+ || return 2
+
+ # ps x | grep $DAEMON | grep -v grep | cut -f1 -d" " > $PIDFILE
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=INT/60/KILL/5 --pidfile $PIDFILE --name $NAME
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ # If the above conditions are not satisfied then add some other code
+ # that waits for the process to drop all resources that could be
+ # needed by services started subsequently. A last resort is to
+ # sleep for some time.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/60/KILL/5 --exec $DAEMON
+ [ "$?" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+ # If the daemon can reload its configuration without
+ # restarting (for example, when it is sent a SIGHUP),
+ # then implement that here.
+ start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
+ return 0
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ reload)
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ log_daemon_msg "Reloading $DESC" "$NAME"
+ do_reload
+ log_end_msg $?
+ ;;
+ restart)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
--- /dev/null
+#! /bin/sh
+
+# About: This script is called when user account is changed.
+# Common Task: Notify about various events.
+# Priority: optional
+
+# User login
+LOGIN=$1
+
+# User parameter
+PARAMETER=$2
+
+# User parameter old value
+OLDVALUE=$3
+
+# User parameter new value
+NEWVALUE=$4
+
+# Usage examples:
+#echo "User: '$LOGIN'. Parameter $PARAMETER changed from '$OLDVALUE' to '$NEWVALUE'" >> /var/stargazer/user.change.log
\ No newline at end of file
--- /dev/null
+#! /bin/sh
+
+# About: This script is called when the user successfully authenticated on the server.
+# Common Task: Rebuild firewall to allow user to access the Internet.
+# Priority: required
+
+# User login
+LOGIN=$1
+
+# User IP
+IP=$2
+
+# User cash
+CASH=$3
+
+# User ID
+ID=$4
+
+# Selected DIRs (from rules file) to connect
+DIRS=$5
+
+# Usage examples:
+#echo "Connected `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
\ No newline at end of file
--- /dev/null
+#! /bin/sh
+
+# About: This script is called when the user wants to disconnect or authorization timeout has passed.
+# Common task: Rebuild firewall to disallow user to access the Internet.
+# Priority: required
+
+# User login
+LOGIN=$1
+
+# User IP
+IP=$2
+
+# User cash
+CASH=$3
+
+# User ID
+ID=$4
+
+# Selected DIRs (from rules file) to disconnect
+DIRS=$5
+
+# Usage examples:
+#echo "Disconnected `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
--- /dev/null
+#! /bin/sh
+
+# About: This script is called when the user is added to the Stargazer.
+# Common task: Automate typical actions on adding user to the network,
+# such as creating email or IM account.
+# Priority: optional
+
+# User login
+LOGIN=$1
+
+# Usage examples:
+#echo "Added user $login" >> /var/stargazer/add_del.log
\ No newline at end of file
--- /dev/null
+#! /bin/sh
+
+# About: This script is called when the user is removed from the Stargazer.
+# Common task: Automate typical actions on removing user from the network,
+# such as removing email or IM account.
+# Priority: optional
+
+# User login
+LOGIN=$1
+
+# Usage examples:
+#echo "Deleted user $LOGIN" >> /var/stargazer/add_del.log
+
--- /dev/null
+# Enable the authorization module Always Online "mod_auth_ao.so"
+<Module auth_ao>
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the traffic capture module "mod_cap_ether.so" using Packet-sockets
+<Module cap_ether>
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the traffic capture module "mod_cap_ipq.so" using mechanism of IP Queueing
+<Module cap_ipq>
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the traffic capture module "mod_cap_ipq.so" using NetFlow protocol
+<Module cap_nf>
+ # Port for TCP connections
+ # Note: Parameters TCPPort and UDPPort can be equal
+ # Parameter: optional
+ # Value: 1 ... 65535
+ # Default: 9996
+ #TCPPort = 9996
+
+ # Port for UDP connections
+ # Note: Parameters TCPPort and UDPPort can be equal
+ # Parameter: optional
+ # Value: 1 ... 65535
+ # Default: 9996
+ UDPPort = 9996
+</Module>
--- /dev/null
+# Enable the authorization module InetAccess "mod_auth_ia.so"
+<Module auth_ia>
+ # Port on which the server interacts with authorizator
+ # Parameter: required
+ # Value: 1 ... 65535
+ # Default: 5555
+ Port = 5555
+
+ # The time interval between sending an alive query to the user
+ # and updating statistics
+ # Parameter: required
+ # Values: 5 ... 600 (seconds)
+ # Default: 60
+ UserDelay = 60
+
+ # User timeout. If authorizer does not respond during this time,
+ # the user will be disconnected
+ # Parameter: required
+ # Values: 5 ... 600
+ # Default: 60
+ UserTimeout = 65
+
+ # Define which information will be transmitted from the server to InetAccess
+ # as a residue of prepaid traffic
+ # FreeMb = 0 — amount of free megabytes in terms of cost of zero direction
+ # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
+ # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
+ # FreeMb = 2 — amount of free megabytes in terms of cost of the second direction
+ # ........................
+ # FreeMb = 9 — amount of free megabytes in terms of cost of the ninth direction
+ # FreeMb = cash - amount of money for which the user can download for free
+ # FreeMb = none - no transfer
+ # Default: cash
+ # Parameter: required
+ # Values: different, see above
+ # Default: cash
+ FreeMb = cash
+
+ # Enable protocol errors logging
+ # Parameter: optional
+ # Values: yes, no
+ # Default: no
+ # LogProtocolErrors = no
+</Module>
--- /dev/null
+# Enable the module that pings users "mod_ping.so"
+<Module ping>
+ # The time interval between pings
+ # Parameter: required
+ # Value: 10 ... 3600 (seconds)
+ # Default: 15
+ PingDelay = 15
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the interaction module for FreeRADIUS "mod_radius.so"
+<Module radius>
+ # FreeRADIUS password
+ # Parameter: required
+ # Values: any, supported by software
+ # Default: 123456
+ Password = 123456
+
+ # FreeRADIUS server
+ # Parameter: required
+ # Values: IP address or DNS name
+ # Default: 127.0.0.1
+ ServerIP = 127.0.0.1
+
+ # FreeRADIUS port
+ # Parameter: required
+ # Value: 1 ... 65535
+ # Default: 6666
+ Port = 6666
+
+ # List of services for which will be carried out FreeRADIUS authentication
+ # Note: Parameter can be blank
+ # Parameter: required
+ # Value: any, supported by software
+ # Default: Login-User
+ AuthServices = Login-User
+
+ # List of services for which will be carried out FreeRADIUS Accounting
+ # Note: Parameter can be blank
+ # Parameter: required
+ # Value: any, supported by software
+ # Default: Framed-User
+ AcctServices = Framed-User
+</Module>
\ No newline at end of file
--- /dev/null
+# Enable the module for remote execution of scripts OnConnect and OnDisconnect "mod_remote_script.so"
+<Module remote_script>
+ # The time interval between sending confirmations that the user is online
+ # Parametr: required
+ # Values: 10 ... 600 (seconds)
+ # Default: 60
+ SendPeriod = 15
+
+ # Define mapping between subnet(s) and remote server(s)
+ # File format: <subnet> <Router1> <Router2> ...
+ # Example:
+ # 192.168.1.0/24 192.168.1.7 192.168.1.8
+ # 192.168.2.0/24 192.168.2.5 192.168.2.6 192.168.2.7
+ # 192.168.3.0/24 192.168.3.5
+ # 192.168.4.0/24 192.168.4.5
+ # Parametr: required
+ # Values: file path
+ # Default: subnets
+ SubnetFile = subnets
+
+ # The password to encrypt packets between the stg-server and remote server
+ # Parameter: required
+ # Values: any
+ # Default: 123456
+ Password = 123456
+
+ # Define which user parameters are transferred to a remote server in addition to
+ # other parameters that transfered by default (ID, IP, Login, Cash, Dirs).
+ # Note: Parameter can be blank.
+ # Parameter: required
+ # Values: Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName,
+ # NextTariff, Address, Note, Group, Email, RealName, Credit, EnabledDirs,
+ # Userdata0...Userdata9
+ # Default: Cash Tariff EnabledDirs
+ UserParams = Cash Tariff EnabledDirs
+
+ # Port on which the server interacts with remote server
+ # Parameter: required
+ # Value: 1...65535
+ # Default: 9999
+ Port = 9999
+</Module>
--- /dev/null
+# Enable the configuration module ConfRPC "mod_conf_rpc.so"
+<Module conf_rpc>
+ # Port on which the server interacts with configurator
+ # Parameter: required
+ # Value: 1...65535
+ # Default:
+ Port = 8080
+
+ # Session timeout in seconds
+ # Parameter: required
+ # Value: positive integer
+ # Default: 1800
+ CookieTimeout = 1800
+</Module>
--- /dev/null
+# Enable the configuration module SgConfig "mod_conf_sg.so"
+<Module conf_sg>
+ # Port on which the server interacts with configurator
+ # Parameter: required
+ # Value: 1...65535
+ # Default: 5555
+ Port = 5555
+</Module>
\ No newline at end of file
--- /dev/null
+# Enables SMUX-peer for SNMPd.
+<Module smux>
+ # IP-address of a server to connect to
+ # Parameter: required
+ # Value: X.X.X.X
+ # Default: 127.0.0.1
+ Server = 127.0.0.1
+
+ # Port number on a server to connect to
+ # Parameter: required
+ # Value: 1 ... 65535
+ # Default: 199
+ Port = 199
+
+ # Password for authentication on a server
+ # Parameter: required
+ # Value: any text
+ Password =
+</Module>
--- /dev/null
+# Enables plain file backend.
+<StoreModule store_files>
+
+ # Working server directory, provides data on tariffs, users, administrators.
+ # Parameter: required
+ # Value: directory path
+ WorkDir = /var/stargazer
+
+ # Owner, group and permissions of the files of user statistics (stat)
+ # Parameter: required
+ # Values: any, supported by OS
+ ConfOwner = root
+ ConfGroup = root
+ ConfMode = 640
+
+ # Owner, group and permissions on user configuration files (conf)
+ # Parameter: required
+ # Values: any, supported by OS
+ StatOwner = root
+ StatGroup = root
+ StatMode = 640
+
+ # Owner, group and permissions for user log files (log)
+ # Parameter: required
+ # Values: any, supported by OS
+ UserLogOwner = root
+ UserLogGroup = root
+ UserLogMode = 640
+
+</StoreModule>
--- /dev/null
+# Enables Firebird backend.
+<StoreModule store_firebird>
+ # Database server address
+ # Parameter: optional
+ # Value: IP address or DNS name
+ # Default: localhost
+ # Server = localhost
+
+ # Path to the database on the server or its alias
+ # Parameter: optional
+ # Value: file path
+ # Default: /var/stg/stargazer.fdb
+ # Database = /var/stg/stargazer.fdb
+
+ # Database username
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: stg
+ # User = stg
+
+ # Database password
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: 123456
+ # Password = 123456
+
+ # The transaction isolation level
+ # Parameter: optional
+ # Values: concurrency, dirtyread, readcommitted, consistency
+ # Defalt: concurrency
+ # IsolationLevel = concurrency
+
+ # Responding to lock (optional, defaults to wait):
+ # Parameter: optional
+ # Values: wait, nowait
+ # Defalt: wait
+ # LockResolution = wait
+</StoreModule>
--- /dev/null
+# Enables MySQL backend.
+<StoreModule store_mysql>
+ # Database server address
+ # Parameter: required
+ # Value: IP address or DNS name
+ # Default: localhost
+ Server = localhost
+
+ # Database name
+ # Parameter: required
+ # Value: any, supported by database
+ # Default: stg
+ Database = stg
+
+ # Database username
+ # Parameter: required
+ # Value: any, supported by database
+ # Default: stg
+ User = stg
+
+ # Database password
+ # Parameter: required
+ # Value: any, supported by database
+ # Default: 123456
+ Password = 123456
+</StoreModule>
--- /dev/null
+# Enables PostgreSQL backend.
+<StoreModule store_postgresql>
+ # Database server address
+ # Parameter: optional
+ # Value: IP address or DNS name
+ # Default: localhost
+ # Server = localhost
+
+ # Database name
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: stargazer
+ # Database = stargazer
+
+ # Database username
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: stg
+ # User = stg
+
+ # Database password
+ # Parameter: optional
+ # Value: any, supported by database
+ # Default: 123456
+ # Password = 123456
+
+ # Number of tries to reconnect
+ # Parameter: optional
+ # Value: positive integer
+ # Default: 3
+ # Retries = 3
+</StoreModule>
--- /dev/null
+../conf-available.d/mod_ao.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_cap_ether.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_ia.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_ping.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/mod_sg.conf
\ No newline at end of file
--- /dev/null
+../conf-available.d/store_files.conf
\ No newline at end of file
--- /dev/null
+ALL 192.168.0.0/16 DIR1
+ALL 10.0.0.0/8 DIR2
+ALL 0.0.0.0/0 DIR0
\ No newline at end of file
--- /dev/null
+################################################################################
+# Stargazer Configuration file #
+################################################################################
+
+# LOG file name
+# Parameter: required
+# Value: file path
+# Default: /var/log/stargazer.log
+LogFile = /var/log/stargazer.log
+
+# PID file name
+# Parameter: optional
+# Value: file path
+# Default: /var/run/stargazer.pid
+PIDFile = /var/run/stargazer.pid
+
+# Traffic classification rules
+# Parameter: required
+# Value: file path
+# Default: /etc/stargazer/rules
+Rules = /etc/stargazer/rules
+
+# The time interval between writing detailed user's statistics into the database
+# Note: With a large number of users this value should be increased,
+# since writting into the database can take a long time.
+# Parameter: required
+# Values: 1 (hourly), 1/2 (every half hour), 1/4 (every 15 m), 1/6 (every 10 m)
+# Default: 1/2
+DetailStatWritePeriod = 1/2
+
+# The time interval between writing summary user's statistics into the database
+# Parameter: optional
+# Value: 1 ... 1440 (minutes)
+# Default: 10
+StatWritePeriod = 10
+
+# Day of charging fee
+# Note: 0 - The last day of the month
+# Parameter: required
+# Value: 0 ... 31
+# Default: 1
+DayFee = 1
+
+# When set to 'no' Stargazer will continue reading database after error and show all of them.
+# Parameter: optional
+# Values: yes, no
+# Default: yes
+# StopOnError = yes
+
+# Fee charged at the last (yes) or first (no) day of tariffication period.
+# Defines how the fee will be charged in the transition to the new tariff.
+# User has tariff A with fee 100. Changing it to tariff B with fee 200
+# will result in charging user's account at 100 if DayFeeIsLastDay = yes
+# and at 200, if DayFeeIsLastDay = no
+# Parameter: required
+# Values: yes, no
+# Default: no
+DayFeeIsLastDay = no
+
+# Day of changing delayed tariffs and resetting summary user's statistics.
+# Defines the edge of the tariffication period.
+# Parameter: required
+# Value: 0 ... 31. 0 - The last day of the month
+# Default: 1
+DayResetTraff = 1
+
+# Defines whether to charge fee daily (yes) or monthly (no)
+# Parameter: required
+# Values: yes, no
+# Default: no
+SpreadFee = no
+
+# Defines whether the user can access the internet if it has no cash,
+# but remained prepaid traffic
+# Parameter: required
+# Values: yes, no
+# Default: no
+FreeMbAllowInet = no
+
+# Defines what will be written in the traffic cost in detail_stat.
+# If user still has the prepaid traffic and WriteFreeMbTraffCost = no,
+# then the traffic cost willn't be written in detail_stat.
+# If user doestn't have prepaid traffic and WriteFreeMbTraffCost = no,
+# then the traffic cost will be written in detail_stat.
+# When WriteFreeMbTraffCost = yes the traffic cost will be recorded in any case.
+# Parameter: required
+# Values: yes, no
+# Default: yes
+WriteFreeMbTraffCost = yes
+
+# Charge a full monthly fee even if user was "frozen" a part
+# of the tariffication period
+# Parameter: optional
+# Values: yes, no
+# Default: no
+FullFee = no
+
+# Allow user to see and use a full cash (yes) or hide a part of it (no)
+# for the next fee charge
+# Parameter: optional
+# Values: yes, no
+# Default: yes
+# ShowFeeInCash=yes
+
+# The names of directions. Direction without names will not appear in
+# authorizer and configurator.
+# Note: Names consisting of several words should be quoted
+# Parameter: optional
+# Values:
+<DirNames>
+ DirName0 = Internet
+ DirName1 =
+ DirName2 =
+ DirName3 =
+ DirName4 =
+ DirName5 =
+ DirName6 =
+ DirName7 =
+ DirName8 =
+ DirName9 =
+</DirNames>
+
+# Amount of stg-exec processes.
+# These processes are responsible for the execution of scripts OnConnect,
+# OnDisconnect, etc.
+# Amount of processes means how many scripts can be executed simultaneously.
+# Recommend to leave 1 to avoid errors when executing scripts
+# Parameter: optional
+# Value: 1 ... 1024
+# Default: 1
+ExecutersNum = 1
+
+# Message queue identifier for the script executer.
+# It may be changed if there're a needs to run multiple copies of stargazer.
+# Warning: If you do not understand it, do not touch this setting!
+# Parameter: optional
+# Value: 0 ... 2 ^ 32
+# Default: 5555
+# ExecMsgKey = 5555
+
+# The path to directory with server modules
+# Parameter: required
+# Value: directory path
+# Default: /usr/lib/stg
+ModulesPath = /usr/lib/stg
+
+# Directory where the "monitor" files are located.
+# A blank files will be created in this directory. The modification time of such
+# files will be changed about once a minute. If server crashes or some of server
+# component hang, the files will stop refreshing, and on this basis we can define
+# the failure of the server and if necessary restart.
+# If option is omitted or blank, the monitoring is not performed.
+# Parameter: optional
+# Value: file path
+# Default: /var/stargazer/monitor
+#MonitorDir=/var/stargazer/monitor
+
+# Defines message maximum lifetime
+# Note: 0 - unlimited
+# Parameter: optional
+# Value: any numeric
+# Default: 0 (day)
+# MessagesTimeout = 0
+
+# Defines fee charging rules.
+# 0 - classic rules, allow fee charge even cash is negative;
+# 1 - disallow fee charge if cash value is negative;
+# 2 - disallow fee charge if there is not enought cash (cash < fee).
+# Parameter: optional
+# Value: 0 ... 2
+# Default: 0 (classic)
+# FeeChargeType = 0
+
+# Enable or disable reconnect on tariff change
+# Parameter: optional
+# Values: yes, no
+# Default: no
+# ReconnectOnTariffChange = no
+
+# Definest set of parameters passed to OnConnect and OnDisconnect scripts
+# This set is added to the end of the default param list, which are, respectively:
+# login, ip, cash, id, dirs
+# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
+# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
+# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
+# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
+# "userdata0" ... "userdata9".
+# Parameter: optional
+# Values: parameter names, case insensitive
+# Default:
+# ScriptParams =
+
+# Enable or disable writing session log
+# Parameter: optional
+# Values: yes, no
+# Default: no (session log is enabled)
+# DisableSessionLog = no
+
+# Filter for logging parameter changes
+# Defines which parameters will be logged to parameter log in database. Allows
+# to specify multiuple parameter names or asterisk (*), which means "log all params".
+# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
+# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
+# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
+# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
+# "userdata0" ... "userdata9".
+# Parameter: optional
+# Values: parameter names, case insensitive, or "*"
+# Default: *
+# FilterParamsLog = *
+
+################################################################################
+# Store module
+# Configure the module that works with the database server
+
+# Warning: Only one store module could be used at the same time!
+
+<IncludeFile "conf-enabled.d/store_*.conf">
+</IncludeFile>
+
+
+################################################################################
+# Other modules
+
+<Modules>
+
+ <IncludeFile "conf-enabled.d/mod_*.conf">
+ </IncludeFile>
+
+</Modules>
+################################################################################
--- /dev/null
+/*
+ * DB migration from v00 to v01 (postgres)
+ */
+
+ALTER TABLE tb_sessions_log ADD free_mb dm_money;
+ALTER TABLE tb_sessions_log ADD reason TEXT;
+
+DROP FUNCTION sp_add_session_log_entry ( dm_name, timestamp without time zone, dm_session_event_type, inet, dm_money);
+
+CREATE FUNCTION sp_add_session_log_entry(_login dm_name,
+ _event_time TIMESTAMP,
+ _event_type dm_session_event_type,
+ _ip INET,
+ _cash dm_money,
+ _free_mb dm_money,
+ _reason TEXT)
+RETURNS INTEGER
+AS $$
+DECLARE
+ _pk_user INTEGER;
+ _pk_session_log INTEGER;
+BEGIN
+ SELECT pk_user INTO _pk_user
+ FROM tb_users
+ WHERE name = _login;
+ IF _pk_user IS NULL THEN
+ RAISE EXCEPTION 'User % not found', _login;
+ RETURN -1;
+ END IF;
+
+ INSERT INTO tb_sessions_log
+ (fk_user,
+ event_time,
+ event_type,
+ ip,
+ cash,
+ free_mb,
+ reason)
+ VALUES
+ (_pk_user,
+ _event_time,
+ _event_type,
+ _ip,
+ _cash,
+ _free_mb,
+ _reason);
+
+ SELECT CURRVAL('tb_sessions_log_pk_session_log_seq') INTO _pk_session_log;
+
+ RETURN _pk_session_log;
+END;
+$$ LANGUAGE plpgsql;
+
+UPDATE tb_info SET version = 6;
--- /dev/null
+/*
+ * DB migration from v00 to v01 (firebird)
+ */
+
+alter table tb_users add disabled_detail_stat dm_bool;
+
+drop procedure sp_add_user;
+
+set term !! ;
+create procedure sp_add_user(name varchar(32), dirs integer)
+as
+declare variable pk_user integer;
+declare variable pk_stat integer;
+begin
+ pk_user = gen_id(gn_pk_user, 1);
+ insert into tb_users(pk_user, fk_tariff, fk_tariff_change, fk_corporation, address, always_online, credit, credit_expire, disabled, disabled_detail_stat, email, grp, note, passive, passwd, phone, name, real_name) values (:pk_user, NULL, NULL, NULL, '', 0, 0, 'now', 0, 0, '', '_', '', 0, '', '', :name, '');
+ pk_stat = gen_id(gn_pk_stat, 1);
+ insert into tb_stats values (:pk_stat, :pk_user, 0, 0, 'now', 0, 'now', 0, 'now');
+ while (dirs > 0) do
+ begin
+ insert into tb_stats_traffic (fk_stat, dir_num, upload, download) values (:pk_stat, :dirs - 1, 0, 0);
+ dirs = dirs - 1;
+ end
+end!!
+set term ; !!
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ *****************************************************************************
+ *
+ * Скрипт генерации структуры базы для хранения данных Stargazer-a
+ *
+ * Примечание.
+ * * dm_permission_flag. Представляет собой битовую маску - rw.
+ * r - чтение, w - изменение параметра.
+ * 0 - дествие запрещено, 1 - действие разрешено
+ *
+ * * dm_traff_type. Число определяющее тип подсчета трафика:
+ * 0 - up - считается по upload
+ * 1 - down - считается по download
+ * 2 - max - считается по максимальному среди upload/download
+ * 3 - up+down - считается по сумме upload и download
+ *
+ * * dm_session_event_type. Указывает тип записи в логе о сессии.
+ * 'c' - connect, 'd' - disconnect.
+ *
+ *****************************************************************************
+ */
+
+/*
+ * $Revision: 1.12 $
+ * $Date: 2009/08/20 14:58:43 $
+ */
+
+
+/*
+ *****************************************************************************
+ * -= Создание типов и доменов =-
+ *****************************************************************************
+ */
+
+CREATE DOMAIN dm_name AS VARCHAR(32) NOT NULL;
+CREATE DOMAIN dm_password AS VARCHAR(64) NOT NULL;
+CREATE DOMAIN dm_permission_flag AS SMALLINT NOT NULL
+ CHECK ( value BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_money AS NUMERIC(12, 4) NOT NULL DEFAULT 0;
+CREATE DOMAIN dm_traff_type AS SMALLINT NOT NULL
+ CHECK ( value BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_day AS SMALLINT NOT NULL
+ CHECK ( value BETWEEN 0 AND 31 )
+ DEFAULT 0;
+CREATE DOMAIN dm_session_event_type AS CHAR(1) NOT NULL
+ CHECK ( value = 'c' OR value = 'd' );
+
+/*
+ *****************************************************************************
+ * -= Создание таблиц =-
+ *****************************************************************************
+ */
+
+CREATE TABLE tb_info
+(
+ version INTEGER NOT NULL
+);
+
+CREATE TABLE tb_admins
+(
+ pk_admin SERIAL PRIMARY KEY,
+ login dm_name UNIQUE,
+ passwd dm_password NOT NULL,
+ chg_conf dm_permission_flag,
+ chg_password dm_permission_flag,
+ chg_stat dm_permission_flag,
+ chg_cash dm_permission_flag,
+ usr_add_del dm_permission_flag,
+ chg_tariff dm_permission_flag,
+ chg_admin dm_permission_flag,
+ chg_service dm_permission_flag,
+ chg_corporation dm_permission_flag
+);
+
+CREATE TABLE tb_tariffs
+(
+ pk_tariff SERIAL PRIMARY KEY,
+ name dm_name UNIQUE,
+ fee dm_money,
+ free dm_money,
+ passive_cost dm_money,
+ traff_type dm_traff_type
+);
+
+CREATE TABLE tb_tariffs_params
+(
+ pk_tariff_param SERIAL PRIMARY KEY,
+ fk_tariff INTEGER NOT NULL,
+ dir_num SMALLINT NOT NULL,
+ price_day_a dm_money,
+ price_day_b dm_money,
+ price_night_a dm_money,
+ price_night_b dm_money,
+ threshold INTEGER NOT NULL,
+ time_day_begins TIME NOT NULL,
+ time_day_ends TIME NOT NULL,
+
+ FOREIGN KEY (fk_tariff)
+ REFERENCES tb_tariffs (pk_tariff)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_corporations
+(
+ pk_corporation SERIAL PRIMARY KEY,
+ name dm_name UNIQUE,
+ cash dm_money
+);
+
+CREATE TABLE tb_users
+(
+ pk_user SERIAL PRIMARY KEY,
+ fk_tariff INTEGER,
+ fk_tariff_change INTEGER,
+ fk_corporation INTEGER,
+ address VARCHAR(256) NOT NULL,
+ always_online BOOLEAN NOT NULL,
+ credit dm_money,
+ credit_expire TIMESTAMP NOT NULL,
+ disabled BOOLEAN NOT NULL,
+ disabled_detail_stat BOOLEAN NOT NULL,
+ email VARCHAR(256) NOT NULL,
+ grp dm_name,
+ note TEXT NOT NULL,
+ passive BOOLEAN NOT NULL,
+ passwd dm_password,
+ phone VARCHAR(256) NOT NULL,
+ name dm_name UNIQUE,
+ real_name VARCHAR(256) NOT NULL,
+ cash dm_money,
+ free_mb dm_money,
+ last_activity_time TIMESTAMP NOT NULL,
+ last_cash_add dm_money,
+ last_cash_add_time TIMESTAMP NOT NULL,
+ passive_time INTEGER NOT NULL,
+
+ FOREIGN KEY (fk_tariff)
+ REFERENCES tb_tariffs (pk_tariff)
+ ON DELETE CASCADE,
+ FOREIGN KEY (fk_tariff_change)
+ REFERENCES tb_tariffs (pk_tariff)
+ ON DELETE CASCADE,
+ FOREIGN KEY (fk_corporation)
+ REFERENCES tb_corporations (pk_corporation)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_detail_stats
+(
+ pk_detail_stat BIGSERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ dir_num SMALLINT NOT NULL,
+ ip INET NOT NULL,
+ download BIGINT NOT NULL,
+ upload BIGINT NOT NULL,
+ cost dm_money,
+ from_time TIMESTAMP NOT NULL,
+ till_time TIMESTAMP NOT NULL,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_services
+(
+ pk_service SERIAL PRIMARY KEY,
+ name dm_name UNIQUE,
+ comment TEXT NOT NULL,
+ cost dm_money,
+ pay_day dm_day
+);
+
+CREATE TABLE tb_users_services
+(
+ pk_user_service SERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ fk_service INTEGER NOT NULL,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE,
+ FOREIGN KEY (fk_service)
+ REFERENCES tb_services (pk_service)
+);
+
+CREATE TABLE tb_messages
+(
+ pk_message SERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ ver SMALLINT NOT NULL,
+ msg_type SMALLINT NOT NULL,
+ last_send_time TIMESTAMP NOT NULL,
+ creation_time TIMESTAMP NOT NULL,
+ show_time INTEGER NOT NULL,
+ repeat SMALLINT NOT NULL,
+ repeat_period INTEGER NOT NULL,
+ msg_text TEXT NOT NULL,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_stats_traffic
+(
+ pk_stat_traffic BIGSERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ stats_date DATE NOT NULL,
+ dir_num SMALLINT NOT NULL,
+ download BIGINT NOT NULL,
+ upload BIGINT NOT NULL,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE,
+ UNIQUE (fk_user, stats_date, dir_num)
+);
+
+CREATE TABLE tb_users_data
+(
+ pk_user_data SERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ num SMALLINT NOT NULL,
+ data VARCHAR(256) NOT NULL,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_allowed_ip
+(
+ pk_allowed_ip SERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ ip INET NOT NULL,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_sessions_log
+(
+ pk_session_log SERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ event_time TIMESTAMP NOT NULL,
+ event_type dm_session_event_type,
+ ip INET NOT NULL,
+ cash dm_money,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_sessions_data
+(
+ pk_session_data SERIAL PRIMARY KEY,
+ fk_session_log INTEGER NOT NULL,
+ dir_num SMALLINT NOT NULL,
+ session_upload BIGINT NOT NULL,
+ session_download BIGINT NOT NULL,
+ month_upload BIGINT NOT NULL,
+ month_download BIGINT NOT NULL,
+
+ FOREIGN KEY (fk_session_log)
+ REFERENCES tb_sessions_log (pk_session_log)
+ ON DELETE CASCADE
+);
+
+CREATE TABLE tb_parameters
+(
+ pk_parameter SERIAL PRIMARY KEY,
+ name dm_name UNIQUE
+);
+
+CREATE TABLE tb_params_log
+(
+ pk_param_log SERIAL PRIMARY KEY,
+ fk_user INTEGER NOT NULL,
+ fk_parameter INTEGER NOT NULL,
+ fk_admin INTEGER NOT NULL,
+ ip INET NOT NULL,
+ event_time TIMESTAMP NOT NULL,
+ from_val VARCHAR(256),
+ to_val VARCHAR(256),
+ comment TEXT,
+
+ FOREIGN KEY (fk_user)
+ REFERENCES tb_users (pk_user)
+ ON DELETE CASCADE,
+ FOREIGN KEY (fk_parameter)
+ REFERENCES tb_parameters (pk_parameter),
+ FOREIGN KEY (fk_admin)
+ REFERENCES tb_admins (pk_admin)
+ ON DELETE CASCADE
+);
+
+/*
+ *****************************************************************************
+ * -= Создание хранимых процедур =-
+ *****************************************************************************
+ */
+
+CREATE FUNCTION sp_add_message(_login dm_name,
+ _ver SMALLINT,
+ _msg_type SMALLINT,
+ _last_send_time TIMESTAMP,
+ _creation_time TIMESTAMP,
+ _show_time INTEGER,
+ _repeat SMALLINT,
+ _repeat_period INTEGER,
+ _msg_text TEXT)
+RETURNS INTEGER
+AS $$
+DECLARE
+ _pk_user INTEGER;
+BEGIN
+ SELECT pk_user INTO _pk_user
+ FROM tb_users
+ WHERE name = _login;
+ IF _pk_user IS NULL THEN
+ RAISE EXCEPTION 'User % not found', _login;
+ RETURN -1;
+ END IF;
+ INSERT INTO tb_messages
+ (fk_user,
+ ver,
+ msg_type,
+ last_send_time,
+ creation_time,
+ show_time,
+ repeat,
+ repeat_period,
+ msg_text)
+ VALUES
+ (_pk_user,
+ _ver,
+ _msg_type,
+ _last_send_time,
+ _creation_time,
+ _show_time,
+ _repeat,
+ _repeat_period,
+ _msg_text);
+ RETURN CURRVAL('tb_messages_pk_message_seq');
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_tariff(_name dm_name, _dirs INTEGER)
+RETURNS INTEGER
+AS $$
+DECLARE
+ pk_tariff INTEGER;
+BEGIN
+ INSERT INTO tb_tariffs
+ (name,
+ fee,
+ free,
+ passive_cost,
+ traff_type)
+ VALUES
+ (_name,
+ 0, 0, 0, 0);
+ SELECT CURRVAL('tb_tariffs_pk_tariff_seq') INTO pk_tariff;
+ FOR i IN 1.._dirs LOOP
+ INSERT INTO tb_tariffs_params
+ (fk_tariff,
+ dir_num,
+ price_day_a,
+ price_day_b,
+ price_night_a,
+ price_night_b,
+ threshold,
+ time_day_begins,
+ time_day_ends)
+ VALUES
+ (pk_tariff,
+ i - 1,
+ 0, 0, 0, 0, 0,
+ CAST('1970-01-01 00:00:00+00' AS TIMESTAMP),
+ CAST('1970-01-01 00:00:00+00' AS TIMESTAMP));
+ END LOOP;
+ RETURN pk_tariff;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_user(_name dm_name)
+RETURNS INTEGER
+AS $$
+DECLARE
+ pk_user INTEGER;
+BEGIN
+ INSERT INTO tb_users
+ (fk_tariff,
+ fk_tariff_change,
+ fk_corporation,
+ address,
+ always_online,
+ credit,
+ credit_expire,
+ disabled,
+ disabled_detail_stat,
+ email,
+ grp,
+ note,
+ passive,
+ passwd,
+ phone,
+ name,
+ real_name,
+ cash,
+ free_mb,
+ last_activity_time,
+ last_cash_add,
+ last_cash_add_time,
+ passive_time)
+ VALUES
+ (NULL, NULL, NULL, '', FALSE, 0, CAST('now' AS TIMESTAMP),
+ FALSE, FALSE, '', '', '', FALSE, '', '', _name, '', 0, 0,
+ CAST('now' AS TIMESTAMP), 0, CAST('now' AS TIMESTAMP), 0);
+ SELECT CURRVAL('tb_users_pk_user_seq') INTO pk_user;
+ RETURN pk_user;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_stats_traffic (_login dm_name,
+ _stats_date DATE,
+ _dir_num SMALLINT,
+ _upload BIGINT,
+ _download BIGINT)
+RETURNS INTEGER
+AS $$
+DECLARE
+ _pk_user INTEGER;
+BEGIN
+ SELECT pk_user INTO _pk_user
+ FROM tb_users
+ WHERE name = _login;
+
+ IF _pk_user IS NULL THEN
+ RAISE EXCEPTION 'User % not found', _login;
+ RETURN -1;
+ END IF;
+
+ UPDATE tb_stats_traffic SET
+ upload = _upload,
+ download = _download
+ WHERE fk_user = _pk_user AND
+ dir_num = _dir_num AND
+ stats_date = _stats_date;
+
+ IF NOT FOUND THEN
+ INSERT INTO tb_stats_traffic
+ (fk_user,
+ dir_num,
+ stats_date,
+ upload,
+ download)
+ VALUES
+ (_pk_user,
+ _dir_num,
+ _stats_date,
+ _upload,
+ _download);
+ END IF;
+
+ RETURN 1;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_set_user_data (_pk_user INTEGER,
+ _num SMALLINT,
+ _data VARCHAR(256))
+RETURNS INTEGER
+AS $$
+BEGIN
+ UPDATE tb_users_data SET
+ data = _data
+ WHERE fk_user = _pk_user AND num = _num;
+
+ IF NOT FOUND THEN
+ INSERT INTO tb_users_data
+ (fk_user,
+ num,
+ data)
+ VALUES
+ (_pk_user,
+ _num,
+ _data);
+ END IF;
+
+ RETURN 1;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_param_log_entry(_login dm_name,
+ _admin_login dm_name,
+ _ip INET,
+ _param_name dm_name,
+ _event_time TIMESTAMP,
+ _from VARCHAR(256),
+ _to VARCHAR(256),
+ _comment TEXT)
+RETURNS INTEGER
+AS $$
+DECLARE
+ _pk_user INTEGER;
+ _pk_admin INTEGER;
+ _pk_param INTEGER;
+BEGIN
+ SELECT pk_user INTO _pk_user
+ FROM tb_users
+ WHERE name = _login;
+ IF _pk_user IS NULL THEN
+ RAISE EXCEPTION 'User % not found', _login;
+ RETURN -1;
+ END IF;
+
+ SELECT pk_admin INTO _pk_admin
+ FROM tb_admins
+ WHERE login = _admin_login;
+ IF _pk_admin IS NULL THEN
+ RAISE EXCEPTION 'Admin % not found', _admin_login;
+ RETURN -1;
+ END IF;
+
+ SELECT pk_parameter INTO _pk_param
+ FROM tb_parameters
+ WHERE name = _param_name;
+
+ IF NOT FOUND THEN
+ INSERT INTO tb_parameters (name) VALUES (_param_name);
+ SELECT CURRVAL('tb_parameters_pk_parameter_seq') INTO _pk_param;
+ END IF;
+
+ INSERT INTO tb_params_log
+ (fk_user,
+ fk_parameter,
+ fk_admin,
+ ip,
+ event_time,
+ from_val,
+ to_val,
+ comment)
+ VALUES
+ (_pk_user,
+ _pk_param,
+ _pk_admin,
+ _ip,
+ _event_time,
+ _from,
+ _to,
+ _comment);
+
+ RETURN 1;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_session_log_entry(_login dm_name,
+ _event_time TIMESTAMP,
+ _event_type dm_session_event_type,
+ _ip INET,
+ _cash dm_money)
+RETURNS INTEGER
+AS $$
+DECLARE
+ _pk_user INTEGER;
+ _pk_session_log INTEGER;
+BEGIN
+ SELECT pk_user INTO _pk_user
+ FROM tb_users
+ WHERE name = _login;
+ IF _pk_user IS NULL THEN
+ RAISE EXCEPTION 'User % not found', _login;
+ RETURN -1;
+ END IF;
+
+ INSERT INTO tb_sessions_log
+ (fk_user,
+ event_time,
+ event_type,
+ ip,
+ cash)
+ VALUES
+ (_pk_user,
+ _event_time,
+ _event_type,
+ _ip,
+ _cash);
+
+ SELECT CURRVAL('tb_sessions_log_pk_session_log_seq') INTO _pk_session_log;
+
+ RETURN _pk_session_log;
+END;
+$$ LANGUAGE plpgsql;
+
+/*
+ *****************************************************************************
+ * -= Создание администратора =-
+ *
+ * Двоичные права доступа пока не поддерживаются, по этому используются флаги
+ *****************************************************************************
+ */
+INSERT INTO tb_admins
+ (login, passwd,
+ chg_conf, chg_password, chg_stat,
+ chg_cash, usr_add_del, chg_tariff,
+ chg_admin, chg_service, chg_corporation)
+VALUES
+ ('admin',
+ 'geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmk',
+ 1, 1, 1, 1, 1, 1, 1, 1, 1);
+INSERT INTO tb_admins
+ (login, passwd,
+ chg_conf, chg_password, chg_stat,
+ chg_cash, usr_add_del, chg_tariff,
+ chg_admin, chg_service, chg_corporation)
+VALUES
+ ('@stargazer',
+ '',
+ 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+INSERT INTO tb_info
+ (version)
+VALUES
+ (5);
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ *****************************************************************************
+ *
+ * Скрипт генерации структуры базы для хранения данных Stargazer-a
+ *
+ * $Id: 00-base-00.sql,v 1.7 2010/01/06 14:41:13 faust Exp $
+ *
+ * Примечание.
+ * * dm_permission_flag. Представляет собой битовую маску - rw.
+ * r - чтение, w - изменение параметра.
+ * 0 - дествие запрещено, 1 - действие разрешено
+ *
+ * * dm_traff_type. Число определяющее тип подсчета трафика:
+ * 0 - up - считается по upload
+ * 1 - down - считается по download
+ * 2 - max - считается по максимальному среди upload/download
+ * 3 - up+down - считается по сумме upload и download
+ *
+ * * dm_ip. IP адресс в виде четырех байтового целого числа со знаком.
+ * Выполнять приведение к знаковуму целому при занесении IP в БД!!!
+ *
+ * * dm_period. Задает периодичность показа сообщения пользователю.
+ * Период задается целым числом (int16). Если значение равно 0 то
+ * сообщение показывается только при подключении пользователя.
+ * Также этот домен определяет промежуток времени в течении которого
+ * сообщение показывается пользователю.
+ *
+ * * dm_session_event_type. Указывает тип записи в логе о сессии.
+ * 'c' - connect, 'd' - disconnect.
+ *
+ *****************************************************************************
+ */
+
+/*
+ * CONNECT 'localhost:/var/stg/stargazer.fdb' USER 'stg' PASSWORD '123456';
+ * DROP DATABASE;
+ *
+ * CREATE DATABASE 'localhost:/var/stg/stargazer.fdb' USER 'stg' PASSWORD '123456' DEFAULT CHARACTER SET UTF8;
+ */
+
+
+
+/*
+ *****************************************************************************
+ * -= Создание ДОМЕНОВ =-
+ *****************************************************************************
+ */
+
+CREATE DOMAIN dm_id AS INTEGER NOT NULL;
+CREATE DOMAIN dm_null_id AS INTEGER;
+CREATE DOMAIN dm_login AS VARCHAR(32) NOT NULL;
+CREATE DOMAIN dm_tariff_name AS VARCHAR(32) NOT NULL;
+CREATE DOMAIN dm_group_name AS VARCHAR(32);
+CREATE DOMAIN dm_corporation_name AS VARCHAR(32);
+CREATE DOMAIN dm_parameter_name AS VARCHAR(32);
+
+CREATE DOMAIN dm_password AS VARCHAR(64) NOT NULL;
+/* bitmask - rw => Read, Write */
+CREATE DOMAIN dm_permission_flag AS SMALLINT NOT NULL
+ CHECK ( VALUE BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_money AS NUMERIC(10,6) NOT NULL;
+/* (0, 1, 2, 3) => (up, down, max, up+down) */
+CREATE DOMAIN dm_traff_type AS SMALLINT NOT NULL
+ CHECK ( VALUE BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_dir_num AS SMALLINT NOT NULL;
+CREATE DOMAIN dm_num AS SMALLINT NOT NULL;
+CREATE DOMAIN dm_traffic_mb AS INTEGER NOT NULL;
+CREATE DOMAIN dm_traffic_byte AS BIGINT NOT NULL;
+CREATE DOMAIN dm_time AS TIME NOT NULL;
+CREATE DOMAIN dm_moment AS TIMESTAMP NOT NULL;
+CREATE DOMAIN dm_credit_moment AS TIMESTAMP;
+CREATE DOMAIN dm_ip AS INTEGER NOT NULL;
+CREATE DOMAIN dm_mask AS INTEGER NOT NULL;
+CREATE DOMAIN dm_user_address AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_bool AS CHAR(1) NOT NULL
+ CHECK ( VALUE IN ('0', '1', 't', 'f', 'T', 'F') );
+CREATE DOMAIN dm_email AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_note AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_phone AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_user_name AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_service_comment AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_service_name AS VARCHAR(32) DEFAULT '';
+
+CREATE DOMAIN dm_pay_day AS SMALLINT NOT NULL
+ CHECK ( VALUE BETWEEN 0 AND 31 );
+CREATE DOMAIN dm_period AS INTEGER NOT NULL;
+CREATE DOMAIN dm_counter AS SMALLINT NOT NULL;
+
+CREATE DOMAIN dm_message_ver AS INTEGER NOT NULL;
+CREATE DOMAIN dm_message_type AS INTEGER NOT NULL;
+
+CREATE DOMAIN dm_message AS VARCHAR(256) NOT NULL;
+CREATE DOMAIN dm_user_data AS VARCHAR(256) NOT NULL;
+CREATE DOMAIN dm_session_event_type AS CHAR(1) NOT NULL
+ CHECK ( VALUE IN ('c', 'd') );
+CREATE DOMAIN dm_char_value AS VARCHAR(64) NOT NULL;
+CREATE DOMAIN dm_date AS DATE NOT NULL;
+
+
+
+/*
+ *****************************************************************************
+ * -= Создание ТАБЛИЦ =-
+ *****************************************************************************
+ */
+
+CREATE TABLE tb_admins
+(
+ pk_admin dm_id PRIMARY KEY,
+ login dm_login UNIQUE,
+ passwd dm_password,
+ chg_conf dm_permission_flag,
+ chg_password dm_permission_flag,
+ chg_stat dm_permission_flag,
+ chg_cash dm_permission_flag,
+ usr_add_del dm_permission_flag,
+ chg_tariff dm_permission_flag,
+ chg_admin dm_permission_flag,
+ chg_service dm_permission_flag,
+ chg_corporation dm_permission_flag
+);
+
+CREATE TABLE tb_tariffs
+(
+ pk_tariff dm_id PRIMARY KEY,
+ name dm_tariff_name UNIQUE,
+ fee dm_money,
+ free dm_money,
+ passive_cost dm_money,
+ traff_type dm_traff_type
+);
+
+CREATE TABLE tb_tariffs_params
+(
+ pk_tariff_param dm_id PRIMARY KEY,
+ fk_tariff dm_id,
+ dir_num dm_dir_num,
+ price_day_a dm_money,
+ price_day_b dm_money,
+ price_night_a dm_money,
+ price_night_b dm_money,
+ threshold dm_traffic_mb,
+ time_day_begins dm_time,
+ time_day_ends dm_time,
+
+ FOREIGN KEY (fk_tariff) REFERENCES tb_tariffs (pk_tariff)
+);
+
+CREATE TABLE tb_corporations
+(
+ pk_corporation dm_id PRIMARY KEY,
+ name dm_corporation_name UNIQUE,
+ cash dm_money
+);
+
+CREATE TABLE tb_users
+(
+ pk_user dm_id PRIMARY KEY,
+ fk_tariff dm_null_id,
+ fk_tariff_change dm_null_id,
+ fk_corporation dm_null_id,
+ address dm_user_address,
+ always_online dm_bool,
+ credit dm_money,
+ credit_expire dm_credit_moment,
+ disabled dm_bool,
+ disabled_detail_stat dm_bool,
+ email dm_email,
+ grp dm_group_name,
+ note dm_note,
+ passive dm_bool,
+ passwd dm_password,
+ phone dm_phone,
+ name dm_login UNIQUE,
+ real_name dm_user_name,
+
+ FOREIGN KEY (fk_tariff) REFERENCES tb_tariffs (pk_tariff),
+ FOREIGN KEY (fk_tariff_change) REFERENCES tb_tariffs (pk_tariff),
+ FOREIGN KEY (fk_corporation) REFERENCES tb_corporations (pk_corporation)
+);
+
+CREATE TABLE tb_detail_stats
+(
+ pk_detail_stat dm_id PRIMARY KEY,
+ fk_user dm_id,
+ dir_num dm_dir_num,
+ ip dm_ip,
+ download dm_traffic_byte,
+ upload dm_traffic_byte,
+ cost dm_money,
+ from_time dm_moment,
+ till_time dm_moment,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_services
+(
+ pk_service dm_id PRIMARY KEY,
+ name dm_service_name UNIQUE,
+ comment dm_service_comment,
+ cost dm_money,
+ pay_day dm_pay_day
+);
+
+CREATE TABLE tb_users_services
+(
+ pk_user_service dm_id PRIMARY KEY,
+ fk_user dm_id,
+ fk_service dm_id,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user),
+ FOREIGN KEY (fk_service) REFERENCES tb_services (pk_service)
+);
+
+CREATE TABLE tb_messages
+(
+ pk_message dm_id PRIMARY KEY,
+ fk_user dm_id,
+ ver dm_message_ver,
+ msg_type dm_message_type,
+ last_send_time dm_period,
+ creation_time dm_period,
+ show_time dm_period,
+ repeat dm_counter,
+ repeat_period dm_period,
+ msg_text dm_message,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_stats
+(
+ pk_stat dm_id PRIMARY KEY,
+ fk_user dm_id,
+ cash dm_money,
+ free_mb dm_money,
+ last_activity_time dm_moment,
+ last_cash_add dm_money,
+ last_cash_add_time dm_moment,
+ passive_time dm_period,
+ stats_date dm_date,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_stats_traffic
+(
+ pk_stat_traffic dm_id PRIMARY KEY,
+ fk_stat dm_id,
+ dir_num dm_dir_num,
+ download dm_traffic_byte,
+ upload dm_traffic_byte,
+
+ FOREIGN KEY (fk_stat) REFERENCES tb_stats (pk_stat)
+);
+
+CREATE TABLE tb_users_data
+(
+ pk_user_data dm_id PRIMARY KEY,
+ fk_user dm_id,
+ num dm_num,
+ data dm_user_data,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_allowed_ip
+(
+ pk_allowed_ip dm_id PRIMARY KEY,
+ fk_user dm_id,
+ ip dm_ip,
+ mask dm_mask,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_sessions_log
+(
+ pk_session_log dm_id PRIMARY KEY,
+ fk_user dm_id,
+ event_time dm_moment,
+ event_type dm_session_event_type,
+ ip dm_ip,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_sessions_data
+(
+ pk_session_data dm_id PRIMARY KEY,
+ fk_session_log dm_id,
+ dir_num dm_dir_num,
+ session_upload dm_traffic_byte,
+ session_download dm_traffic_byte,
+ month_upload dm_traffic_byte,
+ month_download dm_traffic_byte,
+
+ FOREIGN KEY (fk_session_log) REFERENCES tb_sessions_log (pk_session_log)
+);
+
+CREATE TABLE tb_parameters
+(
+ pk_parameter dm_id PRIMARY KEY,
+ name dm_parameter_name UNIQUE
+);
+
+CREATE TABLE tb_params_log
+(
+ pk_param_log dm_id PRIMARY KEY,
+ fk_user dm_id,
+ fk_parameter dm_id,
+ event_time dm_moment,
+ from_val dm_char_value,
+ to_val dm_char_value,
+ comment dm_service_comment,
+
+ FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user),
+ FOREIGN KEY (fk_parameter) REFERENCES tb_parameters (pk_parameter)
+);
+
+
+/*
+ *****************************************************************************
+ * -= Создание ИНДЕКСОВ =-
+ *****************************************************************************
+ */
+
+
+
+/*
+ *****************************************************************************
+ * -= Создание ГЕНЕРАТОРОВ =-
+ *****************************************************************************
+ */
+
+CREATE GENERATOR gn_pk_admin;
+SET GENERATOR gn_pk_admin TO 0;
+CREATE GENERATOR gn_pk_tariff;
+SET GENERATOR gn_pk_tariff TO 0;
+CREATE GENERATOR gn_pk_tariff_param;
+SET GENERATOR gn_pk_tariff_param TO 0;
+CREATE GENERATOR gn_pk_corporation;
+SET GENERATOR gn_pk_corporation TO 0;
+CREATE GENERATOR gn_pk_user;
+SET GENERATOR gn_pk_user TO 0;
+CREATE GENERATOR gn_pk_detail_stat;
+SET GENERATOR gn_pk_detail_stat TO 0;
+CREATE GENERATOR gn_pk_service;
+SET GENERATOR gn_pk_service TO 0;
+CREATE GENERATOR gn_pk_user_service;
+SET GENERATOR gn_pk_user_service TO 0;
+CREATE GENERATOR gn_pk_message;
+SET GENERATOR gn_pk_message TO 0;
+CREATE GENERATOR gn_pk_stat;
+SET GENERATOR gn_pk_stat TO 0;
+CREATE GENERATOR gn_pk_stat_traffic;
+SET GENERATOR gn_pk_stat_traffic TO 0;
+CREATE GENERATOR gn_pk_user_data;
+SET GENERATOR gn_pk_user_data TO 0;
+CREATE GENERATOR gn_pk_allowed_ip;
+SET GENERATOR gn_pk_allowed_ip TO 0;
+CREATE GENERATOR gn_pk_session;
+SET GENERATOR gn_pk_session TO 0;
+CREATE GENERATOR gn_pk_session_log;
+SET GENERATOR gn_pk_session_log TO 0;
+CREATE GENERATOR gn_pk_session_data;
+SET GENERATOR gn_pk_session_data TO 0;
+CREATE GENERATOR gn_pk_parameter;
+SET GENERATOR gn_pk_parameter TO 0;
+CREATE GENERATOR gn_pk_param_log;
+SET GENERATOR gn_pk_param_log TO 0;
+
+
+/*
+ *****************************************************************************
+ * -= Создание ТРИГГЕРОВ =-
+ *****************************************************************************
+ */
+
+SET TERM !! ;
+CREATE TRIGGER tr_admin_bi FOR tb_admins
+ACTIVE BEFORE INSERT POSITION 0
+AS
+BEGIN
+ IF (new.pk_admin IS NULL)
+ THEN new.pk_admin = GEN_ID(gn_pk_admin, 1);
+END !!
+SET TERM ; !!
+
+set term !! ;
+create trigger tr_tariff_param_bi for tb_tariffs_params active
+before insert position 0
+as
+begin
+ if (new.pk_tariff_param is null)
+ then new.pk_tariff_param = gen_id(gn_pk_tariff_param, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_corporation_bi for tb_corporations active
+before insert position 0
+as
+begin
+ if (new.pk_corporation is null)
+ then new.pk_corporation = gen_id(gn_pk_corporation, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_detail_stat_bi for tb_detail_stats active
+before insert position 0
+as
+begin
+ if (new.pk_detail_stat is null)
+ then new.pk_detail_stat = gen_id(gn_pk_detail_stat, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_service_bi for tb_services active
+before insert position 0
+as
+begin
+ if (new.pk_service is null)
+ then new.pk_service = gen_id(gn_pk_service, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_user_service_bi for tb_users_services active
+before insert position 0
+as
+begin
+ if (new.pk_user_service is null)
+ then new.pk_user_service = gen_id(gn_pk_user_service, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_stat_traffic_bi for tb_stats_traffic active
+before insert position 0
+as
+begin
+ if (new.pk_stat_traffic is null)
+ then new.pk_stat_traffic = gen_id(gn_pk_stat_traffic, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_user_data_bi for tb_users_data active
+before insert position 0
+as
+begin
+ if (new.pk_user_data is null)
+ then new.pk_user_data = gen_id(gn_pk_user_data, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_allowed_ip_bi for tb_allowed_ip active
+before insert position 0
+as
+begin
+ if (new.pk_allowed_ip is null)
+ then new.pk_allowed_ip = gen_id(gn_pk_allowed_ip, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_session_data_bi for tb_sessions_data active
+before insert position 0
+as
+begin
+ if (new.pk_session_data is null)
+ then new.pk_session_data = gen_id(gn_pk_session_data, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_parameter_bi for tb_parameters active
+before insert position 0
+as
+begin
+ if (new.pk_parameter is null)
+ then new.pk_parameter = gen_id(gn_pk_parameter, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_param_log_bi for tb_params_log active
+before insert position 0
+as
+begin
+ if (new.pk_param_log is null)
+ then new.pk_param_log = gen_id(gn_pk_param_log, 1);
+end !!
+set term ; !!
+
+/*
+ *****************************************************************************
+ * -= Создание stored procedure =-
+ *****************************************************************************
+ */
+
+/*
+ * Add a message returning it's ID
+ */
+set term !! ;
+create procedure sp_add_message(pk_message integer, login varchar(32), ver integer, msg_type integer, last_send_time integer, creation_time integer, show_time integer, repeat integer, repeat_period integer, msg_text varchar(256))
+returns(res integer)
+as
+begin
+ if (:pk_message is null) then
+ begin
+ pk_message = gen_id(gn_pk_message, 1);
+ insert into tb_messages values (:pk_message,
+ (select pk_user from tb_users where name = :login),
+ :ver,
+ :msg_type,
+ :last_send_time,
+ :creation_time,
+ :show_time,
+ :repeat,
+ :repeat_period,
+ :msg_text);
+ end
+ else
+ begin
+ update tb_messages set fk_user = (select pk_user from tb_users where name = :login),
+ ver = :ver,
+ msg_type = :msg_type,
+ last_send_time = :last_send_time,
+ creation_time = :creation_time,
+ show_time = :show_time,
+ repeat = :repeat_period,
+ repeat_period = :repeat_period,
+ msg_text = :msg_text
+ where pk_message = :pk_message;
+ end
+ res = :pk_message;
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_delete_service(name varchar(32))
+as
+declare variable pk_service integer;
+begin
+ select pk_service from tb_services where name = :name into pk_service;
+ if (pk_service is not null) then
+ begin
+ delete from tb_users_services where fk_service = :pk_service;
+ delete from tb_services where pk_service = :pk_service;
+ end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_add_tariff(name varchar(32), dirs integer)
+as
+declare variable pk_tariff integer;
+begin
+ pk_tariff = gen_id(gn_pk_tariff, 1);
+ insert into tb_tariffs (pk_tariff, name, fee, free, passive_cost, traff_type) values (:pk_tariff, :name, 0, 0, 0, 0);
+ while (dirs > 0) do
+ begin
+ insert into tb_tariffs_params (fk_tariff, dir_num, price_day_a,
+ price_day_b, price_night_a, price_night_b,
+ threshold, time_day_begins, time_day_ends)
+ values (:pk_tariff, :dirs - 1, 0, 0, 0, 0, 0, '0:0', '0:0');
+ dirs = dirs - 1;
+ end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_delete_tariff(name varchar(32))
+as
+declare variable pk_tariff integer;
+begin
+ select pk_tariff from tb_tariffs where name = :name into pk_tariff;
+ if (pk_tariff is not null) then
+ begin
+ delete from tb_tariffs_params where fk_tariff = :pk_tariff;
+ delete from tb_tariffs where pk_tariff = :pk_tariff;
+ end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_add_user(name varchar(32), dirs integer)
+as
+declare variable pk_user integer;
+declare variable pk_stat integer;
+begin
+ pk_user = gen_id(gn_pk_user, 1);
+ insert into tb_users(pk_user, fk_tariff, fk_tariff_change, fk_corporation, address, always_online, credit, credit_expire, disabled, disabled_detail_stat, email, grp, note, passive, passwd, phone, name, real_name) values (:pk_user, NULL, NULL, NULL, '', 0, 0, 'now', 0, 0, '', '_', '', 0, '', '', :name, '');
+ pk_stat = gen_id(gn_pk_stat, 1);
+ insert into tb_stats values (:pk_stat, :pk_user, 0, 0, 'now', 0, 'now', 0, 'now');
+ while (dirs > 0) do
+ begin
+ insert into tb_stats_traffic (fk_stat, dir_num, upload, download) values (:pk_stat, :dirs - 1, 0, 0);
+ dirs = dirs - 1;
+ end
+end!!
+set term ; !!
+
+set term !! ;
+create procedure sp_delete_user(name varchar(32))
+as
+declare variable pk_user integer;
+begin
+ select pk_user from tb_users where name = :name into pk_user;
+ if (pk_user is not null) then
+ begin
+ delete from tb_users_services where fk_user = :pk_user;
+ delete from tb_params_log where fk_user = :pk_user;
+ delete from tb_detail_stats where fk_user = :pk_user;
+ delete from tb_stats_traffic where fk_stat in (select pk_stat from tb_stats where fk_user = :pk_user);
+ delete from tb_stats where fk_user = :pk_user;
+ delete from tb_sessions_data where fk_session_log in (select pk_session_log from tb_sessions_log where fk_user = :pk_user);
+ delete from tb_sessions_log where fk_user = :pk_user;
+ delete from tb_allowed_ip where fk_user = :pk_user;
+ delete from tb_users_data where fk_user = :pk_user;
+ delete from tb_messages where fk_user = :pk_user;
+ delete from tb_users where pk_user = :pk_user;
+ end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_append_session_log(name varchar(32), event_time timestamp, event_type char(1), ip integer)
+returns(pk_session_log integer)
+as
+begin
+ pk_session_log = gen_id(gn_pk_session_log, 1);
+ insert into tb_sessions_log (pk_session_log, fk_user, event_time, event_type, ip) values (:pk_session_log, (select pk_user from tb_users where name = :name), :event_time, :event_type, :ip);
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_add_stat(name varchar(32), cash numeric(10,6), free_mb numeric(10,6), last_activity_time timestamp, last_cash_add numeric(10,6), last_cash_add_time timestamp, passive_time integer, stats_date date)
+returns(pk_stat integer)
+as
+begin
+ pk_stat = gen_id(gn_pk_stat, 1);
+ insert into tb_stats (pk_stat, fk_user, cash, free_mb, last_activity_time, last_cash_add, last_cash_add_time, passive_time, stats_date) values (:pk_stat, (select pk_user from tb_users where name = :name), :cash, :free_mb, :last_activity_time, :last_cash_add, :last_cash_add_time, :passive_time, :stats_date);
+end !!
+set term ; !!
+
+/*
+ *****************************************************************************
+ * -= Создание администратора =-
+ *****************************************************************************
+ */
+
+insert into tb_admins values(0, 'admin', 'geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmk', 1, 1, 1, 1, 1, 1, 1, 1, 1);
+
+/* EOF */
--- /dev/null
+/*
+ * DB migration from v00 to v01 (mysql)
+ */
+
+ALTER TABLE users ADD DisabledDetailStat INT(3) DEFAULT 0;
--- /dev/null
+/*
+ * DB migration from v01 to v02 (mysql)
+ */
+
+ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month';
+
+CREATE TABLE info
+(
+ version INTEGER NOT NULL
+);
+
+INSERT INTO info VALUES (1);
--- /dev/null
+/*
+ * DB migration from v01 to v02 (postgres)
+ */
+BEGIN;
+
+CREATE DOMAIN DM_TARIFF_PERIOD AS TEXT NOT NULL
+ CONSTRAINT valid_value CHECK (VALUE = 'month' OR VALUE = 'day');
+
+ALTER TABLE tb_tariffs ADD period DM_TARIFF_PERIOD DEFAULT 'month';
+
+UPDATE tb_info SET version = 7;
+
+COMMIT;
--- /dev/null
+/*
+ * DB migration from v01 to v02 (firebird)
+ */
+
+CREATE DOMAIN DM_TARIFF_PERIOD AS VARCHAR(32) NOT NULL
+ CHECK (VALUE = 'month' OR VALUE = 'day');
+
+ALTER TABLE tb_tariffs ADD period DM_TARIFF_PERIOD DEFAULT 'month';
+
+CREATE TABLE tb_info
+(
+ version INTEGER NOT NULL
+);
+
+INSERT INTO tb_info VALUES (1);
--- /dev/null
+/*
+ * DB migration from v02 to v03 (postgres)
+ */
+BEGIN;
+
+CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS TEXT NOT NULL
+ CONSTRAINT valid_value CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny'));
+
+ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow';
+ALTER TABLE tb_tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:00';
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT;
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT;
+
+UPDATE tb_info SET version = 8;
+
+COMMIT;
--- /dev/null
+/*
+ * DB migration from v02 to v03 (firebird)
+ */
+
+CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS VARCHAR(32) NOT NULL
+ CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny'));
+
+ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow';
+ALTER TABLE tb_tariffs ADD change_policy_timeout DM_MOMENT DEFAULT '1970-01-01 00:00:00';
+
+UPDATE tb_tariffs SET change_policy = 'allow', change_policy_timeout = '1970-01-01 00:00:00';
+
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT;
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT;
+
+UPDATE tb_info SET version = 2;
--- /dev/null
+password=geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa
+ChgConf=1
+ChgPassword=1
+ChgStat=1
+ChgCash=1
+UsrAddDel=1
+ChgTariff=1
+ChgAdmin=1
--- /dev/null
+Fee=10.000000
+Free=0
+NoDiscount0=1
+NoDiscount1=1
+NoDiscount2=1
+NoDiscount3=1
+NoDiscount4=1
+NoDiscount5=1
+NoDiscount6=1
+NoDiscount7=1
+NoDiscount8=1
+NoDiscount9=1
+PassiveCost=0.000000
+PriceDayA0=0.000000
+PriceDayA1=0.750000
+PriceDayA2=0.000000
+PriceDayA3=0.000000
+PriceDayA4=0.000000
+PriceDayA5=0.000000
+PriceDayA6=0.000000
+PriceDayA7=0.000000
+PriceDayA8=0.000000
+PriceDayA9=0.000000
+PriceDayB0=0.000000
+PriceDayB1=0.750000
+PriceDayB2=0.000000
+PriceDayB3=0.000000
+PriceDayB4=0.000000
+PriceDayB5=0.000000
+PriceDayB6=0.000000
+PriceDayB7=0.000000
+PriceDayB8=0.000000
+PriceDayB9=0.000000
+PriceNightA0=1.000000
+PriceNightA1=0.000000
+PriceNightA2=0.000000
+PriceNightA3=0.000000
+PriceNightA4=0.000000
+PriceNightA5=0.000000
+PriceNightA6=0.000000
+PriceNightA7=0.000000
+PriceNightA8=0.000000
+PriceNightA9=0.000000
+PriceNightB0=1.000000
+PriceNightB1=0.000000
+PriceNightB2=0.000000
+PriceNightB3=0.000000
+PriceNightB4=0.000000
+PriceNightB5=0.000000
+PriceNightB6=0.000000
+PriceNightB7=0.000000
+PriceNightB8=0.000000
+PriceNightB9=0.000000
+SinglePrice0=1
+SinglePrice1=1
+SinglePrice2=0
+SinglePrice3=0
+SinglePrice4=0
+SinglePrice5=0
+SinglePrice6=0
+SinglePrice7=0
+SinglePrice8=0
+SinglePrice9=0
+Threshold0=0
+Threshold1=0
+Threshold2=0
+Threshold3=0
+Threshold4=0
+Threshold5=0
+Threshold6=0
+Threshold7=0
+Threshold8=0
+Threshold9=0
+Time0=0:0-0:0
+Time1=0:0-0:0
+Time2=0:0-0:0
+Time3=0:0-0:0
+Time4=0:0-0:0
+Time5=0:0-0:0
+Time6=0:0-0:0
+Time7=0:0-0:0
+Time8=0:0-0:0
+Time9=0:0-0:0
+TraffType=up+down
--- /dev/null
+Address=
+AlwaysOnline=0
+CreationTime=1123487395
+Credit=0.000000
+CreditExpire=0
+Down=0
+Email=
+Group=
+Iface=eth1
+IP=192.168.1.1
+Note=
+Passive=0
+Password=123456
+Phone=
+RealName=
+Tariff=tariff
+TariffChange=
+Userdata0=
+Userdata1=
--- /dev/null
+Cash=10.000000
+D0=0
+D1=0
+D2=0
+D3=0
+D4=0
+D5=0
+D6=0
+D7=0
+D8=0
+D9=0
+FreeMb=0.000000
+LastActivityTime=0
+LastCashAdd=0
+LastCashAddTime=0
+PassiveTime=0
+U0=0
+U1=0
+U2=0
+U3=0
+U4=0
+U5=0
+U6=0
+U7=0
+U8=0
+U9=0
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include "store_loader.h"
+#include "plugin_mgr.h"
+#include "plugin_runner.h"
+#include "users_impl.h"
+#include "admins_impl.h"
+#include "tariffs_impl.h"
+#include "services_impl.h"
+#include "corps_impl.h"
+#include "traffcounter_impl.h"
+#include "settings_impl.h"
+#include "pidfile.h"
+#include "eventloop.h"
+#include "stg_timer.h"
+
+#include "stg/user.h"
+#include "stg/common.h"
+#include "stg/plugin.h"
+#include "stg/logger.h"
+#include "stg/scriptexecuter.h"
+#include "stg/version.h"
+
+#include <fstream>
+#include <vector>
+#include <set>
+#include <csignal>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib> // srandom, exit
+
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h> // S_IRUSR
+#include <fcntl.h> // create
+
+#ifdef DEBUG
+ #define NO_DAEMON (1)
+#endif
+
+#define START_FILE "/._ST_ART_ED_"
+
+using STG::SettingsImpl;
+using STG::AdminsImpl;
+using STG::TraffCounterImpl;
+using STG::UsersImpl;
+using STG::TariffsImpl;
+using STG::ServicesImpl;
+using STG::CorporationsImpl;
+using STG::StoreLoader;
+
+namespace
+{
+std::set<pid_t> executers;
+
+void StartTimer();
+int StartScriptExecuter(char* procName, int msgKey, int* msgID);
+int ForkAndWait(const std::string& confDir);
+void KillExecuters();
+
+//-----------------------------------------------------------------------------
+void StartTimer()
+{
+ auto& WriteServLog = STG::Logger::get();
+
+ if (RunStgTimer())
+ {
+ WriteServLog("Cannot start timer. Fatal.");
+ exit(1);
+ }
+ else
+ WriteServLog("Timer thread started successfully.");
+}
+//-----------------------------------------------------------------------------
+#if defined(LINUX) || defined(DARWIN)
+int StartScriptExecuter(char* procName, int msgKey, int* msgID)
+#else
+int StartScriptExecuter(char*, int msgKey, int* msgID)
+#endif
+{
+ auto& WriteServLog = STG::Logger::get();
+
+ if (*msgID == -11) // If msgID == -11 - first call. Create queue
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
+
+ if (*msgID == -1)
+ {
+ *msgID = msgget(msgKey, 0);
+ if (*msgID == -1)
+ {
+ WriteServLog("Message queue not created.");
+ return -1;
+ }
+ else
+ msgctl(*msgID, IPC_RMID, NULL);
+ }
+ else
+ {
+ WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
+ break;
+ }
+ }
+ }
+
+ const auto pid = fork();
+
+ switch (pid)
+ {
+ case -1:
+ WriteServLog("Fork error!");
+ return -1;
+
+ case 0:
+#if defined(LINUX) || defined(DARWIN)
+ Executer(*msgID, pid, procName);
+#else
+ Executer(*msgID, pid);
+#endif
+ return 1;
+
+ default:
+ if (executers.empty()) {
+#if defined(LINUX) || defined(DARWIN)
+ Executer(*msgID, pid, NULL);
+#else
+ Executer(*msgID, pid);
+#endif
+ }
+ executers.insert(pid);
+ }
+ return 0;
+}
+//-----------------------------------------------------------------------------
+#ifndef NO_DAEMON
+int ForkAndWait(const std::string& confDir)
+#else
+int ForkAndWait(const std::string&)
+#endif
+{
+#ifndef NO_DAEMON
+ const auto pid = fork();
+ const auto startFile = confDir + START_FILE;
+ unlink(startFile.c_str());
+
+ switch (pid)
+ {
+ case -1:
+ return -1;
+ break;
+
+ case 0:
+ close(1);
+ close(2);
+ setsid();
+ break;
+
+ default:
+ struct timespec ts = {0, 200000000};
+ for (int i = 0; i < 120 * 5; i++)
+ {
+ if (access(startFile.c_str(), F_OK) == 0)
+ {
+ unlink(startFile.c_str());
+ exit(0);
+ }
+
+ nanosleep(&ts, NULL);
+ }
+ unlink(startFile.c_str());
+ exit(1);
+ break;
+ }
+#endif
+ return 0;
+}
+//-----------------------------------------------------------------------------
+void KillExecuters()
+{
+ auto pid = executers.begin();
+ while (pid != executers.end())
+ {
+ printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
+ kill(*pid, SIGUSR1);
+ ++pid;
+ }
+}
+//-----------------------------------------------------------------------------
+} // namespace anonymous
+//-----------------------------------------------------------------------------
+int main(int argc, char* argv[])
+{
+ int msgID = -11;
+
+ STG::Logger::get().setFileName("/var/log/stargazer.log");
+
+ if (getuid())
+ {
+ printf("You must be root. Exit.\n");
+ return 1;
+ }
+
+ SettingsImpl settings(argc == 2 ? argv[1] : "");
+
+ if (settings.ReadSettings())
+ {
+ auto& WriteServLog = STG::Logger::get();
+
+ if (settings.GetLogFileName() != "")
+ WriteServLog.setFileName(settings.GetLogFileName());
+
+ WriteServLog("ReadSettings error. %s", settings.GetStrError().c_str());
+ return -1;
+ }
+
+#ifndef NO_DAEMON
+ const auto startFile = settings.GetConfDir() + START_FILE;
+#endif
+
+ if (ForkAndWait(settings.GetConfDir()) < 0)
+ {
+ STG::Logger::get()("Fork error!");
+ return -1;
+ }
+
+ auto& WriteServLog = STG::Logger::get();
+ WriteServLog.setFileName(settings.GetLogFileName());
+ WriteServLog("Stg v. %s", SERVER_VERSION);
+
+ for (size_t i = 0; i < settings.GetExecutersNum(); i++)
+ {
+ auto ret = StartScriptExecuter(argv[0], settings.GetExecMsgKey(), &msgID);
+ if (ret < 0)
+ {
+ STG::Logger::get()("Start Script Executer error!");
+ return -1;
+ }
+ if (ret == 1)
+ return 0;
+ }
+
+ PIDFile pidFile(settings.GetPIDFileName());
+
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGHUP, &sa, NULL); // Apparently FreeBSD ignores SIGHUP by default when launched from rc.d at bot time.
+
+ sigset_t signalSet;
+ sigfillset(&signalSet);
+ pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+ StartTimer();
+ WaitTimer();
+ if (!IsStgTimerRunning())
+ {
+ printfd(__FILE__, "Timer thread not started in 1 sec!\n");
+ WriteServLog("Timer thread not started in 1 sec!");
+ return -1;
+ }
+
+ auto& loop = EVENT_LOOP_SINGLETON::GetInstance();
+
+ StoreLoader storeLoader(settings);
+ if (storeLoader.load())
+ {
+ printfd(__FILE__, "Storage plugin: '%s'\n", storeLoader.GetStrError().c_str());
+ WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str());
+ return -1;
+ }
+
+ if (loop.Start())
+ {
+ printfd(__FILE__, "Event loop not started.\n");
+ WriteServLog("Event loop not started.");
+ return -1;
+ }
+
+ auto& store = storeLoader.get();
+ WriteServLog("Storage plugin: %s. Loading successfull.", store.GetVersion().c_str());
+
+ AdminsImpl admins(store);
+ TariffsImpl tariffs(&store);
+ ServicesImpl services(&store);
+ CorporationsImpl corps(&store);
+ UsersImpl users(&settings, &store, &tariffs, services, admins.sysAdmin());
+ TraffCounterImpl traffCnt(&users, settings.GetRulesFileName());
+ traffCnt.SetMonitorDir(settings.GetMonitorDir());
+
+ if (users.Start())
+ return -1;
+
+ WriteServLog("Users started successfully.");
+
+ if (traffCnt.Start())
+ return -1;
+
+ WriteServLog("Traffcounter started successfully.");
+
+ STG::PluginManager manager(settings, store, admins, tariffs, services, corps, users, traffCnt);
+
+ srandom(static_cast<unsigned int>(stgTime));
+
+ WriteServLog("Stg started successfully.");
+ WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+#ifndef NO_DAEMON
+ creat(startFile.c_str(), S_IRUSR);
+#endif
+
+ bool running = true;
+ while (running)
+ {
+ sigfillset(&signalSet);
+ int sig = 0;
+ sigwait(&signalSet, &sig);
+ int status;
+ switch (sig)
+ {
+ case SIGHUP:
+ {
+ SettingsImpl newSettings(settings);
+ if (newSettings.ReadSettings())
+ WriteServLog("ReadSettings error. %s", newSettings.GetStrError().c_str());
+ else
+ settings = newSettings;
+ WriteServLog.setFileName(settings.GetLogFileName());
+ traffCnt.Reload();
+ manager.reload(settings);
+ break;
+ }
+ case SIGTERM:
+ running = false;
+ break;
+ case SIGINT:
+ running = false;
+ break;
+ case SIGPIPE:
+ WriteServLog("Broken pipe!");
+ break;
+ case SIGCHLD:
+ executers.erase(waitpid(-1, &status, WNOHANG));
+ if (executers.empty())
+ running = false;
+ break;
+ default:
+ WriteServLog("Ignore signal %d", sig);
+ break;
+ }
+ }
+
+ WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+ manager.stop();
+
+ if (loop.Stop())
+ WriteServLog("Event loop not stopped.");
+
+ if (!traffCnt.Stop())
+ WriteServLog("Traffcounter: Stop successfull.");
+
+ if (!users.Stop())
+ WriteServLog("Users: Stop successfull.");
+
+ sleep(1);
+ int res = msgctl(msgID, IPC_RMID, NULL);
+ if (res)
+ WriteServLog("Queue was not removed. id=%d", msgID);
+ else
+ WriteServLog("Queue removed successfully.");
+
+ KillExecuters();
+
+ StopStgTimer();
+ WriteServLog("StgTimer: Stop successfull.");
+
+ WriteServLog("Stg stopped successfully.");
+ WriteServLog("---------------------------------------------");
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2009/06/09 09:07:32 $
+ $Author: faust $
+ */
+
+/*
+ * An implementation of RAII pid-file writer
+ */
+
+#include <fstream>
+#include <unistd.h>
+
+#include "pidfile.h"
+
+PIDFile::PIDFile(const std::string & fn)
+ : fileName(fn)
+{
+if (fileName != "")
+ {
+ std::ofstream pf(fileName.c_str());
+ pf << getpid() << std::endl;
+ pf.close();
+ }
+}
+
+PIDFile::~PIDFile()
+{
+if (fileName != "")
+ {
+ unlink(fileName.c_str());
+ }
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Header file for RAII pid-file writer
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2009/06/09 09:07:32 $
+ $Author: faust $
+ */
+
+#ifndef __PID_FILE_H__
+#define __PID_FILE_H__
+
+#include <string>
+
+class PIDFile {
+public:
+ explicit PIDFile(const std::string & fn);
+ ~PIDFile();
+private:
+ std::string fileName;
+};
+
+#endif
--- /dev/null
+/*
+ * 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 "plugin_mgr.h"
+
+#include "plugin_runner.h"
+
+#include "admins_impl.h"
+#include "tariffs_impl.h"
+#include "services_impl.h"
+#include "corps_impl.h"
+#include "users_impl.h"
+#include "traffcounter_impl.h"
+#include "settings_impl.h"
+
+#include "stg/logger.h"
+
+using STG::PluginManager;
+using STG::PluginRunner;
+
+namespace
+{
+
+bool StartModCmp(const PluginRunner * lhs, const PluginRunner * rhs)
+{
+ return lhs->GetStartPosition() < rhs->GetStartPosition();
+}
+
+bool StopModCmp(const PluginRunner * lhs, const PluginRunner * rhs)
+{
+ return lhs->GetStopPosition() > rhs->GetStopPosition();
+}
+
+} // namespace anonymous
+
+PluginManager::PluginManager(const SettingsImpl& settings,
+ Store& store, AdminsImpl& admins, TariffsImpl& tariffs,
+ ServicesImpl& services, CorporationsImpl& corporations,
+ UsersImpl& users, TraffCounterImpl& traffcounter)
+ : m_log(Logger::get())
+{
+ std::string basePath = settings.GetModulesPath();
+ const std::vector<ModuleSettings> & modSettings(settings.GetModulesSettings());
+ for (size_t i = 0; i < modSettings.size(); i++)
+ {
+ std::string moduleName = modSettings[i].moduleName;
+ std::string modulePath = basePath + "/mod_" + moduleName + ".so";
+ printfd(__FILE__, "Module: %s\n", modulePath.c_str());
+ try
+ {
+ m_modules.push_back(
+ new PluginRunner(modulePath, moduleName, modSettings[i], admins, tariffs,
+ users, services, corporations, traffcounter,
+ store, settings)
+ );
+ }
+ catch (const PluginRunner::Error & ex)
+ {
+ m_log(ex.what());
+ printfd(__FILE__, "%s\n", ex.what());
+ // TODO: React
+ }
+ }
+ std::sort(m_modules.begin(), m_modules.end(), StartModCmp);
+ for (size_t i = 0; i < m_modules.size(); ++i)
+ {
+ auto& plugin = m_modules[i]->GetPlugin();
+ if (m_modules[i]->Start())
+ {
+ m_log("Failed to start module '%s': '%s'", plugin.GetVersion().c_str(),
+ plugin.GetStrError().c_str());
+ printfd(__FILE__, "Failed to start module '%s': '%s'\n", plugin.GetVersion().c_str(),
+ plugin.GetStrError().c_str());
+ }
+ else
+ {
+ m_log("Module '%s' started successfully.", plugin.GetVersion().c_str());
+ printfd(__FILE__, "Module '%s' started successfully.\n", plugin.GetVersion().c_str());
+ }
+ }
+}
+
+PluginManager::~PluginManager()
+{
+ stop();
+ for (size_t i = 0; i < m_modules.size(); ++i)
+ delete m_modules[i];
+}
+
+void PluginManager::reload(const SettingsImpl& settings)
+{
+ const std::vector<ModuleSettings> & modSettings(settings.GetModulesSettings());
+ for (size_t i = 0; i < m_modules.size(); ++i)
+ {
+ for (size_t j = 0; j < modSettings.size(); j++)
+ {
+ if (modSettings[j].moduleName == m_modules[i]->GetName())
+ {
+ auto& plugin = m_modules[i]->GetPlugin();
+ if (m_modules[i]->Reload(modSettings[j]))
+ {
+ m_log("Error reloading module '%s': '%s'", plugin.GetVersion().c_str(),
+ plugin.GetStrError().c_str());
+ printfd(__FILE__, "Error reloading module '%s': '%s'\n", plugin.GetVersion().c_str(),
+ plugin.GetStrError().c_str());
+ }
+ break;
+ }
+ }
+ }
+}
+
+void PluginManager::stop()
+{
+ std::sort(m_modules.begin(), m_modules.end(), StopModCmp);
+ for (size_t i = 0; i < m_modules.size(); ++i)
+ {
+ if (!m_modules[i]->IsRunning())
+ continue;
+ auto& plugin = m_modules[i]->GetPlugin();
+ if (m_modules[i]->Stop())
+ {
+ m_log("Failed to stop module '%s': '%s'", plugin.GetVersion().c_str(),
+ plugin.GetStrError().c_str());
+ printfd(__FILE__, "Failed to stop module '%s': '%s'\n", plugin.GetVersion().c_str(),
+ plugin.GetStrError().c_str());
+ }
+ else
+ {
+ m_log("Module '%s' stopped successfully.", plugin.GetVersion().c_str());
+ printfd(__FILE__, "Module '%s' stopped successfully.\n", plugin.GetVersion().c_str());
+ }
+ }
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/module_settings.h"
+
+#include <vector>
+
+namespace STG
+{
+
+class SettingsImpl;
+class PluginRunner;
+struct Store;
+class AdminsImpl;
+class TariffsImpl;
+class ServicesImpl;
+class CorporationsImpl;
+class UsersImpl;
+class TraffCounterImpl;
+class Logger;
+
+class PluginManager
+{
+ public:
+ PluginManager(const SettingsImpl& settings,
+ Store& store, AdminsImpl& admins, TariffsImpl& tariffs,
+ ServicesImpl& services, CorporationsImpl& corporations,
+ UsersImpl& users, TraffCounterImpl& traffcounter);
+ ~PluginManager();
+
+ void reload(const SettingsImpl& settings);
+ void stop();
+
+ private:
+ std::vector<PluginRunner*> m_modules;
+ Logger & m_log;
+};
+
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "plugin_runner.h"
+
+#include "stg/common.h"
+
+#include <dlfcn.h>
+#include <unistd.h>
+
+using STG::PluginRunner;
+using STG::Plugin;
+
+//-----------------------------------------------------------------------------
+PluginRunner::PluginRunner(const std::string& fileName,
+ const std::string& name,
+ const ModuleSettings& ms,
+ Admins& admins,
+ Tariffs& tariffs,
+ Users& users,
+ Services& services,
+ Corporations& corporations,
+ TraffCounter& traffcounter,
+ Store& store,
+ const Settings& settings)
+ : pluginFileName(fileName),
+ pluginName(name),
+ libHandle(NULL),
+ m_plugin(load(ms, admins, tariffs, users, services, corporations,
+ traffcounter, store, settings))
+{
+}
+//-----------------------------------------------------------------------------
+PluginRunner::~PluginRunner()
+{
+ delete &m_plugin;
+ if (dlclose(libHandle))
+ {
+ errorStr = "Failed to unload plugin '" + pluginFileName + "': " + dlerror();
+ printfd(__FILE__, "PluginRunner::Unload() - %s", errorStr.c_str());
+ }
+}
+//-----------------------------------------------------------------------------
+int PluginRunner::Start()
+{
+ int res = m_plugin.Start();
+ errorStr = m_plugin.GetStrError();
+ return res;
+}
+//-----------------------------------------------------------------------------
+int PluginRunner::Stop()
+{
+ int res = m_plugin.Stop();
+ errorStr = m_plugin.GetStrError();
+ return res;
+}
+//-----------------------------------------------------------------------------
+int PluginRunner::Reload(const ModuleSettings& ms)
+{
+ int res = m_plugin.Reload(ms);
+ errorStr = m_plugin.GetStrError();
+ return res;
+}
+//-----------------------------------------------------------------------------
+Plugin & PluginRunner::load(const ModuleSettings& ms,
+ Admins& admins,
+ Tariffs& tariffs,
+ Users& users,
+ Services& services,
+ Corporations& corporations,
+ TraffCounter& traffcounter,
+ Store& store,
+ const Settings& settings)
+{
+ if (pluginFileName.empty())
+ {
+ const std::string msg = "Empty plugin file name.";
+ printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
+ throw Error(msg);
+ }
+
+ if (access(pluginFileName.c_str(), R_OK))
+ {
+ const std::string msg = "Plugin file '" + pluginFileName + "' is missing or inaccessible.";
+ printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
+ throw Error(msg);
+ }
+
+ libHandle = dlopen(pluginFileName.c_str(), RTLD_NOW);
+
+ if (!libHandle)
+ {
+ std::string msg = "Error loading plugin '" + pluginFileName + "'";
+ const char* error = dlerror();
+ if (error)
+ msg = msg + ": '" + error + "'";
+ printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
+ throw Error(msg);
+ }
+
+ using Getter = Plugin* (*)();
+ auto GetPlugin = reinterpret_cast<Getter>(dlsym(libHandle, "GetPlugin"));
+ if (!GetPlugin)
+ {
+ const std::string msg = "Plugin '" + pluginFileName + "' does not have GetPlugin() function. ";
+ printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
+ throw Error(msg);
+ }
+
+ Plugin* plugin = GetPlugin();
+
+ if (!plugin)
+ {
+ const std::string msg = "Failed to create an instance of plugin '" + pluginFileName + "'.";
+ printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
+ throw Error(msg);
+ }
+
+ plugin->SetSettings(ms);
+ plugin->SetTariffs(&tariffs);
+ plugin->SetAdmins(&admins);
+ plugin->SetUsers(&users);
+ plugin->SetServices(&services);
+ plugin->SetCorporations(&corporations);
+ plugin->SetTraffcounter(&traffcounter);
+ plugin->SetStore(&store);
+ plugin->SetStgSettings(&settings);
+
+ if (plugin->ParseSettings())
+ {
+ const std::string msg = "Plugin '" + pluginFileName + "' is unable to parse settings. " + plugin->GetStrError();
+ printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
+ throw Error(msg);
+ }
+
+ return *plugin;
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/plugin.h"
+
+#include <string>
+#include <stdexcept>
+#include <cstdint>
+
+namespace STG
+{
+
+struct ModuleSettings;
+struct Settings;
+struct Admins;
+struct Tariffs;
+struct Users;
+struct Services;
+struct Corporations;
+struct TraffCounter;
+struct Store;
+
+//-----------------------------------------------------------------------------
+class PluginRunner {
+public:
+ struct Error : public std::runtime_error {
+ explicit Error(const std::string & msg) : runtime_error(msg) {}
+ };
+
+ PluginRunner(const std::string& pluginFileName,
+ const std::string& pluginName,
+ const ModuleSettings& ms,
+ Admins& admins,
+ Tariffs& tariffs,
+ Users& users,
+ Services& services,
+ Corporations& corporations,
+ TraffCounter& traffcounter,
+ Store& store,
+ const Settings & settings);
+ ~PluginRunner();
+
+ int Start();
+ int Stop();
+ int Reload(const ModuleSettings& ms);
+ int Restart();
+ bool IsRunning() { return m_plugin.IsRunning(); }
+
+ const std::string& GetStrError() const { return errorStr; }
+ Plugin& GetPlugin() { return m_plugin; }
+ const std::string& GetFileName() const { return pluginFileName; }
+ const std::string& GetName() const { return pluginName; }
+
+ uint16_t GetStartPosition() const { return m_plugin.GetStartPosition(); }
+ uint16_t GetStopPosition() const { return m_plugin.GetStopPosition(); }
+
+private:
+ Plugin & load(const ModuleSettings& ms,
+ Admins& admins,
+ Tariffs& tariffs,
+ Users& users,
+ Services& services,
+ Corporations& corporations,
+ TraffCounter& traffcounter,
+ Store& store,
+ const Settings& settings);
+
+ std::string pluginFileName;
+ std::string pluginName;
+ void* libHandle;
+
+ Plugin& m_plugin;
+ std::string errorStr;
+};
+//-----------------------------------------------------------------------------
+}
--- /dev/null
+if ( BUILD_MOD_AO )
+ add_library ( mod_auth_ao MODULE authorization/ao/ao.cpp )
+ target_link_libraries ( mod_auth_ao scriptexecuter logger common )
+ set_target_properties ( mod_auth_ao PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_AO )
+
+if ( BUILD_MOD_IA )
+ add_library ( mod_auth_ia MODULE authorization/inetaccess/inetaccess.cpp )
+ target_link_libraries ( mod_auth_ia scriptexecuter crypto logger common )
+ set_target_properties ( mod_auth_ia PROPERTIES PREFIX "" )
+ if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
+ set_target_properties ( mod_auth_ia PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
+ endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
+endif ( BUILD_MOD_IA )
+
+if ( BUILD_MOD_CAP_NF )
+ add_library ( mod_cap_nf MODULE capture/cap_nf/cap_nf.cpp )
+ target_link_libraries ( mod_cap_nf logger common )
+ set_target_properties ( mod_cap_nf PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_CAP_NF )
+
+if ( BUILD_MOD_CAP_DIVERT )
+ add_library ( mod_cap_divert MODULE capture/divert_freebsd/divert_cap.cpp )
+ target_link_libraries ( mod_cap_divert logger common )
+ set_target_properties ( mod_cap_divert PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_CAP_DIVERT )
+
+if ( BUILD_MOD_CAP_ETHER_FREEBSD )
+ add_library ( mod_cap_bpf MODULE capture/ether_freebsd/ether_cap.cpp )
+ target_link_libraries ( mod_cap_bpf logger common )
+ set_target_properties ( mod_cap_bpf PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_CAP_ETHER_FREEBSD )
+
+if ( BUILD_MOD_CAP_ETHER_LINUX )
+ add_library ( mod_cap_ether MODULE capture/ether_linux/ether_cap.cpp )
+ target_link_libraries ( mod_cap_ether logger common )
+ set_target_properties ( mod_cap_ether PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_CAP_ETHER_LINUX )
+
+if ( BUILD_MOD_CAP_PCAP )
+ find_package ( PCap REQUIRED )
+ add_library ( mod_cap_pcap MODULE capture/pcap/pcap_cap.cpp )
+ target_link_libraries ( mod_cap_pcap logger common PCap::PCap )
+ set_target_properties ( mod_cap_pcap PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_CAP_PCAP )
+
+if ( BUILD_MOD_CAP_NFQUEUE )
+ find_package ( NFQueue REQUIRED )
+ find_package ( NFNetLink REQUIRED )
+ find_package ( MNL REQUIRED )
+ add_library ( mod_cap_nfqueue MODULE capture/nfqueue/nfqueue.cpp )
+ target_link_libraries ( mod_cap_nfqueue logger common NF::Queue NF::NetLink MNL::MNL )
+ set_target_properties ( mod_cap_nfqueue PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_CAP_NFQUEUE )
+
+if ( BUILD_MOD_SGCONFIG )
+ find_package ( EXPAT REQUIRED )
+ add_library ( mod_conf_sg MODULE configuration/sgconfig/stgconfig.cpp
+ configuration/sgconfig/conn.cpp
+ configuration/sgconfig/configproto.cpp
+ configuration/sgconfig/parser.cpp
+ configuration/sgconfig/parser_tariffs.cpp
+ configuration/sgconfig/parser_admins.cpp
+ configuration/sgconfig/parser_users.cpp
+ configuration/sgconfig/parser_services.cpp
+ configuration/sgconfig/parser_message.cpp
+ configuration/sgconfig/parser_auth_by.cpp
+ configuration/sgconfig/parser_user_info.cpp
+ configuration/sgconfig/parser_server_info.cpp )
+ target_link_libraries ( mod_conf_sg scriptexecuter crypto logger common EXPAT::EXPAT )
+ set_target_properties ( mod_conf_sg PROPERTIES PREFIX "" )
+ if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
+ set_target_properties ( mod_conf_sg PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
+ endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
+endif ( BUILD_MOD_SGCONFIG )
+
+if ( BUILD_MOD_RPCCONFIG )
+ find_package ( XMLRPC REQUIRED c++ abyss-server )
+ include_directories ( ${XMLRPC_INCLUDE_DIRS} )
+ add_library ( mod_conf_rpc MODULE configuration/rpcconfig/rpcconfig.cpp
+ configuration/rpcconfig/user_helper.cpp
+ configuration/rpcconfig/tariff_helper.cpp
+ configuration/rpcconfig/info_methods.cpp
+ configuration/rpcconfig/users_methods.cpp
+ configuration/rpcconfig/tariffs_methods.cpp
+ configuration/rpcconfig/admins_methods.cpp
+ configuration/rpcconfig/messages_methods.cpp )
+ target_link_libraries ( mod_conf_rpc scriptexecuter logger common ${XMLRPC_LIBRARIES} )
+ set_target_properties ( mod_conf_rpc PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_RPCCONFIG )
+
+if ( BUILD_MOD_PING )
+ add_library ( mod_ping MODULE other/ping/ping.cpp )
+ target_link_libraries ( mod_ping scriptexecuter logger pinger common )
+ set_target_properties ( mod_ping PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_PING )
+
+if ( BUILD_MOD_RSCRYPT )
+ add_library ( mod_remote_script MODULE other/rscript/rscript.cpp other/rscript/nrmap_parser.cpp )
+ target_link_libraries ( mod_remote_script crypto scriptexecuter logger common )
+ set_target_properties ( mod_remote_script PROPERTIES PREFIX "" )
+ if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
+ set_target_properties ( mod_remote_script PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
+ endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
+endif ( BUILD_MOD_RSCRYPT )
+
+if ( BUILD_MOD_SMUX )
+ add_library ( mod_smux MODULE other/smux/smux.cpp
+ other/smux/sensors.cpp
+ other/smux/tables.cpp
+ other/smux/handlers.cpp
+ other/smux/utils.cpp
+ other/smux/types.cpp )
+ target_link_libraries ( mod_smux scriptexecuter logger smux common )
+ set_target_properties ( mod_smux PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_SMUX )
+
+if ( BUILD_MOD_STORE_FILES )
+ add_library ( mod_store_files MODULE store/files/file_store.cpp )
+ target_link_libraries ( mod_store_files crypto conffiles logger common )
+ set_target_properties ( mod_store_files PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_STORE_FILES )
+
+if ( BUILD_MOD_STORE_FIREBIRD )
+ find_package ( FBClient REQUIRED )
+ add_library ( mod_store_firebird MODULE store/firebird/firebird_store.cpp
+ store/firebird/firebird_store_admins.cpp
+ store/firebird/firebird_store_corporations.cpp
+ store/firebird/firebird_store_messages.cpp
+ store/firebird/firebird_store_services.cpp
+ store/firebird/firebird_store_tariffs.cpp
+ store/firebird/firebird_store_users.cpp
+ store/firebird/firebird_store_utils.cpp )
+ target_link_libraries ( mod_store_firebird crypto common logger ibpp FBClient::FBClient )
+ set_target_properties ( mod_store_firebird PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_STORE_FIREBIRD )
+
+if ( BUILD_MOD_STORE_MYSQL )
+ find_package ( MySQLConnector REQUIRED )
+ add_library ( mod_store_mysql MODULE store/mysql/mysql_store.cpp )
+ target_link_libraries ( mod_store_mysql crypto logger common MySQL::Connector )
+ set_target_properties ( mod_store_mysql PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_STORE_MYSQL )
+
+if ( BUILD_MOD_STORE_POSTGRESQL )
+ find_package ( PostgreSQL REQUIRED )
+ include_directories ( ${PostgreSQL_INCLUDE_DIRS} )
+ add_library ( mod_store_postgresql MODULE store/postgresql/postgresql_store.cpp
+ store/postgresql/postgresql_store_admins.cpp
+ store/postgresql/postgresql_store_corporations.cpp
+ store/postgresql/postgresql_store_messages.cpp
+ store/postgresql/postgresql_store_services.cpp
+ store/postgresql/postgresql_store_tariffs.cpp
+ store/postgresql/postgresql_store_users.cpp
+ store/postgresql/postgresql_store_utils.cpp )
+ target_link_libraries ( mod_store_postgresql crypto logger common ${PostgreSQL_LIBRARIES} )
+ set_target_properties ( mod_store_postgresql PROPERTIES PREFIX "" )
+endif ( BUILD_MOD_STORE_POSTGRESQL )
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include "ao.h"
+
+#include "stg/user.h"
+#include "stg/users.h"
+#include "stg/user_property.h"
+#include "stg/common.h"
+
+#include <algorithm> // for_each
+#include <functional> // mem_fun_ref
+#include <csignal>
+#include <cassert>
+
+#include <unistd.h>
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static AUTH_AO plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string AUTH_AO::GetVersion() const
+{
+return "Always Online authorizator v.1.0";
+}
+//-----------------------------------------------------------------------------
+AUTH_AO::AUTH_AO()
+ : users(NULL),
+ isRunning(false),
+ onAddUserNotifier(*this),
+ onDelUserNotifier(*this),
+ logger(STG::PluginLogger::get("auth_ao"))
+{
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::Start()
+{
+printfd(__FILE__, "AUTH_AO::Start()\n");
+GetUsers();
+
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+std::for_each(userList.begin(), userList.end(), [this](auto user){ UpdateUserAuthorization(user); });
+
+isRunning = true;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::Stop()
+{
+printfd(__FILE__, "AUTH_AO::Stop()\n");
+if (!isRunning)
+ return 0;
+
+users->DelNotifierUserAdd(&onAddUserNotifier);
+users->DelNotifierUserDel(&onDelUserNotifier);
+
+auto it = userList.begin();
+while (it != userList.end())
+ {
+ if ((*it)->IsAuthorizedBy(this))
+ users->Unauthorize((*it)->GetLogin(), this);
+ UnSetUserNotifiers(*it);
+ ++it;
+ }
+isRunning = false;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::SetUserNotifiers(UserPtr u)
+{
+// ---------- AlwaysOnline -------------------
+CHG_BEFORE_NOTIFIER<int> BeforeChgAONotifier(*this, u);
+CHG_AFTER_NOTIFIER<int> AfterChgAONotifier(*this, u);
+
+BeforeChgAONotifierList.push_front(BeforeChgAONotifier);
+AfterChgAONotifierList.push_front(AfterChgAONotifier);
+
+u->GetProperties().alwaysOnline.AddBeforeNotifier(&BeforeChgAONotifierList.front());
+u->GetProperties().alwaysOnline.AddAfterNotifier(&AfterChgAONotifierList.front());
+// ---------- AlwaysOnline end ---------------
+
+// ---------- IP -------------------
+CHG_BEFORE_NOTIFIER<STG::UserIPs> BeforeChgIPNotifier(*this, u);
+CHG_AFTER_NOTIFIER<STG::UserIPs> AfterChgIPNotifier(*this, u);
+
+BeforeChgIPNotifierList.push_front(BeforeChgIPNotifier);
+AfterChgIPNotifierList.push_front(AfterChgIPNotifier);
+
+u->GetProperties().ips.AddBeforeNotifier(&BeforeChgIPNotifierList.front());
+u->GetProperties().ips.AddAfterNotifier(&AfterChgIPNotifierList.front());
+// ---------- IP end ---------------
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::UnSetUserNotifiers(UserPtr u)
+{
+// --- AlwaysOnline ---
+auto aoBIter = find_if(BeforeChgAONotifierList.begin(),
+ BeforeChgAONotifierList.end(),
+ [u](auto notifier){ return notifier.GetUser() == u; });
+
+if (aoBIter != BeforeChgAONotifierList.end())
+ {
+ aoBIter->GetUser()->GetProperties().alwaysOnline.DelBeforeNotifier(&(*aoBIter));
+ BeforeChgAONotifierList.erase(aoBIter);
+ }
+
+auto aoAIter = find_if(AfterChgAONotifierList.begin(),
+ AfterChgAONotifierList.end(),
+ [u](auto notifier){ return notifier.GetUser() == u; });
+
+if (aoAIter != AfterChgAONotifierList.end())
+ {
+ aoAIter->GetUser()->GetProperties().alwaysOnline.DelAfterNotifier(&(*aoAIter));
+ AfterChgAONotifierList.erase(aoAIter);
+ }
+// --- AlwaysOnline end ---
+
+// --- IP ---
+auto ipBIter = std::find_if(BeforeChgIPNotifierList.begin(),
+ BeforeChgIPNotifierList.end(),
+ [u](auto notifier){ return notifier.GetUser() == u; });
+
+if (ipBIter != BeforeChgIPNotifierList.end())
+ {
+ ipBIter->GetUser()->GetProperties().ips.DelBeforeNotifier(&(*ipBIter));
+ BeforeChgIPNotifierList.erase(ipBIter);
+ }
+
+auto ipAIter = find_if(AfterChgIPNotifierList.begin(),
+ AfterChgIPNotifierList.end(),
+ [u](auto notifier){ return notifier.GetUser() == u; });
+
+if (ipAIter != AfterChgIPNotifierList.end())
+ {
+ ipAIter->GetUser()->GetProperties().ips.DelAfterNotifier(&(*ipAIter));
+ AfterChgIPNotifierList.erase(ipAIter);
+ }
+// --- IP end ---
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::GetUsers()
+{
+UserPtr u;
+int h = users->OpenSearch();
+assert(h && "USERS::OpenSearch is always correct");
+
+while (!users->SearchNext(h, &u))
+ {
+ userList.push_back(u);
+ SetUserNotifiers(u);
+ }
+
+users->CloseSearch(h);
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::UpdateUserAuthorization(ConstUserPtr u) const
+{
+if (u->GetProperties().alwaysOnline)
+ {
+ auto ips = u->GetProperties().ips.get();
+ if (ips.onlyOneIP())
+ {
+ users->Authorize(u->GetLogin(), ips[0].ip, 0xFFffFFff, this);
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::AddUser(UserPtr u)
+{
+SetUserNotifiers(u);
+userList.push_back(u);
+UpdateUserAuthorization(u);
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::DelUser(UserPtr u)
+{
+if (u->IsAuthorizedBy(this))
+ users->Unauthorize(u->GetLogin(), this);
+UnSetUserNotifiers(u);
+userList.erase(std::remove(userList.begin(), userList.end(), u), userList.end());
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::SendMessage(const STG::Message &, uint32_t) const
+{
+errorStr = "Authorization modele \'AlwaysOnline\' does not support sending messages";
+return -1;
+}
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void CHG_BEFORE_NOTIFIER<varParamType>::Notify(const varParamType &, const varParamType &)
+{
+//EVENT_LOOP_SINGLETON::GetInstance().Enqueue(auth, &AUTH_AO::Unauthorize, user);
+if (user->IsAuthorizedBy(&auth))
+ auth.users->Unauthorize(user->GetLogin(), &auth);
+}
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void CHG_AFTER_NOTIFIER<varParamType>::Notify(const varParamType &, const varParamType &)
+{
+//EVENT_LOOP_SINGLETON::GetInstance().Enqueue(auth, &AUTH_AO::UpdateUserAuthorization, user);
+auth.UpdateUserAuthorization(user);
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/auth.h"
+#include "stg/module_settings.h"
+#include "stg/store.h"
+#include "stg/notifer.h"
+#include "stg/user_ips.h"
+#include "stg/user.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+#include <list>
+
+#include <pthread.h>
+
+namespace STG
+{
+struct Users;
+}
+
+class AUTH_AO;
+
+using UserPtr = STG::User*;
+using ConstUserPtr = const STG::User*;
+
+template <typename T>
+class CHG_BEFORE_NOTIFIER : public STG::PropertyNotifierBase<T> {
+public:
+ CHG_BEFORE_NOTIFIER(AUTH_AO & a, UserPtr u)
+ : user(u), auth(a) {}
+ CHG_BEFORE_NOTIFIER(const CHG_BEFORE_NOTIFIER<T> & rvalue)
+ : user(rvalue.user), auth(rvalue.auth) {}
+ void Notify(const T & oldValue, const T & newValue);
+ UserPtr GetUser() const { return user; }
+
+private:
+ CHG_BEFORE_NOTIFIER<T> & operator=(const CHG_BEFORE_NOTIFIER<T> & rvalue);
+
+ UserPtr user;
+ const AUTH_AO & auth;
+};
+//-----------------------------------------------------------------------------
+template <typename T>
+class CHG_AFTER_NOTIFIER : public STG::PropertyNotifierBase<T> {
+public:
+ CHG_AFTER_NOTIFIER(AUTH_AO & a, UserPtr u)
+ : user(u), auth(a) {}
+ CHG_AFTER_NOTIFIER(const CHG_AFTER_NOTIFIER<T> & rvalue)
+ : user(rvalue.user), auth(rvalue.auth) {}
+ void Notify(const T & oldValue, const T & newValue);
+ UserPtr GetUser() const { return user; }
+
+private:
+ CHG_AFTER_NOTIFIER<T> & operator=(const CHG_AFTER_NOTIFIER<T> & rvalue);
+
+ UserPtr user;
+ const AUTH_AO & auth;
+};
+//-----------------------------------------------------------------------------
+class AUTH_AO : public STG::Auth {
+public:
+ AUTH_AO();
+
+ void SetUsers(STG::Users * u) override { users = u; }
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return isRunning; }
+ void SetSettings(const STG::ModuleSettings &) override {}
+ int ParseSettings() override { return 0; }
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override;
+ uint16_t GetStartPosition() const override { return 30; }
+ uint16_t GetStopPosition() const override { return 30; }
+
+ int SendMessage(const STG::Message & msg, uint32_t ip) const override;
+
+private:
+ AUTH_AO(const AUTH_AO & rvalue);
+ AUTH_AO & operator=(const AUTH_AO & rvalue);
+
+ void AddUser(UserPtr u);
+ void DelUser(UserPtr u);
+
+ void GetUsers();
+ void SetUserNotifiers(UserPtr u);
+ void UnSetUserNotifiers(UserPtr u);
+ void UpdateUserAuthorization(ConstUserPtr u) const;
+
+ mutable std::string errorStr;
+ STG::Users * users;
+ std::vector<UserPtr> userList;
+ bool isRunning;
+ STG::ModuleSettings settings;
+
+ std::list<CHG_BEFORE_NOTIFIER<int> > BeforeChgAONotifierList;
+ std::list<CHG_AFTER_NOTIFIER<int> > AfterChgAONotifierList;
+
+ std::list<CHG_BEFORE_NOTIFIER<STG::UserIPs> > BeforeChgIPNotifierList;
+ std::list<CHG_AFTER_NOTIFIER<STG::UserIPs> > AfterChgIPNotifierList;
+
+ class ADD_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
+ public:
+ explicit ADD_USER_NONIFIER(AUTH_AO & a) : auth(a) {}
+ virtual ~ADD_USER_NONIFIER() {}
+ void Notify(const UserPtr & user) { auth.AddUser(user); }
+
+ private:
+ ADD_USER_NONIFIER(const ADD_USER_NONIFIER & rvalue);
+ ADD_USER_NONIFIER & operator=(const ADD_USER_NONIFIER & rvalue);
+
+ AUTH_AO & auth;
+ } onAddUserNotifier;
+
+ class DEL_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
+ public:
+ explicit DEL_USER_NONIFIER(AUTH_AO & a) : auth(a) {}
+ virtual ~DEL_USER_NONIFIER() {}
+ void Notify(const UserPtr & user) { auth.DelUser(user); }
+
+ private:
+ DEL_USER_NONIFIER(const DEL_USER_NONIFIER & rvalue);
+ DEL_USER_NONIFIER & operator=(const DEL_USER_NONIFIER & rvalue);
+
+ AUTH_AO & auth;
+ } onDelUserNotifier;
+
+ STG::PluginLogger logger;
+
+ friend class CHG_BEFORE_NOTIFIER<int>;
+ friend class CHG_AFTER_NOTIFIER<int>;
+ friend class CHG_BEFORE_NOTIFIER<STG::UserIPs>;
+ friend class CHG_AFTER_NOTIFIER<STG::UserIPs>;
+
+};
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "inetaccess.h"
+
+#include "stg/common.h"
+#include "stg/locker.h"
+#include "stg/tariff.h"
+#include "stg/settings.h"
+
+#include <algorithm>
+#include <csignal>
+#include <cstdlib>
+#include <cstdio> // snprintf
+#include <cerrno>
+#include <cmath>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h> // close
+
+#define IA_PROTO_VER (6)
+
+extern volatile time_t stgTime;
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static AUTH_IA plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+AUTH_IA_SETTINGS::AUTH_IA_SETTINGS()
+ : userDelay(0),
+ userTimeout(0),
+ port(0),
+ freeMbShowType(freeMbCash),
+ logProtocolErrors(false)
+{
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+int p;
+STG::ParamValue pv;
+std::vector<STG::ParamValue>::const_iterator pvi;
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Port\' not found.";
+ printfd(__FILE__, "Parameter 'Port' not found\n");
+ return -1;
+ }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+ {
+ errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+ return -1;
+ }
+port = static_cast<uint16_t>(p);
+///////////////////////////
+pv.param = "UserDelay";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'UserDelay\' not found.";
+ printfd(__FILE__, "Parameter 'UserDelay' not found\n");
+ return -1;
+ }
+
+if (ParseIntInRange(pvi->value[0], 5, 600, &userDelay))
+ {
+ errorStr = "Cannot parse parameter \'UserDelay\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'UserDelay'\n");
+ return -1;
+ }
+///////////////////////////
+pv.param = "UserTimeout";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'UserTimeout\' not found.";
+ printfd(__FILE__, "Parameter 'UserTimeout' not found\n");
+ return -1;
+ }
+
+if (ParseIntInRange(pvi->value[0], 15, 1200, &userTimeout))
+ {
+ errorStr = "Cannot parse parameter \'UserTimeout\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'UserTimeout'\n");
+ return -1;
+ }
+///////////////////////////
+pv.param = "LogProtocolErrors";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ logProtocolErrors = false;
+else if (ParseYesNo(pvi->value[0], &logProtocolErrors))
+ {
+ errorStr = "Cannot parse parameter \'LogProtocolErrors\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'LogProtocolErrors'\n");
+ return -1;
+ }
+/////////////////////////////////////////////////////////////
+std::string freeMbType;
+int n = 0;
+pv.param = "FreeMb";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'FreeMb\' not found.";
+ printfd(__FILE__, "Parameter 'FreeMb' not found\n");
+ return -1;
+ }
+freeMbType = pvi->value[0];
+
+if (strcasecmp(freeMbType.c_str(), "cash") == 0)
+ {
+ freeMbShowType = freeMbCash;
+ }
+else if (strcasecmp(freeMbType.c_str(), "none") == 0)
+ {
+ freeMbShowType = freeMbNone;
+ }
+else if (!str2x(freeMbType.c_str(), n))
+ {
+ if (n < 0 || n >= DIR_NUM)
+ {
+ errorStr = "Incorrect parameter \'" + freeMbType + "\'.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+ freeMbShowType = (FREEMB)(freeMb0 + n);
+ }
+else
+ {
+ errorStr = "Incorrect parameter \'" + freeMbType + "\'.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+/////////////////////////////////////////////////////////////
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+#ifdef IA_PHASE_DEBUG
+IA_PHASE::IA_PHASE()
+ : phase(1),
+ flog(NULL)
+{
+gettimeofday(&phaseTime, NULL);
+}
+#else
+IA_PHASE::IA_PHASE()
+ : phase(1)
+{
+gettimeofday(&phaseTime, NULL);
+}
+#endif
+//-----------------------------------------------------------------------------
+IA_PHASE::~IA_PHASE()
+{
+#ifdef IA_PHASE_DEBUG
+flog = fopen(log.c_str(), "at");
+if (flog)
+ {
+ fprintf(flog, "IA %s D\n", login.c_str());
+ fclose(flog);
+ }
+#endif
+}
+//-----------------------------------------------------------------------------
+#ifdef IA_PHASE_DEBUG
+void IA_PHASE::SetLogFileName(const string & logFileName)
+{
+log = logFileName + ".ia.log";
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetUserLogin(const string & login)
+{
+IA_PHASE::login = login;
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::WritePhaseChange(int newPhase)
+{
+UTIME newPhaseTime;
+gettimeofday(&newPhaseTime, NULL);
+flog = fopen(log.c_str(), "at");
+if (flog)
+ {
+ string action = newPhase == phase ? "U" : "C";
+ double delta = newPhaseTime.GetSec() - phaseTime.GetSec();
+ delta += (newPhaseTime.GetUSec() - phaseTime.GetUSec()) * 1.0e-6;
+ fprintf(flog, "IA %s %s oldPhase = %d, newPhase = %d. dt = %.6f\n",
+ login.c_str(),
+ action.c_str(),
+ phase,
+ newPhase,
+ delta);
+ fclose(flog);
+ }
+}
+#endif
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase1()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(1);
+#endif
+phase = 1;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase2()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(2);
+#endif
+phase = 2;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase3()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(3);
+#endif
+phase = 3;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase4()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(4);
+#endif
+phase = 4;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+int IA_PHASE::GetPhase() const
+{
+return phase;
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::UpdateTime()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(phase);
+#endif
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+const UTIME & IA_PHASE::GetTime() const
+{
+return phaseTime;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+AUTH_IA::AUTH_IA()
+ : nonstop(false),
+ isRunningRun(false),
+ isRunningRunTimeouter(false),
+ users(NULL),
+ stgSettings(NULL),
+ listenSocket(-1),
+ enabledDirs(0xFFffFFff),
+ onDelUserNotifier(*this),
+ logger(STG::PluginLogger::get("auth_ia"))
+{
+InitContext("pr7Hhen", 7, &ctxS);
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+
+memset(&connSynAck6, 0, sizeof(CONN_SYN_ACK_6));
+memset(&connSynAck8, 0, sizeof(CONN_SYN_ACK_8));
+memset(&disconnSynAck6, 0, sizeof(DISCONN_SYN_ACK_6));
+memset(&disconnSynAck8, 0, sizeof(DISCONN_SYN_ACK_8));
+memset(&aliveSyn6, 0, sizeof(ALIVE_SYN_6));
+memset(&aliveSyn8, 0, sizeof(ALIVE_SYN_8));
+memset(&fin6, 0, sizeof(FIN_6));
+memset(&fin8, 0, sizeof(FIN_8));
+
+printfd(__FILE__, "sizeof(CONN_SYN_6) = %d %d\n", sizeof(CONN_SYN_6), Min8(sizeof(CONN_SYN_6)));
+printfd(__FILE__, "sizeof(CONN_SYN_8) = %d %d\n", sizeof(CONN_SYN_8), Min8(sizeof(CONN_SYN_8)));
+printfd(__FILE__, "sizeof(CONN_SYN_ACK_6) = %d %d\n", sizeof(CONN_SYN_ACK_6), Min8(sizeof(CONN_SYN_ACK_6)));
+printfd(__FILE__, "sizeof(CONN_SYN_ACK_8) = %d %d\n", sizeof(CONN_SYN_ACK_8), Min8(sizeof(CONN_SYN_ACK_8)));
+printfd(__FILE__, "sizeof(CONN_ACK_6) = %d %d\n", sizeof(CONN_ACK_6), Min8(sizeof(CONN_ACK_6)));
+printfd(__FILE__, "sizeof(ALIVE_SYN_6) = %d %d\n", sizeof(ALIVE_SYN_6), Min8(sizeof(ALIVE_SYN_6)));
+printfd(__FILE__, "sizeof(ALIVE_SYN_8) = %d %d\n", sizeof(ALIVE_SYN_8), Min8(sizeof(ALIVE_SYN_8)));
+printfd(__FILE__, "sizeof(ALIVE_ACK_6) = %d %d\n", sizeof(ALIVE_ACK_6), Min8(sizeof(ALIVE_ACK_6)));
+printfd(__FILE__, "sizeof(DISCONN_SYN_6) = %d %d\n", sizeof(DISCONN_SYN_6), Min8(sizeof(DISCONN_SYN_6)));
+printfd(__FILE__, "sizeof(DISCONN_SYN_ACK_6) = %d %d\n", sizeof(DISCONN_SYN_ACK_6), Min8(sizeof(DISCONN_SYN_ACK_6)));
+printfd(__FILE__, "sizeof(DISCONN_SYN_ACK_8) = %d %d\n", sizeof(DISCONN_SYN_ACK_8), Min8(sizeof(DISCONN_SYN_ACK_8)));
+printfd(__FILE__, "sizeof(DISCONN_ACK_6) = %d %d\n", sizeof(DISCONN_ACK_6), Min8(sizeof(DISCONN_ACK_6)));
+printfd(__FILE__, "sizeof(FIN_6) = %d %d\n", sizeof(FIN_6), Min8(sizeof(FIN_6)));
+printfd(__FILE__, "sizeof(FIN_8) = %d %d\n", sizeof(FIN_8), Min8(sizeof(FIN_8)));
+printfd(__FILE__, "sizeof(ERR) = %d %d\n", sizeof(ERR), Min8(sizeof(ERR)));
+printfd(__FILE__, "sizeof(INFO_6) = %d %d\n", sizeof(INFO_6), Min8(sizeof(INFO_6)));
+printfd(__FILE__, "sizeof(INFO_7) = %d %d\n", sizeof(INFO_7), Min8(sizeof(INFO_7)));
+printfd(__FILE__, "sizeof(INFO_8) = %d %d\n", sizeof(INFO_8), Min8(sizeof(INFO_8)));
+
+packetTypes["CONN_SYN"] = CONN_SYN_N;
+packetTypes["CONN_SYN_ACK"] = CONN_SYN_ACK_N;
+packetTypes["CONN_ACK"] = CONN_ACK_N;
+packetTypes["ALIVE_SYN"] = ALIVE_SYN_N;
+packetTypes["ALIVE_ACK"] = ALIVE_ACK_N;
+packetTypes["DISCONN_SYN"] = DISCONN_SYN_N;
+packetTypes["DISCONN_SYN_ACK"] = DISCONN_SYN_ACK_N;
+packetTypes["DISCONN_ACK"] = DISCONN_ACK_N;
+packetTypes["FIN"] = FIN_N;
+packetTypes["ERR"] = ERROR_N;
+}
+//-----------------------------------------------------------------------------
+AUTH_IA::~AUTH_IA()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Start()
+{
+users->AddNotifierUserDel(&onDelUserNotifier);
+nonstop = true;
+
+if (PrepareNet())
+ {
+ return -1;
+ }
+
+if (!isRunningRun)
+ {
+ if (pthread_create(&recvThread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ printfd(__FILE__, "Cannot create recv thread\n");
+ logger("Cannot create recv thread.");
+ return -1;
+ }
+ }
+
+if (!isRunningRunTimeouter)
+ {
+ if (pthread_create(&timeouterThread, NULL, RunTimeouter, this))
+ {
+ errorStr = "Cannot create thread.";
+ printfd(__FILE__, "Cannot create timeouter thread\n");
+ logger("Cannot create timeouter thread.");
+ return -1;
+ }
+ }
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Stop()
+{
+if (!IsRunning())
+ return 0;
+
+nonstop = false;
+
+std::for_each(
+ ip2user.begin(),
+ ip2user.end(),
+ UnauthorizeUser(this)
+ );
+
+if (isRunningRun)
+ {
+ //5 seconds to thread stops itself
+ for (int i = 0; i < 25 && isRunningRun; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ }
+
+FinalizeNet();
+
+if (isRunningRunTimeouter)
+ {
+ //5 seconds to thread stops itself
+ for (int i = 0; i < 25 && isRunningRunTimeouter; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ }
+
+users->DelNotifierUserDel(&onDelUserNotifier);
+
+if (isRunningRun || isRunningRunTimeouter)
+ return -1;
+
+printfd(__FILE__, "AUTH_IA::Stoped successfully.\n");
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * AUTH_IA::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+AUTH_IA * ia = static_cast<AUTH_IA *>(d);
+
+ia->isRunningRun = true;
+
+char buffer[512];
+
+time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+
+while (ia->nonstop)
+ {
+ ia->RecvData(buffer, sizeof(buffer));
+ if ((touchTime + MONITOR_TIME_DELAY_SEC <= stgTime) && ia->stgSettings->GetMonitoring())
+ {
+ touchTime = stgTime;
+ std::string monFile = ia->stgSettings->GetMonitorDir() + "/inetaccess_r";
+ TouchFile(monFile);
+ }
+ }
+
+ia->isRunningRun = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void * AUTH_IA::RunTimeouter(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+AUTH_IA * ia = static_cast<AUTH_IA *>(d);
+
+ia->isRunningRunTimeouter = true;
+
+int a = -1;
+std::string monFile = ia->stgSettings->GetMonitorDir() + "/inetaccess_t";
+while (ia->nonstop)
+ {
+ struct timespec ts = {0, 20000000};
+ nanosleep(&ts, NULL);
+ ia->Timeouter();
+ // TODO change counter to timer and MONITOR_TIME_DELAY_SEC
+ if (++a % (50 * 60) == 0 && ia->stgSettings->GetMonitoring())
+ {
+ TouchFile(monFile);
+ }
+ }
+
+ia->isRunningRunTimeouter = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::ParseSettings()
+{
+int ret = iaSettings.ParseSettings(settings);
+if (ret)
+ errorStr = iaSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Reload(const STG::ModuleSettings & ms)
+{
+AUTH_IA_SETTINGS newIaSettings;
+if (newIaSettings.ParseSettings(ms))
+ {
+ printfd(__FILE__, "AUTH_IA::Reload() - Failed to reload InetAccess.\n");
+ logger("AUTH_IA: Cannot reload InetAccess. Errors found.");
+ return -1;
+ }
+
+printfd(__FILE__, "AUTH_IA::Reload() - Reloaded InetAccess successfully.\n");
+logger("AUTH_IA: Reloaded InetAccess successfully.");
+iaSettings = newIaSettings;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::PrepareNet()
+{
+struct sockaddr_in listenAddr;
+
+listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (listenSocket < 0)
+ {
+ errorStr = "Cannot create socket.";
+ logger("Cannot create a socket: %s", strerror(errno));
+ return -1;
+ }
+
+listenAddr.sin_family = AF_INET;
+listenAddr.sin_port = htons(static_cast<uint16_t>(iaSettings.GetUserPort()));
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+if (bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0)
+ {
+ errorStr = "AUTH_IA: Bind failed.";
+ logger("Cannot bind the socket: %s", strerror(errno));
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::FinalizeNet()
+{
+close(listenSocket);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RecvData(char * buffer, int bufferSize)
+{
+if (!WaitPackets(listenSocket)) // Timeout
+ {
+ return 0;
+ }
+
+struct sockaddr_in outerAddr;
+socklen_t outerAddrLen(sizeof(outerAddr));
+ssize_t dataLen = recvfrom(listenSocket, buffer, bufferSize, 0, (struct sockaddr *)&outerAddr, &outerAddrLen);
+
+if (!dataLen) // EOF
+ {
+ return 0;
+ }
+
+if (dataLen <= 0) // Error
+ {
+ if (errno != EINTR)
+ {
+ printfd(__FILE__, "recvfrom res=%d, error: '%s'\n", dataLen, strerror(errno));
+ logger("recvfrom error: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+ }
+
+if (dataLen > 256)
+ return -1;
+
+uint32_t sip = outerAddr.sin_addr.s_addr;
+uint16_t sport = htons(outerAddr.sin_port);
+
+int protoVer;
+if (CheckHeader(buffer, sip, &protoVer))
+ return -1;
+
+char login[PASSWD_LEN]; //TODO why PASSWD_LEN ?
+memset(login, 0, PASSWD_LEN);
+
+DecryptString(login, buffer + 8, PASSWD_LEN, &ctxS);
+
+UserPtr user;
+if (users->FindByName(login, &user))
+ {
+ logger("User's connect failed: user '%s' not found. IP %s",
+ login,
+ inet_ntostring(sip).c_str());
+ printfd(__FILE__, "User '%s' NOT found!\n", login);
+ SendError(sip, sport, protoVer, IconvString("Неправильный логин.", "utf8", "koi8-ru"));
+ return -1;
+ }
+
+printfd(__FILE__, "User '%s' FOUND!\n", user->GetLogin().c_str());
+
+if (user->GetProperties().disabled.Get())
+ {
+ logger("Cannont authorize '%s', user is disabled.", login);
+ SendError(sip, sport, protoVer, IconvString("Учетная запись заблокирована.", "utf8", "koi8-ru"));
+ return 0;
+ }
+
+if (user->GetProperties().passive.Get())
+ {
+ logger("Cannont authorize '%s', user is passive.", login);
+ SendError(sip, sport, protoVer, IconvString("Учетная запись заморожена.", "utf8", "koi8-ru"));
+ return 0;
+ }
+
+if (!user->GetProperties().ips.Get().find(sip))
+ {
+ printfd(__FILE__, "User %s. IP address is incorrect. IP %s\n",
+ user->GetLogin().c_str(), inet_ntostring(sip).c_str());
+ logger("User %s. IP address is incorrect. IP %s",
+ user->GetLogin().c_str(), inet_ntostring(sip).c_str());
+ SendError(sip, sport, protoVer, IconvString("Пользователь не опознан. Проверьте IP-адрес.", "utf8", "koi8-ru"));
+ return 0;
+ }
+
+return PacketProcessor(buffer, dataLen, sip, sport, protoVer, user);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::CheckHeader(const char * buffer, uint32_t sip, int * protoVer)
+{
+if (strncmp(IA_ID, buffer, strlen(IA_ID)) != 0)
+ {
+ printfd(__FILE__, "update needed - IA_ID\n");
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. Header: invalid packed signature.", inet_ntostring(sip).c_str());
+ return -1;
+ }
+
+if (buffer[6] != 0) //proto[0] shoud be 0
+ {
+ printfd(__FILE__, "update needed - PROTO major: %d\n", buffer[6]);
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. Header: invalid protocol major version: %d.", inet_ntostring(sip).c_str(), buffer[6]);
+ return -1;
+ }
+
+if (buffer[7] < 6)
+ {
+ // need update
+ printfd(__FILE__, "update needed - PROTO minor: %d\n", buffer[7]);
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. Header: invalid protocol minor version: %d.", inet_ntostring(sip).c_str(), buffer[7]);
+ return -1;
+ }
+else
+ {
+ *protoVer = buffer[7];
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Timeouter()
+{
+STG_LOCKER lock(&mutex);
+
+std::map<uint32_t, IA_USER>::iterator it;
+it = ip2user.begin();
+
+while (it != ip2user.end())
+ {
+ uint32_t sip = it->first;
+
+ static UTIME currTime;
+ gettimeofday(&currTime, NULL);
+
+ if ((it->second.phase.GetPhase() == 2)
+ && (currTime - it->second.phase.GetTime()) > iaSettings.GetUserDelay())
+ {
+ if (iaSettings.LogProtocolErrors())
+ logger("User '%s'. Protocol version: %d. Phase 2: connect request timeout (%f > %d).", it->second.login.c_str(), it->second.protoVer, (currTime - it->second.phase.GetTime()).AsDouble(), iaSettings.GetUserDelay().GetSec());
+ it->second.phase.SetPhase1();
+ printfd(__FILE__, "Phase changed from 2 to 1. Reason: timeout\n");
+ ip2user.erase(it++);
+ continue;
+ }
+
+ if (it->second.phase.GetPhase() == 3)
+ {
+ if (!it->second.messagesToSend.empty())
+ {
+ if (it->second.protoVer == 6)
+ RealSendMessage6(*it->second.messagesToSend.begin(), sip, it->second);
+
+ if (it->second.protoVer == 7)
+ RealSendMessage7(*it->second.messagesToSend.begin(), sip, it->second);
+
+ if (it->second.protoVer == 8)
+ RealSendMessage8(*it->second.messagesToSend.begin(), sip, it->second);
+
+ it->second.messagesToSend.erase(it->second.messagesToSend.begin());
+ }
+
+ if((currTime - it->second.lastSendAlive) > iaSettings.GetUserDelay())
+ {
+ switch (it->second.protoVer)
+ {
+ case 6:
+ Send_ALIVE_SYN_6(&(it->second), sip);
+ break;
+ case 7:
+ Send_ALIVE_SYN_7(&(it->second), sip);
+ break;
+ case 8:
+ Send_ALIVE_SYN_8(&(it->second), sip);
+ break;
+ }
+
+ gettimeofday(&it->second.lastSendAlive, NULL);
+ }
+
+ if ((currTime - it->second.phase.GetTime()) > iaSettings.GetUserTimeout())
+ {
+ if (iaSettings.LogProtocolErrors())
+ logger("User '%s'. Protocol version: %d. Phase 3: alive timeout (%f > %d).", it->second.login.c_str(), it->second.protoVer, (currTime - it->second.phase.GetTime()).AsDouble(), iaSettings.GetUserTimeout().GetSec());
+ users->Unauthorize(it->second.user->GetLogin(), this);
+ ip2user.erase(it++);
+ continue;
+ }
+ }
+
+ if ((it->second.phase.GetPhase() == 4)
+ && ((currTime - it->second.phase.GetTime()) > iaSettings.GetUserDelay()))
+ {
+ if (iaSettings.LogProtocolErrors())
+ logger("User '%s'. Protocol version: %d. Phase 4: disconnect request timeout (%f > %d).", it->second.login.c_str(), it->second.protoVer, (currTime - it->second.phase.GetTime()).AsDouble(), iaSettings.GetUserDelay().GetSec());
+ it->second.phase.SetPhase3();
+ printfd(__FILE__, "Phase changed from 4 to 3. Reason: timeout\n");
+ }
+
+ ++it;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::PacketProcessor(void * buff, size_t dataLen, uint32_t sip, uint16_t sport, int protoVer, UserPtr user)
+{
+std::string login(user->GetLogin());
+const size_t offset = LOGIN_LEN + 2 + 6; // LOGIN_LEN + sizeOfMagic + sizeOfVer;
+
+STG_LOCKER lock(&mutex);
+std::map<uint32_t, IA_USER>::iterator it(ip2user.find(sip));
+
+if (it == ip2user.end())
+ {
+ UserPtr userPtr;
+ if (!users->FindByIPIdx(sip, &userPtr))
+ {
+ if (userPtr->GetID() != user->GetID())
+ {
+ printfd(__FILE__, "IP address already in use by user '%s'. IP %s, login: '%s'\n",
+ userPtr->GetLogin().c_str(),
+ inet_ntostring(sip).c_str(),
+ login.c_str());
+ logger("IP address is already in use by user '%s'. IP %s, login: '%s'",
+ userPtr->GetLogin().c_str(),
+ inet_ntostring(sip).c_str(),
+ login.c_str());
+ SendError(sip, sport, protoVer, IconvString("IP-адрес уже сипользуется.", "utf8", "koi8-ru"));
+ return 0;
+ }
+ }
+
+ printfd(__FILE__, "Add new user '%s' from ip %s\n",
+ login.c_str(), inet_ntostring(sip).c_str());
+ std::pair<std::map<uint32_t, IA_USER>::iterator, bool> res;
+ res = ip2user.insert(std::make_pair(sip, IA_USER(login, user, sport, protoVer)));
+ it = res.first;
+ #ifdef IA_PHASE_DEBUG
+ it->second.phase.SetLogFileName(stgSettings->GetLogFileName());
+ it->second.phase.SetUserLogin(login);
+ #endif
+ }
+else if (user->GetID() != it->second.user->GetID())
+ {
+ printfd(__FILE__, "IP address already in use by user '%s'. IP %s, login: '%s'\n",
+ it->second.user->GetLogin().c_str(),
+ inet_ntostring(sip).c_str(),
+ user->GetLogin().c_str());
+ logger("IP address is already in use by user '%s'. IP %s, login: '%s'",
+ it->second.user->GetLogin().c_str(),
+ inet_ntostring(sip).c_str(),
+ user->GetLogin().c_str());
+ SendError(sip, sport, protoVer, IconvString("IP-адрес уже используется.", "utf8", "koi8-ru"));
+ return 0;
+ }
+
+IA_USER * iaUser = &(it->second);
+
+if (iaUser->password != user->GetProperties().password.Get())
+ {
+ const std::string & password = user->GetProperties().password.Get();
+ InitContext(password.c_str(), password.length(), &iaUser->ctx);
+ iaUser->password = user->GetProperties().password.Get();
+ }
+
+DecryptString(static_cast<char *>(buff) + offset, static_cast<char *>(buff) + offset, (dataLen - offset), &iaUser->ctx);
+
+char packetName[IA_MAX_TYPE_LEN];
+strncpy(packetName, static_cast<char *>(buff) + offset + 4, IA_MAX_TYPE_LEN);
+packetName[IA_MAX_TYPE_LEN - 1] = 0;
+
+std::map<std::string, int>::iterator pi(packetTypes.find(packetName));
+if (pi == packetTypes.end())
+ {
+ SendError(sip, sport, protoVer, IconvString("Неправильный логин или пароль.", "utf8", "koi8-ru"));
+ printfd(__FILE__, "Login or password is wrong!\n");
+ logger("User's connect failed. User: '%s', ip %s. Wrong login or password",
+ login.c_str(),
+ inet_ntostring(sip).c_str());
+ ip2user.erase(it);
+ return 0;
+ }
+
+if (user->IsAuthorizedBy(this) && user->GetCurrIP() != sip)
+ {
+ printfd(__FILE__, "Login %s already in use from ip %s. IP %s\n",
+ login.c_str(), inet_ntostring(user->GetCurrIP()).c_str(),
+ inet_ntostring(sip).c_str());
+ logger("Login '%s' is already in use from ip %s. IP %s",
+ login.c_str(),
+ inet_ntostring(user->GetCurrIP()).c_str(),
+ inet_ntostring(sip).c_str());
+ SendError(sip, sport, protoVer, IconvString("Логин уже используется.", "utf8", "koi8-ru"));
+ ip2user.erase(it);
+ return 0;
+ }
+
+switch (pi->second)
+ {
+ case CONN_SYN_N:
+ switch (protoVer)
+ {
+ case 6:
+ if (Process_CONN_SYN_6(static_cast<CONN_SYN_6 *>(buff), &(it->second), sip))
+ return -1;
+ return Send_CONN_SYN_ACK_6(iaUser, sip);
+ case 7:
+ if (Process_CONN_SYN_7(static_cast<CONN_SYN_7 *>(buff), &(it->second), sip))
+ return -1;
+ return Send_CONN_SYN_ACK_7(iaUser, sip);
+ case 8:
+ if (Process_CONN_SYN_8(static_cast<CONN_SYN_8 *>(buff), &(it->second), sip))
+ return -1;
+ return Send_CONN_SYN_ACK_8(iaUser, sip);
+ }
+ break;
+
+ case CONN_ACK_N:
+ switch (protoVer)
+ {
+ case 6:
+ if (Process_CONN_ACK_6(static_cast<CONN_ACK_6 *>(buff), iaUser, sip))
+ return -1;
+ return Send_ALIVE_SYN_6(iaUser, sip);
+ case 7:
+ if (Process_CONN_ACK_7(static_cast<CONN_ACK_6 *>(buff), iaUser, sip))
+ return -1;
+ return Send_ALIVE_SYN_7(iaUser, sip);
+ case 8:
+ if (Process_CONN_ACK_8(static_cast<CONN_ACK_8 *>(buff), iaUser, sip))
+ return -1;
+ return Send_ALIVE_SYN_8(iaUser, sip);
+ }
+ break;
+
+ case ALIVE_ACK_N:
+ switch (protoVer)
+ {
+ case 6:
+ return Process_ALIVE_ACK_6(static_cast<ALIVE_ACK_6 *>(buff), iaUser, sip);
+ case 7:
+ return Process_ALIVE_ACK_7(static_cast<ALIVE_ACK_6 *>(buff), iaUser, sip);
+ case 8:
+ return Process_ALIVE_ACK_8(static_cast<ALIVE_ACK_8 *>(buff), iaUser, sip);
+ }
+ break;
+
+ case DISCONN_SYN_N:
+ switch (protoVer)
+ {
+ case 6:
+ if (Process_DISCONN_SYN_6(static_cast<DISCONN_SYN_6 *>(buff), iaUser, sip))
+ return -1;
+ return Send_DISCONN_SYN_ACK_6(iaUser, sip);
+ case 7:
+ if (Process_DISCONN_SYN_7(static_cast<DISCONN_SYN_6 *>(buff), iaUser, sip))
+ return -1;
+ return Send_DISCONN_SYN_ACK_7(iaUser, sip);
+ case 8:
+ if (Process_DISCONN_SYN_8(static_cast<DISCONN_SYN_8 *>(buff), iaUser, sip))
+ return -1;
+ return Send_DISCONN_SYN_ACK_8(iaUser, sip);
+ }
+ break;
+
+ case DISCONN_ACK_N:
+ switch (protoVer)
+ {
+ case 6:
+ if (Process_DISCONN_ACK_6(static_cast<DISCONN_ACK_6 *>(buff), iaUser, sip, it))
+ return -1;
+ return Send_FIN_6(iaUser, sip, it);
+ case 7:
+ if (Process_DISCONN_ACK_7(static_cast<DISCONN_ACK_6 *>(buff), iaUser, sip, it))
+ return -1;
+ return Send_FIN_7(iaUser, sip, it);
+ case 8:
+ if (Process_DISCONN_ACK_8(static_cast<DISCONN_ACK_8 *>(buff), iaUser, sip, it))
+ return -1;
+ return Send_FIN_8(iaUser, sip, it);
+ }
+ break;
+ }
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+void AUTH_IA::DelUser(UserPtr u)
+{
+
+uint32_t ip = u->GetCurrIP();
+
+if (!ip)
+ return;
+
+std::map<uint32_t, IA_USER>::iterator it;
+
+STG_LOCKER lock(&mutex);
+it = ip2user.find(ip);
+if (it == ip2user.end())
+ {
+ //Nothing to delete
+ printfd(__FILE__, "Nothing to delete\n");
+ return;
+ }
+
+if (it->second.user == u)
+ {
+ printfd(__FILE__, "User removed!\n");
+ users->Unauthorize(u->GetLogin(), this);
+ ip2user.erase(it);
+ }
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::SendError(uint32_t ip, uint16_t port, int protoVer, const std::string & text)
+{
+struct sockaddr_in sendAddr;
+ssize_t res;
+switch (protoVer)
+ {
+ case 6:
+ case 7:
+ ERR err;
+ memset(&err, 0, sizeof(ERR));
+
+ sendAddr.sin_family = AF_INET;
+ sendAddr.sin_port = htons(port);
+ sendAddr.sin_addr.s_addr = ip;
+
+ err.len = 1;
+ strncpy((char*)err.type, "ERR", 16);
+ strncpy((char*)err.text, text.c_str(), MAX_MSG_LEN);
+
+ #ifdef ARCH_BE
+ SwapBytes(err.len);
+ #endif
+
+ res = sendto(listenSocket, &err, sizeof(err), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+ printfd(__FILE__, "SendError %d bytes sent\n", res);
+ break;
+
+ case 8:
+ ERR_8 err8;
+ memset(&err8, 0, sizeof(ERR_8));
+
+ sendAddr.sin_family = AF_INET;
+ sendAddr.sin_port = htons(port);
+ sendAddr.sin_addr.s_addr = ip;
+
+ err8.len = 256;
+ strncpy((char*)err8.type, "ERR", 16);
+ strncpy((char*)err8.text, text.c_str(), MAX_MSG_LEN);
+
+ #ifdef ARCH_BE
+ SwapBytes(err8.len);
+ #endif
+
+ res = sendto(listenSocket, &err8, sizeof(err8), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+ printfd(__FILE__, "SendError_8 %d bytes sent\n", res);
+ break;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send(uint32_t ip, uint16_t port, const char * buffer, size_t len)
+{
+struct sockaddr_in sendAddr;
+
+sendAddr.sin_family = AF_INET;
+sendAddr.sin_port = htons(port);
+sendAddr.sin_addr.s_addr = ip;
+
+if (sendto(listenSocket, buffer, len, 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr)) == static_cast<ssize_t>(len))
+ return 0;
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::SendMessage(const STG::Message & msg, uint32_t ip) const
+{
+printfd(__FILE__, "SendMessage userIP=%s\n", inet_ntostring(ip).c_str());
+
+std::map<uint32_t, IA_USER>::iterator it;
+
+STG_LOCKER lock(&mutex);
+it = ip2user.find(ip);
+if (it == ip2user.end())
+ {
+ errorStr = "Unknown user.";
+ return -1;
+ }
+it->second.messagesToSend.push_back(msg);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RealSendMessage6(const STG::Message & msg, uint32_t ip, IA_USER & user)
+{
+printfd(__FILE__, "RealSendMessage 6 user=%s\n", user.login.c_str());
+
+INFO_6 info;
+memset(&info, 0, sizeof(INFO_6));
+
+info.len = 256;
+strncpy((char*)info.type, "INFO", 16);
+info.infoType = 'I';
+strncpy((char*)info.text, msg.text.c_str(), 235);
+info.text[234] = 0;
+
+size_t len = info.len;
+#ifdef ARCH_BE
+SwapBytes(info.len);
+#endif
+
+char buffer[256];
+memcpy(buffer, &info, sizeof(INFO_6));
+EncryptString(buffer, buffer, len, &user.ctx);
+return Send(ip, iaSettings.GetUserPort(), buffer, len);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RealSendMessage7(const STG::Message & msg, uint32_t ip, IA_USER & user)
+{
+printfd(__FILE__, "RealSendMessage 7 user=%s\n", user.login.c_str());
+
+INFO_7 info;
+memset(&info, 0, sizeof(INFO_7));
+
+info.len = 264;
+strncpy((char*)info.type, "INFO_7", 16);
+info.infoType = static_cast<int8_t>(msg.header.type);
+info.showTime = static_cast<int8_t>(msg.header.showTime);
+info.sendTime = msg.header.creationTime;
+
+size_t len = info.len;
+#ifdef ARCH_BE
+SwapBytes(info.len);
+SwapBytes(info.sendTime);
+#endif
+
+strncpy((char*)info.text, msg.text.c_str(), MAX_MSG_LEN - 1);
+info.text[MAX_MSG_LEN - 1] = 0;
+
+char buffer[300];
+memcpy(buffer, &info, sizeof(INFO_7));
+
+EncryptString(buffer, buffer, len, &user.ctx);
+return Send(ip, iaSettings.GetUserPort(), buffer, len);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RealSendMessage8(const STG::Message & msg, uint32_t ip, IA_USER & user)
+{
+printfd(__FILE__, "RealSendMessage 8 user=%s\n", user.login.c_str());
+
+INFO_8 info;
+memset(&info, 0, sizeof(INFO_8));
+
+info.len = 1056;
+strncpy((char*)info.type, "INFO_8", 16);
+info.infoType = static_cast<int8_t>(msg.header.type);
+info.showTime = static_cast<int8_t>(msg.header.showTime);
+info.sendTime = msg.header.creationTime;
+
+strncpy((char*)info.text, msg.text.c_str(), IA_MAX_MSG_LEN_8 - 1);
+info.text[IA_MAX_MSG_LEN_8 - 1] = 0;
+
+size_t len = info.len;
+#ifdef ARCH_BE
+SwapBytes(info.len);
+SwapBytes(info.sendTime);
+#endif
+
+char buffer[1500];
+memcpy(buffer, &info, sizeof(INFO_8));
+
+EncryptString(buffer, buffer, len, &user.ctx);
+return Send(ip, user.port, buffer, len);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_SYN_6(CONN_SYN_6 *, IA_USER * iaUser, uint32_t)
+{
+if (!(iaUser->phase.GetPhase() == 1 || iaUser->phase.GetPhase() == 3))
+ return -1;
+
+enabledDirs = 0xFFffFFff;
+
+iaUser->phase.SetPhase2();
+printfd(__FILE__, "Phase changed from %d to 2. Reason: CONN_SYN_6\n", iaUser->phase.GetPhase());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_SYN_7(CONN_SYN_7 * connSyn, IA_USER * iaUser, uint32_t sip)
+{
+return Process_CONN_SYN_6(connSyn, iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_SYN_8(CONN_SYN_8 * connSyn, IA_USER * iaUser, uint32_t sip)
+{
+#ifdef ARCH_BE
+SwapBytes(connSyn->dirs);
+#endif
+int ret = Process_CONN_SYN_6(reinterpret_cast<CONN_SYN_6 *>(connSyn), iaUser, sip);
+enabledDirs = connSyn->dirs;
+return ret;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_ACK_6(CONN_ACK_6 * connAck, IA_USER * iaUser, uint32_t sip)
+{
+#ifdef ARCH_BE
+SwapBytes(connAck->len);
+SwapBytes(connAck->rnd);
+#endif
+printfd( __FILE__, "CONN_ACK_6 %s\n", connAck->type);
+
+if ((iaUser->phase.GetPhase() == 2) && (connAck->rnd == iaUser->rnd + 1))
+ {
+ iaUser->phase.UpdateTime();
+
+ iaUser->lastSendAlive = iaUser->phase.GetTime();
+ if (users->Authorize(iaUser->login, sip, enabledDirs, this))
+ {
+ iaUser->phase.SetPhase3();
+ printfd(__FILE__, "Phase changed from 2 to 3. Reason: CONN_ACK_6\n");
+ return 0;
+ }
+ else
+ {
+ errorStr = iaUser->user->GetStrError();
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: phase 2, authorization error ('%s').", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, errorStr.c_str());
+ iaUser->phase.SetPhase1();
+ ip2user.erase(sip);
+ printfd(__FILE__, "Phase changed from 2 to 1. Reason: failed to authorize user\n");
+ return -1;
+ }
+ }
+printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d, expected: %d\n", iaUser->phase.GetPhase(), connAck->rnd, iaUser->rnd + 1);
+if (iaSettings.LogProtocolErrors())
+ {
+ if (iaUser->phase.GetPhase() != 2)
+ logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid phase, expected 2, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
+ if (connAck->rnd != iaUser->rnd + 1)
+ logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), connAck->rnd);
+ }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_ACK_7(CONN_ACK_7 * connAck, IA_USER * iaUser, uint32_t sip)
+{
+return Process_CONN_ACK_6(connAck, iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_ACK_8(CONN_ACK_8 * connAck, IA_USER * iaUser, uint32_t sip)
+{
+#ifdef ARCH_BE
+SwapBytes(connAck->len);
+SwapBytes(connAck->rnd);
+#endif
+printfd( __FILE__, "CONN_ACK_8 %s\n", connAck->type);
+
+if ((iaUser->phase.GetPhase() == 2) && (connAck->rnd == iaUser->rnd + 1))
+ {
+ iaUser->phase.UpdateTime();
+ iaUser->lastSendAlive = iaUser->phase.GetTime();
+ if (users->Authorize(iaUser->login, sip, enabledDirs, this))
+ {
+ iaUser->phase.SetPhase3();
+ printfd(__FILE__, "Phase changed from 2 to 3. Reason: CONN_ACK_8\n");
+ return 0;
+ }
+ else
+ {
+ errorStr = iaUser->user->GetStrError();
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: phase 2, authorization error ('%s').", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, errorStr.c_str());
+ iaUser->phase.SetPhase1();
+ ip2user.erase(sip);
+ printfd(__FILE__, "Phase changed from 2 to 1. Reason: failed to authorize user\n");
+ return -1;
+ }
+ }
+printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d, expected: %d\n", iaUser->phase.GetPhase(), connAck->rnd, iaUser->rnd + 1);
+if (iaSettings.LogProtocolErrors())
+ {
+ if (iaUser->phase.GetPhase() != 2)
+ logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid phase, expected 2, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
+ if (connAck->rnd != iaUser->rnd + 1)
+ logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), connAck->rnd);
+ }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_ALIVE_ACK_6(ALIVE_ACK_6 * aliveAck, IA_USER * iaUser, uint32_t)
+{
+#ifdef ARCH_BE
+SwapBytes(aliveAck->len);
+SwapBytes(aliveAck->rnd);
+#endif
+printfd(__FILE__, "ALIVE_ACK_6\n");
+if ((iaUser->phase.GetPhase() == 3) && (aliveAck->rnd == iaUser->rnd + 1))
+ {
+ iaUser->phase.UpdateTime();
+ #ifdef IA_DEBUG
+ iaUser->aliveSent = false;
+ #endif
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_ALIVE_ACK_7(ALIVE_ACK_7 * aliveAck, IA_USER * iaUser, uint32_t sip)
+{
+return Process_ALIVE_ACK_6(aliveAck, iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_ALIVE_ACK_8(ALIVE_ACK_8 * aliveAck, IA_USER * iaUser, uint32_t)
+{
+#ifdef ARCH_BE
+SwapBytes(aliveAck->len);
+SwapBytes(aliveAck->rnd);
+#endif
+printfd(__FILE__, "ALIVE_ACK_8\n");
+if ((iaUser->phase.GetPhase() == 3) && (aliveAck->rnd == iaUser->rnd + 1))
+ {
+ iaUser->phase.UpdateTime();
+ #ifdef IA_DEBUG
+ iaUser->aliveSent = false;
+ #endif
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_SYN_6(DISCONN_SYN_6 *, IA_USER * iaUser, uint32_t sip)
+{
+printfd(__FILE__, "DISCONN_SYN_6\n");
+if (iaUser->phase.GetPhase() != 3)
+ {
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_SYN: invalid phase, expected 3, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
+ printfd(__FILE__, "Invalid phase. Expected 3, actual %d\n", iaUser->phase.GetPhase());
+ errorStr = "Incorrect request DISCONN_SYN";
+ return -1;
+ }
+
+iaUser->phase.SetPhase4();
+printfd(__FILE__, "Phase changed from 3 to 4. Reason: DISCONN_SYN_6\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_SYN_7(DISCONN_SYN_7 * disconnSyn, IA_USER * iaUser, uint32_t sip)
+{
+return Process_DISCONN_SYN_6(disconnSyn, iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_SYN_8(DISCONN_SYN_8 *, IA_USER * iaUser, uint32_t sip)
+{
+if (iaUser->phase.GetPhase() != 3)
+ {
+ if (iaSettings.LogProtocolErrors())
+ logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_SYN: invalid phase, expected 3, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
+ errorStr = "Incorrect request DISCONN_SYN";
+ printfd(__FILE__, "Invalid phase. Expected 3, actual %d\n", iaUser->phase.GetPhase());
+ return -1;
+ }
+
+iaUser->phase.SetPhase4();
+printfd(__FILE__, "Phase changed from 3 to 4. Reason: DISCONN_SYN_6\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_ACK_6(DISCONN_ACK_6 * disconnAck,
+ IA_USER * iaUser,
+ uint32_t sip,
+ std::map<uint32_t, IA_USER>::iterator)
+{
+#ifdef ARCH_BE
+SwapBytes(disconnAck->len);
+SwapBytes(disconnAck->rnd);
+#endif
+printfd(__FILE__, "DISCONN_ACK_6\n");
+if (!((iaUser->phase.GetPhase() == 4) && (disconnAck->rnd == iaUser->rnd + 1)))
+ {
+ if (iaSettings.LogProtocolErrors())
+ {
+ if (iaUser->phase.GetPhase() != 4)
+ logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid phase, expected 4, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
+ if (disconnAck->rnd != iaUser->rnd + 1)
+ logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), disconnAck->rnd);
+ }
+ printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), disconnAck->rnd);
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_ACK_7(DISCONN_ACK_7 * disconnAck, IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
+{
+return Process_DISCONN_ACK_6(disconnAck, iaUser, sip, it);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_ACK_8(DISCONN_ACK_8 * disconnAck, IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator)
+{
+#ifdef ARCH_BE
+SwapBytes(disconnAck->len);
+SwapBytes(disconnAck->rnd);
+#endif
+printfd(__FILE__, "DISCONN_ACK_8\n");
+if (!((iaUser->phase.GetPhase() == 4) && (disconnAck->rnd == iaUser->rnd + 1)))
+ {
+ if (iaSettings.LogProtocolErrors())
+ {
+ if (iaUser->phase.GetPhase() != 4)
+ logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid phase, expected 4, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
+ if (disconnAck->rnd != iaUser->rnd + 1)
+ logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), disconnAck->rnd);
+ }
+ printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), disconnAck->rnd);
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_CONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip)
+{
+//+++ Fill static data in connSynAck +++
+// TODO Move this code. It must be executed only once
+connSynAck6.len = Min8(sizeof(CONN_SYN_ACK_6));
+strcpy((char*)connSynAck6.type, "CONN_SYN_ACK");
+for (int j = 0; j < DIR_NUM; j++)
+ {
+ strncpy((char*)connSynAck6.dirName[j],
+ stgSettings->GetDirName(j).c_str(),
+ sizeof(string16));
+
+ connSynAck6.dirName[j][sizeof(string16) - 1] = 0;
+ }
+//--- Fill static data in connSynAck ---
+
+iaUser->rnd = static_cast<uint32_t>(random());
+connSynAck6.rnd = iaUser->rnd;
+
+printfd(__FILE__, "Sending CONN_SYN_ACK with control number %d.\n", iaUser->rnd);
+
+connSynAck6.userTimeOut = iaSettings.GetUserTimeout().GetSec();
+connSynAck6.aliveDelay = iaSettings.GetUserDelay().GetSec();
+
+#ifdef ARCH_BE
+SwapBytes(connSynAck6.len);
+SwapBytes(connSynAck6.rnd);
+SwapBytes(connSynAck6.userTimeOut);
+SwapBytes(connSynAck6.aliveDelay);
+#endif
+
+EncryptString((char*)&connSynAck6, (char*)&connSynAck6, Min8(sizeof(CONN_SYN_ACK_6)), &iaUser->ctx);
+return Send(sip, iaSettings.GetUserPort(), (char*)&connSynAck6, Min8(sizeof(CONN_SYN_ACK_6)));;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_CONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip)
+{
+return Send_CONN_SYN_ACK_6(iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_CONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip)
+{
+strcpy((char*)connSynAck8.hdr.magic, IA_ID);
+connSynAck8.hdr.protoVer[0] = 0;
+connSynAck8.hdr.protoVer[1] = 8;
+
+//+++ Fill static data in connSynAck +++
+// TODO Move this code. It must be executed only once
+connSynAck8.len = Min8(sizeof(CONN_SYN_ACK_8));
+strcpy((char*)connSynAck8.type, "CONN_SYN_ACK");
+for (int j = 0; j < DIR_NUM; j++)
+ {
+ strncpy((char*)connSynAck8.dirName[j],
+ stgSettings->GetDirName(j).c_str(),
+ sizeof(string16));
+
+ connSynAck8.dirName[j][sizeof(string16) - 1] = 0;
+ }
+//--- Fill static data in connSynAck ---
+
+iaUser->rnd = static_cast<uint32_t>(random());
+connSynAck8.rnd = iaUser->rnd;
+
+printfd(__FILE__, "Sending CONN_SYN_ACK with control number %d.\n", iaUser->rnd);
+
+connSynAck8.userTimeOut = iaSettings.GetUserTimeout().GetSec();
+connSynAck8.aliveDelay = iaSettings.GetUserDelay().GetSec();
+
+#ifdef ARCH_BE
+SwapBytes(connSynAck8.len);
+SwapBytes(connSynAck8.rnd);
+SwapBytes(connSynAck8.userTimeOut);
+SwapBytes(connSynAck8.aliveDelay);
+#endif
+
+EncryptString((char*)&connSynAck8, (char*)&connSynAck8, Min8(sizeof(CONN_SYN_ACK_8)), &iaUser->ctx);
+return Send(sip, iaUser->port, (char*)&connSynAck8, Min8(sizeof(CONN_SYN_ACK_8)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_ALIVE_SYN_6(IA_USER * iaUser, uint32_t sip)
+{
+aliveSyn6.len = Min8(sizeof(ALIVE_SYN_6));
+aliveSyn6.rnd = iaUser->rnd = static_cast<uint32_t>(random());
+
+strcpy((char*)aliveSyn6.type, "ALIVE_SYN");
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ aliveSyn6.md[i] = iaUser->user->GetProperties().down.Get()[i];
+ aliveSyn6.mu[i] = iaUser->user->GetProperties().up.Get()[i];
+
+ aliveSyn6.sd[i] = iaUser->user->GetSessionDownload()[i];
+ aliveSyn6.su[i] = iaUser->user->GetSessionUpload()[i];
+ }
+
+//TODO
+int dn = iaSettings.GetFreeMbShowType();
+const auto tf = iaUser->user->GetTariff();
+
+if (dn < DIR_NUM)
+ {
+ double p = tf->GetPriceWithTraffType(aliveSyn6.mu[dn],
+ aliveSyn6.md[dn],
+ dn,
+ stgTime);
+ p *= 1024 * 1024;
+ if (std::fabs(p) < 1.0e-3)
+ {
+ snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "---");
+ }
+ else
+ {
+ double fmb = iaUser->user->GetProperties().freeMb;
+ fmb = fmb < 0 ? 0 : fmb;
+ snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "%.3f", fmb / p);
+ }
+ }
+else
+ {
+ if (freeMbNone == iaSettings.GetFreeMbShowType())
+ {
+ aliveSyn6.freeMb[0] = 0;
+ }
+ else
+ {
+ double fmb = iaUser->user->GetProperties().freeMb;
+ fmb = fmb < 0 ? 0 : fmb;
+ snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "C%.3f", fmb);
+ }
+ }
+
+#ifdef IA_DEBUG
+if (iaUser->aliveSent)
+ {
+ printfd(__FILE__, "========= ALIVE_ACK_6(7) TIMEOUT !!! %s =========\n", iaUser->login.c_str());
+ }
+iaUser->aliveSent = true;
+#endif
+
+aliveSyn6.cash =(int64_t) (iaUser->user->GetProperties().cash.Get() * 1000.0);
+if (!stgSettings->GetShowFeeInCash())
+ aliveSyn6.cash -= (int64_t)(tf->GetFee() * 1000.0);
+
+#ifdef ARCH_BE
+SwapBytes(aliveSyn6.len);
+SwapBytes(aliveSyn6.rnd);
+SwapBytes(aliveSyn6.cash);
+for (int i = 0; i < DIR_NUM; ++i)
+ {
+ SwapBytes(aliveSyn6.mu[i]);
+ SwapBytes(aliveSyn6.md[i]);
+ SwapBytes(aliveSyn6.su[i]);
+ SwapBytes(aliveSyn6.sd[i]);
+ }
+#endif
+
+EncryptString((char*)&aliveSyn6, (char*)&aliveSyn6, Min8(sizeof(aliveSyn6)), &iaUser->ctx);
+return Send(sip, iaSettings.GetUserPort(), (char*)&aliveSyn6, Min8(sizeof(aliveSyn6)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_ALIVE_SYN_7(IA_USER * iaUser, uint32_t sip)
+{
+return Send_ALIVE_SYN_6(iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_ALIVE_SYN_8(IA_USER * iaUser, uint32_t sip)
+{
+strcpy((char*)aliveSyn8.hdr.magic, IA_ID);
+aliveSyn8.hdr.protoVer[0] = 0;
+aliveSyn8.hdr.protoVer[1] = 8;
+
+aliveSyn8.len = Min8(sizeof(ALIVE_SYN_8));
+aliveSyn8.rnd = iaUser->rnd = static_cast<uint32_t>(random());
+
+strcpy((char*)aliveSyn8.type, "ALIVE_SYN");
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ aliveSyn8.md[i] = iaUser->user->GetProperties().down.Get()[i];
+ aliveSyn8.mu[i] = iaUser->user->GetProperties().up.Get()[i];
+
+ aliveSyn8.sd[i] = iaUser->user->GetSessionDownload()[i];
+ aliveSyn8.su[i] = iaUser->user->GetSessionUpload()[i];
+ }
+
+//TODO
+int dn = iaSettings.GetFreeMbShowType();
+
+if (dn < DIR_NUM)
+ {
+ const auto tf = iaUser->user->GetTariff();
+ double p = tf->GetPriceWithTraffType(aliveSyn8.mu[dn],
+ aliveSyn8.md[dn],
+ dn,
+ stgTime);
+ p *= 1024 * 1024;
+ if (std::fabs(p) < 1.0e-3)
+ {
+ snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "---");
+ }
+ else
+ {
+ double fmb = iaUser->user->GetProperties().freeMb;
+ fmb = fmb < 0 ? 0 : fmb;
+ snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "%.3f", fmb / p);
+ }
+ }
+else
+ {
+ if (freeMbNone == iaSettings.GetFreeMbShowType())
+ {
+ aliveSyn8.freeMb[0] = 0;
+ }
+ else
+ {
+ double fmb = iaUser->user->GetProperties().freeMb;
+ fmb = fmb < 0 ? 0 : fmb;
+ snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "C%.3f", fmb);
+ }
+ }
+
+#ifdef IA_DEBUG
+if (iaUser->aliveSent)
+ {
+ printfd(__FILE__, "========= ALIVE_ACK_8 TIMEOUT !!! =========\n");
+ }
+iaUser->aliveSent = true;
+#endif
+
+const auto tf = iaUser->user->GetTariff();
+
+aliveSyn8.cash =(int64_t) (iaUser->user->GetProperties().cash.Get() * 1000.0);
+if (!stgSettings->GetShowFeeInCash())
+ aliveSyn8.cash -= (int64_t)(tf->GetFee() * 1000.0);
+
+#ifdef ARCH_BE
+SwapBytes(aliveSyn8.len);
+SwapBytes(aliveSyn8.rnd);
+SwapBytes(aliveSyn8.cash);
+SwapBytes(aliveSyn8.status);
+for (int i = 0; i < DIR_NUM; ++i)
+ {
+ SwapBytes(aliveSyn8.mu[i]);
+ SwapBytes(aliveSyn8.md[i]);
+ SwapBytes(aliveSyn8.su[i]);
+ SwapBytes(aliveSyn8.sd[i]);
+ }
+#endif
+
+EncryptString((char*)&aliveSyn8, (char*)&aliveSyn8, Min8(sizeof(aliveSyn8)), &iaUser->ctx);
+return Send(sip, iaUser->port, (char*)&aliveSyn8, Min8(sizeof(aliveSyn8)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_DISCONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip)
+{
+disconnSynAck6.len = Min8(sizeof(DISCONN_SYN_ACK_6));
+strcpy((char*)disconnSynAck6.type, "DISCONN_SYN_ACK");
+disconnSynAck6.rnd = iaUser->rnd = static_cast<uint32_t>(random());
+
+#ifdef ARCH_BE
+SwapBytes(disconnSynAck6.len);
+SwapBytes(disconnSynAck6.rnd);
+#endif
+
+EncryptString((char*)&disconnSynAck6, (char*)&disconnSynAck6, Min8(sizeof(disconnSynAck6)), &iaUser->ctx);
+return Send(sip, iaSettings.GetUserPort(), (char*)&disconnSynAck6, Min8(sizeof(disconnSynAck6)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_DISCONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip)
+{
+return Send_DISCONN_SYN_ACK_6(iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_DISCONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip)
+{
+strcpy((char*)disconnSynAck8.hdr.magic, IA_ID);
+disconnSynAck8.hdr.protoVer[0] = 0;
+disconnSynAck8.hdr.protoVer[1] = 8;
+
+disconnSynAck8.len = Min8(sizeof(DISCONN_SYN_ACK_8));
+strcpy((char*)disconnSynAck8.type, "DISCONN_SYN_ACK");
+disconnSynAck8.rnd = iaUser->rnd = static_cast<uint32_t>(random());
+
+#ifdef ARCH_BE
+SwapBytes(disconnSynAck8.len);
+SwapBytes(disconnSynAck8.rnd);
+#endif
+
+EncryptString((char*)&disconnSynAck8, (char*)&disconnSynAck8, Min8(sizeof(disconnSynAck8)), &iaUser->ctx);
+return Send(sip, iaUser->port, (char*)&disconnSynAck8, Min8(sizeof(disconnSynAck8)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_FIN_6(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
+{
+fin6.len = Min8(sizeof(FIN_6));
+strcpy((char*)fin6.type, "FIN");
+strcpy((char*)fin6.ok, "OK");
+
+#ifdef ARCH_BE
+SwapBytes(fin6.len);
+#endif
+
+EncryptString((char*)&fin6, (char*)&fin6, Min8(sizeof(fin6)), &iaUser->ctx);
+
+users->Unauthorize(iaUser->login, this);
+
+int res = Send(sip, iaSettings.GetUserPort(), (char*)&fin6, Min8(sizeof(fin6)));
+
+ip2user.erase(it);
+
+return res;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_FIN_7(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
+{
+return Send_FIN_6(iaUser, sip, it);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_FIN_8(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
+{
+strcpy((char*)fin8.hdr.magic, IA_ID);
+fin8.hdr.protoVer[0] = 0;
+fin8.hdr.protoVer[1] = 8;
+
+fin8.len = Min8(sizeof(FIN_8));
+strcpy((char*)fin8.type, "FIN");
+strcpy((char*)fin8.ok, "OK");
+
+#ifdef ARCH_BE
+SwapBytes(fin8.len);
+#endif
+
+EncryptString((char*)&fin8, (char*)&fin8, Min8(sizeof(fin8)), &iaUser->ctx);
+
+users->Unauthorize(iaUser->login, this);
+
+int res = Send(sip, iaUser->port, (char*)&fin8, Min8(sizeof(fin8)));
+
+ip2user.erase(it);
+
+return res;
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+#pragma once
+
+#include "stg/auth.h"
+#include "stg/store.h"
+#include "stg/module_settings.h"
+#include "stg/notifer.h"
+#include "stg/user_ips.h"
+#include "stg/user.h"
+#include "stg/users.h"
+#include "stg/user_property.h"
+#include "stg/ia_packets.h"
+#include "stg/blowfish.h"
+#include "stg/logger.h"
+#include "stg/utime.h"
+#include "stg/logger.h"
+
+#include <cstring>
+#include <ctime>
+#include <cstdint>
+#include <string>
+#include <map>
+#include <list>
+#include <functional>
+#include <utility>
+
+#include <sys/time.h>
+#include <pthread.h>
+
+//#define IA_DEBUG (1)
+//#define IA_PHASE_DEBUG (1)
+
+class AUTH_IA;
+//-----------------------------------------------------------------------------
+enum FREEMB {
+ freeMb0 = 0,
+ freeMb1,
+ freeMb2,
+ freeMb3,
+ freeMb4,
+ freeMb5,
+ freeMb6,
+ freeMb7,
+ freeMb8,
+ freeMb9,
+ freeMb10,
+ freeMb11,
+ freeMb12,
+ freeMb13,
+ freeMb14,
+ freeMb15,
+ freeMb16,
+ freeMb17,
+ freeMb18,
+ freeMb19,
+ freeMbCash = 100,
+ freeMbNone = 101
+};
+//-----------------------------------------------------------------------------
+class IA_PHASE {
+public:
+ IA_PHASE();
+ ~IA_PHASE();
+
+ void SetPhase1();
+ void SetPhase2();
+ void SetPhase3();
+ void SetPhase4();
+ int GetPhase() const;
+
+ void UpdateTime();
+ const UTIME & GetTime() const;
+
+ #ifdef IA_PHASE_DEBUG
+ void SetUserLogin(const std::string & login);
+ void SetLogFileName(const std::string & logFileName);
+ #endif
+
+private:
+ int phase;
+ UTIME phaseTime;
+
+ #ifdef IA_PHASE_DEBUG
+ void WritePhaseChange(int newPhase);
+ std::string log;
+ std::string login;
+ FILE * flog;
+ #endif
+};
+//-----------------------------------------------------------------------------
+struct IA_USER {
+ using ConstUserPtr = const STG::User*;
+ IA_USER()
+ : user(NULL),
+ lastSendAlive(0),
+ rnd(static_cast<uint32_t>(random())),
+ port(0),
+ protoVer(0),
+ password("NO PASSWORD")
+ {
+ unsigned char keyL[PASSWD_LEN];
+ memset(keyL, 0, PASSWD_LEN);
+ strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+ Blowfish_Init(&ctx, keyL, PASSWD_LEN);
+
+ #ifdef IA_DEBUG
+ aliveSent = false;
+ #endif
+ }
+
+ IA_USER(const IA_USER & u)
+ : login(u.login),
+ user(u.user),
+ phase(u.phase),
+ lastSendAlive(u.lastSendAlive),
+ rnd(u.rnd),
+ port(u.port),
+ ctx(),
+ messagesToSend(u.messagesToSend),
+ protoVer(u.protoVer),
+ password(u.password)
+ {
+ #ifdef IA_DEBUG
+ aliveSent = u.aliveSent;
+ #endif
+ memcpy(&ctx, &u.ctx, sizeof(BLOWFISH_CTX));
+ }
+
+ IA_USER(const std::string & l,
+ ConstUserPtr u,
+ uint16_t p,
+ int ver)
+ : login(l),
+ user(u),
+ lastSendAlive(0),
+ rnd(static_cast<uint32_t>(random())),
+ port(p),
+ messagesToSend(),
+ protoVer(ver),
+ password(user->GetProperties().password.Get())
+ {
+ unsigned char keyL[PASSWD_LEN];
+ memset(keyL, 0, PASSWD_LEN);
+ strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+ Blowfish_Init(&ctx, keyL, PASSWD_LEN);
+
+ #ifdef IA_DEBUG
+ aliveSent = false;
+ #endif
+ }
+
+ std::string login;
+ ConstUserPtr user;
+ IA_PHASE phase;
+ UTIME lastSendAlive;
+ uint32_t rnd;
+ uint16_t port;
+ BLOWFISH_CTX ctx;
+ std::vector<STG::Message> messagesToSend;
+ int protoVer;
+ std::string password;
+ #ifdef IA_DEBUG
+ bool aliveSent;
+ #endif
+
+private:
+ IA_USER & operator=(const IA_USER & rvalue);
+};
+//-----------------------------------------------------------------------------
+class AUTH_IA_SETTINGS {
+public:
+ AUTH_IA_SETTINGS();
+ virtual ~AUTH_IA_SETTINGS() {}
+ const std::string & GetStrError() const { return errorStr; }
+ int ParseSettings(const STG::ModuleSettings & s);
+ UTIME GetUserDelay() const { return UTIME(userDelay); }
+ UTIME GetUserTimeout() const { return UTIME(userTimeout); }
+ uint16_t GetUserPort() const { return port; }
+ FREEMB GetFreeMbShowType() const { return freeMbShowType; }
+ bool LogProtocolErrors() const { return logProtocolErrors; }
+
+private:
+ int userDelay;
+ int userTimeout;
+ uint16_t port;
+ std::string errorStr;
+ FREEMB freeMbShowType;
+ bool logProtocolErrors;
+};
+//-----------------------------------------------------------------------------
+class AUTH_IA;
+using UserPtr = STG::User*;
+//-----------------------------------------------------------------------------
+class DEL_USER_NOTIFIER: public STG::NotifierBase<UserPtr> {
+public:
+ explicit DEL_USER_NOTIFIER(AUTH_IA & a) : auth(a) {}
+ virtual ~DEL_USER_NOTIFIER() {}
+
+ void Notify(const UserPtr & user);
+private:
+ DEL_USER_NOTIFIER(const DEL_USER_NOTIFIER & rvalue);
+ DEL_USER_NOTIFIER & operator=(const DEL_USER_NOTIFIER & rvalue);
+
+ AUTH_IA & auth;
+};
+//-----------------------------------------------------------------------------
+class AUTH_IA : public STG::Auth {
+friend class DEL_USER_NOTIFIER;
+public:
+ AUTH_IA();
+ ~AUTH_IA() override;
+
+ void SetUsers(STG::Users * u) override { users = u; }
+ void SetStgSettings(const STG::Settings * s) override { stgSettings = s; }
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & ms) override;
+ bool IsRunning() override { return isRunningRunTimeouter || isRunningRun; }
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override { return "InetAccess authorization plugin v.1.4"; }
+ uint16_t GetStartPosition() const override { return 30; }
+ uint16_t GetStopPosition() const override { return 30; }
+
+ int SendMessage(const STG::Message & msg, uint32_t ip) const override;
+
+private:
+ AUTH_IA(const AUTH_IA & rvalue);
+ AUTH_IA & operator=(const AUTH_IA & rvalue);
+
+ static void * Run(void *);
+ static void * RunTimeouter(void * d);
+ int PrepareNet();
+ int FinalizeNet();
+ void DelUser(UserPtr u);
+ int RecvData(char * buffer, int bufferSize);
+ int CheckHeader(const char * buffer, uint32_t sip, int * protoVer);
+ int PacketProcessor(void * buff, size_t dataLen, uint32_t sip, uint16_t sport, int protoVer, UserPtr user);
+
+ int Process_CONN_SYN_6(CONN_SYN_6 * connSyn, IA_USER * iaUser, uint32_t sip);
+ int Process_CONN_SYN_7(CONN_SYN_7 * connSyn, IA_USER * iaUser, uint32_t sip);
+ int Process_CONN_SYN_8(CONN_SYN_8 * connSyn, IA_USER * iaUser, uint32_t sip);
+
+ int Process_CONN_ACK_6(CONN_ACK_6 * connAck, IA_USER * iaUser, uint32_t sip);
+ int Process_CONN_ACK_7(CONN_ACK_7 * connAck, IA_USER * iaUser, uint32_t sip);
+ int Process_CONN_ACK_8(CONN_ACK_8 * connAck, IA_USER * iaUser, uint32_t sip);
+
+ int Process_ALIVE_ACK_6(ALIVE_ACK_6 * aliveAck, IA_USER * iaUser, uint32_t sip);
+ int Process_ALIVE_ACK_7(ALIVE_ACK_7 * aliveAck, IA_USER * iaUser, uint32_t sip);
+ int Process_ALIVE_ACK_8(ALIVE_ACK_8 * aliveAck, IA_USER * iaUser, uint32_t sip);
+
+ int Process_DISCONN_SYN_6(DISCONN_SYN_6 * disconnSyn, IA_USER * iaUser, uint32_t sip);
+ int Process_DISCONN_SYN_7(DISCONN_SYN_7 * disconnSyn, IA_USER * iaUser, uint32_t sip);
+ int Process_DISCONN_SYN_8(DISCONN_SYN_8 * disconnSyn, IA_USER * iaUser, uint32_t sip);
+
+ int Process_DISCONN_ACK_6(DISCONN_ACK_6 * disconnSyn,
+ IA_USER * iaUser,
+ uint32_t sip,
+ std::map<uint32_t, IA_USER>::iterator it);
+ int Process_DISCONN_ACK_7(DISCONN_ACK_7 * disconnSyn,
+ IA_USER * iaUser,
+ uint32_t sip,
+ std::map<uint32_t, IA_USER>::iterator it);
+ int Process_DISCONN_ACK_8(DISCONN_ACK_8 * disconnSyn,
+ IA_USER * iaUser,
+ uint32_t sip,
+ std::map<uint32_t, IA_USER>::iterator it);
+
+ int Send_CONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip);
+ int Send_CONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip);
+ int Send_CONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip);
+
+ int Send_ALIVE_SYN_6(IA_USER * iaUser, uint32_t sip);
+ int Send_ALIVE_SYN_7(IA_USER * iaUser, uint32_t sip);
+ int Send_ALIVE_SYN_8(IA_USER * iaUser, uint32_t sip);
+
+ int Send_DISCONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip);
+ int Send_DISCONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip);
+ int Send_DISCONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip);
+
+ int Send_FIN_6(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it);
+ int Send_FIN_7(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it);
+ int Send_FIN_8(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it);
+
+ int Timeouter();
+
+ int SendError(uint32_t ip, uint16_t port, int protoVer, const std::string & text);
+ int Send(uint32_t ip, uint16_t port, const char * buffer, size_t len);
+ int RealSendMessage6(const STG::Message & msg, uint32_t ip, IA_USER & user);
+ int RealSendMessage7(const STG::Message & msg, uint32_t ip, IA_USER & user);
+ int RealSendMessage8(const STG::Message & msg, uint32_t ip, IA_USER & user);
+
+ BLOWFISH_CTX ctxS; //for loginS
+
+ mutable std::string errorStr;
+ AUTH_IA_SETTINGS iaSettings;
+ STG::ModuleSettings settings;
+
+ bool nonstop;
+
+ bool isRunningRun;
+ bool isRunningRunTimeouter;
+
+ STG::Users * users;
+ const STG::Settings * stgSettings;
+
+ mutable std::map<uint32_t, IA_USER> ip2user;
+
+ pthread_t recvThread;
+ pthread_t timeouterThread;
+ mutable pthread_mutex_t mutex;
+
+ int listenSocket;
+
+ CONN_SYN_ACK_6 connSynAck6;
+ CONN_SYN_ACK_8 connSynAck8;
+
+ DISCONN_SYN_ACK_6 disconnSynAck6;
+ DISCONN_SYN_ACK_8 disconnSynAck8;
+
+ ALIVE_SYN_6 aliveSyn6;
+ ALIVE_SYN_8 aliveSyn8;
+ FIN_6 fin6;
+ FIN_8 fin8;
+
+ std::map<std::string, int> packetTypes;
+
+ uint32_t enabledDirs;
+
+ DEL_USER_NOTIFIER onDelUserNotifier;
+
+ STG::PluginLogger logger;
+
+ friend class UnauthorizeUser;
+};
+//-----------------------------------------------------------------------------
+class UnauthorizeUser : std::unary_function<const std::pair<uint32_t, IA_USER> &, void> {
+ public:
+ explicit UnauthorizeUser(AUTH_IA * a) : auth(a) {}
+ UnauthorizeUser(const UnauthorizeUser & rvalue) : auth(rvalue.auth) {}
+ void operator()(const std::pair<uint32_t, IA_USER> & p)
+ {
+ auth->users->Unauthorize(p.second.user->GetLogin(), auth);
+ }
+ private:
+ UnauthorizeUser & operator=(const UnauthorizeUser & rvalue);
+
+ AUTH_IA * auth;
+};
+//-----------------------------------------------------------------------------
+inline
+void DEL_USER_NOTIFIER::Notify(const UserPtr & user)
+{
+ auth.DelUser(user);
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+Date: 16.05.2008
+*/
+
+/*
+* Author : Maxim Mamontov <faust@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.11 $
+$Date: 2010/09/10 06:41:06 $
+$Author: faust $
+*/
+
+#include "cap_nf.h"
+
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+#include "stg/traffcounter.h"
+
+#include <vector>
+
+#include <csignal>
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+namespace
+{
+
+struct NF_HEADER {
+ uint16_t version; // Protocol version
+ uint16_t count; // Flows count
+ uint32_t uptime; // System uptime
+ uint32_t timestamp; // UNIX timestamp
+ uint32_t nsecs; // Residual nanoseconds
+ uint32_t flowSeq; // Sequence counter
+ uint8_t eType; // Engine type
+ uint8_t eID; // Engine ID
+ uint16_t sInterval; // Sampling mode and interval
+};
+
+struct NF_DATA {
+ uint32_t srcAddr; // Flow source address
+ uint32_t dstAddr; // Flow destination address
+ uint32_t nextHop; // IP addres on next hop router
+ uint16_t inSNMP; // SNMP index of input iface
+ uint16_t outSNMP; // SNMP index of output iface
+ uint32_t packets; // Packets in flow
+ uint32_t octets; // Total number of bytes in flow
+ uint32_t timeStart; // Uptime on first packet in flow
+ uint32_t timeFinish;// Uptime on last packet in flow
+ uint16_t srcPort; // Flow source port
+ uint16_t dstPort; // Flow destination port
+ uint8_t pad1; // 1-byte padding
+ uint8_t TCPFlags; // Cumulative OR of TCP flags
+ uint8_t proto; // IP protocol type (tcp, udp, etc.)
+ uint8_t tos; // IP Type of Service (ToS)
+ uint16_t srcAS; // Source BGP autonomous system number
+ uint16_t dstAS; // Destination BGP autonomus system number
+ uint8_t srcMask; // Source address mask in "slash" notation
+ uint8_t dstMask; // Destination address mask in "slash" notation
+ uint16_t pad2; // 2-byte padding
+};
+
+#define BUF_SIZE (sizeof(NF_HEADER) + 30 * sizeof(NF_DATA))
+
+}
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static NF_CAP plugin;
+ return &plugin;
+}
+
+NF_CAP::NF_CAP()
+ : traffCnt(NULL),
+ runningTCP(false),
+ runningUDP(false),
+ stoppedTCP(true),
+ stoppedUDP(true),
+ portT(0),
+ portU(0),
+ sockTCP(-1),
+ sockUDP(-1),
+ logger(STG::PluginLogger::get("cap_nf"))
+{
+}
+
+int NF_CAP::ParseSettings()
+{
+std::vector<STG::ParamValue>::iterator it;
+for (it = settings.moduleParams.begin(); it != settings.moduleParams.end(); ++it)
+ {
+ if (it->param == "TCPPort" && !it->value.empty())
+ {
+ if (str2x(it->value[0], portT))
+ {
+ errorStr = "Invalid TCPPort value";
+ printfd(__FILE__, "Error: Invalid TCPPort value\n");
+ return -1;
+ }
+ continue;
+ }
+ if (it->param == "UDPPort" && !it->value.empty())
+ {
+ if (str2x(it->value[0], portU))
+ {
+ errorStr = "Invalid UDPPort value";
+ printfd(__FILE__, "Error: Invalid UDPPort value\n");
+ return -1;
+ }
+ continue;
+ }
+ printfd(__FILE__, "'%s' is not a valid module param\n", it->param.c_str());
+ }
+return 0;
+}
+
+int NF_CAP::Start()
+{
+if (portU > 0)
+ {
+ if (OpenUDP())
+ {
+ return -1;
+ }
+ runningUDP = true;
+ if (pthread_create(&tidUDP, NULL, RunUDP, this))
+ {
+ runningUDP = false;
+ CloseUDP();
+ errorStr = "Cannot create UDP thread";
+ logger("Cannot create UDP thread.");
+ printfd(__FILE__, "Error: Cannot create UDP thread\n");
+ return -1;
+ }
+ }
+if (portT > 0)
+ {
+ if (OpenTCP())
+ {
+ return -1;
+ }
+ runningTCP = true;
+ if (pthread_create(&tidTCP, NULL, RunTCP, this))
+ {
+ runningTCP = false;
+ CloseTCP();
+ logger("Cannot create TCP thread.");
+ errorStr = "Cannot create TCP thread";
+ printfd(__FILE__, "Error: Cannot create TCP thread\n");
+ return -1;
+ }
+ }
+return 0;
+}
+
+int NF_CAP::Stop()
+{
+runningTCP = runningUDP = false;
+if (portU && !stoppedUDP)
+ {
+ CloseUDP();
+ for (int i = 0; i < 25 && !stoppedUDP; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ if (stoppedUDP)
+ {
+ pthread_join(tidUDP, NULL);
+ }
+ else
+ {
+ if (pthread_kill(tidUDP, SIGUSR1))
+ {
+ errorStr = "Error sending signal to UDP thread";
+ logger("Error sending sugnal to UDP thread.");
+ printfd(__FILE__, "Error: Error sending signal to UDP thread\n");
+ return -1;
+ }
+ printfd(__FILE__, "UDP thread NOT stopped\n");
+ logger("Cannot stop UDP thread.");
+ }
+ }
+if (portT && !stoppedTCP)
+ {
+ CloseTCP();
+ for (int i = 0; i < 25 && !stoppedTCP; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ if (stoppedTCP)
+ {
+ pthread_join(tidTCP, NULL);
+ }
+ else
+ {
+ if (pthread_kill(tidTCP, SIGUSR1))
+ {
+ errorStr = "Error sending signal to TCP thread";
+ logger("Error sending signal to TCP thread.");
+ printfd(__FILE__, "Error: Error sending signal to TCP thread\n");
+ return -1;
+ }
+ printfd(__FILE__, "TCP thread NOT stopped\n");
+ logger("Cannot stop TCP thread.");
+ }
+ }
+return 0;
+}
+
+bool NF_CAP::OpenUDP()
+{
+struct sockaddr_in sin;
+sockUDP = socket(PF_INET, SOCK_DGRAM, 0);
+if (sockUDP <= 0)
+ {
+ errorStr = "Error opening UDP socket";
+ logger("Cannot create UDP socket: %s", strerror(errno));
+ printfd(__FILE__, "Error: Error opening UDP socket\n");
+ return true;
+ }
+sin.sin_family = AF_INET;
+sin.sin_port = htons(portU);
+sin.sin_addr.s_addr = inet_addr("0.0.0.0");
+if (bind(sockUDP, (struct sockaddr *)&sin, sizeof(sin)))
+ {
+ errorStr = "Error binding UDP socket";
+ logger("Cannot bind UDP socket: %s", strerror(errno));
+ printfd(__FILE__, "Error: Error binding UDP socket\n");
+ return true;
+ }
+return false;
+}
+
+bool NF_CAP::OpenTCP()
+{
+struct sockaddr_in sin;
+sockTCP = socket(PF_INET, SOCK_STREAM, 0);
+if (sockTCP <= 0)
+ {
+ errorStr = "Error opening TCP socket";
+ logger("Cannot create TCP socket: %s", strerror(errno));
+ printfd(__FILE__, "Error: Error opening TCP socket\n");
+ return true;
+ }
+sin.sin_family = AF_INET;
+sin.sin_port = htons(portT);
+sin.sin_addr.s_addr = inet_addr("0.0.0.0");
+if (bind(sockTCP, (struct sockaddr *)&sin, sizeof(sin)))
+ {
+ errorStr = "Error binding TCP socket";
+ logger("Cannot bind TCP socket: %s", strerror(errno));
+ printfd(__FILE__, "Error: Error binding TCP socket\n");
+ return true;
+ }
+if (listen(sockTCP, 1))
+ {
+ errorStr = "Error listening on TCP socket";
+ logger("Cannot listen on TCP socket: %s", strerror(errno));
+ printfd(__FILE__, "Error: Error listening TCP socket\n");
+ return true;
+ }
+return false;
+}
+
+void * NF_CAP::RunUDP(void * c)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+NF_CAP * cap = static_cast<NF_CAP *>(c);
+cap->stoppedUDP = false;
+while (cap->runningUDP)
+ {
+ if (!WaitPackets(cap->sockUDP))
+ {
+ continue;
+ }
+
+ // Data
+ struct sockaddr_in sin;
+ socklen_t slen = sizeof(sin);
+ uint8_t buf[BUF_SIZE];
+ ssize_t res = recvfrom(cap->sockUDP, buf, BUF_SIZE, 0, reinterpret_cast<struct sockaddr *>(&sin), &slen);
+ if (!cap->runningUDP)
+ break;
+
+ if (res < 0)
+ {
+ cap->logger("recvfrom error: %s", strerror(errno));
+ continue;
+ }
+
+ if (res == 0) // EOF
+ {
+ continue;
+ }
+
+ if (res < 24)
+ {
+ if (errno != EINTR)
+ {
+ cap->errorStr = "Invalid data received";
+ printfd(__FILE__, "Error: Invalid data received through UDP\n");
+ }
+ continue;
+ }
+
+ cap->ParseBuffer(buf, res);
+ }
+cap->stoppedUDP = true;
+return NULL;
+}
+
+void * NF_CAP::RunTCP(void * c)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+NF_CAP * cap = static_cast<NF_CAP *>(c);
+cap->stoppedTCP = false;
+while (cap->runningTCP)
+ {
+ if (!WaitPackets(cap->sockTCP))
+ {
+ continue;
+ }
+
+ // Data
+ struct sockaddr_in sin;
+ socklen_t slen = sizeof(sin);
+ int sd = accept(cap->sockTCP, reinterpret_cast<struct sockaddr *>(&sin), &slen);
+ if (!cap->runningTCP)
+ break;
+
+ if (sd <= 0)
+ {
+ if (sd < 0)
+ cap->logger("accept error: %s", strerror(errno));
+ continue;
+ }
+
+ if (!WaitPackets(sd))
+ {
+ close(sd);
+ continue;
+ }
+
+ uint8_t buf[BUF_SIZE];
+ ssize_t res = recv(sd, buf, BUF_SIZE, MSG_WAITALL);
+
+ if (res < 0)
+ cap->logger("recv error: %s", strerror(errno));
+
+ close(sd);
+
+ if (!cap->runningTCP)
+ break;
+
+ if (res == 0) // EOF
+ {
+ continue;
+ }
+
+ // Wrong logic!
+ // Need to check actual data length and wait all data to receive
+ if (res < 24)
+ {
+ continue;
+ }
+
+ cap->ParseBuffer(buf, res);
+ }
+cap->stoppedTCP = true;
+return NULL;
+}
+
+void NF_CAP::ParseBuffer(uint8_t * buf, ssize_t size)
+{
+STG::RawPacket ip;
+NF_HEADER * hdr = reinterpret_cast<NF_HEADER *>(buf);
+if (htons(hdr->version) != 5)
+ {
+ return;
+ }
+
+int packets = htons(hdr->count);
+
+if (packets < 0 || packets > 30)
+ {
+ return;
+ }
+
+if (24 + 48 * packets != size)
+ {
+ // See 'wrong logic' upper
+ return;
+ }
+
+for (int i = 0; i < packets; ++i)
+ {
+ NF_DATA * data = reinterpret_cast<NF_DATA *>(buf + 24 + i * 48);
+
+ ip.rawPacket.header.ipHeader.ip_v = 4;
+ ip.rawPacket.header.ipHeader.ip_hl = 5;
+ ip.rawPacket.header.ipHeader.ip_p = data->proto;
+ ip.dataLen = ntohl(data->octets);
+ ip.rawPacket.header.ipHeader.ip_src.s_addr = data->srcAddr;
+ ip.rawPacket.header.ipHeader.ip_dst.s_addr = data->dstAddr;
+ ip.rawPacket.header.sPort = data->srcPort;
+ ip.rawPacket.header.dPort = data->dstPort;
+
+ traffCnt->process(ip);
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+Date: 16.05.2008
+*/
+
+/*
+* Author : Maxim Mamontov <faust@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.5 $
+$Date: 2009/12/13 12:56:07 $
+$Author: faust $
+*/
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <cstdint>
+
+#include <pthread.h>
+#include <unistd.h> // close
+
+#define VERSION "cap_nf v. 0.4"
+#define START_POS 40
+#define STOP_POS 40
+
+namespace STG
+{
+
+struct Users;
+struct Tariffs;
+struct Admins;
+struct TraffCounter;
+struct Store;
+struct Settings;
+
+}
+
+class NF_CAP : public STG::Plugin {
+public:
+ NF_CAP();
+
+ void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+
+ bool IsRunning() override { return runningTCP || runningUDP; }
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override { return VERSION; }
+ uint16_t GetStartPosition() const override { return START_POS; }
+ uint16_t GetStopPosition() const override { return STOP_POS; }
+
+private:
+ NF_CAP(const NF_CAP & rvalue);
+ NF_CAP & operator=(const NF_CAP & rvalue);
+
+ STG::TraffCounter * traffCnt;
+ STG::ModuleSettings settings;
+ pthread_t tidTCP;
+ pthread_t tidUDP;
+ bool runningTCP;
+ bool runningUDP;
+ bool stoppedTCP;
+ bool stoppedUDP;
+ uint16_t portT;
+ uint16_t portU;
+ int sockTCP;
+ int sockUDP;
+ mutable std::string errorStr;
+ STG::PluginLogger logger;
+
+ static void * RunUDP(void *);
+ static void * RunTCP(void *);
+ void ParseBuffer(uint8_t * buf, ssize_t size);
+
+ bool OpenTCP();
+ bool OpenUDP();
+ void CloseTCP() { close(sockTCP); }
+ void CloseUDP() { close(sockUDP); }
+};
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.13 $
+$Date: 2010/09/10 06:43:03 $
+*/
+
+#include "divert_cap.h"
+
+#include "stg/traffcounter.h"
+#include "stg/raw_ip_packet.h"
+#include "stg/common.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <cstdio>
+#include <cstring>
+#include <cerrno>
+#include <cstdlib>
+#include <csignal>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#define BUFF_LEN (16384) /* max mtu -> lo=16436 TODO why?*/
+
+//-----------------------------------------------------------------------------
+struct DIVERT_DATA {
+int sock;
+short int port;
+char iface[10];
+};
+//-----------------------------------------------------------------------------
+pollfd pollddiv;
+DIVERT_DATA cddiv; //capture data
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static DIVERT_CAP plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string DIVERT_CAP::GetVersion() const
+{
+return "cap_divert v.1.0";
+}
+//-----------------------------------------------------------------------------
+DIVERT_CAP::DIVERT_CAP()
+ : port(0),
+ disableForwarding(false),
+ nonstop(false),
+ isRunning(false),
+ traffCnt(NULL),
+ logger(STG::PluginLogger::get("cap_divert"))
+{
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::Start()
+{
+if (isRunning)
+ return 0;
+
+if (DivertCapOpen() < 0)
+ {
+ errorStr = "Cannot open socket!";
+ printfd(__FILE__, "Cannot open socket\n");
+ return -1;
+ }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::Stop()
+{
+if (!isRunning)
+ return 0;
+
+DivertCapClose();
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+ {
+ if (!isRunning)
+ break;
+
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+ {
+ if (pthread_kill(thread, SIGINT))
+ {
+ errorStr = "Cannot kill thread.";
+ logger("Cannot send signal to thread.");
+ printfd(__FILE__, "Cannot kill thread\n");
+ return -1;
+ }
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * DIVERT_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+DIVERT_CAP * dc = static_cast<DIVERT_CAP *>(d);
+dc->isRunning = true;
+
+char buffer[STG::packetSize + 14];
+while (dc->nonstop)
+ {
+ STG::RawPacket rp;
+ dc->DivertCapRead(buffer, sizeof(buffer), NULL);
+
+ if (buffer[12] != 0x8)
+ continue;
+
+ memcpy(&rp.rawPacket, &buffer[14], STG::packetSize);
+
+ dc->traffCnt->process(rp);
+ }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapOpen()
+{
+memset(&pollddiv, 0, sizeof(pollddiv));
+memset(&cddiv, 0, sizeof(DIVERT_DATA));
+
+strcpy(cddiv.iface, "foo");
+cddiv.port = port;
+
+DivertCapOpen(0);
+pollddiv.events = POLLIN;
+pollddiv.fd = cddiv.sock;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapOpen(int)
+{
+int ret;
+cddiv.sock = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
+if (cddiv.sock < 0)
+ {
+ errorStr = "Create divert socket error.";
+ logger("Cannot create a socket: %s", strerror(errno));
+ printfd(__FILE__, "Cannot create divert socket\n");
+ return -1;
+ }
+
+struct sockaddr_in divAddr;
+
+memset(&divAddr, 0, sizeof(divAddr));
+
+divAddr.sin_family = AF_INET;
+divAddr.sin_port = htons(cddiv.port);
+divAddr.sin_addr.s_addr = INADDR_ANY;
+
+ret = bind(cddiv.sock, (struct sockaddr *)&divAddr, sizeof(divAddr));
+
+if (ret < 0)
+ {
+ errorStr = "Bind divert socket error.";
+ logger("Cannot bind the scoket: %s", strerror(errno));
+ printfd(__FILE__, "Cannot bind divert socket\n");
+ return -1;
+ }
+
+return cddiv.sock;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface)
+{
+poll(&pollddiv, 1, -1);
+
+if (pollddiv.revents & POLLIN)
+ {
+ DivertCapRead(b, blen, iface, 0);
+ pollddiv.revents = 0;
+ return 0;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface, int)
+{
+static char buf[BUFF_LEN];
+static struct sockaddr_in divertaddr;
+static int bytes;
+static socklen_t divertaddrSize = sizeof(divertaddr);
+
+if ((bytes = recvfrom (cddiv.sock, buf, BUFF_LEN,
+ 0, (struct sockaddr*) &divertaddr, &divertaddrSize)) > 50)
+ {
+ memcpy(b + 14, buf, blen - 14);
+ b[12] = 0x8;
+
+ if (iface)
+ *iface = cddiv.iface;
+
+ if (!disableForwarding)
+ {
+ if (sendto(cddiv.sock, buf, bytes, 0, (struct sockaddr*)&divertaddr, divertaddrSize) < 0)
+ logger("sendto error: %s", strerror(errno));
+ }
+ }
+else
+ {
+ if (bytes < 0)
+ logger("recvfrom error: %s", strerror(errno));
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapClose()
+{
+close(cddiv.sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::ParseSettings()
+{
+int p;
+STG::ParamValue pv;
+std::vector<STG::ParamValue>::const_iterator pvi;
+
+pv.param = "Port";
+pvi = std::find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
+if (pvi == settings.moduleParams.end() || pvi->value.empty())
+ {
+ p = 15701;
+ }
+else if (ParseIntInRange(pvi->value[0], 1, 65535, &p))
+ {
+ errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+ return -1;
+ }
+
+port = p;
+
+bool d = false;
+pv.param = "DisableForwarding";
+pvi = std::find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
+if (pvi == settings.moduleParams.end() || pvi->value.empty())
+ {
+ disableForwarding = false;
+ }
+else if (ParseYesNo(pvi->value[0], &d))
+ {
+ errorStr = "Cannot parse parameter \'DisableForwarding\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'DisableForwarding'\n");
+ return -1;
+ }
+
+disableForwarding = d;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stg.dp.ua>
+*/
+
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+
+#include <pthread.h>
+
+namespace STG
+{
+struct Users;
+struct Tariffs;
+struct Admins;
+struct TraffCounter;
+struct Settings;
+}
+
+//-----------------------------------------------------------------------------
+class DIVERT_CAP : public STG::Plugin {
+public:
+ DIVERT_CAP();
+
+ void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return isRunning; }
+
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override;
+ uint16_t GetStartPosition() const override { return 40; }
+ uint16_t GetStopPosition() const override { return 40; }
+
+private:
+ DIVERT_CAP(const DIVERT_CAP & rvalue);
+ DIVERT_CAP & operator=(const DIVERT_CAP & rvalue);
+
+ static void * Run(void *);
+
+ int DivertCapOpen();
+ int DivertCapOpen(int n);
+ int DivertCapRead(char * buffer, int blen, char ** iface);
+ int DivertCapRead(char * buffer, int blen, char ** iface, int n);
+ int DivertCapClose();
+
+ STG::ModuleSettings settings;
+
+ int port;
+ bool disableForwarding;
+
+ mutable std::string errorStr;
+
+ pthread_t thread;
+
+ bool nonstop;
+ bool isRunning;
+
+ STG::TraffCounter * traffCnt;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+Date: 18.09.2002
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.19 $
+$Date: 2009/03/24 11:20:15 $
+$Author: faust $
+*/
+
+#include "ether_cap.h"
+
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+#include "stg/traffcounter.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <csignal>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+//#define CAP_DEBUG 1
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static BPF_CAP plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int BPF_CAP_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+iface.erase(iface.begin(), iface.end());
+
+if (s.moduleParams.empty())
+ {
+ errorStr = "Parameter \'iface\' not found.";
+ printfd(__FILE__, "Parameter 'iface' not found\n");
+ return -1;
+ }
+
+for (unsigned i = 0; i < s.moduleParams.size(); i++)
+ {
+ if (s.moduleParams[i].param != "iface")
+ {
+ errorStr = "Parameter \'" + s.moduleParams[i].param + "\' unrecognized.";
+ printfd(__FILE__, "Invalid parameter: '%s'\n", s.moduleParams[i].param.c_str());
+ return -1;
+ }
+ for (unsigned j = 0; j < s.moduleParams[i].value.size(); j++)
+ {
+ iface.push_back(s.moduleParams[i].value[j]);
+ }
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+std::string BPF_CAP_SETTINGS::GetIface(unsigned int num)
+{
+if (num >= iface.size())
+ {
+ return "";
+ }
+return iface[num];
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string BPF_CAP::GetVersion() const
+{
+return "cap_bpf v.1.0";
+}
+//-----------------------------------------------------------------------------
+BPF_CAP::BPF_CAP()
+ : nonstop(false),
+ isRunning(false),
+ capSock(-1),
+ traffCnt(NULL),
+ logger(STG::PluginLogger::get("cap_bpf"))
+{
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::ParseSettings()
+{
+int ret = capSettings.ParseSettings(settings);
+if (ret)
+ {
+ errorStr = capSettings.GetStrError();
+ return ret;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::Start()
+{
+if (isRunning)
+ return 0;
+
+if (BPFCapOpen() < 0)
+ {
+ //errorStr = "Cannot open bpf device!";
+ return -1;
+ }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::Stop()
+{
+if (!isRunning)
+ return 0;
+
+BPFCapClose();
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+ {
+ if (!isRunning)
+ break;
+
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+ {
+ //TODO pthread_cancel()
+ if (pthread_kill(thread, SIGINT))
+ {
+ errorStr = "Cannot kill thread.";
+ logger("Cannot send signal to thread.");
+ printfd(__FILE__, "Cannot kill thread\n");
+ return -1;
+ }
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * BPF_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+BPF_CAP * dc = static_cast<BPF_CAP *>(d);
+dc->isRunning = true;
+
+uint8_t hdr[96]; //68 + 14 + 4(size) + 9(SYS_IFACE) + 1(align to 4) = 96
+
+STG::RawPacket * rpp = (STG::RawPacket *)&hdr[14];
+memset(hdr, 0, sizeof(hdr));
+
+rpp->dataLen = -1;
+char * iface;
+
+while (dc->nonstop)
+ {
+ if (dc->BPFCapRead((char*)&hdr, 68 + 14, &iface))
+ continue;
+
+ if (!(hdr[12] == 0x8 && hdr[13] == 0x0))
+ continue;
+
+ dc->traffCnt->process(*rpp);
+ }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapOpen()
+{
+int i = 0;
+BPF_DATA bd;
+pollfd pd;
+
+while ((bd.iface = capSettings.GetIface(i)) != "")
+ {
+ bpfData.push_back(bd);
+ if (BPFCapOpen(&bpfData[i]) < 0)
+ {
+ return -1;
+ }
+
+ pd.events = POLLIN;
+ pd.fd = bpfData[i].fd;
+ polld.push_back(pd);
+ i++;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapOpen(BPF_DATA * bd)
+{
+char devbpf[20];
+int i = 0;
+int l = BUFF_LEN;
+int im = 1;
+struct ifreq ifr;
+
+do
+ {
+ sprintf(devbpf, "/dev/bpf%d", i);
+ i++;
+ bd->fd = open(devbpf, O_RDONLY);
+ } while(bd->fd < 0 && errno == EBUSY);
+
+if (bd->fd < 0)
+ {
+ errorStr = "Can't capture packets. Open bpf device for " + bd->iface + " error.";
+ logger("Cannot open device for interface '%s': %s", bd->iface.c_str(), strerror(errno));
+ printfd(__FILE__, "Cannot open BPF device\n");
+ return -1;
+ }
+
+strncpy(ifr.ifr_name, bd->iface.c_str(), sizeof(ifr.ifr_name));
+
+if (ioctl(bd->fd, BIOCSBLEN, (caddr_t)&l) < 0)
+ {
+ errorStr = bd->iface + " BIOCSBLEN " + std::string(strerror(errno));
+ logger("ioctl (BIOCSBLEN) error for interface '%s': %s", bd->iface.c_str(), strerror(errno));
+ printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
+ return -1;
+ }
+
+if (ioctl(bd->fd, BIOCSETIF, (caddr_t)&ifr) < 0)
+ {
+ errorStr = bd->iface + " BIOCSETIF " + std::string(strerror(errno));
+ logger("ioctl (BIOCSETIF) error for interface '%s': %s", bd->iface.c_str(), strerror(errno));
+ printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
+ return -1;
+ }
+
+if (ioctl(bd->fd, BIOCIMMEDIATE, &im) < 0)
+ {
+ errorStr = bd->iface + " BIOCIMMEDIATE " + std::string(strerror(errno));
+ logger("ioctl (BIOCIMMEDIATE) error for interface '%s': %s", bd->iface.c_str(), strerror(errno));
+ printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
+ return -1;
+ }
+
+return bd->fd;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapClose()
+{
+for (unsigned int i = 0; i < bpfData.size(); i++)
+ close(bpfData[i].fd);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapRead(char * buffer, int blen, char ** capIface)
+{
+poll(&polld[0], polld.size(), -1);
+
+for (unsigned int i = 0; i < polld.size(); i++)
+ {
+ if (polld[i].revents & POLLIN)
+ {
+ if (BPFCapRead(buffer, blen, capIface, &bpfData[i]))
+ {
+ polld[i].revents = 0;
+ continue;
+ }
+ polld[i].revents = 0;
+ return 0;
+ }
+ }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapRead(char * buffer, int blen, char **, BPF_DATA * bd)
+{
+if (bd->canRead)
+ {
+ bd->r = read(bd->fd, bd->buffer, BUFF_LEN);
+ if (bd->r < 0)
+ {
+ logger("read error: %s", strerror(errno));
+ struct timespec ts = {0, 20000000};
+ nanosleep(&ts, NULL);
+ return -1;
+ }
+
+ bd->p = bd->buffer;
+ bd->bh = (struct bpf_hdr*)bd->p;
+ bd->canRead = 0;
+ }
+
+if(bd->r > bd->sum)
+ {
+ memcpy(buffer, (char*)(bd->p) + bd->bh->bh_hdrlen, blen);
+
+ bd->sum += BPF_WORDALIGN(bd->bh->bh_hdrlen + bd->bh->bh_caplen);
+ bd->p = bd->p + BPF_WORDALIGN(bd->bh->bh_hdrlen + bd->bh->bh_caplen);
+ bd->bh = (struct bpf_hdr*)bd->p;
+ }
+
+if(bd->r <= bd->sum)
+ {
+ bd->canRead = 1;
+ bd->sum = 0;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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
+ */
+
+ /*
+ $Revision: 1.11 $
+ $Date: 2009/06/23 11:32:27 $
+ $Author: faust $
+ */
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+#include <cstdint>
+
+#include <pthread.h>
+#include <sys/poll.h>
+
+#define BUFF_LEN (128)
+
+namespace STG
+{
+struct TraffCounter;
+}
+
+//-----------------------------------------------------------------------------
+struct BPF_DATA {
+ BPF_DATA()
+ {
+ fd = 0;
+ p = NULL;
+ r = 0;
+ sum = 0;
+ memset(buffer, 0, BUFF_LEN);
+ bh = NULL;
+ canRead = 1;
+ iface = "";
+ };
+
+ BPF_DATA(const BPF_DATA & bd)
+ {
+ fd = bd.fd;
+ p = bd.p;
+ r = bd.r;
+ sum = bd.sum;
+ memcpy(buffer, bd.buffer, BUFF_LEN);
+ bh = bd.bh;
+ canRead = bd.canRead;
+ iface = bd.iface;
+ };
+
+int fd;
+uint8_t * p;
+int r;
+int sum;
+uint8_t buffer[BUFF_LEN];
+struct bpf_hdr * bh;
+int canRead;
+std::string iface;
+};
+//-----------------------------------------------------------------------------
+class BPF_CAP_SETTINGS {
+public:
+ const std::string & GetStrError() const { return errorStr; }
+ int ParseSettings(const STG::ModuleSettings & s);
+ std::string GetIface(unsigned int num);
+
+private:
+ std::vector<std::string> iface;
+ mutable std::string errorStr;
+};
+//-----------------------------------------------------------------------------
+class BPF_CAP : public STG::Plugin {
+public:
+ BPF_CAP();
+
+ void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return isRunning; }
+
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override;
+ uint16_t GetStartPosition() const override { return 40; }
+ uint16_t GetStopPosition() const override { return 40; }
+
+private:
+ BPF_CAP(const BPF_CAP & rvalue);
+ BPF_CAP & operator=(const BPF_CAP & rvalue);
+
+ static void * Run(void *);
+ int BPFCapOpen();
+ int BPFCapOpen(BPF_DATA * bd);
+ int BPFCapClose();
+ int BPFCapRead(char * buffer, int blen, char ** iface);
+ int BPFCapRead(char * buffer, int blen, char ** iface, BPF_DATA * bd);
+
+ BPF_CAP_SETTINGS capSettings;
+
+ mutable std::string errorStr;
+
+ std::vector<BPF_DATA> bpfData;
+ std::vector<pollfd> polld;
+
+ pthread_t thread;
+ bool nonstop;
+ bool isRunning;
+ int capSock;
+ STG::ModuleSettings settings;
+
+ STG::TraffCounter * traffCnt;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+Date: 18.09.2002
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+
+/*
+$Revision: 1.23 $
+$Date: 2009/12/13 13:45:13 $
+*/
+
+#include "ether_cap.h"
+
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+#include "stg/traffcounter.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <csignal>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+//#define CAP_DEBUG 1
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static ETHER_CAP plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string ETHER_CAP::GetVersion() const
+{
+return "cap_ether v.1.2";
+}
+//-----------------------------------------------------------------------------
+ETHER_CAP::ETHER_CAP()
+ : nonstop(false),
+ isRunning(false),
+ capSock(-1),
+ traffCnt(NULL),
+ logger(STG::PluginLogger::get("cap_ether"))
+{
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::Start()
+{
+if (isRunning)
+ return 0;
+
+if (EthCapOpen() < 0)
+ {
+ errorStr = "Cannot open socket!";
+ printfd(__FILE__, "Cannot open socket\n");
+ return -1;
+ }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::Stop()
+{
+if (!isRunning)
+ return 0;
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && isRunning; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+ {
+ if (pthread_kill(thread, SIGUSR1))
+ {
+ errorStr = "Cannot kill thread.";
+ logger("Cannot send signal to thread.");
+ return -1;
+ }
+ for (int i = 0; i < 25 && isRunning; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ if (isRunning)
+ {
+ errorStr = "ETHER_CAP not stopped.";
+ logger("Cannot stop thread.");
+ printfd(__FILE__, "Cannot stop thread\n");
+ return -1;
+ }
+ else
+ {
+ pthread_join(thread, NULL);
+ }
+ }
+
+EthCapClose();
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * ETHER_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+ETHER_CAP * dc = static_cast<ETHER_CAP *>(d);
+dc->isRunning = true;
+
+struct ETH_IP
+{
+uint16_t ethHdr[8];
+STG::RawPacket rp;
+char padding[4];
+char padding1[8];
+};
+
+char ethip[sizeof(ETH_IP)];
+
+memset(ðip, 0, sizeof(ETH_IP));
+
+ETH_IP * ethIP = static_cast<ETH_IP *>(static_cast<void *>(ðip));
+ethIP->rp.dataLen = -1;
+
+char * iface = NULL;
+
+while (dc->nonstop)
+ {
+ if (dc->EthCapRead(ðip, 68 + 14, &iface))
+ {
+ continue;
+ }
+
+ if (ethIP->ethHdr[7] != 0x8)
+ continue;
+
+ dc->traffCnt->process(ethIP->rp);
+ }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::EthCapOpen()
+{
+capSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+if (capSock < 0)
+ logger("Cannot create socket: %s", strerror(errno));
+return capSock;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::EthCapClose()
+{
+close(capSock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::EthCapRead(void * buffer, int blen, char **)
+{
+struct sockaddr_ll addr;
+int addrLen;
+
+if (!WaitPackets(capSock))
+ {
+ return ENODATA;
+ }
+
+addrLen = sizeof(addr);
+
+if (recvfrom(capSock, ((char*)buffer) + 2, blen, 0, (struct sockaddr *)&addr, (socklen_t*)&addrLen) < 0)
+ {
+ logger("recvfrom error: %s", strerror(errno));
+ return ENODATA;
+ }
+
+return 0;
+}
--- /dev/null
+/*
+ * 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
+ */
+
+ /*
+ $Revision: 1.12 $
+ $Date: 2009/12/13 13:45:13 $
+ */
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+
+#pragma once
+
+#include <pthread.h>
+
+#include <string>
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+namespace STG
+{
+
+struct Users;
+struct Tariffs;
+struct Admins;
+struct TraffCounter;
+struct Settings;
+
+}
+
+//-----------------------------------------------------------------------------
+class ETHER_CAP : public STG::Plugin {
+public:
+ ETHER_CAP();
+
+ void SetTraffcounter(STG::TraffCounter * tc) { traffCnt = tc; }
+
+ int Start();
+ int Stop();
+ int Reload(const STG::ModuleSettings & /*ms*/) { return 0; }
+ bool IsRunning() { return isRunning; }
+
+ int ParseSettings() { return 0; }
+ const std::string & GetStrError() const { return errorStr; }
+ std::string GetVersion() const;
+ uint16_t GetStartPosition() const { return 40; }
+ uint16_t GetStopPosition() const { return 40; }
+
+private:
+ ETHER_CAP(const ETHER_CAP & rvalue);
+ ETHER_CAP & operator=(const ETHER_CAP & rvalue);
+
+ static void * Run(void *);
+ int EthCapOpen();
+ int EthCapClose();
+ int EthCapRead(void * buffer, int blen, char ** iface);
+
+ mutable std::string errorStr;
+
+ pthread_t thread;
+ bool nonstop;
+ bool isRunning;
+ int capSock;
+
+ STG::TraffCounter * traffCnt;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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 "nfqueue.h"
+
+#include "stg/traffcounter.h"
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+
+extern "C" {
+
+#include <linux/netfilter.h> /* Defines verdicts (NF_ACCEPT, etc) */
+#include <libnetfilter_queue/libnetfilter_queue.h>
+
+}
+
+#include <cerrno>
+#include <csignal>
+
+#include <arpa/inet.h> // ntohl
+
+#include <unistd.h> // read
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+namespace
+{
+
+int Callback(struct nfq_q_handle * queueHandle, struct nfgenmsg * /*msg*/,
+ struct nfq_data * nfqData, void *data)
+{
+int id = 0;
+
+struct nfqnl_msg_packet_hdr * packetHeader = nfq_get_msg_packet_hdr(nfqData);
+if (packetHeader == NULL)
+ return 0;
+
+id = ntohl(packetHeader->packet_id);
+
+unsigned char * payload = NULL;
+
+if (nfq_get_payload(nfqData, &payload) < 0 || payload == NULL)
+ return id;
+
+STG::RawPacket packet;
+
+memcpy(&packet.rawPacket, payload, sizeof(packet.rawPacket));
+
+NFQ_CAP * cap = static_cast<NFQ_CAP *>(data);
+
+cap->Process(packet);
+
+return nfq_set_verdict(queueHandle, id, NF_ACCEPT, 0, NULL);
+}
+
+}
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static NFQ_CAP plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string NFQ_CAP::GetVersion() const
+{
+return "cap_nfqueue v.1.0";
+}
+//-----------------------------------------------------------------------------
+NFQ_CAP::NFQ_CAP()
+ : nonstop(false),
+ isRunning(false),
+ queueNumber(0),
+ nfqHandle(NULL),
+ queueHandle(NULL),
+ traffCnt(NULL),
+ logger(STG::PluginLogger::get("cap_nfqueue"))
+{
+}
+//-----------------------------------------------------------------------------
+int NFQ_CAP::ParseSettings()
+{
+for (size_t i = 0; i < settings.moduleParams.size(); i++)
+ if (settings.moduleParams[i].param == "queueNumber" && !settings.moduleParams[i].value.empty())
+ if (str2x(settings.moduleParams[i].value[0], queueNumber) < 0)
+ {
+ errorStr = "Queue number should be a number. Got: '" + settings.moduleParams[i].param + "'";
+ logger(errorStr);
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NFQ_CAP::Start()
+{
+if (isRunning)
+ return 0;
+
+nfqHandle = nfq_open();
+if (nfqHandle == NULL)
+ {
+ errorStr = "Failed to initialize netfilter queue.";
+ logger(errorStr);
+ return -1;
+ }
+
+if (nfq_unbind_pf(nfqHandle, AF_INET) < 0)
+ {
+ errorStr = "Failed to unbind netfilter queue from IP handling.";
+ logger(errorStr);
+ return -1;
+ }
+
+if (nfq_bind_pf(nfqHandle, AF_INET) < 0)
+ {
+ errorStr = "Failed to bind netfilter queue to IP handling.";
+ logger(errorStr);
+ return -1;
+ }
+
+queueHandle = nfq_create_queue(nfqHandle, queueNumber, &Callback, this);
+if (queueHandle == NULL)
+ {
+ errorStr = "Failed to create queue " + std::to_string(queueNumber) + ".";
+ logger(errorStr);
+ return -1;
+ }
+
+if (nfq_set_mode(queueHandle, NFQNL_COPY_PACKET, 0xffFF) < 0)
+ {
+ errorStr = "Failed to set queue " + std::to_string(queueNumber) + " mode.";
+ logger(errorStr);
+ return -1;
+ }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NFQ_CAP::Stop()
+{
+if (!isRunning)
+ return 0;
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && isRunning; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+ {
+ if (pthread_kill(thread, SIGUSR1))
+ {
+ errorStr = "Cannot kill thread.";
+ logger("Cannot send signal to thread.");
+ return -1;
+ }
+ for (int i = 0; i < 25 && isRunning; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ if (isRunning)
+ {
+ errorStr = "NFQ_CAP not stopped.";
+ logger("Cannot stop thread.");
+ printfd(__FILE__, "Cannot stop thread\n");
+ return -1;
+ }
+ }
+
+pthread_join(thread, NULL);
+
+nfq_destroy_queue(queueHandle);
+nfq_close(nfqHandle);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * NFQ_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+NFQ_CAP * dc = static_cast<NFQ_CAP *>(d);
+dc->isRunning = true;
+
+int fd = nfq_fd(dc->nfqHandle);
+char buf[4096];
+
+while (dc->nonstop)
+ {
+ if (!WaitPackets(fd))
+ continue;
+
+ int rv = read(fd, buf, sizeof(buf));
+ if (rv < 0)
+ {
+ dc->errorStr = std::string("Read error: ") + strerror(errno);
+ dc->logger(dc->errorStr);
+ break;
+ }
+ nfq_handle_packet(dc->nfqHandle, buf, rv);
+ }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void NFQ_CAP::Process(const STG::RawPacket & packet)
+{
+traffCnt->process(packet);
+}
--- /dev/null
+/*
+ * 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>
+*/
+
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+
+#include <pthread.h>
+
+namespace STG
+{
+
+struct Users;
+struct Tariffs;
+struct Admins;
+struct TraffCounter;
+struct Settings;
+struct RawPacket;
+
+}
+
+struct nfq_handle;
+struct nfq_q_handle;
+
+class NFQ_CAP : public STG::Plugin {
+public:
+ NFQ_CAP();
+
+ void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return isRunning; }
+
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override;
+ uint16_t GetStartPosition() const override { return 40; }
+ uint16_t GetStopPosition() const override { return 40; }
+
+ void Process(const STG::RawPacket & packet);
+
+private:
+ NFQ_CAP(const NFQ_CAP & rvalue);
+ NFQ_CAP & operator=(const NFQ_CAP & rvalue);
+
+ static void * Run(void *);
+
+ mutable std::string errorStr;
+
+ pthread_t thread;
+ bool nonstop;
+ bool isRunning;
+ STG::ModuleSettings settings;
+
+ size_t queueNumber;
+
+ struct nfq_handle * nfqHandle;
+ struct nfq_q_handle * queueHandle;
+
+ STG::TraffCounter * traffCnt;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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 "pcap_cap.h"
+
+#include "stg/traffcounter.h"
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+
+#include <signal.h>
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+namespace
+{
+
+const size_t SNAP_LEN = 1518;
+const size_t ETHER_ADDR_LEN = 6;
+
+struct ETH
+{
+u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */
+u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */
+u_short ether_type; /* IP? ARP? RARP? etc */
+};
+
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+extern "C" STG::Plugin* GetPlugin()
+{
+ static PCAP_CAP plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string PCAP_CAP::GetVersion() const
+{
+return "pcap_cap v.1.0";
+}
+//-----------------------------------------------------------------------------
+PCAP_CAP::PCAP_CAP()
+ : nonstop(false),
+ isRunning(false),
+ traffCnt(NULL),
+ logger(STG::PluginLogger::get("pcap_cap"))
+{
+}
+//-----------------------------------------------------------------------------
+int PCAP_CAP::ParseSettings()
+{
+devices.erase(devices.begin(), devices.end());
+
+if (settings.moduleParams.empty())
+ {
+ devices.push_back(DEV());
+ logger("Defaulting to pseudo-device 'any'.");
+ return 0;
+ }
+
+for (size_t i = 0; i < settings.moduleParams.size(); i++)
+ if (settings.moduleParams[i].param == "interfaces")
+ for (size_t j = 0; j < settings.moduleParams[i].value.size(); j++)
+ devices.push_back(DEV(settings.moduleParams[i].value[j]));
+
+for (size_t i = 0; i < settings.moduleParams.size(); i++)
+ if (settings.moduleParams[i].param == "filters")
+ for (size_t j = 0; j < settings.moduleParams[i].value.size(); j++)
+ if (j < devices.size())
+ devices[j].filterExpression = settings.moduleParams[i].value[j];
+
+if (devices.empty())
+ {
+ devices.push_back(DEV());
+ logger("Defaulting to pseudo-device 'all'.");
+ return 0;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PCAP_CAP::Start()
+{
+if (isRunning)
+ return 0;
+
+DEV_MAP::iterator it(devices.begin());
+while (it != devices.end())
+ {
+ bpf_u_int32 mask;
+ bpf_u_int32 net;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ /* get network number and mask associated with capture device */
+ if (pcap_lookupnet(it->device.c_str(), &net, &mask, errbuf) == -1)
+ {
+ errorStr = "Couldn't get netmask for device " + it->device + ": " + errbuf;
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ /* open capture device */
+ it->handle = pcap_open_live(it->device.c_str(), SNAP_LEN, 1, 1000, errbuf);
+ if (it->handle == NULL)
+ {
+ errorStr = "Couldn't open device " + it->device + ": " + errbuf;
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ if (pcap_setnonblock(it->handle, true, errbuf) == -1)
+ {
+ errorStr = "Couldn't put device " + it->device + " into non-blocking mode: " + errbuf;
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ /* make sure we're capturing on an Ethernet device [2] */
+ if (pcap_datalink(it->handle) != DLT_EN10MB)
+ {
+ errorStr = it->device + " is not an Ethernet";
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ /* compile the filter expression */
+ if (pcap_compile(it->handle, &it->filter, it->filterExpression.c_str(), 0, net) == -1)
+ {
+ errorStr = "Couldn't parse filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ /* apply the compiled filter */
+ if (pcap_setfilter(it->handle, &it->filter) == -1)
+ {
+ errorStr = "Couldn't install filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ it->fd = pcap_get_selectable_fd(it->handle);
+ if (it->fd == -1)
+ {
+ errorStr = "Couldn't get a file descriptor for " + it->device + ": " + pcap_geterr(it->handle);
+ logger(errorStr);
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+ ++it;
+ }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PCAP_CAP::Stop()
+{
+if (!isRunning)
+ return 0;
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && isRunning; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+ {
+ if (pthread_kill(thread, SIGUSR1))
+ {
+ errorStr = "Cannot kill thread.";
+ logger("Cannot send signal to thread.");
+ return -1;
+ }
+ for (int i = 0; i < 25 && isRunning; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ if (isRunning)
+ {
+ errorStr = "PCAP_CAP not stopped.";
+ logger("Cannot stop thread.");
+ printfd(__FILE__, "Cannot stop thread\n");
+ return -1;
+ }
+ }
+
+pthread_join(thread, NULL);
+
+for (DEV_MAP::iterator it(devices.begin()); it != devices.end(); ++it)
+ {
+ pcap_freecode(&it->filter);
+ pcap_close(it->handle);
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * PCAP_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+PCAP_CAP * dc = static_cast<PCAP_CAP *>(d);
+dc->isRunning = true;
+
+fd_set fds;
+FD_ZERO(&fds);
+int maxFd = 0;
+for (DEV_MAP::const_iterator it(dc->devices.begin()); it != dc->devices.end(); ++it)
+ {
+ FD_SET(it->fd, &fds);
+ maxFd = std::max(maxFd, it->fd);
+ }
+
+while (dc->nonstop)
+ {
+ fd_set rfds = fds;
+ struct timeval tv = {0, 500000};
+
+ if (select(maxFd + 1, &rfds, NULL, NULL, &tv) > 0)
+ dc->TryRead(rfds);
+ }
+
+dc->isRunning = false;
+return NULL;
+}
+
+void PCAP_CAP::TryRead(const fd_set & set)
+{
+for (DEV_MAP::const_iterator it(devices.begin()); it != devices.end(); ++it)
+ if (FD_ISSET(it->fd, &set))
+ TryReadDev(*it);
+}
+
+void PCAP_CAP::TryReadDev(const DEV & dev)
+{
+struct pcap_pkthdr * header;
+const u_char * packet;
+if (pcap_next_ex(dev.handle, &header, &packet) == -1)
+ {
+ printfd(__FILE__, "Failed to read data from '%s': %s\n", dev.device.c_str(), pcap_geterr(dev.handle));
+ return;
+ }
+
+const ETH * eth = reinterpret_cast<const ETH *>(packet);
+if (eth->ether_type != 0x8)
+ return;
+
+STG::RawPacket ip;
+memcpy(&ip.rawPacket, packet + 14, sizeof(ip.rawPacket));
+traffCnt->process(ip);
+}
--- /dev/null
+/*
+ * 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>
+*/
+
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+
+#include <pcap.h>
+#include <pthread.h>
+#include <sys/select.h>
+
+namespace STG
+{
+
+struct Users;
+struct Tariffs;
+struct Admins;
+struct TraffCounter;
+struct Settings;
+
+}
+
+struct DEV
+{
+ DEV() : device("any"), filterExpression("ip"), handle(NULL), fd(-1) {}
+ DEV(const std::string & d) : device(d), filterExpression("ip"), handle(NULL), fd(-1) {}
+ DEV(const std::string & d, const std::string & f)
+ : device(d), filterExpression(f), handle(NULL), fd(-1) {}
+
+ std::string device;
+ std::string filterExpression;
+ pcap_t * handle;
+ struct bpf_program filter;
+ int fd;
+};
+
+typedef std::vector<DEV> DEV_MAP;
+
+class PCAP_CAP : public STG::Plugin {
+public:
+ PCAP_CAP();
+
+ void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return isRunning; }
+
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override;
+ uint16_t GetStartPosition() const override { return 40; }
+ uint16_t GetStopPosition() const override { return 40; }
+
+private:
+ PCAP_CAP(const PCAP_CAP & rvalue);
+ PCAP_CAP & operator=(const PCAP_CAP & rvalue);
+
+ void TryRead(const fd_set & set);
+ void TryReadDev(const DEV & dev);
+
+ static void * Run(void *);
+
+ mutable std::string errorStr;
+
+ pthread_t thread;
+ bool nonstop;
+ bool isRunning;
+ STG::ModuleSettings settings;
+ DEV_MAP devices;
+
+ STG::TraffCounter * traffCnt;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+#include "admins_methods.h"
+#include "rpcconfig.h"
+
+#include "stg/common.h"
+
+#include "stg/admins.h"
+#include "stg/admin.h"
+#include "stg/admin_conf.h"
+
+#include <ostream> // xmlrpc-c devs have missed something :)
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_GET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(login, &admin))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+structVal["result"] = xmlrpc_c::value_boolean(true);
+structVal["login"] = xmlrpc_c::value_string(admin->login());
+structVal["password"] = xmlrpc_c::value_string(admin->password());
+
+const auto priv = admin->priv();
+
+structVal["user_stat"] = xmlrpc_c::value_boolean(priv.userStat);
+structVal["user_conf"] = xmlrpc_c::value_boolean(priv.userConf);
+structVal["user_cash"] = xmlrpc_c::value_boolean(priv.userCash);
+structVal["user_passwd"] = xmlrpc_c::value_boolean(priv.userPasswd);
+structVal["user_add_del"] = xmlrpc_c::value_boolean(priv.userAddDel);
+structVal["admin_chg"] = xmlrpc_c::value_boolean(priv.adminChg);
+structVal["tariff_chg"] = xmlrpc_c::value_boolean(priv.tariffChg);
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_ADD::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Not logged or cookie timeout'\n");
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Invalid admin (logged)'\n");
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (admins->add(login, *admin))
+ {
+ printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Failed to add admin'\n");
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_DEL::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (admins->del(login, *admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_CHG::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+xmlrpc_c::value_struct info(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * loggedAdmin;
+
+if (admins->find(adminInfo.admin, &loggedAdmin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(login, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::AdminConf conf;
+
+conf.priv = admin->priv();
+conf.password = admin->password();
+conf.login = login;
+
+std::map<std::string, xmlrpc_c::value> structVal = info;
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = structVal.find("password")) != structVal.end())
+ {
+ conf.password = xmlrpc_c::value_string(it->second);
+ }
+
+if ((it = structVal.find("user_stat")) != structVal.end())
+ {
+ conf.priv.userStat = xmlrpc_c::value_boolean(it->second);
+ }
+
+if ((it = structVal.find("user_conf")) != structVal.end())
+ {
+ conf.priv.userConf = xmlrpc_c::value_boolean(it->second);
+ }
+
+if ((it = structVal.find("user_cash")) != structVal.end())
+ {
+ conf.priv.userCash = xmlrpc_c::value_boolean(it->second);
+ }
+
+if ((it = structVal.find("user_passwd")) != structVal.end())
+ {
+ conf.priv.userPasswd = xmlrpc_c::value_boolean(it->second);
+ }
+
+if ((it = structVal.find("user_add_del")) != structVal.end())
+ {
+ conf.priv.userAddDel = xmlrpc_c::value_boolean(it->second);
+ }
+
+if ((it = structVal.find("admin_chg")) != structVal.end())
+ {
+ conf.priv.adminChg = xmlrpc_c::value_boolean(it->second);
+ }
+
+if ((it = structVal.find("tariff_chg")) != structVal.end())
+ {
+ conf.priv.tariffChg = xmlrpc_c::value_boolean(it->second);
+ }
+
+if (admins->change(conf, *loggedAdmin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMINS_GET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> mainStructVal;
+std::vector<xmlrpc_c::value> retval;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ mainStructVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(mainStructVal);
+ return;
+ }
+
+admins->fmap([&retval](const auto& admin)
+ {
+ const std::map<std::string, xmlrpc_c::value> structVal{
+ {"result", xmlrpc_c::value_boolean(true)},
+ {"login", xmlrpc_c::value_string(admin.login())},
+ {"password", xmlrpc_c::value_string(admin.password())},
+ {"user_stat", xmlrpc_c::value_boolean(admin.priv().userStat)},
+ {"user_conf", xmlrpc_c::value_boolean(admin.priv().userConf)},
+ {"user_cash", xmlrpc_c::value_boolean(admin.priv().userCash)},
+ {"user_passwd", xmlrpc_c::value_boolean(admin.priv().userPasswd)},
+ {"user_add_del", xmlrpc_c::value_boolean(admin.priv().userAddDel)},
+ {"admin_chg", xmlrpc_c::value_boolean(admin.priv().adminChg)},
+ {"tariff_chg", xmlrpc_c::value_boolean(admin.priv().tariffChg)}
+ };
+ retval.push_back(xmlrpc_c::value_struct(structVal));
+ });
+
+*retvalPtr = xmlrpc_c::value_array(retval);
+}
--- /dev/null
+#pragma once
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+namespace STG
+{
+
+struct Admins;
+
+}
+
+class RPC_CONFIG;
+
+class METHOD_ADMIN_GET : public xmlrpc_c::method {
+public:
+ METHOD_ADMIN_GET(RPC_CONFIG * c,
+ STG::Admins * a)
+ : config(c),
+ admins(a)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_ADMIN_GET(const METHOD_ADMIN_GET & rvalue);
+ METHOD_ADMIN_GET & operator=(const METHOD_ADMIN_GET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+};
+
+class METHOD_ADMIN_ADD : public xmlrpc_c::method {
+public:
+ METHOD_ADMIN_ADD(RPC_CONFIG * c,
+ STG::Admins * a)
+ : config(c),
+ admins(a)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_ADMIN_ADD(const METHOD_ADMIN_ADD & rvalue);
+ METHOD_ADMIN_ADD & operator=(const METHOD_ADMIN_ADD & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+};
+
+class METHOD_ADMIN_DEL : public xmlrpc_c::method {
+public:
+ METHOD_ADMIN_DEL(RPC_CONFIG * c,
+ STG::Admins * a)
+ : config(c),
+ admins(a)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_ADMIN_DEL(const METHOD_ADMIN_DEL & rvalue);
+ METHOD_ADMIN_DEL & operator=(const METHOD_ADMIN_DEL & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+};
+
+class METHOD_ADMIN_CHG : public xmlrpc_c::method {
+public:
+ METHOD_ADMIN_CHG(RPC_CONFIG * c,
+ STG::Admins * a)
+ : config(c),
+ admins(a)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_ADMIN_CHG(const METHOD_ADMIN_CHG & rvalue);
+ METHOD_ADMIN_CHG & operator=(const METHOD_ADMIN_CHG & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+};
+
+class METHOD_ADMINS_GET : public xmlrpc_c::method {
+public:
+ METHOD_ADMINS_GET(RPC_CONFIG * c,
+ STG::Admins * a)
+ : config(c),
+ admins(a)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_ADMINS_GET(const METHOD_ADMINS_GET & rvalue);
+ METHOD_ADMINS_GET & operator=(const METHOD_ADMINS_GET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+};
--- /dev/null
+#include "info_methods.h"
+#include "rpcconfig.h"
+
+#include "stg/users.h"
+#include "stg/tariffs.h"
+#include "stg/version.h"
+#include "stg/common.h"
+#include "stg/const.h"
+
+#include <ostream> // xmlrpc-c devs have missed something :)
+
+#include <sys/utsname.h>
+
+void METHOD_INFO::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+paramList.verifyEnd(0);
+std::map<std::string, xmlrpc_c::value> structVal;
+
+std::string un;
+struct utsname utsn;
+
+uname(&utsn);
+un[0] = 0;
+
+un += utsn.sysname;
+un += " ";
+un += utsn.release;
+un += " ";
+un += utsn.machine;
+un += " ";
+un += utsn.nodename;
+
+structVal["version"] = xmlrpc_c::value_string(SERVER_VERSION);
+structVal["tariff_num"] = xmlrpc_c::value_int(static_cast<int>(tariffs->Count()));
+structVal["tariff"] = xmlrpc_c::value_int(2);
+structVal["users_num"] = xmlrpc_c::value_int(static_cast<int>(users->Count()));
+structVal["uname"] = xmlrpc_c::value_string(un);
+structVal["dir_num"] = xmlrpc_c::value_int(DIR_NUM);
+structVal["day_fee"] = xmlrpc_c::value_int(static_cast<int>(dayFee));
+
+std::vector<xmlrpc_c::value> dirnameVal;
+
+for (int i = 0; i< DIR_NUM; i++)
+ {
+ dirnameVal.push_back(xmlrpc_c::value_string(IconvString(dirNames[i], "KOI8-RU", "UTF-8")));
+ }
+
+structVal["dir_names"] = xmlrpc_c::value_array(dirnameVal);
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+void METHOD_LOGIN::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string login = paramList.getString(0);
+std::string password = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+
+std::string cookie;
+if (config->CheckAdmin(login, password, &cookie))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ structVal["cookie"] = xmlrpc_c::value_string("");
+ }
+else
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(true);
+ structVal["cookie"] = xmlrpc_c::value_string(cookie);
+ }
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+void METHOD_LOGOUT::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+if (config->LogoutAdmin(cookie))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ }
+else
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(true);
+ }
+}
--- /dev/null
+#pragma once
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+#include <string>
+#include <vector>
+
+namespace STG
+{
+
+struct Settings;
+struct Users;
+struct Tariffs;
+
+}
+
+// Forward declaration
+class RPC_CONFIG;
+
+class METHOD_INFO : public xmlrpc_c::method
+{
+public:
+ METHOD_INFO(STG::Tariffs * t,
+ STG::Users * u,
+ size_t df,
+ const std::vector<std::string> & dn)
+ : tariffs(t),
+ users(u),
+ dayFee(df),
+ dirNames(dn)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_INFO(const METHOD_INFO & rvalue);
+ METHOD_INFO & operator=(const METHOD_INFO & rvalue);
+
+ STG::Tariffs * tariffs;
+ STG::Users * users;
+ size_t dayFee;
+ const std::vector<std::string> & dirNames;
+};
+
+class METHOD_LOGIN : public xmlrpc_c::method
+{
+public:
+ explicit METHOD_LOGIN(RPC_CONFIG * c)
+ : config(c)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_LOGIN(const METHOD_LOGIN & rvalue);
+ METHOD_LOGIN & operator=(const METHOD_LOGIN & rvalue);
+
+ RPC_CONFIG * config;
+};
+
+class METHOD_LOGOUT : public xmlrpc_c::method
+{
+public:
+ explicit METHOD_LOGOUT(RPC_CONFIG * c)
+ : config(c)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_LOGOUT(const METHOD_LOGOUT & rvalue);
+ METHOD_LOGOUT & operator=(const METHOD_LOGOUT & rvalue);
+
+ RPC_CONFIG * config;
+};
--- /dev/null
+#include "messages_methods.h"
+#include "rpcconfig.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/message.h"
+#include "stg/common.h"
+
+#include <ostream> // xmlrpc-c devs have missed something :)
+
+extern volatile time_t stgTime;
+
+//------------------------------------------------------------------------------
+
+void METHOD_MESSAGE_SEND::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::vector<xmlrpc_c::value> logins(paramList.getArray(1));
+std::map<std::string, xmlrpc_c::value> msgInfo(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Message message;
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = msgInfo.find("version")) == msgInfo.end())
+ {
+ message.header.ver = 1; // Default value
+ }
+else
+ {
+ message.header.ver = xmlrpc_c::value_int(it->second);
+ }
+
+if ((it = msgInfo.find("type")) == msgInfo.end())
+ {
+ message.header.type = 1; // default value
+ }
+else
+ {
+ message.header.type = xmlrpc_c::value_int(it->second);
+ }
+
+if ((it = msgInfo.find("repeat")) == msgInfo.end())
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+message.header.repeat = xmlrpc_c::value_int(it->second);
+
+if ((it = msgInfo.find("repeat_period")) == msgInfo.end())
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+message.header.repeatPeriod = xmlrpc_c::value_int(it->second);
+
+if ((it = msgInfo.find("show_time")) == msgInfo.end())
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+message.header.showTime = xmlrpc_c::value_int(it->second);
+
+if ((it = msgInfo.find("text")) == msgInfo.end())
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+message.text = IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "CP1251");
+
+message.header.creationTime = static_cast<int>(stgTime);
+message.header.lastSendTime = 0;
+
+std::vector<xmlrpc_c::value>::iterator lit;
+for (lit = logins.begin(); lit != logins.end(); ++lit)
+ {
+ using UserPtr = STG::User*;
+ UserPtr ui;
+ if (users->FindByName(xmlrpc_c::value_string(*lit), &ui))
+ {
+ printfd(__FILE__, "METHOD_MESSAGE_SEND::execute(): 'User '%s' not found'\n", std::string(xmlrpc_c::value_string(*lit)).c_str());
+ }
+ else
+ {
+ ui->AddMessage(&message);
+ }
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
--- /dev/null
+#pragma once
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+namespace STG
+{
+
+struct Users;
+
+}
+
+class RPC_CONFIG;
+
+class METHOD_MESSAGE_SEND : public xmlrpc_c::method {
+public:
+ METHOD_MESSAGE_SEND(RPC_CONFIG * c,
+ STG::Users * u)
+ : config(c),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_MESSAGE_SEND(const METHOD_MESSAGE_SEND & rvalue);
+ METHOD_MESSAGE_SEND & operator=(const METHOD_MESSAGE_SEND & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Users * users;
+};
--- /dev/null
+#include "rpcconfig.h"
+
+#include "info_methods.h"
+#include "users_methods.h"
+#include "tariffs_methods.h"
+#include "admins_methods.h"
+#include "messages_methods.h"
+
+#include "stg/admins.h"
+#include "stg/admin.h"
+#include "stg/module_settings.h"
+#include "stg/settings.h"
+#include "stg/common.h"
+#include "stg/const.h"
+
+#include <algorithm>
+#include <vector>
+#include <ostream> // xmlrpc-c devs have missed something :)
+#include <cstdlib>
+#include <csignal>
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+RPC_CONFIG_SETTINGS::RPC_CONFIG_SETTINGS()
+ : port(0),
+ cookieTimeout(0)
+{
+}
+
+int RPC_CONFIG_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+STG::ParamValue pv;
+pv.param = "Port";
+std::vector<STG::ParamValue>::const_iterator pvi;
+pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Port\' not found.";
+ printfd(__FILE__, "Parameter 'Port' not found\n");
+ return -1;
+ }
+int p;
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+ {
+ errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+ return -1;
+ }
+port = static_cast<uint16_t>(p);
+
+pv.param = "CookieTimeout";
+pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ cookieTimeout = 1800; // 30 * 60
+ }
+else
+ {
+ if (str2x(pvi->value[0], cookieTimeout))
+ {
+ errorStr = "Incorrect value of CookieTimeout: \'" + pvi->value[0] + "\'";
+ printfd(__FILE__, "Incorrect value of 'CookieTimeout'\n");
+ return -1;
+ }
+ }
+
+return 0;
+}
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static RPC_CONFIG plugin;
+ return &plugin;
+}
+
+RPC_CONFIG::RPC_CONFIG()
+ : users(NULL),
+ admins(NULL),
+ tariffs(NULL),
+ store(NULL),
+ fd(-1),
+ rpcServer(NULL),
+ running(false),
+ stopped(true),
+ dayFee(0),
+ logger(STG::PluginLogger::get("conf_rpc"))
+{
+}
+
+RPC_CONFIG::~RPC_CONFIG()
+{
+// delete server
+delete rpcServer;
+}
+
+int RPC_CONFIG::ParseSettings()
+{
+int ret = rpcConfigSettings.ParseSettings(settings);
+
+if (ret)
+ errorStr = rpcConfigSettings.GetStrError();
+
+return ret;
+}
+
+void RPC_CONFIG::SetStgSettings(const STG::Settings * s)
+{
+ dayFee = s->GetDayFee();
+ dirNames.erase(dirNames.begin(), dirNames.end());
+ for (size_t i = 0; i < DIR_NUM; ++i) {
+ dirNames.push_back(s->GetDirName(i));
+ }
+}
+
+int RPC_CONFIG::Start()
+{
+InitiateRegistry();
+running = true;
+
+fd = socket(AF_INET, SOCK_STREAM, 0);
+if (fd < 0)
+ {
+ errorStr = "Failed to create socket";
+ logger("Cannot create a socket: %s", strerror(errno));
+ printfd(__FILE__, "Failed to create listening socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+int flag = 1;
+
+if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
+ {
+ errorStr = "Setsockopt failed.";
+ logger("setsockopt error: %s", strerror(errno));
+ printfd(__FILE__, "Setsockopt failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+struct sockaddr_in addr;
+addr.sin_family = AF_INET;
+addr.sin_port = htons(rpcConfigSettings.GetPort());
+addr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
+ {
+ logger("Cannot bind the socket: %s", strerror(errno));
+ errorStr = "Failed to bind socket";
+ printfd(__FILE__, "Failed to bind listening socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+if (listen(fd, 10))
+ {
+ logger("Cannot listen the socket: %s", strerror(errno));
+ errorStr = "Failed to listen socket";
+ printfd(__FILE__, "Failed to listen listening socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+rpcServer = new xmlrpc_c::serverAbyss(
+ xmlrpc_c::serverAbyss::constrOpt()
+ .registryP(&rpcRegistry)
+ .logFileName("/var/log/stargazer_rpc.log")
+ .socketFd(fd)
+ );
+
+if (pthread_create(&tid, NULL, Run, this))
+ {
+ errorStr = "Failed to create RPC thread";
+ logger("Cannot create RPC thread.");
+ printfd(__FILE__, "Failed to crate RPC thread\n");
+ return -1;
+ }
+
+return 0;
+}
+
+int RPC_CONFIG::Stop()
+{
+running = false;
+for (int i = 0; i < 5 && !stopped; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+if (!stopped)
+ {
+ running = true;
+ logger("Cannot stop RPC thread.");
+ printfd(__FILE__, "Failed to stop RPC thread\n");
+ errorStr = "Failed to stop RPC thread";
+ return -1;
+ }
+else
+ {
+ pthread_join(tid, NULL);
+ }
+
+close(fd);
+
+return 0;
+}
+
+void * RPC_CONFIG::Run(void * rc)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+RPC_CONFIG * config = static_cast<RPC_CONFIG *>(rc);
+
+config->stopped = false;
+while (config->running)
+ {
+ if (WaitPackets(config->fd))
+ config->rpcServer->runOnce();
+ }
+config->stopped = true;
+
+return NULL;
+}
+
+bool RPC_CONFIG::GetAdminInfo(const std::string & cookie,
+ ADMIN_INFO * info)
+{
+std::map<std::string,
+ ADMIN_INFO>::iterator it;
+
+it = cookies.find(cookie);
+
+if (it == cookies.end())
+ {
+ return true;
+ }
+
+if (difftime(it->second.accessTime, time(NULL)) >
+ rpcConfigSettings.GetCookieTimeout())
+ {
+ cookies.erase(it);
+ return true;
+ }
+
+// Update access time
+time(&it->second.accessTime);
+*info = it->second;
+return false;
+}
+
+bool RPC_CONFIG::CheckAdmin(const std::string & login,
+ const std::string & password,
+ std::string * cookie)
+{
+STG::Admin * admin = NULL;
+
+if (!admins->correct(login, password, &admin))
+ {
+ logger("Attempt to connect with invalid credentials. Login: %s", login.c_str());
+ return true;
+ }
+
+ADMIN_INFO info;
+time(&info.accessTime);
+info.admin = login;
+info.priviledges = admin->priv();
+*cookie = GetCookie();
+cookies[*cookie] = info;
+
+return false;
+}
+
+bool RPC_CONFIG::LogoutAdmin(const std::string & cookie)
+{
+std::map<std::string,
+ ADMIN_INFO>::iterator it;
+
+it = cookies.find(cookie);
+
+if (it == cookies.end())
+ {
+ return true;
+ }
+
+cookies.erase(it);
+
+return false;
+}
+
+std::string RPC_CONFIG::GetCookie() const
+{
+std::string charset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
+std::string cookie;
+
+for (int i = 0; i < 64; ++i)
+ {
+ cookie += charset[rand() % charset.length()];
+ };
+
+return cookie;
+}
+
+void RPC_CONFIG::InitiateRegistry()
+{
+// manage registry
+xmlrpc_c::methodPtr const methodInfoPtr(new METHOD_INFO(
+ tariffs,
+ users,
+ dayFee,
+ dirNames
+ ));
+rpcRegistry.addMethod("stargazer.info", methodInfoPtr);
+
+xmlrpc_c::methodPtr const methodLoginPtr(new METHOD_LOGIN(
+ this
+ ));
+rpcRegistry.addMethod("stargazer.login", methodLoginPtr);
+
+xmlrpc_c::methodPtr const methodLogoutPtr(new METHOD_LOGOUT(
+ this
+ ));
+rpcRegistry.addMethod("stargazer.logout", methodLogoutPtr);
+
+xmlrpc_c::methodPtr const methodGetUserPtr(new METHOD_USER_GET(
+ this,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.get_user", methodGetUserPtr);
+
+xmlrpc_c::methodPtr const methodAddUserPtr(new METHOD_USER_ADD(
+ this,
+ admins,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.add_user", methodAddUserPtr);
+
+xmlrpc_c::methodPtr const methodDelUserPtr(new METHOD_USER_DEL(
+ this,
+ admins,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.del_user", methodDelUserPtr);
+
+xmlrpc_c::methodPtr const methodGetUsersPtr(new METHOD_USERS_GET(
+ this,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.get_users", methodGetUsersPtr);
+
+xmlrpc_c::methodPtr const methodChgUserPtr(new METHOD_USER_CHG(
+ this,
+ admins,
+ tariffs,
+ store,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.chg_user", methodChgUserPtr);
+
+xmlrpc_c::methodPtr const methodAddCashPtr(new METHOD_USER_CASH_ADD(
+ this,
+ admins,
+ store,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.add_user_cash", methodAddCashPtr);
+
+xmlrpc_c::methodPtr const methodSetCashPtr(new METHOD_USER_CASH_SET(
+ this,
+ admins,
+ store,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.set_user_cash", methodSetCashPtr);
+
+xmlrpc_c::methodPtr const methodTariffChangePtr(new METHOD_USER_TARIFF_CHANGE(
+ this,
+ admins,
+ tariffs,
+ store,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.chg_user_tariff", methodTariffChangePtr);
+
+xmlrpc_c::methodPtr const methodGetTariffPtr(new METHOD_TARIFF_GET(
+ this,
+ tariffs
+ ));
+rpcRegistry.addMethod("stargazer.get_tariff", methodGetTariffPtr);
+
+xmlrpc_c::methodPtr const methodChgTariffPtr(new METHOD_TARIFF_CHG(
+ this,
+ admins,
+ tariffs
+ ));
+rpcRegistry.addMethod("stargazer.chg_tariff", methodChgTariffPtr);
+
+xmlrpc_c::methodPtr const methodGetTariffsPtr(new METHOD_TARIFFS_GET(
+ this,
+ tariffs
+ ));
+rpcRegistry.addMethod("stargazer.get_tariffs", methodGetTariffsPtr);
+
+xmlrpc_c::methodPtr const methodAddTariffPtr(new METHOD_TARIFF_ADD(
+ this,
+ admins,
+ tariffs
+ ));
+rpcRegistry.addMethod("stargazer.add_tariff", methodAddTariffPtr);
+
+xmlrpc_c::methodPtr const methodDelTariffPtr(new METHOD_TARIFF_DEL(
+ this,
+ admins,
+ tariffs,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.del_tariff", methodDelTariffPtr);
+
+xmlrpc_c::methodPtr const methodGetAdminPtr(new METHOD_ADMIN_GET(
+ this,
+ admins
+ ));
+rpcRegistry.addMethod("stargazer.get_admin", methodGetAdminPtr);
+
+xmlrpc_c::methodPtr const methodAddAdminPtr(new METHOD_ADMIN_ADD(
+ this,
+ admins
+ ));
+rpcRegistry.addMethod("stargazer.add_admin", methodAddAdminPtr);
+
+xmlrpc_c::methodPtr const methodDelAdminPtr(new METHOD_ADMIN_DEL(
+ this,
+ admins
+ ));
+rpcRegistry.addMethod("stargazer.del_admin", methodDelAdminPtr);
+
+xmlrpc_c::methodPtr const methodChgAdminPtr(new METHOD_ADMIN_CHG(
+ this,
+ admins
+ ));
+rpcRegistry.addMethod("stargazer.chg_admin", methodChgAdminPtr);
+
+xmlrpc_c::methodPtr const methodGetAdminsPtr(new METHOD_ADMINS_GET(
+ this,
+ admins
+ ));
+rpcRegistry.addMethod("stargazer.get_admins", methodGetAdminsPtr);
+
+xmlrpc_c::methodPtr const methodSendMessagePtr(new METHOD_MESSAGE_SEND(
+ this,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.send_user_message", methodSendMessagePtr);
+
+xmlrpc_c::methodPtr const methodGetOnlinIPsPtr(new METHOD_GET_ONLINE_IPS(
+ this,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.get_online_ips", methodGetOnlinIPsPtr);
+
+xmlrpc_c::methodPtr const methodGetUserAuthByPtr(new METHOD_GET_USER_AUTH_BY(
+ this,
+ users
+ ));
+rpcRegistry.addMethod("stargazer.get_user_auth_by", methodGetUserAuthByPtr);
+}
+
--- /dev/null
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/admin_conf.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+#include <xmlrpc-c/server_abyss.hpp>
+
+#include <ctime>
+#include <cstdint>
+#include <string>
+#include <map>
+#include <vector>
+
+#include <pthread.h>
+
+#define RPC_CONFIG_VERSION "Stargazer RPC v. 0.2"
+
+namespace STG
+{
+
+struct Admins;
+struct Tariffs;
+struct Users;
+struct Store;
+
+}
+
+class RPC_CONFIG_SETTINGS
+{
+public:
+ RPC_CONFIG_SETTINGS();
+ virtual ~RPC_CONFIG_SETTINGS() {}
+ const std::string & GetStrError() const { return errorStr; }
+ int ParseSettings(const STG::ModuleSettings & s);
+ uint16_t GetPort() const { return port; }
+ double GetCookieTimeout() const { return cookieTimeout; }
+
+private:
+ std::string errorStr;
+ uint16_t port;
+ double cookieTimeout;
+};
+
+struct ADMIN_INFO
+{
+ ADMIN_INFO()
+ : admin(),
+ accessTime(0),
+ priviledges()
+ {}
+
+ std::string admin;
+ time_t accessTime;
+ STG::Priv priviledges;
+};
+
+class RPC_CONFIG : public STG::Plugin
+{
+public:
+ RPC_CONFIG();
+ ~RPC_CONFIG() override;
+
+ void SetUsers(STG::Users * u) override { users = u; }
+ void SetTariffs(STG::Tariffs * t) override { tariffs = t; }
+ void SetAdmins(STG::Admins * a) override { admins = a; }
+ void SetStore(STG::Store * s) override { store = s; }
+ void SetStgSettings(const STG::Settings * s) override;
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return running && !stopped; }
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override { return RPC_CONFIG_VERSION; }
+ uint16_t GetStartPosition() const override { return 20; }
+ uint16_t GetStopPosition() const override { return 20; }
+
+ bool GetAdminInfo(const std::string & cookie,
+ ADMIN_INFO * info);
+ bool CheckAdmin(const std::string & login,
+ const std::string & password,
+ std::string * cookie);
+ bool LogoutAdmin(const std::string & cookie);
+
+private:
+ RPC_CONFIG(const RPC_CONFIG & rvalue);
+ RPC_CONFIG & operator=(const RPC_CONFIG & rvalue);
+
+ static void * Run(void *);
+ std::string GetCookie() const;
+ void InitiateRegistry();
+
+ mutable std::string errorStr;
+ RPC_CONFIG_SETTINGS rpcConfigSettings;
+ STG::Users * users;
+ STG::Admins * admins;
+ STG::Tariffs * tariffs;
+ STG::Store * store;
+ STG::ModuleSettings settings;
+ int fd;
+ xmlrpc_c::registry rpcRegistry;
+ xmlrpc_c::serverAbyss * rpcServer;
+ bool running;
+ bool stopped;
+ pthread_t tid;
+ std::map<std::string,
+ ADMIN_INFO> cookies;
+ size_t dayFee;
+ std::vector<std::string> dirNames;
+ STG::PluginLogger logger;
+};
--- /dev/null
+#include "tariff_helper.h"
+
+#include "stg/tariff_conf.h"
+#include "stg/common.h"
+#include "stg/const.h"
+
+#include <ostream> // xmlrpc-c devs have missed something :)
+
+void TARIFF_HELPER::GetTariffInfo(xmlrpc_c::value * info) const
+{
+std::map<std::string, xmlrpc_c::value> structVal;
+
+structVal["result"] = xmlrpc_c::value_boolean(true);
+structVal["name"] = xmlrpc_c::value_string(data.tariffConf.name);
+structVal["fee"] = xmlrpc_c::value_double(data.tariffConf.fee);
+structVal["freemb"] = xmlrpc_c::value_double(data.tariffConf.free);
+structVal["passivecost"] = xmlrpc_c::value_double(data.tariffConf.passiveCost);
+structVal["traffType"] = xmlrpc_c::value_int(data.tariffConf.traffType);
+structVal["period"] = xmlrpc_c::value_string(STG::Tariff::toString(data.tariffConf.period));
+structVal["changePolicy"] = xmlrpc_c::value_string(STG::Tariff::toString(data.tariffConf.changePolicy));
+structVal["changePolicyTimeout"] = xmlrpc_c::value_string(formatTime(data.tariffConf.changePolicyTimeout));
+
+std::vector<xmlrpc_c::value> prices(DIR_NUM);
+
+for (unsigned i = 0; i < DIR_NUM; ++i)
+ {
+ std::map<std::string, xmlrpc_c::value> dirPrice;
+ dirPrice["hday"] = xmlrpc_c::value_int(data.dirPrice[i].hDay);
+ dirPrice["mday"] = xmlrpc_c::value_int(data.dirPrice[i].mDay);
+ dirPrice["hnight"] = xmlrpc_c::value_int(data.dirPrice[i].hNight);
+ dirPrice["mnight"] = xmlrpc_c::value_int(data.dirPrice[i].mNight);
+ dirPrice["pricedaya"] = xmlrpc_c::value_double(data.dirPrice[i].priceDayA * 1024 * 1024);
+ dirPrice["pricedayb"] = xmlrpc_c::value_double(data.dirPrice[i].priceDayB * 1024 * 1024);
+ dirPrice["pricenighta"] = xmlrpc_c::value_double(data.dirPrice[i].priceNightA * 1024 * 1024);
+ dirPrice["pricenightb"] = xmlrpc_c::value_double(data.dirPrice[i].priceNightB * 1024 * 1024);
+ dirPrice["threshold"] = xmlrpc_c::value_int(data.dirPrice[i].threshold);
+ dirPrice["singleprice"] = xmlrpc_c::value_boolean(data.dirPrice[i].singlePrice);
+ dirPrice["nodiscount"] = xmlrpc_c::value_boolean(data.dirPrice[i].noDiscount);
+ prices[i] = xmlrpc_c::value_struct(dirPrice);
+ }
+
+structVal["dirprices"] = xmlrpc_c::value_array(prices);
+
+*info = xmlrpc_c::value_struct(structVal);
+}
+
+bool TARIFF_HELPER::SetTariffInfo(const xmlrpc_c::value & info)
+{
+std::map<std::string, xmlrpc_c::value> structVal(
+ static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
+ );
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = structVal.find("fee")) != structVal.end())
+ {
+ data.tariffConf.fee = xmlrpc_c::value_double(it->second);
+ }
+
+if ((it = structVal.find("freemb")) != structVal.end())
+ {
+ data.tariffConf.free = xmlrpc_c::value_double(it->second);
+ }
+
+if ((it = structVal.find("passivecost")) != structVal.end())
+ {
+ data.tariffConf.passiveCost = xmlrpc_c::value_double(it->second);
+ }
+
+if ((it = structVal.find("traffType")) != structVal.end())
+ {
+ data.tariffConf.traffType = static_cast<STG::Tariff::TraffType>(xmlrpc_c::value_int(it->second).cvalue());
+ }
+
+if ((it = structVal.find("period")) != structVal.end())
+ {
+ data.tariffConf.period = STG::Tariff::parsePeriod(xmlrpc_c::value_string(it->second));
+ }
+
+if ((it = structVal.find("changePolicy")) != structVal.end())
+ {
+ data.tariffConf.changePolicy = STG::Tariff::parseChangePolicy(xmlrpc_c::value_string(it->second));
+ }
+
+if ((it = structVal.find("changePolicyTimeout")) != structVal.end())
+ {
+ data.tariffConf.changePolicyTimeout = readTime(xmlrpc_c::value_string(it->second));
+ }
+
+if ((it = structVal.find("dirprices")) != structVal.end())
+ {
+ std::vector<xmlrpc_c::value> prices(
+ xmlrpc_c::value_array(it->second).vectorValueValue()
+ );
+
+ for (unsigned i = 0; i < DIR_NUM; ++i)
+ {
+ std::map<std::string, xmlrpc_c::value> dirPrice(
+ static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(prices[i]))
+ );
+ data.dirPrice[i].mDay = xmlrpc_c::value_int(dirPrice["mday"]);
+ data.dirPrice[i].hDay = xmlrpc_c::value_int(dirPrice["hday"]);
+ data.dirPrice[i].mNight = xmlrpc_c::value_int(dirPrice["mnight"]);
+ data.dirPrice[i].hNight = xmlrpc_c::value_int(dirPrice["hnight"]);
+ data.dirPrice[i].priceDayA = xmlrpc_c::value_double(dirPrice["pricedaya"]) / 1024 / 1024;
+ data.dirPrice[i].priceDayB = xmlrpc_c::value_double(dirPrice["pricedayb"]) / 1024 / 1024;
+ data.dirPrice[i].priceNightA = xmlrpc_c::value_double(dirPrice["pricenighta"]) / 1024 / 1024;
+ data.dirPrice[i].priceNightB = xmlrpc_c::value_double(dirPrice["pricenightb"]) / 1024 / 1024;
+ data.dirPrice[i].threshold = xmlrpc_c::value_int(dirPrice["threshold"]);
+ data.dirPrice[i].singlePrice = xmlrpc_c::value_boolean(dirPrice["singleprice"]);
+ data.dirPrice[i].noDiscount = xmlrpc_c::value_boolean(dirPrice["nodiscount"]);
+ }
+ }
+
+return false;
+}
--- /dev/null
+#pragma once
+
+#include <xmlrpc-c/base.hpp>
+
+namespace STG
+{
+
+struct TariffData;
+
+}
+
+class TARIFF_HELPER
+{
+public:
+ explicit TARIFF_HELPER(STG::TariffData & td)
+ : data(td)
+ {}
+
+ void GetTariffInfo(xmlrpc_c::value * info) const;
+ bool SetTariffInfo(const xmlrpc_c::value & info);
+private:
+ STG::TariffData & data;
+};
--- /dev/null
+#include <ostream> // xmlrpc-c devs have missed something :)
+
+#include "tariffs_methods.h"
+#include "rpcconfig.h"
+#include "tariff_helper.h"
+
+#include "stg/tariffs.h"
+#include "stg/tariff.h"
+#include "stg/tariff_conf.h"
+#include "stg/users.h"
+#include "stg/admins.h"
+#include "stg/admin.h"
+
+void METHOD_TARIFF_GET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string name = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+const auto tariff = tariffs->FindByName(name);
+
+if (!tariff)
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+auto td = tariff->GetTariffData();
+
+TARIFF_HELPER helper(td);
+
+helper.GetTariffInfo(retvalPtr);
+}
+
+void METHOD_TARIFF_CHG::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string name = paramList.getString(1);
+xmlrpc_c::value_struct info(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+const auto tariff = tariffs->FindByName(name);
+
+if (!tariff)
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+auto td = tariff->GetTariffData();
+
+TARIFF_HELPER helper(td);
+
+helper.SetTariffInfo(info);
+
+if (tariffs->Chg(td, admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+void METHOD_TARIFFS_GET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+std::vector<xmlrpc_c::value> tariffsInfo;
+
+
+std::vector<STG::TariffData> dataList;
+tariffs->GetTariffsData(&dataList);
+auto it = dataList.begin();
+for (; it != dataList.end(); ++it)
+ {
+ xmlrpc_c::value info;
+ auto td = *it; // 'cause TARIFF_HELPER work in both ways and take not const referense
+ TARIFF_HELPER helper(td);
+ helper.GetTariffInfo(&info);
+ tariffsInfo.push_back(info);
+ }
+
+*retvalPtr = xmlrpc_c::value_array(tariffsInfo);
+}
+
+void METHOD_TARIFF_ADD::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string tariff = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (tariffs->Add(tariff, admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+void METHOD_TARIFF_DEL::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string tariff = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (users->TariffInUse(tariff))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (tariffs->Del(tariff, admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
--- /dev/null
+#pragma once
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+namespace STG
+{
+
+struct Tariffs;
+struct Users;
+struct Admins;
+
+}
+
+class RPC_CONFIG;
+
+class METHOD_TARIFF_GET : public xmlrpc_c::method {
+public:
+ METHOD_TARIFF_GET(RPC_CONFIG * c,
+ STG::Tariffs * t)
+ : config(c),
+ tariffs(t)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_TARIFF_GET(const METHOD_TARIFF_GET & rvalue);
+ METHOD_TARIFF_GET & operator=(const METHOD_TARIFF_GET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Tariffs * tariffs;
+};
+
+class METHOD_TARIFF_CHG : public xmlrpc_c::method {
+public:
+ METHOD_TARIFF_CHG(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Tariffs * t)
+ : config(c),
+ admins(a),
+ tariffs(t)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_TARIFF_CHG(const METHOD_TARIFF_CHG & rvalue);
+ METHOD_TARIFF_CHG & operator=(const METHOD_TARIFF_CHG & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Tariffs * tariffs;
+};
+
+class METHOD_TARIFFS_GET : public xmlrpc_c::method {
+public:
+ METHOD_TARIFFS_GET(RPC_CONFIG * c,
+ STG::Tariffs * t)
+ : config(c),
+ tariffs(t)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr);
+
+private:
+ METHOD_TARIFFS_GET(const METHOD_TARIFFS_GET & rvalue);
+ METHOD_TARIFFS_GET & operator=(const METHOD_TARIFFS_GET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Tariffs * tariffs;
+};
+
+class METHOD_TARIFF_ADD : public xmlrpc_c::method {
+public:
+ METHOD_TARIFF_ADD(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Tariffs * t)
+ : config(c),
+ admins(a),
+ tariffs(t)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_TARIFF_ADD(const METHOD_TARIFF_ADD & rvalue);
+ METHOD_TARIFF_ADD & operator=(const METHOD_TARIFF_ADD & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Tariffs * tariffs;
+};
+
+class METHOD_TARIFF_DEL : public xmlrpc_c::method {
+public:
+ METHOD_TARIFF_DEL(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Tariffs * t,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ tariffs(t),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_TARIFF_DEL(const METHOD_TARIFF_DEL & rvalue);
+ METHOD_TARIFF_DEL & operator=(const METHOD_TARIFF_DEL & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Tariffs * tariffs;
+ STG::Users * users;
+};
--- /dev/null
+#include "user_helper.h"
+
+#include "stg/tariffs.h"
+#include "stg/tariff.h"
+#include "stg/admin.h"
+#include "stg/store.h"
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/user_ips.h"
+#include "stg/user_property.h"
+#include "stg/common.h"
+#include "stg/const.h"
+
+#include <cmath>
+
+//------------------------------------------------------------------------------
+
+void USER_HELPER::GetUserInfo(xmlrpc_c::value * info,
+ bool hidePassword)
+{
+std::map<std::string, xmlrpc_c::value> structVal;
+
+structVal["result"] = xmlrpc_c::value_boolean(true);
+structVal["login"] = xmlrpc_c::value_string(ptr->GetLogin());
+
+if (!hidePassword)
+ {
+ structVal["password"] = xmlrpc_c::value_string(ptr->GetProperties().password.Get());
+ }
+else
+ {
+ structVal["password"] = xmlrpc_c::value_string("++++++++");
+ }
+
+structVal["cash"] = xmlrpc_c::value_double(ptr->GetProperties().cash.Get());
+structVal["freemb"] = xmlrpc_c::value_double(ptr->GetProperties().freeMb.Get());
+structVal["credit"] = xmlrpc_c::value_double(ptr->GetProperties().credit.Get());
+
+if (ptr->GetProperties().nextTariff.Get() != "")
+ {
+ structVal["tariff"] = xmlrpc_c::value_string(
+ ptr->GetProperties().tariffName.Get() +
+ "/" +
+ ptr->GetProperties().nextTariff.Get()
+ );
+ }
+else
+ {
+ structVal["tariff"] = xmlrpc_c::value_string(ptr->GetProperties().tariffName.Get());
+ }
+
+structVal["note"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().note, "KOI8-RU", "UTF-8"));
+
+structVal["phone"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().phone, "KOI8-RU", "UTF-8"));
+
+structVal["address"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().address, "KOI8-RU", "UTF-8"));
+
+structVal["email"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().email, "KOI8-RU", "UTF-8"));
+
+std::vector<xmlrpc_c::value> userdata;
+
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata0.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata1.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata2.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata3.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata4.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata5.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata6.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata7.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata8.Get(), "KOI8-RU", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata9.Get(), "KOI8-RU", "UTF-8")));
+
+structVal["userdata"] = xmlrpc_c::value_array(userdata);
+
+structVal["name"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().realName, "KOI8-RU", "UTF-8"));
+
+structVal["group"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().group, "KOI8-RU", "UTF-8"));
+
+structVal["status"] = xmlrpc_c::value_boolean(ptr->GetConnected());
+structVal["aonline"] = xmlrpc_c::value_boolean(ptr->GetProperties().alwaysOnline.Get());
+structVal["currip"] = xmlrpc_c::value_string(inet_ntostring(ptr->GetCurrIP()));
+structVal["pingtime"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetPingTime()));
+structVal["ips"] = xmlrpc_c::value_string(ptr->GetProperties().ips.Get().toString());
+
+std::map<std::string, xmlrpc_c::value> traffInfo;
+std::vector<xmlrpc_c::value> mu(DIR_NUM);
+std::vector<xmlrpc_c::value> md(DIR_NUM);
+std::vector<xmlrpc_c::value> su(DIR_NUM);
+std::vector<xmlrpc_c::value> sd(DIR_NUM);
+
+auto upload = ptr->GetProperties().up.Get();
+auto download = ptr->GetProperties().down.Get();
+auto supload = ptr->GetSessionUpload();
+auto sdownload = ptr->GetSessionDownload();
+
+for (int j = 0; j < DIR_NUM; j++)
+ {
+ mu[j] = xmlrpc_c::value_string(std::to_string(upload[j]));
+ md[j] = xmlrpc_c::value_string(std::to_string(download[j]));
+ su[j] = xmlrpc_c::value_string(std::to_string(supload[j]));
+ sd[j] = xmlrpc_c::value_string(std::to_string(sdownload[j]));
+ }
+
+traffInfo["mu"] = xmlrpc_c::value_array(mu);
+traffInfo["md"] = xmlrpc_c::value_array(md);
+traffInfo["su"] = xmlrpc_c::value_array(su);
+traffInfo["sd"] = xmlrpc_c::value_array(sd);
+
+structVal["traff"] = xmlrpc_c::value_struct(traffInfo);
+
+structVal["down"] = xmlrpc_c::value_boolean(ptr->GetProperties().disabled.Get());
+structVal["disableddetailstat"] = xmlrpc_c::value_boolean(ptr->GetProperties().disabledDetailStat.Get());
+structVal["passive"] = xmlrpc_c::value_boolean(ptr->GetProperties().passive.Get());
+structVal["lastcash"] = xmlrpc_c::value_double(ptr->GetProperties().lastCashAdd.Get());
+structVal["lasttimecash"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetProperties().lastCashAddTime.Get()));
+structVal["lastactivitytime"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetProperties().lastActivityTime.Get()));
+structVal["creditexpire"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetProperties().creditExpire.Get()));
+
+*info = xmlrpc_c::value_struct(structVal);
+}
+
+//------------------------------------------------------------------------------
+
+bool USER_HELPER::SetUserInfo(const xmlrpc_c::value & info,
+ const STG::Admin& admin,
+ const std::string & login,
+ const STG::Store & store,
+ STG::Tariffs * tariffs)
+{
+std::map<std::string, xmlrpc_c::value> structVal(
+ static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
+ );
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+bool check = false;
+bool alwaysOnline = ptr->GetProperties().alwaysOnline;
+if ((it = structVal.find("aonline")) != structVal.end())
+ {
+ check = true;
+ alwaysOnline = xmlrpc_c::value_boolean(it->second);
+ }
+bool onlyOneIP = ptr->GetProperties().ips.ConstData().onlyOneIP();
+if ((it = structVal.find("ips")) != structVal.end())
+ {
+ check = true;
+ onlyOneIP = STG::UserIPs::parse(xmlrpc_c::value_string(it->second)).onlyOneIP();
+ }
+
+if (check && alwaysOnline && !onlyOneIP)
+ {
+ printfd(__FILE__, "Requested change leads to a forbidden state: AlwaysOnline with multiple IP's\n");
+ return true;
+ }
+
+if ((it = structVal.find("ips")) != structVal.end())
+ {
+ auto ips = STG::UserIPs::parse(xmlrpc_c::value_string(it->second));
+
+ for (size_t i = 0; i < ips.count(); ++i)
+ {
+ using ConstUserPtr = const STG::User*;
+ ConstUserPtr user;
+ uint32_t ip = ips[i].ip;
+ if (users.IsIPInUse(ip, login, &user))
+ {
+ printfd(__FILE__, "Trying to assign an IP %s to '%s' that is already in use by '%s'\n", inet_ntostring(ip).c_str(), login.c_str(), user->GetLogin().c_str());
+ return true;
+ }
+ }
+
+ if (!ptr->GetProperties().ips.Set(ips, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("aonline")) != structVal.end())
+ {
+ bool value(xmlrpc_c::value_boolean(it->second));
+ if (ptr->GetProperties().alwaysOnline.Get() != value)
+ if (!ptr->GetProperties().alwaysOnline.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("password")) != structVal.end())
+ {
+ std::string value(xmlrpc_c::value_string(it->second));
+ if (ptr->GetProperties().password.Get() != value)
+ if (!ptr->GetProperties().password.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("address")) != structVal.end())
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
+ if (ptr->GetProperties().address.Get() != value)
+ if (!ptr->GetProperties().address.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("phone")) != structVal.end())
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
+ if (ptr->GetProperties().phone.Get() != value)
+ if (!ptr->GetProperties().phone.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("email")) != structVal.end())
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
+ if (ptr->GetProperties().email.Get() != value)
+ if (!ptr->GetProperties().email.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("cash")) != structVal.end())
+ {
+ double value(xmlrpc_c::value_double(it->second));
+ if (std::fabs(ptr->GetProperties().cash.Get() - value) > 1.0e-3)
+ if (!ptr->GetProperties().cash.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("creditexpire")) != structVal.end())
+ {
+ time_t value(xmlrpc_c::value_int(it->second));
+ if (ptr->GetProperties().creditExpire.Get() != value)
+ if (!ptr->GetProperties().creditExpire.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("credit")) != structVal.end())
+ {
+ double value(xmlrpc_c::value_double(it->second));
+ if (std::fabs(ptr->GetProperties().credit.Get() - value) > 1.0e-3)
+ if (!ptr->GetProperties().credit.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("freemb")) != structVal.end())
+ {
+ double value(xmlrpc_c::value_double(it->second));
+ if (std::fabs(ptr->GetProperties().freeMb.Get() - value) > 1.0e-3)
+ if (!ptr->GetProperties().freeMb.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("down")) != structVal.end())
+ {
+ bool value(xmlrpc_c::value_boolean(it->second));
+ if (ptr->GetProperties().disabled.Get() != value)
+ if (!ptr->GetProperties().disabled.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("passive")) != structVal.end())
+ {
+ bool value(xmlrpc_c::value_boolean(it->second));
+ if (ptr->GetProperties().passive.Get() != value)
+ if (!ptr->GetProperties().passive.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("disableddetailstat")) != structVal.end())
+ {
+ bool value(xmlrpc_c::value_boolean(it->second));
+ if (ptr->GetProperties().disabledDetailStat.Get() != value)
+ if (!ptr->GetProperties().disabledDetailStat.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("name")) != structVal.end())
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
+ if (ptr->GetProperties().realName.Get() != value)
+ if (!ptr->GetProperties().realName.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("group")) != structVal.end())
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
+ if (ptr->GetProperties().group.Get() != value)
+ if (!ptr->GetProperties().group.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("note")) != structVal.end())
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
+ if (ptr->GetProperties().note.Get() != value)
+ if (!ptr->GetProperties().note.Set(value, admin, login, store))
+ return true;
+ }
+
+if ((it = structVal.find("userdata")) != structVal.end())
+ {
+ std::vector<STG::UserPropertyLogged<std::string> *> userdata;
+ userdata.push_back(ptr->GetProperties().userdata0.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata1.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata2.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata3.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata4.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata5.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata6.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata7.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata8.GetPointer());
+ userdata.push_back(ptr->GetProperties().userdata9.GetPointer());
+
+ std::vector<xmlrpc_c::value> udata(
+ xmlrpc_c::value_array(it->second).vectorValueValue()
+ );
+
+ for (unsigned i = 0; i < userdata.size(); ++i)
+ {
+ std::string value(IconvString(xmlrpc_c::value_string(udata[i]), "UTF-8", "KOI8-RU"));
+ if (userdata[i]->Get() != value)
+ if (!userdata[i]->Set(value, admin, login, store))
+ return true;
+ }
+ }
+
+if ((it = structVal.find("traff")) != structVal.end())
+ {
+ std::map<std::string, xmlrpc_c::value> traff(
+ static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(it->second))
+ );
+
+ auto dtData = ptr->GetProperties().up.Get();
+ if ((it = traff.find("mu")) != traff.end())
+ {
+ std::vector<xmlrpc_c::value> data(xmlrpc_c::value_array(it->second).vectorValueValue());
+
+ for (int i = 0; i < std::min(DIR_NUM, static_cast<int>(data.size())); ++i)
+ {
+ int64_t value;
+ if (str2x(xmlrpc_c::value_string(data[i]), value))
+ printfd(__FILE__, "USER_HELPER::SetUserInfo(): 'Invalid month upload value'\n");
+ else
+ dtData[i] = value;
+ }
+ if (!ptr->GetProperties().up.Set(dtData, admin, login, store))
+ return true;
+ }
+ dtData = ptr->GetProperties().down.Get();
+ if ((it = traff.find("md")) != traff.end())
+ {
+ std::vector<xmlrpc_c::value> data(xmlrpc_c::value_array(it->second).vectorValueValue());
+
+ for (int i = 0; i < std::min(DIR_NUM, static_cast<int>(data.size())); ++i)
+ {
+ int64_t value;
+ if (str2x(xmlrpc_c::value_string(data[i]), value))
+ printfd(__FILE__, "USER_HELPER::SetUserInfo(): 'Invalid month download value'\n");
+ else
+ dtData[i] = value;
+ }
+ if (!ptr->GetProperties().down.Set(dtData, admin, login, store))
+ return true;
+ }
+ }
+
+if ((it = structVal.find("tariff")) != structVal.end())
+ {
+ std::string tariff(xmlrpc_c::value_string(it->second));
+ size_t pos = tariff.find('/');
+ std::string nextTariff;
+ if (pos != std::string::npos)
+ {
+ nextTariff = tariff.substr(pos + 1);
+ tariff = tariff.substr(0, pos);
+ }
+
+ const auto newTariff = tariffs->FindByName(tariff);
+ if (newTariff)
+ {
+ const auto currentTariff = ptr->GetTariff();
+ std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime);
+ if (message.empty())
+ {
+ if (ptr->GetProperties().tariffName.Get() != tariff)
+ {
+ if (!ptr->GetProperties().tariffName.Set(tariff, admin, login, store))
+ return true;
+ }
+ }
+ else
+ {
+ STG::PluginLogger::get("conf_rpc")("Tariff change is prohibited for user %s. %s", ptr->GetLogin().c_str(), message.c_str());
+ }
+ }
+
+ if (nextTariff != "" &&
+ tariffs->FindByName(nextTariff))
+ if (ptr->GetProperties().nextTariff.Get() != nextTariff)
+ if (!ptr->GetProperties().nextTariff.Set(tariff, admin, login, store))
+ return true;
+ }
+
+return false;
+}
--- /dev/null
+#pragma once
+
+#include <string>
+
+#include <xmlrpc-c/base.hpp>
+
+namespace STG
+{
+
+struct Admin;
+struct Store;
+struct Tariffs;
+struct User;
+struct Users;
+
+}
+
+class USER_HELPER
+{
+public:
+ using UserPtr = STG::User*;
+ USER_HELPER(UserPtr & p, STG::Users & us)
+ : ptr(p),
+ users(us)
+ {
+ }
+
+ void GetUserInfo(xmlrpc_c::value * info,
+ bool hidePassword = false);
+ bool SetUserInfo(const xmlrpc_c::value & info,
+ const STG::Admin& admin,
+ const std::string & login,
+ const STG::Store & store,
+ STG::Tariffs * tariffs);
+private:
+ UserPtr & ptr;
+ STG::Users & users;
+};
--- /dev/null
+#include "users_methods.h"
+#include "rpcconfig.h"
+#include "user_helper.h"
+
+#include "stg/users.h"
+#include "stg/admins.h"
+#include "stg/tariffs.h"
+#include "stg/tariff.h"
+#include "stg/user.h"
+#include "stg/user_property.h"
+#include "stg/common.h"
+
+#include <cerrno>
+
+using UserPtr = STG::User*;
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_GET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+USER_HELPER uhelper(u, *users);
+
+if (!adminInfo.priviledges.userConf || !adminInfo.priviledges.userPasswd)
+ {
+ uhelper.GetUserInfo(retvalPtr, true);
+ return;
+ }
+
+uhelper.GetUserInfo(retvalPtr);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_ADD::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin = NULL;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ if (users->Add(login, admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+ *retvalPtr = xmlrpc_c::value_boolean(true);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(false);
+return;
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_DEL::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+UserPtr u;
+
+if (!users->FindByName(login, &u))
+ {
+ users->Del(login, admin);
+ *retvalPtr = xmlrpc_c::value_boolean(true);
+ return;
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(false);
+return;
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USERS_GET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+std::vector<xmlrpc_c::value> retval;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+bool hidePassword = !adminInfo.priviledges.userConf ||
+ !adminInfo.priviledges.userPasswd;
+
+UserPtr u;
+
+int h = users->OpenSearch();
+if (!h)
+ {
+ printfd(__FILE__, "users->OpenSearch() error\n");
+ users->CloseSearch(h);
+ return;
+ }
+
+while (1)
+ {
+ if (users->SearchNext(h, &u))
+ {
+ break;
+ }
+
+ xmlrpc_c::value info;
+
+ USER_HELPER uhelper(u, *users);
+
+ uhelper.GetUserInfo(&info, hidePassword);
+
+ retval.push_back(info);
+ }
+
+*retvalPtr = xmlrpc_c::value_array(retval);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_CHG::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+xmlrpc_c::value_struct info(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+USER_HELPER uhelper(u, *users);
+
+if (!adminInfo.priviledges.userConf || !adminInfo.priviledges.userPasswd)
+ {
+ uhelper.SetUserInfo(info, *admin, login, *store, tariffs);
+ }
+else
+ {
+ uhelper.SetUserInfo(info, *admin, login, *store, tariffs);
+ }
+
+u->WriteConf();
+u->WriteStat();
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_CASH_ADD::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+double amount = paramList.getDouble(2);
+std::string comment = IconvString(paramList.getString(3), "UTF-8", "KOI8-R");
+paramList.verifyEnd(4);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+double cash = u->GetProperties().cash.Get();
+cash += amount;
+
+if (!u->GetProperties().cash.Set(cash, *admin, login, *store, comment))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+u->WriteStat();
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_CASH_SET::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+double cash = paramList.getDouble(2);
+std::string comment = IconvString(paramList.getString(3), "UTF-8", "KOI8-R");
+paramList.verifyEnd(4);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (!u->GetProperties().cash.Set(cash, *admin, login, *store, comment))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+u->WriteStat();
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_TARIFF_CHANGE::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+std::string tariff = paramList.getString(2);
+bool delayed = paramList.getBoolean(3);
+std::string comment = IconvString(paramList.getString(4), "UTF-8", "KOI8-R");
+paramList.verifyEnd(5);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+STG::Admin * admin;
+
+if (admins->find(adminInfo.admin, &admin))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ *retvalPtr = xmlrpc_c::value_boolean(false);
+ return;
+ }
+
+if (tariffs->FindByName(tariff))
+ {
+ if (delayed)
+ {
+ if (u->GetProperties().nextTariff.Set(tariff, *admin, login, *store, comment))
+ {
+ u->WriteConf();
+ *retvalPtr = xmlrpc_c::value_boolean(true);
+ return;
+ }
+ }
+ else
+ {
+ const auto newTariff = tariffs->FindByName(tariff);
+ if (newTariff)
+ {
+ const auto currentTariff = u->GetTariff();
+ std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime);
+ if (message.empty())
+ {
+ if (u->GetProperties().tariffName.Set(tariff, *admin, login, *store, comment))
+ {
+ u->ResetNextTariff();
+ u->WriteConf();
+ *retvalPtr = xmlrpc_c::value_boolean(true);
+ return;
+ }
+ }
+ else
+ {
+ STG::PluginLogger::get("conf_rpc")("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str());
+ }
+ }
+ }
+ }
+
+*retvalPtr = xmlrpc_c::value_boolean(false);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_GET_ONLINE_IPS::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+typedef std::vector<xmlrpc_c::value> ValueVector;
+ValueVector subnetsStr = paramList.getArray(1);
+paramList.verifyEnd(2);
+
+std::vector<STG::IPMask> subnets;
+
+for (ValueVector::const_iterator it(subnetsStr.begin()); it != subnetsStr.end(); ++it)
+ {
+ STG::IPMask ipm;
+ if (ParseNet(xmlrpc_c::value_string(*it), ipm))
+ {
+ printfd(__FILE__, "METHOD_GET_ONLINE_IPS::execute(): Failed to parse subnet ('%s')\n", std::string(xmlrpc_c::value_string(*it)).c_str());
+ }
+ else
+ {
+ subnets.push_back(ipm);
+ }
+ }
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+ValueVector ips;
+
+UserPtr u;
+
+int handle = users->OpenSearch();
+if (!handle)
+ {
+ printfd(__FILE__, "users->OpenSearch() error\n");
+ users->CloseSearch(handle);
+ return;
+ }
+
+while (1)
+ {
+ if (users->SearchNext(handle, &u))
+ {
+ break;
+ }
+
+ if (u->GetAuthorized())
+ {
+ uint32_t ip = u->GetCurrIP();
+
+ for (std::vector<STG::IPMask>::const_iterator it(subnets.begin()); it != subnets.end(); ++it)
+ {
+ if ((it->ip & it->mask) == (ip & it->mask))
+ {
+ ips.push_back(xmlrpc_c::value_string(inet_ntostring(u->GetCurrIP())));
+ break;
+ }
+ }
+ }
+ }
+
+structVal["ips"] = xmlrpc_c::value_array(ips);
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+bool METHOD_GET_ONLINE_IPS::ParseNet(const std::string & net, STG::IPMask & ipm) const
+{
+size_t pos = net.find_first_of('/');
+
+if (pos == std::string::npos)
+ {
+ printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Network address is not in CIDR-notation\n");
+ return true;
+ }
+
+int res = inet_pton(AF_INET, net.substr(0, pos).c_str(), &ipm.ip);
+
+if (res < 0)
+ {
+ printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): '%s'\n", strerror(errno));
+ return true;
+ }
+else if (res == 0)
+ {
+ printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Invalid network address\n", strerror(errno));
+ return true;
+ }
+
+if (str2x(net.substr(pos + 1, net.length() - pos - 1), ipm.mask))
+ {
+ printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Invalid network mask\n");
+ return true;
+ }
+if (ipm.mask > 32)
+ {
+ printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Network mask is out of range\n");
+ return true;
+ }
+ipm.mask = htonl(0xffFFffFF << (32 - ipm.mask));
+
+return false;
+}
+
+void METHOD_GET_USER_AUTH_BY::execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+UserPtr u;
+
+if (users->FindByName(login, &u))
+ {
+ structVal["result"] = xmlrpc_c::value_boolean(false);
+ *retvalPtr = xmlrpc_c::value_struct(structVal);
+ return;
+ }
+
+std::vector<std::string> list(u->GetAuthorizers());
+std::vector<xmlrpc_c::value> authList;
+for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
+ authList.push_back(xmlrpc_c::value_string(*it));
+*retvalPtr = xmlrpc_c::value_array(authList);
+}
--- /dev/null
+#pragma once
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+namespace STG
+{
+
+struct Admins;
+struct Tariffs;
+struct Users;
+struct Store;
+struct IPMask;
+
+}
+
+class RPC_CONFIG;
+
+class METHOD_USER_GET : public xmlrpc_c::method {
+public:
+ METHOD_USER_GET(RPC_CONFIG * c,
+ STG::Users * u)
+ : config(c),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_GET(const METHOD_USER_GET & rvalue);
+ METHOD_USER_GET & operator=(const METHOD_USER_GET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Users * users;
+};
+
+class METHOD_USER_ADD : public xmlrpc_c::method {
+public:
+ METHOD_USER_ADD(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_ADD(const METHOD_USER_ADD & rvalue);
+ METHOD_USER_ADD & operator=(const METHOD_USER_ADD & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Users * users;
+};
+
+class METHOD_USER_DEL : public xmlrpc_c::method {
+public:
+ METHOD_USER_DEL(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_DEL(const METHOD_USER_DEL & rvalue);
+ METHOD_USER_DEL & operator=(const METHOD_USER_DEL & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Users * users;
+};
+
+class METHOD_USERS_GET : public xmlrpc_c::method {
+public:
+ METHOD_USERS_GET(RPC_CONFIG * c,
+ STG::Users * u)
+ : config(c),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USERS_GET(const METHOD_USERS_GET & rvalue);
+ METHOD_USERS_GET & operator=(const METHOD_USERS_GET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Users * users;
+};
+
+class METHOD_USER_CHG : public xmlrpc_c::method {
+public:
+ METHOD_USER_CHG(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Tariffs * t,
+ STG::Store * s,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ tariffs(t),
+ store(s),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_CHG(const METHOD_USER_CHG & rvalue);
+ METHOD_USER_CHG & operator=(const METHOD_USER_CHG & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Tariffs * tariffs;
+ STG::Store * store;
+ STG::Users * users;
+};
+
+class METHOD_USER_CASH_ADD : public xmlrpc_c::method {
+public:
+ METHOD_USER_CASH_ADD(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Store * s,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ store(s),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_CASH_ADD(const METHOD_USER_CASH_ADD & rvalue);
+ METHOD_USER_CASH_ADD & operator=(const METHOD_USER_CASH_ADD & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Store * store;
+ STG::Users * users;
+};
+
+class METHOD_USER_CASH_SET : public xmlrpc_c::method {
+public:
+ METHOD_USER_CASH_SET(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Store * s,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ store(s),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_CASH_SET(const METHOD_USER_CASH_SET & rvalue);
+ METHOD_USER_CASH_SET & operator=(const METHOD_USER_CASH_SET & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Store * store;
+ STG::Users * users;
+};
+
+class METHOD_USER_TARIFF_CHANGE : public xmlrpc_c::method {
+public:
+ METHOD_USER_TARIFF_CHANGE(RPC_CONFIG * c,
+ STG::Admins * a,
+ STG::Tariffs * t,
+ STG::Store * s,
+ STG::Users * u)
+ : config(c),
+ admins(a),
+ tariffs(t),
+ store(s),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_USER_TARIFF_CHANGE(const METHOD_USER_TARIFF_CHANGE & rvalue);
+ METHOD_USER_TARIFF_CHANGE & operator=(const METHOD_USER_TARIFF_CHANGE & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Admins * admins;
+ STG::Tariffs * tariffs;
+ STG::Store * store;
+ STG::Users * users;
+};
+
+class METHOD_GET_ONLINE_IPS : public xmlrpc_c::method {
+public:
+ METHOD_GET_ONLINE_IPS(RPC_CONFIG * c,
+ STG::Users * u)
+ : config(c),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_GET_ONLINE_IPS(const METHOD_GET_ONLINE_IPS & rvalue);
+ METHOD_GET_ONLINE_IPS & operator=(const METHOD_GET_ONLINE_IPS & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Users * users;
+
+ bool ParseNet(const std::string & net, STG::IPMask & ipm) const;
+};
+
+class METHOD_GET_USER_AUTH_BY : public xmlrpc_c::method {
+public:
+ METHOD_GET_USER_AUTH_BY(RPC_CONFIG * c,
+ STG::Users * u)
+ : config(c),
+ users(u)
+ {
+ }
+
+ void execute(xmlrpc_c::paramList const & paramList,
+ xmlrpc_c::value * const retvalP);
+
+private:
+ METHOD_GET_USER_AUTH_BY(const METHOD_GET_ONLINE_IPS & rvalue);
+ METHOD_GET_USER_AUTH_BY & operator=(const METHOD_GET_ONLINE_IPS & rvalue);
+
+ RPC_CONFIG * config;
+ STG::Users * users;
+};
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "configproto.h"
+
+#include "conn.h"
+
+#include "parser_server_info.h"
+#include "parser_admins.h"
+#include "parser_tariffs.h"
+#include "parser_users.h"
+#include "parser_services.h"
+#include "parser_message.h"
+#include "parser_user_info.h"
+#include "parser_auth_by.h"
+
+#include "stg/common.h"
+#include "stg/logger.h"
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <csignal>
+#include <cstring>
+#include <cerrno>
+#include <cassert>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+namespace SP = STG::PARSER;
+
+CONFIGPROTO::CONFIGPROTO(STG::PluginLogger & l)
+ : m_settings(NULL),
+ m_admins(NULL),
+ m_tariffs(NULL),
+ m_users(NULL),
+ m_services(NULL),
+ m_corporations(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::~CONFIGPROTO()
+{
+ {
+ std::deque<STG::Conn *>::iterator it;
+ for (it = m_conns.begin(); it != m_conns.end(); ++it)
+ delete *it;
+ }
+ {
+ BASE_PARSER::REGISTRY::iterator it;
+ for (it = m_registry.begin(); it != m_registry.end(); ++it)
+ delete it->second;
+ }
+}
+
+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)
+ {
+ m_errorStr = std::string("Cannot create listen socket: '") + strerror(errno) + "'.";
+ m_logger(m_errorStr);
+ return -1;
+ }
+
+ int dummy = 1;
+
+ if (setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &dummy, 4) != 0)
+ {
+ 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;
+}
+
+int CONFIGPROTO::Stop()
+{
+ m_running = false;
+ for (int i = 0; i < 5 && !m_stopped; ++i)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+ if (!m_stopped)
+ {
+ m_errorStr = "Cannot stop listenign thread.";
+ m_logger(m_errorStr);
+ return -1;
+ }
+
+ shutdown(m_listenSocket, SHUT_RDWR);
+ close(m_listenSocket);
+ return 0;
+}
+
+void CONFIGPROTO::Run()
+{
+ 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_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;
+}
+
+bool CONFIGPROTO::Bind()
+{
+ const hostent * he = gethostbyname(m_bindAddress.c_str());
+ if (he == NULL)
+ {
+ 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<in_addr_t *>(*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<sockaddr *>(&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;
+}
+
+void CONFIGPROTO::RegisterParsers()
+{
+ assert(m_settings != NULL);
+ assert(m_store != NULL);
+ assert(m_admins != NULL);
+ assert(m_users != NULL);
+ assert(m_tariffs != NULL);
+ assert(m_services != NULL);
+ assert(m_corporations != NULL);
+
+ SP::GET_SERVER_INFO::FACTORY::Register(m_registry, *m_settings, *m_users, *m_tariffs);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ SP::GET_SERVICES::FACTORY::Register(m_registry, *m_services);
+ SP::GET_SERVICE::FACTORY::Register(m_registry, *m_services);
+ SP::ADD_SERVICE::FACTORY::Register(m_registry, *m_services);
+ SP::DEL_SERVICE::FACTORY::Register(m_registry, *m_services);
+ SP::CHG_SERVICE::FACTORY::Register(m_registry, *m_services);
+
+ SP::SEND_MESSAGE::FACTORY::Register(m_registry, *m_users);
+
+ SP::AUTH_BY::FACTORY::Register(m_registry, *m_users);
+
+ SP::USER_INFO::FACTORY::Register(m_registry, *m_users);
+}
+
+int CONFIGPROTO::MaxFD() const
+{
+ 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;
+}
+
+void CONFIGPROTO::BuildFDSet(fd_set & fds) const
+{
+ 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);
+}
+
+void CONFIGPROTO::CleanupConns()
+{
+ 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());
+}
+
+void CONFIGPROTO::HandleEvents(const fd_set & fds)
+{
+ 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();
+ }
+}
+
+void CONFIGPROTO::AcceptConnection()
+{
+ struct sockaddr_in outerAddr;
+ socklen_t outerAddrLen(sizeof(outerAddr));
+ int sock = accept(m_listenSocket, reinterpret_cast<sockaddr *>(&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() + "'.");
+ }
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/module_settings.h"
+
+#include <string>
+#include <deque>
+#include <cstdint>
+
+#include <sys/select.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace STG
+{
+
+struct Settings;
+struct Admins;
+struct Tariffs;
+struct Users;
+struct Services;
+struct Corporations;
+struct Store;
+class PluginLogger;
+
+class Conn;
+
+}
+
+class CONFIGPROTO {
+public:
+ explicit CONFIGPROTO(STG::PluginLogger & l);
+ ~CONFIGPROTO();
+
+ void SetPort(uint16_t port) { m_port = port; }
+ void SetBindAddress(const std::string & address) { m_bindAddress = address; }
+ void SetSettings(const STG::Settings * settings) { m_settings = settings; }
+ void SetAdmins(STG::Admins * admins) { m_admins = admins; }
+ void SetTariffs(STG::Tariffs * tariffs) { m_tariffs = tariffs; }
+ void SetUsers(STG::Users * users) { m_users = users; }
+ void SetStore(STG::Store * store) { m_store = store; }
+ void SetServices(STG::Services * services) { m_services = services; }
+ void SetCorporations(STG::Corporations * corporations) { m_corporations = corporations; }
+
+ int Prepare();
+ int Stop();
+ const std::string & GetStrError() const { return m_errorStr; }
+ void Run();
+
+private:
+ CONFIGPROTO(const CONFIGPROTO & rvalue);
+ CONFIGPROTO & operator=(const CONFIGPROTO & rvalue);
+
+ const STG::Settings * m_settings;
+ STG::Admins * m_admins;
+ STG::Tariffs * m_tariffs;
+ STG::Users * m_users;
+ STG::Services * m_services;
+ STG::Corporations * m_corporations;
+ STG::Store * m_store;
+
+ uint16_t m_port;
+ std::string m_bindAddress;
+ bool m_running;
+ bool m_stopped;
+ STG::PluginLogger & m_logger;
+ int m_listenSocket;
+
+ std::string m_errorStr;
+
+ BASE_PARSER::REGISTRY m_registry;
+ std::deque<STG::Conn *> m_conns;
+
+ bool Bind();
+
+ void RegisterParsers();
+
+ int MaxFD() const;
+ void BuildFDSet(fd_set & fds) const;
+ void CleanupConns();
+ void HandleEvents(const fd_set & fds);
+ void AcceptConnection();
+};
--- /dev/null
+/*
+ * 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 "conn.h"
+
+#include "stg/admins.h"
+#include "stg/admin.h"
+#include "stg/logger.h"
+#include "stg/blowfish.h"
+#include "stg/bfstream.h"
+#include "stg/common.h"
+
+#include <cassert>
+#include <cstring>
+#include <cerrno>
+
+#include <unistd.h>
+#include <sys/socket.h>
+
+using STG::Conn;
+
+const char Conn::STG_HEADER[] = "SG04";
+const char Conn::OK_HEADER[] = "OKHD";
+const char Conn::ERR_HEADER[] = "ERHD";
+const char Conn::OK_LOGIN[] = "OKLG";
+const char Conn::ERR_LOGIN[] = "ERLG";
+const char Conn::OK_LOGINS[] = "OKLS";
+const char Conn::ERR_LOGINS[] = "ERLS";
+
+Conn::Conn(const BASE_PARSER::REGISTRY & registry,
+ Admins & admins, int sock, const sockaddr_in& addr,
+ PluginLogger & logger)
+ : m_registry(registry),
+ m_admins(admins),
+ m_admin(NULL),
+ m_sock(sock),
+ m_addr(addr),
+ m_keepAlive(false),
+ m_parser(NULL),
+ m_xmlParser(XML_ParserCreate(NULL)),
+ m_state(HEADER),
+ m_buffer(m_header),
+ m_bufferSize(sizeof(m_header)),
+ m_stream(NULL),
+ m_logger(logger),
+#ifdef DUMPCRYPTO
+ m_dataState(false, *this),
+ m_dumper(endpoint())
+#else
+ m_dataState(false, *this)
+#endif
+{
+ if (m_xmlParser == NULL)
+ throw Error("Failed to create XML parser.");
+
+ XML_ParserReset(m_xmlParser, NULL);
+ XML_SetElementHandler(m_xmlParser, ParseXMLStart, ParseXMLEnd);
+ XML_SetUserData(m_xmlParser, this);
+}
+
+Conn::~Conn()
+{
+ shutdown(m_sock, SHUT_RDWR);
+ close(m_sock);
+
+ XML_ParserFree(m_xmlParser);
+
+ delete m_stream;
+ delete m_parser;
+}
+
+bool Conn::Read()
+{
+ ssize_t res = read(m_sock, m_buffer, m_bufferSize);
+ if (res < 0)
+ {
+ m_state = ERROR;
+ Log(__FILE__, "Failed to read data from " + endpoint() + ". Reason: '" + strerror(errno) + "'");
+ return false;
+ }
+ if (res == 0 && m_state != DATA) // EOF is ok for data.
+ {
+ m_state = ERROR;
+ Log(__FILE__, "Failed to read data from " + endpoint() + ". Unexpected EOF.");
+ return false;
+ }
+#ifdef DUMPCRYPTO
+ m_dumper.write(m_buffer, res);
+#endif
+ m_bufferSize -= res;
+ m_buffer = static_cast<char*>(m_buffer) + res;
+ return HandleBuffer(res);
+}
+
+bool Conn::WriteAnswer(const void* buffer, size_t size)
+{
+ ssize_t res = write(m_sock, buffer, size);
+ if (res < 0)
+ {
+ m_state = ERROR;
+ Log(__FILE__, "Failed to write data to " + endpoint() + ". Reason: '" + strerror(errno) + "'.");
+ return false;
+ }
+ return true;
+}
+
+BASE_PARSER * Conn::GetParser(const std::string & tag) const
+{
+ BASE_PARSER::REGISTRY::const_iterator it = m_registry.find(ToLower(tag));
+ if (it == m_registry.end())
+ return NULL;
+ return it->second->create(*m_admin);
+}
+
+bool Conn::HandleBuffer(size_t size)
+{
+ if (m_state == DATA)
+ return HandleData(size);
+
+ if (m_bufferSize > 0)
+ return true;
+
+ switch (m_state)
+ {
+ case HEADER: return HandleHeader();
+ case LOGIN: return HandleLogin();
+ case CRYPTO_LOGIN: return HandleCryptoLogin();
+ default: return true;
+ }
+
+ return true;
+}
+
+bool Conn::HandleHeader()
+{
+ if (strncmp(m_header, STG_HEADER, sizeof(m_header)) != 0)
+ {
+ Log(__FILE__, "Received invalid header from " + endpoint() + ".");
+ WriteAnswer(ERR_HEADER, sizeof(ERR_HEADER) - 1); // Without \0
+ m_state = ERROR;
+ return false;
+ }
+ m_state = LOGIN;
+ m_buffer = m_login;
+ m_bufferSize = sizeof(m_login);
+ return WriteAnswer(OK_HEADER, sizeof(OK_HEADER) - 1); // Without \0
+}
+
+bool Conn::HandleLogin()
+{
+ if (m_admins.find(m_login, &m_admin)) // ADMINS::Find returns true on error.
+ {
+ std::string login(m_login, strnlen(m_login, sizeof(m_login)));
+ Log(__FILE__, "Received invalid login '" + ToPrintable(login) + "' from " + endpoint() + ".");
+ WriteAnswer(ERR_LOGIN, sizeof(ERR_LOGIN) - 1); // Without \0
+ m_state = ERROR;
+ return false;
+ }
+ m_admin->setIP(IP());
+ m_state = CRYPTO_LOGIN;
+ m_buffer = m_cryptoLogin;
+ m_bufferSize = sizeof(m_cryptoLogin);
+ return WriteAnswer(OK_LOGIN, sizeof(OK_LOGIN) - 1); // Without \0
+}
+
+bool Conn::HandleCryptoLogin()
+{
+ char login[ADM_LOGIN_LEN + 1];
+ BLOWFISH_CTX ctx;
+ InitContext(m_admin->password().c_str(), ADM_PASSWD_LEN, &ctx);
+ DecryptString(login, m_cryptoLogin, ADM_LOGIN_LEN, &ctx);
+
+ if (strncmp(m_login, login, sizeof(login)) != 0)
+ {
+ Log(__FILE__, "Attempt to connect with wrong password from " + m_admin->login() + "@" + endpoint() + ".");
+ WriteAnswer(ERR_LOGINS, sizeof(ERR_LOGINS) - 1); // Without \0
+ m_state = ERROR;
+ return false;
+ }
+
+ m_state = DATA;
+ m_buffer = m_data;
+ m_bufferSize = sizeof(m_data);
+ m_stream = new STG::DECRYPT_STREAM(m_admin->password(), DataCallback, &m_dataState);
+ return WriteAnswer(OK_LOGINS, sizeof(OK_LOGINS) - 1); // Without \0
+}
+
+bool Conn::HandleData(size_t size)
+{
+ m_stream->Put(m_data, size, size == 0 || memchr(m_data, 0, size) != NULL);
+ m_buffer = m_data;
+ return m_stream->IsOk();
+}
+
+bool Conn::DataCallback(const void * block, size_t size, void * data)
+{
+ assert(data != NULL);
+ DataState& state = *static_cast<DataState *>(data);
+
+ const char * xml = static_cast<const char *>(block);
+ size_t length = strnlen(xml, size);
+
+ state.final = state.final || length < size || size == 0;
+
+ if (XML_Parse(state.conn.m_xmlParser, xml, length, state.final) == XML_STATUS_ERROR)
+ {
+ state.conn.Log(__FILE__, "Received invalid XML from " + state.conn.m_admin->login() + "@" + state.conn.endpoint() + ".");
+ printfd(__FILE__, "XML parse error at line %d, %d: %s. Is final: %d\n",
+ static_cast<int>(XML_GetCurrentLineNumber(state.conn.m_xmlParser)),
+ static_cast<int>(XML_GetCurrentColumnNumber(state.conn.m_xmlParser)),
+ XML_ErrorString(XML_GetErrorCode(state.conn.m_xmlParser)), (int)state.final);
+ printfd(__FILE__, "Data block: '%s' of size %d\n", xml, length);
+ state.conn.m_state = ERROR;
+ return false;
+ }
+
+ if (state.final)
+ {
+ if (!state.conn.WriteResponse())
+ {
+ state.conn.Log(__FILE__, "Failed to write response to " + state.conn.m_admin->login() + "@" + state.conn.endpoint() + ".");
+ state.conn.m_state = ERROR;
+ return false;
+ }
+ state.conn.m_state = DONE;
+ }
+
+ return true;
+}
+
+void Conn::ParseXMLStart(void * data, const char * el, const char ** attr)
+{
+ assert(data != NULL);
+ Conn & conn = *static_cast<Conn *>(data);
+
+ if (conn.m_parser == NULL)
+ conn.m_parser = conn.GetParser(el);
+
+ if (conn.m_parser == NULL)
+ {
+ conn.Log(__FILE__, "Received unknown command '" + std::string(el) + "' from " + conn.m_admin->login() + "@" + conn.endpoint() + ".");
+ conn.m_state = ERROR;
+ return;
+ }
+
+ conn.m_parser->Start(data, el, attr);
+}
+
+void Conn::ParseXMLEnd(void * data, const char * el)
+{
+ assert(data != NULL);
+ Conn & conn = *static_cast<Conn *>(data);
+
+ if (conn.m_parser == NULL)
+ {
+ // No need to log it.
+ conn.m_state = ERROR;
+ return;
+ }
+
+ conn.m_parser->End(data, el);
+}
+
+bool Conn::WriteResponse()
+{
+ STG::ENCRYPT_STREAM stream(m_admin->password(), WriteCallback, this);
+ std::string answer;
+ if (m_parser != NULL)
+ answer = m_parser->GetAnswer();
+ else
+ answer = "<Error result=\"Unknown command.\"/>";
+ delete m_parser;
+ m_parser = NULL;
+ printfd(__FILE__, "Writing %d bytes of answer.\n", answer.length());
+ stream.Put(answer.c_str(), answer.length() + 1 /* including \0 */, true /* final */);
+ return stream.IsOk();
+}
+
+bool Conn::WriteCallback(const void * block, size_t size, void * data)
+{
+ assert(data != NULL);
+ Conn & conn = *static_cast<Conn *>(data);
+ return WriteAll(conn.m_sock, block, size);;
+}
+
+void Conn::Log(const char * file, const std::string & message)
+{
+ printfd(file, "%s\n", message.c_str());
+ m_logger(message);
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "dumphelpers.h"
+
+#include "stg/const.h"
+
+#include <stdexcept>
+#include <string>
+#include <cstdint>
+
+#include <expat.h>
+
+#include <netinet/in.h>
+
+namespace STG
+{
+
+struct Settings;
+struct Admins;
+struct Users;
+struct Tariffs;
+struct Admin;
+class PluginLogger;
+
+class DECRYPT_STREAM;
+
+class Conn
+{
+ public:
+ struct Error : public std::runtime_error
+ {
+ explicit Error(const std::string& message) : runtime_error(message.c_str()) {}
+ };
+
+ Conn(const BASE_PARSER::REGISTRY & registry,
+ Admins & admins, int sock, const sockaddr_in& addr,
+ PluginLogger & logger);
+ ~Conn();
+
+ int Sock() const { return m_sock; }
+ uint32_t IP() const { return *(uint32_t *)(&m_addr.sin_addr); }
+ uint16_t Port() const { return ntohs(m_addr.sin_port); }
+
+ std::string endpoint() const { return inet_ntostring(IP()) + ":" + std::to_string(Port()); }
+
+ bool Read();
+
+ bool IsOk() const { return m_state != ERROR; }
+ bool IsDone() const { return m_state == DONE; }
+ bool IsKeepAlive() const { return m_keepAlive; }
+
+ void SetKeepAlive() { m_keepAlive = true; }
+
+ private:
+
+ static const char STG_HEADER[5];
+ static const char OK_HEADER[5];
+ static const char ERR_HEADER[5];
+ static const char OK_LOGIN[5];
+ static const char ERR_LOGIN[5];
+ static const char OK_LOGINS[5];
+ static const char ERR_LOGINS[5];
+
+ const BASE_PARSER::REGISTRY & m_registry;
+
+ Admins & m_admins;
+
+ Admin * m_admin;
+
+ int m_sock;
+ sockaddr_in m_addr;
+ bool m_keepAlive;
+
+ BASE_PARSER * m_parser;
+
+ XML_Parser m_xmlParser;
+
+ enum { HEADER, LOGIN, CRYPTO_LOGIN, DATA, DONE, ERROR } m_state;
+
+ void * m_buffer;
+ size_t m_bufferSize;
+ char m_header[sizeof(STG_HEADER) - 1]; // Without \0
+ char m_login[ADM_LOGIN_LEN]; // Without \0
+ char m_cryptoLogin[ADM_LOGIN_LEN]; // Without \0
+ char m_data[1024];
+ STG::DECRYPT_STREAM * m_stream;
+ PluginLogger & m_logger;
+
+ BASE_PARSER * GetParser(const std::string & tag) const;
+
+ bool HandleBuffer(size_t size);
+
+ bool HandleHeader();
+ bool HandleLogin();
+ bool HandleCryptoLogin();
+ bool HandleData(size_t size);
+
+ bool WriteAnswer(const void* buffer, size_t size);
+ bool WriteResponse();
+
+ void Log(const char * file, const std::string & message);
+
+ struct DataState
+ {
+ DataState(bool f, Conn & c) : final(f), conn(c) {}
+ bool final;
+ Conn & conn;
+ } m_dataState;
+
+#ifdef DUMPCRYPTO
+ Dumper m_dumper;
+#endif
+
+ static bool DataCallback(const void * block, size_t size, void * data);
+ static void ParseXMLStart(void * data, const char * el, const char ** attr);
+ static void ParseXMLEnd(void * data, const char * el);
+ static bool WriteCallback(const void * block, size_t size, void * data);
+};
+
+}
--- /dev/null
+#ifndef __STG_DUMP_HELPERS_H__
+#define __STG_DUMP_HELPERS_H__
+
+#include "stg/common.h"
+
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+
+#include <cstddef>
+#include <ctime>
+
+namespace STG
+{
+
+class Dumper
+{
+ public:
+ explicit Dumper(const std::string& tag)
+ : m_stream(getName(tag).c_str())
+ {
+ }
+ ~Dumper() {}
+
+ void write(const void* data, size_t size)
+ {
+ writePrefix();
+ m_stream << " ";
+ writeHEX(data, size);
+ }
+
+ private:
+ std::ofstream m_stream;
+
+ tm getTime() const
+ {
+ time_t now = time(NULL);
+ tm localTime;
+ localtime_r(&now, &localTime);
+ return localTime;
+ }
+
+ std::string getName(const std::string& tag) const
+ {
+ tm localTime = getTime();
+
+ std::ostringstream res;
+ res << tag
+ << "-" << (localTime.tm_year + 1900) << twoDigit(localTime.tm_mon + 1) << twoDigit(localTime.tm_mday)
+ << "-" << twoDigit(localTime.tm_hour) << twoDigit(localTime.tm_min) << twoDigit(localTime.tm_sec)
+ << ".data";
+
+ return res.str();
+ }
+
+ void writePrefix()
+ {
+ tm localTime = getTime();
+ m_stream << "[" << (localTime.tm_year + 1900) << "-" << twoDigit(localTime.tm_mon + 1) << "-" << twoDigit(localTime.tm_mday)
+ << " " << twoDigit(localTime.tm_hour) << ":" << twoDigit(localTime.tm_min) << ":" << twoDigit(localTime.tm_sec)
+ << "]";
+ }
+
+ void writeHEX(const void* data, size_t size)
+ {
+ m_stream << "(" << std::setw(4) << std::setfill(' ') << size << ") ";
+ const unsigned char* pos = static_cast<const unsigned char*>(data);
+ for (size_t i = 0; i < size; ++i)
+ m_stream << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*pos++);
+ m_stream << std::dec << "\n";
+ }
+
+ std::string twoDigit(int value) const
+ {
+ std::string res = std::to_string(value);
+ if (res.length() < 2)
+ res = "0" + res;
+ return res;
+ }
+};
+
+} // namespace STG
+
+#endif
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include "parser.h"
+
+#include <cstring>
+
+//-----------------------------------------------------------------------------
+// BASE PARSER
+//-----------------------------------------------------------------------------
+int BASE_PARSER::Start(void *, const char * el, const char **)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ return 0;
+
+ return -1;
+}
+//-----------------------------------------------------------------------------
+int BASE_PARSER::End(void *, const char * el)
+{
+ if (m_depth < 2)
+ {
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+ CreateAnswer();
+ }
+
+ --m_depth;
+ return 0;
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include <string>
+#include <map>
+
+namespace STG
+{
+struct Admin;
+}
+
+class BASE_PARSER
+{
+ public:
+ struct FACTORY
+ {
+ virtual ~FACTORY() {}
+ virtual BASE_PARSER * create(const STG::Admin & admin) = 0;
+ };
+ typedef std::map<std::string, FACTORY *> REGISTRY;
+
+ BASE_PARSER(const STG::Admin & admin, const std::string & t)
+ : m_currAdmin(admin),
+ m_depth(0),
+ m_tag(t)
+ {}
+ virtual ~BASE_PARSER() {}
+ virtual int Start(void * data, const char * el, const char ** attr);
+ virtual int End(void * data, const char * el);
+
+ const std::string & GetAnswer() const { return m_answer; }
+ const std::string & GetTag() const { return m_tag; }
+ std::string GetOpenTag() const { return "<" + m_tag + ">"; }
+ std::string GetCloseTag() const { return "</" + m_tag + ">"; }
+
+ protected:
+ BASE_PARSER(const BASE_PARSER & rvalue);
+ BASE_PARSER & operator=(const BASE_PARSER & rvalue);
+
+ const STG::Admin & m_currAdmin;
+ size_t m_depth;
+ std::string m_answer;
+ std::string m_tag;
+
+ private:
+ virtual void CreateAnswer() = 0;
+};
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "parser_admins.h"
+
+#include "stg/admins.h"
+#include "stg/admin.h"
+#include "stg/admin_conf.h"
+
+#include <strings.h> // strcasecmp
+
+using STG::PARSER::GET_ADMINS;
+using STG::PARSER::ADD_ADMIN;
+using STG::PARSER::DEL_ADMIN;
+using STG::PARSER::CHG_ADMIN;
+
+const char * GET_ADMINS::tag = "GetAdmins";
+const char * ADD_ADMIN::tag = "AddAdmin";
+const char * DEL_ADMIN::tag = "DelAdmin";
+const char * CHG_ADMIN::tag = "ChgAdmin";
+
+void GET_ADMINS::CreateAnswer()
+{
+ const auto& priv = m_currAdmin.priv();
+ if (!priv.adminChg)
+ {
+ m_answer = "<Error Result=\"Error. Access denied.\"/>";
+ return;
+ }
+
+ m_answer = "<Admins>";
+ m_admins.fmap([this](const Admin& admin)
+ {
+ const unsigned int p = (admin.priv().userStat << 0) +
+ (admin.priv().userConf << 2) +
+ (admin.priv().userCash << 4) +
+ (admin.priv().userPasswd << 6) +
+ (admin.priv().userAddDel << 8) +
+ (admin.priv().adminChg << 10) +
+ (admin.priv().tariffChg << 12);
+ m_answer += "<admin login=\"" + admin.login() + "\" priv=\"" + std::to_string(p) + "\"/>";
+ });
+ m_answer += "</Admins>";
+}
+
+int DEL_ADMIN::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ m_admin = attr[1];
+ return 0;
+ }
+ return -1;
+}
+
+void DEL_ADMIN::CreateAnswer()
+{
+ if (m_admins.del(m_admin, m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " Result=\"Ok\"/>";
+ else
+ m_answer = "<" + m_tag + " Result=\"Error. " + m_admins.strError() + "\"/>";
+}
+
+int ADD_ADMIN::Start(void *, const char *el, const char **attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ m_admin = attr[1];
+ return 0;
+ }
+ return -1;
+}
+
+void ADD_ADMIN::CreateAnswer()
+{
+ if (m_admins.add(m_admin, m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " Result=\"Ok\"/>";
+ else
+ m_answer = "<" + m_tag + " Result=\"Error. " + m_admins.strError() + "\"/>";
+}
+
+int CHG_ADMIN::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ for (size_t i = 0; i < 6; i += 2)
+ {
+ printfd(__FILE__, "PARSER_CHG_ADMIN::attr[%d] = %s\n", i, attr[i]);
+ if (attr[i] == NULL)
+ break;
+
+ if (strcasecmp(attr[i], "Login") == 0)
+ {
+ login = attr[i + 1];
+ continue;
+ }
+
+ if (strcasecmp(attr[i], "Priv") == 0)
+ {
+ privAsString = attr[i + 1];
+ continue;
+ }
+
+ if (strcasecmp(attr[i], "Password") == 0)
+ {
+ password = attr[i + 1];
+ continue;
+ }
+ }
+
+ return 0;
+ }
+ return -1;
+}
+
+void CHG_ADMIN::CreateAnswer()
+{
+ if (!login.empty())
+ {
+ Admin * origAdmin = NULL;
+
+ if (m_admins.find(login, &origAdmin))
+ {
+ m_answer = "<" + m_tag + " Result = \"Admin '" + login + "' is not found.\"/>";
+ return;
+ }
+
+ AdminConf conf(origAdmin->conf());
+
+ if (!password.empty())
+ conf.password = password.data();
+
+ if (!privAsString.empty())
+ {
+ int p = 0;
+ if (str2x(privAsString.data().c_str(), p) < 0)
+ {
+ m_answer = "<" + m_tag + " Result = \"Incorrect parameter Priv.\"/>";
+ return;
+ }
+
+ conf.priv = Priv(p);
+ }
+
+ if (m_admins.change(conf, m_currAdmin) != 0)
+ m_answer = "<" + m_tag + " Result = \"" + m_admins.strError() + "\"/>";
+ else
+ m_answer = "<" + m_tag + " Result = \"Ok\"/>";
+ }
+ else
+ m_answer = "<" + m_tag + " Result = \"Incorrect parameter login.\"/>";
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/common.h"
+#include "stg/optional.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Admins;
+struct Admin;
+
+namespace PARSER
+{
+
+class GET_ADMINS: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(const Admins & admins) : m_admins(admins) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_ADMINS(admin, m_admins); }
+ static void Register(REGISTRY & registry, const Admins & admins)
+ { registry[ToLower(tag)] = new FACTORY(admins); }
+ private:
+ const Admins & m_admins;
+ };
+
+ static const char * tag;
+
+ GET_ADMINS(const Admin & admin, const Admins & admins)
+ : BASE_PARSER(admin, tag), m_admins(admins) {}
+
+ private:
+ const Admins & m_admins;
+
+ void CreateAnswer();
+};
+
+class ADD_ADMIN: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Admins & admins) : m_admins(admins) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new ADD_ADMIN(admin, m_admins); }
+ static void Register(REGISTRY & registry, Admins & admins)
+ { registry[ToLower(tag)] = new FACTORY(admins); }
+ private:
+ Admins & m_admins;
+ };
+
+ static const char * tag;
+
+ ADD_ADMIN(const Admin & admin, Admins & admins)
+ : BASE_PARSER(admin, tag), m_admins(admins) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string m_admin;
+ Admins & m_admins;
+
+ void CreateAnswer();
+};
+
+class DEL_ADMIN: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Admins & admins) : m_admins(admins) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new DEL_ADMIN(admin, m_admins); }
+ static void Register(REGISTRY & registry, Admins & admins)
+ { registry[ToLower(tag)] = new FACTORY(admins); }
+ private:
+ Admins & m_admins;
+ };
+
+ static const char * tag;
+
+ DEL_ADMIN(const Admin & admin, Admins & admins)
+ : BASE_PARSER(admin, tag), m_admins(admins) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string m_admin;
+ Admins & m_admins;
+
+ void CreateAnswer();
+};
+
+class CHG_ADMIN: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Admins & admins) : m_admins(admins) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new CHG_ADMIN(admin, m_admins); }
+ static void Register(REGISTRY & registry, Admins & admins)
+ { registry[ToLower(tag)] = new FACTORY(admins); }
+ private:
+ Admins & m_admins;
+ };
+
+ static const char * tag;
+
+ CHG_ADMIN(const Admin & admin, Admins & admins)
+ : BASE_PARSER(admin, tag), m_admins(admins) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string login;
+ Optional<std::string> password;
+ Optional<std::string> privAsString;
+ Admins & m_admins;
+
+ void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 "parser_auth_by.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+
+#include <cstring>
+
+using STG::PARSER::AUTH_BY;
+
+const char * AUTH_BY::tag = "GetUserAuthBy";
+
+int AUTH_BY::Start(void * /*data*/, const char *el, const char **attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ if (!attr[1])
+ return -1;
+
+ m_login = attr[1];
+ return 0;
+}
+
+void AUTH_BY::CreateAnswer()
+{
+ using ConstUserPtr = const User*;
+ ConstUserPtr u;
+ if (m_users.FindByName(m_login, &u))
+ {
+ m_answer = "<AuthorizedBy result=\"error\" reason=\"User not found.\"/>";
+ return;
+ }
+
+ m_answer = "<AuthorizedBy result=\"ok\">";
+ std::vector<std::string> list(u->GetAuthorizers());
+ for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
+ m_answer += "<Auth name=\"" + *it + "\"/>";
+ m_answer += "</AuthorizedBy>";
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/common.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Admin;
+struct Users;
+
+namespace PARSER
+{
+
+class AUTH_BY : public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(const Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new AUTH_BY(admin, m_users); }
+ static void Register(REGISTRY & registry, const Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ const Users & m_users;
+ };
+
+ static const char * tag;
+
+ AUTH_BY(const Admin & admin, const Users & users)
+ : BASE_PARSER(admin, tag), m_users(users) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ const Users & m_users;
+ std::string m_login;
+
+ void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "parser_message.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+
+#include <cstring>
+
+extern volatile time_t stgTime; // So sad...
+
+using STG::PARSER::SEND_MESSAGE;
+
+const char * SEND_MESSAGE::tag = "Message";
+
+int SEND_MESSAGE::Start(void *, const char *el, const char **attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ for (size_t i = 0; i < 14; i++)
+ if (attr[i] == NULL)
+ {
+ m_result = res_params_error;
+ CreateAnswer();
+ printfd(__FILE__, "To few parameters\n");
+ return 0;
+ }
+
+ for (size_t i = 0; i < 14; i += 2)
+ {
+ if (strcasecmp(attr[i], "login") == 0)
+ ParseLogins(attr[i + 1]);
+
+ if (strcasecmp(attr[i], "MsgVer") == 0)
+ {
+ str2x(attr[i + 1], m_msg.header.ver);
+ if (m_msg.header.ver != 1)
+ m_result = res_params_error;
+ }
+
+ if (strcasecmp(attr[i], "MsgType") == 0)
+ {
+ str2x(attr[i + 1], m_msg.header.type);
+ if (m_msg.header.type != 1)
+ m_result = res_params_error;
+ }
+
+ if (strcasecmp(attr[i], "Repeat") == 0)
+ {
+ str2x(attr[i + 1], m_msg.header.repeat);
+ if (m_msg.header.repeat < 0)
+ m_result = res_params_error;
+ }
+
+ if (strcasecmp(attr[i], "RepeatPeriod") == 0)
+ str2x(attr[i + 1], m_msg.header.repeatPeriod);
+
+ if (strcasecmp(attr[i], "ShowTime") == 0)
+ str2x(attr[i + 1], m_msg.header.showTime);
+
+ if (strcasecmp(attr[i], "Text") == 0)
+ {
+ Decode21str(m_msg.text, attr[i + 1]);
+ m_result = res_ok;
+ }
+ }
+ return 0;
+}
+
+int SEND_MESSAGE::End(void *, const char *el)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ m_result = res_unknown;
+ for (unsigned i = 0; i < m_logins.size(); i++)
+ {
+ if (m_users.FindByName(m_logins[i], &m_user))
+ {
+ printfd(__FILE__, "User not found. %s\n", m_logins[i].c_str());
+ continue;
+ }
+ m_msg.header.creationTime = static_cast<unsigned int>(stgTime);
+ m_user->AddMessage(&m_msg);
+ m_result = res_ok;
+ }
+ CreateAnswer();
+ return 0;
+}
+
+int SEND_MESSAGE::ParseLogins(const char * login)
+{
+ char * p;
+ char * l = new char[strlen(login) + 1];
+ strcpy(l, login);
+ p = strtok(l, ":");
+ m_logins.clear();
+ while (p)
+ {
+ m_logins.push_back(p);
+ p = strtok(NULL, ":");
+ }
+
+ delete[] l;
+ return 0;
+}
+
+void SEND_MESSAGE::CreateAnswer()
+{
+ switch (m_result)
+ {
+ case res_ok:
+ m_answer = "<SendMessageResult value=\"ok\"/>";
+ break;
+ case res_params_error:
+ m_answer = "<SendMessageResult value=\"Parameters error.\"/>";
+ break;
+ case res_unknown:
+ m_answer = "<SendMessageResult value=\"Unknown user.\"/>";
+ break;
+ }
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/message.h"
+#include "stg/common.h"
+
+#include <vector>
+#include <string>
+
+namespace STG
+{
+
+struct Users;
+struct User;
+
+namespace PARSER
+{
+
+class SEND_MESSAGE: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new SEND_MESSAGE(admin, m_users); }
+ static void Register(REGISTRY & registry, Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ Users & m_users;
+ };
+
+ static const char * tag;
+
+ SEND_MESSAGE(const Admin & admin, Users & users)
+ : BASE_PARSER(admin, tag), m_users(users), m_result(res_ok), m_user(NULL) {}
+ int Start(void *data, const char *el, const char **attr);
+ int End(void *data, const char *el);
+
+ private:
+ Users & m_users;
+ std::vector<std::string> m_logins;
+ enum { res_ok, res_params_error, res_unknown } m_result;
+ STG::Message m_msg;
+ User * m_user;
+
+ int ParseLogins(const char * logins);
+ void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "parser_server_info.h"
+
+#include "stg/settings.h"
+#include "stg/users.h"
+#include "stg/tariffs.h"
+#include "stg/version.h"
+#include "stg/const.h"
+
+#include <string>
+#include <cstring>
+
+#include <sys/utsname.h>
+
+using STG::PARSER::GET_SERVER_INFO;
+
+const char * GET_SERVER_INFO::tag = "GetServerInfo";
+
+void GET_SERVER_INFO::CreateAnswer()
+{
+ struct utsname utsn;
+ uname(&utsn);
+
+ std::string name = std::string(utsn.sysname) + " " +
+ utsn.release + " " +
+ utsn.machine + " " +
+ utsn.nodename;
+
+ m_answer = std::string("<ServerInfo><version value=\"") + SERVER_VERSION + "\"/>" +
+ "<tariff_num value=\"" + std::to_string(m_tariffs.Count()) + "\"/>" +
+ "<tariff value=\"2\"/>" +
+ "<user_num value=\"" + std::to_string(m_users.Count()) + "\"/>" +
+ "<uname value=\"" + name + "\"/>" +
+ "<dir_num value=\"" + std::to_string(DIR_NUM) + "\"/>" +
+ "<day_fee value=\"" + std::to_string(m_settings.GetDayFee()) + "\"/>";
+
+ for (size_t i = 0; i< DIR_NUM; i++)
+ m_answer += "<dir_name_" + std::to_string(i) + " value=\"" + Encode12str(m_settings.GetDirName(i)) + "\"/>";
+
+ m_answer += "</ServerInfo>";
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/common.h"
+
+namespace STG
+{
+
+struct Admin;
+struct Settings;
+struct Users;
+struct Tariffs;
+
+namespace PARSER
+{
+
+class GET_SERVER_INFO: public BASE_PARSER {
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(const Settings & settings, const Users & users, const Tariffs & tariffs)
+ : m_settings(settings), m_users(users), m_tariffs(tariffs) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_SERVER_INFO(admin, m_settings, m_users, m_tariffs); }
+ static void Register(REGISTRY & registry, const Settings & settings, const Users & users, const Tariffs & tariffs)
+ { registry[ToLower(tag)] = new FACTORY(settings, users, tariffs); }
+ private:
+ const Settings & m_settings;
+ const Users & m_users;
+ const Tariffs & m_tariffs;
+ };
+
+ static const char * tag;
+
+ GET_SERVER_INFO(const Admin & admin,
+ const Settings & settings,
+ const Users & users,
+ const Tariffs & tariffs)
+ : BASE_PARSER(admin, tag),
+ m_settings(settings),
+ m_users(users),
+ m_tariffs(tariffs)
+ {}
+
+ private:
+ const Settings & m_settings;
+ const Users & m_users;
+ const Tariffs & m_tariffs;
+
+ void CreateAnswer();
+};
+
+}
+}
--- /dev/null
+/*
+ * 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 "parser_services.h"
+
+#include "stg/services.h"
+
+#include <strings.h> // strcasecmp
+
+using STG::PARSER::GET_SERVICES;
+using STG::PARSER::GET_SERVICE;
+using STG::PARSER::ADD_SERVICE;
+using STG::PARSER::DEL_SERVICE;
+using STG::PARSER::CHG_SERVICE;
+
+const char * GET_SERVICES::tag = "GetServices";
+const char * GET_SERVICE::tag = "AddService";
+const char * ADD_SERVICE::tag = "AddService";
+const char * DEL_SERVICE::tag = "DelService";
+const char * CHG_SERVICE::tag = "SetService";
+
+void GET_SERVICES::CreateAnswer()
+{
+ // TODO: no priviledges implemented yet
+ /*const PRIV * priv = m_currAdmin.GetPriv();
+ if (!priv->serviceChg)
+ {
+ m_answer = "<Error Result=\"Error. Access denied.\"/>";
+ return;
+ }*/
+
+ m_answer = "<Services>";
+ ServiceConf conf;
+ int h = m_services.OpenSearch();
+ while (m_services.SearchNext(h, &conf) == 0)
+ {
+ m_answer += "<Service name=\"" + conf.name +
+ "\" comment=\"" + Encode12str(conf.comment) +
+ "\" cost=\"" + std::to_string(conf.cost) +
+ "\" payDay=\"" + std::to_string(conf.payDay) + "\"/>";
+ }
+ m_services.CloseSearch(h);
+ m_answer += "</Services>";
+}
+
+int GET_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ m_name = attr[1];
+ return 0;
+ }
+ return -1;
+}
+
+void GET_SERVICE::CreateAnswer()
+{
+ // TODO: no priviledges implemented yet
+ /*const PRIV * priv = m_currAdmin.GetPriv();
+ if (!priv->serviceChg)
+ {
+ m_answer = "<Error Result=\"Error. Access denied.\"/>";
+ return;
+ }*/
+
+ ServiceConf conf;
+ if (!m_services.Find(m_name, &conf))
+ m_answer = "<Error result=\"Service '" + m_name + "' does not exist.\"/>";
+ else
+ m_answer += "<" + m_tag + " name=\"" + conf.name +
+ "\" comment=\"" + Encode12str(conf.comment) +
+ "\" cost=\"" + std::to_string(conf.cost) +
+ "\" payDay=\"" + std::to_string(conf.payDay) + "\"/>";
+}
+
+int ADD_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ m_name = attr[1];
+ return 0;
+ }
+ return -1;
+}
+
+void ADD_SERVICE::CreateAnswer()
+{
+ ServiceConf conf(m_name);
+ if (m_services.Add(conf, &m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " result=\"Ok\"/>";
+ else
+ m_answer = "<" + m_tag + " result=\"" + m_services.GetStrError() + "\"/>";
+}
+
+int DEL_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ m_name = attr[1];
+ return 0;
+ }
+ return -1;
+}
+
+void DEL_SERVICE::CreateAnswer()
+{
+ if (m_services.Del(m_name, &m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " result=\"Ok\"/>";
+ else
+ m_answer = "<" + m_tag + " result=\"" + m_services.GetStrError() + "\"/>";
+}
+
+int CHG_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ for (size_t i = 0; i < 8; i += 2)
+ {
+ if (attr[i] == NULL)
+ break;
+
+ if (strcasecmp(attr[i], "name") == 0)
+ {
+ m_service.name = attr[i + 1];
+ continue;
+ }
+
+ if (strcasecmp(attr[i], "comment") == 0)
+ {
+ m_service.comment = Decode21str(attr[i + 1]);
+ continue;
+ }
+
+ if (strcasecmp(attr[i], "cost") == 0)
+ {
+ double cost = 0;
+ if (str2x(attr[i + 1], cost) == 0)
+ m_service.cost = cost;
+ else
+ printfd(__FILE__, "Bad cast from '%s' to double\n", attr[i + 1]);
+ // TODO: log it
+ continue;
+ }
+
+ if (strcasecmp(attr[i], "payDay") == 0)
+ {
+ unsigned payDay;
+ if (str2x(attr[i + 1], payDay) == 0)
+ m_service.payDay = payDay;
+ else
+ printfd(__FILE__, "Bad cast from '%s' to unsigned\n", attr[i + 1]);
+ // TODO: log it
+ continue;
+ }
+ }
+
+ return 0;
+ }
+ return -1;
+}
+
+void CHG_SERVICE::CreateAnswer()
+{
+ if (m_service.name.empty())
+ {
+ m_answer = "<" + m_tag + " result=\"Empty service name.\"/>";
+ return;
+ }
+
+ if (!m_services.Exists(m_service.name.const_data()))
+ {
+ m_answer = "<" + m_tag + " result = \"Service '" + m_service.name.const_data() + "' does not exist.\"/>";
+ return;
+ }
+
+ ServiceConf orig;
+ m_services.Find(m_service.name.const_data(), &orig);
+
+ ServiceConfOpt conf(orig);
+ conf.splice(m_service);
+
+ if (m_services.Change(conf.get({}), &m_currAdmin) != 0)
+ m_answer = "<" + m_tag + " result = \"" + m_services.GetStrError() + "\"/>";
+ else
+ m_answer = "<" + m_tag + " result = \"Ok\"/>";
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/service_conf.h"
+
+#include "stg/common.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Services;
+
+namespace PARSER
+{
+
+class GET_SERVICES: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(const Services & services) : m_services(services) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_SERVICES(admin, m_services); }
+ static void Register(REGISTRY & registry, const Services & services)
+ { registry[ToLower(tag)] = new FACTORY(services); }
+ private:
+ const Services & m_services;
+ };
+
+ static const char * tag;
+
+ GET_SERVICES(const Admin & admin, const Services & services)
+ : BASE_PARSER(admin, tag), m_services(services) {}
+
+ private:
+ const Services & m_services;
+
+ void CreateAnswer();
+};
+
+class GET_SERVICE: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(const Services & services) : m_services(services) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_SERVICE(admin, m_services); }
+ static void Register(REGISTRY & registry, Services & services)
+ { registry[ToLower(tag)] = new FACTORY(services); }
+ private:
+ const Services & m_services;
+ };
+
+ static const char * tag;
+
+ GET_SERVICE(const Admin & admin, const Services & services)
+ : BASE_PARSER(admin, tag), m_services(services) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string m_name;
+ const Services & m_services;
+
+ void CreateAnswer();
+};
+
+class ADD_SERVICE: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(Services & services) : m_services(services) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new ADD_SERVICE(admin, m_services); }
+ static void Register(REGISTRY & registry, Services & services)
+ { registry[ToLower(tag)] = new FACTORY(services); }
+ private:
+ Services & m_services;
+ };
+
+ static const char * tag;
+
+ ADD_SERVICE(const Admin & admin, Services & services)
+ : BASE_PARSER(admin, tag), m_services(services) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string m_name;
+ Services & m_services;
+
+ void CreateAnswer();
+};
+
+class DEL_SERVICE: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(Services & services) : m_services(services) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new DEL_SERVICE(admin, m_services); }
+ static void Register(REGISTRY & registry, Services & services)
+ { registry[ToLower(tag)] = new FACTORY(services); }
+ private:
+ Services & m_services;
+ };
+
+ static const char * tag;
+
+ DEL_SERVICE(const Admin & admin, Services & services)
+ : BASE_PARSER(admin, tag), m_services(services) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string m_name;
+ Services & m_services;
+
+ void CreateAnswer();
+};
+
+class CHG_SERVICE: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(Services & services) : m_services(services) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new CHG_SERVICE(admin, m_services); }
+ static void Register(REGISTRY & registry, Services & services)
+ { registry[ToLower(tag)] = new FACTORY(services); }
+ private:
+ Services & m_services;
+ };
+
+ static const char * tag;
+
+ CHG_SERVICE(const Admin & admin, Services & services)
+ : BASE_PARSER(admin, tag), m_services(services) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ ServiceConfOpt m_service;
+ Services & m_services;
+
+ void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "parser_tariffs.h"
+
+#include "stg/tariffs.h"
+#include "stg/users.h"
+#include "stg/optional.h"
+
+#include <cstdio> // snprintf
+#include <cstring>
+
+using STG::PARSER::GET_TARIFFS;
+using STG::PARSER::ADD_TARIFF;
+using STG::PARSER::DEL_TARIFF;
+using STG::PARSER::CHG_TARIFF;
+
+const char * GET_TARIFFS::tag = "GetTariffs";
+const char * ADD_TARIFF::tag = "AddTariff";
+const char * DEL_TARIFF::tag = "DelTariff";
+const char * CHG_TARIFF::tag = "SetTariff";
+
+namespace
+{
+
+const double pt_mega = 1024 * 1024;
+
+template <typename A, typename C, typename F>
+std::string AOS2String(const A & array, size_t size, const F C::* field, F multiplier)
+{
+ std::string res;
+ for (size_t i = 0; i < size; ++i)
+ {
+ if (!res.empty())
+ res += "/";
+ res += std::to_string((array[i].*field) * multiplier);
+ }
+ return res;
+}
+
+template <typename T>
+bool str2res(const std::string& source, STG::Optional<T>& dest, T divisor)
+{
+ T value = 0;
+ if (str2x(source, value))
+ return false;
+ dest = value / divisor;
+ return true;
+}
+
+template <typename A, typename C, typename F>
+bool String2AOS(const std::string & source, A & array, size_t size, STG::Optional<F> C::* field, F divisor)
+{
+ size_t index = 0;
+ std::string::size_type from = 0;
+ std::string::size_type pos = 0;
+ while (index < size && (pos = source.find('/', from)) != std::string::npos)
+ {
+ if (!str2res(source.substr(from, pos - from), array[index].*field, divisor))
+ return false;
+ from = pos + 1;
+ ++index;
+ }
+ if (str2res(source.substr(from), array[index].*field, divisor))
+ return false;
+ return true;
+}
+
+}
+
+void GET_TARIFFS::CreateAnswer()
+{
+ m_answer = "<Tariffs>";
+
+ std::vector<TariffData> dataList;
+ m_tariffs.GetTariffsData(&dataList);
+ auto it = dataList.begin();
+ for (; it != dataList.end(); ++it)
+ {
+ m_answer += "<tariff name=\"" + it->tariffConf.name + "\">";
+
+ for (size_t i = 0; i < DIR_NUM; i++)
+ m_answer += "<Time" + std::to_string(i) + " value=\"" +
+ std::to_string(it->dirPrice[i].hDay) + ":" + std::to_string(it->dirPrice[i].mDay) + "-" +
+ std::to_string(it->dirPrice[i].hNight) + ":" + std::to_string(it->dirPrice[i].mNight) + "\"/>";
+
+ m_answer += "<PriceDayA value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceDayA, pt_mega) + "\"/>" +
+ "<PriceDayB value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceDayB, pt_mega) + "\"/>" +
+ "<PriceNightA value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceNightA, pt_mega) + "\"/>" +
+ "<PriceNightB value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceNightB, pt_mega) + "\"/>" +
+ "<Threshold value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::threshold, 1) + "\"/>" +
+ "<SinglePrice value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::singlePrice, 1) + "\"/>" +
+ "<NoDiscount value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::noDiscount, 1) + "\"/>" +
+ "<Fee value=\"" + std::to_string(it->tariffConf.fee) + "\"/>" +
+ "<PassiveCost value=\"" + std::to_string(it->tariffConf.passiveCost) + "\"/>" +
+ "<Free value=\"" + std::to_string(it->tariffConf.free) + "\"/>" +
+ "<TraffType value=\"" + Tariff::toString(it->tariffConf.traffType) + "\"/>" +
+ "<Period value=\"" + Tariff::toString(it->tariffConf.period) + "\"/>" +
+ "<ChangePolicy value=\"" + Tariff::toString(it->tariffConf.changePolicy) + "\"/>" +
+ "<ChangePolicyTimeout value=\"" + std::to_string(it->tariffConf.changePolicyTimeout) + "\"/>" +
+ "</tariff>";
+ }
+
+ m_answer += "</Tariffs>";
+}
+
+int ADD_TARIFF::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ if (attr[1] == NULL)
+ return -1;
+
+ tariff = attr[1];
+ return 0;
+}
+
+void ADD_TARIFF::CreateAnswer()
+{
+ if (m_tariffs.Add(tariff, &m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " Result=\"Ok\"/>";
+ else
+ m_answer = "<" + m_tag + " Result=\"Error. " + m_tariffs.GetStrError() + "\"/>";
+}
+
+int DEL_TARIFF::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ if (attr[1] == NULL)
+ return -1;
+
+ tariff = attr[1];
+ return 0;
+}
+
+void DEL_TARIFF::CreateAnswer()
+{
+ if (m_users.TariffInUse(tariff))
+ m_answer = "<" + m_tag + " Result=\"Error. Tariff \'" + tariff + "\' cannot be deleted, it is in use.\"/>";
+ else if (m_tariffs.Del(tariff, &m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " Result=\"Ok\"/>";
+ else
+ m_answer = "<" + m_tag + " Result=\"Error. " + m_tariffs.GetStrError() + "\"/>";
+}
+
+int CHG_TARIFF::Start(void *, const char * el, const char ** attr)
+{
+ m_depth++;
+
+ if (m_depth == 1)
+ {
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ const auto tariff = m_tariffs.FindByName(attr[1]);
+ if (tariff != NULL)
+ td = tariff->GetTariffData();
+ else
+ return -1;
+ return 0;
+ }
+ }
+ else
+ {
+ if (strcasecmp(el, "PriceDayA") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceDayA, pt_mega))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ if (strcasecmp(el, "PriceDayB") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceDayB, pt_mega))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ if (strcasecmp(el, "PriceNightA") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceNightA, pt_mega))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ if (strcasecmp(el, "PriceNightB") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceNightB, pt_mega))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ if (strcasecmp(el, "Threshold") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::threshold, 1))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ if (strcasecmp(el, "SinglePrice") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::singlePrice, 1))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ if (strcasecmp(el, "NoDiscount") == 0)
+ {
+ if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::noDiscount, 1))
+ return -1; // TODO: log it
+ else
+ return 0;
+ }
+
+ for (int j = 0; j < DIR_NUM; j++)
+ {
+ char st[50];
+ snprintf(st, 50, "Time%d", j);
+ if (strcasecmp(el, st) == 0)
+ {
+ int h1 = 0;
+ int m1 = 0;
+ int h2 = 0;
+ int m2 = 0;
+ if (ParseTariffTimeStr(attr[1], h1, m1, h2, m2) == 0)
+ {
+ td.dirPrice[j].hDay = h1;
+ td.dirPrice[j].mDay = m1;
+ td.dirPrice[j].hNight = h2;
+ td.dirPrice[j].mNight = m2;
+ }
+ return 0;
+ }
+ }
+
+ if (strcasecmp(el, "Fee") == 0)
+ {
+ double fee;
+ if (strtodouble2(attr[1], fee) == 0)
+ td.tariffConf.fee = fee;
+ return 0;
+ }
+
+ if (strcasecmp(el, "PassiveCost") == 0)
+ {
+ double pc;
+ if (strtodouble2(attr[1], pc) == 0)
+ td.tariffConf.passiveCost = pc;
+ return 0;
+ }
+
+ if (strcasecmp(el, "Free") == 0)
+ {
+ double free;
+ if (strtodouble2(attr[1], free) == 0)
+ td.tariffConf.free = free;
+ return 0;
+ }
+
+ if (strcasecmp(el, "TraffType") == 0)
+ {
+ td.tariffConf.traffType = Tariff::parseTraffType(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "Period") == 0)
+ {
+ td.tariffConf.period = Tariff::parsePeriod(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "ChangePolicy") == 0)
+ {
+ td.tariffConf.changePolicy = Tariff::parseChangePolicy(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "ChangePolicyTimeout") == 0)
+ {
+ int64_t policyTime = 0;
+ if (str2x(attr[1], policyTime) == 0)
+ td.tariffConf.changePolicyTimeout = (time_t)policyTime;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void CHG_TARIFF::CreateAnswer()
+{
+ if (!td.tariffConf.name.data().empty())
+ {
+ auto tariffData = td.get({});
+ if (m_tariffs.Chg(tariffData, &m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " Result=\"ok\"/>";
+ else
+ m_answer = "<" + m_tag + " Result=\"Change tariff error! " + m_tariffs.GetStrError() + "\"/>";
+ }
+ else
+ m_answer = "<" + m_tag + " Result=\"Change tariff error!\"/>";
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/tariff_conf.h"
+#include "stg/common.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Tariffs;
+struct Users;
+struct Admin;
+
+namespace PARSER
+{
+
+class GET_TARIFFS: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(const Tariffs & tariffs) : m_tariffs(tariffs) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_TARIFFS(admin, m_tariffs); }
+ static void Register(REGISTRY & registry, const Tariffs & tariffs)
+ { registry[ToLower(tag)] = new FACTORY(tariffs); }
+ private:
+ const Tariffs & m_tariffs;
+ };
+
+ static const char * tag;
+
+ GET_TARIFFS(const Admin & admin, const Tariffs & tariffs)
+ : BASE_PARSER(admin, tag), m_tariffs(tariffs) {}
+
+ private:
+ const Tariffs & m_tariffs;
+
+ void CreateAnswer();
+};
+
+class ADD_TARIFF: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Tariffs & tariffs) : m_tariffs(tariffs) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new ADD_TARIFF(admin, m_tariffs); }
+ static void Register(REGISTRY & registry, Tariffs & tariffs)
+ { registry[ToLower(tag)] = new FACTORY(tariffs); }
+ private:
+ Tariffs & m_tariffs;
+ };
+
+ static const char * tag;
+
+ ADD_TARIFF(const Admin & admin, Tariffs & tariffs)
+ : BASE_PARSER(admin, tag), m_tariffs(tariffs) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string tariff;
+ Tariffs & m_tariffs;
+
+ void CreateAnswer();
+};
+
+class DEL_TARIFF: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(Tariffs & tariffs, const Users & users) : m_tariffs(tariffs), m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new DEL_TARIFF(admin, m_users, m_tariffs); }
+ static void Register(REGISTRY & registry, Tariffs & tariffs, const Users & users)
+ { registry[ToLower(tag)] = new FACTORY(tariffs, users); }
+ private:
+ Tariffs & m_tariffs;
+ const Users & m_users;
+ };
+
+ static const char * tag;
+
+ DEL_TARIFF(const Admin & admin, const Users & users, Tariffs & tariffs)
+ : BASE_PARSER(admin, tag), m_users(users), m_tariffs(tariffs) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ std::string tariff;
+ const Users & m_users;
+ Tariffs & m_tariffs;
+
+ void CreateAnswer();
+};
+
+class CHG_TARIFF: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Tariffs & tariffs) : m_tariffs(tariffs) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new CHG_TARIFF(admin, m_tariffs); }
+ static void Register(REGISTRY & registry, Tariffs & tariffs)
+ { registry[ToLower(tag)] = new FACTORY(tariffs); }
+ private:
+ Tariffs & m_tariffs;
+ };
+
+ static const char * tag;
+
+ CHG_TARIFF(const Admin & admin, Tariffs & tariffs)
+ : BASE_PARSER(admin, tag), m_tariffs(tariffs) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ TariffDataOpt td;
+ Tariffs & m_tariffs;
+
+ int CheckTariffData();
+ void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 "parser_user_info.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+
+#include <strings.h> // strcasecmp
+
+using STG::PARSER::USER_INFO;
+
+const char * USER_INFO::tag = "GetUserInfo";
+
+int USER_INFO::Start(void * /*data*/, const char *el, const char **attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ if (!attr[1])
+ return -1;
+
+ m_login = attr[1];
+ return 0;
+}
+
+void USER_INFO::CreateAnswer()
+{
+ using ConstUserPtr = const User*;
+ ConstUserPtr u;
+ if (m_users.FindByName(m_login, &u))
+ {
+ m_answer = "<UserInfo result=\"error\"/>";
+ return;
+ }
+
+ m_answer = "<UserInfo lastAuthTime=\"" + std::to_string(u->GetAuthorizedModificationTime()) + "\"" +
+ " lastDisconnectTime=\"" + std::to_string(u->GetConnectedModificationTime()) + "\"" +
+ " connected=\"" + (u->GetConnected() ? "true" : "false") + "\"" +
+ " lastDisconnectReason=\"" + u->GetLastDisconnectReason() + "\">";
+ std::vector<std::string> list(u->GetAuthorizers());
+ for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
+ m_answer += "<Auth name=\"" + *it + "\"/>";
+ m_answer += "</UserInfo>";
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/common.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Users;
+
+namespace PARSER
+{
+
+class USER_INFO : public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(const Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new USER_INFO(admin, m_users); }
+ static void Register(REGISTRY & registry, const Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ const Users & m_users;
+ };
+
+ static const char * tag;
+
+ USER_INFO(const Admin & admin, const Users & users)
+ : BASE_PARSER(admin, tag), m_users(users) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ const Users & m_users;
+ std::string m_login;
+
+ void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "parser_users.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/tariffs.h"
+#include "stg/tariff.h"
+#include "stg/user_property.h"
+
+#include <cstdio>
+#include <cassert>
+
+using STG::PARSER::GET_USERS;
+using STG::PARSER::GET_USER;
+using STG::PARSER::ADD_USER;
+using STG::PARSER::DEL_USER;
+using STG::PARSER::CHG_USER;
+using STG::PARSER::CHECK_USER;
+
+const char * GET_USERS::tag = "GetUsers";
+const char * GET_USER::tag = "GetUser";
+const char * ADD_USER::tag = "AddUser";
+const char * CHG_USER::tag = "SetUser";
+const char * DEL_USER::tag = "DelUser";
+const char * CHECK_USER::tag = "CheckUser";
+
+using UserPtr = STG::User*;
+using ConstUserPtr = const STG::User*;
+
+namespace
+{
+
+std::string UserToXML(const STG::User & user, bool loginInStart, bool showPass, time_t lastTime = 0)
+{
+ std::string answer;
+
+ if (loginInStart)
+ answer += "<User login=\"" + user.GetLogin() + "\" result=\"ok\">";
+ else
+ answer += "<User result=\"ok\">";
+
+ answer += "<Login value=\"" + user.GetLogin() + "\"/>";
+
+ if (user.GetProperties().password.ModificationTime() > lastTime)
+ {
+ if (showPass)
+ answer += "<Password value=\"" + user.GetProperties().password.Get() + "\" />";
+ else
+ answer += "<Password value=\"++++++\"/>";
+ }
+
+ if (user.GetProperties().cash.ModificationTime() > lastTime)
+ answer += "<Cash value=\"" + std::to_string(user.GetProperties().cash.Get()) + "\"/>";
+ if (user.GetProperties().freeMb.ModificationTime() > lastTime)
+ answer += "<FreeMb value=\"" + std::to_string(user.GetProperties().freeMb.Get()) + "\"/>";
+ if (user.GetProperties().credit.ModificationTime() > lastTime)
+ answer += "<Credit value=\"" + std::to_string(user.GetProperties().credit.Get()) + "\"/>";
+
+ if (user.GetProperties().nextTariff.Get() != "")
+ {
+ if (user.GetProperties().tariffName.ModificationTime() > lastTime ||
+ user.GetProperties().nextTariff.ModificationTime() > lastTime)
+ answer += "<Tariff value=\"" + user.GetProperties().tariffName.Get() + "/" + user.GetProperties().nextTariff.Get() + "\"/>";
+ }
+ else
+ {
+ if (user.GetProperties().tariffName.ModificationTime() > lastTime)
+ answer += "<Tariff value=\"" + user.GetProperties().tariffName.Get() + "\"/>";
+ }
+
+ if (user.GetProperties().note.ModificationTime() > lastTime)
+ answer += "<Note value=\"" + Encode12str(user.GetProperties().note) + "\"/>";
+ if (user.GetProperties().phone.ModificationTime() > lastTime)
+ answer += "<Phone value=\"" + Encode12str(user.GetProperties().phone) + "\"/>";
+ if (user.GetProperties().address.ModificationTime() > lastTime)
+ answer += "<Address value=\"" + Encode12str(user.GetProperties().address) + "\"/>";
+ if (user.GetProperties().email.ModificationTime() > lastTime)
+ answer += "<Email value=\"" + Encode12str(user.GetProperties().email) + "\"/>";
+
+ std::vector<const STG::UserPropertyLogged<std::string> *> userdata;
+ userdata.push_back(user.GetProperties().userdata0.GetPointer());
+ userdata.push_back(user.GetProperties().userdata1.GetPointer());
+ userdata.push_back(user.GetProperties().userdata2.GetPointer());
+ userdata.push_back(user.GetProperties().userdata3.GetPointer());
+ userdata.push_back(user.GetProperties().userdata4.GetPointer());
+ userdata.push_back(user.GetProperties().userdata5.GetPointer());
+ userdata.push_back(user.GetProperties().userdata6.GetPointer());
+ userdata.push_back(user.GetProperties().userdata7.GetPointer());
+ userdata.push_back(user.GetProperties().userdata8.GetPointer());
+ userdata.push_back(user.GetProperties().userdata9.GetPointer());
+
+ for (size_t i = 0; i < userdata.size(); i++)
+ if (userdata[i]->ModificationTime() > lastTime)
+ answer += "<UserData" + std::to_string(i) + " value=\"" + Encode12str(userdata[i]->Get()) + "\" />";
+
+ if (user.GetProperties().realName.ModificationTime() > lastTime)
+ answer += "<Name value=\"" + Encode12str(user.GetProperties().realName) + "\"/>";
+ if (user.GetProperties().group.ModificationTime() > lastTime)
+ answer += "<Group value=\"" + Encode12str(user.GetProperties().group) + "\"/>";
+ if (user.GetConnectedModificationTime() > lastTime)
+ answer += std::string("<Status value=\"") + (user.GetConnected() ? "1" : "0") + "\"/>";
+ if (user.GetProperties().alwaysOnline.ModificationTime() > lastTime)
+ answer += std::string("<AOnline value=\"") + (user.GetProperties().alwaysOnline.Get() ? "1" : "0") + "\"/>";
+ if (user.GetCurrIPModificationTime() > lastTime)
+ answer += "<CurrIP value=\"" + inet_ntostring(user.GetCurrIP()) + "\"/>";
+ if (user.GetPingTime() > lastTime)
+ answer += "<PingTime value=\"" + std::to_string(user.GetPingTime()) + "\"/>";
+ if (user.GetProperties().ips.ModificationTime() > lastTime)
+ answer += "<IP value=\"" + user.GetProperties().ips.Get().toString() + "\"/>";
+
+ answer += "<Traff";
+ const auto & upload(user.GetProperties().up.Get());
+ const auto & download(user.GetProperties().down.Get());
+ if (user.GetProperties().up.ModificationTime() > lastTime)
+ for (size_t j = 0; j < DIR_NUM; j++)
+ answer += " MU" + std::to_string(j) + "=\"" + std::to_string(upload[j]) + "\"";
+ if (user.GetProperties().down.ModificationTime() > lastTime)
+ for (size_t j = 0; j < DIR_NUM; j++)
+ answer += " MD" + std::to_string(j) + "=\"" + std::to_string(download[j]) + "\"";
+ if (user.GetSessionUploadModificationTime() > lastTime)
+ for (size_t j = 0; j < DIR_NUM; j++)
+ answer += " SU" + std::to_string(j) + "=\"" + std::to_string(user.GetSessionUpload()[j]) + "\"";
+ if (user.GetSessionDownloadModificationTime() > lastTime)
+ for (size_t j = 0; j < DIR_NUM; j++)
+ answer += " SD" + std::to_string(j) + "=\"" + std::to_string(user.GetSessionDownload()[j]) + "\"";
+ answer += "/>";
+
+ if (user.GetProperties().disabled.ModificationTime() > lastTime)
+ answer += std::string("<Down value=\"") + (user.GetProperties().disabled.Get() ? "1" : "0") + "\"/>";
+ if (user.GetProperties().disabledDetailStat.ModificationTime() > lastTime)
+ answer += std::string("<DisableDetailStat value=\"") + (user.GetProperties().disabledDetailStat.Get() ? "1" : "0") + "\"/>";
+ if (user.GetProperties().passive.ModificationTime() > lastTime)
+ answer += std::string("<Passive value=\"") + (user.GetProperties().passive.Get() ? "1" : "0") + "\"/>";
+ if (user.GetProperties().lastCashAdd.ModificationTime() > lastTime)
+ answer += "<LastCash value=\"" + std::to_string(user.GetProperties().lastCashAdd.Get()) + "\"/>";
+ if (user.GetProperties().lastCashAddTime.ModificationTime() > lastTime)
+ answer += "<LastTimeCash value=\"" + std::to_string(user.GetProperties().lastCashAddTime.Get()) + "\"/>";
+ if (user.GetProperties().lastActivityTime.ModificationTime() > lastTime)
+ answer += "<LastActivityTime value=\"" + std::to_string(user.GetProperties().lastActivityTime.Get()) + "\"/>";
+ if (user.GetProperties().creditExpire.ModificationTime() > lastTime)
+ answer += "<CreditExpire value=\"" + std::to_string(user.GetProperties().creditExpire.Get()) + "\"/>";
+
+ if (lastTime == 0)
+ {
+ answer += "<AuthorizedBy>";
+ std::vector<std::string> list(user.GetAuthorizers());
+ for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
+ answer += "<Auth name=\"" + *it + "\"/>";
+ answer += "</AuthorizedBy>";
+ }
+
+ answer += "</User>";
+
+ return answer;
+}
+
+} // namespace anonymous
+
+int GET_USERS::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ {
+ printfd(__FILE__, "Got wrong tag: '%s' instead of '%s'\n", el, m_tag.c_str());
+ return -1;
+ }
+
+ while (attr && *attr && *(attr + 1))
+ {
+ if (strcasecmp(*attr, "LastUpdate") == 0)
+ str2x(*(attr + 1), m_lastUserUpdateTime);
+ ++attr;
+ }
+
+ return 0;
+}
+
+void GET_USERS::CreateAnswer()
+{
+ int h = m_users.OpenSearch();
+ assert(h);
+
+ if (m_lastUserUpdateTime > 0)
+ m_answer = "<Users LastUpdate=\"" + std::to_string(time(NULL)) + "\">";
+ else
+ m_answer = "<Users>";
+
+ UserPtr u;
+
+ while (m_users.SearchNext(h, &u) == 0)
+ m_answer += UserToXML(*u, true, m_currAdmin.priv().userConf || m_currAdmin.priv().userPasswd, m_lastUserUpdateTime);
+
+ m_users.CloseSearch(h);
+
+ m_answer += "</Users>";
+}
+
+int GET_USER::Start(void *, const char * el, const char ** attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) != 0)
+ return -1;
+
+ if (attr[1] == NULL)
+ return -1;
+
+ m_login = attr[1];
+ return 0;
+}
+
+void GET_USER::CreateAnswer()
+{
+ ConstUserPtr u;
+
+ if (m_users.FindByName(m_login, &u))
+ m_answer = "<User result=\"error\" reason=\"User not found.\"/>";
+ else
+ m_answer = UserToXML(*u, false, m_currAdmin.priv().userConf || m_currAdmin.priv().userPasswd);
+}
+
+int ADD_USER::Start(void *, const char * el, const char ** attr)
+{
+ m_depth++;
+
+ if (m_depth == 1)
+ {
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ return 0;
+ }
+ else
+ {
+ if (strcasecmp(el, "login") == 0)
+ {
+ m_login = attr[1];
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void ADD_USER::CreateAnswer()
+{
+ if (m_users.Exists(m_login))
+ m_answer = "<" + m_tag + " result=\"error\" reason=\"User '" + m_login + "' exists.\"/>";
+ else if (m_users.Add(m_login, &m_currAdmin) == 0)
+ m_answer = "<" + m_tag + " result=\"ok\"/>";
+ else
+ m_answer = "<" + m_tag + " result=\"error\" reason=\"Access denied\"/>";
+}
+
+int CHG_USER::Start(void *, const char * el, const char ** attr)
+{
+ m_depth++;
+
+ if (m_depth == 1)
+ {
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ return 0;
+ }
+ else
+ {
+ if (strcasecmp(el, "login") == 0)
+ {
+ m_login = attr[1];
+ return 0;
+ }
+
+ if (strcasecmp(el, "ip") == 0)
+ {
+ m_ucr.ips = UserIPs::parse(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "password") == 0)
+ {
+ m_ucr.password = attr[1];
+ return 0;
+ }
+
+ if (strcasecmp(el, "address") == 0)
+ {
+ m_ucr.address = Decode21str(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "aonline") == 0)
+ {
+ m_ucr.alwaysOnline = (*(attr[1]) != '0');
+ return 0;
+ }
+
+ if (strcasecmp(el, "cash") == 0)
+ {
+ if (attr[2] && (strcasecmp(attr[2], "msg") == 0))
+ m_cashMsg = Decode21str(attr[3]);
+
+ double cash = 0;
+ if (strtodouble2(attr[1], cash) == 0)
+ m_usr.cash = cash;
+
+ m_cashMustBeAdded = (strcasecmp(attr[0], "add") == 0);
+
+ return 0;
+ }
+
+ if (strcasecmp(el, "CreditExpire") == 0)
+ {
+ long int creditExpire = 0;
+ if (str2x(attr[1], creditExpire) == 0)
+ m_ucr.creditExpire = (time_t)creditExpire;
+
+ return 0;
+ }
+
+ if (strcasecmp(el, "credit") == 0)
+ {
+ double credit = 0;
+ if (strtodouble2(attr[1], credit) == 0)
+ m_ucr.credit = credit;
+ return 0;
+ }
+
+ if (strcasecmp(el, "freemb") == 0)
+ {
+ double freeMb = 0;
+ if (strtodouble2(attr[1], freeMb) == 0)
+ m_usr.freeMb = freeMb;
+ return 0;
+ }
+
+ if (strcasecmp(el, "down") == 0)
+ {
+ int down = 0;
+ if (str2x(attr[1], down) == 0)
+ m_ucr.disabled = down;
+ return 0;
+ }
+
+ if (strcasecmp(el, "DisableDetailStat") == 0)
+ {
+ int disabledDetailStat = 0;
+ if (str2x(attr[1], disabledDetailStat) == 0)
+ m_ucr.disabledDetailStat = disabledDetailStat;
+ return 0;
+ }
+
+ if (strcasecmp(el, "email") == 0)
+ {
+ m_ucr.email = Decode21str(attr[1]);
+ return 0;
+ }
+
+ for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ char name[15];
+ sprintf(name, "userdata%d", i);
+ if (strcasecmp(el, name) == 0)
+ {
+ m_ucr.userdata[i] = Decode21str(attr[1]);
+ return 0;
+ }
+ }
+
+ if (strcasecmp(el, "group") == 0)
+ {
+ m_ucr.group = Decode21str(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "note") == 0)
+ {
+ m_ucr.note = Decode21str(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "passive") == 0)
+ {
+ int passive = 0;
+ if (str2x(attr[1], passive) == 0)
+ m_ucr.passive = passive;
+ return 0;
+ }
+
+ if (strcasecmp(el, "phone") == 0)
+ {
+ m_ucr.phone = Decode21str(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "Name") == 0)
+ {
+ m_ucr.realName = Decode21str(attr[1]);
+ return 0;
+ }
+
+ if (strcasecmp(el, "traff") == 0)
+ {
+ int j = 0;
+ while (attr[j])
+ {
+ int dir = attr[j][2] - '0';
+
+ if (strncasecmp(attr[j], "md", 2) == 0)
+ {
+ uint64_t t = 0;
+ str2x(attr[j + 1], t);
+ m_downr[dir] = t;
+ }
+ if (strncasecmp(attr[j], "mu", 2) == 0)
+ {
+ uint64_t t = 0;
+ str2x(attr[j + 1], t);
+ m_upr[dir] = t;
+ }
+ j += 2;
+ }
+ return 0;
+ }
+
+ if (strcasecmp(el, "tariff") == 0)
+ {
+ if (strcasecmp(attr[0], "now") == 0)
+ m_ucr.tariffName = attr[1];
+
+ if (strcasecmp(attr[0], "delayed") == 0)
+ m_ucr.nextTariff = attr[1];
+
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void CHG_USER::CreateAnswer()
+{
+ if (ApplyChanges() == 0)
+ m_answer = "<" + m_tag + " result=\"ok\"/>";
+ else
+ m_answer = "<" + m_tag + " result=\"error\"/>";
+}
+
+int CHG_USER::ApplyChanges()
+{
+ printfd(__FILE__, "PARSER_CHG_USER::ApplyChanges()\n");
+ UserPtr u;
+
+ if (m_users.FindByName(m_login, &u))
+ return -1;
+
+ bool check = false;
+ bool alwaysOnline = u->GetProperties().alwaysOnline;
+ if (!m_ucr.alwaysOnline.empty())
+ {
+ check = true;
+ alwaysOnline = m_ucr.alwaysOnline.const_data();
+ }
+ bool onlyOneIP = u->GetProperties().ips.ConstData().onlyOneIP();
+ if (!m_ucr.ips.empty())
+ {
+ check = true;
+ onlyOneIP = m_ucr.ips.const_data().onlyOneIP();
+ }
+
+ if (check && alwaysOnline && !onlyOneIP)
+ {
+ printfd(__FILE__, "Requested change leads to a forbidden state: AlwaysOnline with multiple IP's\n");
+ PluginLogger::get("conf_sg")("%s Requested change leads to a forbidden state: AlwaysOnline with multiple IP's", m_currAdmin.logStr().c_str());
+ return -1;
+ }
+
+ for (size_t i = 0; i < m_ucr.ips.const_data().count(); ++i)
+ {
+ ConstUserPtr user;
+ uint32_t ip = m_ucr.ips.const_data().operator[](i).ip;
+ if (m_users.IsIPInUse(ip, m_login, &user))
+ {
+ printfd(__FILE__, "Trying to assign an IP %s to '%s' that is already in use by '%s'\n", inet_ntostring(ip).c_str(), m_login.c_str(), user->GetLogin().c_str());
+ PluginLogger::get("conf_sg")("%s trying to assign an IP %s to '%s' that is currently in use by '%s'", m_currAdmin.logStr().c_str(), inet_ntostring(ip).c_str(), m_login.c_str(), user->GetLogin().c_str());
+ return -1;
+ }
+ }
+
+ if (!m_ucr.ips.empty())
+ if (!u->GetProperties().ips.Set(m_ucr.ips.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.alwaysOnline.empty())
+ if (!u->GetProperties().alwaysOnline.Set(m_ucr.alwaysOnline.const_data(),
+ m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.address.empty())
+ if (!u->GetProperties().address.Set(m_ucr.address.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.creditExpire.empty())
+ if (!u->GetProperties().creditExpire.Set(m_ucr.creditExpire.const_data(),
+ m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.credit.empty())
+ if (!u->GetProperties().credit.Set(m_ucr.credit.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_usr.freeMb.empty())
+ if (!u->GetProperties().freeMb.Set(m_usr.freeMb.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.disabled.empty())
+ if (!u->GetProperties().disabled.Set(m_ucr.disabled.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.disabledDetailStat.empty())
+ if (!u->GetProperties().disabledDetailStat.Set(m_ucr.disabledDetailStat.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.email.empty())
+ if (!u->GetProperties().email.Set(m_ucr.email.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.group.empty())
+ if (!u->GetProperties().group.Set(m_ucr.group.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.note.empty())
+ if (!u->GetProperties().note.Set(m_ucr.note.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ std::vector<STG::UserPropertyLogged<std::string> *> userdata;
+ userdata.push_back(u->GetProperties().userdata0.GetPointer());
+ userdata.push_back(u->GetProperties().userdata1.GetPointer());
+ userdata.push_back(u->GetProperties().userdata2.GetPointer());
+ userdata.push_back(u->GetProperties().userdata3.GetPointer());
+ userdata.push_back(u->GetProperties().userdata4.GetPointer());
+ userdata.push_back(u->GetProperties().userdata5.GetPointer());
+ userdata.push_back(u->GetProperties().userdata6.GetPointer());
+ userdata.push_back(u->GetProperties().userdata7.GetPointer());
+ userdata.push_back(u->GetProperties().userdata8.GetPointer());
+ userdata.push_back(u->GetProperties().userdata9.GetPointer());
+
+ for (int i = 0; i < (int)userdata.size(); i++)
+ if (!m_ucr.userdata[i].empty())
+ if(!userdata[i]->Set(m_ucr.userdata[i].const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.passive.empty())
+ if (!u->GetProperties().passive.Set(m_ucr.passive.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.password.empty())
+ if (!u->GetProperties().password.Set(m_ucr.password.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.phone.empty())
+ if (!u->GetProperties().phone.Set(m_ucr.phone.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_ucr.realName.empty())
+ if (!u->GetProperties().realName.Set(m_ucr.realName.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (!m_usr.cash.empty())
+ {
+ if (m_cashMustBeAdded)
+ {
+ if (!u->GetProperties().cash.Set(m_usr.cash.const_data() + u->GetProperties().cash,
+ m_currAdmin,
+ m_login,
+ m_store,
+ m_cashMsg))
+ return -1;
+ }
+ else
+ {
+ if (!u->GetProperties().cash.Set(m_usr.cash.const_data(), m_currAdmin, m_login, m_store, m_cashMsg))
+ return -1;
+ }
+ }
+
+ if (!m_ucr.tariffName.empty())
+ {
+ const auto newTariff = m_tariffs.FindByName(m_ucr.tariffName.const_data());
+ if (newTariff)
+ {
+ const auto tariff = u->GetTariff();
+ std::string message = tariff->TariffChangeIsAllowed(*newTariff, stgTime);
+ if (message.empty())
+ {
+ if (!u->GetProperties().tariffName.Set(m_ucr.tariffName.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+ u->ResetNextTariff();
+ }
+ else
+ {
+ PluginLogger::get("conf_sg")("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str());
+ }
+ }
+ else
+ {
+ //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
+ return -1;
+ }
+ }
+
+ if (!m_ucr.nextTariff.empty())
+ {
+ if (m_tariffs.FindByName(m_ucr.nextTariff.const_data()))
+ {
+ if (!u->GetProperties().nextTariff.Set(m_ucr.nextTariff.const_data(), m_currAdmin, m_login, m_store))
+ return -1;
+ }
+ else
+ {
+ //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
+ return -1;
+ }
+ }
+
+ auto up = u->GetProperties().up.get();
+ auto down = u->GetProperties().down.get();
+ int upCount = 0;
+ int downCount = 0;
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ if (!m_upr[i].empty())
+ {
+ up[i] = m_upr[i].data();
+ upCount++;
+ }
+ if (!m_downr[i].empty())
+ {
+ down[i] = m_downr[i].data();
+ downCount++;
+ }
+ }
+
+ if (upCount)
+ if (!u->GetProperties().up.Set(up, m_currAdmin, m_login, m_store))
+ return -1;
+
+ if (downCount)
+ if (!u->GetProperties().down.Set(down, m_currAdmin, m_login, m_store))
+ return -1;
+
+ u->WriteConf();
+ u->WriteStat();
+
+ return 0;
+}
+
+int DEL_USER::Start(void *, const char *el, const char **attr)
+{
+ res = 0;
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ if (attr[0] == NULL || attr[1] == NULL)
+ {
+ //CreateAnswer("Parameters error!");
+ CreateAnswer();
+ return 0;
+ }
+
+ if (m_users.FindByName(attr[1], &u))
+ {
+ res = 1;
+ CreateAnswer();
+ return 0;
+ }
+ CreateAnswer();
+ return 0;
+ }
+ return -1;
+}
+
+int DEL_USER::End(void *, const char *el)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ if (!res)
+ m_users.Del(u->GetLogin(), &m_currAdmin);
+
+ return 0;
+ }
+ return -1;
+}
+
+void DEL_USER::CreateAnswer()
+{
+ if (res)
+ m_answer = "<" + m_tag + " value=\"error\" reason=\"User not found\"/>";
+ else
+ m_answer = "<" + m_tag + " value=\"ok\"/>";
+}
+
+int CHECK_USER::Start(void *, const char *el, const char **attr)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ {
+ if (attr[0] == NULL || attr[1] == NULL ||
+ attr[2] == NULL || attr[3] == NULL)
+ {
+ CreateAnswer("Invalid parameters.");
+ printfd(__FILE__, "PARSER_CHECK_USER - attr err\n");
+ return 0;
+ }
+
+ ConstUserPtr user;
+ if (m_users.FindByName(attr[1], &user))
+ {
+ CreateAnswer("User not found.");
+ printfd(__FILE__, "PARSER_CHECK_USER - login err\n");
+ return 0;
+ }
+
+ if (strcmp(user->GetProperties().password.Get().c_str(), attr[3]))
+ {
+ CreateAnswer("Wrong password.");
+ printfd(__FILE__, "PARSER_CHECK_USER - passwd err\n");
+ return 0;
+ }
+
+ CreateAnswer(NULL);
+ return 0;
+ }
+ return -1;
+}
+
+int CHECK_USER::End(void *, const char *el)
+{
+ if (strcasecmp(el, m_tag.c_str()) == 0)
+ return 0;
+ return -1;
+}
+
+void CHECK_USER::CreateAnswer(const char * error)
+{
+ if (error)
+ m_answer = "<" + m_tag + " value=\"Err\" reason=\"" + error + "\"/>";
+ else
+ m_answer = "<" + m_tag + " value=\"Ok\"/>";
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "parser.h"
+
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/common.h"
+#include "stg/optional.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Users;
+struct User;
+struct Tariffs;
+struct Admin;
+struct Store;
+
+namespace PARSER
+{
+
+class GET_USERS: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_USERS(admin, m_users); }
+ static void Register(REGISTRY & registry, Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ Users & m_users;
+ };
+
+ static const char * tag;
+
+ GET_USERS(const Admin & admin, Users & users)
+ : BASE_PARSER(admin, tag), m_users(users),
+ m_lastUserUpdateTime(0) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ Users & m_users;
+ time_t m_lastUserUpdateTime;
+
+ void CreateAnswer();
+};
+
+class GET_USER: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(const Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new GET_USER(admin, m_users); }
+ static void Register(REGISTRY & registry, const Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ const Users & m_users;
+ };
+
+ static const char * tag;
+
+ GET_USER(const Admin & admin, const Users & users)
+ : BASE_PARSER(admin, tag), m_users(users) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ const Users & m_users;
+ std::string m_login;
+
+ void CreateAnswer();
+};
+
+class ADD_USER: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new ADD_USER(admin, m_users); }
+ static void Register(REGISTRY & registry, Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ Users & m_users;
+ };
+
+ static const char * tag;
+
+ ADD_USER(const Admin & admin, Users & users)
+ : BASE_PARSER(admin, tag), m_users(users) {}
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ Users & m_users;
+ std::string m_login;
+
+ void CreateAnswer();
+};
+
+class CHG_USER: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ FACTORY(Users & users, Store & store, const Tariffs & tariffs)
+ : m_users(users), m_store(store), m_tariffs(tariffs)
+ {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new CHG_USER(admin, m_users, m_store, m_tariffs); }
+ static void Register(REGISTRY & registry, Users & users, Store & store, const Tariffs & tariffs)
+ { registry[ToLower(tag)] = new FACTORY(users, store, tariffs); }
+ private:
+ Users & m_users;
+ Store & m_store;
+ const Tariffs & m_tariffs;
+ };
+
+ static const char * tag;
+
+ CHG_USER(const Admin & admin, Users & users,
+ Store & store, const Tariffs & tariffs)
+ : BASE_PARSER(admin, tag),
+ m_users(users),
+ m_store(store),
+ m_tariffs(tariffs),
+ m_cashMustBeAdded(false) {}
+
+ int Start(void * data, const char * el, const char ** attr);
+
+ private:
+ Users & m_users;
+ Store & m_store;
+ const Tariffs & m_tariffs;
+ UserStatOpt m_usr;
+ UserConfOpt m_ucr;
+ Optional<uint64_t> m_upr[DIR_NUM];
+ Optional<uint64_t> m_downr[DIR_NUM];
+ std::string m_cashMsg;
+ std::string m_login;
+ bool m_cashMustBeAdded;
+
+ int ApplyChanges();
+ void CreateAnswer();
+};
+
+class DEL_USER: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new DEL_USER(admin, m_users); }
+ static void Register(REGISTRY & registry, Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ Users & m_users;
+ };
+
+ static const char * tag;
+
+ DEL_USER(const Admin & admin, Users & users)
+ : BASE_PARSER(admin, tag), m_users(users), res(0), u(NULL) {}
+ int Start(void * data, const char * el, const char ** attr);
+ int End(void * data, const char * el);
+
+ private:
+ Users & m_users;
+ int res;
+ User * u;
+
+ void CreateAnswer();
+};
+
+class CHECK_USER: public BASE_PARSER
+{
+ public:
+ class FACTORY : public BASE_PARSER::FACTORY
+ {
+ public:
+ explicit FACTORY(const Users & users) : m_users(users) {}
+ virtual BASE_PARSER * create(const Admin & admin) { return new CHECK_USER(admin, m_users); }
+ static void Register(REGISTRY & registry, const Users & users)
+ { registry[ToLower(tag)] = new FACTORY(users); }
+ private:
+ const Users & m_users;
+ };
+
+ static const char * tag;
+
+ CHECK_USER(const Admin & admin, const Users & users)
+ : BASE_PARSER(admin, tag), m_users(users) {}
+ int Start(void * data, const char * el, const char ** attr);
+ int End(void * data, const char * el);
+
+ private:
+ const Users & m_users;
+
+ void CreateAnswer(const char * error);
+ void CreateAnswer() {} // dummy
+};
+
+} // namespace PARSER
+} // namespace STG
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include "stgconfig.h"
+
+#include "stg/common.h"
+
+#include <algorithm>
+#include <csignal>
+#include <cstring>
+#include <cerrno>
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool STG_CONFIG_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+ STG::ParamValue pv;
+ std::vector<STG::ParamValue>::const_iterator pvi;
+ ///////////////////////////
+ pv.param = "Port";
+ pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+ if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Port\' is not found.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return false;
+ }
+ int p;
+ if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+ {
+ errorStr = "Parameter \'Port\' should be an integral value in range (2, 65535). Actual value: '" + pvi->value[0] + "'.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return false;
+ }
+ m_port = static_cast<uint16_t>(p);
+
+ pv.param = "BindAddress";
+ pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+ if (pvi != s.moduleParams.end() && !pvi->value.empty())
+ m_bindAddress = pvi->value[0];
+
+ return true;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+extern "C" STG::Plugin * GetPlugin()
+{
+ static STG_CONFIG plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+STG_CONFIG::STG_CONFIG()
+ : nonstop(false),
+ isRunning(false),
+ logger(STG::PluginLogger::get("conf_sg")),
+ config(logger)
+{
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG::ParseSettings()
+{
+ if (stgConfigSettings.ParseSettings(settings))
+ return 0;
+ errorStr = stgConfigSettings.GetStrError();
+ return -1;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG::Start()
+{
+ if (isRunning)
+ return 0;
+
+ nonstop = true;
+
+ config.SetPort(stgConfigSettings.GetPort());
+ config.SetBindAddress(stgConfigSettings.GetBindAddress());
+
+ if (config.Prepare())
+ {
+ errorStr = config.GetStrError();
+ return -1;
+ }
+
+ if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = std::string("Cannot create thread: '") + strerror(errno) + "'.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ logger(errorStr);
+ return -1;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG::Stop()
+{
+ if (!isRunning)
+ return 0;
+
+ config.Stop();
+
+ //5 seconds to thread stops itself
+ for (size_t i = 0; i < 25; ++i)
+ {
+ if (!isRunning)
+ break;
+
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+
+ if (isRunning)
+ return -1;
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+void * STG_CONFIG::Run(void * d)
+{
+ sigset_t signalSet;
+ sigfillset(&signalSet);
+ pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+ STG_CONFIG & stgConf = *static_cast<STG_CONFIG *>(d);
+ stgConf.isRunning = true;
+
+ stgConf.config.Run();
+
+ stgConf.isRunning = false;
+
+ return NULL;
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "configproto.h"
+
+#include "stg/plugin.h"
+#include "stg/logger.h"
+
+#include <string>
+
+#include <pthread.h>
+
+class STG_CONFIG_SETTINGS
+{
+ public:
+ STG_CONFIG_SETTINGS() : m_port(0), m_bindAddress("0.0.0.0") {}
+ const std::string & GetStrError() const { return errorStr; }
+ bool ParseSettings(const STG::ModuleSettings & s);
+ uint16_t GetPort() const { return m_port; }
+ const std::string & GetBindAddress() const { return m_bindAddress; }
+ private:
+ std::string errorStr;
+ uint16_t m_port;
+ std::string m_bindAddress;
+};
+
+class STG_CONFIG : public STG::Plugin
+{
+ public:
+ STG_CONFIG();
+
+ void SetUsers(STG::Users * users) override { config.SetUsers(users); }
+ void SetTariffs(STG::Tariffs * tariffs) override { config.SetTariffs(tariffs); }
+ void SetAdmins(STG::Admins * admins) override { config.SetAdmins(admins); }
+ void SetServices(STG::Services * services) override { config.SetServices(services); }
+ void SetCorporations(STG::Corporations * corporations) override { config.SetCorporations( corporations); }
+ void SetStore(STG::Store * store) override { config.SetStore(store); }
+ void SetStgSettings(const STG::Settings * s) override { config.SetSettings(s); }
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override { return isRunning; }
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override { return "Stg Configurator v. 2.0"; }
+ uint16_t GetStartPosition() const override { return 20; }
+ uint16_t GetStopPosition() const override { return 20; }
+
+ private:
+ STG_CONFIG(const STG_CONFIG & rvalue);
+ STG_CONFIG & operator=(const STG_CONFIG & rvalue);
+
+ static void * Run(void *);
+
+ mutable std::string errorStr;
+ STG_CONFIG_SETTINGS stgConfigSettings;
+ pthread_t thread;
+ bool nonstop;
+ bool isRunning;
+ STG::PluginLogger logger;
+ CONFIGPROTO config;
+ STG::ModuleSettings settings;
+};
--- /dev/null
+#include "ping.h"
+
+#include "stg/user.h"
+#include "stg/locker.h"
+#include "stg/user_property.h"
+
+#include <cstdio>
+#include <cassert>
+#include <csignal>
+#include <ctime>
+#include <algorithm>
+
+namespace
+{
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template <typename varType>
+class HAS_USER: public std::binary_function<varType, UserPtr, bool>
+{
+public:
+ explicit HAS_USER(const UserPtr & u) : user(u) {}
+ bool operator()(varType notifier) const
+ {
+ return notifier.GetUser() == user;
+ }
+private:
+ const UserPtr & user;
+};
+}
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static PING plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int PING_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+STG::ParamValue pv;
+std::vector<STG::ParamValue>::const_iterator pvi;
+
+pv.param = "PingDelay";
+pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'PingDelay\' not found.";
+ printfd(__FILE__, "Parameter 'PingDelay' not found\n");
+ return -1;
+ }
+if (ParseIntInRange(pvi->value[0], 5, 3600, &pingDelay))
+ {
+ errorStr = "Cannot parse parameter \'PingDelay\': " + errorStr;
+ printfd(__FILE__, "Canot parse parameter 'PingDelay'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+PING::PING()
+ : users(NULL),
+ nonstop(false),
+ isRunning(false),
+ onAddUserNotifier(*this),
+ onDelUserNotifier(*this),
+ logger(STG::PluginLogger::get("ping"))
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+PING::~PING()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int PING::ParseSettings()
+{
+int ret = pingSettings.ParseSettings(settings);
+if (ret)
+ errorStr = pingSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+int PING::Start()
+{
+GetUsers();
+
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+nonstop = true;
+
+pinger.SetDelayTime(pingSettings.GetPingDelay());
+pinger.Start();
+
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot start thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot start thread\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PING::Stop()
+{
+STG_LOCKER lock(&mutex);
+
+if (!isRunning)
+ return 0;
+
+pinger.Stop();
+nonstop = false;
+//5 seconds to thread stops itself
+struct timespec ts = {0, 200000000};
+for (int i = 0; i < 25; i++)
+ {
+ if (!isRunning)
+ break;
+
+ nanosleep(&ts, NULL);
+ }
+
+users->DelNotifierUserAdd(&onAddUserNotifier);
+users->DelNotifierUserDel(&onDelUserNotifier);
+
+std::list<UserPtr>::iterator users_iter;
+users_iter = usersList.begin();
+while (users_iter != usersList.end())
+ {
+ UnSetUserNotifiers(*users_iter);
+ ++users_iter;
+ }
+
+if (isRunning)
+ return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool PING::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * PING::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+PING * ping = static_cast<PING *>(d);
+ping->isRunning = true;
+
+long delay = (10000000 * ping->pingSettings.GetPingDelay()) / 3 + 50000000;
+
+while (ping->nonstop)
+ {
+ std::list<UserPtr>::iterator iter = ping->usersList.begin();
+ {
+ STG_LOCKER lock(&ping->mutex);
+ while (iter != ping->usersList.end())
+ {
+ if ((*iter)->GetProperties().ips.ConstData().onlyOneIP())
+ {
+ uint32_t ip = (*iter)->GetProperties().ips.ConstData()[0].ip;
+ time_t t;
+ if (ping->pinger.GetIPTime(ip, &t) == 0)
+ {
+ if (t)
+ (*iter)->UpdatePingTime(t);
+ }
+ }
+ else
+ {
+ uint32_t ip = (*iter)->GetCurrIP();
+ if (ip)
+ {
+ time_t t;
+ if (ping->pinger.GetIPTime(ip, &t) == 0)
+ {
+ if (t)
+ (*iter)->UpdatePingTime(t);
+ }
+ }
+ }
+ ++iter;
+ }
+ }
+ struct timespec ts = {delay / 1000000000, delay % 1000000000};
+ for (int i = 0; i < 100; i++)
+ {
+ if (ping->nonstop)
+ {
+ nanosleep(&ts, NULL);
+ }
+ }
+ }
+
+ping->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void PING::SetUserNotifiers(UserPtr u)
+{
+CHG_CURRIP_NOTIFIER_PING ChgCurrIPNotifier(*this, u);
+CHG_IPS_NOTIFIER_PING ChgIPNotifier(*this, u);
+
+ChgCurrIPNotifierList.push_front(ChgCurrIPNotifier);
+ChgIPNotifierList.push_front(ChgIPNotifier);
+
+u->AddCurrIPAfterNotifier(&(*ChgCurrIPNotifierList.begin()));
+u->GetProperties().ips.AddAfterNotifier(&(*ChgIPNotifierList.begin()));
+}
+//-----------------------------------------------------------------------------
+void PING::UnSetUserNotifiers(UserPtr u)
+{
+// --- CurrIP ---
+HAS_USER<CHG_CURRIP_NOTIFIER_PING> IsContainsUserCurrIP(u);
+HAS_USER<CHG_IPS_NOTIFIER_PING> IsContainsUserIP(u);
+
+std::list<CHG_CURRIP_NOTIFIER_PING>::iterator currIPter;
+std::list<CHG_IPS_NOTIFIER_PING>::iterator IPIter;
+
+currIPter = find_if(ChgCurrIPNotifierList.begin(),
+ ChgCurrIPNotifierList.end(),
+ IsContainsUserCurrIP);
+
+if (currIPter != ChgCurrIPNotifierList.end())
+ {
+ currIPter->GetUser()->DelCurrIPAfterNotifier(&(*currIPter));
+ ChgCurrIPNotifierList.erase(currIPter);
+ }
+// --- CurrIP end ---
+
+// --- IP ---
+IPIter = find_if(ChgIPNotifierList.begin(),
+ ChgIPNotifierList.end(),
+ IsContainsUserIP);
+
+if (IPIter != ChgIPNotifierList.end())
+ {
+ IPIter->GetUser()->GetProperties().ips.DelAfterNotifier(&(*IPIter));
+ ChgIPNotifierList.erase(IPIter);
+ }
+// --- IP end ---
+}
+//-----------------------------------------------------------------------------
+void PING::GetUsers()
+{
+STG_LOCKER lock(&mutex);
+
+UserPtr u;
+int h = users->OpenSearch();
+assert(h && "USERS::OpenSearch is always correct");
+
+while (users->SearchNext(h, &u) == 0)
+ {
+ usersList.push_back(u);
+ SetUserNotifiers(u);
+ if (u->GetProperties().ips.ConstData().onlyOneIP())
+ {
+ pinger.AddIP(u->GetProperties().ips.ConstData()[0].ip);
+ }
+ else
+ {
+ uint32_t ip = u->GetCurrIP();
+ if (ip)
+ pinger.AddIP(ip);
+ }
+ }
+
+users->CloseSearch(h);
+}
+//-----------------------------------------------------------------------------
+void PING::AddUser(UserPtr u)
+{
+STG_LOCKER lock(&mutex);
+
+SetUserNotifiers(u);
+usersList.push_back(u);
+}
+//-----------------------------------------------------------------------------
+void PING::DelUser(UserPtr u)
+{
+STG_LOCKER lock(&mutex);
+
+UnSetUserNotifiers(u);
+
+std::list<UserPtr>::iterator users_iter;
+users_iter = usersList.begin();
+
+while (users_iter != usersList.end())
+ {
+ if (u == *users_iter)
+ {
+ usersList.erase(users_iter);
+ break;
+ }
+ ++users_iter;
+ }
+}
+//-----------------------------------------------------------------------------
+void CHG_CURRIP_NOTIFIER_PING::Notify(const uint32_t & oldIP, const uint32_t & newIP)
+{
+ping.pinger.DelIP(oldIP);
+if (newIP)
+ ping.pinger.AddIP(newIP);
+}
+//-----------------------------------------------------------------------------
+void CHG_IPS_NOTIFIER_PING::Notify(const STG::UserIPs & oldIPS, const STG::UserIPs & newIPS)
+{
+if (oldIPS.onlyOneIP())
+ ping.pinger.DelIP(oldIPS[0].ip);
+
+if (newIPS.onlyOneIP())
+ ping.pinger.AddIP(newIPS[0].ip);
+}
+//-----------------------------------------------------------------------------
+void ADD_USER_NONIFIER_PING::Notify(const UserPtr & user)
+{
+ping.AddUser(user);
+}
+//-----------------------------------------------------------------------------
+void DEL_USER_NONIFIER_PING::Notify(const UserPtr & user)
+{
+ping.DelUser(user);
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/notifer.h"
+#include "stg/user_ips.h"
+#include "stg/pinger.h"
+#include "stg/users.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <list>
+#include <cstdint>
+
+#include <pthread.h>
+
+class PING;
+
+namespace STG
+{
+struct USER;
+struct SETTINGS;
+}
+
+using UserPtr = STG::User*;
+//-----------------------------------------------------------------------------*/
+class CHG_CURRIP_NOTIFIER_PING: public STG::PropertyNotifierBase<uint32_t> {
+public:
+ CHG_CURRIP_NOTIFIER_PING(const PING & p, UserPtr u)
+ : user(u), ping(p) {}
+ void Notify(const uint32_t & oldIP, const uint32_t & newIP);
+ UserPtr GetUser() const { return user; }
+
+private:
+ CHG_CURRIP_NOTIFIER_PING & operator=(const CHG_CURRIP_NOTIFIER_PING &);
+
+ UserPtr user;
+ const PING & ping;
+};
+//-----------------------------------------------------------------------------
+class CHG_IPS_NOTIFIER_PING: public STG::PropertyNotifierBase<STG::UserIPs> {
+public:
+ CHG_IPS_NOTIFIER_PING(const PING & p, UserPtr u)
+ : user(u), ping(p) {}
+ void Notify(const STG::UserIPs & oldIPS, const STG::UserIPs & newIPS);
+ UserPtr GetUser() const { return user; }
+
+private:
+ CHG_IPS_NOTIFIER_PING & operator=(const CHG_IPS_NOTIFIER_PING &);
+
+ UserPtr user;
+ const PING & ping;
+};
+//-----------------------------------------------------------------------------
+class ADD_USER_NONIFIER_PING: public STG::NotifierBase<UserPtr> {
+public:
+ explicit ADD_USER_NONIFIER_PING(PING & p) : ping(p) {}
+ void Notify(const UserPtr & user);
+
+private:
+ ADD_USER_NONIFIER_PING(const ADD_USER_NONIFIER_PING &);
+ ADD_USER_NONIFIER_PING & operator=(const ADD_USER_NONIFIER_PING &);
+
+ PING & ping;
+};
+//-----------------------------------------------------------------------------
+class DEL_USER_NONIFIER_PING: public STG::NotifierBase<UserPtr> {
+public:
+ explicit DEL_USER_NONIFIER_PING(PING & p) : ping(p) {}
+ void Notify(const UserPtr & user);
+
+private:
+ DEL_USER_NONIFIER_PING(const DEL_USER_NONIFIER_PING &);
+ DEL_USER_NONIFIER_PING & operator=(const DEL_USER_NONIFIER_PING &);
+
+ PING & ping;
+};
+//-----------------------------------------------------------------------------
+class PING_SETTINGS {
+public:
+ PING_SETTINGS() : pingDelay(0) {}
+ const std::string & GetStrError() const { return errorStr; }
+ int ParseSettings(const STG::ModuleSettings & s);
+ int GetPingDelay() const { return pingDelay; }
+private:
+ int pingDelay;
+ mutable std::string errorStr;
+};
+//-----------------------------------------------------------------------------
+class PING : public STG::Plugin {
+friend class CHG_CURRIP_NOTIFIER_PING;
+friend class CHG_IPS_NOTIFIER_PING;
+public:
+ PING();
+ ~PING() override;
+
+ void SetUsers(STG::Users * u) override { users = u; }
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
+ bool IsRunning() override;
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override { return "Pinger v.1.01"; }
+ uint16_t GetStartPosition() const override { return 10; }
+ uint16_t GetStopPosition() const override { return 10; }
+
+ void AddUser(UserPtr u);
+ void DelUser(UserPtr u);
+
+private:
+ explicit PING(const PING & rvalue);
+ PING & operator=(const PING & rvalue);
+
+ void GetUsers();
+ void SetUserNotifiers(UserPtr u);
+ void UnSetUserNotifiers(UserPtr u);
+ static void * Run(void * d);
+
+ mutable std::string errorStr;
+ PING_SETTINGS pingSettings;
+ STG::ModuleSettings settings;
+ STG::Users * users;
+ std::list<UserPtr> usersList;
+
+ pthread_t thread;
+ pthread_mutex_t mutex;
+ bool nonstop;
+ bool isRunning;
+ mutable STG_PINGER pinger;
+
+ std::list<CHG_CURRIP_NOTIFIER_PING> ChgCurrIPNotifierList;
+ std::list<CHG_IPS_NOTIFIER_PING> ChgIPNotifierList;
+
+ ADD_USER_NONIFIER_PING onAddUserNotifier;
+ DEL_USER_NONIFIER_PING onDelUserNotifier;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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>
+ */
+
+ /*
+ $Revision: 1.8 $
+ $Author: faust $
+ $Date: 2009/10/22 09:58:53 $
+ */
+
+#include <fstream>
+#include <cerrno>
+#include <cstring>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "stg/common.h"
+#include "nrmap_parser.h"
+
+bool NRMapParser::ReadFile(const std::string & fileName)
+{
+std::ifstream source(fileName.c_str());
+
+if (!source)
+ {
+ errorStr = "Error opening file ";
+ errorStr += fileName;
+ printfd(__FILE__, "NRMapParser::ReadFile(): %s\n", errorStr.c_str());
+ return true;
+ }
+
+int lineNumber = 0;
+std::string line;
+std::vector<NET_ROUTER> _nrmap;
+
+while (getline(source, line))
+ {
+ ++lineNumber;
+ NET_ROUTER nr;
+
+ if (Trim(line) == "")
+ {
+ continue;
+ }
+
+ if (ParseLine(line, nr))
+ {
+ printfd(__FILE__, "NRMapParser::ReadFile(): Error parsing line %d: '%s'\n", lineNumber, errorStr.c_str());
+ return true;
+ }
+
+ _nrmap.push_back(nr);
+ }
+
+nrmap = _nrmap;
+
+return false;
+}
+
+bool NRMapParser::ParseLine(const std::string & line, NET_ROUTER & nr) const
+{
+// xxx.xxx.xxx.xxx/yy zzz.zzz.zzz.zzz
+size_t pos = line.find_first_of(" \t");
+
+if (pos == std::string::npos)
+ {
+ errorStr = "No space between subnet and router";
+ return true;
+ }
+
+std::string subnet(line.substr(0, pos)); // xxx.xxx.xxx.xxx/yy
+
+uint32_t ip = 0;
+uint32_t mask = 0;
+
+if (ParseNet(subnet, ip, mask))
+ {
+ return true;
+ }
+
+nr.subnetIP = ip;
+nr.subnetMask = mask;
+
+pos = line.find_first_not_of(" \t", pos);
+
+if (pos == std::string::npos)
+ {
+ errorStr = "No router address found";
+ return true;
+ }
+
+size_t pos2 = line.find_first_of(" \t", pos);
+
+std::string router(line.substr(pos, pos2 == std::string::npos ? line.length() - pos2 - 1 : pos2 - pos)); //zzz.zzz.zzz.zzz
+
+uint32_t routerIP;
+
+if (ParseRouter(router, routerIP))
+ {
+ return true;
+ }
+
+std::vector<uint32_t>::iterator it;
+
+it = std::lower_bound(
+ nr.routers.begin(),
+ nr.routers.end(),
+ routerIP
+ );
+nr.routers.insert(it, routerIP);
+
+//nr.routers.push_back(routerIP);
+
+while (pos2 != std::string::npos)
+ {
+ pos = line.find_first_not_of(" \t", pos2);
+
+ if (pos == std::string::npos)
+ {
+ return false;
+ }
+
+ pos2 = line.find_first_of(" \t", pos);
+
+ if (ParseRouter(line.substr(
+ pos,
+ pos2 == std::string::npos ? line.length() - pos2 - 1 : pos2 - pos),
+ routerIP))
+ {
+ return true;
+ }
+
+ it = std::lower_bound(
+ nr.routers.begin(),
+ nr.routers.end(),
+ routerIP
+ );
+ nr.routers.insert(it, routerIP);
+
+ //nr.routers.push_back(routerIP);
+
+ }
+
+return false;
+}
+
+bool NRMapParser::ParseNet(const std::string & line, uint32_t & ip, uint32_t & mask) const
+{
+// xxx.xxx.xxx.xxx/yy
+
+size_t pos = line.find_first_of('/');
+
+if (pos == std::string::npos)
+ {
+ errorStr = "Subnet is not in CIDR notation";
+ return true;
+ }
+
+int res = inet_pton(AF_INET, line.substr(0, pos).c_str(), &ip); //xxx.xxx.xxx.xxx
+
+if (res < 0)
+ {
+ errorStr = strerror(errno);
+ return true;
+ }
+else if (res == 0)
+ {
+ errorStr = "Invalid subnet address";
+ return true;
+ }
+
+if (str2x(line.substr(pos + 1, line.length() - pos - 1), mask)) //yy
+ {
+ errorStr = "Invalid subnet mask";
+ return true;
+ }
+if (mask > 32)
+ {
+ errorStr = "Subnet mask is out of range [0..32]";
+ return true;
+ }
+mask = htonl(0xffFFffFF << (32 - mask)); //bitmask
+
+return false;
+}
+
+bool NRMapParser::ParseRouter(const std::string & line, uint32_t & ip) const
+{
+int res = inet_pton(AF_INET, line.c_str(), &ip); //zzz.zzz.zzz.zzz
+
+if (res < 0)
+ {
+ errorStr = strerror(errno);
+ return true;
+ }
+else if (res == 0)
+ {
+ printfd(__FILE__, "NRMapParser::ParseRouter(): IP '%s' is invalid\n", line.c_str());
+ errorStr = "Invalid router address";
+ return true;
+ }
+return false;
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+ /*
+ $Revision: 1.2 $
+ $Author: faust $
+ $Date: 2009/09/23 12:51:42 $
+ */
+
+#ifndef __NRMAP_PARSER_H__
+#define __NRMAP_PARSER_H__
+
+#include <string>
+#include <vector>
+#include <cstdint>
+
+struct NET_ROUTER
+{
+ NET_ROUTER() : subnetIP(0), subnetMask(0), routers() {}
+ NET_ROUTER(const NET_ROUTER & rvalue)
+ : subnetIP(rvalue.subnetIP),
+ subnetMask(rvalue.subnetMask),
+ routers(rvalue.routers)
+ {}
+
+ uint32_t subnetIP;
+ uint32_t subnetMask;
+ std::vector<uint32_t> routers;
+
+ NET_ROUTER & operator=(const NET_ROUTER & rvalue)
+ {
+ subnetIP = rvalue.subnetIP;
+ subnetMask = rvalue.subnetMask;
+ routers = rvalue.routers;
+ return *this;
+ }
+};
+
+class NRMapParser {
+public:
+ NRMapParser() : nrmap(), errorStr() {}
+ ~NRMapParser() {}
+
+ bool ReadFile(const std::string & fileName);
+ const std::vector<NET_ROUTER> & GetMap() const { return nrmap; }
+ const std::string & GetErrorStr() const { return errorStr; }
+
+private:
+ NRMapParser(const NRMapParser & rvalue);
+ NRMapParser & operator=(const NRMapParser & rvalue);
+
+ std::vector<NET_ROUTER> nrmap;
+ mutable std::string errorStr;
+
+ bool ParseLine(const std::string & line, NET_ROUTER & nr) const;
+ bool ParseNet(const std::string & line, uint32_t & ip, uint32_t & mask) const;
+ bool ParseRouter(const std::string & line, uint32_t & ip) const;
+};
+
+#endif
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "rscript.h"
+
+#include "ur_functor.h"
+#include "send_functor.h"
+
+#include "stg/common.h"
+#include "stg/locker.h"
+#include "stg/users.h"
+#include "stg/user_property.h"
+#include "stg/logger.h"
+
+#include <algorithm>
+
+#include <csignal>
+#include <cassert>
+#include <cstdlib>
+#include <cerrno>
+#include <cstring>
+
+#include <sys/time.h>
+#include <netinet/ip.h>
+
+#define RS_DEBUG (1)
+#define MAX_SHORT_PCKT (3)
+
+extern volatile time_t stgTime;
+
+using RS::REMOTE_SCRIPT;
+
+namespace {
+
+template<typename T>
+struct USER_IS
+{
+ explicit USER_IS(RS::UserPtr u) : user(u) {}
+ bool operator()(const T & notifier) { return notifier.GetUser() == user; }
+
+ RS::UserPtr user;
+};
+
+} // namespace anonymous
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static REMOTE_SCRIPT plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+RS::SETTINGS::SETTINGS()
+ : sendPeriod(0),
+ port(0)
+{
+}
+//-----------------------------------------------------------------------------
+int RS::SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+int p;
+STG::ParamValue pv;
+std::vector<STG::ParamValue>::const_iterator pvi;
+netRouters.clear();
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Port\' not found.";
+ printfd(__FILE__, "Parameter 'Port' not found\n");
+ return -1;
+ }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+ {
+ errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+ return -1;
+ }
+port = static_cast<uint16_t>(p);
+///////////////////////////
+pv.param = "SendPeriod";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'SendPeriod\' not found.";
+ printfd(__FILE__, "Parameter 'SendPeriod' not found\n");
+ return -1;
+ }
+
+if (ParseIntInRange(pvi->value[0], 5, 600, &sendPeriod))
+ {
+ errorStr = "Cannot parse parameter \'SendPeriod\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'SendPeriod'\n");
+ return -1;
+ }
+///////////////////////////
+pv.param = "UserParams";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'UserParams\' not found.";
+ printfd(__FILE__, "Parameter 'UserParams' not found\n");
+ return -1;
+ }
+userParams = pvi->value;
+///////////////////////////
+pv.param = "Password";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Password\' not found.";
+ printfd(__FILE__, "Parameter 'Password' not found\n");
+ return -1;
+ }
+password = pvi->value[0];
+///////////////////////////
+pv.param = "SubnetFile";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'SubnetFile\' not found.";
+ printfd(__FILE__, "Parameter 'SubnetFile' not found\n");
+ return -1;
+ }
+subnetFile = pvi->value[0];
+
+NRMapParser nrMapParser;
+
+if (!nrMapParser.ReadFile(subnetFile))
+ {
+ netRouters = nrMapParser.GetMap();
+ }
+else
+ {
+ STG::PluginLogger::get("rscript")("mod_rscript: error opening subnets file '%s'", subnetFile.c_str());
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+REMOTE_SCRIPT::REMOTE_SCRIPT()
+ : sendPeriod(15),
+ halfPeriod(8),
+ nonstop(false),
+ isRunning(false),
+ users(NULL),
+ sock(0),
+ onAddUserNotifier(*this),
+ onDelUserNotifier(*this),
+ logger(STG::PluginLogger::get("rscript"))
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+REMOTE_SCRIPT::~REMOTE_SCRIPT()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+void * REMOTE_SCRIPT::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+REMOTE_SCRIPT * rs = static_cast<REMOTE_SCRIPT *>(d);
+
+rs->isRunning = true;
+
+while (rs->nonstop)
+ {
+ rs->PeriodicSend();
+ sleep(2);
+ }
+
+rs->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::ParseSettings()
+{
+int ret = rsSettings.ParseSettings(settings);
+if (ret)
+ errorStr = rsSettings.GetStrError();
+
+sendPeriod = rsSettings.GetSendPeriod();
+halfPeriod = sendPeriod / 2;
+
+return ret;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::Start()
+{
+netRouters = rsSettings.GetSubnetsMap();
+
+InitEncrypt(&ctx, rsSettings.GetPassword());
+
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+nonstop = true;
+
+if (GetUsers())
+ {
+ return -1;
+ }
+
+if (PrepareNet())
+ {
+ return -1;
+ }
+
+if (!isRunning)
+ {
+ if (pthread_create(&thread, NULL, Run, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+ }
+
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::Stop()
+{
+if (!IsRunning())
+ return 0;
+
+nonstop = false;
+
+std::for_each(
+ authorizedUsers.begin(),
+ authorizedUsers.end(),
+ DisconnectUser(*this)
+ );
+
+FinalizeNet();
+
+if (isRunning)
+ {
+ //5 seconds to thread stops itself
+ for (int i = 0; i < 25 && isRunning; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ }
+
+users->DelNotifierUserDel(&onDelUserNotifier);
+users->DelNotifierUserAdd(&onAddUserNotifier);
+
+if (isRunning)
+ {
+ logger("Cannot stop thread.");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::Reload(const STG::ModuleSettings & /*ms*/)
+{
+NRMapParser nrMapParser;
+
+if (nrMapParser.ReadFile(rsSettings.GetMapFileName()))
+ {
+ errorStr = nrMapParser.GetErrorStr();
+ logger("Map file reading error: %s", errorStr.c_str());
+ return -1;
+ }
+
+ {
+ STG_LOCKER lock(&mutex);
+
+ printfd(__FILE__, "REMOTE_SCRIPT::Reload()\n");
+
+ netRouters = nrMapParser.GetMap();
+ }
+
+std::for_each(authorizedUsers.begin(),
+ authorizedUsers.end(),
+ UpdateRouter(*this));
+
+logger("%s reloaded successfully.", rsSettings.GetMapFileName().c_str());
+printfd(__FILE__, "REMOTE_SCRIPT::Reload() %s reloaded successfully.\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::PrepareNet()
+{
+sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (sock < 0)
+ {
+ errorStr = "Cannot create socket.";
+ logger("Canot create a socket: %s", strerror(errno));
+ printfd(__FILE__, "Cannot create socket\n");
+ return true;
+ }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::FinalizeNet()
+{
+close(sock);
+return false;
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::PeriodicSend()
+{
+STG_LOCKER lock(&mutex);
+
+std::map<uint32_t, RS::USER>::iterator it(authorizedUsers.begin());
+while (it != authorizedUsers.end())
+ {
+ if (difftime(stgTime, it->second.lastSentTime) - (rand() % halfPeriod) > sendPeriod)
+ {
+ Send(it->second);
+ }
+ ++it;
+ }
+}
+//-----------------------------------------------------------------------------
+#ifdef NDEBUG
+bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t, RS::USER & rsu, bool forceDisconnect) const
+#else
+bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t bufSize, RS::USER & rsu, bool forceDisconnect) const
+#endif
+{
+RS::PACKET_HEADER packetHead;
+
+memset(packetHead.padding, 0, sizeof(packetHead.padding));
+strcpy((char*)packetHead.magic, RS_ID);
+packetHead.protoVer[0] = '0';
+packetHead.protoVer[1] = '2';
+if (forceDisconnect)
+ {
+ packetHead.packetType = RS_DISCONNECT_PACKET;
+ printfd(__FILE__, "RSCRIPT: force disconnect for '%s'\n", rsu.user->GetLogin().c_str());
+ }
+else
+ {
+ if (rsu.shortPacketsCount % MAX_SHORT_PCKT == 0)
+ {
+ //SendLong
+ packetHead.packetType = rsu.user->IsInetable() ? RS_CONNECT_PACKET : RS_DISCONNECT_PACKET;
+ if (rsu.user->IsInetable())
+ printfd(__FILE__, "RSCRIPT: connect for '%s'\n", rsu.user->GetLogin().c_str());
+ else
+ printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
+ }
+ else
+ {
+ //SendShort
+ packetHead.packetType = rsu.user->IsInetable() ? RS_ALIVE_PACKET : RS_DISCONNECT_PACKET;
+ if (rsu.user->IsInetable())
+ printfd(__FILE__, "RSCRIPT: alive for '%s'\n", rsu.user->GetLogin().c_str());
+ else
+ printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
+ }
+ }
+rsu.shortPacketsCount++;
+rsu.lastSentTime = stgTime;
+
+packetHead.ip = htonl(rsu.ip);
+packetHead.id = htonl(rsu.user->GetID());
+strncpy((char*)packetHead.login, rsu.user->GetLogin().c_str(), RS_LOGIN_LEN);
+packetHead.login[RS_LOGIN_LEN - 1] = 0;
+
+memcpy(buf, &packetHead, sizeof(packetHead));
+
+if (packetHead.packetType == RS_ALIVE_PACKET)
+ {
+ return false;
+ }
+
+RS::PACKET_TAIL packetTail;
+
+memset(packetTail.padding, 0, sizeof(packetTail.padding));
+strcpy((char*)packetTail.magic, RS_ID);
+std::vector<std::string>::const_iterator it;
+std::string params;
+for(it = rsSettings.GetUserParams().begin();
+ it != rsSettings.GetUserParams().end();
+ ++it)
+ {
+ std::string parameter(rsu.user->GetParamValue(it->c_str()));
+ if (params.length() + parameter.length() > RS_PARAMS_LEN - 1)
+ {
+ logger("Script params string length %d exceeds the limit of %d symbols.", params.length() + parameter.length(), RS_PARAMS_LEN);
+ break;
+ }
+ params += parameter + " ";
+ }
+strncpy((char *)packetTail.params, params.c_str(), RS_PARAMS_LEN);
+packetTail.params[RS_PARAMS_LEN - 1] = 0;
+
+assert(sizeof(packetHead) + sizeof(packetTail) <= bufSize && "Insufficient buffer space");
+
+Encrypt(&ctx, buf + sizeof(packetHead), (char *)&packetTail, sizeof(packetTail) / 8);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::Send(RS::USER & rsu, bool forceDisconnect) const
+{
+char buffer[RS_MAX_PACKET_LEN];
+
+memset(buffer, 0, sizeof(buffer));
+
+if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
+ {
+ printfd(__FILE__, "REMOTE_SCRIPT::Send() - Invalid packet length!\n");
+ return true;
+ }
+
+std::for_each(
+ rsu.routers.begin(),
+ rsu.routers.end(),
+ PacketSender(sock, buffer, sizeof(buffer), static_cast<uint16_t>(htons(rsSettings.GetPort())))
+ );
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::SendDirect(RS::USER & rsu, uint32_t routerIP, bool forceDisconnect) const
+{
+char buffer[RS_MAX_PACKET_LEN];
+
+if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
+ {
+ printfd(__FILE__, "REMOTE_SCRIPT::SendDirect() - Invalid packet length!\n");
+ return true;
+ }
+
+struct sockaddr_in sendAddr;
+
+sendAddr.sin_family = AF_INET;
+sendAddr.sin_port = static_cast<uint16_t>(htons(rsSettings.GetPort()));
+sendAddr.sin_addr.s_addr = routerIP;
+
+ssize_t res = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&sendAddr, sizeof(sendAddr));
+
+if (res < 0)
+ logger("sendto error: %s", strerror(errno));
+
+return (res != sizeof(buffer));
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::GetUsers()
+{
+UserPtr u;
+
+int h = users->OpenSearch();
+assert(h && "USERS::OpenSearch is always correct");
+
+while (!users->SearchNext(h, &u))
+ {
+ SetUserNotifiers(u);
+ }
+
+users->CloseSearch(h);
+return false;
+}
+//-----------------------------------------------------------------------------
+std::vector<uint32_t> REMOTE_SCRIPT::IP2Routers(uint32_t ip)
+{
+STG_LOCKER lock(&mutex);
+for (size_t i = 0; i < netRouters.size(); ++i)
+ {
+ if ((ip & netRouters[i].subnetMask) == (netRouters[i].subnetIP & netRouters[i].subnetMask))
+ {
+ return netRouters[i].routers;
+ }
+ }
+return std::vector<uint32_t>();
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::SetUserNotifiers(UserPtr u)
+{
+ipNotifierList.push_front(RS::IP_NOTIFIER(*this, u));
+connNotifierList.push_front(RS::CONNECTED_NOTIFIER(*this, u));
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::UnSetUserNotifiers(UserPtr u)
+{
+ipNotifierList.erase(std::remove_if(ipNotifierList.begin(),
+ ipNotifierList.end(),
+ USER_IS<IP_NOTIFIER>(u)),
+ ipNotifierList.end());
+connNotifierList.erase(std::remove_if(connNotifierList.begin(),
+ connNotifierList.end(),
+ USER_IS<CONNECTED_NOTIFIER>(u)),
+ connNotifierList.end());
+
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::AddRSU(UserPtr user)
+{
+RS::USER rsu(IP2Routers(user->GetCurrIP()), user);
+Send(rsu);
+
+STG_LOCKER lock(&mutex);
+authorizedUsers.insert(std::make_pair(user->GetCurrIP(), rsu));
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::DelRSU(UserPtr user)
+{
+STG_LOCKER lock(&mutex);
+std::map<uint32_t, RS::USER>::iterator it(authorizedUsers.begin());
+while (it != authorizedUsers.end())
+ {
+ if (it->second.user == user)
+ {
+ Send(it->second, true);
+ authorizedUsers.erase(it);
+ return;
+ }
+ ++it;
+ }
+/*const std::map<uint32_t, RS::USER>::iterator it(
+ authorizedUsers.find(user->GetCurrIP())
+ );
+if (it != authorizedUsers.end())
+ {
+ Send(it->second, true);
+ authorizedUsers.erase(it);
+ }*/
+}
+//-----------------------------------------------------------------------------
+void RS::IP_NOTIFIER::Notify(const uint32_t & /*oldValue*/, const uint32_t & newValue)
+{
+if (newValue)
+ rs.AddRSU(user);
+else
+ rs.DelRSU(user);
+}
+//-----------------------------------------------------------------------------
+void RS::CONNECTED_NOTIFIER::Notify(const bool & /*oldValue*/, const bool & newValue)
+{
+if (newValue)
+ rs.AddRSU(user);
+else
+ rs.DelRSU(user);
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) const
+{
+unsigned char keyL[PASSWD_LEN]; // Пароль для шифровки
+memset(keyL, 0, PASSWD_LEN);
+strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, size_t len8) const
+{
+if (dst != src)
+ memcpy(dst, src, len8 * 8);
+for (size_t i = 0; i < len8; ++i)
+ Blowfish_Encrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ * Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/notifer.h"
+#include "stg/user.h"
+#include "stg/blowfish.h"
+#include "stg/rs_packets.h"
+#include "stg/logger.h"
+
+#include "nrmap_parser.h"
+
+#include <string>
+#include <list>
+#include <map>
+#include <functional>
+#include <utility>
+#include <cstdint>
+
+#include <pthread.h>
+
+namespace STG
+{
+struct Settings;
+struct Settings;
+}
+
+namespace RS
+{
+
+class REMOTE_SCRIPT;
+class UpdateRouter;
+class DisconnectUser;
+
+using UserPtr = STG::User*;
+
+//-----------------------------------------------------------------------------
+class ADD_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
+public:
+ explicit ADD_USER_NONIFIER(REMOTE_SCRIPT & r)
+ : rs(r) {}
+ void Notify(const UserPtr & user);
+
+private:
+ ADD_USER_NONIFIER(const ADD_USER_NONIFIER & rhs);
+ ADD_USER_NONIFIER & operator=(const ADD_USER_NONIFIER);
+
+ REMOTE_SCRIPT & rs;
+};
+//-----------------------------------------------------------------------------
+class DEL_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
+public:
+ explicit DEL_USER_NONIFIER(REMOTE_SCRIPT & r)
+ : rs(r) {}
+ void Notify(const UserPtr & user);
+
+private:
+ DEL_USER_NONIFIER(const DEL_USER_NONIFIER & rhs);
+ DEL_USER_NONIFIER & operator=(const DEL_USER_NONIFIER);
+
+ REMOTE_SCRIPT & rs;
+};
+//-----------------------------------------------------------------------------
+class IP_NOTIFIER: public STG::PropertyNotifierBase<uint32_t> {
+public:
+ IP_NOTIFIER(REMOTE_SCRIPT & r, UserPtr u)
+ : user(u), rs(r) { user->AddCurrIPAfterNotifier(this); }
+ IP_NOTIFIER(const IP_NOTIFIER & rhs)
+ : user(rhs.user), rs(rhs.rs) { user->AddCurrIPAfterNotifier(this); }
+ ~IP_NOTIFIER() { user->DelCurrIPAfterNotifier(this); }
+
+ IP_NOTIFIER & operator=(const IP_NOTIFIER & rhs)
+ {
+ user->DelCurrIPAfterNotifier(this);
+ user = rhs.user;
+ user->AddCurrIPAfterNotifier(this);
+ return *this;
+ }
+
+ void Notify(const uint32_t & oldValue, const uint32_t & newValue);
+ UserPtr GetUser() const { return user; }
+
+private:
+
+ UserPtr user;
+ REMOTE_SCRIPT & rs;
+};
+//-----------------------------------------------------------------------------
+class CONNECTED_NOTIFIER: public STG::PropertyNotifierBase<bool> {
+public:
+ CONNECTED_NOTIFIER(REMOTE_SCRIPT & r, UserPtr u)
+ : user(u), rs(r) { user->AddConnectedAfterNotifier(this); }
+ CONNECTED_NOTIFIER(const CONNECTED_NOTIFIER & rhs)
+ : user(rhs.user), rs(rhs.rs) { user->AddConnectedAfterNotifier(this); }
+ ~CONNECTED_NOTIFIER() { user->DelConnectedAfterNotifier(this); }
+
+ CONNECTED_NOTIFIER & operator=(const CONNECTED_NOTIFIER & rhs)
+ {
+ user->DelConnectedAfterNotifier(this);
+ user = rhs.user;
+ user->AddConnectedAfterNotifier(this);
+ return *this;
+ }
+
+ void Notify(const bool & oldValue, const bool & newValue);
+ UserPtr GetUser() const { return user; }
+
+private:
+
+ UserPtr user;
+ REMOTE_SCRIPT & rs;
+};
+//-----------------------------------------------------------------------------
+struct USER {
+ USER(const std::vector<uint32_t> & r, UserPtr it)
+ : lastSentTime(0),
+ user(it),
+ routers(r),
+ shortPacketsCount(0),
+ ip(user->GetCurrIP())
+ {}
+
+ time_t lastSentTime;
+ UserPtr user;
+ std::vector<uint32_t> routers;
+ int shortPacketsCount;
+ uint32_t ip;
+};
+//-----------------------------------------------------------------------------
+class SETTINGS {
+public:
+ SETTINGS();
+ virtual ~SETTINGS() {}
+ const std::string & GetStrError() const { return errorStr; }
+ int ParseSettings(const STG::ModuleSettings & s);
+ int GetSendPeriod() const { return sendPeriod; }
+ uint16_t GetPort() const { return port; }
+ const std::vector<NET_ROUTER> & GetSubnetsMap() const { return netRouters; }
+ const std::vector<std::string> & GetUserParams() const { return userParams; }
+ const std::string & GetPassword() const { return password; }
+ const std::string & GetMapFileName() const { return subnetFile; }
+
+private:
+ int sendPeriod;
+ uint16_t port;
+ std::string errorStr;
+ std::vector<NET_ROUTER> netRouters;
+ std::vector<std::string> userParams;
+ std::string password;
+ std::string subnetFile;
+};
+//-----------------------------------------------------------------------------
+class REMOTE_SCRIPT : public STG::Plugin {
+public:
+ REMOTE_SCRIPT();
+ ~REMOTE_SCRIPT() override;
+
+ void SetUsers(STG::Users * u) override { users = u; }
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ int Start() override;
+ int Stop() override;
+ int Reload(const STG::ModuleSettings & ms) override;
+ bool IsRunning() override { return isRunning; }
+
+ const std::string & GetStrError() const override { return errorStr; }
+ std::string GetVersion() const override { return "Remote script v 0.3"; }
+ uint16_t GetStartPosition() const override { return 10; }
+ uint16_t GetStopPosition() const override { return 10; }
+
+ void DelUser(UserPtr u) { UnSetUserNotifiers(u); }
+ void AddUser(UserPtr u) { SetUserNotifiers(u); }
+
+ void AddRSU(UserPtr user);
+ void DelRSU(UserPtr user);
+
+private:
+ REMOTE_SCRIPT(const REMOTE_SCRIPT & rhs);
+ REMOTE_SCRIPT & operator=(const REMOTE_SCRIPT & rhs);
+
+ static void * Run(void *);
+ bool PrepareNet();
+ bool FinalizeNet();
+
+ bool Send(USER & rsu, bool forceDisconnect = false) const;
+ bool SendDirect(USER & rsu, uint32_t routerIP, bool forceDisconnect = false) const;
+ bool PreparePacket(char * buf, size_t bufSize, USER &rsu, bool forceDisconnect = false) const;
+ void PeriodicSend();
+
+ std::vector<uint32_t> IP2Routers(uint32_t ip);
+ bool GetUsers();
+
+ void SetUserNotifiers(UserPtr u);
+ void UnSetUserNotifiers(UserPtr u);
+
+ void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) const;
+ void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, size_t len8) const;
+
+ mutable BLOWFISH_CTX ctx;
+
+ std::list<IP_NOTIFIER> ipNotifierList;
+ std::list<CONNECTED_NOTIFIER> connNotifierList;
+ std::map<uint32_t, USER> authorizedUsers;
+
+ mutable std::string errorStr;
+ SETTINGS rsSettings;
+ STG::ModuleSettings settings;
+ int sendPeriod;
+ int halfPeriod;
+
+ bool nonstop;
+ bool isRunning;
+
+ STG::Users * users;
+
+ std::vector<NET_ROUTER> netRouters;
+
+ pthread_t thread;
+ pthread_mutex_t mutex;
+
+ int sock;
+
+ ADD_USER_NONIFIER onAddUserNotifier;
+ DEL_USER_NONIFIER onDelUserNotifier;
+
+ STG::PluginLogger logger;
+
+ friend class RS::UpdateRouter;
+ friend class RS::DisconnectUser;
+ friend class RS::CONNECTED_NOTIFIER;
+};
+//-----------------------------------------------------------------------------
+class DisconnectUser : public std::unary_function<std::pair<const uint32_t, USER> &, void> {
+ public:
+ explicit DisconnectUser(REMOTE_SCRIPT & rs) : rscript(rs) {}
+ void operator()(std::pair<const uint32_t, USER> & p)
+ {
+ rscript.Send(p.second, true);
+ }
+ private:
+ REMOTE_SCRIPT & rscript;
+};
+//-----------------------------------------------------------------------------
+inline void ADD_USER_NONIFIER::Notify(const UserPtr & user)
+{
+rs.AddUser(user);
+}
+//-----------------------------------------------------------------------------
+inline void DEL_USER_NONIFIER::Notify(const UserPtr & user)
+{
+rs.DelUser(user);
+}
+//-----------------------------------------------------------------------------
+
+} // namespace RS
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2010/03/04 12:11:09 $
+ $Author: faust $
+*/
+
+#ifndef __SEND_FUNCTOR_H__
+#define __SEND_FUNCTOR_H__
+
+#include <functional>
+#include <cstdint>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+class PacketSender : public std::unary_function<uint32_t, ssize_t> {
+ public:
+ PacketSender(int s, char * b, size_t l, uint16_t p)
+ : sock(s),
+ buffer(b),
+ length(l),
+ port(p) {}
+ ssize_t operator() (uint32_t ip)
+ {
+ struct sockaddr_in sendAddr;
+
+ sendAddr.sin_family = AF_INET;
+ sendAddr.sin_port = port;
+ sendAddr.sin_addr.s_addr = ip;
+
+ return sendto(sock, buffer, length, 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+ }
+ private:
+ int sock;
+ char * buffer;
+ size_t length;
+ uint16_t port;
+};
+
+#endif
--- /dev/null
+/*
+ * 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>
+ */
+
+#ifndef __UR_FUNCTOR_H__
+#define __UR_FUNCTOR_H__
+
+#include "rscript.h"
+
+#include "stg/common.h"
+
+#include <functional>
+#include <algorithm>
+#include <utility>
+#include <cstdint>
+
+namespace RS
+{
+
+class UpdateRouter : public std::unary_function<std::pair<const uint32_t, RS::USER>, void>
+{
+public:
+ explicit UpdateRouter(REMOTE_SCRIPT & t)
+ : obj(t) {}
+
+ void operator() (std::pair<const uint32_t, USER> & val)
+ {
+ std::vector<uint32_t> newRouters = obj.IP2Routers(val.second.ip);
+ std::vector<uint32_t>::const_iterator oldIt(val.second.routers.begin());
+ std::vector<uint32_t>::const_iterator newIt(newRouters.begin());
+ val.second.shortPacketsCount = 0;
+ while (oldIt != val.second.routers.end() ||
+ newIt != newRouters.end())
+ {
+ if (oldIt == val.second.routers.end())
+ {
+ if (newIt != newRouters.end())
+ {
+ obj.SendDirect(val.second, *newIt); // Connect on new router
+ ++newIt;
+ }
+ }
+ else if (newIt == newRouters.end())
+ {
+ obj.SendDirect(val.second, *oldIt, true); // Disconnect on old router
+ ++oldIt;
+ }
+ else if (*oldIt < *newIt)
+ {
+ obj.SendDirect(val.second, *oldIt, true); // Disconnect on old router
+ ++oldIt;
+ }
+ else if (*oldIt > *newIt)
+ {
+ obj.SendDirect(val.second, *newIt); // Connect on new router
+ ++newIt;
+ }
+ else
+ {
+ ++oldIt;
+ if (newIt != newRouters.end())
+ ++newIt;
+ }
+ }
+ val.second.routers = newRouters;
+ }
+private:
+ REMOTE_SCRIPT & obj;
+};
+
+} // namespace RS
+
+#endif
--- /dev/null
+STG-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ enterprises,
+ MODULE-IDENTITY, OBJECT-TYPE,
+ Integer32 FROM SNMPv2-SMI
+ DisplayString FROM SNMPv2-TC;
+
+stgMIB MODULE-IDENTITY
+ LAST-UPDATED "201101060000Z"
+ ORGANIZATION "STG"
+ CONTACT-INFO
+ "Primary Contact: Maxim Mamontov
+ email: faust@stg.dp.ua"
+ DESCRIPTION
+ "This MIB module defines objects for Stargazer data."
+ REVISION "201101060000Z"
+ DESCRIPTION "Initial revision"
+ ::= { enterprises 38313 }
+
+stg24 OBJECT IDENTIFIER ::= { stgMIB 1 }
+
+users OBJECT IDENTIFIER ::= { stg24 1 }
+tariffs OBJECT IDENTIFIER ::= { stg24 2 }
+admins OBJECT IDENTIFIER ::= { stg24 3 }
+services OBJECT IDENTIFIER ::= { stg24 4 }
+corporations OBJECT IDENTIFIER ::= { stg24 5 }
+traffcounter OBJECT IDENTIFIER ::= { stg24 6 }
+
+totalUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total users registered in the billing"
+ DEFVAL { 0 }
+ ::= { users 1 }
+
+onlineUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of currently online users"
+ DEFVAL { 0 }
+ ::= { users 2 }
+
+authorizedUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of currently authorized users"
+ DEFVAL { 0 }
+ ::= { users 3 }
+
+alwaysOnlineUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of users with 'always online' option"
+ DEFVAL { 0 }
+ ::= { users 4 }
+
+noCashUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of users with negative cash"
+ DEFVAL { 0 }
+ ::= { users 5 }
+
+disabledDetailStatsUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of users with disabled detail stats"
+ DEFVAL { 0 }
+ ::= { users 6 }
+
+disabledUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of disabled users"
+ DEFVAL { 0 }
+ ::= { users 7 }
+
+passiveUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of passive users"
+ DEFVAL { 0 }
+ ::= { users 8 }
+
+creditUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of users with positive credit"
+ DEFVAL { 0 }
+ ::= { users 9 }
+
+freeMbUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of users with positive freeMb"
+ DEFVAL { 0 }
+ ::= { users 10 }
+
+tariffChangeUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of users changing tariff next month"
+ DEFVAL { 0 }
+ ::= { users 11 }
+
+activeUsers OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of online users with traffic during session"
+ DEFVAL {0}
+ ::= { users 12 }
+
+totalTariffs OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total tariffs registered in the billing"
+ DEFVAL { 0 }
+ ::= { tariffs 1 }
+
+tariffUsageTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TariffUsageTable
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The number of users by each tariff"
+ DEFVAL { 0 }
+ ::= { tariffs 2 }
+
+tariffUsageTableEntry OBJECT-TYPE
+ SYNTAX TariffUsageTable
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A row describing a given tariff"
+ INDEX { tariffIndex }
+ ::= {tariffUsageTable 1 }
+
+TariffUsageTable ::= SEQUENCE {
+ tariffIndex Integer32,
+ tariffName DisplayString,
+ userCount Integer32
+}
+
+tariffIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..255)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The id of the tariff this table describes."
+ ::= { tariffUsageTableEntry 1 }
+
+tariffName OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the tariff this table describes."
+ ::= { tariffUsageTableEntry 2 }
+
+userCount OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The count fo users of the tariff this table describes."
+ ::= { tariffUsageTableEntry 3 }
+
+totalAdmins OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total admins registered in the billing"
+ DEFVAL { 0 }
+ ::= { admins 1 }
+
+totalServices OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total services registered in the billing"
+ DEFVAL { 0 }
+ ::= { services 1 }
+
+totalCorporations OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total corporations registered in the billing"
+ DEFVAL { 0 }
+ ::= { corporations 1 }
+
+totalRules OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Total traffic classification rules described by rules file"
+ DEFVAL { 0 }
+ ::= { traffcounter 1 }
+
+END
--- /dev/null
+Количество пользователей всего в биллинге
+Количество пользователей онлайн
+Количество пользователей с отрицательный балансом
+Количество пользователей с всегда онлайн
+Количество пользователей по отношению к каждому из тарифов
+Количество пользователей по отношению к каждому UserData полю - ?
+Количество пользователей с отключенной детальной статистикой
+Количество отключенных пользователей
+Количество замороженных пользователей
+Количество пользователей, у которых есть кредит
+Количество пользователей, у которых есть предоплаченный трафик
+
+Количество тарифов
+Количество направлений
--- /dev/null
+#include <cassert>
+
+#include "stg/GetRequest-PDU.h"
+#include "stg/GetResponse-PDU.h"
+#include "stg/VarBindList.h"
+#include "stg/VarBind.h"
+
+#include "stg/common.h"
+
+#include "utils.h"
+#include "smux.h"
+
+#ifdef SMUX_DEBUG
+bool SMUX::CloseHandler(const SMUX_PDUs_t * pdus)
+{
+printfd(__FILE__, "SMUX::CloseHandler()\n");
+asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
+return true;
+}
+#else
+bool SMUX::CloseHandler(const SMUX_PDUs_t *)
+{
+return true;
+}
+#endif
+
+#ifdef SMUX_DEBUG
+bool SMUX::RegisterResponseHandler(const SMUX_PDUs_t * pdus)
+{
+printfd(__FILE__, "SMUX::RegisterResponseHandler()\n");
+asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
+return true;
+}
+#else
+bool SMUX::RegisterResponseHandler(const SMUX_PDUs_t *)
+{
+return true;
+}
+#endif
+
+bool SMUX::PDUsRequestHandler(const SMUX_PDUs_t * pdus)
+{
+#ifdef SMUX_DEBUG
+printfd(__FILE__, "SMUX::PDUsRequestHandler()\n");
+asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
+#endif
+PDUsHandlers::iterator it(pdusHandlers.find(pdus->choice.pdus.present));
+if (it != pdusHandlers.end())
+ {
+ return (this->*(it->second))(&pdus->choice.pdus);
+ }
+#ifdef SMUX_DEBUG
+else
+ {
+ switch (pdus->present)
+ {
+ case PDUs_PR_NOTHING:
+ printfd(__FILE__, "SMUX::PDUsRequestHandler() - nothing\n");
+ break;
+ case PDUs_PR_get_response:
+ printfd(__FILE__, "SMUX::PDUsRequestHandler() - get response\n");
+ break;
+ case PDUs_PR_trap:
+ printfd(__FILE__, "SMUX::PDUsRequestHandler() - trap\n");
+ break;
+ default:
+ printfd(__FILE__, "SMUX::PDUsRequestHandler() - undefined\n");
+ }
+ }
+#endif
+return true;
+}
+
+#ifdef SMUX_DEBUG
+bool SMUX::CommitOrRollbackHandler(const SMUX_PDUs_t * pdus)
+{
+printfd(__FILE__, "SMUX::CommitOrRollbackHandler()\n");
+asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
+return true;
+}
+#else
+bool SMUX::CommitOrRollbackHandler(const SMUX_PDUs_t *)
+{
+return true;
+}
+#endif
+
+bool SMUX::GetRequestHandler(const PDUs_t * pdus)
+{
+#ifdef SMUX_DEBUG
+printfd(__FILE__, "SMUX::GetRequestHandler()\n");
+asn_fprint(stderr, &asn_DEF_PDUs, pdus);
+#endif
+const GetRequest_PDU_t * getRequest = &pdus->choice.get_request;
+GetResponse_PDU_t * msg = static_cast<GetResponse_PDU_t *>(calloc(1, sizeof(GetResponse_PDU_t)));
+assert(msg && "Enought mempry to allocate GetResponse_PDU_t");
+VarBindList_t * varBindList = &msg->variable_bindings;
+
+long id = 0;
+asn_INTEGER2long(&getRequest->request_id, &id);
+asn_long2INTEGER(&msg->request_id, id);
+asn_long2INTEGER(&msg->error_status, 0);
+asn_long2INTEGER(&msg->error_index, 0);
+
+const VarBindList_t * vbl = &getRequest->variable_bindings;
+for (int i = 0; i < vbl->list.count; ++i)
+ {
+ VarBind_t * vb = getRequest->variable_bindings.list.array[i];
+ Sensors::iterator it;
+ it = sensors.find(OID(&vb->name));
+ if (it == sensors.end())
+ {
+ return SendGetResponseErrorPDU(sock, getRequest,
+ PDU__error_status_noSuchName, i);
+ }
+
+ VarBind_t * newVb = static_cast<VarBind_t *>(calloc(1, sizeof(VarBind_t)));
+ assert(newVb && "Enought mempry to allocate VarBind_t");
+
+ it->first.ToOID(&newVb->name);
+ it->second->GetValue(&newVb->value);
+
+ ASN_SEQUENCE_ADD(varBindList, newVb);
+ }
+
+bool res = SendGetResponsePDU(sock, msg);
+#ifdef SMUX_DEBUG
+asn_fprint(stderr, &asn_DEF_GetResponse_PDU, msg);
+#endif
+ASN_STRUCT_FREE(asn_DEF_GetResponse_PDU, msg);
+return res;
+}
+
+bool SMUX::GetNextRequestHandler(const PDUs_t * pdus)
+{
+#ifdef SMUX_DEBUG
+printfd(__FILE__, "SMUX::GetNextRequestHandler()\n");
+asn_fprint(stderr, &asn_DEF_PDUs, pdus);
+#endif
+const GetRequest_PDU_t * getRequest = &pdus->choice.get_request;
+GetResponse_PDU_t * msg = static_cast<GetResponse_PDU_t *>(calloc(1, sizeof(GetResponse_PDU_t)));
+assert(msg && "Enought mempry to allocate GetResponse_PDU_t");
+VarBindList_t * varBindList = &msg->variable_bindings;
+
+long id = 0;
+asn_INTEGER2long(&getRequest->request_id, &id);
+asn_long2INTEGER(&msg->request_id, id);
+asn_long2INTEGER(&msg->error_status, 0);
+asn_long2INTEGER(&msg->error_index, 0);
+
+const VarBindList_t * vbl = &getRequest->variable_bindings;
+for (int i = 0; i < vbl->list.count; ++i)
+ {
+ VarBind_t * vb = getRequest->variable_bindings.list.array[i];
+ Sensors::iterator it;
+ it = sensors.upper_bound(OID(&vb->name));
+ if (it == sensors.end())
+ {
+#ifdef SMUX_DEBUG
+ printfd(__FILE__, "SMUX::GetNextRequestHandler() - '%s' not found\n", OID(&vb->name).ToString().c_str());
+#endif
+ return SendGetResponseErrorPDU(sock, getRequest,
+ PDU__error_status_noSuchName, i);
+ }
+
+ VarBind_t * newVb = static_cast<VarBind_t *>(calloc(1, sizeof(VarBind_t)));
+ assert(newVb && "Enought mempry to allocate VarBind_t");
+
+ it->first.ToOID(&newVb->name);
+ it->second->GetValue(&newVb->value);
+
+ ASN_SEQUENCE_ADD(varBindList, newVb);
+ }
+
+bool res = SendGetResponsePDU(sock, msg);
+#ifdef SMUX_DEBUG
+asn_fprint(stderr, &asn_DEF_PDU, msg);
+#endif
+ASN_STRUCT_FREE(asn_DEF_GetResponse_PDU, msg);
+return res;
+}
+
+bool SMUX::SetRequestHandler(const PDUs_t * pdus)
+{
+#ifdef SMUX_DEBUG
+printfd(__FILE__, "SMUX::SetRequestHandler()\n");
+asn_fprint(stderr, &asn_DEF_PDUs, pdus);
+#endif
+return SendGetResponseErrorPDU(sock, &pdus->choice.set_request,
+ PDU__error_status_readOnly, 0);
+}
--- /dev/null
+#ifndef __PEN_H__
+#define __PEN_H__
+
+#define PEN_PREFIX ".1.3.6.1.4.1.38313"
+
+#endif
--- /dev/null
+#include <cassert>
+
+#include "stg/INTEGER.h"
+
+#include "stg/user.h"
+
+#include "sensors.h"
+
+bool UsersSensor::GetValue(ObjectSyntax_t * objectSyntax) const
+{
+int handle = users.OpenSearch();
+assert(handle && "USERS::OpenSearch is always correct");
+
+STG::User* user;
+size_t count = 0;
+while (!users.SearchNext(handle, &user))
+ {
+ if (UserPredicate(user))
+ ++count;
+ }
+
+users.CloseSearch(handle);
+
+ValueToOS(count, objectSyntax);
+return true;
+}
+
+#ifdef DEBUG
+std::string UsersSensor::ToString() const
+{
+int handle = users.OpenSearch();
+assert(handle && "USERS::OpenSearch is always correct");
+
+STG::User* user;
+size_t count = 0;
+while (!users.SearchNext(handle, &user))
+ {
+ if (UserPredicate(user))
+ ++count;
+ }
+
+users.CloseSearch(handle);
+
+return std::to_string(count);
+}
+#endif
+
+bool ActiveUsersSensor::UserPredicate(STG::User* userPtr) const
+{
+if (!userPtr->GetConnected())
+ return false;
+for (size_t i = 0; i < DIR_NUM; ++i)
+ {
+ if (userPtr->GetSessionUpload()[i] > 0 ||
+ userPtr->GetSessionDownload()[i] > 0)
+ return true;
+ }
+return false;
+}
--- /dev/null
+#ifndef __SENSORS_H__
+#define __SENSORS_H__
+
+#include <map>
+
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/tariffs.h"
+#include "stg/admins.h"
+#include "stg/services.h"
+#include "stg/corporations.h"
+#include "stg/traffcounter.h"
+#include "stg/user_property.h"
+
+#include "stg/ObjectSyntax.h"
+
+#include "value2os.h"
+#include "types.h"
+
+class Sensor {
+ public:
+ virtual ~Sensor() = default;
+ virtual bool GetValue(ObjectSyntax_t * objectSyntax) const = 0;
+#ifdef DEBUG
+ virtual std::string ToString() const = 0;
+#endif
+};
+
+typedef std::map<OID, Sensor *> Sensors;
+
+class TotalUsersSensor : public Sensor {
+ public:
+ explicit TotalUsersSensor(const STG::Users & u) : users(u) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override
+ {
+ ValueToOS(users.Count(), objectSyntax);
+ return true;
+ }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(users.Count(), res); return res; }
+#endif
+
+ private:
+ const STG::Users & users;
+};
+
+class UsersSensor : public Sensor {
+ public:
+ explicit UsersSensor(STG::Users & u) : users(u) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override;
+#ifdef DEBUG
+ std::string ToString() const override;
+#endif
+
+ private:
+ STG::Users & users;
+
+ virtual bool UserPredicate(STG::User* userPtr) const = 0;
+};
+
+class ConnectedUsersSensor : public UsersSensor {
+ public:
+ explicit ConnectedUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetConnected(); }
+};
+
+class AuthorizedUsersSensor : public UsersSensor {
+ public:
+ explicit AuthorizedUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetAuthorized(); }
+};
+
+class AlwaysOnlineUsersSensor : public UsersSensor {
+ public:
+ explicit AlwaysOnlineUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().alwaysOnline; }
+};
+
+class NoCashUsersSensor : public UsersSensor {
+ public:
+ explicit NoCashUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().cash < 0; }
+};
+
+class DisabledDetailStatsUsersSensor : public UsersSensor {
+ public:
+ explicit DisabledDetailStatsUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().disabledDetailStat; }
+};
+
+class DisabledUsersSensor : public UsersSensor {
+ public:
+ explicit DisabledUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().disabled; }
+};
+
+class PassiveUsersSensor : public UsersSensor {
+ public:
+ explicit PassiveUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().passive; }
+};
+
+class CreditUsersSensor : public UsersSensor {
+ public:
+ explicit CreditUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().credit > 0; }
+};
+
+class FreeMbUsersSensor : public UsersSensor {
+ public:
+ explicit FreeMbUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return userPtr->GetProperties().freeMb > 0; }
+};
+
+class TariffChangeUsersSensor : public UsersSensor {
+ public:
+ explicit TariffChangeUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override
+ { return !userPtr->GetProperties().nextTariff.ConstData().empty(); }
+};
+
+class ActiveUsersSensor : public UsersSensor {
+ public:
+ explicit ActiveUsersSensor(STG::Users & u) : UsersSensor(u) {}
+
+ private:
+ bool UserPredicate(STG::User* userPtr) const override;
+};
+
+class TotalTariffsSensor : public Sensor {
+ public:
+ explicit TotalTariffsSensor(const STG::Tariffs & t) : tariffs(t) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override
+ {
+ ValueToOS(tariffs.Count(), objectSyntax);
+ return true;
+ }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(tariffs.Count(), res); return res; }
+#endif
+
+ private:
+ const STG::Tariffs & tariffs;
+};
+
+class TotalAdminsSensor : public Sensor {
+ public:
+ explicit TotalAdminsSensor(const STG::Admins & a) : admins(a) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override
+ {
+ ValueToOS(admins.count(), objectSyntax);
+ return true;
+ }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(admins.Count(), res); return res; }
+#endif
+
+ private:
+ const STG::Admins & admins;
+};
+
+class TotalServicesSensor : public Sensor {
+ public:
+ explicit TotalServicesSensor(const STG::Services & s) : services(s) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override
+ {
+ ValueToOS(services.Count(), objectSyntax);
+ return true;
+ }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(services.Count(), res); return res; }
+#endif
+
+ private:
+ const STG::Services & services;
+};
+
+class TotalCorporationsSensor : public Sensor {
+ public:
+ explicit TotalCorporationsSensor(const STG::Corporations & c) : corporations(c) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override
+ {
+ ValueToOS(corporations.Count(), objectSyntax);
+ return true;
+ }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(corporations.Count(), res); return res; }
+#endif
+
+ private:
+ const STG::Corporations & corporations;
+};
+
+class TotalRulesSensor : public Sensor {
+ public:
+ explicit TotalRulesSensor(const STG::TraffCounter & t) : traffcounter(t) {}
+
+ bool GetValue(ObjectSyntax_t * objectSyntax) const override
+ {
+ ValueToOS(traffcounter.rulesCount(), objectSyntax);
+ return true;
+ }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(traffcounter.rulesCount(), res); return res; }
+#endif
+
+ private:
+ const STG::TraffCounter & traffcounter;
+};
+
+template <typename T>
+class ConstSensor : public Sensor {
+ public:
+ explicit ConstSensor(const T & v) : value(v) {}
+
+ bool GetValue(ObjectSyntax * objectSyntax) const override
+ { return ValueToOS(value, objectSyntax); }
+
+#ifdef DEBUG
+ std::string ToString() const override
+ { std::string res; std::to_string(value, res); return res; }
+#endif
+
+ private:
+ T value;
+};
+
+#ifdef DEBUG
+template <>
+inline
+std::string ConstSensor<std::string>::ToString() const
+{
+return value;
+}
+#endif
+
+#endif
--- /dev/null
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <cstring>
+#include <cerrno>
+#include <ctime>
+#include <csignal>
+#include <cassert>
+
+#include <vector>
+#include <algorithm>
+#include <iterator>
+#include <stdexcept>
+#include <utility>
+
+#include "stg/common.h"
+
+#include "smux.h"
+#include "utils.h"
+
+namespace
+{
+
+bool SPrefixLess(const Sensors::value_type & a,
+ const Sensors::value_type & b)
+{
+return a.first.PrefixLess(b.first);
+}
+
+}
+
+extern "C" STG::Plugin* GetPlugin()
+{
+ static SMUX plugin;
+ return &plugin;
+}
+
+SMUX_SETTINGS::SMUX_SETTINGS()
+ : errorStr(),
+ ip(0),
+ port(0),
+ password()
+{}
+
+int SMUX_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+STG::ParamValue pv;
+std::vector<STG::ParamValue>::const_iterator pvi;
+int p;
+
+pv.param = "Port";
+pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Port\' not found.";
+ printfd(__FILE__, "Parameter 'Port' not found\n");
+ return -1;
+ }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+ {
+ errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+ printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+ return -1;
+ }
+port = static_cast<uint16_t>(p);
+
+pv.param = "Password";
+pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Password\' not found.";
+ printfd(__FILE__, "Parameter 'Password' not found\n");
+ password = "";
+ }
+else
+ {
+ password = pvi->value[0];
+ }
+
+pv.param = "Server";
+pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'Server\' not found.";
+ printfd(__FILE__, "Parameter 'Server' not found\n");
+ return -1;
+ }
+ip = inet_strington(pvi->value[0]);
+
+return 0;
+}
+
+SMUX::SMUX()
+ : users(NULL),
+ tariffs(NULL),
+ admins(NULL),
+ services(NULL),
+ corporations(NULL),
+ traffcounter(NULL),
+ running(false),
+ stopped(true),
+ needReconnect(false),
+ lastReconnectTry(0),
+ reconnectTimeout(1),
+ sock(-1),
+ addUserNotifier(*this),
+ delUserNotifier(*this),
+ addDelTariffNotifier(*this),
+ logger(STG::PluginLogger::get("smux"))
+{
+pthread_mutex_init(&mutex, NULL);
+
+smuxHandlers[SMUX_PDUs_PR_close] = &SMUX::CloseHandler;
+smuxHandlers[SMUX_PDUs_PR_registerResponse] = &SMUX::RegisterResponseHandler;
+smuxHandlers[SMUX_PDUs_PR_pdus] = &SMUX::PDUsRequestHandler;
+smuxHandlers[SMUX_PDUs_PR_commitOrRollback] = &SMUX::CommitOrRollbackHandler;
+
+pdusHandlers[PDUs_PR_get_request] = &SMUX::GetRequestHandler;
+pdusHandlers[PDUs_PR_get_next_request] = &SMUX::GetNextRequestHandler;
+pdusHandlers[PDUs_PR_set_request] = &SMUX::SetRequestHandler;
+}
+
+SMUX::~SMUX()
+{
+ {
+ Sensors::iterator it;
+ for (it = sensors.begin(); it != sensors.end(); ++it)
+ delete it->second;
+ }
+ {
+ Tables::iterator it;
+ for (it = tables.begin(); it != tables.end(); ++it)
+ delete it->second;
+ }
+printfd(__FILE__, "SMUX::~SMUX()\n");
+pthread_mutex_destroy(&mutex);
+}
+
+int SMUX::ParseSettings()
+{
+return smuxSettings.ParseSettings(settings);
+}
+
+int SMUX::Start()
+{
+assert(users != NULL && "users must not be NULL");
+assert(tariffs != NULL && "tariffs must not be NULL");
+assert(admins != NULL && "admins must not be NULL");
+assert(services != NULL && "services must not be NULL");
+assert(corporations != NULL && "corporations must not be NULL");
+assert(traffcounter != NULL && "traffcounter must not be NULL");
+
+if (PrepareNet())
+ needReconnect = true;
+
+// Users
+sensors[OID(".1.3.6.1.4.1.38313.1.1.1")] = new TotalUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.2")] = new ConnectedUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.3")] = new AuthorizedUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.4")] = new AlwaysOnlineUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.5")] = new NoCashUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.6")] = new DisabledDetailStatsUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.7")] = new DisabledUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.8")] = new PassiveUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.9")] = new CreditUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.10")] = new FreeMbUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.11")] = new TariffChangeUsersSensor(*users);
+sensors[OID(".1.3.6.1.4.1.38313.1.1.12")] = new ActiveUsersSensor(*users);
+// Tariffs
+sensors[OID(".1.3.6.1.4.1.38313.1.2.1")] = new TotalTariffsSensor(*tariffs);
+// Admins
+sensors[OID(".1.3.6.1.4.1.38313.1.3.1")] = new TotalAdminsSensor(*admins);
+// Services
+sensors[OID(".1.3.6.1.4.1.38313.1.4.1")] = new TotalServicesSensor(*services);
+// Corporations
+sensors[OID(".1.3.6.1.4.1.38313.1.5.1")] = new TotalCorporationsSensor(*corporations);
+// Traffcounter
+sensors[OID(".1.3.6.1.4.1.38313.1.6.1")] = new TotalRulesSensor(*traffcounter);
+
+// Table data
+tables[".1.3.6.1.4.1.38313.1.2.2"] = new TariffUsersTable(".1.3.6.1.4.1.38313.1.2.2", *tariffs, *users);
+
+UpdateTables();
+SetNotifiers();
+
+#ifdef SMUX_DEBUG
+Sensors::const_iterator it(sensors.begin());
+while (it != sensors.end())
+ {
+ printfd(__FILE__, "%s = %s\n",
+ it->first.ToString().c_str(),
+ it->second->ToString().c_str());
+ ++it;
+ }
+#endif
+
+if (!running)
+ {
+ if (pthread_create(&thread, NULL, Runner, this))
+ {
+ errorStr = "Cannot create thread.";
+ logger("Cannot create thread.");
+ printfd(__FILE__, "Cannot create thread\n");
+ return -1;
+ }
+ }
+
+return 0;
+}
+
+int SMUX::Stop()
+{
+printfd(__FILE__, "SMUX::Stop() - Before\n");
+running = false;
+
+if (!stopped)
+ {
+ //5 seconds to thread stops itself
+ for (int i = 0; i < 25 && !stopped; i++)
+ {
+ struct timespec ts = {0, 200000000};
+ nanosleep(&ts, NULL);
+ }
+ }
+
+if (stopped)
+ pthread_join(thread, NULL);
+
+ResetNotifiers();
+
+ {
+ Tables::iterator it;
+ for (it = tables.begin(); it != tables.end(); ++it)
+ delete it->second;
+ }
+ {
+ Sensors::iterator it;
+ for (it = sensors.begin(); it != sensors.end(); ++it)
+ delete it->second;
+ }
+
+tables.erase(tables.begin(), tables.end());
+sensors.erase(sensors.begin(), sensors.end());
+
+close(sock);
+
+if (!stopped)
+ {
+ running = true;
+ return -1;
+ }
+
+printfd(__FILE__, "SMUX::Stop() - After\n");
+return 0;
+}
+
+int SMUX::Reload(const STG::ModuleSettings & /*ms*/)
+{
+if (Stop())
+ return -1;
+if (Start())
+ return -1;
+if (!needReconnect)
+ {
+ printfd(__FILE__, "SMUX reconnected succesfully.\n");
+ logger("Reconnected successfully.");
+ }
+return 0;
+}
+
+void * SMUX::Runner(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+SMUX * smux = static_cast<SMUX *>(d);
+
+smux->Run();
+
+return NULL;
+}
+
+void SMUX::Run()
+{
+stopped = true;
+if (!SendOpenPDU(sock))
+ needReconnect = true;
+if (!SendRReqPDU(sock))
+ needReconnect = true;
+running = true;
+stopped = false;
+
+while(running)
+ {
+ if (WaitPackets(sock) && !needReconnect)
+ {
+ SMUX_PDUs_t * pdus = RecvSMUXPDUs(sock);
+ if (pdus)
+ {
+ DispatchPDUs(pdus);
+ ASN_STRUCT_FREE(asn_DEF_SMUX_PDUs, pdus);
+ }
+ else if (running)
+ Reconnect();
+ }
+ else if (running && needReconnect)
+ Reconnect();
+ if (!running)
+ break;
+ }
+SendClosePDU(sock);
+stopped = true;
+}
+
+bool SMUX::PrepareNet()
+{
+sock = socket(AF_INET, SOCK_STREAM, 0);
+
+if (sock < 0)
+ {
+ errorStr = "Cannot create socket.";
+ logger("Cannot create a socket: %s", strerror(errno));
+ printfd(__FILE__, "Cannot create socket\n");
+ return true;
+ }
+
+struct sockaddr_in addr;
+
+addr.sin_family = AF_INET;
+addr.sin_port = htons(smuxSettings.GetPort());
+addr.sin_addr.s_addr = smuxSettings.GetIP();
+
+if (connect(sock, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)))
+ {
+ errorStr = "Cannot connect.";
+ logger("Cannot connect the socket: %s", strerror(errno));
+ printfd(__FILE__, "Cannot connect. Message: '%s'\n", strerror(errno));
+ return true;
+ }
+
+return false;
+}
+
+bool SMUX::Reconnect()
+{
+if (needReconnect && difftime(time(NULL), lastReconnectTry) < reconnectTimeout)
+ return true;
+
+time(&lastReconnectTry);
+SendClosePDU(sock);
+close(sock);
+if (!PrepareNet())
+ if (SendOpenPDU(sock))
+ if (SendRReqPDU(sock))
+ {
+ reconnectTimeout = 1;
+ needReconnect = false;
+ logger("Connected successfully");
+ printfd(__FILE__, "Connected successfully\n");
+ return false;
+ }
+
+if (needReconnect)
+ if (reconnectTimeout < 60)
+ reconnectTimeout *= 2;
+
+needReconnect = true;
+return true;
+}
+
+bool SMUX::DispatchPDUs(const SMUX_PDUs_t * pdus)
+{
+SMUXHandlers::iterator it(smuxHandlers.find(pdus->present));
+if (it != smuxHandlers.end())
+ {
+ return (this->*(it->second))(pdus);
+ }
+#ifdef SMUX_DEBUG
+else
+ {
+ switch (pdus->present)
+ {
+ case SMUX_PDUs_PR_NOTHING:
+ printfd(__FILE__, "PDUs: nothing\n");
+ break;
+ case SMUX_PDUs_PR_open:
+ printfd(__FILE__, "PDUs: open\n");
+ break;
+ case SMUX_PDUs_PR_registerRequest:
+ printfd(__FILE__, "PDUs: registerRequest\n");
+ break;
+ default:
+ printfd(__FILE__, "PDUs: undefined\n");
+ }
+ asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
+ }
+#endif
+return false;
+}
+
+bool SMUX::UpdateTables()
+{
+Sensors newSensors;
+bool done = true;
+Tables::iterator it(tables.begin());
+while (it != tables.end())
+ {
+ try
+ {
+ it->second->UpdateSensors(newSensors);
+ }
+ catch (const std::runtime_error & ex)
+ {
+ printfd(__FILE__,
+ "SMUX::UpdateTables - failed to update table '%s': '%s'\n",
+ it->first.c_str(), ex.what());
+ done = false;
+ break;
+ }
+ ++it;
+ }
+if (!done)
+ {
+ Sensors::iterator it(newSensors.begin());
+ while (it != newSensors.end())
+ {
+ delete it->second;
+ ++it;
+ }
+ return false;
+ }
+
+it = tables.begin();
+while (it != tables.end())
+ {
+ std::pair<Sensors::iterator, Sensors::iterator> res;
+ res = std::equal_range(sensors.begin(),
+ sensors.end(),
+ std::pair<OID, Sensor *>(OID(it->first), NULL),
+ SPrefixLess);
+ Sensors::iterator sit(res.first);
+ while (sit != res.second)
+ {
+ delete sit->second;
+ ++sit;
+ }
+ sensors.erase(res.first, res.second);
+ ++it;
+ }
+
+sensors.insert(newSensors.begin(), newSensors.end());
+
+return true;
+}
+
+void SMUX::SetNotifier(UserPtr userPtr)
+{
+notifiers.push_back(CHG_AFTER_NOTIFIER(*this, userPtr));
+userPtr->GetProperties().tariffName.AddAfterNotifier(¬ifiers.back());
+}
+
+void SMUX::UnsetNotifier(UserPtr userPtr)
+{
+std::list<CHG_AFTER_NOTIFIER>::iterator it = notifiers.begin();
+while (it != notifiers.end())
+ {
+ if (it->GetUserPtr() == userPtr)
+ {
+ userPtr->GetProperties().tariffName.DelAfterNotifier(&(*it));
+ notifiers.erase(it);
+ break;
+ }
+ ++it;
+ }
+}
+
+void SMUX::SetNotifiers()
+{
+int h = users->OpenSearch();
+assert(h && "USERS::OpenSearch is always correct");
+
+UserPtr u;
+while (!users->SearchNext(h, &u))
+ SetNotifier(u);
+
+users->CloseSearch(h);
+
+users->AddNotifierUserAdd(&addUserNotifier);
+users->AddNotifierUserDel(&delUserNotifier);
+
+tariffs->AddNotifierAdd(&addDelTariffNotifier);
+tariffs->AddNotifierDel(&addDelTariffNotifier);
+}
+
+void SMUX::ResetNotifiers()
+{
+tariffs->DelNotifierDel(&addDelTariffNotifier);
+tariffs->DelNotifierAdd(&addDelTariffNotifier);
+
+users->DelNotifierUserDel(&delUserNotifier);
+users->DelNotifierUserAdd(&addUserNotifier);
+
+std::list<CHG_AFTER_NOTIFIER>::iterator it(notifiers.begin());
+while (it != notifiers.end())
+ {
+ it->GetUserPtr()->GetProperties().tariffName.DelAfterNotifier(&(*it));
+ ++it;
+ }
+notifiers.clear();
+}
--- /dev/null
+#ifndef __SMUX_H__
+#define __SMUX_H__
+
+#include <pthread.h>
+
+#include <string>
+#include <map>
+#include <list>
+#include <cstdint>
+
+#include "stg/SMUX-PDUs.h"
+#include "stg/ObjectSyntax.h"
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/notifer.h"
+#include "stg/noncopyable.h"
+#include "stg/logger.h"
+
+#include "sensors.h"
+#include "tables.h"
+#include "types.h"
+
+namespace STG
+{
+struct User;
+struct Settings;
+struct Users;
+struct Tariffs;
+struct Services;
+struct Corporations;
+struct TraffCounter;
+}
+
+class SMUX;
+
+typedef bool (SMUX::*SMUXPacketHandler)(const SMUX_PDUs_t * pdus);
+typedef bool (SMUX::*PDUsHandler)(const PDUs_t * pdus);
+typedef std::map<SMUX_PDUs_PR, SMUXPacketHandler> SMUXHandlers;
+typedef std::map<PDUs_PR, PDUsHandler> PDUsHandlers;
+
+using UserPtr = STG::User*;
+//-----------------------------------------------------------------------------
+class SMUX_SETTINGS {
+public:
+ SMUX_SETTINGS();
+ virtual ~SMUX_SETTINGS() {}
+ const std::string & GetStrError() const { return errorStr; }
+ int ParseSettings(const STG::ModuleSettings & s);
+
+ uint32_t GetIP() const { return ip; }
+ uint16_t GetPort() const { return port; }
+ const std::string GetPassword() const { return password; }
+
+private:
+ mutable std::string errorStr;
+
+ uint32_t ip;
+ uint16_t port;
+ std::string password;
+};
+//-----------------------------------------------------------------------------
+class CHG_AFTER_NOTIFIER : public STG::PropertyNotifierBase<std::string> {
+public:
+ CHG_AFTER_NOTIFIER(SMUX & s, const UserPtr & u)
+ : STG::PropertyNotifierBase<std::string>(),
+ smux(s), userPtr(u) {}
+ CHG_AFTER_NOTIFIER(const CHG_AFTER_NOTIFIER & rvalue)
+ : STG::PropertyNotifierBase<std::string>(),
+ smux(rvalue.smux), userPtr(rvalue.userPtr) {}
+ void Notify(const std::string &, const std::string &);
+
+ UserPtr GetUserPtr() const { return userPtr; }
+
+private:
+ CHG_AFTER_NOTIFIER & operator=(const CHG_AFTER_NOTIFIER & rvalue);
+ SMUX & smux;
+ UserPtr userPtr;
+};
+//-----------------------------------------------------------------------------
+class ADD_DEL_TARIFF_NOTIFIER : public STG::NotifierBase<STG::TariffData> {
+public:
+ explicit ADD_DEL_TARIFF_NOTIFIER(SMUX & s)
+ : STG::NotifierBase<STG::TariffData>(), smux(s) {}
+ void Notify(const STG::TariffData &);
+
+private:
+ SMUX & smux;
+};
+//-----------------------------------------------------------------------------
+class ADD_USER_NOTIFIER : public STG::NotifierBase<UserPtr> {
+public:
+ explicit ADD_USER_NOTIFIER(SMUX & s) : STG::NotifierBase<STG::User*>(), smux(s) {}
+ void Notify(const UserPtr &);
+
+private:
+ SMUX & smux;
+};
+//-----------------------------------------------------------------------------
+class DEL_USER_NOTIFIER : public STG::NotifierBase<UserPtr> {
+public:
+ explicit DEL_USER_NOTIFIER(SMUX & s) : STG::NotifierBase<UserPtr>(), smux(s) {}
+ void Notify(const UserPtr &);
+
+private:
+ SMUX & smux;
+};
+//-----------------------------------------------------------------------------
+class SMUX : public STG::Plugin {
+public:
+ SMUX();
+ virtual ~SMUX();
+
+ void SetUsers(STG::Users * u) { users = u; }
+ void SetTariffs(STG::Tariffs * t) { tariffs = t; }
+ void SetAdmins(STG::Admins * a) { admins = a; }
+ void SetServices(STG::Services * s) { services = s; }
+ void SetTraffcounter(STG::TraffCounter * tc) { traffcounter = tc; }
+ void SetCorporations(STG::Corporations * c) { corporations = c; }
+ void SetSettings(const STG::ModuleSettings & s) { settings = s; }
+ int ParseSettings();
+
+ int Start();
+ int Stop();
+ int Reload(const STG::ModuleSettings & ms);
+ bool IsRunning() { return running && !stopped; }
+
+ const std::string & GetStrError() const { return errorStr; }
+ std::string GetVersion() const { return "Stg SMUX Plugin 1.1"; }
+ uint16_t GetStartPosition() const { return 10; }
+ uint16_t GetStopPosition() const { return 10; }
+
+ bool UpdateTables();
+
+ void SetNotifier(UserPtr userPtr);
+ void UnsetNotifier(UserPtr userPtr);
+
+private:
+ SMUX(const SMUX & rvalue);
+ SMUX & operator=(const SMUX & rvalue);
+
+ static void * Runner(void * d);
+ void Run();
+ bool PrepareNet();
+ bool Reconnect();
+
+ bool DispatchPDUs(const SMUX_PDUs_t * pdus);
+
+ bool CloseHandler(const SMUX_PDUs_t * pdus);
+ bool RegisterResponseHandler(const SMUX_PDUs_t * pdus);
+ bool PDUsRequestHandler(const SMUX_PDUs_t * pdus);
+ bool CommitOrRollbackHandler(const SMUX_PDUs_t * pdus);
+
+ bool GetRequestHandler(const PDUs_t * pdus);
+ bool GetNextRequestHandler(const PDUs_t * pdus);
+ bool SetRequestHandler(const PDUs_t * pdus);
+
+ void SetNotifiers();
+ void ResetNotifiers();
+
+ STG::Users * users;
+ STG::Tariffs * tariffs;
+ STG::Admins * admins;
+ STG::Services * services;
+ STG::Corporations * corporations;
+ STG::TraffCounter * traffcounter;
+
+ mutable std::string errorStr;
+ SMUX_SETTINGS smuxSettings;
+ STG::ModuleSettings settings;
+
+ pthread_t thread;
+ pthread_mutex_t mutex;
+ bool running;
+ bool stopped;
+ bool needReconnect;
+
+ time_t lastReconnectTry;
+ unsigned reconnectTimeout;
+
+ int sock;
+
+ SMUXHandlers smuxHandlers;
+ PDUsHandlers pdusHandlers;
+ Sensors sensors;
+ Tables tables;
+
+ std::list<CHG_AFTER_NOTIFIER> notifiers;
+ ADD_USER_NOTIFIER addUserNotifier;
+ DEL_USER_NOTIFIER delUserNotifier;
+ ADD_DEL_TARIFF_NOTIFIER addDelTariffNotifier;
+
+ STG::PluginLogger logger;
+};
+//-----------------------------------------------------------------------------
+
+inline
+void CHG_AFTER_NOTIFIER::Notify(const std::string &, const std::string &)
+{
+smux.UpdateTables();
+}
+
+inline
+void ADD_DEL_TARIFF_NOTIFIER::Notify(const STG::TariffData &)
+{
+smux.UpdateTables();
+}
+
+inline
+void ADD_USER_NOTIFIER::Notify(const UserPtr & userPtr)
+{
+smux.SetNotifier(userPtr);
+smux.UpdateTables();
+}
+
+inline
+void DEL_USER_NOTIFIER::Notify(const UserPtr & userPtr)
+{
+smux.UnsetNotifier(userPtr);
+smux.UpdateTables();
+}
+
+#endif
--- /dev/null
+#include <cassert>
+#include <utility>
+#include <iterator>
+#include <algorithm>
+
+#include "stg/user_property.h"
+#include "stg/tariffs.h"
+#include "stg/tariff_conf.h"
+#include "stg/users.h"
+
+#include "tables.h"
+
+std::pair<std::string, size_t> TD2Info(const STG::TariffData & td);
+
+void TariffUsersTable::UpdateSensors(Sensors & sensors) const
+{
+std::map<std::string, size_t> data;
+
+std::vector<STG::TariffData> tdl;
+tariffs.GetTariffsData(&tdl);
+std::transform(tdl.begin(),
+ tdl.end(),
+ std::inserter(data, data.begin()),
+ TD2Info);
+
+int handle = users.OpenSearch();
+assert(handle && "USERS::OpenSearch is always correct");
+
+STG::User* user;
+while (!users.SearchNext(handle, &user))
+ {
+ if (user->GetDeleted())
+ continue;
+ std::string tariffName(user->GetProperties().tariffName.ConstData());
+ std::map<std::string, size_t>::iterator it(data.lower_bound(tariffName));
+ if (it == data.end() ||
+ it->first != tariffName)
+ {
+ data.insert(it, std::make_pair(tariffName, 1));
+ }
+ else
+ {
+ ++it->second;
+ }
+ }
+
+users.CloseSearch(handle);
+
+size_t idx = 1;
+OID prefixOid(prefix);
+
+std::map<std::string, size_t>::const_iterator it(data.begin());
+while (it != data.end())
+ {
+ sensors[prefixOid.copyWithSuffix(2, static_cast<unsigned int>(idx))] = new ConstSensor<std::string>(it->first);
+ sensors[prefixOid.copyWithSuffix(3, static_cast<unsigned int>(idx))] = new ConstSensor<unsigned long>(it->second);
+ ++idx;
+ ++it;
+ }
+}
+
+std::pair<std::string, size_t> TD2Info(const STG::TariffData & td)
+{
+return std::make_pair(td.tariffConf.name, 0);
+}
--- /dev/null
+#ifndef __TABLES_H__
+#define __TABLES_H__
+
+#include <string>
+#include <map>
+
+#include "sensors.h"
+
+namespace STG
+{
+struct Tariffs;
+struct Users;
+}
+
+class TableSensor {
+ public:
+ explicit TableSensor(const std::string & p) : prefix(p) {}
+ virtual ~TableSensor() {}
+
+ const std::string & GetPrefix() const { return prefix; }
+ virtual void UpdateSensors(Sensors & sensors) const = 0;
+
+ protected:
+ std::string prefix;
+};
+
+class TariffUsersTable : public TableSensor {
+ public:
+ TariffUsersTable(const std::string & p,
+ STG::Tariffs & t,
+ STG::Users & u)
+ : TableSensor(p),
+ tariffs(t),
+ users(u)
+ {}
+ virtual ~TariffUsersTable() {}
+
+ void UpdateSensors(Sensors & sensors) const;
+
+ private:
+ STG::Tariffs & tariffs;
+ STG::Users & users;
+};
+
+typedef std::map<std::string, TableSensor *> Tables;
+
+#endif
--- /dev/null
+#include <stdexcept>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+
+#include "types.h"
+
+namespace
+{
+
+bool ParseArcs(const char * str, ptrdiff_t length, unsigned * a, size_t * pos);
+bool StringToArcs(const char * str, size_t length, std::vector<unsigned> & arcs);
+bool AppendToArcs(const char * str, size_t length, std::vector<unsigned> & arcs);
+
+bool ParseArcs(const char * str, ptrdiff_t length, unsigned * a, size_t * pos)
+{
+if (length == 0)
+ return false;
+const char * left = str;
+if (*left == '.')
+ ++left;
+size_t arcPos = 0;
+while ((left - str) < length)
+ {
+ char * pos = NULL;
+ unsigned arc = static_cast<unsigned int>(strtoul(left, &pos, 10));
+ if (pos == left)
+ return false;
+ a[arcPos++] = arc;
+ if (arcPos >= 1024)
+ return false;
+ left = pos + 1;
+ }
+*pos = arcPos;
+return true;
+}
+
+bool StringToArcs(const char * str, size_t length, std::vector<unsigned> & arcs)
+{
+unsigned a[1024];
+size_t pos = 0;
+
+if (!ParseArcs(str, length, a, &pos))
+ return false;
+
+arcs.assign(a, a + pos);
+return true;
+}
+
+bool AppendToArcs(const char * str, size_t length, std::vector<unsigned> & arcs)
+{
+unsigned a[1024];
+size_t pos = 0;
+
+if (!ParseArcs(str, length, a, &pos))
+ return false;
+
+std::copy(&a[0], &a[pos], std::back_inserter(arcs));
+return true;
+}
+
+}
+
+OID::OID(const std::string & str)
+ : arcs()
+{
+if (!StringToArcs(str.c_str(), str.length(), arcs))
+ throw std::runtime_error("Invalid oid");
+}
+
+OID::OID(const char * str, size_t length)
+ : arcs()
+{
+if (!StringToArcs(str, length, arcs))
+ throw std::runtime_error("Invalid oid");
+}
+
+OID::OID(const std::vector<unsigned> & a)
+ : arcs(a)
+{
+}
+
+OID::OID(const unsigned * a, size_t length)
+ : arcs()
+{
+std::vector<unsigned> newArcs(a, a + length);
+arcs.swap(newArcs);
+}
+
+OID::OID(OBJECT_IDENTIFIER_t * oid)
+ : arcs()
+{
+unsigned a[1024];
+int count = OBJECT_IDENTIFIER_get_arcs(oid, a, sizeof(a[0]), 1024);
+
+if (count > 1024)
+ throw std::runtime_error("OID is too long");
+
+std::vector<unsigned> newArcs(a, a + count);
+arcs.swap(newArcs);
+}
+
+OID::OID(const OID & rvalue)
+ : arcs(rvalue.arcs)
+{
+}
+
+OID::~OID()
+{
+}
+
+bool OID::addSuffix(const char * suffix, size_t length)
+{
+if (!AppendToArcs(suffix, length, arcs))
+ return false;
+return true;
+}
+
+bool OID::addSuffix(const std::string & suffix)
+{
+if (!AppendToArcs(suffix.c_str(), suffix.length(), arcs))
+ return false;
+return true;
+}
+
+bool OID::addSuffix(const unsigned * suffix, size_t length)
+{
+std::copy(suffix, suffix + length, std::back_inserter(arcs));
+return true;
+}
+
+bool OID::addSuffix(const std::vector<unsigned> & suffix)
+{
+std::copy(suffix.begin(), suffix.end(), std::back_inserter(arcs));
+return true;
+}
+
+bool OID::addSuffix(unsigned a, unsigned b)
+{
+arcs.push_back(a);
+arcs.push_back(b);
+return true;
+}
+
+OID OID::copyWithSuffix(const char * suffix, size_t length) const
+{
+OID oid(*this);
+if (!oid.addSuffix(suffix, length))
+ throw std::runtime_error("Invalid suffix");
+return oid;
+}
+
+OID OID::copyWithSuffix(const std::string & suffix) const
+{
+OID oid(*this);
+if (!oid.addSuffix(suffix))
+ throw std::runtime_error("Invalid suffix");
+return oid;
+}
+
+OID OID::copyWithSuffix(const unsigned * suffix, size_t length) const
+{
+OID oid(*this);
+if (!oid.addSuffix(suffix, length))
+ throw std::runtime_error("Invalid suffix");
+return oid;
+}
+
+OID OID::copyWithSuffix(const std::vector<unsigned> & suffix) const
+{
+OID oid(*this);
+if (!oid.addSuffix(suffix))
+ throw std::runtime_error("Invalid suffix");
+return oid;
+}
+
+OID OID::copyWithSuffix(unsigned a, unsigned b) const
+{
+OID oid(*this);
+oid.addSuffix(a, b);
+return oid;
+}
+
+std::string OID::ToString() const
+{
+std::stringstream stream;
+for (size_t i = 0; i < arcs.size(); ++i)
+ stream << "." << arcs[i];
+return stream.str();
+}
+
+void OID::ToOID(OBJECT_IDENTIFIER_t * oid) const
+{
+OBJECT_IDENTIFIER_set_arcs(oid, &arcs.front(), sizeof(unsigned), static_cast<unsigned int>(arcs.size()));
+}
+
+OID & OID::operator=(const OID & rvalue)
+{
+arcs = rvalue.arcs;
+return *this;
+}
+
+bool OID::operator==(const OID & rvalue) const
+{
+if (arcs.size() != rvalue.arcs.size())
+ return false;
+for (size_t i = 0; i < arcs.size(); ++i)
+ if (arcs[i] != rvalue.arcs[i])
+ return false;
+return true;
+}
+
+bool OID::operator<(const OID & rvalue) const
+{
+size_t i = 0;
+size_t min = std::min(arcs.size(), rvalue.arcs.size());
+while (i < min &&
+ arcs[i] == rvalue.arcs[i])
+ ++i;
+if (i == min)
+ {
+ if (rvalue.arcs.size() > arcs.size())
+ return true;
+ return false;
+ }
+
+if (arcs[i] < rvalue.arcs[i])
+ return true;
+
+return false;
+}
+
+bool OID::PrefixLess(const OID & rvalue) const
+{
+size_t i = 0;
+size_t min = std::min(arcs.size(), rvalue.arcs.size());
+while (i < min &&
+ arcs[i] == rvalue.arcs[i])
+ ++i;
+if (i == min)
+ return false;
+if (arcs[i] < rvalue.arcs[i])
+ return true;
+return false;
+}
+
+std::ostream & operator<<(std::ostream & stream, const OID & oid)
+{
+for (size_t i = 0; i < oid.arcs.size(); ++i)
+ stream << "." << oid.arcs[i];
+return stream;
+}
--- /dev/null
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+#include "stg/OBJECT_IDENTIFIER.h"
+
+class OID {
+ public:
+ explicit OID(const std::string & str);
+ OID(const char * str, size_t length);
+ explicit OID(const std::vector<unsigned> & arcs);
+ OID(const unsigned * arcs, size_t length);
+ explicit OID(OBJECT_IDENTIFIER_t * oid);
+ OID(const OID & rvalue);
+ ~OID();
+
+ bool addSuffix(const char * suffix, size_t length);
+ bool addSuffix(const std::string & suffix);
+ bool addSuffix(const unsigned * suffix, size_t length);
+ bool addSuffix(const std::vector<unsigned> & suffix);
+ bool addSuffix(unsigned a, unsigned b);
+
+ OID copyWithSuffix(const char * suffix, size_t length) const;
+ OID copyWithSuffix(const std::string & suffix) const;
+ OID copyWithSuffix(const unsigned * suffix, size_t length) const;
+ OID copyWithSuffix(const std::vector<unsigned> & suffix) const;
+ OID copyWithSuffix(unsigned a, unsigned b) const;
+
+ std::string ToString() const;
+ const std::vector<unsigned> & ToVector() const { return arcs; }
+ void ToOID(OBJECT_IDENTIFIER_t * oid) const;
+
+ OID & operator=(const OID & rvalue);
+ bool operator==(const OID & rvalue) const;
+ bool operator!=(const OID & rvalue) const { return !operator==(rvalue); }
+ bool operator<(const OID & rvalue) const;
+ bool operator>(const OID & rvalue) const
+ { return !operator==(rvalue) && !operator<(rvalue); }
+
+ bool PrefixLess(const OID & rvalue) const;
+
+ friend std::ostream & operator<<(std::ostream & stream, const OID & oid);
+
+ private:
+ std::vector<unsigned> arcs;
+};
+
+inline
+bool PrefixLess(const OID & a, const OID & b)
+{
+return a.PrefixLess(b);
+}
+
+#endif
--- /dev/null
+#include <unistd.h> // write
+
+#include <cstring> // memset
+#include <cerrno>
+
+#include "stg/common.h"
+
+#include "stg/OpenPDU.h"
+#include "stg/ClosePDU.h"
+#include "stg/RReqPDU.h"
+#include "stg/ber_decoder.h"
+#include "stg/der_encoder.h"
+
+#include "pen.h"
+#include "utils.h"
+
+bool String2OI(const std::string & str, OBJECT_IDENTIFIER_t * oi)
+{
+size_t left = 0, pos = 0, arcPos = 0;
+int arcs[1024];
+pos = str.find_first_of('.', left);
+if (pos == 0)
+ {
+ left = 1;
+ pos = str.find_first_of('.', left);
+ }
+while (pos != std::string::npos)
+ {
+ int arc = 0;
+ if (str2x(str.substr(left, left - pos), arc))
+ {
+ return false;
+ }
+ arcs[arcPos++] = arc;
+ left = pos + 1;
+ pos = str.find_first_of('.', left);
+ }
+if (left < str.length())
+ {
+ int arc = 0;
+ if (str2x(str.substr(left, left - pos), arc))
+ {
+ return false;
+ }
+ arcs[arcPos++] = arc;
+ }
+OBJECT_IDENTIFIER_set_arcs(oi, arcs, sizeof(arcs[0]), static_cast<unsigned int>(arcPos));
+return true;
+}
+
+bool SendOpenPDU(int fd)
+{
+const char * description = "Stg SMUX Plugin";
+asn_enc_rval_t error;
+OpenPDU_t msg;
+
+memset(&msg, 0, sizeof(msg));
+
+msg.present = OpenPDU_PR_simple;
+asn_long2INTEGER(&msg.choice.simple.version, SimpleOpen__version_version_1);
+if (!String2OI(PEN_PREFIX, &msg.choice.simple.identity))
+ {
+ printfd(__FILE__,
+ "SendOpenPDU() - failed to convert string to OBJECT_IDENTIFIER\n");
+ return false;
+ }
+OCTET_STRING_fromString(&msg.choice.simple.description, description);
+OCTET_STRING_fromString(&msg.choice.simple.password, "");
+
+char buffer[1024];
+error = der_encode_to_buffer(&asn_DEF_OpenPDU, &msg, buffer, sizeof(buffer));
+
+ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_OpenPDU, &msg);
+
+if (error.encoded == -1)
+ {
+ printfd(__FILE__, "Could not encode OpenPDU (at %s)\n",
+ error.failed_type ? error.failed_type->name : "unknown");
+ return false;
+ }
+else
+ {
+ if (write(fd, buffer, error.encoded) < 0)
+ {
+ printfd(__FILE__, "Failed to send OpenPDU: %s\n", strerror(errno));
+ return false;
+ }
+ }
+return true;
+}
+
+bool SendClosePDU(int fd)
+{
+ClosePDU_t msg;
+
+memset(&msg, 0, sizeof(msg));
+
+asn_long2INTEGER(&msg, ClosePDU_goingDown);
+
+char buffer[1024];
+asn_enc_rval_t error;
+error = der_encode_to_buffer(&asn_DEF_ClosePDU, &msg, buffer, sizeof(buffer));
+
+ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_ClosePDU, &msg);
+
+if (error.encoded == -1)
+ {
+ printfd(__FILE__, "Could not encode ClosePDU (at %s)\n",
+ error.failed_type ? error.failed_type->name : "unknown");
+ return false;
+ }
+else
+ {
+ if (write(fd, buffer, error.encoded) < 0)
+ {
+ printfd(__FILE__, "Failed to send ClosePDU: %s\n", strerror(errno));
+ return false;
+ }
+ }
+return true;
+}
+
+bool SendRReqPDU(int fd)
+{
+int oid[] = {1, 3, 6, 1, 4, 1, 38313, 1};
+asn_enc_rval_t error;
+RReqPDU_t msg;
+
+memset(&msg, 0, sizeof(msg));
+
+msg.priority = 0;
+asn_long2INTEGER(&msg.operation, RReqPDU__operation_readOnly);
+OBJECT_IDENTIFIER_set_arcs(&msg.subtree,
+ oid,
+ sizeof(oid[0]),
+ 8);
+
+char buffer[1024];
+error = der_encode_to_buffer(&asn_DEF_RReqPDU, &msg, buffer, sizeof(buffer));
+
+ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RReqPDU, &msg);
+
+if (error.encoded == -1)
+ {
+ printfd(__FILE__, "Could not encode RReqPDU (at %s)\n",
+ error.failed_type ? error.failed_type->name : "unknown");
+ return false;
+ }
+else
+ {
+ if (write(fd, buffer, error.encoded) < 0)
+ {
+ printfd(__FILE__, "Failed to send RReqPDU: %s\n", strerror(errno));
+ return false;
+ }
+ }
+return true;
+}
+
+SMUX_PDUs_t * RecvSMUXPDUs(int fd)
+{
+char buffer[1024];
+SMUX_PDUs_t * pdus = NULL;
+
+memset(buffer, 0, sizeof(buffer));
+
+size_t length = read(fd, buffer, sizeof(buffer));
+if (length < 1)
+ return NULL;
+asn_dec_rval_t error;
+error = ber_decode(0, &asn_DEF_SMUX_PDUs, (void **)&pdus, buffer, length);
+
+if(error.code != RC_OK)
+ {
+ printfd(__FILE__, "Failed to decode PDUs at byte %ld\n",
+ (long)error.consumed);
+ return NULL;
+ }
+return pdus;
+}
+
+bool SendGetResponsePDU(int fd, GetResponse_PDU_t * getResponse)
+{
+asn_enc_rval_t error;
+
+char buffer[1024];
+error = der_encode_to_buffer(&asn_DEF_GetResponse_PDU, getResponse, buffer,
+ sizeof(buffer));
+
+if (error.encoded == -1)
+ {
+ printfd(__FILE__, "Could not encode GetResponsePDU (at %s)\n",
+ error.failed_type ? error.failed_type->name : "unknown");
+ return false;
+ }
+else
+ {
+ if (write(fd, buffer, error.encoded) < 0)
+ {
+ printfd(__FILE__, "Failed to send GetResponsePDU: %s\n", strerror(errno));
+ return false;
+ }
+ }
+return true;
+}
+
+bool SendGetResponseErrorPDU(int fd,
+ const PDU_t * getRequest,
+ int errorStatus,
+ int errorIndex)
+{
+asn_enc_rval_t error;
+GetResponse_PDU_t msg;
+
+memset(&msg, 0, sizeof(msg));
+
+long id = 0;
+asn_INTEGER2long(&getRequest->request_id, &id);
+asn_long2INTEGER(&msg.request_id, id);
+asn_long2INTEGER(&msg.error_status, errorStatus);
+asn_long2INTEGER(&msg.error_index, errorIndex);
+
+char buffer[1024];
+error = der_encode_to_buffer(&asn_DEF_GetResponse_PDU, &msg, buffer,
+ sizeof(buffer));
+
+ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetResponse_PDU, &msg);
+
+if (error.encoded == -1)
+ {
+ printfd(__FILE__, "Could not encode GetResponsePDU for error (at %s)\n",
+ error.failed_type ? error.failed_type->name : "unknown");
+ return false;
+ }
+else
+ {
+ if (write(fd, buffer, error.encoded) < 0)
+ {
+ printfd(__FILE__, "Failed to send GetResponseErrorPDU: %s\n", strerror(errno));
+ return false;
+ }
+ }
+return true;
+}
--- /dev/null
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <string>
+
+#include "stg/OBJECT_IDENTIFIER.h"
+#include "stg/SMUX-PDUs.h"
+#include "stg/GetResponse-PDU.h"
+
+bool String2OI(const std::string & str, OBJECT_IDENTIFIER_t * oi);
+bool SendOpenPDU(int fd);
+bool SendClosePDU(int fd);
+bool SendRReqPDU(int fd);
+SMUX_PDUs_t * RecvSMUXPDUs(int fd);
+bool SendGetResponsePDU(int fd, GetResponse_PDU_t * getResponse);
+bool SendGetResponseErrorPDU(int fd,
+ const PDU_t * getRequest,
+ int errorStatus,
+ int errorIndex);
+
+#endif
--- /dev/null
+#ifndef __VALUE_2_OS_H__
+#define __VALUE_2_OS_H__
+
+#include "stg/ObjectSyntax.h"
+
+template <typename T>
+bool ValueToOS(const T & value, ObjectSyntax * objectSyntax);
+
+template <>
+inline
+bool ValueToOS<int>(const int & value, ObjectSyntax * objectSyntax)
+{
+objectSyntax->present = ObjectSyntax_PR_simple;
+SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
+simpleSyntax->present = SimpleSyntax_PR_number;
+asn_long2INTEGER(&simpleSyntax->choice.number, value);
+return true;
+}
+
+template <>
+inline
+bool ValueToOS<unsigned int>(const unsigned int & value, ObjectSyntax * objectSyntax)
+{
+objectSyntax->present = ObjectSyntax_PR_simple;
+SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
+simpleSyntax->present = SimpleSyntax_PR_number;
+asn_long2INTEGER(&simpleSyntax->choice.number, value);
+return true;
+}
+
+template <>
+inline
+bool ValueToOS<long>(const long & value, ObjectSyntax * objectSyntax)
+{
+objectSyntax->present = ObjectSyntax_PR_simple;
+SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
+simpleSyntax->present = SimpleSyntax_PR_number;
+asn_long2INTEGER(&simpleSyntax->choice.number, value);
+return true;
+}
+
+template <>
+inline
+bool ValueToOS<unsigned long>(const unsigned long & value, ObjectSyntax * objectSyntax)
+{
+objectSyntax->present = ObjectSyntax_PR_simple;
+SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
+simpleSyntax->present = SimpleSyntax_PR_number;
+asn_long2INTEGER(&simpleSyntax->choice.number, value);
+return true;
+}
+
+template <>
+inline
+bool ValueToOS<std::string>(const std::string & value, ObjectSyntax * objectSyntax)
+{
+objectSyntax->present = ObjectSyntax_PR_simple;
+SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
+simpleSyntax->present = SimpleSyntax_PR_string;
+OCTET_STRING_fromBuf(&simpleSyntax->choice.string, value.c_str(), static_cast<int>(value.length()));
+return true;
+}
+
+#endif
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.67 $
+ $Date: 2010/10/07 19:53:11 $
+ $Author: faust $
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "file_store.h"
+
+#include "stg/common.h"
+#include "stg/user_ips.h"
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/const.h"
+#include "stg/blowfish.h"
+#include "stg/logger.h"
+#include "stg/locker.h"
+#include "stg/admin_conf.h"
+#include "stg/tariff.h"
+#include "stg/tariff_conf.h"
+#include "stg/service_conf.h"
+
+#include <sstream>
+#include <algorithm>
+#include <cstdio>
+#include <ctime>
+#include <cerrno>
+#include <cstring>
+
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define DELETED_USERS_DIR "deleted_users"
+
+#define adm_enc_passwd "cjeifY8m3"
+
+int GetFileList(std::vector<std::string> * fileList, const std::string & directory, mode_t mode, const std::string & ext);
+
+const int pt_mega = 1024 * 1024;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+namespace
+{
+
+bool CheckAndCreate(const std::string & dir, mode_t mode)
+{
+if (access(dir.c_str(), F_OK) == 0)
+ return true;
+if (mkdir(dir.c_str(), mode) == 0)
+ return true;
+return false;
+}
+
+}
+
+extern "C" STG::Store* GetStore()
+{
+ static FILES_STORE plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+FILES_STORE_SETTINGS::FILES_STORE_SETTINGS()
+ : settings(NULL),
+ statMode(0),
+ statUID(0),
+ statGID(0),
+ confMode(0),
+ confUID(0),
+ confGID(0),
+ userLogMode(0),
+ userLogUID(0),
+ userLogGID(0),
+ removeBak(true),
+ readBak(true)
+{
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseOwner(const std::vector<STG::ParamValue> & moduleParams, const std::string & owner, uid_t * uid)
+{
+STG::ParamValue pv;
+pv.param = owner;
+std::vector<STG::ParamValue>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'" + owner + "\' not found.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+if (User2UID(pvi->value[0].c_str(), uid) < 0)
+ {
+ errorStr = "Parameter \'" + owner + "\': Unknown user \'" + pvi->value[0] + "\'";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseGroup(const std::vector<STG::ParamValue> & moduleParams, const std::string & group, gid_t * gid)
+{
+STG::ParamValue pv;
+pv.param = group;
+std::vector<STG::ParamValue>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'" + group + "\' not found.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+if (Group2GID(pvi->value[0].c_str(), gid) < 0)
+ {
+ errorStr = "Parameter \'" + group + "\': Unknown group \'" + pvi->value[0] + "\'";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseYesNo(const std::string & value, bool * val)
+{
+if (0 == strcasecmp(value.c_str(), "yes"))
+ {
+ *val = true;
+ return 0;
+ }
+if (0 == strcasecmp(value.c_str(), "no"))
+ {
+ *val = false;
+ return 0;
+ }
+
+errorStr = "Incorrect value \'" + value + "\'.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseMode(const std::vector<STG::ParamValue> & moduleParams, const std::string & modeStr, mode_t * mode)
+{
+STG::ParamValue pv;
+pv.param = modeStr;
+std::vector<STG::ParamValue>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'" + modeStr + "\' not found.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+if (Str2Mode(pvi->value[0].c_str(), mode) < 0)
+ {
+ errorStr = "Parameter \'" + modeStr + "\': Incorrect mode \'" + pvi->value[0] + "\'";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+if (ParseOwner(s.moduleParams, "StatOwner", &statUID) < 0)
+ return -1;
+if (ParseGroup(s.moduleParams, "StatGroup", &statGID) < 0)
+ return -1;
+if (ParseMode(s.moduleParams, "StatMode", &statMode) < 0)
+ return -1;
+
+if (ParseOwner(s.moduleParams, "ConfOwner", &confUID) < 0)
+ return -1;
+if (ParseGroup(s.moduleParams, "ConfGroup", &confGID) < 0)
+ return -1;
+if (ParseMode(s.moduleParams, "ConfMode", &confMode) < 0)
+ return -1;
+
+if (ParseOwner(s.moduleParams, "UserLogOwner", &userLogUID) < 0)
+ return -1;
+if (ParseGroup(s.moduleParams, "UserLogGroup", &userLogGID) < 0)
+ return -1;
+if (ParseMode(s.moduleParams, "UserLogMode", &userLogMode) < 0)
+ return -1;
+
+std::vector<STG::ParamValue>::const_iterator pvi;
+STG::ParamValue pv;
+pv.param = "RemoveBak";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ removeBak = true;
+ }
+else
+ {
+ if (ParseYesNo(pvi->value[0], &removeBak))
+ {
+ printfd(__FILE__, "Cannot parse parameter 'RemoveBak'\n");
+ return -1;
+ }
+ }
+
+pv.param = "ReadBak";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ readBak = false;
+ }
+else
+ {
+ if (ParseYesNo(pvi->value[0], &readBak))
+ {
+ printfd(__FILE__, "Cannot parse parameter 'ReadBak'\n");
+ return -1;
+ }
+ }
+
+pv.param = "WorkDir";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'WorkDir\' not found.";
+ printfd(__FILE__, "Parameter 'WorkDir' not found\n");
+ return -1;
+ }
+
+workDir = pvi->value[0];
+if (workDir.size() && workDir[workDir.size() - 1] == '/')
+ {
+ workDir.resize(workDir.size() - 1);
+ }
+usersDir = workDir + "/users/";
+if (!CheckAndCreate(usersDir, GetConfModeDir()))
+ {
+ errorStr = usersDir + " doesn't exist. Failed to create.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+tariffsDir = workDir + "/tariffs/";
+if (!CheckAndCreate(tariffsDir, GetConfModeDir()))
+ {
+ errorStr = tariffsDir + " doesn't exist. Failed to create.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+adminsDir = workDir + "/admins/";
+if (!CheckAndCreate(adminsDir, GetConfModeDir()))
+ {
+ errorStr = adminsDir + " doesn't exist. Failed to create.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+servicesDir = workDir + "/services/";
+if (!CheckAndCreate(servicesDir, GetConfModeDir()))
+ {
+ errorStr = servicesDir + " doesn't exist. Failed to create.";
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+const std::string & FILES_STORE_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::User2UID(const char * user, uid_t * uid)
+{
+struct passwd * pw;
+pw = getpwnam(user);
+if (!pw)
+ {
+ errorStr = std::string("User \'") + std::string(user) + std::string("\' not found in system.");
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+*uid = pw->pw_uid;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::Group2GID(const char * gr, gid_t * gid)
+{
+struct group * grp;
+grp = getgrnam(gr);
+if (!grp)
+ {
+ errorStr = std::string("Group \'") + std::string(gr) + std::string("\' not found in system.");
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+*gid = grp->gr_gid;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::Str2Mode(const char * str, mode_t * mode)
+{
+char a;
+char b;
+char c;
+if (strlen(str) > 3)
+ {
+ errorStr = std::string("Error parsing mode \'") + str + std::string("\'");
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+for (int i = 0; i < 3; i++)
+ if (str[i] > '7' || str[i] < '0')
+ {
+ errorStr = std::string("Error parsing mode \'") + str + std::string("\'");
+ printfd(__FILE__, "%s\n", errorStr.c_str());
+ return -1;
+ }
+
+a = str[0] - '0';
+b = str[1] - '0';
+c = str[2] - '0';
+
+*mode = ((mode_t)c) + ((mode_t)b << 3) + ((mode_t)a << 6);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetStatModeDir() const
+{
+mode_t mode = statMode;
+if (statMode & S_IRUSR) mode |= S_IXUSR;
+if (statMode & S_IRGRP) mode |= S_IXGRP;
+if (statMode & S_IROTH) mode |= S_IXOTH;
+return mode;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetConfModeDir() const
+{
+mode_t mode = confMode;
+if (confMode & S_IRUSR) mode |= S_IXUSR;
+if (confMode & S_IRGRP) mode |= S_IXGRP;
+if (confMode & S_IROTH) mode |= S_IXOTH;
+return mode;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+FILES_STORE::FILES_STORE()
+ : version("file_store v.1.04"),
+ logger(STG::PluginLogger::get("store_files"))
+{
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::ParseSettings()
+{
+int ret = storeSettings.ParseSettings(settings);
+if (ret)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = storeSettings.GetStrError();
+ }
+return ret;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetUsersList(std::vector<std::string> * userList) const
+{
+std::vector<std::string> files;
+
+if (GetFileList(&files, storeSettings.GetUsersDir(), S_IFDIR, ""))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Failed to open '" + storeSettings.GetUsersDir() + "': " + std::string(strerror(errno));
+ return -1;
+ }
+
+STG_LOCKER lock(&mutex);
+
+userList->swap(files);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetAdminsList(std::vector<std::string> * adminList) const
+{
+std::vector<std::string> files;
+
+if (GetFileList(&files, storeSettings.GetAdminsDir(), S_IFREG, ".adm"))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Failed to open '" + storeSettings.GetAdminsDir() + "': " + std::string(strerror(errno));
+ return -1;
+ }
+
+STG_LOCKER lock(&mutex);
+
+adminList->swap(files);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetTariffsList(std::vector<std::string> * tariffList) const
+{
+std::vector<std::string> files;
+
+if (GetFileList(&files, storeSettings.GetTariffsDir(), S_IFREG, ".tf"))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Failed to open '" + storeSettings.GetTariffsDir() + "': " + std::string(strerror(errno));
+ return -1;
+ }
+
+STG_LOCKER lock(&mutex);
+
+tariffList->swap(files);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetServicesList(std::vector<std::string> * list) const
+{
+std::vector<std::string> files;
+
+if (GetFileList(&files, storeSettings.GetServicesDir(), S_IFREG, ".serv"))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Failed to open '" + storeSettings.GetServicesDir() + "': " + std::string(strerror(errno));
+ return -1;
+ }
+
+STG_LOCKER lock(&mutex);
+
+list->swap(files);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RemoveDir(const char * path) const
+{
+DIR * d = opendir(path);
+
+if (!d)
+ {
+ errorStr = "failed to open dir. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILE_STORE::RemoveDir() - Failed to open dir '%s': '%s'\n", path, strerror(errno));
+ return -1;
+ }
+
+dirent * entry;
+while ((entry = readdir(d)))
+ {
+ if (!(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")))
+ continue;
+
+ std::string str = path;
+ str += "/" + std::string(entry->d_name);
+
+ struct stat st;
+ if (stat(str.c_str(), &st))
+ continue;
+
+ if ((st.st_mode & S_IFREG))
+ {
+ if (unlink(str.c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "unlink failed. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::RemoveDir() - unlink failed. Message: '%s'\n", strerror(errno));
+ closedir(d);
+ return -1;
+ }
+ }
+
+ if (!(st.st_mode & S_IFDIR))
+ {
+ if (RemoveDir(str.c_str()))
+ {
+ closedir(d);
+ return -1;
+ }
+
+ }
+ }
+
+closedir(d);
+
+if (rmdir(path))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "rmdir failed. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::RemoveDir() - rmdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::AddUser(const std::string & login) const
+{
+std::string fileName;
+
+strprintf(&fileName, "%s%s", storeSettings.GetUsersDir().c_str(), login.c_str());
+
+if (mkdir(fileName.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("mkdir failed. Message: '") + strerror(errno) + "'";
+ printfd(__FILE__, "FILES_STORE::AddUser - mkdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+strprintf(&fileName, "%s%s/conf", storeSettings.GetUsersDir().c_str(), login.c_str());
+if (Touch(fileName))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file \"" + fileName + "\'";
+ printfd(__FILE__, "FILES_STORE::AddUser - fopen failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+strprintf(&fileName, "%s%s/stat", storeSettings.GetUsersDir().c_str(), login.c_str());
+if (Touch(fileName))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file \"" + fileName + "\'";
+ printfd(__FILE__, "FILES_STORE::AddUser - fopen failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::DelUser(const std::string & login) const
+{
+std::string dirName;
+std::string dirName1;
+
+strprintf(&dirName, "%s/%s", storeSettings.GetWorkDir().c_str(), DELETED_USERS_DIR);
+if (access(dirName.c_str(), F_OK) != 0)
+ {
+ if (mkdir(dirName.c_str(), 0700) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Directory '" + dirName + "' cannot be created.";
+ printfd(__FILE__, "FILES_STORE::DelUser - mkdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ }
+
+if (access(dirName.c_str(), F_OK) == 0)
+ {
+ strprintf(&dirName, "%s/%s/%s.%lu", storeSettings.GetWorkDir().c_str(), DELETED_USERS_DIR, login.c_str(), time(NULL));
+ strprintf(&dirName1, "%s/%s", storeSettings.GetUsersDir().c_str(), login.c_str());
+ if (rename(dirName1.c_str(), dirName.c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error moving dir from " + dirName1 + " to " + dirName;
+ printfd(__FILE__, "FILES_STORE::DelUser - rename failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ }
+else
+ {
+ strprintf(&dirName, "%s/%s", storeSettings.GetUsersDir().c_str(), login.c_str());
+ if (RemoveDir(dirName.c_str()))
+ {
+ return -1;
+ }
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserConf(STG::UserConf * conf, const std::string & login) const
+{
+std::string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/conf";
+if (RestoreUserConf(conf, login, fileName))
+ {
+ if (!storeSettings.GetReadBak())
+ {
+ return -1;
+ }
+ return RestoreUserConf(conf, login, fileName + ".bak");
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserConf(STG::UserConf * conf, const std::string & login, const std::string & fileName) const
+{
+CONFIGFILE cf(fileName);
+int e = cf.Error();
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - conf read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadString("Password", &conf->password, "") < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter Password.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - password read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+if (conf->password.empty())
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' password is blank.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - password is blank for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadString("tariff", &conf->tariffName, "") < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter Tariff.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - tariff read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+if (conf->tariffName.empty())
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' tariff is blank.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - tariff is blank for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+std::string ipStr;
+cf.ReadString("IP", &ipStr, "?");
+try
+ {
+ conf->ips = STG::UserIPs::parse(ipStr);
+ }
+catch (const std::string & s)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - ip read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadInt("alwaysOnline", &conf->alwaysOnline, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - alwaysonline read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadInt("down", &conf->disabled, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter Down.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - down read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadInt("passive", &conf->passive, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - passive read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+cf.ReadInt("DisabledDetailStat", &conf->disabledDetailStat, 0);
+cf.ReadTime("CreditExpire", &conf->creditExpire, 0);
+cf.ReadString("TariffChange", &conf->nextTariff, "");
+cf.ReadString("Group", &conf->group, "");
+cf.ReadString("RealName", &conf->realName, "");
+cf.ReadString("Address", &conf->address, "");
+cf.ReadString("Phone", &conf->phone, "");
+cf.ReadString("Note", &conf->note, "");
+cf.ReadString("email", &conf->email, "");
+
+char userdataName[12];
+for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ snprintf(userdataName, 12, "Userdata%d", i);
+ cf.ReadString(userdataName, &conf->userdata[i], "");
+ }
+
+if (cf.ReadDouble("Credit", &conf->credit, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
+ printfd(__FILE__, "FILES_STORE::RestoreUserConf - credit read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserStat(STG::UserStat * stat, const std::string & login) const
+{
+std::string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/stat";
+
+if (RestoreUserStat(stat, login, fileName))
+ {
+ if (!storeSettings.GetReadBak())
+ {
+ return -1;
+ }
+ return RestoreUserStat(stat, login, fileName + ".bak");
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserStat(STG::UserStat * stat, const std::string & login, const std::string & fileName) const
+{
+CONFIGFILE cf(fileName);
+
+int e = cf.Error();
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Cannot open file " + fileName + ".";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - stat read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+char s[22];
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ uint64_t traff;
+ snprintf(s, 22, "D%d", i);
+ if (cf.ReadULongLongInt(s, &traff, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - download stat read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+ stat->monthDown[i] = traff;
+
+ snprintf(s, 22, "U%d", i);
+ if (cf.ReadULongLongInt(s, &traff, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - upload stat read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+ stat->monthUp[i] = traff;
+ }
+
+if (cf.ReadDouble("Cash", &stat->cash, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter Cash";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - cash read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadDouble("FreeMb", &stat->freeMb, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter FreeMb";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - freemb read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadTime("LastCashAddTime", &stat->lastCashAddTime, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastcashaddtime read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadTime("PassiveTime", &stat->passiveTime, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter PassiveTime";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - passivetime read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadDouble("LastCashAdd", &stat->lastCashAdd, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAdd";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastcashadd read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+if (cf.ReadTime("LastActivityTime", &stat->lastActivityTime, 0) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "User \'" + login + "\' stat not read. Parameter LastActivityTime";
+ printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastactivitytime read failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveUserConf(const STG::UserConf & conf, const std::string & login) const
+{
+std::string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/conf";
+
+CONFIGFILE cfstat(fileName, true);
+
+int e = cfstat.Error();
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("User \'") + login + "\' conf not written\n";
+ printfd(__FILE__, "FILES_STORE::SaveUserConf - conf write failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+e = chmod(fileName.c_str(), storeSettings.GetConfMode());
+e += chown(fileName.c_str(), storeSettings.GetConfUID(), storeSettings.GetConfGID());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::SaveUserConf - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+cfstat.WriteString("Password", conf.password);
+cfstat.WriteInt ("Passive", conf.passive);
+cfstat.WriteInt ("Down", conf.disabled);
+cfstat.WriteInt("DisabledDetailStat", conf.disabledDetailStat);
+cfstat.WriteInt ("AlwaysOnline", conf.alwaysOnline);
+cfstat.WriteString("Tariff", conf.tariffName);
+cfstat.WriteString("Address", conf.address);
+cfstat.WriteString("Phone", conf.phone);
+cfstat.WriteString("Email", conf.email);
+cfstat.WriteString("Note", conf.note);
+cfstat.WriteString("RealName", conf.realName);
+cfstat.WriteString("Group", conf.group);
+cfstat.WriteDouble("Credit", conf.credit);
+cfstat.WriteString("TariffChange", conf.nextTariff);
+
+char userdataName[12];
+for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ snprintf(userdataName, 12, "Userdata%d", i);
+ cfstat.WriteString(userdataName, conf.userdata[i]);
+ }
+cfstat.WriteInt("CreditExpire", conf.creditExpire);
+
+std::ostringstream ipStr;
+ipStr << conf.ips;
+cfstat.WriteString("IP", ipStr.str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveUserStat(const STG::UserStat & stat, const std::string & login) const
+{
+std::string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/stat";
+
+ {
+ CONFIGFILE cfstat(fileName, true);
+ int e = cfstat.Error();
+
+ if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("User \'") + login + "\' stat not written\n";
+ printfd(__FILE__, "FILES_STORE::SaveUserStat - stat write failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ char s[22];
+ snprintf(s, 22, "D%d", i);
+ cfstat.WriteInt(s, stat.monthDown[i]);
+ snprintf(s, 22, "U%d", i);
+ cfstat.WriteInt(s, stat.monthUp[i]);
+ }
+
+ cfstat.WriteDouble("Cash", stat.cash);
+ cfstat.WriteDouble("FreeMb", stat.freeMb);
+ cfstat.WriteDouble("LastCashAdd", stat.lastCashAdd);
+ cfstat.WriteInt("LastCashAddTime", stat.lastCashAddTime);
+ cfstat.WriteInt("PassiveTime", stat.passiveTime);
+ cfstat.WriteInt("LastActivityTime", stat.lastActivityTime);
+ }
+
+int e = chmod(fileName.c_str(), storeSettings.GetStatMode());
+e += chown(fileName.c_str(), storeSettings.GetStatUID(), storeSettings.GetStatGID());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::SaveUserStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteLogString(const std::string & str, const std::string & login) const
+{
+FILE * f;
+time_t tm = time(NULL);
+std::string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/log";
+f = fopen(fileName.c_str(), "at");
+
+if (f)
+ {
+ fprintf(f, "%s", LogDate(tm));
+ fprintf(f, " -- ");
+ fprintf(f, "%s", str.c_str());
+ fprintf(f, "\n");
+ fclose(f);
+ }
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot open \'" + fileName + "\'";
+ printfd(__FILE__, "FILES_STORE::WriteLogString - log write failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+int e = chmod(fileName.c_str(), storeSettings.GetLogMode());
+e += chown(fileName.c_str(), storeSettings.GetLogUID(), storeSettings.GetLogGID());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::WriteLogString - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteLog2String(const std::string & str, const std::string & login) const
+{
+FILE * f;
+time_t tm = time(NULL);
+std::string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/log2";
+f = fopen(fileName.c_str(), "at");
+
+if (f)
+ {
+ fprintf(f, "%s", LogDate(tm));
+ fprintf(f, " -- ");
+ fprintf(f, "%s", str.c_str());
+ fprintf(f, "\n");
+ fclose(f);
+ }
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot open \'" + fileName + "\'";
+ printfd(__FILE__, "FILES_STORE::WriteLogString - log write failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+int e = chmod(fileName.c_str(), storeSettings.GetLogMode());
+e += chown(fileName.c_str(), storeSettings.GetLogUID(), storeSettings.GetLogGID());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::WriteLogString - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message) const
+{
+std::string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
+ + paramName + "\' parameter changed from \'" + oldValue +
+ "\' to \'" + newValue + "\'. " + message;
+
+return WriteLogString(userLogMsg, login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
+{
+std::string logStr = "Connect, " + inet_ntostring(ip);
+if (WriteLogString(logStr, login))
+ return -1;
+return WriteLog2String(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & monthUp,
+ const STG::DirTraff & monthDown,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double freeMb,
+ const std::string & reason) const
+{
+std::ostringstream logStr;
+logStr << "Disconnect, "
+ << " session upload: \'"
+ << sessionUp
+ << "\' session download: \'"
+ << sessionDown
+ << "\' month upload: \'"
+ << monthUp
+ << "\' month download: \'"
+ << monthDown
+ << "\' cash: \'"
+ << cash
+ << "\'";
+
+if (WriteLogString(logStr.str(), login))
+ return -1;
+
+logStr << " freeMb: \'"
+ << freeMb
+ << "\'"
+ << " reason: \'"
+ << reason
+ << "\'";
+
+return WriteLog2String(logStr.str(), login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
+{
+// Classic stats
+std::string stat1;
+strprintf(&stat1,"%s/%s/stat.%d.%02d",
+ storeSettings.GetUsersDir().c_str(), login.c_str(), year + 1900, month + 1);
+
+CONFIGFILE s(stat1, true);
+
+if (s.Error())
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file '" + stat1 + "'";
+ printfd(__FILE__, "FILES_STORE::SaveMonthStat - month stat write failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+// New stats
+std::string stat2;
+strprintf(&stat2,"%s/%s/stat2.%d.%02d",
+ storeSettings.GetUsersDir().c_str(), login.c_str(), year + 1900, month + 1);
+
+CONFIGFILE s2(stat2, true);
+
+if (s2.Error())
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file '" + stat2 + "'";
+ printfd(__FILE__, "FILES_STORE::SaveMonthStat - month stat write failed for user '%s'\n", login.c_str());
+ return -1;
+ }
+
+for (size_t i = 0; i < DIR_NUM; i++)
+ {
+ char dirName[3];
+ snprintf(dirName, 3, "U%llu", (unsigned long long)i);
+ s.WriteInt(dirName, stat.monthUp[i]); // Classic
+ s2.WriteInt(dirName, stat.monthUp[i]); // New
+ snprintf(dirName, 3, "D%llu", (unsigned long long)i);
+ s.WriteInt(dirName, stat.monthDown[i]); // Classic
+ s2.WriteInt(dirName, stat.monthDown[i]); // New
+ }
+
+// Classic
+s.WriteDouble("cash", stat.cash);
+
+// New
+s2.WriteDouble("Cash", stat.cash);
+s2.WriteDouble("FreeMb", stat.freeMb);
+s2.WriteDouble("LastCashAdd", stat.lastCashAdd);
+s2.WriteInt("LastCashAddTime", stat.lastCashAddTime);
+s2.WriteInt("PassiveTime", stat.passiveTime);
+s2.WriteInt("LastActivityTime", stat.lastActivityTime);
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::AddAdmin(const std::string & login) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
+
+if (Touch(fileName))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file " + fileName;
+ printfd(__FILE__, "FILES_STORE::AddAdmin - failed to add admin '%s'\n", login.c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::DelAdmin(const std::string & login) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
+if (unlink(fileName.c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "unlink failed. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::SaveAdmin(const STG::AdminConf & ac) const
+{
+std::string fileName;
+
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), ac.login.c_str());
+
+ {
+ CONFIGFILE cf(fileName, true);
+
+ int e = cf.Error();
+
+ if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot write admin " + ac.login + ". " + fileName;
+ printfd(__FILE__, "FILES_STORE::SaveAdmin - failed to save admin '%s'\n", ac.login.c_str());
+ return -1;
+ }
+
+ char pass[ADM_PASSWD_LEN + 1];
+ memset(pass, 0, sizeof(pass));
+
+ char adminPass[ADM_PASSWD_LEN + 1];
+ memset(adminPass, 0, sizeof(adminPass));
+
+ BLOWFISH_CTX ctx;
+ InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+ strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+ adminPass[ADM_PASSWD_LEN - 1] = 0;
+
+ for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+ {
+ EncryptBlock(pass + 8*i, adminPass + 8*i, &ctx);
+ }
+
+ pass[ADM_PASSWD_LEN - 1] = 0;
+ char passwordE[2 * ADM_PASSWD_LEN + 2];
+ Encode12(passwordE, pass, ADM_PASSWD_LEN);
+
+ cf.WriteString("password", passwordE);
+ cf.WriteInt("ChgConf", ac.priv.userConf);
+ cf.WriteInt("ChgPassword", ac.priv.userPasswd);
+ cf.WriteInt("ChgStat", ac.priv.userStat);
+ cf.WriteInt("ChgCash", ac.priv.userCash);
+ cf.WriteInt("UsrAddDel", ac.priv.userAddDel);
+ cf.WriteInt("ChgTariff", ac.priv.tariffChg);
+ cf.WriteInt("ChgAdmin", ac.priv.adminChg);
+ cf.WriteInt("ChgService", ac.priv.serviceChg);
+ cf.WriteInt("ChgCorp", ac.priv.corpChg);
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
+CONFIGFILE cf(fileName);
+char pass[ADM_PASSWD_LEN + 1];
+char password[ADM_PASSWD_LEN + 1];
+char passwordE[2 * ADM_PASSWD_LEN + 2];
+BLOWFISH_CTX ctx;
+
+std::string p;
+
+if (cf.Error())
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot open " + fileName;
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - failed to restore admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadString("password", &p, "*"))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter password";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - password read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+memset(passwordE, 0, sizeof(passwordE));
+strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
+
+memset(pass, 0, sizeof(pass));
+
+if (passwordE[0] != 0)
+ {
+ Decode21(pass, passwordE);
+ InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+ for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+ {
+ DecryptBlock(password + 8*i, pass + 8*i, &ctx);
+ }
+ }
+else
+ {
+ password[0] = 0;
+ }
+
+ac->password = password;
+
+uint16_t a;
+
+if (cf.ReadUShortInt("ChgConf", &a, 0) == 0)
+ ac->priv.userConf = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter ChgConf";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgconf read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("ChgPassword", &a, 0) == 0)
+ ac->priv.userPasswd = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter ChgPassword";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgpassword read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("ChgStat", &a, 0) == 0)
+ ac->priv.userStat = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter ChgStat";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgstat read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("ChgCash", &a, 0) == 0)
+ ac->priv.userCash = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter ChgCash";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgcash read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("UsrAddDel", &a, 0) == 0)
+ ac->priv.userAddDel = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter UsrAddDel";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - usradddel read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("ChgAdmin", &a, 0) == 0)
+ ac->priv.adminChg = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter ChgAdmin";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgadmin read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("ChgTariff", &a, 0) == 0)
+ ac->priv.tariffChg = a;
+else
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter ChgTariff";
+ printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgtariff read failed for admin '%s'\n", ac->login.c_str());
+ return -1;
+ }
+
+if (cf.ReadUShortInt("ChgService", &a, 0) == 0)
+ ac->priv.serviceChg = a;
+else
+ ac->priv.serviceChg = 0;
+
+if (cf.ReadUShortInt("ChgCorp", &a, 0) == 0)
+ ac->priv.corpChg = a;
+else
+ ac->priv.corpChg = 0;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::AddTariff(const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.tf", storeSettings.GetTariffsDir().c_str(), name.c_str());
+if (Touch(fileName))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file " + fileName;
+ printfd(__FILE__, "FILES_STORE::AddTariff - failed to add tariff '%s'\n", name.c_str());
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::DelTariff(const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.tf", storeSettings.GetTariffsDir().c_str(), name.c_str());
+if (unlink(fileName.c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "unlink failed. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::DelTariff - unlink failed. Message: '%s'\n", strerror(errno));
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreTariff(STG::TariffData * td, const std::string & tariffName) const
+{
+std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
+CONFIGFILE conf(fileName);
+std::string str;
+td->tariffConf.name = tariffName;
+
+if (conf.Error() != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read file " + fileName;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - failed to read tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+std::string param;
+for (int i = 0; i<DIR_NUM; i++)
+ {
+ strprintf(¶m, "Time%d", i);
+ if (conf.ReadString(param, &str, "00:00-00:00") < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - time%d read failed for tariff '%s'\n", i, tariffName.c_str());
+ return -1;
+ }
+
+ ParseTariffTimeStr(str.c_str(),
+ td->dirPrice[i].hDay,
+ td->dirPrice[i].mDay,
+ td->dirPrice[i].hNight,
+ td->dirPrice[i].mNight);
+
+ strprintf(¶m, "PriceDayA%d", i);
+ if (conf.ReadDouble(param, &td->dirPrice[i].priceDayA, 0.0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - pricedaya read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+ td->dirPrice[i].priceDayA /= (1024*1024);
+
+ strprintf(¶m, "PriceDayB%d", i);
+ if (conf.ReadDouble(param, &td->dirPrice[i].priceDayB, 0.0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - pricedayb read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+ td->dirPrice[i].priceDayB /= (1024*1024);
+
+ strprintf(¶m, "PriceNightA%d", i);
+ if (conf.ReadDouble(param, &td->dirPrice[i].priceNightA, 0.0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - pricenighta read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+ td->dirPrice[i].priceNightA /= (1024*1024);
+
+ strprintf(¶m, "PriceNightB%d", i);
+ if (conf.ReadDouble(param, &td->dirPrice[i].priceNightB, 0.0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - pricenightb read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+ td->dirPrice[i].priceNightB /= (1024*1024);
+
+ strprintf(¶m, "Threshold%d", i);
+ if (conf.ReadInt(param, &td->dirPrice[i].threshold, 0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - threshold read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+ strprintf(¶m, "SinglePrice%d", i);
+ if (conf.ReadInt(param, &td->dirPrice[i].singlePrice, 0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - singleprice read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+ strprintf(¶m, "NoDiscount%d", i);
+ if (conf.ReadInt(param, &td->dirPrice[i].noDiscount, 0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - nodiscount read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+ }
+
+if (conf.ReadDouble("Fee", &td->tariffConf.fee, 0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - fee read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+if (conf.ReadDouble("Free", &td->tariffConf.free, 0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - free read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+if (conf.ReadDouble("PassiveCost", &td->tariffConf.passiveCost, 0) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - passivecost read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+if (conf.ReadString("TraffType", &str, "") < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType";
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - trafftype read failed for tariff '%s'\n", tariffName.c_str());
+ return -1;
+ }
+
+td->tariffConf.traffType = STG::Tariff::parseTraffType(str);
+
+if (conf.ReadString("Period", &str, "month") < 0)
+ td->tariffConf.period = STG::Tariff::MONTH;
+else
+ td->tariffConf.period = STG::Tariff::parsePeriod(str);
+
+if (conf.ReadString("ChangePolicy", &str, "allow") < 0)
+ td->tariffConf.changePolicy = STG::Tariff::ALLOW;
+else
+ td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(str);
+
+conf.ReadTime("ChangePolicyTimeout", &td->tariffConf.changePolicyTimeout, 0);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveTariff(const STG::TariffData & td, const std::string & tariffName) const
+{
+std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
+
+ {
+ CONFIGFILE cf(fileName, true);
+
+ int e = cf.Error();
+
+ if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error writing tariff " + tariffName;
+ printfd(__FILE__, "FILES_STORE::RestoreTariff - failed to save tariff '%s'\n", tariffName.c_str());
+ return e;
+ }
+
+ std::string param;
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, "PriceDayA%d", i);
+ cf.WriteDouble(param, td.dirPrice[i].priceDayA * pt_mega);
+
+ strprintf(¶m, "PriceDayB%d", i);
+ cf.WriteDouble(param, td.dirPrice[i].priceDayB * pt_mega);
+
+ strprintf(¶m, "PriceNightA%d", i);
+ cf.WriteDouble(param, td.dirPrice[i].priceNightA * pt_mega);
+
+ strprintf(¶m, "PriceNightB%d", i);
+ cf.WriteDouble(param, td.dirPrice[i].priceNightB * pt_mega);
+
+ strprintf(¶m, "Threshold%d", i);
+ cf.WriteInt(param, td.dirPrice[i].threshold);
+
+ std::string s;
+ strprintf(¶m, "Time%d", i);
+
+ strprintf(&s, "%0d:%0d-%0d:%0d",
+ td.dirPrice[i].hDay,
+ td.dirPrice[i].mDay,
+ td.dirPrice[i].hNight,
+ td.dirPrice[i].mNight);
+
+ cf.WriteString(param, s);
+
+ strprintf(¶m, "NoDiscount%d", i);
+ cf.WriteInt(param, td.dirPrice[i].noDiscount);
+
+ strprintf(¶m, "SinglePrice%d", i);
+ cf.WriteInt(param, td.dirPrice[i].singlePrice);
+ }
+
+ cf.WriteDouble("PassiveCost", td.tariffConf.passiveCost);
+ cf.WriteDouble("Fee", td.tariffConf.fee);
+ cf.WriteDouble("Free", td.tariffConf.free);
+ cf.WriteString("TraffType", STG::Tariff::toString(td.tariffConf.traffType));
+ cf.WriteString("Period", STG::Tariff::toString(td.tariffConf.period));
+ cf.WriteString("ChangePolicy", STG::Tariff::toString(td.tariffConf.changePolicy));
+ cf.WriteTime("ChangePolicyTimeout", td.tariffConf.changePolicyTimeout);
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::AddService(const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
+
+if (Touch(fileName))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot create file " + fileName;
+ printfd(__FILE__, "FILES_STORE::AddService - failed to add service '%s'\n", name.c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::DelService(const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
+if (unlink(fileName.c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "unlink failed. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::SaveService(const STG::ServiceConf & conf) const
+{
+std::string fileName;
+
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), conf.name.c_str());
+
+ {
+ CONFIGFILE cf(fileName, true);
+
+ int e = cf.Error();
+
+ if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot write service " + conf.name + ". " + fileName;
+ printfd(__FILE__, "FILES_STORE::SaveService - failed to save service '%s'\n", conf.name.c_str());
+ return -1;
+ }
+
+ cf.WriteString("name", conf.name);
+ cf.WriteString("comment", conf.comment);
+ cf.WriteDouble("cost", conf.cost);
+ cf.WriteInt("pay_day", conf.payDay);
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreService(STG::ServiceConf * conf, const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
+CONFIGFILE cf(fileName);
+
+if (cf.Error())
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot open " + fileName;
+ printfd(__FILE__, "FILES_STORE::RestoreService - failed to restore service '%s'\n", name.c_str());
+ return -1;
+ }
+
+if (cf.ReadString("name", &conf->name, name))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter 'name'";
+ printfd(__FILE__, "FILES_STORE::RestoreService - name read failed for service '%s'\n", name.c_str());
+ return -1;
+ }
+
+if (cf.ReadString("comment", &conf->comment, ""))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter 'comment'";
+ printfd(__FILE__, "FILES_STORE::RestoreService - comment read failed for service '%s'\n", name.c_str());
+ return -1;
+ }
+
+if (cf.ReadDouble("cost", &conf->cost, 0.0))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter 'cost'";
+ printfd(__FILE__, "FILES_STORE::RestoreService - cost read failed for service '%s'\n", name.c_str());
+ return -1;
+ }
+
+unsigned short value = 0;
+if (cf.ReadUShortInt("pay_day", &value, 0))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error in parameter 'pay_day'";
+ printfd(__FILE__, "FILES_STORE::RestoreService - pay day read failed for service '%s'\n", name.c_str());
+ return -1;
+ }
+conf->payDay = value;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const
+{
+char fn[FN_STR_LEN];
+char dn[FN_STR_LEN];
+FILE * statFile;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+
+snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat", storeSettings.GetUsersDir().c_str(), login.c_str());
+if (access(dn, F_OK) != 0)
+ {
+ if (mkdir(dn, 0700) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Directory \'" + std::string(dn) + "\' cannot be created.";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ }
+
+int e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(dn, storeSettings.GetStatModeDir());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+lt = localtime(&t);
+
+if (lt->tm_hour == 0 && lt->tm_min <= 5)
+ {
+ t -= 3600 * 24;
+ lt = localtime(&t);
+ }
+
+snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat/%d",
+ storeSettings.GetUsersDir().c_str(),
+ login.c_str(),
+ lt->tm_year+1900);
+
+if (access(dn, F_OK) != 0)
+ {
+ if (mkdir(dn, 0700) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Directory \'" + std::string(dn) + "\' cannot be created.";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ }
+
+e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(dn, storeSettings.GetStatModeDir());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat/%d/%s%d",
+ storeSettings.GetUsersDir().c_str(),
+ login.c_str(),
+ lt->tm_year+1900,
+ lt->tm_mon+1 < 10 ? "0" : "",
+ lt->tm_mon+1);
+if (access(dn, F_OK) != 0)
+ {
+ if (mkdir(dn, 0700) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Directory \'" + std::string(dn) + "\' cannot be created.";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ }
+
+e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(dn, storeSettings.GetStatModeDir());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+snprintf(fn, FN_STR_LEN, "%s/%s%d", dn, lt->tm_mday < 10 ? "0" : "", lt->tm_mday);
+
+statFile = fopen (fn, "at");
+
+if (!statFile)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "File \'" + std::string(fn) + "\' cannot be written.";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - fopen failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+struct tm * lt1;
+struct tm * lt2;
+
+lt1 = localtime(&lastStat);
+
+int h1, m1, s1;
+int h2, m2, s2;
+
+h1 = lt1->tm_hour;
+m1 = lt1->tm_min;
+s1 = lt1->tm_sec;
+
+lt2 = localtime(&t);
+
+h2 = lt2->tm_hour;
+m2 = lt2->tm_min;
+s2 = lt2->tm_sec;
+
+if (fprintf(statFile, "-> %02d.%02d.%02d - %02d.%02d.%02d\n",
+ h1, m1, s1, h2, m2, s2) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("fprint failed. Message: '") + strerror(errno) + "'";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
+ fclose(statFile);
+ return -1;
+ }
+
+auto stIter = statTree.begin();
+
+while (stIter != statTree.end())
+ {
+ const auto u = std::to_string(stIter->second.up);
+ const auto d = std::to_string(stIter->second.down);
+ #ifdef TRAFF_STAT_WITH_PORTS
+ if (fprintf(statFile, "%17s:%hu\t%15d\t%15s\t%15s\t%f\n",
+ inet_ntostring(stIter->first.ip).c_str(),
+ stIter->first.port,
+ stIter->first.dir,
+ d.c_str(),
+ u.c_str(),
+ stIter->second.cash) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "fprint failed. Message: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
+ fclose(statFile);
+ return -1;
+ }
+ #else
+ if (fprintf(statFile, "%17s\t%15d\t%15s\t%15s\t%f\n",
+ inet_ntostring(stIter->first.ip).c_str(),
+ stIter->first.dir,
+ d.c_str(),
+ u.c_str(),
+ stIter->second.cash) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("fprint failed. Message: '");
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
+ fclose(statFile);
+ return -1;
+ }
+ #endif
+
+ ++stIter;
+ }
+
+fclose(statFile);
+
+e = chown(fn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(fn, storeSettings.GetStatMode());
+
+if (e)
+ {
+ STG_LOCKER lock(&mutex);
+ printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::AddMessage(STG::Message * msg, const std::string & login) const
+{
+std::string fn;
+std::string dn;
+struct timeval tv;
+
+strprintf(&dn, "%s/%s/messages", storeSettings.GetUsersDir().c_str(), login.c_str());
+if (access(dn.c_str(), F_OK) != 0)
+ {
+ if (mkdir(dn.c_str(), 0700) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Directory \'";
+ errorStr += dn;
+ errorStr += "\' cannot be created.";
+ printfd(__FILE__, "FILES_STORE::AddMessage - mkdir failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ }
+
+chmod(dn.c_str(), storeSettings.GetConfModeDir());
+
+gettimeofday(&tv, NULL);
+
+msg->header.id = ((long long)tv.tv_sec) * 1000000 + ((long long)tv.tv_usec);
+strprintf(&fn, "%s/%lld", dn.c_str(), msg->header.id);
+
+if (Touch(fn))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "File \'";
+ errorStr += fn;
+ errorStr += "\' cannot be writen.";
+ printfd(__FILE__, "FILES_STORE::AddMessage - fopen failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+return EditMessage(*msg, login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::EditMessage(const STG::Message & msg, const std::string & login) const
+{
+std::string fileName;
+
+FILE * msgFile;
+strprintf(&fileName, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), msg.header.id);
+
+if (access(fileName.c_str(), F_OK) != 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Message for user \'";
+ errorStr += login + "\' with ID \'";
+ errorStr += std::to_string(msg.header.id) + "\' does not exist.";
+ printfd(__FILE__, "FILES_STORE::EditMessage - %s\n", errorStr.c_str());
+ return -1;
+ }
+
+Touch(fileName + ".new");
+
+msgFile = fopen((fileName + ".new").c_str(), "wt");
+if (!msgFile)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "File \'" + fileName + "\' cannot be writen.";
+ printfd(__FILE__, "FILES_STORE::EditMessage - fopen failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+bool res = true;
+res &= (fprintf(msgFile, "%u\n", msg.header.type) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.lastSendTime) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.creationTime) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.showTime) >= 0);
+res &= (fprintf(msgFile, "%d\n", msg.header.repeat) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.repeatPeriod) >= 0);
+res &= (fprintf(msgFile, "%s", msg.text.c_str()) >= 0);
+
+if (!res)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("fprintf failed. Message: '") + strerror(errno) + "'";
+ printfd(__FILE__, "FILES_STORE::EditMessage - fprintf failed. Message: '%s'\n", strerror(errno));
+ fclose(msgFile);
+ return -1;
+ }
+
+fclose(msgFile);
+
+chmod((fileName + ".new").c_str(), storeSettings.GetConfMode());
+
+if (rename((fileName + ".new").c_str(), fileName.c_str()) < 0)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Error moving dir from " + fileName + ".new to " + fileName;
+ printfd(__FILE__, "FILES_STORE::EditMessage - rename failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const
+{
+std::string fn;
+strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), id);
+msg->header.id = id;
+return ReadMessage(fn, &msg->header, &msg->text);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::DelMessage(uint64_t id, const std::string & login) const
+{
+std::string fn;
+strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), id);
+
+return unlink(fn.c_str());
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const
+{
+std::string dn(storeSettings.GetUsersDir() + "/" + login + "/messages/");
+
+if (access(dn.c_str(), F_OK) != 0)
+ {
+ return 0;
+ }
+
+std::vector<std::string> messages;
+GetFileList(&messages, dn, S_IFREG, "");
+
+for (unsigned i = 0; i < messages.size(); i++)
+ {
+ unsigned long long id = 0;
+
+ if (str2x(messages[i].c_str(), id))
+ {
+ if (unlink((dn + messages[i]).c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("unlink failed. Message: '") + strerror(errno) + "'";
+ printfd(__FILE__, "FILES_STORE::GetMessageHdrs - unlink failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ continue;
+ }
+
+ STG::Message::Header hdr;
+ if (ReadMessage(dn + messages[i], &hdr, NULL))
+ {
+ return -1;
+ }
+
+ if (hdr.repeat < 0)
+ {
+ if (unlink((dn + messages[i]).c_str()))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = std::string("unlink failed. Message: '") + strerror(errno) + "'";
+ printfd(__FILE__, "FILES_STORE::GetMessageHdrs - unlink failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+ continue;
+ }
+
+ hdr.id = id;
+ hdrsList->push_back(hdr);
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::ReadMessage(const std::string & fileName,
+ STG::Message::Header * hdr,
+ std::string * text) const
+{
+FILE * msgFile;
+msgFile = fopen(fileName.c_str(), "rt");
+if (!msgFile)
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "File \'";
+ errorStr += fileName;
+ errorStr += "\' cannot be openned.";
+ printfd(__FILE__, "FILES_STORE::ReadMessage - fopen failed. Message: '%s'\n", strerror(errno));
+ return -1;
+ }
+char p[20];
+unsigned * d[6];
+d[0] = &hdr->type;
+d[1] = &hdr->lastSendTime;
+d[2] = &hdr->creationTime;
+d[3] = &hdr->showTime;
+d[4] = (unsigned*)(&hdr->repeat);
+d[5] = &hdr->repeatPeriod;
+
+memset(p, 0, sizeof(p));
+
+for (int pos = 0; pos < 6; pos++)
+ {
+ if (fgets(p, sizeof(p) - 1, msgFile) == NULL) {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read file \'";
+ errorStr += fileName;
+ errorStr += "\'. Missing data.";
+ printfd(__FILE__, "FILES_STORE::ReadMessage - cannot read file (missing data)\n");
+ printfd(__FILE__, "FILES_STORE::ReadMessage - position: %d\n", pos);
+ fclose(msgFile);
+ return -1;
+ }
+
+ char * ep;
+ ep = strrchr(p, '\r');
+ if (ep) *ep = 0;
+ ep = strrchr(p, '\n');
+ if (ep) *ep = 0;
+
+ if (feof(msgFile))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read file \'";
+ errorStr += fileName;
+ errorStr += "\'. Missing data.";
+ printfd(__FILE__, "FILES_STORE::ReadMessage - cannot read file (feof)\n");
+ printfd(__FILE__, "FILES_STORE::ReadMessage - position: %d\n", pos);
+ fclose(msgFile);
+ return -1;
+ }
+
+ if (str2x(p, *(d[pos])))
+ {
+ STG_LOCKER lock(&mutex);
+ errorStr = "Cannot read file \'";
+ errorStr += fileName;
+ errorStr += "\'. Incorrect value. \'";
+ errorStr += p;
+ errorStr += "\'";
+ printfd(__FILE__, "FILES_STORE::ReadMessage - incorrect value\n");
+ fclose(msgFile);
+ return -1;
+ }
+ }
+
+char txt[2048];
+memset(txt, 0, sizeof(txt));
+if (text)
+ {
+ text->erase(text->begin(), text->end());
+ while (!feof(msgFile))
+ {
+ txt[0] = 0;
+ if (fgets(txt, sizeof(txt) - 1, msgFile) == NULL) {
+ break;
+ }
+
+ (*text) += txt;
+ }
+ }
+fclose(msgFile);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::Touch(const std::string & path) const
+{
+FILE * f = fopen(path.c_str(), "wb");
+if (f)
+ {
+ fclose(f);
+ return 0;
+ }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int GetFileList(std::vector<std::string> * fileList, const std::string & directory, mode_t mode, const std::string & ext)
+{
+DIR * d = opendir(directory.c_str());
+
+if (!d)
+ {
+ printfd(__FILE__, "GetFileList - Failed to open dir '%s': '%s'\n", directory.c_str(), strerror(errno));
+ return -1;
+ }
+
+dirent * entry;
+while ((entry = readdir(d)))
+ {
+ if (!(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")))
+ continue;
+
+ std::string str = directory + "/" + std::string(entry->d_name);
+
+ struct stat st;
+ if (stat(str.c_str(), &st))
+ continue;
+
+ if (!(st.st_mode & mode)) // Filter by mode
+ continue;
+
+ if (!ext.empty())
+ {
+ // Check extension
+ size_t d_nameLen = strlen(entry->d_name);
+ if (d_nameLen <= ext.size())
+ continue;
+
+ if (ext == entry->d_name + (d_nameLen - ext.size()))
+ {
+ entry->d_name[d_nameLen - ext.size()] = 0;
+ fileList->push_back(entry->d_name);
+ }
+ }
+ else
+ {
+ fileList->push_back(entry->d_name);
+ }
+ }
+
+closedir(d);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/module_settings.h"
+#include "stg/store.h"
+#include "stg/conffiles.h"
+#include "stg/user_traff.h"
+#include "stg/logger.h"
+
+#include <string>
+
+#include <sys/types.h>
+#include <pthread.h>
+
+//-----------------------------------------------------------------------------
+class FILES_STORE_SETTINGS {
+public:
+ FILES_STORE_SETTINGS();
+ int ParseSettings(const STG::ModuleSettings & s);
+ const std::string & GetStrError() const;
+
+ std::string GetWorkDir() const { return workDir; }
+ std::string GetUsersDir() const { return usersDir; }
+ std::string GetAdminsDir() const { return adminsDir; }
+ std::string GetTariffsDir() const { return tariffsDir; }
+ std::string GetServicesDir() const { return servicesDir; }
+
+ mode_t GetStatMode() const { return statMode; }
+ mode_t GetStatModeDir() const;
+ uid_t GetStatUID() const { return statUID; }
+ gid_t GetStatGID() const { return statGID; }
+
+ mode_t GetConfMode() const { return confMode; }
+ mode_t GetConfModeDir() const;
+ uid_t GetConfUID() const { return confUID; }
+ gid_t GetConfGID() const { return confGID; }
+
+ mode_t GetLogMode() const { return userLogMode; }
+ uid_t GetLogUID() const { return userLogUID; }
+ gid_t GetLogGID() const { return userLogGID; }
+
+ bool GetRemoveBak() const { return removeBak; }
+ bool GetReadBak() const { return readBak; }
+
+private:
+ FILES_STORE_SETTINGS(const FILES_STORE_SETTINGS & rvalue);
+ FILES_STORE_SETTINGS & operator=(const FILES_STORE_SETTINGS & rvalue);
+
+ const STG::ModuleSettings * settings;
+
+ int User2UID(const char * user, uid_t * uid);
+ int Group2GID(const char * gr, gid_t * gid);
+ int Str2Mode(const char * str, mode_t * mode);
+ int ParseOwner(const std::vector<STG::ParamValue> & moduleParams, const std::string & owner, uid_t * uid);
+ int ParseGroup(const std::vector<STG::ParamValue> & moduleParams, const std::string & group, uid_t * uid);
+ int ParseMode(const std::vector<STG::ParamValue> & moduleParams, const std::string & modeStr, mode_t * mode);
+ int ParseYesNo(const std::string & value, bool * val);
+
+ std::string errorStr;
+
+ std::string workDir;
+ std::string usersDir;
+ std::string adminsDir;
+ std::string tariffsDir;
+ std::string servicesDir;
+
+ mode_t statMode;
+ uid_t statUID;
+ gid_t statGID;
+
+ mode_t confMode;
+ uid_t confUID;
+ gid_t confGID;
+
+ mode_t userLogMode;
+ uid_t userLogUID;
+ gid_t userLogGID;
+
+ bool removeBak;
+ bool readBak;
+};
+//-----------------------------------------------------------------------------
+class FILES_STORE: public STG::Store {
+public:
+ FILES_STORE();
+ const std::string & GetStrError() const override { return errorStr; }
+
+ //User
+ int GetUsersList(std::vector<std::string> * usersList) const override;
+ int AddUser(const std::string & login) const override;
+ int DelUser(const std::string & login) const override;
+ int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
+ int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
+
+ int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
+ int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
+
+ int WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message = "") const override;
+ int WriteUserConnect(const std::string & login, uint32_t ip) const override;
+ int WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & up,
+ const STG::DirTraff & down,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double freeMb,
+ const std::string & reason) const override;
+
+ int WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const override;
+
+ int AddMessage(STG::Message * msg, const std::string & login) const override;
+ int EditMessage(const STG::Message & msg, const std::string & login) const override;
+ int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
+ int DelMessage(uint64_t id, const std::string & login) const override;
+ int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
+
+ int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
+
+ //Admin
+ int GetAdminsList(std::vector<std::string> * adminsList) const override;
+ int AddAdmin(const std::string & login) const override;
+ int DelAdmin(const std::string & login) const override;
+ int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
+ int SaveAdmin(const STG::AdminConf & ac) const override;
+
+ //Tariff
+ int GetTariffsList(std::vector<std::string> * tariffsList) const override;
+ int AddTariff(const std::string & name) const override;
+ int DelTariff(const std::string & name) const override;
+ int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
+ int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
+
+ //Corparation
+ int GetCorpsList(std::vector<std::string> *) const override { return 0; }
+ int SaveCorp(const STG::CorpConf &) const override { return 0; }
+ int RestoreCorp(STG::CorpConf *, const std::string &) const override { return 0; }
+ int AddCorp(const std::string &) const override { return 0; }
+ int DelCorp(const std::string &) const override { return 0; }
+
+ // Services
+ int GetServicesList(std::vector<std::string> *) const override;
+ int SaveService(const STG::ServiceConf &) const override;
+ int RestoreService(STG::ServiceConf *, const std::string &) const override;
+ int AddService(const std::string &) const override;
+ int DelService(const std::string &) const override;
+
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+ const std::string & GetVersion() const override { return version; }
+
+private:
+ FILES_STORE(const FILES_STORE & rvalue);
+ FILES_STORE & operator=(const FILES_STORE & rvalue);
+
+ int ReadMessage(const std::string & fileName,
+ STG::Message::Header * hdr,
+ std::string * text) const;
+
+ virtual int RestoreUserStat(STG::UserStat * stat, const std::string & login, const std::string & fileName) const;
+ virtual int RestoreUserConf(STG::UserConf * conf, const std::string & login, const std::string & fileName) const;
+
+ virtual int WriteLogString(const std::string & str, const std::string & login) const;
+ virtual int WriteLog2String(const std::string & str, const std::string & login) const;
+ int RemoveDir(const char * path) const;
+ int Touch(const std::string & path) const;
+
+ mutable std::string errorStr;
+ std::string version;
+ FILES_STORE_SETTINGS storeSettings;
+ STG::ModuleSettings settings;
+ mutable pthread_mutex_t mutex;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * This file contains a realization of a base firebird-storage plugin class
+ *
+ * $Revision: 1.18 $
+ * $Date: 2010/01/08 16:00:45 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/common.h"
+
+#include <string>
+#include <vector>
+
+extern "C" STG::Store* GetStore()
+{
+ static FIREBIRD_STORE plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+FIREBIRD_STORE::FIREBIRD_STORE()
+ : version("firebird_store v.1.4"),
+ db_server("localhost"),
+ db_database("/var/stg/stargazer.fdb"),
+ db_user("stg"),
+ db_password("123456"),
+ til(IBPP::ilConcurrency),
+ tlr(IBPP::lrWait),
+ schemaVersion(0),
+ logger(STG::PluginLogger::get("store_firebird"))
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+FIREBIRD_STORE::~FIREBIRD_STORE()
+{
+db->Disconnect();
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::ParseSettings()
+{
+std::vector<STG::ParamValue>::iterator i;
+std::string s;
+
+for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
+ {
+ if (i->value.empty())
+ continue;
+ s = ToLower(i->param);
+
+ if (s == "server")
+ db_server = i->value.front();
+
+ if (s == "database")
+ db_database = i->value.front();
+
+ if (s == "user")
+ db_user = i->value.front();
+
+ if (s == "password")
+ db_password = i->value.front();
+
+ // Advanced settings block
+
+ if (s == "isolationLevel")
+ {
+ if (i->value.front() == "Concurrency")
+ til = IBPP::ilConcurrency;
+ else if (i->value.front() == "DirtyRead")
+ til = IBPP::ilReadDirty;
+ else if (i->value.front() == "ReadCommitted")
+ til = IBPP::ilReadCommitted;
+ else if (i->value.front() == "Consistency")
+ til = IBPP::ilConsistency;
+ }
+
+ if (s == "lockResolution")
+ {
+ if (i->value.front() == "Wait")
+ tlr = IBPP::lrWait;
+ else if (i->value.front() == "NoWait")
+ tlr = IBPP::lrNoWait;
+ }
+ }
+
+try
+ {
+ db = IBPP::DatabaseFactory(db_server, db_database, db_user, db_password, "", "KOI8U", "");
+ db->Connect();
+ return CheckVersion();
+ }
+catch (IBPP::Exception & ex)
+ {
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::CheckVersion()
+{
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Execute("SELECT RDB$RELATION_NAME FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG=0 AND RDB$RELATION_NAME = 'TB_INFO'");
+ if (!st->Fetch())
+ {
+ schemaVersion = 0;
+ }
+ else
+ {
+ st->Execute("SELECT version FROM tb_info");
+ while (st->Fetch())
+ st->Get(1, schemaVersion);
+ }
+ tr->Commit();
+ logger("FIREBIRD_STORE: Current DB schema version: %d", schemaVersion);
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/store.h"
+#include "stg/locker.h"
+#include "stg/ibpp.h"
+#include "stg/logger.h"
+#include "stg/module_settings.h"
+
+#include <ctime>
+#include <string>
+#include <vector>
+
+struct ToLower {
+ char operator() (char c) const { return static_cast<char>(std::tolower(c)); }
+};
+
+class FIREBIRD_STORE : public STG::Store {
+public:
+ FIREBIRD_STORE();
+ ~FIREBIRD_STORE() override;
+
+ int GetUsersList(std::vector<std::string> * usersList) const override;
+ int AddUser(const std::string & login) const override;
+ int DelUser(const std::string & login) const override;
+ int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
+ int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
+ int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
+ int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
+ int WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message) const override;
+ int WriteUserConnect(const std::string & login, uint32_t ip) const override;
+ int WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & up,
+ const STG::DirTraff & down,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double freeMb,
+ const std::string & reason) const override;
+ int WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const override;
+
+ int AddMessage(STG::Message * msg, const std::string & login) const override;
+ int EditMessage(const STG::Message & msg, const std::string & login) const override;
+ int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
+ int DelMessage(uint64_t id, const std::string & login) const override;
+ int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
+
+ int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
+
+ int GetAdminsList(std::vector<std::string> * adminsList) const override;
+ int SaveAdmin(const STG::AdminConf & ac) const override;
+ int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
+ int AddAdmin(const std::string & login) const override;
+ int DelAdmin(const std::string & login) const override;
+
+ int GetTariffsList(std::vector<std::string> * tariffsList) const override;
+ int AddTariff(const std::string & name) const override;
+ int DelTariff(const std::string & name) const override;
+ int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
+ int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
+
+ int GetCorpsList(std::vector<std::string> * corpsList) const override;
+ int SaveCorp(const STG::CorpConf & cc) const override;
+ int RestoreCorp(STG::CorpConf * cc, const std::string & name) const override;
+ int AddCorp(const std::string & name) const override;
+ int DelCorp(const std::string & name) const override;
+
+ inline void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ inline const std::string & GetStrError() const override { return strError; }
+
+ inline const std::string & GetVersion() const override { return version; }
+
+ int GetServicesList(std::vector<std::string> * servicesList) const override;
+ int SaveService(const STG::ServiceConf & sc) const override;
+ int RestoreService(STG::ServiceConf * sc, const std::string & name) const override;
+ int AddService(const std::string & name) const override;
+ int DelService(const std::string & name) const override;
+
+private:
+ FIREBIRD_STORE(const FIREBIRD_STORE & rvalue);
+ FIREBIRD_STORE & operator=(const FIREBIRD_STORE & rvalue);
+
+ std::string version;
+ mutable std::string strError;
+ std::string db_server, db_database, db_user, db_password;
+ STG::ModuleSettings settings;
+ mutable IBPP::Database db;
+ mutable pthread_mutex_t mutex;
+ IBPP::TIL til;
+ IBPP::TLR tlr;
+ int schemaVersion;
+ STG::PluginLogger logger;
+
+ int SaveStat(const STG::UserStat & stat, const std::string & login, int year = 0, int month = 0) const;
+ int CheckVersion();
+};
+
+time_t ts2time_t(const IBPP::Timestamp & ts);
+void time_t2ts(time_t t, IBPP::Timestamp * ts);
+void ym2date(int year, int month, IBPP::Date * date);
+
+template <typename T>
+inline
+T Get(IBPP::Statement st, size_t pos)
+{
+ T value;
+ st->Get(pos, value);
+ return value;
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Administrators manipulation methods
+ *
+ * $Revision: 1.11 $
+ * $Date: 2008/12/04 17:10:06 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/admin_conf.h"
+#include "stg/blowfish.h"
+#include "stg/common.h"
+
+#include <string>
+#include <vector>
+
+#define adm_enc_passwd "cjeifY8m3"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+std::string login;
+
+try
+ {
+ tr->Start();
+ st->Execute("select login from tb_admins");
+ while (st->Fetch())
+ {
+ st->Get(1, login);
+ adminsList->push_back(login);
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveAdmin(const STG::AdminConf & ac) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+char encodedPass[2 * ADM_PASSWD_LEN + 2];
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+memset(cryptedPass, 0, ADM_PASSWD_LEN + 1);
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+ EncryptBlock(cryptedPass + 8 * i, adminPass + 8 * i, &ctx);
+
+cryptedPass[ADM_PASSWD_LEN] = 0;
+Encode12(encodedPass, cryptedPass, ADM_PASSWD_LEN);
+
+try
+ {
+ tr->Start();
+ st->Prepare("update tb_admins set passwd=?, \
+ chg_conf=?, \
+ chg_password=?, \
+ chg_stat=?, \
+ chg_cash=?, \
+ usr_add_del=?, \
+ chg_tariff=?, \
+ chg_admin=? \
+ where login=?");
+ st->Set(1, encodedPass);
+ st->Set(2, static_cast<int16_t>(ac.priv.userConf));
+ st->Set(3, static_cast<int16_t>(ac.priv.userPasswd));
+ st->Set(4, static_cast<int16_t>(ac.priv.userStat));
+ st->Set(5, static_cast<int16_t>(ac.priv.userCash));
+ st->Set(6, static_cast<int16_t>(ac.priv.userAddDel));
+ st->Set(7, static_cast<int16_t>(ac.priv.tariffChg));
+ st->Set(8, static_cast<int16_t>(ac.priv.adminChg));
+ st->Set(9, ac.login);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+try
+ {
+ tr->Start();
+ st->Prepare("select * from tb_admins where login = ?");
+ st->Set(1, login);
+ st->Execute();
+ if (st->Fetch())
+ {
+ st->Get(2, ac->login);
+ st->Get(3, ac->password);
+ st->Get(4, (int16_t &)ac->priv.userConf);
+ st->Get(5, (int16_t &)ac->priv.userPasswd);
+ st->Get(6, (int16_t &)ac->priv.userStat);
+ st->Get(7, (int16_t &)ac->priv.userCash);
+ st->Get(8, (int16_t &)ac->priv.userAddDel);
+ st->Get(9, (int16_t &)ac->priv.tariffChg);
+ st->Get(10, (int16_t &)ac->priv.adminChg);
+ }
+ else
+ {
+ strError = "Admin \"" + login + "\" not found in database";
+ printfd(__FILE__, "Admin '%s' not found in database\n", login.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+if (ac->password == "")
+ {
+ return 0;
+ }
+
+Decode21(cryptedPass, ac->password.c_str());
+InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+ {
+ DecryptBlock(adminPass + 8 * i, cryptedPass + 8 * i, &ctx);
+ }
+ac->password = adminPass;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddAdmin(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("insert into tb_admins(login, \
+ passwd, \
+ chg_conf, \
+ chg_password, \
+ chg_stat, \
+ chg_cash, \
+ usr_add_del, \
+ chg_tariff, \
+ chg_admin, \
+ chg_service, \
+ chg_corporation) \
+ values (?, '', 0, 0, 0, 0, 0, 0, 0, 0, 0)");
+ st->Set(1, login);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelAdmin(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("delete from tb_admins where login = ?");
+ st->Set(1, login);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Corporations manipulation methods
+ *
+ * $Revision: 1.5 $
+ * $Date: 2007/12/23 13:39:59 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/corp_conf.h"
+#include "stg/common.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetCorpsList(std::vector<std::string> * corpsList) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+std::string name;
+
+try
+ {
+ tr->Start();
+ st->Execute("select name from tb_corporations");
+ while (st->Fetch())
+ {
+ st->Get(1, name);
+ corpsList->push_back(name);
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveCorp(const STG::CorpConf & cc) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Execute("update tb_corporations set cash = ? where name = ?");
+ st->Set(1, cc.cash);
+ st->Set(2, cc.name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreCorp(STG::CorpConf * cc, const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select cash from tb_corporations where name = ?");
+ st->Set(1, name);
+ st->Execute();
+ if (st->Fetch())
+ {
+ st->Get(1, cc->cash);
+ }
+ else
+ {
+ strError = "Corporation \"" + name + "\" not found in database";
+ tr->Rollback();
+ printfd(__FILE__, "Corporation '%s' not found in database\n", name.c_str());
+ return -1;
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddCorp(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("insert into tb_corporations (name, cash), values (?, 0)");
+ st->Set(1, name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelCorp(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("delete from tb_corporations where name = ?");
+ st->Set(1, name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+
+/*
+ * Messages manipualtion methods
+ *
+ * $Revision: 1.10 $
+ * $Date: 2009/03/03 16:16:23 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/message.h"
+#include "stg/common.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddMessage(STG::Message * msg, const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_add_message(NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ st->Set(1, login);
+ st->Set(2, (int32_t)msg->header.ver);
+ st->Set(3, (int32_t)msg->header.type);
+ st->Set(4, (int32_t)msg->header.lastSendTime);
+ st->Set(5, (int32_t)msg->header.creationTime);
+ st->Set(6, (int32_t)msg->header.showTime);
+ st->Set(7, msg->header.repeat);
+ st->Set(8, (int32_t)msg->header.repeatPeriod);
+ st->Set(9, msg->text);
+ st->Execute();
+ st->Get(1, (int64_t &)msg->header.id);
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::EditMessage(const STG::Message & msg,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_add_message(?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ st->Set(1, (int64_t)msg.header.id);
+ st->Set(2, login);
+ st->Set(3, (int32_t)msg.header.ver);
+ st->Set(4, (int32_t)msg.header.type);
+ st->Set(5, (int32_t)msg.header.lastSendTime);
+ st->Set(6, (int32_t)msg.header.creationTime);
+ st->Set(7, (int32_t)msg.header.showTime);
+ st->Set(8, msg.header.repeat);
+ st->Set(9, (int32_t)msg.header.repeatPeriod);
+ st->Set(10, msg.text.c_str());
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetMessage(uint64_t id,
+ STG::Message * msg,
+ const std::string &) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select * from tb_messages where pk_message = ?");
+ st->Set(1, (int64_t)id);
+ st->Execute();
+ if (st->Fetch())
+ {
+ st->Get(1, (int64_t &)msg->header.id);
+ st->Get(3, (int32_t &)msg->header.ver);
+ st->Get(4, (int32_t &)msg->header.type);
+ st->Get(5, (int32_t &)msg->header.lastSendTime);
+ st->Get(6, (int32_t &)msg->header.creationTime);
+ st->Get(7, (int32_t &)msg->header.showTime);
+ st->Get(8, msg->header.repeat);
+ st->Get(9, (int32_t &)msg->header.repeatPeriod);
+ st->Get(10, msg->text);
+ }
+ else
+ {
+ strprintf(&strError, "Message with id = %d not found in database", id);
+ printfd(__FILE__, "Message with id - %d not found in database\n", id);
+ tr->Rollback();
+ return -1;
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelMessage(uint64_t id, const std::string &) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("delete from tb_messages where pk_message = ?");
+ st->Set(1, (int64_t)id);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+STG::Message::Header header;
+
+try
+ {
+ tr->Start();
+ st->Prepare("select pk_message, ver, msg_type, \
+ last_send_time, creation_time, \
+ show_time, repeat, repeat_period \
+ from tb_messages where \
+ fk_user = (select pk_user from tb_users where name = ?)");
+ st->Set(1, login);
+ st->Execute();
+ while (st->Fetch())
+ {
+ st->Get(1, (int64_t &)header.id);
+ st->Get(2, (int32_t &)header.ver);
+ st->Get(3, (int32_t &)header.type);
+ st->Get(4, (int32_t &)header.lastSendTime);
+ st->Get(5, (int32_t &)header.creationTime);
+ st->Get(6, (int32_t &)header.showTime);
+ st->Get(7, header.repeat);
+ st->Get(8, (int32_t &)header.repeatPeriod);
+ hdrsList->push_back(header);
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+
+/*
+ * Services manipulation methods
+ *
+ * $Revision: 1.6 $
+ * $Date: 2009/05/13 13:19:33 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/service_conf.h"
+#include "stg/common.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetServicesList(std::vector<std::string> * servicesList) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+std::string name;
+
+try
+ {
+ tr->Start();
+ st->Execute("select name from tb_services");
+ while (st->Fetch())
+ {
+ st->Get(1, name);
+ servicesList->push_back(name);
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveService(const STG::ServiceConf & sc) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("update tb_services set \
+ comments = ?, \
+ cost = ?, \
+ pay_day = ? \
+ where name = ?");
+ st->Set(1, sc.comment);
+ st->Set(2, sc.cost);
+ st->Set(3, static_cast<int16_t>(sc.payDay));
+ st->Set(4, sc.name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreService(STG::ServiceConf * sc,
+ const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select * from tb_services where name = ?");
+ st->Set(1, name);
+ st->Execute();
+ if (st->Fetch())
+ {
+ st->Get(3, sc->comment);
+ st->Get(4, sc->cost);
+ int16_t pd;
+ st->Get(5, pd);
+ sc->payDay = static_cast<uint8_t>(pd);
+ }
+ else
+ {
+ strError = "Service \"" + name + "\" not found in database";
+ printfd(__FILE__, "Service '%s' not found in database\n", name.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddService(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("insert into tb_services (name, comment, cost, pay_day) \
+ values (?, '', 0, 0)");
+ st->Set(1, name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelService(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_delete_service(?)");
+ st->Set(1, name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Tariffs manipulation methods
+ *
+ * $Revision: 1.5 $
+ * $Date: 2007/12/23 13:39:59 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/tariff.h"
+#include "stg/tariff_conf.h"
+#include "stg/common.h"
+
+#include <cmath>
+
+namespace
+{
+
+const int pt_mega = 1024 * 1024;
+
+}
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+std::string name;
+
+try
+ {
+ tr->Start();
+ st->Execute("select name from tb_tariffs");
+ while (st->Fetch())
+ {
+ st->Get(1, name);
+ tariffsList->push_back(name);
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddTariff(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_add_tariff(?, ?)");
+ st->Set(1, name);
+ st->Set(2, DIR_NUM);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelTariff(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_delete_tariff(?)");
+ st->Set(1, name);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveTariff(const STG::TariffData & td,
+ const std::string & tariffName) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select pk_tariff from tb_tariffs where name = ?");
+ st->Set(1, tariffName);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ tr->Rollback();
+ strprintf(&strError, "Tariff \"%s\" not found in database", tariffName.c_str());
+ printfd(__FILE__, "Tariff '%s' not found in database\n", tariffName.c_str());
+ return -1;
+ }
+ int32_t id;
+ st->Get(1, id);
+ st->Close();
+
+ std::string query = "update tb_tariffs set \
+ fee = ?, \
+ free = ?, \
+ passive_cost = ?, \
+ traff_type = ?";
+
+ if (schemaVersion > 0)
+ query += ", period = ?";
+ if (schemaVersion > 1)
+ query += ", change_policy = ?, \
+ change_policy_timeout = ?";
+
+ query += " where pk_tariff = ?";
+
+ unsigned num = 5;
+ st->Prepare(query);
+ st->Set(1, td.tariffConf.fee);
+ st->Set(2, td.tariffConf.free);
+ st->Set(3, td.tariffConf.passiveCost);
+ st->Set(4, td.tariffConf.traffType);
+
+ if (schemaVersion > 0)
+ {
+ st->Set(5, STG::Tariff::toString(td.tariffConf.period));
+ ++num;
+ }
+
+ if (schemaVersion > 1)
+ {
+ st->Set(6, STG::Tariff::toString(td.tariffConf.changePolicy));
+ IBPP::Timestamp policyTimeout;
+ time_t2ts(td.tariffConf.changePolicyTimeout, &policyTimeout);
+ st->Set(7, policyTimeout);
+ num += 2;
+ }
+
+ st->Set(num, id);
+ st->Execute();
+ st->Close();
+
+ IBPP::Time tb;
+ IBPP::Time te;
+
+ for(int i = 0; i < DIR_NUM; i++)
+ {
+
+ tb.SetTime(td.dirPrice[i].hDay, td.dirPrice[i].mDay, 0);
+ te.SetTime(td.dirPrice[i].hNight, td.dirPrice[i].mNight, 0);
+
+ double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
+ double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
+ double pna = 0;
+ double pnb = 0;
+
+ if (td.dirPrice[i].singlePrice)
+ {
+ pna = pda;
+ pnb = pdb;
+ }
+ else
+ {
+ pna = td.dirPrice[i].priceNightA;
+ pnb = td.dirPrice[i].priceNightB;
+ }
+
+ int threshold = 0;
+ if (td.dirPrice[i].noDiscount)
+ {
+ threshold = 0xffFFffFF;
+ }
+ else
+ {
+ threshold = td.dirPrice[i].threshold;
+ }
+
+ st->Prepare("update tb_tariffs_params set \
+ price_day_a = ?, \
+ price_day_b = ?, \
+ price_night_a = ?, \
+ price_night_b = ?, \
+ threshold = ?, \
+ time_day_begins = ?, \
+ time_day_ends = ? \
+ where fk_tariff = ? and dir_num = ?");
+ st->Set(1, pda);
+ st->Set(2, pdb);
+ st->Set(3, pna);
+ st->Set(4, pnb);
+ st->Set(5, threshold);
+ st->Set(6, tb);
+ st->Set(7, te);
+ st->Set(8, id);
+ st->Set(9, i);
+ st->Execute();
+ st->Close();
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreTariff(STG::TariffData * td,
+ const std::string & tariffName) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+
+td->tariffConf.name = tariffName;
+
+try
+ {
+ tr->Start();
+ st->Prepare("select * from tb_tariffs where name = ?"); // TODO: explicit field order!
+ st->Set(1, tariffName);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ strError = "Tariff \"" + tariffName + "\" not found in database";
+ printfd(__FILE__, "Tariff '%s' not found in database\n", tariffName.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ int32_t id;
+ st->Get(1, id);
+ st->Get(3, td->tariffConf.fee);
+ st->Get(4, td->tariffConf.free);
+ st->Get(5, td->tariffConf.passiveCost);
+ td->tariffConf.traffType = STG::Tariff::fromInt(Get<int>(st, 6));
+ if (schemaVersion > 0)
+ td->tariffConf.period = STG::Tariff::parsePeriod(Get<std::string>(st, 7));
+ if (schemaVersion > 1)
+ {
+ td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(Get<std::string>(st, 8));
+ td->tariffConf.changePolicyTimeout = ts2time_t(Get<IBPP::Timestamp>(st, 9));
+ }
+ st->Close();
+ st->Prepare("select * from tb_tariffs_params where fk_tariff = ?");
+ st->Set(1, id);
+ st->Execute();
+ int i = 0;
+ while (st->Fetch())
+ {
+ i++;
+ if (i > DIR_NUM)
+ {
+ strError = "Too mach params for tariff \"" + tariffName + "\"";
+ printfd(__FILE__, "Too mach params for tariff '%s'\n", tariffName.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ int16_t dir;
+ st->Get(3, dir);
+ st->Get(4, td->dirPrice[dir].priceDayA);
+ td->dirPrice[dir].priceDayA /= 1024*1024;
+ st->Get(5, td->dirPrice[dir].priceDayB);
+ td->dirPrice[dir].priceDayB /= 1024*1024;
+ st->Get(6, td->dirPrice[dir].priceNightA);
+ td->dirPrice[dir].priceNightA /= 1024*1024;
+ st->Get(7, td->dirPrice[dir].priceNightB);
+ td->dirPrice[dir].priceNightB /= 1024*1024;
+ st->Get(8, td->dirPrice[dir].threshold);
+ if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
+ std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
+ {
+ td->dirPrice[dir].singlePrice = true;
+ }
+ else
+ {
+ td->dirPrice[dir].singlePrice = false;
+ }
+ if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
+ {
+ td->dirPrice[dir].noDiscount = true;
+ }
+ else
+ {
+
+ td->dirPrice[dir].noDiscount = false;
+ }
+ IBPP::Time tb;
+ st->Get(9, tb);
+ IBPP::Time te;
+ st->Get(10, te);
+ int h, m, s;
+ tb.GetTime(h, m, s);
+ td->dirPrice[dir].hDay = h;
+ td->dirPrice[dir].mDay = m;
+ te.GetTime(h, m, s);
+ td->dirPrice[dir].hNight = h;
+ td->dirPrice[dir].mNight = m;
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * User manipulation methods
+ *
+ * $Revision: 1.19 $
+ * $Date: 2010/01/19 11:07:25 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/user_traff.h"
+#include "stg/user_ips.h"
+#include "stg/const.h"
+#include "stg/common.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetUsersList(std::vector<std::string> * usersList) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+std::string name;
+
+try
+ {
+ tr->Start();
+ st->Execute("select name from tb_users");
+ while (st->Fetch())
+ {
+ st->Get(1, name);
+ usersList->push_back(name);
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddUser(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_add_user(?, ?)");
+ st->Set(1, name);
+ st->Set(2, DIR_NUM);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelUser(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_delete_user(?)");
+ st->Set(1, login);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveUserStat(const STG::UserStat & stat,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+return SaveStat(stat, login);
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveStat(const STG::UserStat & stat,
+ const std::string & login,
+ int year,
+ int month) const
+{
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select pk_user from tb_users where name = ?");
+ st->Set(1, login);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ strError = "User \"" + login + "\" not found in database";
+ printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ int32_t uid = Get<int32_t>(st, 1);
+ st->Close();
+ st->Prepare("select first 1 pk_stat from tb_stats where fk_user = ? order by stats_date desc");
+ st->Set(1, uid);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ tr->Rollback();
+ strError = "No stat info for user \"" + login + "\"";
+ printfd(__FILE__, "No stat info for user '%s'\n", login.c_str());
+ return -1;
+ }
+ int32_t sid;
+ st->Get(1, sid);
+ st->Close();
+
+ IBPP::Timestamp actTime;
+ time_t2ts(stat.lastActivityTime, &actTime);
+ IBPP::Timestamp addTime;
+ time_t2ts(stat.lastCashAddTime, &addTime);
+ IBPP::Date dt;
+ if (year != 0)
+ ym2date(year, month, &dt);
+ else
+ dt.Today();
+
+ st->Prepare("update tb_stats set \
+ cash = ?, \
+ free_mb = ?, \
+ last_activity_time = ?, \
+ last_cash_add = ?, \
+ last_cash_add_time = ?, \
+ passive_time = ?, \
+ stats_date = ? \
+ where pk_stat = ?");
+
+ st->Set(1, stat.cash);
+ st->Set(2, stat.freeMb);
+ st->Set(3, actTime);
+ st->Set(4, stat.lastCashAdd);
+ st->Set(5, addTime);
+ st->Set(6, (int32_t)stat.passiveTime);
+ st->Set(7, dt);
+ st->Set(8, sid);
+
+ st->Execute();
+ st->Close();
+
+ for(int i = 0; i < DIR_NUM; i++)
+ {
+ st->Prepare("update tb_stats_traffic set \
+ upload = ?, \
+ download = ? \
+ where fk_stat = ? and dir_num = ?");
+ st->Set(1, (int64_t)stat.monthUp[i]);
+ st->Set(2, (int64_t)stat.monthDown[i]);
+ st->Set(3, sid);
+ st->Set(4, i);
+ st->Execute();
+ st->Close();
+ }
+
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveUserConf(const STG::UserConf & conf,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select pk_user from tb_users where name = ?");
+ st->Set(1, login);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ strError = "User \"" + login + "\" not found in database";
+ printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ int32_t uid;
+ st->Get(1, uid);
+ st->Close();
+
+ IBPP::Timestamp creditExpire;
+ time_t2ts(conf.creditExpire, &creditExpire);
+
+ st->Prepare("update tb_users set \
+ address = ?, \
+ always_online = ?, \
+ credit = ?, \
+ credit_expire = ?, \
+ disabled = ?, \
+ disabled_detail_stat = ?, \
+ email = ?, \
+ grp = ?, \
+ note = ?, \
+ passive = ?, \
+ passwd = ?, \
+ phone = ?, \
+ fk_tariff = (select pk_tariff from tb_tariffs \
+ where name = ?), \
+ fk_tariff_change = (select pk_tariff from tb_tariffs \
+ where name = ?), \
+ fk_corporation = (select pk_corporation from tb_corporations \
+ where name = ?), \
+ real_name = ? \
+ where pk_user = ?");
+
+ st->Set(1, conf.address);
+ st->Set(2, (bool)conf.alwaysOnline);
+ st->Set(3, conf.credit);
+ st->Set(4, creditExpire);
+ st->Set(5, (bool)conf.disabled);
+ st->Set(6, (bool)conf.disabledDetailStat);
+ st->Set(7, conf.email);
+ st->Set(8, conf.group);
+ st->Set(9, conf.note);
+ st->Set(10, (bool)conf.passive);
+ st->Set(11, conf.password);
+ st->Set(12, conf.phone);
+ st->Set(13, conf.tariffName);
+ st->Set(14, conf.nextTariff);
+ st->Set(15, conf.corp);
+ st->Set(16, conf.realName);
+ st->Set(17, uid);
+
+ st->Execute();
+ st->Close();
+
+ st->Prepare("delete from tb_users_services where fk_user = ?");
+ st->Set(1, uid);
+ st->Execute();
+ st->Close();
+
+ st->Prepare("insert into tb_users_services (fk_user, fk_service) \
+ values (?, (select pk_service from tb_services \
+ where name = ?))");
+ for(std::vector<std::string>::const_iterator it = conf.services.begin(); it != conf.services.end(); ++it)
+ {
+ st->Set(1, uid);
+ st->Set(2, *it);
+ st->Execute();
+ }
+ st->Close();
+
+ st->Prepare("delete from tb_users_data where fk_user = ?");
+ st->Set(1, uid);
+ st->Execute();
+ st->Close();
+
+ int i = 0;
+ st->Prepare("insert into tb_users_data (fk_user, data, num) values (?, ?, ?)");
+ for (std::vector<std::string>::const_iterator it = conf.userdata.begin(); it != conf.userdata.end(); ++it)
+ {
+ st->Set(1, uid);
+ st->Set(2, *it);
+ st->Set(3, i++);
+ st->Execute();
+ }
+ st->Close();
+
+ st->Prepare("delete from tb_allowed_ip where fk_user = ?");
+ st->Set(1, uid);
+ st->Execute();
+
+ st->Prepare("insert into tb_allowed_ip (fk_user, ip, mask) values (?, ?, ?)");
+ for(size_t i = 0; i < conf.ips.count(); i++)
+ {
+ st->Set(1, uid);
+ st->Set(2, (int32_t)conf.ips[i].ip);
+ st->Set(3, (int32_t)conf.ips[i].mask);
+ st->Execute();
+ }
+ tr->Commit();
+ }
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreUserStat(STG::UserStat * stat,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select pk_user from tb_users where name = ?");
+ st->Set(1, login);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ strError = "User \"" + login + "\" not found in database";
+ printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
+ return -1;
+ }
+ int32_t uid;
+ st->Get(1, uid);
+ st->Close();
+
+ st->Prepare("select first 1 pk_stat, cash, free_mb, last_activity_time, \
+ last_cash_add, last_cash_add_time, passive_time from tb_stats \
+ where fk_user = ? order by stats_date desc");
+ st->Set(1, uid);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ strError = "No stat info for user \"" + login + "\"";
+ printfd(__FILE__, "No stat info for user '%s'\n", login.c_str());
+ tr->Rollback();
+ return -1;
+ }
+
+ int32_t sid;
+ st->Get(1, sid);
+ st->Get(2, stat->cash);
+ st->Get(3, stat->freeMb);
+ IBPP::Timestamp actTime;
+ st->Get(4, actTime);
+ st->Get(5, stat->lastCashAdd);
+ IBPP::Timestamp addTime;
+ st->Get(6, addTime);
+ int32_t passiveTime;
+ st->Get(7, passiveTime);
+
+ stat->passiveTime = passiveTime;
+
+ stat->lastActivityTime = ts2time_t(actTime);
+
+ stat->lastCashAddTime = ts2time_t(addTime);
+
+ st->Close();
+ st->Prepare("select * from tb_stats_traffic where fk_stat = ?");
+ st->Set(1, sid);
+ st->Execute();
+ for(int i = 0; i < DIR_NUM; i++)
+ {
+ if (st->Fetch())
+ {
+ int dir;
+ st->Get(3, dir);
+ st->Get(5, (int64_t &)stat->monthUp[dir]);
+ st->Get(4, (int64_t &)stat->monthDown[dir]);
+ }
+ else
+ {
+ break;
+ }
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreUserConf(STG::UserConf * conf,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+ {
+ tr->Start();
+ st->Prepare("select tb_users.pk_user, tb_users.address, tb_users.always_online, \
+ tb_users.credit, tb_users.credit_expire, tb_users.disabled, \
+ tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, \
+ tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, \
+ tb_users.real_name, tf1.name, tf2.name, tb_corporations.name \
+ from tb_users left join tb_tariffs tf1 \
+ on tf1.pk_tariff = tb_users.fk_tariff \
+ left join tb_tariffs tf2 \
+ on tf2.pk_tariff = tb_users.fk_tariff_change \
+ left join tb_corporations \
+ on tb_corporations.pk_corporation = tb_users.fk_corporation \
+ where tb_users.name = ?");
+ st->Set(1, login);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ strError = "User \"" + login + "\" not found in database";
+ printfd(__FILE__, "User '%s' not found in database", login.c_str());
+ tr->Rollback();
+ return -1;
+ }
+ int32_t uid;
+ st->Get(1, uid);
+ // Getting base config
+ st->Get(2, conf->address);
+ bool test;
+ st->Get(3, test);
+ conf->alwaysOnline = test;
+ st->Get(4, conf->credit);
+ IBPP::Timestamp timestamp;
+ st->Get(5, timestamp);
+
+ conf->creditExpire = ts2time_t(timestamp);
+
+ st->Get(6, test);
+ conf->disabled = test;
+ st->Get(7, test);
+ conf->disabledDetailStat = test;
+ st->Get(8, conf->email);
+ st->Get(9, conf->group);
+ st->Get(10, conf->note);
+ st->Get(11, test);
+ conf->passive = test;
+ st->Get(12, conf->password);
+ st->Get(13, conf->phone);
+ st->Get(14, conf->realName);
+ st->Get(15, conf->tariffName);
+ st->Get(16, conf->nextTariff);
+ st->Get(17, conf->corp);
+
+ if (conf->tariffName == "")
+ conf->tariffName = NO_TARIFF_NAME;
+ if (conf->corp == "")
+ conf->corp = NO_CORP_NAME;
+
+ // Services
+ st->Close();
+ st->Prepare("select name from tb_services \
+ where pk_service in \
+ (select fk_service from tb_users_services \
+ where fk_user = ?)");
+ st->Set(1, uid);
+ st->Execute();
+ while (st->Fetch())
+ {
+ std::string name;
+ st->Get(1, name);
+ conf->services.push_back(name);
+ }
+
+ // User data
+ st->Close();
+ st->Prepare("select data, num from tb_users_data where fk_user = ? order by num");
+ st->Set(1, uid);
+ st->Execute();
+ while (st->Fetch())
+ {
+ int i;
+ st->Get(2, i);
+ st->Get(1, conf->userdata[i]);
+ }
+
+ // User IPs
+ st->Close();
+ st->Prepare("select ip, mask from tb_allowed_ip \
+ where fk_user = ?");
+ st->Set(1, uid);
+ st->Execute();
+ STG::UserIPs ips;
+ while (st->Fetch())
+ {
+ STG::IPMask im;
+ st->Get(1, (int32_t &)im.ip);
+ st->Get(2, (int32_t &)im.mask);
+ ips.add(im);
+ }
+ conf->ips = ips;
+
+ tr->Commit();
+ }
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message = "") const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+IBPP::Timestamp now;
+now.Now();
+
+std::string temp = ""; // Composed message for log
+
+try
+ {
+ tr->Start();
+ temp += "Admin \"" + admLogin + "\", ";
+ temp += inet_ntostring(admIP);
+ temp += ": ";
+ temp = temp + message;
+ //----------------------------------------------------------------------------------------
+ // Checking and inserting parameters in params table
+ st->Prepare("select pk_parameter from tb_parameters where name = ?");
+ st->Set(1, paramName);
+ st->Execute();
+ if (!st->Fetch())
+ {
+ st->Close();
+ st->Prepare("insert into tb_parameters (name) values (?)");
+ st->Set(1, paramName);
+ st->Execute();
+ }
+ st->Close();
+ //----------------------------------------------------------------------------------------
+ st->Prepare("insert into tb_params_log \
+ (fk_user, fk_parameter, event_time, from_val, to_val, comment) \
+ values ((select pk_user from tb_users \
+ where name = ?), \
+ (select pk_parameter from tb_parameters \
+ where name = ?), \
+ ?, ?, ?, ?)");
+ st->Set(1, login);
+ st->Set(2, paramName);
+ st->Set(3, now);
+ st->Set(4, oldValue);
+ st->Set(5, newValue);
+ st->Set(6, temp);
+ st->Execute();
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+IBPP::Timestamp now;
+now.Now();
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_append_session_log(?, ?, 'c', ?)");
+ st->Set(1, login);
+ st->Set(2, now);
+ st->Set(3, (int32_t)ip);
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & up,
+ const STG::DirTraff & down,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double /*cash*/,
+ double /*freeMb*/,
+ const std::string & /*reason*/) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+IBPP::Timestamp now;
+now.Now();
+
+try
+ {
+ tr->Start();
+ st->Prepare("execute procedure sp_append_session_log(?, ?, 'd', 0)");
+ st->Set(1, login);
+ st->Set(2, now);
+ st->Execute();
+ int32_t id;
+ st->Get(1, id);
+ st->Prepare("insert into tb_sessions_data \
+ (fk_session_log, dir_num, session_upload, \
+ session_download, month_upload, month_download) \
+ values (?, ?, ?, ?, ?, ?)");
+ for(int i = 0; i < DIR_NUM; i++)
+ {
+ st->Set(1, id);
+ st->Set(2, i);
+ st->Set(3, (int64_t)sessionUp[i]);
+ st->Set(4, (int64_t)sessionDown[i]);
+ st->Set(5, (int64_t)up[i]);
+ st->Set(6, (int64_t)down[i]);
+ st->Execute();
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+IBPP::Timestamp statTime, now;
+now.Now();
+
+time_t2ts(lastStat, &statTime);
+
+try
+ {
+ tr->Start();
+ STG::TraffStat::const_iterator it;
+ it = statTree.begin();
+ st->Prepare("insert into tb_detail_stats \
+ (till_time, from_time, fk_user, dir_num, \
+ ip, download, upload, cost) \
+ values (?, ?, (select pk_user from tb_users \
+ where name = ?), \
+ ?, ?, ?, ?, ?)");
+ while (it != statTree.end())
+ {
+ st->Set(1, now);
+ st->Set(2, statTime);
+ st->Set(3, login);
+ st->Set(4, it->first.dir);
+ st->Set(5, (int32_t)it->first.ip);
+ st->Set(6, (int64_t)it->second.down);
+ st->Set(7, (int64_t)it->second.up);
+ st->Set(8, it->second.cash);
+ st->Execute();
+ ++it;
+ }
+ tr->Commit();
+ }
+
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+IBPP::Timestamp now;
+IBPP::Date nowDate;
+nowDate.Today();
+now.Now();
+
+if (SaveStat(stat, login, year, month))
+ {
+ return -1;
+ }
+
+try
+ {
+ tr->Start();
+
+ st->Prepare("execute procedure sp_add_stat(?, 0, 0, ?, 0, ?, 0, ?)");
+ st->Set(1, login);
+ st->Set(2, now);
+ st->Set(3, now);
+ st->Set(4, nowDate);
+
+ st->Execute();
+ int32_t id;
+ st->Get(1, id);
+ st->Close();
+
+ st->Prepare("insert into tb_stats_traffic \
+ (fk_stat, dir_num, upload, download) \
+ values (?, ?, 0, 0)");
+
+ for(int i = 0; i < DIR_NUM; i++)
+ {
+ st->Set(1, id);
+ st->Set(2, i);
+ st->Execute();
+ }
+
+ tr->Commit();
+ }
+catch (IBPP::Exception & ex)
+ {
+ tr->Rollback();
+ strError = "IBPP exception";
+ printfd(__FILE__, ex.what());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Vairous utility methods
+ *
+ * $Revision: 1.8 $
+ * $Date: 2010/03/04 12:20:32 $
+ *
+ */
+
+#include "firebird_store.h"
+
+#include "stg/ibpp.h"
+#include "stg/common.h"
+
+#include <cstdio>
+
+//-----------------------------------------------------------------------------
+time_t ts2time_t(const IBPP::Timestamp & ts)
+{
+ char buf[32];
+ int year, month, day, hour, min, sec;
+ struct tm time_tm;
+
+ memset(&time_tm, 0, sizeof(time_tm));
+ ts.GetDate(year, month, day);
+ ts.GetTime(hour, min, sec);
+ if (year < 1990)
+ return 0;
+ sprintf(buf, "%d-%d-%d %d:%d:%d", year, month, day, hour, min, sec);
+ stg_strptime(buf, "%Y-%m-%d %H:%M:%S", &time_tm);
+
+ return mktime(&time_tm);
+}
+//-----------------------------------------------------------------------------
+void time_t2ts(time_t t, IBPP::Timestamp * ts)
+{
+ struct tm res;
+
+ localtime_r(&t, &res); // Reenterable
+
+ *ts = IBPP::Timestamp(res.tm_year + 1900, res.tm_mon + 1, res.tm_mday, res.tm_hour, res.tm_min, res.tm_sec);
+}
+//-----------------------------------------------------------------------------
+void ym2date(int year, int month, IBPP::Date * date)
+{
+ date->SetDate(year + 1900, month + 1, 1);
+ date->EndOfMonth();
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+#include "mysql_store.h"
+
+#include "stg/common.h"
+#include "stg/user_ips.h"
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/admin_conf.h"
+#include "stg/tariff_conf.h"
+#include "stg/blowfish.h"
+#include "stg/logger.h"
+
+#include <algorithm>
+#include <sys/time.h>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+
+#include <mysql/errmsg.h>
+
+#define adm_enc_passwd "cjeifY8m3"
+
+namespace
+{
+char qbuf[4096];
+
+const int pt_mega = 1024 * 1024;
+const std::string badSyms = "'`";
+const char repSym = '\"';
+const int RepitTimes = 3;
+
+template <typename T>
+int GetInt(const std::string & str, T * val, T defaultVal = T())
+{
+ char *res;
+
+ *val = static_cast<T>(strtoll(str.c_str(), &res, 10));
+
+ if (*res != 0)
+ {
+ *val = defaultVal; //Error!
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int GetDouble(const std::string & str, double * val, double defaultVal)
+{
+ char *res;
+
+ *val = strtod(str.c_str(), &res);
+
+ if (*res != 0)
+ {
+ *val = defaultVal; //Error!
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int GetTime(const std::string & str, time_t * val, time_t defaultVal)
+{
+ char *res;
+
+ *val = strtol(str.c_str(), &res, 10);
+
+ if (*res != 0)
+ {
+ *val = defaultVal; //Error!
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+std::string ReplaceStr(std::string source, const std::string & symlist, const char chgsym)
+{
+ std::string::size_type pos=0;
+
+ while( (pos = source.find_first_of(symlist,pos)) != std::string::npos)
+ source.replace(pos, 1,1, chgsym);
+
+ return source;
+}
+
+int GetULongLongInt(const std::string & str, uint64_t * val, uint64_t defaultVal)
+{
+ char *res;
+
+ *val = strtoull(str.c_str(), &res, 10);
+
+ if (*res != 0)
+ {
+ *val = defaultVal; //Error!
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+}
+
+extern "C" STG::Store* GetStore()
+{
+ static MYSQL_STORE plugin;
+ return &plugin;
+}
+//-----------------------------------------------------------------------------
+MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
+ : settings(NULL)
+{
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE_SETTINGS::ParseParam(const std::vector<STG::ParamValue> & moduleParams,
+ const std::string & name, std::string & result)
+{
+STG::ParamValue pv;
+pv.param = name;
+std::vector<STG::ParamValue>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end() || pvi->value.empty())
+ {
+ errorStr = "Parameter \'" + name + "\' not found.";
+ return -1;
+ }
+
+result = pvi->value[0];
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
+{
+if (ParseParam(s.moduleParams, "user", dbUser) < 0 &&
+ ParseParam(s.moduleParams, "dbuser", dbUser) < 0)
+ return -1;
+if (ParseParam(s.moduleParams, "password", dbPass) < 0 &&
+ ParseParam(s.moduleParams, "rootdbpass", dbPass) < 0)
+ return -1;
+if (ParseParam(s.moduleParams, "database", dbName) < 0 &&
+ ParseParam(s.moduleParams, "dbname", dbName) < 0)
+ return -1;
+if (ParseParam(s.moduleParams, "server", dbHost) < 0 &&
+ ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
+ return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+MYSQL_STORE::MYSQL_STORE()
+ : version("mysql_store v.0.67"),
+ schemaVersion(0),
+ logger(STG::PluginLogger::get("store_mysql"))
+{
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
+{
+ int ret;
+
+ if( (ret = mysql_query(sock,sQuery)) )
+ {
+ for(int i=0; i<RepitTimes; i++)
+ {
+ if( (ret = mysql_query(sock,sQuery)) )
+ ;//need to send error result
+ else
+ return 0;
+ }
+ }
+
+ return ret;
+}
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::ParseSettings()
+{
+int ret = storeSettings.ParseSettings(settings);
+MYSQL mysql;
+mysql_init(&mysql);
+if (ret)
+ errorStr = storeSettings.GetStrError();
+else
+{
+ if(storeSettings.GetDBPassword().length() == 0)
+ {
+ errorStr = "Database password must be not empty. Please read Manual.";
+ return -1;
+ }
+ MYSQL * sock;
+ if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
+ storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
+ 0,0,NULL,0)))
+ {
+ errorStr = "Couldn't connect to mysql engine! With error:\n";
+ errorStr += mysql_error(&mysql);
+ mysql_close(sock);
+ ret = -1;
+ }
+ else
+ {
+ if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
+ {
+ std::string res = "CREATE DATABASE " + storeSettings.GetDBName();
+
+ if(MysqlQuery(res.c_str(),sock))
+ {
+ errorStr = "Couldn't create database! With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ ret = -1;
+ }
+ else
+ {
+ if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
+ {
+ errorStr = "Couldn't select database! With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ ret = -1;
+ }
+ else
+ ret = CheckAllTables(sock);
+ }
+ }
+ else
+ {
+ ret = CheckAllTables(sock);
+ }
+ if (!ret)
+ {
+ logger("MYSQL_STORE: Current DB schema version: %d", schemaVersion);
+ MakeUpdates(sock);
+ }
+ mysql_close(sock);
+ }
+}
+return ret;
+}
+//-----------------------------------------------------------------------------
+bool MYSQL_STORE::IsTablePresent(const std::string & str,MYSQL * sock)
+{
+MYSQL_RES* result;
+
+if (!(result=mysql_list_tables(sock,str.c_str() )))
+{
+ errorStr = "Couldn't get tables list With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+my_ulonglong num_rows = mysql_num_rows(result);
+
+if(result)
+ mysql_free_result(result);
+
+return num_rows == 1;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::CheckAllTables(MYSQL * sock)
+{
+//info-------------------------------------------------------------------------
+if(!IsTablePresent("info",sock))
+{
+ sprintf(qbuf,"CREATE TABLE info (version INTEGER NOT NULL)");
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't create info table With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+
+ sprintf(qbuf,"INSERT INTO info SET version=0");
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't write default version. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+ schemaVersion = 0;
+}
+else
+{
+ std::vector<std::string> info;
+ if (GetAllParams(&info, "info", "version"))
+ schemaVersion = 0;
+ else
+ {
+ if (info.empty())
+ schemaVersion = 0;
+ else
+ GetInt(info.front(), &schemaVersion, 0);
+ }
+}
+//admins-----------------------------------------------------------------------
+if(!IsTablePresent("admins",sock))
+{
+ sprintf(qbuf,"CREATE TABLE admins (login VARCHAR(40) DEFAULT '' PRIMARY KEY,"\
+ "password VARCHAR(150) DEFAULT '*',ChgConf TINYINT DEFAULT 0,"\
+ "ChgPassword TINYINT DEFAULT 0,ChgStat TINYINT DEFAULT 0,"\
+ "ChgCash TINYINT DEFAULT 0,UsrAddDel TINYINT DEFAULT 0,"\
+ "ChgTariff TINYINT DEFAULT 0,ChgAdmin TINYINT DEFAULT 0)");
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't create admin table list With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+
+ sprintf(qbuf,"INSERT INTO admins SET login='admin',"\
+ "password='geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa',"\
+ "ChgConf=1,ChgPassword=1,ChgStat=1,ChgCash=1,UsrAddDel=1,ChgTariff=1,ChgAdmin=1");
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't create default admin. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+}
+
+//tariffs-----------------------------------------------------------------------
+std::string param, res;
+if(!IsTablePresent("tariffs",sock))
+{
+ res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
+
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " PriceDayA%d DOUBLE DEFAULT 0.0,", i);
+ res += param;
+
+ strprintf(¶m, " PriceDayB%d DOUBLE DEFAULT 0.0,", i);
+ res += param;
+
+ strprintf(¶m, " PriceNightA%d DOUBLE DEFAULT 0.0,", i);
+ res += param;
+
+ strprintf(¶m, " PriceNightB%d DOUBLE DEFAULT 0.0,", i);
+ res += param;
+
+ strprintf(¶m, " Threshold%d INT DEFAULT 0,", i);
+ res += param;
+
+ strprintf(¶m, " Time%d VARCHAR(15) DEFAULT '0:0-0:0',", i);
+ res += param;
+
+ strprintf(¶m, " NoDiscount%d INT DEFAULT 0,", i);
+ res += param;
+
+ strprintf(¶m, " SinglePrice%d INT DEFAULT 0,", i);
+ res += param;
+ }
+
+ res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"
+ "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '',"
+ "period VARCHAR(32) NOT NULL DEFAULT 'month',"
+ "change_policy VARCHAR(32) NOT NULL DEFAULT 'allow',"
+ "change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0)";
+
+ if(MysqlQuery(res.c_str(),sock))
+ {
+ errorStr = "Couldn't create tariffs table list With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+
+ res = "INSERT INTO tariffs SET name='tariff',";
+
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " NoDiscount%d=1,", i);
+ res += param;
+
+ strprintf(¶m, " Threshold%d=0,", i);
+ res += param;
+
+ strprintf(¶m, " Time%d='0:0-0:0',", i);
+ res += param;
+
+ if(i != 0 && i != 1)
+ {
+ strprintf(¶m, " SinglePrice%d=0,", i);
+ res += param;
+ }
+
+ if(i != 1)
+ {
+ strprintf(¶m, " PriceDayA%d=0.0,", i);
+ res += param;
+ }
+ if(i != 1)
+ {
+ strprintf(¶m, " PriceDayB%d=0.0,", i);
+ res += param;
+ }
+
+ if(i != 0)
+ {
+ strprintf(¶m, " PriceNightA%d=0.0,", i);
+ res += param;
+ }
+ if(i != 0)
+ {
+ strprintf(¶m, " PriceNightB%d=0.0,", i);
+ res += param;
+ }
+ }
+
+ res += "PassiveCost=0.0, Fee=10.0, Free=0,"\
+ "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\
+ "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month',"\
+ "change_policy='allow', change_policy_timeout=0";
+
+ if(MysqlQuery(res.c_str(),sock))
+ {
+ errorStr = "Couldn't create default tariff. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+
+ sprintf(qbuf,"UPDATE info SET version=1");
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't write default version. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+ schemaVersion = 2;
+}
+
+//users-----------------------------------------------------------------------
+if(!IsTablePresent("users",sock))
+{
+ res = "CREATE TABLE users (login VARCHAR(50) NOT NULL DEFAULT '' PRIMARY KEY, Password VARCHAR(150) NOT NULL DEFAULT '*',"\
+ "Passive INT(3) DEFAULT 0,Down INT(3) DEFAULT 0,DisabledDetailStat INT(3) DEFAULT 0,AlwaysOnline INT(3) DEFAULT 0,Tariff VARCHAR(40) NOT NULL DEFAULT '',"\
+ "Address VARCHAR(254) NOT NULL DEFAULT '',Phone VARCHAR(128) NOT NULL DEFAULT '',Email VARCHAR(50) NOT NULL DEFAULT '',"\
+ "Note TEXT NOT NULL,RealName VARCHAR(254) NOT NULL DEFAULT '',StgGroup VARCHAR(40) NOT NULL DEFAULT '',"\
+ "Credit DOUBLE DEFAULT 0, TariffChange VARCHAR(40) NOT NULL DEFAULT '',";
+
+ for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ strprintf(¶m, " Userdata%d VARCHAR(254) NOT NULL,", i);
+ res += param;
+ }
+
+ param = " CreditExpire INT(11) DEFAULT 0,";
+ res += param;
+
+ strprintf(¶m, " IP VARCHAR(254) DEFAULT '*',");
+ res += param;
+
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " D%d BIGINT(30) DEFAULT 0,", i);
+ res += param;
+
+ strprintf(¶m, " U%d BIGINT(30) DEFAULT 0,", i);
+ res += param;
+ }
+
+ strprintf(¶m, "Cash DOUBLE DEFAULT 0,FreeMb DOUBLE DEFAULT 0,LastCashAdd DOUBLE DEFAULT 0,"\
+ "LastCashAddTime INT(11) DEFAULT 0,PassiveTime INT(11) DEFAULT 0,LastActivityTime INT(11) DEFAULT 0,"\
+ "NAS VARCHAR(17) NOT NULL, INDEX (AlwaysOnline), INDEX (IP), INDEX (Address),"\
+ " INDEX (Tariff),INDEX (Phone),INDEX (Email),INDEX (RealName))");
+ res += param;
+
+ if(MysqlQuery(res.c_str(),sock))
+ {
+ errorStr = "Couldn't create users table list With error:\n";
+ errorStr += mysql_error(sock);
+ errorStr += "\n\n" + res;
+ mysql_close(sock);
+ return -1;
+ }
+
+ res = "INSERT INTO users SET login='test',Address='',AlwaysOnline=0,"\
+ "Credit=0.0,CreditExpire=0,Down=0,Email='',DisabledDetailStat=0,"\
+ "StgGroup='',IP='192.168.1.1',Note='',Passive=0,Password='123456',"\
+ "Phone='', RealName='',Tariff='tariff',TariffChange='',NAS='',";
+
+ for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ strprintf(¶m, " Userdata%d='',", i);
+ res += param;
+ }
+
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " D%d=0,", i);
+ res += param;
+
+ strprintf(¶m, " U%d=0,", i);
+ res += param;
+ }
+
+ res += "Cash=10.0,FreeMb=0.0,LastActivityTime=0,LastCashAdd=0,"\
+ "LastCashAddTime=0, PassiveTime=0";
+
+ if(MysqlQuery(res.c_str(),sock))
+ {
+ errorStr = "Couldn't create default user. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+}
+/*
+//logs-----------------------------------------------------------------------
+if(!IsTablePresent("logs"))
+{
+ sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
+
+ if(MysqlQuery(qbuf))
+ {
+ errorStr = "Couldn't create admin table list With error:\n";
+ errorStr += mysql_error(sock);
+ return -1;
+ }
+}
+*/
+//messages---------------------------------------------------------------------
+if(!IsTablePresent("messages",sock))
+{
+ sprintf(qbuf,"CREATE TABLE messages (login VARCHAR(40) DEFAULT '', id BIGINT, "\
+ "type INT, lastSendTime INT, creationTime INT, showTime INT,"\
+ "stgRepeat INT, repeatPeriod INT, text TEXT)");
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't create messages table. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+}
+
+//month_stat-------------------------------------------------------------------
+if(!IsTablePresent("stat",sock))
+{
+ res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
+
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " U%d BIGINT,", i);
+ res += param;
+
+ strprintf(¶m, " D%d BIGINT,", i);
+ res += param;
+ }
+
+ res += " cash DOUBLE, INDEX (login))";
+
+ if(MysqlQuery(res.c_str(),sock))
+ {
+ errorStr = "Couldn't create stat table. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::MakeUpdates(MYSQL * sock)
+{
+if (schemaVersion < 1)
+ {
+ if (MysqlQuery("ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month'", sock))
+ {
+ errorStr = "Couldn't update tariffs table to version 1. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+ if (MysqlQuery("UPDATE info SET version = 1", sock))
+ {
+ errorStr = "Couldn't update DB schema version to 1. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+ schemaVersion = 1;
+ logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
+ }
+
+if (schemaVersion < 2)
+ {
+ if (MysqlQuery("ALTER TABLE tariffs ADD change_policy VARCHAR(32) NOT NULL DEFAULT 'allow'", sock) ||
+ MysqlQuery("ALTER TABLE tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0", sock))
+ {
+ errorStr = "Couldn't update tariffs table to version 2. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+ if (MysqlQuery("UPDATE info SET version = 2", sock))
+ {
+ errorStr = "Couldn't update DB schema version to 2. With error:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+ schemaVersion = 2;
+ logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+int MYSQL_STORE::GetAllParams(std::vector<std::string> * ParamList,
+ const std::string & table, const std::string & name) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock=NULL;
+my_ulonglong num, i;
+
+ParamList->clear();
+
+sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
+
+if(MysqlGetQuery(qbuf,sock))
+{
+ errorStr = "Couldn't GetAllParams Query for: ";
+ errorStr += name + " - " + table + "\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't GetAllParams Results for: ";
+ errorStr += name + " - " + table + "\n";
+ errorStr += mysql_error(sock);
+ return -1;
+}
+
+num = mysql_num_rows(res);
+
+for(i = 0; i < num; i++)
+{
+ row = mysql_fetch_row(res);
+ ParamList->push_back(row[0]);
+}
+
+mysql_free_result(res);
+mysql_close(sock);
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
+{
+if(GetAllParams(usersList, "users", "login"))
+ return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
+{
+if(GetAllParams(adminsList, "admins", "login"))
+ return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
+{
+if(GetAllParams(tariffsList, "tariffs", "name"))
+ return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddUser(const std::string & login) const
+{
+std::string query = "INSERT INTO users SET login='" + login + "',Note='',NAS=''";
+
+for (int i = 0; i < USERDATA_NUM; i++)
+ query += ",Userdata" + std::to_string(i) + "=''";
+
+if(MysqlSetQuery(query.c_str()))
+{
+ errorStr = "Couldn't add user:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelUser(const std::string & login) const
+{
+sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't delete user:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreUserConf(STG::UserConf * conf, const std::string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+std::string query;
+
+query = "SELECT login, Password, Passive, Down, DisabledDetailStat, \
+ AlwaysOnline, Tariff, Address, Phone, Email, Note, \
+ RealName, StgGroup, Credit, TariffChange, ";
+
+for (int i = 0; i < USERDATA_NUM; i++)
+{
+ sprintf(qbuf, "Userdata%d, ", i);
+ query += qbuf;
+}
+
+query += "CreditExpire, IP FROM users WHERE login='";
+query += login + "' LIMIT 1";
+
+//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
+
+if(MysqlGetQuery(query.c_str(),sock))
+{
+ errorStr = "Couldn't restore Tariff(on query):\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't restore Tariff(on getting result):\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (mysql_num_rows(res) != 1)
+{
+ errorStr = "User not found";
+ mysql_close(sock);
+ return -1;
+}
+
+row = mysql_fetch_row(res);
+
+conf->password = row[1];
+
+if (conf->password.empty())
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' password is blank.";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[2],&conf->passive) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[3], &conf->disabled) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' data not read. Parameter Down.";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[4], &conf->disabledDetailStat) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' data not read. Parameter DisabledDetailStat.";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[5], &conf->alwaysOnline) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
+ mysql_close(sock);
+ return -1;
+ }
+
+conf->tariffName = row[6];
+
+if (conf->tariffName.empty())
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' tariff is blank.";
+ mysql_close(sock);
+ return -1;
+ }
+
+conf->address = row[7];
+conf->phone = row[8];
+conf->email = row[9];
+conf->note = row[10];
+conf->realName = row[11];
+conf->group = row[12];
+
+if (GetDouble(row[13], &conf->credit, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
+ mysql_close(sock);
+ return -1;
+ }
+
+conf->nextTariff = row[14];
+
+for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ conf->userdata[i] = row[15+i];
+ }
+
+GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
+
+std::string ipStr = row[16+USERDATA_NUM];
+STG::UserIPs i;
+try
+ {
+ i = STG::UserIPs::parse(ipStr);
+ }
+catch (const std::string & s)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
+ mysql_close(sock);
+ return -1;
+ }
+conf->ips = i;
+
+mysql_free_result(res);
+mysql_close(sock);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreUserStat(STG::UserStat * stat, const std::string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+
+std::string query;
+
+query = "SELECT ";
+
+for (int i = 0; i < DIR_NUM; i++)
+{
+ sprintf(qbuf, "D%d, U%d, ", i, i);
+ query += qbuf;
+}
+
+query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityTime \
+ FROM users WHERE login = '";
+query += login + "'";
+
+//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
+
+if(MysqlGetQuery(query.c_str() ,sock))
+{
+ errorStr = "Couldn't restore UserStat(on query):\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't restore UserStat(on getting result):\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+row = mysql_fetch_row(res);
+
+unsigned int startPos=0;
+
+char s[22];
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ uint64_t traff;
+ sprintf(s, "D%d", i);
+ if (GetULongLongInt(row[startPos+i*2], &traff, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
+ mysql_close(sock);
+ return -1;
+ }
+ stat->monthDown[i] = traff;
+
+ sprintf(s, "U%d", i);
+ if (GetULongLongInt(row[startPos+i*2+1], &traff, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
+ mysql_close(sock);
+ return -1;
+ }
+ stat->monthUp[i] = traff;
+ }//for
+
+startPos += (2*DIR_NUM);
+
+if (GetDouble(row[startPos], &stat->cash, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter Cash";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetDouble(row[startPos+1],&stat->freeMb, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter FreeMb";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetDouble(row[startPos+2], &stat->lastCashAdd, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAdd";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetTime(row[startPos+3], &stat->lastCashAddTime, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetTime(row[startPos+4], &stat->passiveTime, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter PassiveTime";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetTime(row[startPos+5], &stat->lastActivityTime, 0) != 0)
+ {
+ mysql_free_result(res);
+ errorStr = "User \'" + login + "\' stat not read. Parameter LastActivityTime";
+ mysql_close(sock);
+ return -1;
+ }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveUserConf(const STG::UserConf & conf, const std::string & login) const
+{
+std::string param;
+std::string res;
+
+strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDetailStat = %d, "\
+ "AlwaysOnline=%d, Tariff='%s', Address='%s', Phone='%s', Email='%s', "\
+ "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ",
+ conf.password.c_str(),
+ conf.passive,
+ conf.disabled,
+ conf.disabledDetailStat,
+ conf.alwaysOnline,
+ conf.tariffName.c_str(),
+ (ReplaceStr(conf.address,badSyms,repSym)).c_str(),
+ (ReplaceStr(conf.phone,badSyms,repSym)).c_str(),
+ (ReplaceStr(conf.email,badSyms,repSym)).c_str(),
+ (ReplaceStr(conf.note,badSyms,repSym)).c_str(),
+ (ReplaceStr(conf.realName,badSyms,repSym)).c_str(),
+ (ReplaceStr(conf.group,badSyms,repSym)).c_str(),
+ conf.credit,
+ conf.nextTariff.c_str()
+ );
+
+for (int i = 0; i < USERDATA_NUM; i++)
+ {
+ strprintf(¶m, " Userdata%d='%s',", i,
+ (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
+ res += param;
+ }
+
+strprintf(¶m, " CreditExpire=%d,", conf.creditExpire);
+res += param;
+
+std::ostringstream ipStr;
+ipStr << conf.ips;
+
+strprintf(¶m, " IP='%s'", ipStr.str().c_str());
+res += param;
+
+strprintf(¶m, " WHERE login='%s' LIMIT 1", login.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+ errorStr = "Couldn't save user conf:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveUserStat(const STG::UserStat & stat, const std::string & login) const
+{
+std::string param;
+std::string res;
+
+res = "UPDATE users SET";
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " D%d=%lld,", i, stat.monthDown[i]);
+ res += param;
+
+ strprintf(¶m, " U%d=%lld,", i, stat.monthUp[i]);
+ res += param;
+ }
+
+strprintf(¶m, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
+ " PassiveTime=%d, LastActivityTime=%d",
+ stat.cash,
+ stat.freeMb,
+ stat.lastCashAdd,
+ stat.lastCashAddTime,
+ stat.passiveTime,
+ stat.lastActivityTime
+ );
+res += param;
+
+strprintf(¶m, " WHERE login='%s' LIMIT 1", login.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+ errorStr = "Couldn't save user stat:\n";
+// errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteLogString(const std::string & str, const std::string & login) const
+{
+std::string res, tempStr;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+lt = localtime(&t);
+
+MYSQL_RES* result;
+MYSQL * sock;
+strprintf(&tempStr, "logs_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
+if (!(sock=MysqlConnect())){
+ errorStr = "Couldn't connect to Server";
+ return -1;
+}
+if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
+{
+ errorStr = "Couldn't get table " + tempStr + ":\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+my_ulonglong num_rows = mysql_num_rows(result);
+
+mysql_free_result(result);
+
+if (num_rows < 1)
+{
+ sprintf(qbuf,"CREATE TABLE logs_%02d_%4d (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)",
+ lt->tm_mon+1, lt->tm_year+1900);
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't create WriteDetailedStat table:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+}
+
+strprintf(&res, "%s -- %s",LogDate(t), str.c_str());
+
+std::string send;
+
+strprintf(&send,"INSERT INTO logs_%02d_%4d SET login='%s', text='%s'",
+ lt->tm_mon+1, lt->tm_year+1900,
+ login.c_str(), (ReplaceStr(res,badSyms,repSym)).c_str());
+
+if(MysqlQuery(send.c_str(),sock))
+{
+ errorStr = "Couldn't write log string:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+mysql_close(sock);
+return 0;
+
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message) const
+{
+std::string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
+ + paramName + "\' parameter changed from \'" + oldValue +
+ "\' to \'" + newValue + "\'. " + message;
+
+return WriteLogString(userLogMsg, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
+{
+std::string logStr = "Connect, " + inet_ntostring(ip);
+return WriteLogString(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & up,
+ const STG::DirTraff & down,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double /*freeMb*/,
+ const std::string & /*reason*/) const
+{
+std::string logStr = "Disconnect, ";
+std::ostringstream sssu;
+std::ostringstream sssd;
+std::ostringstream ssmu;
+std::ostringstream ssmd;
+std::ostringstream sscash;
+
+ssmu << up;
+ssmd << down;
+
+sssu << sessionUp;
+sssd << sessionDown;
+
+sscash << cash;
+
+logStr += " session upload: \'";
+logStr += sssu.str();
+logStr += "\' session download: \'";
+logStr += sssd.str();
+logStr += "\' month upload: \'";
+logStr += ssmu.str();
+logStr += "\' month download: \'";
+logStr += ssmd.str();
+logStr += "\' cash: \'";
+logStr += sscash.str();
+logStr += "\'";
+
+return WriteLogString(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year,
+ const std::string & login) const
+{
+std::string param, res;
+
+strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,",
+ login.c_str(), month+1, year+1900);
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " U%d=%lld,", i, stat.monthUp[i]);
+ res += param;
+
+ strprintf(¶m, " D%d=%lld,", i, stat.monthDown[i]);
+ res += param;
+ }
+
+strprintf(¶m, " cash=%f", stat.cash);
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+ errorStr = "Couldn't SaveMonthStat:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::AddAdmin(const std::string & login) const
+{
+sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't add admin:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::DelAdmin(const std::string & login) const
+{
+sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't delete admin:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::SaveAdmin(const STG::AdminConf & ac) const
+{
+char passwordE[2 * ADM_PASSWD_LEN + 2];
+char pass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+
+memset(pass, 0, sizeof(pass));
+memset(adminPass, 0, sizeof(adminPass));
+
+BLOWFISH_CTX ctx;
+InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+adminPass[ADM_PASSWD_LEN - 1] = 0;
+
+for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+ {
+ EncryptBlock(pass + 8*i, adminPass + 8*i, &ctx);
+ }
+
+pass[ADM_PASSWD_LEN - 1] = 0;
+Encode12(passwordE, pass, ADM_PASSWD_LEN);
+
+sprintf(qbuf,"UPDATE admins SET password='%s', ChgConf=%d, ChgPassword=%d, "\
+ "ChgStat=%d, ChgCash=%d, UsrAddDel=%d, ChgTariff=%d, ChgAdmin=%d "\
+ "WHERE login='%s' LIMIT 1",
+ passwordE,
+ ac.priv.userConf,
+ ac.priv.userPasswd,
+ ac.priv.userStat,
+ ac.priv.userCash,
+ ac.priv.userAddDel,
+ ac.priv.tariffChg,
+ ac.priv.adminChg,
+ ac.login.c_str()
+ );
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't save admin:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
+{
+char pass[ADM_PASSWD_LEN + 1];
+char password[ADM_PASSWD_LEN + 1];
+char passwordE[2*ADM_PASSWD_LEN + 2];
+BLOWFISH_CTX ctx;
+
+memset(password, 0, sizeof(password));
+
+std::string p;
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
+
+if(MysqlGetQuery(qbuf,sock))
+{
+ errorStr = "Couldn't restore admin:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't restore admin:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if ( mysql_num_rows(res) == 0)
+{
+ mysql_free_result(res);
+ errorStr = "Couldn't restore admin as couldn't found him in table.\n";
+ mysql_close(sock);
+ return -1;
+}
+
+row = mysql_fetch_row(res);
+
+p = row[1];
+
+if(p.length() == 0)
+{
+ mysql_free_result(res);
+ errorStr = "Error in parameter password";
+ mysql_close(sock);
+ return -1;
+}
+
+memset(passwordE, 0, sizeof(passwordE));
+strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
+
+memset(pass, 0, sizeof(pass));
+
+if (passwordE[0] != 0)
+ {
+ Decode21(pass, passwordE);
+ InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+ for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+ {
+ DecryptBlock(password + 8*i, pass + 8*i, &ctx);
+ }
+ }
+else
+ {
+ password[0] = 0;
+ }
+
+ac->password = password;
+
+uint16_t a;
+
+if (GetInt(row[2], &a) == 0)
+ ac->priv.userConf = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter ChgConf";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[3], &a) == 0)
+ ac->priv.userPasswd = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter ChgPassword";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[4], &a) == 0)
+ ac->priv.userStat = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter ChgStat";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[5], &a) == 0)
+ ac->priv.userCash = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter ChgCash";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[6], &a) == 0)
+ ac->priv.userAddDel = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter UsrAddDel";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[7], &a) == 0)
+ ac->priv.tariffChg = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter ChgTariff";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetInt(row[8], &a) == 0)
+ ac->priv.adminChg = a;
+else
+ {
+ mysql_free_result(res);
+ errorStr = "Error in parameter ChgAdmin";
+ mysql_close(sock);
+ return -1;
+ }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddTariff(const std::string & name) const
+{
+sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't add tariff:\n";
+// errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelTariff(const std::string & name) const
+{
+sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't delete tariff: ";
+// errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreTariff(STG::TariffData * td, const std::string & tariffName) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
+
+if(MysqlGetQuery(qbuf,sock))
+{
+ errorStr = "Couldn't restore Tariff:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't restore Tariff:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+std::string str;
+td->tariffConf.name = tariffName;
+
+row = mysql_fetch_row(res);
+
+std::string param;
+for (int i = 0; i<DIR_NUM; i++)
+ {
+ strprintf(¶m, "Time%d", i);
+ str = row[6+i*8];
+ if (str.length() == 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+ ParseTariffTimeStr(str.c_str(),
+ td->dirPrice[i].hDay,
+ td->dirPrice[i].mDay,
+ td->dirPrice[i].hNight,
+ td->dirPrice[i].mNight);
+
+ strprintf(¶m, "PriceDayA%d", i);
+ if (GetDouble(row[1+i*8], &td->dirPrice[i].priceDayA, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+ td->dirPrice[i].priceDayA /= (1024*1024);
+
+ strprintf(¶m, "PriceDayB%d", i);
+ if (GetDouble(row[2+i*8], &td->dirPrice[i].priceDayB, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+ td->dirPrice[i].priceDayB /= (1024*1024);
+
+ strprintf(¶m, "PriceNightA%d", i);
+ if (GetDouble(row[3+i*8], &td->dirPrice[i].priceNightA, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+ td->dirPrice[i].priceNightA /= (1024*1024);
+
+ strprintf(¶m, "PriceNightB%d", i);
+ if (GetDouble(row[4+i*8], &td->dirPrice[i].priceNightB, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+ td->dirPrice[i].priceNightB /= (1024*1024);
+
+ strprintf(¶m, "Threshold%d", i);
+ if (GetInt(row[5+i*8], &td->dirPrice[i].threshold) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+ strprintf(¶m, "SinglePrice%d", i);
+ if (GetInt(row[8+i*8], &td->dirPrice[i].singlePrice) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+ strprintf(¶m, "NoDiscount%d", i);
+ if (GetInt(row[7+i*8], &td->dirPrice[i].noDiscount) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+ }//main for
+
+if (GetDouble(row[2+8*DIR_NUM], &td->tariffConf.fee, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetDouble(row[3+8*DIR_NUM], &td->tariffConf.free, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
+ mysql_close(sock);
+ return -1;
+ }
+
+if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
+ mysql_close(sock);
+ return -1;
+ }
+
+ str = row[4+8*DIR_NUM];
+ param = "TraffType";
+
+ if (str.length() == 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+td->tariffConf.traffType = STG::Tariff::parseTraffType(str);
+
+if (schemaVersion > 0)
+{
+ str = row[5+8*DIR_NUM];
+ param = "Period";
+
+ if (str.length() == 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+ td->tariffConf.period = STG::Tariff::parsePeriod(str);
+ }
+else
+ {
+ td->tariffConf.period = STG::Tariff::MONTH;
+ }
+
+if (schemaVersion > 1)
+ {
+ str = row[6+8*DIR_NUM];
+ param = "ChangePolicy";
+
+ if (str.length() == 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+ td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(str);
+
+ str = row[7+8*DIR_NUM];
+ param = "ChangePolicyTimeout";
+
+ if (str.length() == 0)
+ {
+ mysql_free_result(res);
+ errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+ mysql_close(sock);
+ return -1;
+ }
+
+ td->tariffConf.changePolicyTimeout = readTime(str);
+ }
+else
+ {
+ td->tariffConf.changePolicy = STG::Tariff::ALLOW;
+ td->tariffConf.changePolicyTimeout = 0;
+ }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveTariff(const STG::TariffData & td, const std::string & tariffName) const
+{
+std::string param;
+
+std::string res="UPDATE tariffs SET";
+
+for (int i = 0; i < DIR_NUM; i++)
+ {
+ strprintf(¶m, " PriceDayA%d=%f,", i,
+ td.dirPrice[i].priceDayA * pt_mega);
+ res += param;
+
+ strprintf(¶m, " PriceDayB%d=%f,", i,
+ td.dirPrice[i].priceDayB * pt_mega);
+ res += param;
+
+ strprintf(¶m, " PriceNightA%d=%f,", i,
+ td.dirPrice[i].priceNightA * pt_mega);
+ res += param;
+
+ strprintf(¶m, " PriceNightB%d=%f,", i,
+ td.dirPrice[i].priceNightB * pt_mega);
+ res += param;
+
+ strprintf(¶m, " Threshold%d=%d,", i,
+ td.dirPrice[i].threshold);
+ res += param;
+
+ std::string s;
+ strprintf(¶m, " Time%d", i);
+
+ strprintf(&s, "%0d:%0d-%0d:%0d",
+ td.dirPrice[i].hDay,
+ td.dirPrice[i].mDay,
+ td.dirPrice[i].hNight,
+ td.dirPrice[i].mNight);
+
+ res += (param + "='" + s + "',");
+
+ strprintf(¶m, " NoDiscount%d=%d,", i,
+ td.dirPrice[i].noDiscount);
+ res += param;
+
+ strprintf(¶m, " SinglePrice%d=%d,", i,
+ td.dirPrice[i].singlePrice);
+ res += param;
+ }
+
+strprintf(¶m, " PassiveCost=%f,", td.tariffConf.passiveCost);
+res += param;
+
+strprintf(¶m, " Fee=%f,", td.tariffConf.fee);
+res += param;
+
+strprintf(¶m, " Free=%f,", td.tariffConf.free);
+res += param;
+
+res += " TraffType='" + STG::Tariff::toString(td.tariffConf.traffType) + "'";
+
+if (schemaVersion > 0)
+ res += ", Period='" + STG::Tariff::toString(td.tariffConf.period) + "'";
+
+if (schemaVersion > 1)
+ res += ", change_policy='" + STG::Tariff::toString(td.tariffConf.changePolicy) + "'"\
+ ", change_policy_timeout='" + formatTime(td.tariffConf.changePolicy) + "'";
+
+strprintf(¶m, " WHERE name='%s' LIMIT 1", tariffName.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+ errorStr = "Couldn't save tariff:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const
+{
+std::string res, stTime, endTime, tempStr;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+lt = localtime(&t);
+
+if (lt->tm_hour == 0 && lt->tm_min <= 5)
+ {
+ t -= 3600 * 24;
+ lt = localtime(&t);
+ }
+
+MYSQL_RES* result;
+MYSQL * sock;
+strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
+
+if (!(sock=MysqlConnect())){
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
+{
+ errorStr = "Couldn't get table " + tempStr + ":\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+my_ulonglong num_rows = mysql_num_rows(result);
+
+mysql_free_result(result);
+
+if (num_rows < 1)
+{
+ sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
+ "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
+ "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
+ "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
+ lt->tm_mon+1, lt->tm_year+1900);
+
+ if(MysqlQuery(qbuf,sock))
+ {
+ errorStr = "Couldn't create WriteDetailedStat table:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+}
+
+struct tm * lt1;
+struct tm * lt2;
+
+lt1 = localtime(&lastStat);
+
+int h1, m1, s1;
+int h2, m2, s2;
+
+h1 = lt1->tm_hour;
+m1 = lt1->tm_min;
+s1 = lt1->tm_sec;
+
+lt2 = localtime(&t);
+
+h2 = lt2->tm_hour;
+m2 = lt2->tm_min;
+s2 = lt2->tm_sec;
+
+strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
+strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
+
+strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
+ "day=%d,startTime='%s',endTime='%s',",
+ lt->tm_mon+1, lt->tm_year+1900,
+ login.c_str(),
+ lt->tm_mday,
+ stTime.c_str(),
+ endTime.c_str()
+ );
+
+STG::TraffStat::const_iterator stIter;
+stIter = statTree.begin();
+
+while (stIter != statTree.end())
+ {
+ strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f",
+ inet_ntostring(stIter->first.ip).c_str(),
+ stIter->first.dir,
+ stIter->second.down,
+ stIter->second.up,
+ stIter->second.cash
+ );
+
+ if( MysqlQuery((res+tempStr).c_str(),sock) )
+ {
+ errorStr = "Couldn't insert data in WriteDetailedStat:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+ }
+
+ result=mysql_store_result(sock);
+ if(result)
+ mysql_free_result(result);
+
+ ++stIter;
+ }
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddMessage(STG::Message * msg, const std::string & login) const
+{
+struct timeval tv;
+
+gettimeofday(&tv, NULL);
+
+msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
+
+sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld",
+ login.c_str(),
+ static_cast<long long>(msg->header.id)
+ );
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't add message:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return EditMessage(*msg, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::EditMessage(const STG::Message & msg, const std::string & login) const
+{
+std::string res;
+
+strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
+ "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
+ "WHERE login='%s' AND id=%lld LIMIT 1",
+ msg.header.type,
+ msg.header.lastSendTime,
+ msg.header.creationTime,
+ msg.header.showTime,
+ msg.header.repeat,
+ msg.header.repeatPeriod,
+ (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
+ login.c_str(),
+ msg.header.id
+ );
+
+if(MysqlSetQuery(res.c_str()))
+{
+ errorStr = "Couldn't edit message:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+
+sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
+ login.c_str(), static_cast<unsigned long long>(id));
+
+if(MysqlGetQuery(qbuf,sock))
+{
+ errorStr = "Couldn't GetMessage:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't GetMessage:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+row = mysql_fetch_row(res);
+
+if(row[2]&&str2x(row[2], msg->header.type))
+{
+ mysql_free_result(res);
+ errorStr = "Invalid value in message header for user: " + login;
+ mysql_close(sock);
+ return -1;
+}
+
+if(row[3] && str2x(row[3], msg->header.lastSendTime))
+{
+ mysql_free_result(res);
+ errorStr = "Invalid value in message header for user: " + login;
+ mysql_close(sock);
+ return -1;
+}
+
+if(row[4] && str2x(row[4], msg->header.creationTime))
+{
+ mysql_free_result(res);
+ errorStr = "Invalid value in message header for user: " + login;
+ mysql_close(sock);
+ return -1;
+}
+
+if(row[5] && str2x(row[5], msg->header.showTime))
+{
+ mysql_free_result(res);
+ errorStr = "Invalid value in message header for user: " + login;
+ mysql_close(sock);
+ return -1;
+}
+
+if(row[6] && str2x(row[6], msg->header.repeat))
+{
+ mysql_free_result(res);
+ errorStr = "Invalid value in message header for user: " + login;
+ mysql_close(sock);
+ return -1;
+}
+
+if(row[7] && str2x(row[7], msg->header.repeatPeriod))
+{
+ mysql_free_result(res);
+ errorStr = "Invalid value in message header for user: " + login;
+ mysql_close(sock);
+ return -1;
+}
+
+msg->header.id = id;
+msg->text = row[8];
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
+{
+sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1",
+ login.c_str(), static_cast<long long>(id));
+
+if(MysqlSetQuery(qbuf))
+{
+ errorStr = "Couldn't delete Message:\n";
+ //errorStr += mysql_error(sock);
+ return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
+
+if(MysqlGetQuery(qbuf,sock))
+{
+ errorStr = "Couldn't GetMessageHdrs:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+ errorStr = "Couldn't GetMessageHdrs:\n";
+ errorStr += mysql_error(sock);
+ mysql_close(sock);
+ return -1;
+}
+
+unsigned int i;
+my_ulonglong num_rows = mysql_num_rows(res);
+uint64_t id = 0;
+
+for (i = 0; i < num_rows; i++)
+{
+ row = mysql_fetch_row(res);
+ if (str2x(row[1], id))
+ continue;
+
+ STG::Message::Header hdr;
+ if (row[2])
+ if(str2x(row[2], hdr.type))
+ continue;
+
+ if (row[3])
+ if(str2x(row[3], hdr.lastSendTime))
+ continue;
+
+ if (row[4])
+ if(str2x(row[4], hdr.creationTime))
+ continue;
+
+ if (row[5])
+ if(str2x(row[5], hdr.showTime))
+ continue;
+
+ if (row[6])
+ if(str2x(row[6], hdr.repeat))
+ continue;
+
+ if (row[7])
+ if(str2x(row[7], hdr.repeatPeriod))
+ continue;
+
+ hdr.id = id;
+ hdrsList->push_back(hdr);
+}
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
+
+ MYSQL * sock;
+ int ret=MysqlGetQuery(Query,sock);
+ mysql_close(sock);
+ return ret;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
+ if (!(sock=MysqlConnect())) {
+ return -1;
+ }
+ return MysqlQuery(Query,sock);
+}
+//-----------------------------------------------------------------------------
+MYSQL * MYSQL_STORE::MysqlConnect() const {
+ MYSQL * sock;
+ if ( !(sock=mysql_init(NULL)) ){
+ errorStr= "mysql init susck\n";
+ return NULL;
+ }
+ if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
+ storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
+ 0,0,NULL,0)))
+ {
+ errorStr = "Couldn't connect to mysql engine! With error:\n";
+ errorStr += mysql_error(sock);
+ return NULL;
+ }
+ else{
+ if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
+ errorStr = "Database lost !\n";
+ return NULL;
+ }
+ }
+ return sock;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+#pragma once
+
+#include "stg/store.h"
+#include "stg/module_settings.h"
+#include "stg/user_traff.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include <mysql/mysql.h>
+
+//-----------------------------------------------------------------------------
+class MYSQL_STORE_SETTINGS
+{
+public:
+ MYSQL_STORE_SETTINGS();
+ virtual ~MYSQL_STORE_SETTINGS() {}
+ virtual int ParseSettings(const STG::ModuleSettings & s);
+ virtual const std::string & GetStrError() const { return errorStr; }
+
+ const std::string & GetDBUser() const { return dbUser; }
+ const std::string & GetDBPassword() const { return dbPass; }
+ const std::string & GetDBHost() const { return dbHost; }
+ const std::string & GetDBName() const { return dbName; }
+
+private:
+ MYSQL_STORE_SETTINGS(const MYSQL_STORE_SETTINGS & rvalue);
+ MYSQL_STORE_SETTINGS & operator=(const MYSQL_STORE_SETTINGS & rvalue);
+
+ const STG::ModuleSettings * settings;
+
+ int ParseParam(const std::vector<STG::ParamValue> & moduleParams,
+ const std::string & name, std::string & result);
+
+ std::string errorStr;
+
+ std::string dbUser;
+ std::string dbPass;
+ std::string dbName;
+ std::string dbHost;
+};
+//-----------------------------------------------------------------------------
+class MYSQL_STORE: public STG::Store
+{
+public:
+ MYSQL_STORE();
+ const std::string & GetStrError() const override { return errorStr; }
+
+ //User
+ int GetUsersList(std::vector<std::string> * usersList) const override;
+ int AddUser(const std::string & login) const override;
+ int DelUser(const std::string & login) const override;
+ int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
+ int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
+ int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
+ int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
+ int WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message = "") const override;
+ int WriteUserConnect(const std::string & login, uint32_t ip) const override;
+ int WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & up,
+ const STG::DirTraff & down,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double freeMb,
+ const std::string & reason) const override;
+
+ int WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const override;
+
+ int AddMessage(STG::Message * msg, const std::string & login) const override;
+ int EditMessage(const STG::Message & msg, const std::string & login) const override;
+ int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
+ int DelMessage(uint64_t id, const std::string & login) const override;
+ int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
+
+ int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
+
+ //Admin
+ int GetAdminsList(std::vector<std::string> * adminsList) const override;
+ int AddAdmin(const std::string & login) const override;
+ int DelAdmin(const std::string & login) const override;
+ int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
+ int SaveAdmin(const STG::AdminConf & ac) const override;
+
+ //Tariff
+ int GetTariffsList(std::vector<std::string> * tariffsList) const override;
+ int AddTariff(const std::string & name) const override;
+ int DelTariff(const std::string & name) const override;
+ int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
+ int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
+
+ //Corparation
+ int GetCorpsList(std::vector<std::string> *) const override {return 0;}
+ int SaveCorp(const STG::CorpConf &) const override {return 0;}
+ int RestoreCorp(STG::CorpConf *, const std::string &) const override {return 0;}
+ int AddCorp(const std::string &) const override {return 0;}
+ int DelCorp(const std::string &) const override {return 0;}
+
+ // Services
+ int GetServicesList(std::vector<std::string> *) const override {return 0;}
+ int SaveService(const STG::ServiceConf &) const override {return 0;}
+ int RestoreService(STG::ServiceConf *, const std::string &) const override {return 0;}
+ int AddService(const std::string &) const override {return 0;}
+ int DelService(const std::string &) const override {return 0;}
+
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+ const std::string & GetVersion() const override { return version; }
+
+private:
+ MYSQL_STORE(const MYSQL_STORE & rvalue);
+ MYSQL_STORE & operator=(const MYSQL_STORE & rvalue);
+
+ virtual int WriteLogString(const std::string & str, const std::string & login) const;
+ int GetAllParams(std::vector<std::string> * ParamList, const std::string & table, const std::string & name) const;
+ int CheckAllTables(MYSQL * sock);
+ int MakeUpdates(MYSQL * sock);
+ bool IsTablePresent(const std::string & str,MYSQL * sock);
+ mutable std::string errorStr;
+ int MysqlQuery(const char* sQuery,MYSQL * sock) const;
+ int MysqlGetQuery(const char * Query,MYSQL * & sock) const;
+ int MysqlSetQuery(const char * Query) const;
+ MYSQL * MysqlConnect() const ;
+ std::string version;
+ MYSQL_STORE_SETTINGS storeSettings;
+ STG::ModuleSettings settings;
+ int schemaVersion;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * This file contains a realization of a base postgresql-storage plugin class
+ *
+ * v. 1.3
+ * FreeMb logging on disconnects added
+ *
+ * v. 1.2
+ * Reconnection on faults added
+ *
+ * v. 1.1
+ * tb_stats removed
+ *
+ * v. 1.0
+ * Initial implementation
+ *
+ * $Revision: 1.5 $
+ * $Date: 2010/01/06 10:43:48 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "postgresql_store_utils.h"
+#include "postgresql_store.h"
+
+#include "stg/common.h" // str2x, printfd
+
+#include <string>
+#include <vector>
+
+#include <libpq-fe.h>
+
+extern "C" STG::Store* GetStore()
+{
+ static POSTGRESQL_STORE plugin;
+ return &plugin;
+}
+
+//-----------------------------------------------------------------------------
+POSTGRESQL_STORE::POSTGRESQL_STORE()
+ : versionString("postgresql_store v.1.3"),
+ server("localhost"),
+ database("stargazer"),
+ user("stg"),
+ password("123456"),
+ clientEncoding("KOI8"),
+ version(0),
+ retries(3),
+ connection(NULL),
+ logger(STG::PluginLogger::get("store_postgresql"))
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+POSTGRESQL_STORE::~POSTGRESQL_STORE()
+{
+if (connection)
+ {
+ PQfinish(connection);
+ }
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::ParseSettings()
+{
+std::vector<STG::ParamValue>::iterator i;
+
+for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
+ {
+ if (i->value.empty())
+ continue;
+ std::string s = ToLower(i->param);
+ if (s == "server")
+ {
+ server = i->value.front();
+ }
+ if (s == "database")
+ {
+ database = i->value.front();
+ }
+ if (s == "user")
+ {
+ user = i->value.front();
+ }
+ if (s == "password")
+ {
+ password = i->value.front();
+ }
+ if (s == "retries")
+ {
+ if (str2x(i->value.front(), retries))
+ {
+ strError = "Invalid 'retries' value";
+ printfd(__FILE__, "POSTGRESQL_STORE::ParseSettings(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+ }
+
+clientEncoding = "KOI8";
+
+return Connect();
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::Connect()
+{
+std::string params;
+params = "host=" + server + " "
+ + "dbname=" + database + " "
+ + "user=" + user + " "
+ + "password=" + password;
+
+connection = PQconnectdb(params.c_str());
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ strError = PQerrorMessage(connection);
+ printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
+ // Will try to connect later
+ return 0;
+ }
+
+if (PQsetClientEncoding(connection, clientEncoding.c_str()))
+ {
+ strError = PQerrorMessage(connection);
+ printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
+ return 1;
+ }
+
+return CheckVersion();
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::Reset() const
+{
+for (int i = 0; i < retries && PQstatus(connection) != CONNECTION_OK; ++i)
+ {
+ struct timespec ts = {1, 0};
+ nanosleep(&ts, NULL);
+ PQreset(connection);
+ }
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ strError = PQerrorMessage(connection);
+ printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
+ return 1;
+ }
+
+if (PQsetClientEncoding(connection, clientEncoding.c_str()))
+ {
+ strError = PQerrorMessage(connection);
+ printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+return CheckVersion();
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::CheckVersion() const
+{
+
+if (StartTransaction())
+ {
+ strError = "Failed to start transaction";
+ printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+PGresult * result = PQexec(connection, "SELECT MAX(version) FROM tb_info");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n");
+ RollbackTransaction();
+ return -1;
+ }
+
+if (str2x(PQgetvalue(result, 0, 0), version))
+ {
+ strError = "Invalid DB version";
+ PQclear(result);
+ RollbackTransaction();
+ printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+PQclear(result);
+
+if (version < DB_MIN_VERSION)
+ {
+ strError = "DB version too old";
+ RollbackTransaction();
+ printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+if (version < 6)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): I recommend you to upgrade your DB to higher version to support FreeMb logging on disconnect. Current version is %d\n", version);
+ }
+
+if (CommitTransaction())
+ {
+ strError = "Failed to commit transaction";
+ printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+logger("POSTGRESQL_STORE: Current DB schema version: %d", version);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/store.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+
+#include <libpq-fe.h>
+
+// Minimal DB version is 5
+// Recommended DB version is 6 (support FreeMb logging on disconnects)
+#define DB_MIN_VERSION 5
+
+namespace STG
+{
+
+class UserIPs;
+
+}
+
+class POSTGRESQL_STORE : public STG::Store {
+public:
+ POSTGRESQL_STORE();
+ ~POSTGRESQL_STORE() override;
+
+ // Users
+ int GetUsersList(std::vector<std::string> * usersList) const override;
+ int AddUser(const std::string & login) const override;
+ int DelUser(const std::string & login) const override;
+ int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
+ int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
+ int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
+ int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
+ int WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message) const override;
+ int WriteUserConnect(const std::string & login, uint32_t ip) const override;
+ int WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & up,
+ const STG::DirTraff & down,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double freeMb,
+ const std::string & reason) const override;
+ int WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const override;
+
+ // Messages
+ int AddMessage(STG::Message * msg, const std::string & login) const override;
+ int EditMessage(const STG::Message & msg, const std::string & login) const override;
+ int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
+ int DelMessage(uint64_t id, const std::string & login) const override;
+ int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
+
+ // Stats
+ int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
+
+ // Admins
+ int GetAdminsList(std::vector<std::string> * adminsList) const override;
+ int SaveAdmin(const STG::AdminConf & ac) const override;
+ int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
+ int AddAdmin(const std::string & login) const override;
+ int DelAdmin(const std::string & login) const override;
+
+ // Tariffs
+ int GetTariffsList(std::vector<std::string> * tariffsList) const override;
+ int AddTariff(const std::string & name) const override;
+ int DelTariff(const std::string & name) const override;
+ int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
+ int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
+
+ // Corporations
+ int GetCorpsList(std::vector<std::string> * corpsList) const override;
+ int SaveCorp(const STG::CorpConf & cc) const override;
+ int RestoreCorp(STG::CorpConf * cc, const std::string & name) const override;
+ int AddCorp(const std::string & name) const override;
+ int DelCorp(const std::string & name) const override;
+
+ // Services
+ int GetServicesList(std::vector<std::string> * servicesList) const override;
+ int SaveService(const STG::ServiceConf & sc) const override;
+ int RestoreService(STG::ServiceConf * sc, const std::string & name) const override;
+ int AddService(const std::string & name) const override;
+ int DelService(const std::string & name) const override;
+
+ // Settings
+ void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
+ int ParseSettings() override;
+
+ const std::string & GetStrError() const override { return strError; }
+ const std::string & GetVersion() const override { return versionString; }
+private:
+ POSTGRESQL_STORE(const POSTGRESQL_STORE & rvalue);
+ POSTGRESQL_STORE & operator=(const POSTGRESQL_STORE & rvalue);
+
+ int StartTransaction() const;
+ int CommitTransaction() const;
+ int RollbackTransaction() const;
+
+ int EscapeString(std::string & value) const;
+
+ int SaveStat(const STG::UserStat & stat, const std::string & login, int year = 0, int month = 0) const;
+
+ int SaveUserServices(uint32_t uid, const std::vector<std::string> & services) const;
+ int SaveUserData(uint32_t uid, const std::vector<std::string> & data) const;
+ int SaveUserIPs(uint32_t uid, const STG::UserIPs & ips) const;
+
+ void MakeDate(std::string & date, int year = 0, int month = 0) const;
+
+ int Connect();
+ int Reset() const;
+ int CheckVersion() const;
+
+ std::string versionString;
+ mutable std::string strError;
+ std::string server;
+ std::string database;
+ std::string user;
+ std::string password;
+ std::string clientEncoding;
+ STG::ModuleSettings settings;
+ mutable pthread_mutex_t mutex;
+ mutable int version;
+ int retries;
+
+ PGconn * connection;
+
+ STG::PluginLogger logger;
+};
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Administrators manipulation methods
+ *
+ * $Revision: 1.3 $
+ * $Date: 2010/11/08 10:10:24 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/locker.h"
+#include "stg/common.h"
+#include "stg/admin_conf.h"
+#include "stg/blowfish.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+#define adm_enc_passwd "cjeifY8m3"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+result = PQexec(connection, "SELECT login FROM tb_admins WHERE login <> '@stargazer'");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ adminsList->push_back(PQgetvalue(result, i, 0));
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveAdmin(const STG::AdminConf & ac) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+char encodedPass[2 * ADM_PASSWD_LEN + 2];
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+memset(cryptedPass, 0, ADM_PASSWD_LEN + 1);
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+ EncryptBlock(cryptedPass + 8 * i, adminPass + 8 * i, &ctx);
+
+cryptedPass[ADM_PASSWD_LEN] = 0;
+Encode12(encodedPass, cryptedPass, ADM_PASSWD_LEN);
+
+std::string pass = encodedPass;
+std::string login = ac.login;
+
+if (EscapeString(pass))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to escape password'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(login))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::stringstream query;
+query << "UPDATE tb_admins SET "
+ << "passwd = '" << pass << "', "
+ << "chg_conf = " << ac.priv.userConf << ", "
+ << "chg_password = " << ac.priv.userPasswd << ", "
+ << "chg_stat = " << ac.priv.userStat << ", "
+ << "chg_cash = " << ac.priv.userCash << ", "
+ << "usr_add_del = " << ac.priv.userAddDel << ", "
+ << "chg_tariff = " << ac.priv.tariffChg << ", "
+ << "chg_admin = " << ac.priv.adminChg << " "
+ << "WHERE login = '" << login << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT login, passwd, \
+ chg_conf, chg_password, chg_stat, \
+ chg_cash, usr_add_del, chg_tariff, \
+ chg_admin, chg_service, chg_corporation \
+ FROM tb_admins \
+ WHERE login = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch admin's data";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ac->login = PQgetvalue(result, 0, 0);
+ac->password = PQgetvalue(result, 0, 1);
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 2) << " "
+ << PQgetvalue(result, 0, 3) << " "
+ << PQgetvalue(result, 0, 4) << " "
+ << PQgetvalue(result, 0, 5) << " "
+ << PQgetvalue(result, 0, 6) << " "
+ << PQgetvalue(result, 0, 7) << " "
+ << PQgetvalue(result, 0, 8) << " "
+ << PQgetvalue(result, 0, 9) << " "
+ << PQgetvalue(result, 0, 10);
+
+PQclear(result);
+
+tuple >> ac->priv.userConf
+ >> ac->priv.userPasswd
+ >> ac->priv.userStat
+ >> ac->priv.userCash
+ >> ac->priv.userAddDel
+ >> ac->priv.tariffChg
+ >> ac->priv.adminChg;
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to commit transacion'\n");
+ return -1;
+ }
+
+if (ac->password == "")
+ {
+ return 0;
+ }
+
+Decode21(cryptedPass, ac->password.c_str());
+InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+ {
+ DecryptBlock(adminPass + 8 * i, cryptedPass + 8 * i, &ctx);
+ }
+ac->password = adminPass;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddAdmin(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "INSERT INTO tb_admins \
+ (login, passwd, \
+ chg_conf, chg_password, chg_stat, \
+ chg_cash, usr_add_del, chg_tariff, \
+ chg_admin, chg_service, chg_corporation) \
+ VALUES "
+ << "('" << elogin << "', \
+ '', 0, 0, 0, 0, 0, 0, 0, 0, 0)";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelAdmin(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "DELETE FROM tb_admins WHERE login = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Corporations manipulation methods
+ *
+ * $Revision: 1.2 $
+ * $Date: 2009/06/09 12:32:39 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/corp_conf.h"
+#include "stg/locker.h"
+#include "stg/common.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetCorpsList(std::vector<std::string> * corpsList) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+result = PQexec(connection, "SELECT name FROM tb_corporations");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ corpsList->push_back(PQgetvalue(result, i, 0));
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveCorp(const STG::CorpConf & cc) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = cc.name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "UPDATE tb_corporations SET "
+ << "cash = " << cc.cash
+ << "WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreCorp(STG::CorpConf * cc, const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT cash FROM tb_corporations WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch corp's data";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0);
+
+PQclear(result);
+
+tuple >> cc->cash;
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddCorp(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "INSERT INTO tb_corporations \
+ (name, cash) \
+ VALUES \
+ ('" << ename << "', 0)";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelCorp(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "DELETE FROM tb_corporations WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+
+/*
+ * Messages manipualtion methods
+ *
+ * $Revision: 1.6 $
+ * $Date: 2009/07/15 11:19:42 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/common.h"
+#include "stg/locker.h"
+#include "stg/message.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddMessage(STG::Message * msg, const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+std::string etext = msg->text;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(etext))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to escape message text'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT sp_add_message("
+ << "'" << elogin << "', "
+ << "CAST(1 AS SMALLINT), " // Here need to be a version, but, it's uninitiated actually
+ << "CAST(" << msg->header.type << " AS SMALLINT), "
+ << "CAST('" << formatTime(msg->header.lastSendTime) << "' AS TIMESTAMP), "
+ << "CAST('" << formatTime(msg->header.creationTime) << "' AS TIMESTAMP), "
+ << msg->header.showTime << ", "
+ << "CAST(" << msg->header.repeat << " AS SMALLINT), "
+ << msg->header.repeatPeriod << ", "
+ << "'" << etext << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch newlly added message ID";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0);
+
+PQclear(result);
+
+tuple >> msg->header.id;
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::EditMessage(const STG::Message & msg,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+std::string etext = msg.text;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(etext))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to escape message text'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "UPDATE tb_messages SET "
+ << "fk_user = (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
+ << "ver = " << msg.header.ver << ", "
+ << "msg_type = " << msg.header.type << ", "
+ << "last_send_time = CAST('" << formatTime(msg.header.lastSendTime) << "' AS TIMESTAMP), "
+ << "creation_time = CAST('" << formatTime(msg.header.creationTime) << "' AS TIMESTAMP), "
+ << "show_time = " << msg.header.showTime << ", "
+ << "repeat = " << msg.header.repeat << ", "
+ << "repeat_period = " << msg.header.repeatPeriod << ", "
+ << "msg_text = '" << etext << "' "
+ << "WHERE pk_message = " << msg.header.id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetMessage(uint64_t id,
+ STG::Message * msg,
+ const std::string &) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT ver, msg_type, last_send_time, \
+ creation_time, show_time, repeat, \
+ repeat_period, msg_text \
+ FROM tb_messages \
+ WHERE pk_message = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch message data";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+str2x(PQgetvalue(result, 0, 0), msg->header.ver);
+str2x(PQgetvalue(result, 0, 1), msg->header.type);
+msg->header.lastSendTime = static_cast<unsigned int>(readTime(PQgetvalue(result, 0, 2)));
+msg->header.creationTime = static_cast<unsigned int>(readTime(PQgetvalue(result, 0, 3)));
+str2x(PQgetvalue(result, 0, 4), msg->header.showTime);
+str2x(PQgetvalue(result, 0, 5), msg->header.repeat);
+str2x(PQgetvalue(result, 0, 6), msg->header.repeatPeriod);
+msg->text = PQgetvalue(result, 0, 7);
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelMessage(uint64_t id, const std::string &) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::ostringstream query;
+query << "DELETE FROM tb_messages WHERE pk_message = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT pk_message, ver, msg_type, \
+ last_send_time, creation_time, show_time, \
+ repeat, repeat_period \
+ FROM tb_messages \
+ WHERE fk_user IN \
+ (SELECT pk_user FROM tb_users \
+ WHERE name = '" << elogin << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ std::stringstream tuple;
+ STG::Message::Header header;
+ tuple << PQgetvalue(result, i, 0) << " ";
+ tuple << PQgetvalue(result, i, 1) << " ";
+ tuple << PQgetvalue(result, i, 2) << " ";
+ header.lastSendTime = static_cast<unsigned int>(readTime(PQgetvalue(result, i, 3)));
+ header.creationTime = static_cast<unsigned int>(readTime(PQgetvalue(result, i, 4)));
+ tuple << PQgetvalue(result, i, 5) << " ";
+ tuple << PQgetvalue(result, i, 6) << " ";
+ tuple << PQgetvalue(result, i, 7) << " ";
+
+ tuple >> header.id;
+ tuple >> header.ver;
+ tuple >> header.type;
+ tuple >> header.showTime;
+ tuple >> header.repeat;
+ tuple >> header.repeatPeriod;
+ hdrsList->push_back(header);
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+
+/*
+ * Services manipulation methods
+ *
+ * $Revision: 1.2 $
+ * $Date: 2009/06/09 12:32:40 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/service_conf.h"
+#include "stg/common.h"
+#include "stg/locker.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetServicesList(std::vector<std::string> * servicesList) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+result = PQexec(connection, "SELECT name FROM tb_services");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ servicesList->push_back(PQgetvalue(result, i, 0));
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveService(const STG::ServiceConf & sc) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = sc.name;
+std::string ecomment = sc.comment;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(ecomment))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to escape comment'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "UPDATE tb_services SET "
+ << "comment = '" << ecomment << "', "
+ << "cost = " << sc.cost << ", "
+ << "pay_day = " << sc.payDay << " "
+ << "WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreService(STG::ServiceConf * sc,
+ const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT comment, cost, pay_day FROM tb_services WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch service's data";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0) << " "
+ << PQgetvalue(result, 0, 1) << " "
+ << PQgetvalue(result, 0, 2);
+
+PQclear(result);
+
+tuple >> sc->comment
+ >> sc->cost
+ >> sc->payDay;
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddService(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "INSERT INTO tb_services \
+ (name, comment, cost, pay_day) \
+ VALUES \
+ ('" << ename << "', '', 0, 0)";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelService(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "DELETE FROM tb_services WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Tariffs manipulation methods
+ *
+ * $Revision: 1.2 $
+ * $Date: 2009/06/09 12:32:40 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/tariff_conf.h"
+#include "stg/common.h"
+#include "stg/locker.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <cmath>
+
+#include <libpq-fe.h>
+
+namespace
+{
+
+const int pt_mega = 1024 * 1024;
+
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+result = PQexec(connection, "SELECT name FROM tb_tariffs");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ tariffsList->push_back(PQgetvalue(result, i, 0));
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddTariff(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT sp_add_tariff('" << ename << "', " << DIR_NUM << ")";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelTariff(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "DELETE FROM tb_tariffs WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveTariff(const STG::TariffData & td,
+ const std::string & tariffName) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = tariffName;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ {
+ std::ostringstream query;
+ query << "SELECT pk_tariff FROM tb_tariffs WHERE name = '" << ename << "'";
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch tariff ID";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int32_t id;
+
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, 0, 0);
+
+ PQclear(result);
+
+ tuple >> id;
+ }
+
+ {
+ std::ostringstream query;
+ query << "UPDATE tb_tariffs SET \
+ fee = " << td.tariffConf.fee << ", \
+ free = " << td.tariffConf.free << ", \
+ passive_cost = " << td.tariffConf.passiveCost << ", \
+ traff_type = " << td.tariffConf.traffType;
+
+ if (version > 6)
+ query << ", period = '" << STG::Tariff::toString(td.tariffConf.period) << "'";
+
+ if (version > 7)
+ query << ", change_policy = '" << STG::Tariff::toString(td.tariffConf.changePolicy) << "', \
+ change_policy_timeout = CAST('" << formatTime(td.tariffConf.changePolicyTimeout) << "' AS TIMESTAMP)";
+
+ query << " WHERE pk_tariff = " << id;
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+for(int i = 0; i < DIR_NUM; i++)
+ {
+ double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
+ double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
+ double pna = 0;
+ double pnb = 0;
+
+ if (td.dirPrice[i].singlePrice)
+ {
+ pna = pda;
+ pnb = pdb;
+ }
+ else
+ {
+ pna = td.dirPrice[i].priceNightA * 1024 * 1024;
+ pnb = td.dirPrice[i].priceNightB * 1024 * 1024;
+ }
+
+ int threshold = 0;
+ if (td.dirPrice[i].noDiscount)
+ {
+ threshold = 0xffFFffFF;
+ }
+ else
+ {
+ threshold = td.dirPrice[i].threshold;
+ }
+
+ {
+ std::ostringstream query;
+ query << "UPDATE tb_tariffs_params SET \
+ price_day_a = " << pda << ", \
+ price_day_b = " << pdb << ", \
+ price_night_a = " << pna << ", \
+ price_night_b = " << pnb << ", \
+ threshold = " << threshold << ", \
+ time_day_begins = CAST('" << td.dirPrice[i].hDay
+ << ":"
+ << td.dirPrice[i].mDay << "' AS TIME), \
+ time_day_ends = CAST('" << td.dirPrice[i].hNight
+ << ":"
+ << td.dirPrice[i].mNight << "' AS TIME) \
+ WHERE fk_tariff = " << id << " AND dir_num = " << i;
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreTariff(STG::TariffData * td,
+ const std::string & tariffName) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string ename = tariffName;
+
+if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to escape name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+td->tariffConf.name = tariffName;
+
+std::ostringstream query;
+query << "SELECT pk_tariff, \
+ fee, \
+ free, \
+ passive_cost, \
+ traff_type";
+
+if (version > 6)
+ query << ", period";
+
+if (version > 7)
+ query << ", change_policy \
+ , change_policy_timeout";
+
+query << " FROM tb_tariffs WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch tariff data";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int id;
+
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, 0, 0) << " ";
+ tuple << PQgetvalue(result, 0, 1) << " ";
+ tuple << PQgetvalue(result, 0, 2) << " ";
+ tuple << PQgetvalue(result, 0, 3) << " ";
+ tuple << PQgetvalue(result, 0, 4) << " ";
+
+ tuple >> id;
+ tuple >> td->tariffConf.fee;
+ tuple >> td->tariffConf.free;
+ tuple >> td->tariffConf.passiveCost;
+ unsigned traffType;
+ tuple >> traffType;
+ td->tariffConf.traffType = static_cast<STG::Tariff::TraffType>(traffType);
+ }
+
+if (version > 6)
+ td->tariffConf.period = STG::Tariff::parsePeriod(PQgetvalue(result, 0, 5));
+
+if (version > 7)
+ {
+ td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(PQgetvalue(result, 0, 6));
+ td->tariffConf.changePolicyTimeout = readTime(PQgetvalue(result, 0, 7));
+ }
+
+PQclear(result);
+
+query.str("");
+query << "SELECT dir_num, \
+ price_day_a, \
+ price_day_b, \
+ price_night_a, \
+ price_night_b, \
+ threshold, \
+ EXTRACT(hour FROM time_day_begins), \
+ EXTRACT(minute FROM time_day_begins), \
+ EXTRACT(hour FROM time_day_ends), \
+ EXTRACT(minute FROM time_day_ends) \
+ FROM tb_tariffs_params \
+ WHERE fk_tariff = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+tuples = PQntuples(result);
+
+if (tuples != DIR_NUM)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Tariff params count and DIR_NUM does not feet (wanted %d, actually %d)'\n", DIR_NUM, tuples);
+ }
+
+for (int i = 0; i < std::min(tuples, DIR_NUM); ++i)
+ {
+ int dir;
+
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, i, 0) << " ";
+ tuple << PQgetvalue(result, i, 1) << " ";
+ tuple << PQgetvalue(result, i, 2) << " ";
+ tuple << PQgetvalue(result, i, 3) << " ";
+ tuple << PQgetvalue(result, i, 4) << " ";
+ tuple << PQgetvalue(result, i, 5) << " ";
+ tuple << PQgetvalue(result, i, 6) << " ";
+ tuple << PQgetvalue(result, i, 7) << " ";
+ tuple << PQgetvalue(result, i, 8) << " ";
+ tuple << PQgetvalue(result, i, 9) << " ";
+
+ tuple >> dir;
+ tuple >> td->dirPrice[dir].priceDayA;
+ td->dirPrice[dir].priceDayA /= 1024 * 1024;
+ tuple >> td->dirPrice[dir].priceDayB;
+ td->dirPrice[dir].priceDayB /= 1024 * 1024;
+ tuple >> td->dirPrice[dir].priceNightA;
+ td->dirPrice[dir].priceNightA /= 1024 * 1024;
+ tuple >> td->dirPrice[dir].priceNightB;
+ td->dirPrice[dir].priceNightB /= 1024 * 1024;
+ tuple >> td->dirPrice[dir].threshold;
+ tuple >> td->dirPrice[dir].hDay;
+ tuple >> td->dirPrice[dir].mDay;
+ tuple >> td->dirPrice[dir].hNight;
+ tuple >> td->dirPrice[dir].mNight;
+ }
+
+ if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
+ std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
+ {
+ td->dirPrice[dir].singlePrice = true;
+ }
+ else
+ {
+ td->dirPrice[dir].singlePrice = false;
+ }
+ if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
+ {
+ td->dirPrice[dir].noDiscount = true;
+ }
+ else
+ {
+
+ td->dirPrice[dir].noDiscount = false;
+ }
+
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * User manipulation methods
+ *
+ * $Revision: 1.14 $
+ * $Date: 2010/05/07 07:26:36 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/user_ips.h"
+#include "stg/user_traff.h"
+#include "stg/common.h"
+#include "stg/const.h"
+#include "stg/locker.h"
+#include "../../../stg_timer.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+#include <libpq-fe.h>
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+result = PQexec(connection, "SELECT name FROM tb_users");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ usersList->push_back(PQgetvalue(result, i, 0));
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddUser(const std::string & name) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = name;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT sp_add_user('" << elogin << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelUser(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "DELETE FROM tb_users WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserStat(const STG::UserStat & stat,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+return SaveStat(stat, login);
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveStat(const STG::UserStat & stat,
+ const std::string & login,
+ int year,
+ int month) const
+{
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "UPDATE tb_users SET "
+ "cash = " << stat.cash << ", "
+ "free_mb = " << stat.freeMb << ", "
+ "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), "
+ "last_cash_add = " << stat.lastCashAdd << ", "
+ "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), "
+ "passive_time = " << stat.passiveTime << " "
+ "WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+std::string date;
+
+MakeDate(date, year, month);
+
+for (int dir = 0; dir < DIR_NUM; ++dir)
+ {
+ query.str("");
+ query << "SELECT sp_add_stats_traffic ("
+ "'" << elogin << "', "
+ "CAST('" << date << "' AS DATE), "
+ "CAST(" << dir << " AS SMALLINT), "
+ "CAST(" << stat.monthUp[dir] << " AS BIGINT), "
+ "CAST(" << stat.monthDown[dir] << " AS BIGINT))";
+
+ result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserConf(const STG::UserConf & conf,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch user's ID";
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+uint32_t uid;
+
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, 0, 0);
+
+ PQclear(result);
+
+ tuple >> uid;
+ }
+
+std::string eaddress = conf.address;
+std::string eemail = conf.email;
+std::string egroup = conf.group;
+std::string enote = conf.note;
+std::string epassword = conf.password;
+std::string ephone = conf.phone;
+std::string erealname = conf.realName;
+std::string etariffname = conf.tariffName;
+std::string enexttariff = conf.nextTariff;
+std::string ecorporation = conf.corp;
+
+if (EscapeString(eaddress))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape address'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(eemail))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape email'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(egroup))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape group'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(enote))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape note'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(epassword))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape password'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(ephone))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape phone'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(erealname))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape real name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(etariffname))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape tariff name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(enexttariff))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape next tariff name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(ecorporation))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape corporation name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+query.str("");
+query << "UPDATE tb_users SET "
+ "address = '" << eaddress << "', "
+ "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
+ "credit = " << conf.credit << ", "
+ "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), "
+ "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
+ "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
+ "email = '" << eemail << "', "
+ "grp = '" << egroup << "', "
+ "note = '" << enote << "', "
+ "passive = " << (conf.passive ? "'t'" : "'f'") << ", "
+ "passwd = '" << epassword << "', "
+ "phone = '" << ephone << "', "
+ "real_name = '" << erealname << "', "
+ "fk_tariff = (SELECT pk_tariff "
+ "FROM tb_tariffs "
+ "WHERE name = '" << etariffname << "'), "
+ "fk_tariff_change = (SELECT pk_tariff "
+ "FROM tb_tariffs "
+ "WHERE name = '" << enexttariff << "'), "
+ "fk_corporation = (SELECT pk_corporation "
+ "FROM tb_corporations "
+ "WHERE name = '" << ecorporation << "') "
+ "WHERE pk_user = " << uid;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (SaveUserServices(uid, conf.services))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (SaveUserData(uid, conf.userdata))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's data'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (SaveUserIPs(uid, conf.ips))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's IPs'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreUserStat(STG::UserStat * stat,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ {
+ std::ostringstream query;
+ query << "SELECT cash, free_mb, "
+ "last_activity_time, last_cash_add, "
+ "last_cash_add_time, passive_time "
+ "FROM tb_users "
+ "WHERE name = '" << elogin << "'";
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch user's stat";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, 0, 0) << " ";
+ tuple << PQgetvalue(result, 0, 1) << " ";
+ stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2));
+ tuple << PQgetvalue(result, 0, 3) << " ";
+ stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4));
+ tuple << PQgetvalue(result, 0, 5) << " ";
+
+ PQclear(result);
+
+ tuple >> stat->cash
+ >> stat->freeMb
+ >> stat->lastCashAdd
+ >> stat->passiveTime;
+ }
+
+ {
+ std::ostringstream query;
+ query << "SELECT dir_num, upload, download "
+ "FROM tb_stats_traffic "
+ "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND "
+ "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))";
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, i, 0) << " ";
+ tuple << PQgetvalue(result, i, 1) << " ";
+ tuple << PQgetvalue(result, i, 2) << " ";
+
+ int dir;
+
+ tuple >> dir;
+ tuple >> stat->monthUp[dir];
+ tuple >> stat->monthDown[dir];
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreUserConf(STG::UserConf * conf,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ {
+ std::ostringstream query;
+ query << "SELECT tb_users.pk_user, tb_users.address, tb_users.always_online, "
+ "tb_users.credit, tb_users.credit_expire, tb_users.disabled, "
+ "tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, "
+ "tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, "
+ "tb_users.real_name, tf1.name, tf2.name, tb_corporations.name "
+ "FROM tb_users LEFT JOIN tb_tariffs AS tf1 "
+ "ON tf1.pk_tariff = tb_users.fk_tariff "
+ "LEFT JOIN tb_tariffs AS tf2 "
+ "ON tf2.pk_tariff = tb_users.fk_tariff_change "
+ "LEFT JOIN tb_corporations "
+ "ON tb_corporations.pk_corporation = tb_users.fk_corporation "
+ "WHERE tb_users.name = '" << elogin << "'";
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch user's stat";
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+uint32_t uid;
+
+ {
+ std::stringstream tuple;
+ tuple << PQgetvalue(result, 0, 0) << " "; // uid
+ conf->address = PQgetvalue(result, 0, 1); // address
+ conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1);
+ tuple << PQgetvalue(result, 0, 3) << " "; // credit
+ conf->creditExpire = readTime(PQgetvalue(result, 0, 4)); // creditExpire
+ conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1);
+ conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1);
+ conf->email = PQgetvalue(result, 0, 7); // email
+ conf->group = PQgetvalue(result, 0, 8); // group
+ conf->note = PQgetvalue(result, 0, 9); // note
+ conf->passive = !strncmp(PQgetvalue(result, 0, 10), "t", 1);
+ conf->password = PQgetvalue(result, 0, 11); // password
+ conf->phone = PQgetvalue(result, 0, 12); // phone
+ conf->realName = PQgetvalue(result, 0, 13); // realName
+ conf->tariffName = PQgetvalue(result, 0, 14); // tariffName
+ conf->nextTariff = PQgetvalue(result, 0, 15); // nextTariff
+ conf->corp = PQgetvalue(result, 0, 16); // corp
+
+ PQclear(result);
+
+ if (conf->tariffName == "")
+ conf->tariffName = NO_TARIFF_NAME;
+ if (conf->corp == "")
+ conf->corp = NO_CORP_NAME;
+
+ tuple >> uid
+ >> conf->credit;
+ }
+
+ {
+ std::ostringstream query;
+ query << "SELECT name FROM tb_services "
+ "WHERE pk_service IN (SELECT fk_service "
+ "FROM tb_users_services "
+ "WHERE fk_user = " << uid << ")";
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ conf->services.push_back(PQgetvalue(result, i, 0));
+ }
+
+PQclear(result);
+
+ {
+ std::ostringstream query;
+ query << "SELECT num, data "
+ "FROM tb_users_data "
+ "WHERE fk_user = " << uid;
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+ {
+ int num;
+ if (str2x(PQgetvalue(result, i, 0), num))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to convert string to int'\n");
+ }
+ else
+ {
+ if (num < USERDATA_NUM &&
+ num >= 0)
+ {
+ conf->userdata[num] = PQgetvalue(result, i, 1);
+ }
+ }
+ }
+
+PQclear(result);
+
+ {
+ std::ostringstream query;
+ query << "SELECT host(ip), masklen(ip) "
+ "FROM tb_allowed_ip "
+ "WHERE fk_user = " << uid;
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+tuples = PQntuples(result);
+
+STG::UserIPs ips;
+for (int i = 0; i < tuples; ++i)
+ {
+ STG::IPMask im;
+
+ im.ip = inet_strington(PQgetvalue(result, i, 0));
+
+ if (str2x(PQgetvalue(result, i, 1), im.mask))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to fetch mask'\n");
+ continue;
+ }
+
+ ips.add(im);
+ }
+conf->ips = ips;
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteUserChgLog(const std::string & login,
+ const std::string & admLogin,
+ uint32_t admIP,
+ const std::string & paramName,
+ const std::string & oldValue,
+ const std::string & newValue,
+ const std::string & message = "") const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin(login);
+std::string eadminLogin(admLogin);
+std::string eparam(paramName);
+std::string eold(oldValue);
+std::string enew(newValue);
+std::string emessage(message);
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(eadminLogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape admin's login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(eparam))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape param's name'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(eold))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape old value'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+if (EscapeString(enew))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape new value'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+query << "SELECT sp_add_param_log_entry("
+ "'" << elogin << "', "
+ "'" << eadminLogin << "', CAST('"
+ << inet_ntostring(admIP) << "/32' AS INET), "
+ "'" << eparam << "', "
+ "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
+ "'" << eold << "', "
+ "'" << enew << "', "
+ "'" << emessage << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin(login);
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::ostringstream query;
+if (version < 6)
+ {
+ query << "SELECT sp_add_session_log_entry("
+ "'" << elogin << "', "
+ "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
+ "'c', CAST('"
+ << inet_ntostring(ip) << "/32' AS INET), 0)";
+ }
+else
+ {
+ query << "SELECT sp_add_session_log_entry("
+ "'" << elogin << "', "
+ "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
+ "'c', CAST('"
+ << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
+ }
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteUserDisconnect(const std::string & login,
+ const STG::DirTraff & monthUp,
+ const STG::DirTraff & monthDown,
+ const STG::DirTraff & sessionUp,
+ const STG::DirTraff & sessionDown,
+ double cash,
+ double freeMb,
+ const std::string & reason) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+PGresult * result;
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin(login);
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+std::string ereason(reason);
+
+if (EscapeString(ereason))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape reason'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ {
+ std::ostringstream query;
+ if (version < 6)
+ {
+ // Old database version - no freeMb logging support
+ query << "SELECT sp_add_session_log_entry("
+ "'" << elogin << "', "
+ "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
+ "'d', CAST('0.0.0.0/0' AS INET), "
+ << cash << ")";
+ }
+ else
+ {
+ query << "SELECT sp_add_session_log_entry("
+ "'" << elogin << "', "
+ "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
+ "'d', CAST('0.0.0.0/0' AS INET), "
+ << cash << ", " << freeMb << ", '" << ereason << "')";
+ }
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+ {
+ strError = "Failed to fetch session's log ID";
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+uint32_t lid;
+
+if (str2x(PQgetvalue(result, 0, 0), lid))
+ {
+ strError = "Failed to convert string to int";
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+ PQclear(result);
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+PQclear(result);
+
+for (int i = 0; i < DIR_NUM; ++i)
+ {
+ std::ostringstream query;
+ query << "INSERT INTO tb_sessions_data "
+ "(fk_session_log, "
+ "dir_num, "
+ "session_upload, "
+ "session_download, "
+ "month_upload, "
+ "month_download)"
+ "VALUES ("
+ << lid << ", "
+ << i << ", "
+ << sessionUp[i] << ", "
+ << sessionDown[i] << ", "
+ << monthUp[i] << ", "
+ << monthDown[i] << ")";
+
+ result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
+ time_t lastStat,
+ const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+if (PQstatus(connection) != CONNECTION_OK)
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+ if (Reset())
+ {
+ strError = "Connection lost";
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
+ return -1;
+ }
+ }
+
+if (StartTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to start transaction'\n");
+ return -1;
+ }
+
+std::string elogin(login);
+
+if (EscapeString(elogin))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to escape login'\n");
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+STG::TraffStat::const_iterator it;
+time_t currTime = time(NULL);
+
+for (it = statTree.begin(); it != statTree.end(); ++it)
+ {
+ std::ostringstream query;
+ query << "INSERT INTO tb_detail_stats "
+ "(till_time, from_time, fk_user, "
+ "dir_num, ip, download, upload, cost) "
+ "VALUES ("
+ "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
+ "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
+ "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
+ << it->first.dir << ", "
+ << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
+ << it->second.down << ", "
+ << it->second.up << ", "
+ << it->second.cash << ")";
+
+ PGresult * result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
+ if (RollbackTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
+ }
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+if (CommitTransaction())
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to commit transaction'\n");
+ return -1;
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+
+return SaveStat(stat, login, year, month);
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserServices(uint32_t uid,
+ const std::vector<std::string> & services) const
+{
+PGresult * result;
+
+ {
+ std::ostringstream query;
+ query << "DELETE FROM tb_users_services WHERE fk_user = " << uid;
+
+ result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+std::vector<std::string>::const_iterator it;
+
+for (it = services.begin(); it != services.end(); ++it)
+ {
+ std::string ename = *it;
+
+ if (EscapeString(ename))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): 'Failed to escape service name'\n");
+ return -1;
+ }
+
+ std::ostringstream query;
+ query << "INSERT INTO tb_users_services "
+ "(fk_user, fk_service) "
+ "VALUES "
+ "(" << uid << ", "
+ "(SELECT pk_service "
+ "FROM tb_services "
+ "WHERE name = '" << ename << "'))";
+
+ result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserIPs(uint32_t uid,
+ const STG::UserIPs & ips) const
+{
+PGresult * result;
+
+ {
+ std::ostringstream query;
+ query << "DELETE FROM tb_allowed_ip WHERE fk_user = " << uid;
+
+ result = PQexec(connection, query.str().c_str());
+ }
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+PQclear(result);
+
+for (size_t i = 0; i < ips.count(); ++i)
+ {
+ std::ostringstream query;
+ query << "INSERT INTO tb_allowed_ip "
+ "(fk_user, ip) "
+ "VALUES "
+ "(" << uid << ", CAST('"
+ << inet_ntostring(ips[i].ip) << "/"
+ << static_cast<int>(ips[i].mask) << "' AS INET))";
+
+ result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserData(uint32_t uid,
+ const std::vector<std::string> & data) const
+{
+for (unsigned i = 0; i < data.size(); ++i)
+ {
+ std::string edata = data[i];
+
+ if (EscapeString(edata))
+ {
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): 'Failed to escape userdata field'\n");
+ return -1;
+ }
+
+ PGresult * result;
+
+ std::ostringstream query;
+ query << "SELECT sp_set_user_data("
+ << uid << ", "
+ << "CAST(" << i << " AS SMALLINT), "
+ << "'" << edata << "')";
+
+ result = PQexec(connection, query.str().c_str());
+
+ if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+ PQclear(result);
+ }
+
+return 0;
+}
+
--- /dev/null
+/*
+ * 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>
+ */
+
+/*
+ * Vairous utility methods
+ *
+ * $Revision: 1.3 $
+ * $Date: 2009/10/22 10:01:08 $
+ *
+ */
+
+#include "postgresql_store.h"
+
+#include "stg/common.h"
+
+#include <string>
+#include <ctime>
+
+#include <libpq-fe.h>
+
+extern volatile time_t stgTime;
+
+int POSTGRESQL_STORE::StartTransaction() const
+{
+PGresult * result = PQexec(connection, "BEGIN");
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::StartTransaction(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+PQclear(result);
+
+return 0;
+}
+
+int POSTGRESQL_STORE::CommitTransaction() const
+{
+PGresult * result = PQexec(connection, "COMMIT");
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::CommitTransaction(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+PQclear(result);
+
+return 0;
+}
+
+int POSTGRESQL_STORE::RollbackTransaction() const
+{
+PGresult * result = PQexec(connection, "ROLLBACK");
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ strError = PQresultErrorMessage(result);
+ PQclear(result);
+ printfd(__FILE__, "POSTGRESQL_STORE::RollbackTransaction(): '%s'\n", strError.c_str());
+ return -1;
+ }
+
+PQclear(result);
+
+return 0;
+}
+
+int POSTGRESQL_STORE::EscapeString(std::string & value) const
+{
+int error = 0;
+char * buf = new char[(value.length() << 1) + 1];
+
+PQescapeStringConn(connection,
+ buf,
+ value.c_str(),
+ value.length(),
+ &error);
+
+if (error)
+ {
+ strError = PQerrorMessage(connection);
+ printfd(__FILE__, "POSTGRESQL_STORE::EscapeString(): '%s'\n", strError.c_str());
+ delete[] buf;
+ return -1;
+ }
+
+value = buf;
+
+delete[] buf;
+return 0;
+}
+
+void POSTGRESQL_STORE::MakeDate(std::string & date, int year, int month) const
+{
+struct tm brokenTime;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+if (year)
+ {
+ brokenTime.tm_hour = 0;
+ brokenTime.tm_min = 0;
+ brokenTime.tm_sec = 0;
+ brokenTime.tm_year = year;
+ brokenTime.tm_mon = month;
+ }
+else
+ {
+ time_t curTime = stgTime;
+ localtime_r(&curTime, &brokenTime);
+ }
+
+brokenTime.tm_mday = DaysInMonth(brokenTime.tm_year + 1900, brokenTime.tm_mon);
+
+char buf[32];
+
+strftime(buf, 32, "%Y-%m-%d", &brokenTime);
+
+date = buf;
+}
--- /dev/null
+#ifndef POSTGRESQL_UTILS_STORE_H
+#define POSTGRESQL_UTILS_STORE_H
+
+#include <functional>
+
+struct ToLower : public std::unary_function<char, char>
+{
+char operator() (char c) const { return static_cast<char>(std::tolower(c)); }
+};
+
+#endif
--- /dev/null
+#!/bin/bash
+
+# Этот скрипт производит очистку файловой БД stargazer-а.
+# Его можно вызывать вручную или покрону, к примеру раз в неделю или раз в месяц.
+
+
+# Эта переменная задает сколько месяцев детальной статистики оставить в БД
+SAVE_MONTHS=3
+
+# Эта переменная задает сколько строк оставить в логах юзеров
+MAX_LOG_LINES=5000
+
+# Тут определяется путь к БД
+DB=/var/stargazer/
+
+
+
+
+declare -i NOW=`date +%s`
+declare -i DT=SAVE_MONTHS*31*24*3600
+declare -i stat_time=0
+
+for usr in $DB/users/*
+do
+ echo cleaning `basename $usr`
+ for ys in $usr/detail_stat/*
+ do
+ year=`basename $ys`
+
+ for ms in $ys/*
+ do
+ month=`basename $ms`
+ stat_time=`date --date="$year/$month/01" +%s`
+
+ if (( $NOW - $stat_time > $DT ))
+ then
+ rm -fr $ms
+ fi
+ done
+ done
+ tail -n $MAX_LOG_LINES $usr/log > /tmp/stg_usr_log.`basename $usr`
+ mv -f /tmp/stg_usr_log.`basename $usr` $usr/log
+done
+
--- /dev/null
+#!/bin/bash
+
+# Данный скрипт производит мониторинг СТГ-сервера на зависание и в
+# случае его зависания перезапускает.
+# Для работы скрипта в настройках СТГ должен быть указан параметер
+# MonitorDir
+# Скрипт отрабатывает один раз и выходит. Т.е. он не работает постоянно
+# и следит за СТГ. Его нужно вызывать по крону или как-то еще с нужной
+# периодичностью!!!
+
+
+# Путь к файлам монитора. Должен совпадать со значением MonitorDir
+# в настройках сервера
+MONITOR_DIR=/var/stargazer/monitor/
+
+
+# Максимальная задержка обновления файлов монитора в секундах.
+# При привышении этого значения сервер считается зависшим и будет
+# перезапущен
+DT=300
+
+
+
+
+declare -i now=`date +%s`
+declare -i DT=300
+declare -i file_time=0
+
+stg_running=`ps ax | grep stargazer`
+if [ -z "$stg_running" ]
+then
+ echo "Stargazer is not running"
+ exit 0
+fi
+
+#wakeuper for traffcounter
+ping -c 1 127.0.0.1 > /dev/null
+sleep 1
+
+for mon in $MONITOR_DIR/*
+do
+ if [ ! -r $mon ]
+ then
+ echo "no monitor files"
+ exit 0
+ fi
+ file_time=`stat -c%Y $mon`
+
+ if (( $now - $file_time > $DT ))
+ then
+ echo "Stargazer is deadlocked!"
+
+ # Команда остаовки СТГ
+ killall -KILL stargazer
+
+ rm -f $MONITOR_DIR/*
+ sleep 15
+
+ # Команда запуска СТГ
+ /etc/init.d/stargazer start
+
+ fi
+
+done
+
+
--- /dev/null
+#!/bin/bash
+
+int_iface=eth1
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+default_speed=32kbit
+
+# =========== shaping by tariff ===========
+#tariff=$(grep -i "^tariff=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
+#echo "tariff=$tariff" > /var/stargazer/users/$LOGIN/connect.log
+#case $tariff in
+# minimum) speedkb=128kbit;; # 128 kbit
+# middle) speedkb=256kbit;; # 256 kbi
+# maximum) speedkb=512kbit;; # 512 kbit
+# *) speedkb=$default_speed;; # default speed
+#esac
+# ========= shaping by tariff end =========
+
+# ========= shaping by userdata0 ==========
+speedR=$(grep -i "^Userdata0=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
+speed=$(echo $speedR | grep "^[0-9]*[0-9]$")
+
+if [ -z "$speed" ]
+then
+ speedkb=$default_speed
+else
+ speedkb="$speed"kbit
+fi
+# ======= shaping by userdata0 end ========
+
+declare -i mark=$ID+10
+
+echo "$mark" > /var/stargazer/users/$LOGIN/shaper_mark
+echo "$speedkb" > /var/stargazer/users/$LOGIN/shaper_rate
+
+iptables -t mangle -A FORWARD -d $IP -j MARK --set-mark $mark
+
+tc class add dev $int_iface parent 1:1 classid 1:$mark htb rate $speedkb burst 40k
+tc filter add dev $int_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:$mark
+
--- /dev/null
+#!/bin/bash
+
+int_iface=eth1
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$4
+
+mark=$(cat /var/stargazer/users/$LOGIN/shaper_mark)
+rate=$(cat /var/stargazer/users/$LOGIN/shaper_rate)
+
+if [ -n "$mark" ]
+then
+ iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+ while [ $? == 0 ]
+ do
+ iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+ done
+fi
+
+tc filter del dev $int_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:$mark
+tc class del dev $int_iface parent 1:1 classid 1:$mark htb rate $rate burst 40k
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
+
--- /dev/null
+Настройка шейпера для STG в Linux.
+
+По мотивам форума:
+http://local.com.ua/forum/index.php?showtopic=7920
+
+Настройка сводится к указанию сетевого интерфейса, обращенного к пользователю
+в скриптах shaper.sh, shaper.stop.sh, OnConnect и OnDisconnect, и уточнению
+скоростоей и тарифов в скрипте OnConnect (если нужно).
+
+Скрипты сделаны для БД на файлах, однако, сделать их для БД на Firebird или
+MySQL не составит большого труда.
+
+В OnConnect есть два типа шейпинга.
+1. На основании тарифа. Т.е. для каждого тарифа у задана скорость и задано
+дефолтное значение, на случай отсутсвия тарифа в списке скоростей или
+забывчивости админа.
+2. На основании Userdata0. В этом поле просто прописывается число равное
+скорости в kbit/sec. Также есть дефолтное значение скорости в 32 kbit/sec
+на случай отсутсвия в Userdata0 корректного значения.
+
+В скрипте первый способ закомментирован. Для того чтобы выбрать один из них нужно
+либо удалить, либо закомментировать строчики между
+
+# ========= shaping by tariff ==========
+.........
+# ======= shaping by tariff end ========
+
+и
+
+# ========= shaping by userdata0 ==========
+.........
+# ======= shaping by userdata0 end ========
+
+
+и нужную часть расскоментировать, если она закомментрована.
+
+Скрипт shaper.sh должен быть выполнен один раз при загрузке системы.
+
+Интерфейс обращенный к пользователю определяется в переменной
+int_iface=
+(присутствует во всех 4-х файлах shaper.sh, shaper.stop.sh, OnConnect и
+OnDisconnect !!!)
+
+Скорость по умолчанию в OnConnect в переменной default_speed
+
+Зависимость скорости от тарифа задается в следующем фрагменте кода:
+case $tariff in
+ minimum) speedkb=128kbit;;
+ middle) speedkb=256kbit;;
+ maximum) speedkb=512kbit;;
+ *) speedkb=$default_speed;;
+esac
+
+Т.е. тут нужно вместо minimum, ... maximum подставить имена ваших тарифов
+и соотв. скорость. Пользователи с тарифами не указанными в списке будут иметь
+дефолтную скорость.
+
+Скорость ограничевается только для входящего тарафика, однако расширить
+эти скрипты для исходящего не составит труда.
--- /dev/null
+#!/bin/bash
+
+int_iface=eth1
+
+iptables -t mangle --flush
+
+tc qdisc add dev $int_iface root handle 1: htb
+tc class add dev $int_iface parent 1: classid 1:1 htb rate 100mbit ceil 100mbit burst 200k
+
--- /dev/null
+#!/bin/bash
+
+int_iface=eth1
+
+#iptables -t mangle --flush
+
+tc qdisc del dev $int_iface root handle 1: htb
+
--- /dev/null
+Настройка такой конфигурации происходит в 3 этапа:
+1. Настройка VPN с использованием pptpd;
+2. Настройка авторизации VPN через FreeRADIUS;
+3. Настройка шейпера;
+
+1. Настройка VPN
+
+Необходимо установить пакеты ppp и pptpd. Также необходима поддержка PPP в ядре:
+ Device Drivers --->
+ Network device support --->
+ <M> PPP (point-to-point protocol) support
+ <M> PPP support for sync tty ports
+ <M> PPP Deflate compression
+ <M> PPP BSD-Compress compression
+ <M> PPP MPPE compression (encryption) (EXPERIMENTAL)
+ <M> PPP over Ethernet (EXPERIMENTAL)
+В файле /etc/pptpd.conf прописываем файл настроек PPP (параметр option). Также
+указываем адреса сервера внутри сети VPN (параметр localip) и диапазон адресов
+клиентов (параметр remoteip). См. пример файла конфигурации.
+В настройках PPP указываем имя сервера (параметр name), параметры шифрования.
+Для использования шифрования MPPE необходима его поддержка в ядре. Кроме того,
+в процессе аутентификации MPPE использует MS-CHAPv2. По этому при
+использовании шифрования MPPE также необходимо указать необходимость
+поддержки MS-CHAPv2 клиентом. По желанию указываем proxyarp (для того чтобы
+клиенты в сети VPN "видели" друг друга) и defaultroute. Прописываем в файле
+/etc/ppp/chap-secrets тестового пользователя и проверяем работоспособность
+VPN.
+
+2. Настройка авторизации VPN через FreeRADIUS
+
+Необходимо установить пакет freeradius.
+Настройку сервера (файл radiusd.conf) проводим в соответствии с документацией
+на модуль rlm_stg.so (см. документацию на систему Stargazer).
+Настройку Stargazer с плагином для FreeRADIUS проводим в соответствиии с
+документацией на модуль mod_radius.so (см. документацию на систему Stargazer).
+В файле clients.conf, расположенном в дирректории с конфигурационными файлами
+FreeRADIUS, описываем, какие клиенты могут использовать FreeRADIUS.
+Рекомендуется заменить стандартный пароль, которым шифруется обмен информации
+с клиентом, "testing123" на что-то более приемлимое с точки зрения безопасности.
+После этого запускаем FreeRADIUS и удостоверяемся, что он работает строчкой
+"Mon Mar 31 16:06:17 2008 : Info: Ready to process requests." в журнале
+(обычно, /var/log/radius/radius.log). Если журнал FreeRADIUS не позволяет
+определить проблему - можно запустить сервер в отладочном режме с ключем -X.
+В этом режиме более детальное журналирование проводится в консоль.
+Если на данном этапе все работает - в файл насттроек PPP прописываем строчку
+plugin radius.so. После этого VPN должен нормально авторизоваться
+пользователями системы Stargazer.
+
+3. Настройка шейпера
+
+Собственно настройки шейпер не требует. Всё, что нужно прописано в скриптах
+OnConnect и OnDisconnect. Шейпер предназначен для работы с хранилищем на
+файлах, однако, переделать скипт под MySQL или Firebird не составит труда.
+Скорость для пользоватлея задается в поле Userdata0 в kbit/sec. В этом поле
+должно быть прописано просто число без всяких kbit/sec и т.п. Если в этом поле
+у пользователя нет данных или стоит некорректное значение, пользователь будет
+ограничен скоростью определенной в переменной default_speed в скрипте
+OnConnect.
--- /dev/null
+#!/bin/bash
+
+#adsl-start
+
+modprobe ip_queue
+
+int_addr=10.0.0.2
+ext_addr=192.168.1.34
+
+int_net=10.0.0.0/16
+ext_net=192.168.1.0/24
+
+echo 1 > /proc/sys/net/ipv4/ip_forward
+
+iptables -P INPUT DROP
+iptables -P OUTPUT ACCEPT
+iptables -P FORWARD ACCEPT
+
+iptables -t nat -F
+iptables -t filter -F
+
+#
+#iptables -A INPUT -d $ip1 -j ACCEPT
+#iptables -A OUTPUT -s $ip1 -j ACCEPT
+
+# Разрешам говорить самому с собой
+iptables -A INPUT -d 127.0.0.1 -j ACCEPT
+iptables -A OUTPUT -s 127.0.0.1 -j ACCEPT
+
+#iptables -A INPUT -d $ip4 -j ACCEPT
+#iptables -A INPUT -s $ip4 -j ACCEPT
+#iptables -A OUTPUT -s $ip4 -j ACCEPT
+#iptables -A OUTPUT -d $ip4 -j ACCEPT
+
+iptables -A INPUT -p icmp -j ACCEPT
+iptables -A OUTPUT -p icmp -j ACCEPT
+
+iptables -A INPUT -p 47 -j ACCEPT
+iptables -A FORWARD -p 47 -j ACCEPT
+iptables -A OUTPUT -p 47 -j ACCEPT
+
+#SSH On this machine
+iptables -A INPUT -p tcp -d $int_addr --dport 22 -j ACCEPT
+iptables -A OUTPUT -p tcp -s $int_addr --sport 22 -j ACCEPT
+iptables -A INPUT -p tcp -d $ext_addr --dport 22 -j ACCEPT
+iptables -A OUTPUT -p tcp -s $ext_addr --sport 22 -j ACCEPT
+
+#WEB On this machine
+#iptables -A INPUT -p tcp -d $ip2 --dport 80 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 --sport 80 -j ACCEPT
+#iptables -A INPUT -p tcp -d $ip3 --dport 80 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 --sport 80 -j ACCEPT
+
+#PPTP
+iptables -A INPUT -p tcp --dport 1723 -j ACCEPT
+iptables -A OUTPUT -p tcp --sport 1723 -j ACCEPT
+iptables -A INPUT -p udp --dport 1723 -j ACCEPT
+iptables -A OUTPUT -p udp --sport 1723 -j ACCEPT
+
+#FTP
+#iptables -A INPUT -p tcp -d $ip2 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 -j ACCEPT
+#iptables -A INPUT -p tcp -d $ip3 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 -j ACCEPT
+
+#iptables -A INPUT -p tcp -d $ip2 --dport 20:21 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 --sport 20:21 -j ACCEPT
+#iptables -A INPUT -p tcp -d $ip3 --dport 20:21 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 --sport 20:21 -j ACCEPT
+
+#iptables -A INPUT -p tcp -d $ip2 --dport 1024:65535 --sport 1024:65535 -j ACCEPT
+#iptables -A INPUT -p tcp -d $ip3 --dport 1024:65535 --sport 1024:65535 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 --sport 1024:65535 --dport 1024:65535 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 --sport 1024:65535 --dport 1024:65535 -j ACCEPT
+
+#DNS
+iptables -A INPUT -p tcp --sport 53 -j ACCEPT
+iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
+iptables -A INPUT -p udp --sport 53 -j ACCEPT
+iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
+
+#iptables -t nat -A PREROUTING -p tcp -d $ip1 --dport 80 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -d $ip2 --dport 80 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -d $ip3 --dport 80 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -d $ip4 --dport 80 -j ACCEPT
+
+#iptables -t nat -A PREROUTING -p tcp -s 192.168.1.7 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -s 192.168.1.16 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3128
+
+iptables -t nat -A POSTROUTING -d 0.0.0.0/0 -s 192.168.2.0/24 -j MASQUERADE
+
+
+
--- /dev/null
+#
+# clients.conf - client configuration directives
+#
+#######################################################################
+
+#######################################################################
+#
+# Definition of a RADIUS client (usually a NAS).
+#
+# The information given here over rides anything given in the
+# 'clients' file, or in the 'naslist' file. The configuration here
+# contains all of the information from those two files, and allows
+# for more configuration items.
+#
+# The "shortname" is be used for logging. The "nastype", "login" and
+# "password" fields are mainly used for checkrad and are optional.
+#
+
+#
+# Defines a RADIUS client. The format is 'client [hostname|ip-address]'
+#
+# '127.0.0.1' is another name for 'localhost'. It is enabled by default,
+# to allow testing of the server after an initial installation. If you
+# are not going to be permitting RADIUS queries from localhost, we suggest
+# that you delete, or comment out, this entry.
+#
+client 127.0.0.1 {
+ #
+ # The shared secret use to "encrypt" and "sign" packets between
+ # the NAS and FreeRADIUS. You MUST change this secret from the
+ # default, otherwise it's not a secret any more!
+ #
+ # The secret can be any string, up to 31 characters in length.
+ #
+ secret = testing123
+
+ #
+ # The short name is used as an alias for the fully qualified
+ # domain name, or the IP address.
+ #
+ shortname = localhost
+
+ #
+ # the following three fields are optional, but may be used by
+ # checkrad.pl for simultaneous use checks
+ #
+
+ #
+ # The nastype tells 'checkrad.pl' which NAS-specific method to
+ # use to query the NAS for simultaneous use.
+ #
+ # Permitted NAS types are:
+ #
+ # cisco
+ # computone
+ # livingston
+ # max40xx
+ # multitech
+ # netserver
+ # pathras
+ # patton
+ # portslave
+ # tc
+ # usrhiper
+ # other # for all other types
+
+ #
+ nastype = other # localhost isn't usually a NAS...
+
+ #
+ # The following two configurations are for future use.
+ # The 'naspasswd' file is currently used to store the NAS
+ # login name and password, which is used by checkrad.pl
+ # when querying the NAS for simultaneous use.
+ #
+# login = !root
+# password = someadminpas
+}
--- /dev/null
+##
+## radiusd.conf -- FreeRADIUS server configuration file.
+##
+## http://www.freeradius.org/
+## $Id: radiusd.conf,v 1.1 2008/03/31 13:54:59 faust Exp $
+##
+
+# The location of other config files and
+# logfiles are declared in this file
+#
+# Also general configuration for modules can be done
+# in this file, it is exported through the API to
+# modules that ask for it.
+#
+# The configuration variables defined here are of the form ${foo}
+# They are local to this file, and do not change from request to
+# request.
+#
+# The per-request variables are of the form %{Attribute-Name}, and
+# are taken from the values of the attribute in the incoming
+# request. See 'doc/variables.txt' for more information.
+
+prefix = /usr
+exec_prefix = /usr
+sysconfdir = /etc
+localstatedir = /var
+sbindir = ${exec_prefix}/sbin
+logdir = /var/log/freeradius
+raddbdir = /etc/freeradius
+radacctdir = ${logdir}/radacct
+
+# Location of config and logfiles.
+confdir = ${raddbdir}
+run_dir = ${localstatedir}/run/freeradius
+
+#
+# The logging messages for the server are appended to the
+# tail of this file.
+#
+log_file = ${logdir}/radius.log
+
+#
+# libdir: Where to find the rlm_* modules.
+#
+# This should be automatically set at configuration time.
+#
+# If the server builds and installs, but fails at execution time
+# with an 'undefined symbol' error, then you can use the libdir
+# directive to work around the problem.
+#
+# The cause is usually that a library has been installed on your
+# system in a place where the dynamic linker CANNOT find it. When
+# executing as root (or another user), your personal environment MAY
+# be set up to allow the dynamic linker to find the library. When
+# executing as a daemon, FreeRADIUS MAY NOT have the same
+# personalized configuration.
+#
+# To work around the problem, find out which library contains that symbol,
+# and add the directory containing that library to the end of 'libdir',
+# with a colon separating the directory names. NO spaces are allowed.
+#
+# e.g. libdir = /usr/local/lib:/opt/package/lib
+#
+# You can also try setting the LD_LIBRARY_PATH environment variable
+# in a script which starts the server.
+#
+# If that does not work, then you can re-configure and re-build the
+# server to NOT use shared libraries, via:
+#
+# ./configure --disable-shared
+# make
+# make install
+#
+libdir = /usr/lib/freeradius
+
+# pidfile: Where to place the PID of the RADIUS server.
+#
+# The server may be signalled while it's running by using this
+# file.
+#
+# This file is written when ONLY running in daemon mode.
+#
+# e.g.: kill -HUP `cat /var/run/freeradius/freeradius.pid`
+#
+pidfile = ${run_dir}/freeradius.pid
+
+
+# user/group: The name (or #number) of the user/group to run radiusd as.
+#
+# If these are commented out, the server will run as the user/group
+# that started it. In order to change to a different user/group, you
+# MUST be root ( or have root privleges ) to start the server.
+#
+# We STRONGLY recommend that you run the server with as few permissions
+# as possible. That is, if you're not using shadow passwords, the
+# user and group items below should be set to 'nobody'.
+#
+# On SCO (ODT 3) use "user = nouser" and "group = nogroup".
+#
+# NOTE that some kernels refuse to setgid(group) when the value of
+# (unsigned)group is above 60000; don't use group nobody on these systems!
+#
+# On systems with shadow passwords, you might have to set 'group = shadow'
+# for the server to be able to read the shadow password file. If you can
+# authenticate users while in debug mode, but not in daemon mode, it may be
+# that the debugging mode server is running as a user that can read the
+# shadow info, and the user listed below can not.
+#
+user = freerad
+group = freerad
+
+# max_request_time: The maximum time (in seconds) to handle a request.
+#
+# Requests which take more time than this to process may be killed, and
+# a REJECT message is returned.
+#
+# WARNING: If you notice that requests take a long time to be handled,
+# then this MAY INDICATE a bug in the server, in one of the modules
+# used to handle a request, OR in your local configuration.
+#
+# This problem is most often seen when using an SQL database. If it takes
+# more than a second or two to receive an answer from the SQL database,
+# then it probably means that you haven't indexed the database. See your
+# SQL server documentation for more information.
+#
+# Useful range of values: 5 to 120
+#
+max_request_time = 30
+
+# delete_blocked_requests: If the request takes MORE THAN 'max_request_time'
+# to be handled, then maybe the server should delete it.
+#
+# If you're running in threaded, or thread pool mode, this setting
+# should probably be 'no'. Setting it to 'yes' when using a threaded
+# server MAY cause the server to crash!
+#
+delete_blocked_requests = no
+
+# cleanup_delay: The time to wait (in seconds) before cleaning up
+# a reply which was sent to the NAS.
+#
+# The RADIUS request is normally cached internally for a short period
+# of time, after the reply is sent to the NAS. The reply packet may be
+# lost in the network, and the NAS will not see it. The NAS will then
+# re-send the request, and the server will respond quickly with the
+# cached reply.
+#
+# If this value is set too low, then duplicate requests from the NAS
+# MAY NOT be detected, and will instead be handled as seperate requests.
+#
+# If this value is set too high, then the server will cache too many
+# requests, and some new requests may get blocked. (See 'max_requests'.)
+#
+# Useful range of values: 2 to 10
+#
+cleanup_delay = 5
+
+# max_requests: The maximum number of requests which the server keeps
+# track of. This should be 256 multiplied by the number of clients.
+# e.g. With 4 clients, this number should be 1024.
+#
+# If this number is too low, then when the server becomes busy,
+# it will not respond to any new requests, until the 'cleanup_delay'
+# time has passed, and it has removed the old requests.
+#
+# If this number is set too high, then the server will use a bit more
+# memory for no real benefit.
+#
+# If you aren't sure what it should be set to, it's better to set it
+# too high than too low. Setting it to 1000 per client is probably
+# the highest it should be.
+#
+# Useful range of values: 256 to infinity
+#
+max_requests = 1024
+
+# bind_address: Make the server listen on a particular IP address, and
+# send replies out from that address. This directive is most useful
+# for machines with multiple IP addresses on one interface.
+#
+# It can either contain "*", or an IP address, or a fully qualified
+# Internet domain name. The default is "*"
+#
+# As of 1.0, you can also use the "listen" directive. See below for
+# more information.
+#
+bind_address = *
+
+# port: Allows you to bind FreeRADIUS to a specific port.
+#
+# The default port that most NAS boxes use is 1645, which is historical.
+# RFC 2138 defines 1812 to be the new port. Many new servers and
+# NAS boxes use 1812, which can create interoperability problems.
+#
+# The port is defined here to be 0 so that the server will pick up
+# the machine's local configuration for the radius port, as defined
+# in /etc/services.
+#
+# If you want to use the default RADIUS port as defined on your server,
+# (usually through 'grep radius /etc/services') set this to 0 (zero).
+#
+# A port given on the command-line via '-p' over-rides this one.
+#
+# As of 1.0, you can also use the "listen" directive. See below for
+# more information.
+#
+port = 0
+
+#
+# By default, the server uses "bind_address" to listen to all IP's
+# on a machine, or just one IP. The "port" configuration is used
+# to select the authentication port used when listening on those
+# addresses.
+#
+# If you want the server to listen on additional addresses, you can
+# use the "listen" section. A sample section (commented out) is included
+# below. This "listen" section duplicates the functionality of the
+# "bind_address" and "port" configuration entries, but it only listens
+# for authentication packets.
+#
+# If you comment out the "bind_address" and "port" configuration entries,
+# then it becomes possible to make the server accept only accounting,
+# or authentication packets. Previously, it always listened for both
+# types of packets, and it was impossible to make it listen for only
+# one type of packet.
+#
+#listen {
+ # IP address on which to listen.
+ # Allowed values are:
+ # dotted quad (1.2.3.4)
+ # hostname (radius.example.com)
+ # wildcard (*)
+# ipaddr = *
+
+ # Port on which to listen.
+ # Allowed values are:
+ # integer port number (1812)
+ # 0 means "use /etc/services for the proper port"
+# port = 0
+
+ # Type of packets to listen for.
+ # Allowed values are:
+ # auth listen for authentication packets
+ # acct listen for accounting packets
+ #
+# type = auth
+#}
+
+
+# hostname_lookups: Log the names of clients or just their IP addresses
+# e.g., www.freeradius.org (on) or 206.47.27.232 (off).
+#
+# The default is 'off' because it would be overall better for the net
+# if people had to knowingly turn this feature on, since enabling it
+# means that each client request will result in AT LEAST one lookup
+# request to the nameserver. Enabling hostname_lookups will also
+# mean that your server may stop randomly for 30 seconds from time
+# to time, if the DNS requests take too long.
+#
+# Turning hostname lookups off also means that the server won't block
+# for 30 seconds, if it sees an IP address which has no name associated
+# with it.
+#
+# allowed values: {no, yes}
+#
+hostname_lookups = no
+
+# Core dumps are a bad thing. This should only be set to 'yes'
+# if you're debugging a problem with the server.
+#
+# allowed values: {no, yes}
+#
+allow_core_dumps = no
+
+# Regular expressions
+#
+# These items are set at configure time. If they're set to "yes",
+# then setting them to "no" turns off regular expression support.
+#
+# If they're set to "no" at configure time, then setting them to "yes"
+# WILL NOT WORK. It will give you an error.
+#
+regular_expressions = yes
+extended_expressions = yes
+
+# Log the full User-Name attribute, as it was found in the request.
+#
+# allowed values: {no, yes}
+#
+log_stripped_names = no
+
+# Log authentication requests to the log file.
+#
+# allowed values: {no, yes}
+#
+log_auth = no
+
+# Log passwords with the authentication requests.
+# log_auth_badpass - logs password if it's rejected
+# log_auth_goodpass - logs password if it's correct
+#
+# allowed values: {no, yes}
+#
+log_auth_badpass = no
+log_auth_goodpass = no
+
+# usercollide: Turn "username collision" code on and off. See the
+# "doc/duplicate-users" file
+#
+# WARNING
+# !!!!!!! Setting this to "yes" may result in the server behaving
+# !!!!!!! strangely. The "username collision" code will ONLY work
+# !!!!!!! with clear-text passwords. Even then, it may not do what
+# !!!!!!! you want, or what you expect.
+# !!!!!!!
+# !!!!!!! We STRONGLY RECOMMEND that you do not use this feature,
+# !!!!!!! and that you find another way of acheiving the same goal.
+# !!!!!!!
+# !!!!!!! e,g. module fail-over. See 'doc/configurable_failover'
+# WARNING
+#
+usercollide = no
+
+# lower_user / lower_pass:
+# Lower case the username/password "before" or "after"
+# attempting to authenticate.
+#
+# If "before", the server will first modify the request and then try
+# to auth the user. If "after", the server will first auth using the
+# values provided by the user. If that fails it will reprocess the
+# request after modifying it as you specify below.
+#
+# This is as close as we can get to case insensitivity. It is the
+# admin's job to ensure that the username on the auth db side is
+# *also* lowercase to make this work
+#
+# Default is 'no' (don't lowercase values)
+# Valid values = "before" / "after" / "no"
+#
+lower_user = no
+lower_pass = no
+
+# nospace_user / nospace_pass:
+#
+# Some users like to enter spaces in their username or password
+# incorrectly. To save yourself the tech support call, you can
+# eliminate those spaces here:
+#
+# Default is 'no' (don't remove spaces)
+# Valid values = "before" / "after" / "no" (explanation above)
+#
+nospace_user = no
+nospace_pass = no
+
+# The program to execute to do concurrency checks.
+checkrad = ${sbindir}/checkrad
+
+# SECURITY CONFIGURATION
+#
+# There may be multiple methods of attacking on the server. This
+# section holds the configuration items which minimize the impact
+# of those attacks
+#
+security {
+ #
+ # max_attributes: The maximum number of attributes
+ # permitted in a RADIUS packet. Packets which have MORE
+ # than this number of attributes in them will be dropped.
+ #
+ # If this number is set too low, then no RADIUS packets
+ # will be accepted.
+ #
+ # If this number is set too high, then an attacker may be
+ # able to send a small number of packets which will cause
+ # the server to use all available memory on the machine.
+ #
+ # Setting this number to 0 means "allow any number of attributes"
+ max_attributes = 200
+
+ #
+ # reject_delay: When sending an Access-Reject, it can be
+ # delayed for a few seconds. This may help slow down a DoS
+ # attack. It also helps to slow down people trying to brute-force
+ # crack a users password.
+ #
+ # Setting this number to 0 means "send rejects immediately"
+ #
+ # If this number is set higher than 'cleanup_delay', then the
+ # rejects will be sent at 'cleanup_delay' time, when the request
+ # is deleted from the internal cache of requests.
+ #
+ # Useful ranges: 1 to 5
+ reject_delay = 1
+
+ #
+ # status_server: Whether or not the server will respond
+ # to Status-Server requests.
+ #
+ # Normally this should be set to "no", because they're useless.
+ # See: http://www.freeradius.org/rfc/rfc2865.html#Keep-Alives
+ #
+ # However, certain NAS boxes may require them.
+ #
+ # When sent a Status-Server message, the server responds with
+ # an Access-Accept packet, containing a Reply-Message attribute,
+ # which is a string describing how long the server has been
+ # running.
+ #
+ status_server = no
+}
+
+# PROXY CONFIGURATION
+#
+# proxy_requests: Turns proxying of RADIUS requests on or off.
+#
+# The server has proxying turned on by default. If your system is NOT
+# set up to proxy requests to another server, then you can turn proxying
+# off here. This will save a small amount of resources on the server.
+#
+# If you have proxying turned off, and your configuration files say
+# to proxy a request, then an error message will be logged.
+#
+# To disable proxying, change the "yes" to "no", and comment the
+# $INCLUDE line.
+#
+# allowed values: {no, yes}
+#
+proxy_requests = yes
+$INCLUDE ${confdir}/proxy.conf
+
+
+# CLIENTS CONFIGURATION
+#
+# Client configuration is defined in "clients.conf".
+#
+
+# The 'clients.conf' file contains all of the information from the old
+# 'clients' and 'naslist' configuration files. We recommend that you
+# do NOT use 'client's or 'naslist', although they are still
+# supported.
+#
+# Anything listed in 'clients.conf' will take precedence over the
+# information from the old-style configuration files.
+#
+$INCLUDE ${confdir}/clients.conf
+
+
+# SNMP CONFIGURATION
+#
+# Snmp configuration is only valid if SNMP support was enabled
+# at compile time.
+#
+# To enable SNMP querying of the server, set the value of the
+# 'snmp' attribute to 'yes'
+#
+snmp = no
+$INCLUDE ${confdir}/snmp.conf
+
+
+# THREAD POOL CONFIGURATION
+#
+# The thread pool is a long-lived group of threads which
+# take turns (round-robin) handling any incoming requests.
+#
+# You probably want to have a few spare threads around,
+# so that high-load situations can be handled immediately. If you
+# don't have any spare threads, then the request handling will
+# be delayed while a new thread is created, and added to the pool.
+#
+# You probably don't want too many spare threads around,
+# otherwise they'll be sitting there taking up resources, and
+# not doing anything productive.
+#
+# The numbers given below should be adequate for most situations.
+#
+thread pool {
+ # Number of servers to start initially --- should be a reasonable
+ # ballpark figure.
+ start_servers = 5
+
+ # Limit on the total number of servers running.
+ #
+ # If this limit is ever reached, clients will be LOCKED OUT, so it
+ # should NOT BE SET TOO LOW. It is intended mainly as a brake to
+ # keep a runaway server from taking the system with it as it spirals
+ # down...
+ #
+ # You may find that the server is regularly reaching the
+ # 'max_servers' number of threads, and that increasing
+ # 'max_servers' doesn't seem to make much difference.
+ #
+ # If this is the case, then the problem is MOST LIKELY that
+ # your back-end databases are taking too long to respond, and
+ # are preventing the server from responding in a timely manner.
+ #
+ # The solution is NOT do keep increasing the 'max_servers'
+ # value, but instead to fix the underlying cause of the
+ # problem: slow database, or 'hostname_lookups=yes'.
+ #
+ # For more information, see 'max_request_time', above.
+ #
+ max_servers = 32
+
+ # Server-pool size regulation. Rather than making you guess
+ # how many servers you need, FreeRADIUS dynamically adapts to
+ # the load it sees, that is, it tries to maintain enough
+ # servers to handle the current load, plus a few spare
+ # servers to handle transient load spikes.
+ #
+ # It does this by periodically checking how many servers are
+ # waiting for a request. If there are fewer than
+ # min_spare_servers, it creates a new spare. If there are
+ # more than max_spare_servers, some of the spares die off.
+ # The default values are probably OK for most sites.
+ #
+ min_spare_servers = 3
+ max_spare_servers = 10
+
+ # There may be memory leaks or resource allocation problems with
+ # the server. If so, set this value to 300 or so, so that the
+ # resources will be cleaned up periodically.
+ #
+ # This should only be necessary if there are serious bugs in the
+ # server which have not yet been fixed.
+ #
+ # '0' is a special value meaning 'infinity', or 'the servers never
+ # exit'
+ max_requests_per_server = 0
+}
+
+# MODULE CONFIGURATION
+#
+# The names and configuration of each module is located in this section.
+#
+# After the modules are defined here, they may be referred to by name,
+# in other sections of this configuration file.
+#
+modules {
+ #
+ # Each module has a configuration as follows:
+ #
+ # name [ instance ] {
+ # config_item = value
+ # ...
+ # }
+ #
+ # The 'name' is used to load the 'rlm_name' library
+ # which implements the functionality of the module.
+ #
+ # The 'instance' is optional. To have two different instances
+ # of a module, it first must be referred to by 'name'.
+ # The different copies of the module are then created by
+ # inventing two 'instance' names, e.g. 'instance1' and 'instance2'
+ #
+ # The instance names can then be used in later configuration
+ # INSTEAD of the original 'name'. See the 'radutmp' configuration
+ # below for an example.
+ #
+
+ # PAP module to authenticate users based on their stored password
+ #
+ # Supports multiple encryption schemes
+ # clear: Clear text
+ # crypt: Unix crypt
+ # md5: MD5 ecnryption
+ # sha1: SHA1 encryption.
+ # DEFAULT: crypt
+ pap {
+ encryption_scheme = crypt
+ }
+
+ # CHAP module
+ #
+ # To authenticate requests containing a CHAP-Password attribute.
+ #
+ chap {
+ authtype = CHAP
+ }
+
+ # Extensible Authentication Protocol
+ #
+ # For all EAP related authentications.
+ # Now in another file, because it is very large.
+ #
+$INCLUDE ${confdir}/eap.conf
+
+ # Microsoft CHAP authentication
+ #
+ # This module supports MS-CHAP and MS-CHAPv2 authentication.
+ # It also enforces the SMB-Account-Ctrl attribute.
+ #
+ mschap {
+ #
+ # As of 0.9, the mschap module does NOT support
+ # reading from /etc/smbpasswd.
+ #
+ # If you are using /etc/smbpasswd, see the 'passwd'
+ # module for an example of how to use /etc/smbpasswd
+
+ # if use_mppe is not set to no mschap will
+ # add MS-CHAP-MPPE-Keys for MS-CHAPv1 and
+ # MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2
+ #
+ use_mppe = yes
+ authtype = MS-CHAP
+
+ # if mppe is enabled require_encryption makes
+ # encryption moderate
+ #
+ #require_encryption = yes
+
+ # require_strong always requires 128 bit key
+ # encryption
+ #
+ #require_strong = yes
+
+ # Windows sends us a username in the form of
+ # DOMAIN\user, but sends the challenge response
+ # based on only the user portion. This hack
+ # corrects for that incorrect behavior.
+ #
+ #with_ntdomain_hack = no
+
+ # The module can perform authentication itself, OR
+ # use a Windows Domain Controller. This configuration
+ # directive tells the module to call the ntlm_auth
+ # program, which will do the authentication, and return
+ # the NT-Key. Note that you MUST have "winbindd" and
+ # "nmbd" running on the local machine for ntlm_auth
+ # to work. See the ntlm_auth program documentation
+ # for details.
+ #
+ # Be VERY careful when editing the following line!
+ #
+ #ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{Stripped-User-Name:-%{User-Name:-None}} --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00}"
+ }
+
+ # Preprocess the incoming RADIUS request, before handing it off
+ # to other modules.
+ #
+ # This module processes the 'huntgroups' and 'hints' files.
+ # In addition, it re-writes some weird attributes created
+ # by some NASes, and converts the attributes into a form which
+ # is a little more standard.
+ #
+ preprocess {
+ huntgroups = ${confdir}/huntgroups
+ hints = ${confdir}/hints
+
+ # This hack changes Ascend's wierd port numberings
+ # to standard 0-??? port numbers so that the "+" works
+ # for IP address assignments.
+ with_ascend_hack = no
+ ascend_channels_per_line = 23
+
+ # Windows NT machines often authenticate themselves as
+ # NT_DOMAIN\username
+ #
+ # If this is set to 'yes', then the NT_DOMAIN portion
+ # of the user-name is silently discarded.
+ #
+ # This configuration entry SHOULD NOT be used.
+ # See the "realms" module for a better way to handle
+ # NT domains.
+ with_ntdomain_hack = no
+
+ # Specialix Jetstream 8500 24 port access server.
+ #
+ # If the user name is 10 characters or longer, a "/"
+ # and the excess characters after the 10th are
+ # appended to the user name.
+ #
+ # If you're not running that NAS, you don't need
+ # this hack.
+ with_specialix_jetstream_hack = no
+
+ # Cisco (and Quintum in Cisco mode) sends it's VSA attributes
+ # with the attribute name *again* in the string, like:
+ #
+ # H323-Attribute = "h323-attribute=value".
+ #
+ # If this configuration item is set to 'yes', then
+ # the redundant data in the the attribute text is stripped
+ # out. The result is:
+ #
+ # H323-Attribute = "value"
+ #
+ # If you're not running a Cisco or Quintum NAS, you don't
+ # need this hack.
+ with_cisco_vsa_hack = no
+ }
+
+ # Write a detailed log of all accounting records received.
+ #
+ detail {
+ # Note that we do NOT use NAS-IP-Address here, as
+ # that attribute MAY BE from the originating NAS, and
+ # NOT from the proxy which actually sent us the
+ # request. The Client-IP-Address attribute is ALWAYS
+ # the address of the client which sent us the
+ # request.
+ #
+ # The following line creates a new detail file for
+ # every radius client (by IP address or hostname).
+ # In addition, a new detail file is created every
+ # day, so that the detail file doesn't have to go
+ # through a 'log rotation'
+ #
+ # If your detail files are large, you may also want
+ # to add a ':%H' (see doc/variables.txt) to the end
+ # of it, to create a new detail file every hour, e.g.:
+ #
+ # ..../detail-%Y%m%d:%H
+ #
+ # This will create a new detail file for every hour.
+ #
+ detailfile = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
+
+ #
+ # The Unix-style permissions on the 'detail' file.
+ #
+ # The detail file often contains secret or private
+ # information about users. So by keeping the file
+ # permissions restrictive, we can prevent unwanted
+ # people from seeing that information.
+ detailperm = 0600
+
+ #
+ # Certain attributes such as User-Password may be
+ # "sensitive", so they should not be printed in the
+ # detail file. This section lists the attributes
+ # that should be suppressed.
+ #
+ # The attributes should be listed one to a line.
+ #
+ #suppress {
+ # User-Password
+ #}
+ }
+
+ #
+ # Create a unique accounting session Id. Many NASes re-use
+ # or repeat values for Acct-Session-Id, causing no end of
+ # confusion.
+ #
+ # This module will add a (probably) unique session id
+ # to an accounting packet based on the attributes listed
+ # below found in the packet. See doc/rlm_acct_unique for
+ # more information.
+ #
+ acct_unique {
+ key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port"
+ }
+
+ # Write a 'utmp' style file, of which users are currently
+ # logged in, and where they've logged in from.
+ #
+ # This file is used mainly for Simultaneous-Use checking,
+ # and also 'radwho', to see who's currently logged in.
+ #
+ radutmp {
+ # Where the file is stored. It's not a log file,
+ # so it doesn't need rotating.
+ #
+ filename = ${logdir}/radutmp
+
+ # The field in the packet to key on for the
+ # 'user' name, If you have other fields which you want
+ # to use to key on to control Simultaneous-Use,
+ # then you can use them here.
+ #
+ # Note, however, that the size of the field in the
+ # 'utmp' data structure is small, around 32
+ # characters, so that will limit the possible choices
+ # of keys.
+ #
+ # You may want instead: %{Stripped-User-Name:-%{User-Name}}
+ username = %{User-Name}
+
+
+ # Whether or not we want to treat "user" the same
+ # as "USER", or "User". Some systems have problems
+ # with case sensitivity, so this should be set to
+ # 'no' to enable the comparisons of the key attribute
+ # to be case insensitive.
+ #
+ case_sensitive = yes
+
+ # Accounting information may be lost, so the user MAY
+ # have logged off of the NAS, but we haven't noticed.
+ # If so, we can verify this information with the NAS,
+ #
+ # If we want to believe the 'utmp' file, then this
+ # configuration entry can be set to 'no'.
+ #
+ check_with_nas = yes
+
+ # Set the file permissions, as the contents of this file
+ # are usually private.
+ perm = 0600
+
+ callerid = "yes"
+ }
+
+ # "Safe" radutmp - does not contain caller ID, so it can be
+ # world-readable, and radwho can work for normal users, without
+ # exposing any information that isn't already exposed by who(1).
+ #
+ # This is another 'instance' of the radutmp module, but it is given
+ # then name "sradutmp" to identify it later in the "accounting"
+ # section.
+ radutmp sradutmp {
+ filename = ${logdir}/sradutmp
+ perm = 0644
+ callerid = "no"
+ }
+
+ # attr_filter - filters the attributes received in replies from
+ # proxied servers, to make sure we send back to our RADIUS client
+ # only allowed attributes.
+ attr_filter {
+ attrsfile = ${confdir}/attrs
+ }
+
+ # counter module:
+ # This module takes an attribute (count-attribute).
+ # It also takes a key, and creates a counter for each unique
+ # key. The count is incremented when accounting packets are
+ # received by the server. The value of the increment depends
+ # on the attribute type.
+ # If the attribute is Acct-Session-Time or of an integer type we add the
+ # value of the attribute. If it is anything else we increase the
+ # counter by one.
+ #
+ # The 'reset' parameter defines when the counters are all reset to
+ # zero. It can be hourly, daily, weekly, monthly or never.
+ #
+ # hourly: Reset on 00:00 of every hour
+ # daily: Reset on 00:00:00 every day
+ # weekly: Reset on 00:00:00 on sunday
+ # monthly: Reset on 00:00:00 of the first day of each month
+ #
+ # It can also be user defined. It should be of the form:
+ # num[hdwm] where:
+ # h: hours, d: days, w: weeks, m: months
+ # If the letter is ommited days will be assumed. In example:
+ # reset = 10h (reset every 10 hours)
+ # reset = 12 (reset every 12 days)
+ #
+ #
+ # The check-name attribute defines an attribute which will be
+ # registered by the counter module and can be used to set the
+ # maximum allowed value for the counter after which the user
+ # is rejected.
+ # Something like:
+ #
+ # DEFAULT Max-Daily-Session := 36000
+ # Fall-Through = 1
+ #
+ # You should add the counter module in the instantiate
+ # section so that it registers check-name before the files
+ # module reads the users file.
+ #
+ # If check-name is set and the user is to be rejected then we
+ # send back a Reply-Message and we log a Failure-Message in
+ # the radius.log
+ # If the count attribute is Acct-Session-Time then on each login
+ # we send back the remaining online time as a Session-Timeout attribute
+ #
+ # The counter-name can also be used instead of using the check-name
+ # like below:
+ #
+ # DEFAULT Daily-Session-Time > 3600, Auth-Type = Reject
+ # Reply-Message = "You've used up more than one hour today"
+ #
+ # The allowed-servicetype attribute can be used to only take
+ # into account specific sessions. For example if a user first
+ # logs in through a login menu and then selects ppp there will
+ # be two sessions. One for Login-User and one for Framed-User
+ # service type. We only need to take into account the second one.
+ #
+ # The module should be added in the instantiate, authorize and
+ # accounting sections. Make sure that in the authorize
+ # section it comes after any module which sets the
+ # 'check-name' attribute.
+ #
+ counter daily {
+ filename = ${raddbdir}/db.daily
+ key = User-Name
+ count-attribute = Acct-Session-Time
+ reset = daily
+ counter-name = Daily-Session-Time
+ check-name = Max-Daily-Session
+ allowed-servicetype = Framed-User
+ cache-size = 5000
+ }
+
+ #
+ # The "always" module is here for debugging purposes. Each
+ # instance simply returns the same result, always, without
+ # doing anything.
+ always fail {
+ rcode = fail
+ }
+ always reject {
+ rcode = reject
+ }
+ always ok {
+ rcode = ok
+ simulcount = 0
+ mpp = no
+ }
+
+ stg {
+ local_port = 6667
+ server = localhost
+ port = 6666
+ password = 123456
+ }
+
+}
+
+# Instantiation
+#
+# This section orders the loading of the modules. Modules
+# listed here will get loaded BEFORE the later sections like
+# authorize, authenticate, etc. get examined.
+#
+# This section is not strictly needed. When a section like
+# authorize refers to a module, it's automatically loaded and
+# initialized. However, some modules may not be listed in any
+# of the following sections, so they can be listed here.
+#
+# Also, listing modules here ensures that you have control over
+# the order in which they are initalized. If one module needs
+# something defined by another module, you can list them in order
+# here, and ensure that the configuration will be OK.
+#
+instantiate {
+ stg
+}
+
+# Authorization. First preprocess (hints and huntgroups files),
+# then realms, and finally look in the "users" file.
+#
+# The order of the realm modules will determine the order that
+# we try to find a matching realm.
+#
+# Make *sure* that 'preprocess' comes before any realm if you
+# need to setup hints for the remote radius server
+authorize {
+ #
+ # The preprocess module takes care of sanitizing some bizarre
+ # attributes in the request, and turning them into attributes
+ # which are more standard.
+ #
+ # It takes care of processing the 'raddb/hints' and the
+ # 'raddb/huntgroups' files.
+ #
+ # It also adds the %{Client-IP-Address} attribute to the request.
+ preprocess
+
+ #
+ # The chap module will set 'Auth-Type := CHAP' if we are
+ # handling a CHAP request and Auth-Type has not already been set
+ chap
+
+ #
+ # If the users are logging in with an MS-CHAP-Challenge
+ # attribute for authentication, the mschap module will find
+ # the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP'
+ # to the request, which will cause the server to then use
+ # the mschap module for authentication.
+ mschap
+
+ #
+ # This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP
+ # authentication.
+ #
+ # It also sets the EAP-Type attribute in the request
+ # attribute list to the EAP type from the packet.
+ eap
+
+ stg
+}
+
+
+# Authentication.
+#
+#
+# This section lists which modules are available for authentication.
+# Note that it does NOT mean 'try each module in order'. It means
+# that a module from the 'authorize' section adds a configuration
+# attribute 'Auth-Type := FOO'. That authentication type is then
+# used to pick the apropriate module from the list below.
+#
+
+# In general, you SHOULD NOT set the Auth-Type attribute. The server
+# will figure it out on its own, and will do the right thing. The
+# most common side effect of erroneously setting the Auth-Type
+# attribute is that one authentication method will work, but the
+# others will not.
+#
+# The common reasons to set the Auth-Type attribute by hand
+# is to either forcibly reject the user, or forcibly accept him.
+#
+authenticate {
+ #
+ # PAP authentication, when a back-end database listed
+ # in the 'authorize' section supplies a password. The
+ # password can be clear-text, or encrypted.
+ Auth-Type PAP {
+ stg
+ pap
+ }
+
+ #
+ # Most people want CHAP authentication
+ # A back-end database listed in the 'authorize' section
+ # MUST supply a CLEAR TEXT password. Encrypted passwords
+ # won't work.
+ Auth-Type CHAP {
+ stg
+ chap
+ }
+
+ #
+ # MSCHAP authentication.
+ Auth-Type MS-CHAP {
+ stg
+ mschap
+ }
+
+ #
+ # Allow EAP authentication.
+ eap
+}
+
+
+#
+# Pre-accounting. Decide which accounting type to use.
+#
+preacct {
+ preprocess
+
+ #
+ # Ensure that we have a semi-unique identifier for every
+ # request, and many NAS boxes are broken.
+ acct_unique
+}
+
+#
+# Accounting. Log the accounting data.
+#
+accounting {
+ #
+ # Create a 'detail'ed log of the packets.
+ # Note that accounting requests which are proxied
+ # are also logged in the detail file.
+ detail
+# daily
+
+ #
+ # For Simultaneous-Use tracking.
+ #
+ # Due to packet losses in the network, the data here
+ # may be incorrect. There is little we can do about it.
+ radutmp
+
+ stg
+
+}
+
+
+# Session database, used for checking Simultaneous-Use. Either the radutmp
+# or rlm_sql module can handle this.
+# The rlm_sql module is *much* faster
+session {
+ radutmp
+}
+
+
+# Post-Authentication
+# Once we KNOW that the user has been authenticated, there are
+# additional steps we can take.
+post-auth {
+ stg
+}
+
+#
+# When the server decides to proxy a request to a home server,
+# the proxied request is first passed through the pre-proxy
+# stage. This stage can re-write the request, or decide to
+# cancel the proxy.
+#
+# Only a few modules currently have this method.
+#
+pre-proxy {
+}
+
+#
+# When the server receives a reply to a request it proxied
+# to a home server, the request may be massaged here, in the
+# post-proxy stage.
+#
+post-proxy {
+ #
+ # If you are proxying LEAP, you MUST configure the EAP
+ # module, and you MUST list it here, in the post-proxy
+ # stage.
+ #
+ # You MUST also use the 'nostrip' option in the 'realm'
+ # configuration. Otherwise, the User-Name attribute
+ # in the proxied request will not match the user name
+ # hidden inside of the EAP packet, and the end server will
+ # reject the EAP request.
+ #
+ eap
+}
--- /dev/null
+#!/bin/sh
+
+rm -f /var/stargazer/ifaces/$PPP_REMOTE
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+
+echo $PPP_IFACE > /var/stargazer/ifaces/$PPP_REMOTE
\ No newline at end of file
--- /dev/null
+###############################################################################
+# $Id: pptpd-options,v 1.1 2008/03/31 13:55:20 faust Exp $
+#
+# Sample Poptop PPP options file /etc/ppp/pptpd-options
+# Options used by PPP when a connection arrives from a client.
+# This file is pointed to by /etc/pptpd.conf option keyword.
+# Changes are effective on the next connection. See "man pppd".
+#
+# You are expected to change this file to suit your system. As
+# packaged, it requires PPP 2.4.2 and the kernel MPPE module.
+###############################################################################
+
+
+# Authentication
+
+# Name of the local system for authentication purposes
+# (must match the second field in /etc/ppp/chap-secrets entries)
+name pptpd
+
+# Optional: domain name to use for authentication
+# domain mydomain.net
+
+# Strip the domain prefix from the username before authentication.
+# (applies if you use pppd with chapms-strip-domain patch)
+#chapms-strip-domain
+
+
+# Encryption
+# Debian: on systems with a kernel built with the package
+# kernel-patch-mppe >= 2.4.2 and using ppp >= 2.4.2, ...
+# {{{
+refuse-pap
+refuse-chap
+refuse-mschap
+# Require the peer to authenticate itself using MS-CHAPv2 [Microsoft
+# Challenge Handshake Authentication Protocol, Version 2] authentication.
+require-mschap-v2
+# Require MPPE 128-bit encryption
+# (note that MPPE requires the use of MSCHAP-V2 during authentication)
+require-mppe-128
+# }}}
+
+
+
+
+# Network and Routing
+
+# If pppd is acting as a server for Microsoft Windows clients, this
+# option allows pppd to supply one or two DNS (Domain Name Server)
+# addresses to the clients. The first instance of this option
+# specifies the primary DNS address; the second instance (if given)
+# specifies the secondary DNS address.
+# Attention! This information may not be taken into account by a Windows
+# client. See KB311218 in Microsoft's knowledge base for more information.
+#ms-dns 10.0.0.1
+#ms-dns 10.0.0.2
+
+# If pppd is acting as a server for Microsoft Windows or "Samba"
+# clients, this option allows pppd to supply one or two WINS (Windows
+# Internet Name Services) server addresses to the clients. The first
+# instance of this option specifies the primary WINS address; the
+# second instance (if given) specifies the secondary WINS address.
+#ms-wins 10.0.0.3
+#ms-wins 10.0.0.4
+
+# Add an entry to this system's ARP [Address Resolution Protocol]
+# table with the IP address of the peer and the Ethernet address of this
+# system. This will have the effect of making the peer appear to other
+# systems to be on the local ethernet.
+# (you do not need this if your PPTP server is responsible for routing
+# packets to the clients -- James Cameron)
+proxyarp
+
+# Debian: do not replace the default route
+defaultroute
+
+
+# Logging
+
+# Enable connection debugging facilities.
+# (see your syslog configuration for where pppd sends to)
+#debug
+
+# Print out all the option values which have been set.
+# (often requested by mailing list to verify options)
+#dump
+
+
+# Miscellaneous
+
+# Create a UUCP-style lock file for the pseudo-tty to ensure exclusive
+# access.
+lock
+
+# Disable BSD-Compress compression
+nobsdcomp
+plugin radius.so
\ No newline at end of file
--- /dev/null
+###############################################################################
+# $Id: pptpd.conf,v 1.1 2008/03/31 13:54:13 faust Exp $
+#
+# Sample Poptop configuration file /etc/pptpd.conf
+#
+# Changes are effective when pptpd is restarted.
+###############################################################################
+
+# TAG: ppp
+# Path to the pppd program, default '/usr/sbin/pppd' on Linux
+#
+#ppp /usr/sbin/pppd
+
+# TAG: option
+# Specifies the location of the PPP options file.
+# By default PPP looks in '/etc/ppp/options'
+#
+option /etc/ppp/pptpd-options
+
+# TAG: debug
+# Turns on (more) debugging to syslog
+#
+#debug
+
+# TAG: stimeout
+# Specifies timeout (in seconds) on starting ctrl connection
+#
+# stimeout 10
+
+# TAG: noipparam
+# Suppress the passing of the client's IP address to PPP, which is
+# done by default otherwise.
+#
+#noipparam
+
+# TAG: logwtmp
+# Use wtmp(5) to record client connections and disconnections.
+#
+logwtmp
+
+# TAG: bcrelay <if>
+# Turns on broadcast relay to clients from interface <if>
+#
+#bcrelay eth1
+
+# TAG: localip
+# TAG: remoteip
+# Specifies the local and remote IP address ranges.
+#
+# Any addresses work as long as the local machine takes care of the
+# routing. But if you want to use MS-Windows networking, you should
+# use IP addresses out of the LAN address space and use the proxyarp
+# option in the pppd options file, or run bcrelay.
+#
+# You can specify single IP addresses seperated by commas or you can
+# specify ranges, or both. For example:
+#
+# 192.168.0.234,192.168.0.245-249,192.168.0.254
+#
+# IMPORTANT RESTRICTIONS:
+#
+# 1. No spaces are permitted between commas or within addresses.
+#
+# 2. If you give more IP addresses than MAX_CONNECTIONS, it will
+# start at the beginning of the list and go until it gets
+# MAX_CONNECTIONS IPs. Others will be ignored.
+#
+# 3. No shortcuts in ranges! ie. 234-8 does not mean 234 to 238,
+# you must type 234-238 if you mean this.
+#
+# 4. If you give a single localIP, that's ok - all local IPs will
+# be set to the given one. You MUST still give at least one remote
+# IP for each simultaneous client.
+#
+# (Recommended)
+#localip 192.168.0.1
+#remoteip 192.168.0.234-238,192.168.0.245
+# or
+#localip 192.168.0.234-238,192.168.0.245
+#remoteip 192.168.1.234-238,192.168.1.245
+localip 192.168.2.1
+remoteip 192.168.2.2-254
--- /dev/null
+localhost testing123
--- /dev/null
+#! /bin/sh
+
+login=$1
+param=$2
+oldValue=$3
+newValue=$4
+
+#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
--- /dev/null
+#!/bin/bash
+
+#Этот скрипт вызывается в момент, когда пользователь
+#успешно прошел авторизацию на сервере. Задача скрипта - перестроить
+#файрвол так, что бы пользователь получил доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+iptables -A INPUT -s $IP -j QUEUE
+iptables -A OUTPUT -d $IP -j QUEUE
+iptables -A FORWARD -s $IP -j QUEUE
+iptables -A FORWARD -d $IP -j QUEUE
+
+# shaper
+
+default_speed=32
+
+speedR=$(grep -i "^Userdata0=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
+#echo "speedR=$speedR" >> /var/stargazer/users/$LOGIN/connect.log
+speed=$(echo $speedR | grep "^[0-9]*[0-9]$")
+
+if [ -z "$speed" ]
+then
+ speed=$default_speed
+fi
+
+speedkbit=$speed"kbit"
+
+#echo "speed=$speedkbit" >> /var/stargazer/users/$LOGIN/connect.log
+declare -i mark=$ID+1
+
+iptables -t mangle -A FORWARD -d $IP -j MARK --set-mark $mark
+
+sleep 1
+
+if [ -f "/var/stargazer/ifaces/$IP" ]
+then
+ #echo "1" >> /var/stargazer/users/$LOGIN/connect.log
+ ppp_iface=$(cat /var/stargazer/ifaces/$IP)
+else
+ #echo "2" >> /var/stargazer/users/$LOGIN/connect.log
+ exit 0
+fi
+
+tc qdisc add dev $ppp_iface root handle 1: htb
+tc class add dev $ppp_iface parent 1: classid 1:1 htb rate 100mbit ceil 100mbit burst 200k
+tc class add dev $ppp_iface parent 1:1 classid 1:10 htb rate $speedkbit burst 20k
+tc filter add dev $ppp_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:10
+
+#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH $ID $mark $speed $ppp_iface" >> /var/stargazer/users/$LOGIN/connect.log
+
--- /dev/null
+#!/bin/bash
+
+# Этот скрипт вызывается в момент, когда пользователь
+# желает отключится от интернета или вышел таймаут у пользователя
+# и сервер сам отключает пользователя
+# Задача скрипта подобна задаче скрипта OnConnect - перестроить
+# файрвол так, что бы пользователю закрыть доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$4
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
+iptables -D INPUT -s $IP -j QUEUE
+while [ $? == 0 ]
+do
+ iptables -D INPUT -s $IP -j QUEUE
+done
+
+iptables -D OUTPUT -d $IP -j QUEUE
+while [ $? == 0 ]
+do
+ iptables -D OUTPUT -d $IP -j QUEUE
+done
+
+iptables -D FORWARD -s $IP -j QUEUE
+while [ $? == 0 ]
+do
+ iptables -D FORWARD -s $IP -j QUEUE
+done
+
+iptables -D FORWARD -d $IP -j QUEUE
+while [ $? == 0 ]
+do
+ iptables -D FORWARD -d $IP -j QUEUE
+done
+
+
+
+declare -i mark=$ID+1
+
+iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+while [ $? == 0 ]
+do
+ iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+done
+
+
+if [ -f /var/stargazer/ifaces/$IP ]
+then
+ ppp_iface=$(cat /var/stargazer/ifaces/$IP)
+else
+ exit 0
+fi
+
+tc qdisc del dev $ppp_iface root
+
+
--- /dev/null
+#! /bin/sh
+
+# Использование (неиспользование) этого скрипта дело вкуса.
+# Он не выполняет критических функций. Его задача автматизировать
+# действия характерные при добавлении пользователя сети, например добавлекние
+# пользователю почты
+
+# Login
+login=$1
+
+#echo "added user $login" >> /var/stargazer/add_del.log
+
+
+
--- /dev/null
+#! /bin/sh
+
+# Login
+login=$1
+
+#echo "deleted user $login" >> /var/stargazer/add_del.log
+
--- /dev/null
+ALL 192.168.0.0/16 DIR1
+ALL 10.0.0.0/8 DIR2
+ALL 0.0.0.0/0 DIR0
\ No newline at end of file
--- /dev/null
+
+# Имя лог-файла куда пишутся события
+LogFile = /var/log/stargazer.log
+
+
+
+# Имя файла в котором определяются правила подсчета трафика
+Rules = /etc/stargazer/rules
+
+
+
+# Время через которое пишется d БД детальная статистика пользователя
+# Значения: 1, 1/2, 1/4, 1/6.
+# 1 - раз в чаc, 1/2 - раз в пол часа, 1/4 - раз в 15 мин, 1/6 - раз в 10 мин
+DetailStatWritePeriod=1/6
+
+
+
+# Периодичность записи записи в БД информации о статистике пользователя (минуты)
+# При большом кол-ве пользователей эту величину стоит увеличить, т.к.
+# запись в БД может занимать длительное время.
+# Значения: 1...1440 (минуты)
+StatWritePeriod = 10
+
+
+
+# День снятия абонплаты
+# Значения: 0...31. 0 - Последний день месяца
+DayFee = 1
+
+
+
+# Абонплата снимается в последний (yes) или первый (no) день учетного периода.
+# Это влияет на то, как будет снята абонплата (АП) при переходе на новый тариф.
+# Если у пользователя был тариф A с АП=100 и он хочет перейти на тариф B с АП=200,
+# то при переходе на новый тариф со счета пользователя снимется 100, если
+# DayFeeIsLastDay = yes и 200, если DayFeeIsLastDay = no
+DayFeeIsLastDay = yes
+
+
+
+# День сброса данных о трафике за месяц и день перехода пользователей на новые тарифы
+# Значения: 0...31. 0 - Последний день месяца
+DayResetTraff = 1
+
+
+
+# "Размазанное" снятие абонплаты. Снятие АП не раз в месяц, а каждый
+# день 1/30 или 1/31 части АП
+# Значения: yes, no
+SpreadFee = no
+
+
+
+# Данная опция определяет может ли пользователь получить доступ в интерент
+# если у него на счету нет денег, но остался предоплаченный трафик
+# Значения: yes, no
+FreeMbAllowInet = no
+
+
+
+# Эта опция определяет что будет писаться в стоимость трафика в detail_stat.
+# Если у пользователя еще есть предоплаченный трафик и WriteFreeMbTraffCost = no,
+# то в detail_stat стоимость будет 0. Если у пользователя уже нет
+# предоплаченного трафика и WriteFreeMbTraffCost = no, то в detail_stat
+# будет записана стоиость трафика. При WriteFreeMbTraffCost = yes стоимость
+# трафика будет записана в любом случае.
+WriteFreeMbTraffCost = no
+
+
+
+# Необязательный параметр. Указывает снимать полную абонплату у пользователя даже
+# если он быз заморожен только часть учетного периода.
+# По умолчанию установлен в no
+# FullFee=no
+
+# Необязательный параметр указывающий показывать на счету и позволять
+# использовать пользователю абонплату. По умолчанию установлен в yes
+# ShowFeeInCash=yes
+
+
+
+# Названия направлений. Направления без названий не будут отображаться в
+# авторизаторе и конфигураторе. Названия состоящие из нескольких слов должны
+# быть взяты в кавычки
+<DirNames>
+ DirName0 = Local
+ DirName1 = City
+ DirName2 = World
+ DirName3 =
+ DirName4 =
+ DirName5 =
+ DirName6 =
+ DirName7 =
+ DirName8 =
+ DirName9 =
+</DirNames>
+
+
+
+# Кол-во запускаемых процессов stg-exec.
+# Эти процессы отвечают за выполнение скриптов OnConnect, OnDisconnect, ...
+# Кол-во процессов означает сколько скриптов могут выполнятся одновременно.
+# Значения: 1...1024
+ExecutersNum = 2
+
+
+
+# Message Key для stg-exec.
+# Идентификатор очереди сообщений для выполнятеля скриптов.
+# Его изменение может понадобится если есть необходимость запустить несколько
+# экземпляров stg. Если вы не понимаете, что это, не трогайте этот параметр!
+# Значения: 0...2^32
+# Значение по умолчанию: 5555
+# ExecMsgKey = 5555
+
+
+
+# Путь к директории, в которой находятся модули сервера
+ModulesPath = /usr/lib/stg
+
+# Определяет директорию, в которой будут находится файлы "монитора"
+# работы сервера. В этой директории будут созданы пустые файлы, время
+# модификации которых будет меняться примерно раз в минуту. Если какой-то
+# компонент сервера зависнет, файл(ы) перестанет обновлятся, и по этому
+# признаку можно определить сбой в работе сервера и при надобности
+# перезапустить. Если параметр не указан или пустой, мониторинг производится
+# не будет. Параметр не является обязательным, по умолчанию пустой.
+# MonitorDir=/var/stargazer/monitor
+
+
+################################################################################
+# Store module
+# Настройки плагина работающего с БД сервера
+
+# Второй параметр - это имя модуля без mod_ в начале и .so в конце
+# Т.е. полное имя модуля mod_store_files.so
+<StoreModule store_files>
+
+ # Рабочая директория сервера, тут содержатся данные о тарифах, пользователях,
+ # администраторах и т.д.
+ WorkDir = /var/stargazer
+
+
+ # Владелец, группа и права доступа на файлы статистики (stat) пользователя
+ ConfOwner = root
+ ConfGroup = root
+ ConfMode = 600
+
+
+ # Владелец, группа и права доступа на файлы конфигурации (conf) пользователя
+ StatOwner = root
+ StatGroup = root
+ StatMode = 640
+
+ # Владелец, группа и права доступа на лог-файлы (log) пользователя
+ UserLogOwner = root
+ UserLogGroup = root
+ UserLogMode = 640
+
+</StoreModule>
+
+#<StoreModule store_firebird>
+# # Адрес сервера БД
+# server=localhost
+#
+# # Путь к БД на сервере или ее алиас
+# path=/var/stg/stargazer.fdb
+#
+# # Имя пользователя БД
+# user=stg
+#
+# # Пароль пользователя БД
+# password=123456
+#</StoreModule>
+
+#<StoreModule store_mysql>
+# # Имя пользователя БД
+# dbuser = stg
+#
+# # Пароль пользователя БД
+# rootdbpass = 123456
+#
+# # Имя БД на сервере
+# dbname = stg
+#
+# # Адрес сервера БД
+# dbhost = localhost
+#</StoreModule>
+
+
+
+################################################################################
+# Прочие модули
+
+<Modules>
+
+ # Настройки плагина авторизации Always Online "mod_auth_ao.so"
+ # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+ # Т.е. полное имя модуля mod_auth_ao.so
+ #<Module auth_ao>
+ #</Module>
+
+
+
+ # Настройки плагина авторизации InetAccess "mod_auth_ia.so"
+ # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+ # Т.е. полное имя модуля mod_auth_ia.so
+ #<Module auth_ia>
+ # Port = 5555
+ # UserDelay = 15
+ # UserTimeout = 65
+ # FreeMb = 0
+ #</Module>
+
+
+
+ # Настройки модуля конфигурации SgConfig "mod_conf_sg.so"
+ # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+ <Module conf_sg>
+
+ # Порт по которому сервер взаимодействует с конфигуратором
+ # Значения: 1...65535
+ Port = 5555
+
+ </Module>
+
+
+
+ # Модуль захвата трафика "mod_cap_ether.so"
+ # Второй параметер - это имя модуля без mod_ в начале и .so в конце
+ # Без параметров. Только имя модуля.
+ <Module cap_ipq>
+ # Модуль без параметров
+ </Module>
+
+
+
+ # Настройки модуля пингующего пользователей "mod_ping.so"
+ # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+ <Module ping>
+
+ # Время, в секундах, между пингами одного и того же пользователя
+ # Значения: 10...3600
+ PingDelay = 15
+
+ </Module>
+
+ <Module radius>
+ Password = 123456
+ ServerIP = 127.0.0.1
+ Port = 6666
+ AuthServices = Login-User
+ AcctServices = Framed-User
+ </Module>
+
+# # Настройки модуля для удаленного выполнения скриптов OnConnect и
+# # OnDisconnect "mod_remote_script.so"
+# # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+# <Module remote_script>
+#
+# # Время, в секундах, между посылками подтверждений, того, что пользователь
+# # всё еще онлайн
+# # Значения: 10...600
+# SendPeriod = 15
+#
+# # Соответствие подсетей, в которой находится пользователь и
+# # соответствующего роутера. Первая часть строки - подсеть, заданная
+# # как IP-адрес и маска, через пробел - IP-адрес роутера на котором
+# # должны выполняться скрипты
+# # Например эта запись "192.168.1.0/24 192.168.1.1" означает, что для
+# # всех пользователей из подсети 192.168.1.0/24, скрипты будут
+# # выполняться на роутере с адресом 192.168.1.1
+# # Subnet0...Subnet100
+# Subnet0 = 192.168.1.0/24 192.168.1.7
+# Subnet1 = 192.168.2.0/24 192.168.2.5
+# Subnet2 = 192.168.3.0/24 192.168.2.5
+# Subnet3 = 192.168.4.0/24 192.168.2.5
+#
+# # Пароль для шифрования пакетов между stg-сервером и сервером,
+# # выполняющим скрипты
+# Password = 123456
+#
+# # Этот параметр определяет какие параметры пользователя передаются
+# # на удаленный сервер
+# # Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName, NextTariff, Address,
+# # Note, Group, Email, RealName, Credit, EnabledDirs, Userdata0...Userdata9
+# UserParams=Cash Tariff EnabledDirs
+#
+# # Порт по которому сервер отсылает сообщения на роутер
+# # Значения: 1...65535
+# Port = 9999
+#
+# </Module>
+
+</Modules>
+################################################################################
+
--- /dev/null
+/*
+ * 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 "services_impl.h"
+
+#include "stg/admin.h"
+#include "stg/admin_conf.h"
+#include "stg/store.h"
+#include "stg/common.h"
+
+#include <algorithm>
+#include <cassert>
+
+using STG::ServicesImpl;
+
+//-----------------------------------------------------------------------------
+ServicesImpl::ServicesImpl(Store * st)
+ : store(st),
+ WriteServLog(Logger::get()),
+ searchDescriptors(),
+ handle(0)
+{
+Read();
+}
+//-----------------------------------------------------------------------------
+int ServicesImpl::Add(const ServiceConf & service, const Admin * admin)
+{
+std::lock_guard<std::mutex> lock(mutex);
+const auto& priv = admin->priv();
+
+if (!priv.serviceChg)
+ {
+ std::string s = admin->logStr() + " Add service \'" + service.name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+iterator si(std::find(data.begin(), data.end(), service));
+
+if (si != data.end())
+ {
+ strError = "Service \'" + service.name + "\' cannot not be added. Service already exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+
+ return -1;
+ }
+
+data.push_back(service);
+
+if (store->AddService(service.name) == 0)
+ {
+ WriteServLog("%s Service \'%s\' added.",
+ admin->logStr().c_str(), service.name.c_str());
+ return 0;
+ }
+
+strError = "Service \'" + service.name + "\' was not added. Error: " + store->GetStrError();
+WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+int ServicesImpl::Del(const std::string & name, const Admin * admin)
+{
+std::lock_guard<std::mutex> lock(mutex);
+const auto& priv = admin->priv();
+
+if (!priv.serviceChg)
+ {
+ std::string s = admin->logStr() + " Delete service \'" + name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
+
+if (si == data.end())
+ {
+ strError = "Service \'" + name + "\' cannot be deleted. Service does not exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+std::map<int, const_iterator>::iterator csi;
+csi = searchDescriptors.begin();
+while (csi != searchDescriptors.end())
+ {
+ if (csi->second == si)
+ (csi->second)++;
+ ++csi;
+ }
+
+data.erase(si);
+if (store->DelService(name) < 0)
+ {
+ strError = "Service \'" + name + "\' was not deleted. Error: " + store->GetStrError();
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+
+ return -1;
+ }
+
+WriteServLog("%s Service \'%s\' deleted.", admin->logStr().c_str(), name.c_str());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ServicesImpl::Change(const ServiceConf & service, const Admin * admin)
+{
+std::lock_guard<std::mutex> lock(mutex);
+const auto& priv = admin->priv();
+
+if (!priv.serviceChg)
+ {
+ std::string s = admin->logStr() + " Change service \'" + service.name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+iterator si(std::find(data.begin(), data.end(), service));
+
+if (si == data.end())
+ {
+ strError = "Service \'" + service.name + "\' cannot be changed " + ". Service does not exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+printfd(__FILE__, "Old cost = %f, old pay day = %u\n", si->cost, static_cast<unsigned>(si->payDay));
+*si = service;
+printfd(__FILE__, "New cost = %f, New pay day = %u\n", si->cost, static_cast<unsigned>(si->payDay));
+if (store->SaveService(service))
+ {
+ WriteServLog("Cannot write service %s.", service.name.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ return -1;
+ }
+
+WriteServLog("%s Service \'%s\' changed.",
+ admin->logStr().c_str(), service.name.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool ServicesImpl::Read()
+{
+std::lock_guard<std::mutex> lock(mutex);
+std::vector<std::string> servicesList;
+if (store->GetServicesList(&servicesList) < 0)
+ {
+ WriteServLog(store->GetStrError().c_str());
+ return true;
+ }
+
+for (size_t i = 0; i < servicesList.size(); i++)
+ {
+ ServiceConf service;
+
+ if (store->RestoreService(&service, servicesList[i]))
+ {
+ WriteServLog(store->GetStrError().c_str());
+ return true;
+ }
+
+ data.push_back(service);
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+bool ServicesImpl::Find(const std::string & name, ServiceConf * service) const
+{
+assert(service != NULL && "Pointer to service is not null");
+
+std::lock_guard<std::mutex> lock(mutex);
+if (data.empty())
+ return true;
+
+const_iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
+
+if (si != data.end())
+ {
+ *service = *si;
+ return false;
+ }
+
+return true;
+}
+//-----------------------------------------------------------------------------
+bool ServicesImpl::Find(const std::string & name, ServiceConfOpt * service) const
+{
+assert(service != NULL && "Pointer to service is not null");
+
+std::lock_guard<std::mutex> lock(mutex);
+if (data.empty())
+ return true;
+
+const_iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
+
+if (si != data.end())
+ {
+ *service = *si;
+ return false;
+ }
+
+return true;
+}
+//-----------------------------------------------------------------------------
+bool ServicesImpl::Exists(const std::string & name) const
+{
+std::lock_guard<std::mutex> lock(mutex);
+if (data.empty())
+ {
+ printfd(__FILE__, "No services in the system!\n");
+ return true;
+ }
+
+const_iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
+
+if (si != data.end())
+ return true;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+int ServicesImpl::OpenSearch() const
+{
+std::lock_guard<std::mutex> lock(mutex);
+handle++;
+searchDescriptors[handle] = data.begin();
+return handle;
+}
+//-----------------------------------------------------------------------------
+int ServicesImpl::SearchNext(int h, ServiceConf * service) const
+{
+std::lock_guard<std::mutex> lock(mutex);
+if (searchDescriptors.find(h) == searchDescriptors.end())
+ {
+ WriteServLog("SERVICES. Incorrect search handle.");
+ return -1;
+ }
+
+if (searchDescriptors[h] == data.end())
+ return -1;
+
+*service = *searchDescriptors[h]++;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ServicesImpl::CloseSearch(int h) const
+{
+std::lock_guard<std::mutex> lock(mutex);
+if (searchDescriptors.find(h) != searchDescriptors.end())
+ {
+ searchDescriptors.erase(searchDescriptors.find(h));
+ return 0;
+ }
+
+WriteServLog("SERVICES. Incorrect search handle.");
+return -1;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/services.h"
+#include "stg/service_conf.h"
+#include "stg/locker.h"
+#include "stg/noncopyable.h"
+#include "stg/logger.h"
+
+#include <vector>
+#include <map>
+#include <string>
+#include <mutex>
+
+namespace STG
+{
+
+struct Admin;
+struct Store;
+
+class ServicesImpl : public Services {
+ public:
+ explicit ServicesImpl(Store* st);
+
+ int Add(const ServiceConf& service, const Admin* admin) override;
+ int Del(const std::string& name, const Admin* admin) override;
+ int Change(const ServiceConf& service, const Admin* admin) override;
+ bool Find(const std::string& name, ServiceConf* service) const override;
+ bool Find(const std::string& name, ServiceConfOpt* service) const override;
+ bool Exists(const std::string& name) const override;
+ const std::string& GetStrError() const override { return strError; }
+
+ size_t Count() const override { return data.size(); }
+
+ int OpenSearch() const override;
+ int SearchNext(int, ServiceConf* service) const override;
+ int CloseSearch(int) const override;
+
+ private:
+ typedef std::vector<ServiceConf>::iterator iterator;
+ typedef std::vector<ServiceConf>::const_iterator const_iterator;
+
+ bool Read();
+
+ std::vector<ServiceConf> data;
+ Store* store;
+ Logger& WriteServLog;
+ mutable std::map<int, const_iterator> searchDescriptors;
+ mutable unsigned int handle;
+ mutable std::mutex mutex;
+ std::string strError;
+};
+
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include "settings_impl.h"
+
+#include "stg/logger.h"
+#include "stg/dotconfpp.h"
+#include "stg/common.h"
+#include "stg/const.h"
+
+#include <stdexcept>
+#include <cstring>
+#include <cerrno>
+
+using STG::SettingsImpl;
+using STG::ParamValue;
+
+namespace
+{
+
+struct Error : public std::runtime_error
+{
+ Error(const std::string& message) : runtime_error(message) {}
+};
+
+std::vector<std::string> toValues(const DOTCONFDocumentNode& node)
+{
+ std::vector<std::string> values;
+
+ size_t i = 0;
+ const char* value = NULL;
+ while ((value = node.getValue(i++)) != NULL)
+ values.push_back(value);
+
+ return values;
+}
+
+std::vector<ParamValue> toPVS(const DOTCONFDocumentNode& node)
+{
+ std::vector<ParamValue> pvs;
+
+ const DOTCONFDocumentNode* child = node.getChildNode();
+ while (child != NULL)
+ {
+ if (child->getName() == NULL)
+ continue;
+
+ if (child->getChildNode() == NULL)
+ pvs.push_back(ParamValue(child->getName(), toValues(*child)));
+ else
+ pvs.push_back(ParamValue(child->getName(), toValues(*child), toPVS(*child)));
+
+ child = child->getNextNode();
+ }
+
+ return pvs;
+}
+
+unsigned toPeriod(const char* value)
+{
+ if (value == NULL)
+ throw Error("No detail stat period value.");
+
+ std::string period(value);
+ if (period == "1")
+ return STG::dsPeriod_1;
+ else if (period == "1/2")
+ return STG::dsPeriod_1_2;
+ else if (period == "1/4")
+ return STG::dsPeriod_1_4;
+ else if (period == "1/6")
+ return STG::dsPeriod_1_6;
+
+ throw Error("Invalid detail stat period value: '" + period + "'. Should be one of '1', '1/2', '1/4' or '1/6'.");
+}
+
+void errorCallback(void* /*data*/, const char* buf)
+{
+ printfd(__FILE__, "SettingsImpl::errorCallback() - %s\n", buf);
+ STG::Logger::get()("%s", buf);
+}
+
+}
+
+//-----------------------------------------------------------------------------
+SettingsImpl::SettingsImpl(const std::string & cd)
+ : modulesPath("/usr/lib/stg"),
+ dirName(DIR_NUM),
+ confDir(cd.empty() ? "/etc/stargazer" : cd),
+ scriptsDir(confDir),
+ rules(confDir + "/rules"),
+ logFile("/var/log/stargazer.log"),
+ pidFile("/var/run/stargazer.pid"),
+ monitorDir("/var/stargazer/monitoring"),
+ monitoring(false),
+ detailStatWritePeriod(dsPeriod_1_6),
+ statWritePeriod(10),
+ stgExecMsgKey(5555),
+ executersNum(1),
+ fullFee(false),
+ dayFee(0),
+ dayResetTraff(0),
+ spreadFee(false),
+ freeMbAllowInet(false),
+ dayFeeIsLastDay(false),
+ stopOnError(true),
+ writeFreeMbTraffCost(false),
+ showFeeInCash(true),
+ messageTimeout(0),
+ feeChargeType(0),
+ reconnectOnTariffChange(false),
+ disableSessionLog(false)
+{
+ filterParamsLog.push_back("*");
+}
+//-----------------------------------------------------------------------------
+int SettingsImpl::ReadSettings()
+{
+const char * requiredOptions[] = {
+ "ModulesPath",
+ "Modules",
+ "StoreModule",
+ "Rules",
+ "LogFile",
+ "DetailStatWritePeriod",
+ "DayFee",
+ "DayResetTraff",
+ "SpreadFee",
+ "FreeMbAllowInet",
+ "DayFeeIsLastDay",
+ "WriteFreeMbTraffCost",
+ NULL
+ };
+int storeModulesCount = 0;
+modulesSettings.clear();
+
+DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
+conf.setErrorCallback(errorCallback, nullptr);
+conf.setRequiredOptionNames(requiredOptions);
+std::string confFile = confDir + "/stargazer.conf";
+
+if(conf.setContent(confFile.c_str()) != 0)
+ {
+ strError = "Cannot read file " + confFile;
+ return -1;
+ }
+
+auto node = conf.getFirstNode();
+
+while (node)
+ {
+ if (strcasecmp(node->getName(), "ScriptDir") == 0)
+ {
+ scriptsDir = node->getValue(0);
+ }
+
+ if (strcasecmp(node->getName(), "LogFile") == 0)
+ {
+ logFile = node->getValue(0);
+ }
+
+ if (strcasecmp(node->getName(), "PIDFile") == 0)
+ {
+ pidFile = node->getValue(0);
+ }
+
+ if (strcasecmp(node->getName(), "ModulesPath") == 0)
+ {
+ modulesPath = node->getValue(0);
+ }
+
+ if (strcasecmp(node->getName(), "Rules") == 0)
+ {
+ rules = node->getValue(0);
+ }
+
+ if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
+ {
+ try
+ {
+ detailStatWritePeriod = toPeriod(node->getValue(0));
+ }
+ catch (const Error& error)
+ {
+ strError = error.what();
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
+ {
+ if (ParseUnsignedInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
+ {
+ strError = "Incorrect StatWritePeriod value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
+ {
+ if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
+ {
+ strError = "Incorrect ExecMsgKey value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "ExecutersNum") == 0)
+ {
+ if (ParseUnsignedInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
+ {
+ strError = "Incorrect ExecutersNum value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "DayFee") == 0)
+ {
+ if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayFee) != 0)
+ {
+ strError = "Incorrect DayFee value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "FullFee") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &fullFee) != 0)
+ {
+ strError = "Incorrect FullFee value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "DayResetTraff") == 0)
+ {
+ if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
+ {
+ strError = "Incorrect DayResetTraff value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "SpreadFee") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
+ {
+ strError = "Incorrect SpreadFee value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
+ {
+ strError = "Incorrect FreeMbAllowInet value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
+ {
+ strError = "Incorrect DayFeeIsLastDay value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "StopOnError") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &stopOnError) != 0)
+ {
+ strError = "Incorrect StopOnError value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
+ {
+ strError = "Incorrect WriteFreeMbTraffCost value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
+ {
+ strError = "Incorrect ShowFeeInCash value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "MonitorDir") == 0)
+ {
+ monitorDir = node->getValue(0);
+ struct stat stat;
+ monitoring = false;
+
+ if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
+ {
+ monitoring = true;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "MessageTimeout") == 0)
+ {
+ if (ParseUnsigned(node->getValue(0), &messageTimeout) != 0)
+ {
+ strError = "Incorrect MessageTimeout value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "FeeChargeType") == 0)
+ {
+ if (ParseUnsignedInRange(node->getValue(0), 0, 3, &feeChargeType) != 0)
+ {
+ strError = "Incorrect FeeChargeType value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "ReconnectOnTariffChange") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &reconnectOnTariffChange) != 0)
+ {
+ strError = "Incorrect ReconnectOnTariffChange value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "DisableSessionLog") == 0)
+ {
+ if (ParseYesNo(node->getValue(0), &disableSessionLog) != 0)
+ {
+ strError = "Incorrect DisableSessionLog value: \'" + std::string(node->getValue(0)) + "\'";
+ return -1;
+ }
+ }
+
+ if (strcasecmp(node->getName(), "FilterParamsLog") == 0)
+ {
+ filterParamsLog.clear();
+ for (int i = 0; node->getValue(i) != NULL; ++i)
+ filterParamsLog.push_back(node->getValue(i));
+ }
+
+ if (strcasecmp(node->getName(), "DirNames") == 0)
+ {
+ const DOTCONFDocumentNode * child = node->getChildNode();
+ if (child)
+ {
+ const DOTCONFDocumentNode * dirNameNode;
+ dirName.reserve(DIR_NUM);
+ for (int i = 0; i < DIR_NUM; i++)
+ {
+ char strDirName[12];
+ sprintf(strDirName, "DirName%d", i);
+ dirNameNode = conf.findNode(strDirName, node);
+ if (dirNameNode && dirNameNode->getValue(0))
+ {
+ dirName[i] = dirNameNode->getValue(0);
+ }
+ }
+ }
+ }
+
+ if (strcasecmp(node->getName(), "StoreModule") == 0)
+ {
+ if (node->getValue(1))
+ {
+ strError = "Unexpected \'" + std::string(node->getValue(1)) + "\'.";
+ return -1;
+ }
+
+ if (storeModulesCount)
+ {
+ strError = "Should be only one StoreModule.";
+ return -1;
+ }
+ storeModulesCount++;
+
+ if (node->getValue(0) == NULL)
+ {
+ strError = "No module name in the StoreModule section.";
+ return -1;
+ }
+ storeModuleSettings.moduleName = node->getValue(0);
+ storeModuleSettings.moduleParams = toPVS(*node);
+ }
+
+ if (strcasecmp(node->getName(), "Modules") == 0)
+ {
+ if (node->getValue(0))
+ {
+ strError = "Unexpected \'" + std::string(node->getValue(0)) + "\'.";
+ return -1;
+ }
+ const DOTCONFDocumentNode * child = node->getChildNode();
+ while (child)
+ {
+ if (strcasecmp(child->getName(), "Module") != 0)
+ {
+ child = child->getNextNode();
+ continue;
+ }
+
+ if (child->getValue(0) == NULL)
+ {
+ strError = "No module name in the Module section.";
+ return -1;
+ }
+
+ modulesSettings.push_back(ModuleSettings(child->getValue(0), toPVS(*child)));
+
+ child = child->getNextNode();
+ }
+ }
+
+ if (strcasecmp(node->getName(), "ScriptParams") == 0)
+ {
+ for (int i = 0; node->getValue(i) != NULL; ++i)
+ scriptParams.push_back(node->getValue(i));
+ }
+ node = node->getNextNode();
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/settings.h"
+#include "stg/common.h"
+#include "stg/module_settings.h"
+
+#include <string>
+#include <vector>
+
+class DOTCONFDocumentNode;
+
+namespace STG
+{
+
+//-----------------------------------------------------------------------------
+enum DETAIL_STAT_PERIOD {
+ dsPeriod_1,
+ dsPeriod_1_2,
+ dsPeriod_1_4,
+ dsPeriod_1_6
+};
+//-----------------------------------------------------------------------------
+class SettingsImpl : public Settings {
+ public:
+ explicit SettingsImpl(const std::string &);
+
+ SettingsImpl(const SettingsImpl&) = default;
+ SettingsImpl& operator=(const SettingsImpl&) = default;
+ SettingsImpl(SettingsImpl&&) = default;
+ SettingsImpl& operator=(SettingsImpl&&) = default;
+
+ int Reload() { return ReadSettings(); }
+ int ReadSettings();
+
+ std::string GetStrError() const { return strError; }
+
+ int GetExecMsgKey() const { return stgExecMsgKey; }
+ unsigned GetExecutersNum() const { return executersNum; }
+ const std::string & GetDirName(size_t num) const { return dirName[num]; }
+ const std::string & GetConfDir() const { return confDir; }
+ const std::string & GetScriptsDir() const { return scriptsDir; }
+ const std::string & GetRulesFileName() const { return rules; }
+ const std::string & GetLogFileName() const { return logFile; }
+ const std::string & GetPIDFileName() const { return pidFile; }
+ unsigned GetDetailStatWritePeriod() const
+ { return detailStatWritePeriod; }
+ unsigned GetStatWritePeriod() const { return statWritePeriod * 60; }
+ unsigned GetDayFee() const { return dayFee; }
+ bool GetFullFee() const { return fullFee; }
+ unsigned GetDayResetTraff() const { return dayResetTraff; }
+ bool GetSpreadFee() const { return spreadFee; }
+ bool GetFreeMbAllowInet() const { return freeMbAllowInet; }
+ bool GetDayFeeIsLastDay() const { return dayFeeIsLastDay; }
+ bool GetStopOnError() const { return stopOnError; }
+ bool GetWriteFreeMbTraffCost() const
+ { return writeFreeMbTraffCost; }
+ bool GetShowFeeInCash() const { return showFeeInCash; }
+ const std::string & GetMonitorDir() const { return monitorDir; }
+ bool GetMonitoring() const { return monitoring; }
+ unsigned GetMessageTimeout() const { return messageTimeout * 3600 * 24; }
+ unsigned GetFeeChargeType() const { return feeChargeType; }
+ bool GetReconnectOnTariffChange() const { return reconnectOnTariffChange; }
+ bool GetDisableSessionLog() const { return disableSessionLog; }
+ const std::vector<std::string> & GetFilterParamsLog() const { return filterParamsLog; }
+
+ const std::string & GetModulesPath() const { return modulesPath; }
+ const ModuleSettings & GetStoreModuleSettings() const
+ { return storeModuleSettings; }
+ const std::vector<ModuleSettings> & GetModulesSettings() const
+ { return modulesSettings; }
+ const std::vector<std::string> & GetScriptParams() const { return scriptParams; }
+
+ private:
+ std::string strError;
+
+ //////////settings
+ std::string modulesPath;
+ std::vector<std::string> dirName;
+ std::string confDir;
+ std::string scriptsDir;
+ std::string rules;
+ std::string logFile;
+ std::string pidFile;
+ std::string monitorDir;
+ std::vector<std::string> scriptParams;
+ bool monitoring;
+ unsigned detailStatWritePeriod;
+ unsigned statWritePeriod;
+ int stgExecMsgKey;
+ unsigned executersNum;
+ bool fullFee;
+ unsigned dayFee;
+ unsigned dayResetTraff;
+ bool spreadFee;
+ bool freeMbAllowInet;
+ bool dayFeeIsLastDay;
+ bool stopOnError;
+ bool writeFreeMbTraffCost;
+ bool showFeeInCash;
+ unsigned messageTimeout;
+ unsigned feeChargeType;
+ bool reconnectOnTariffChange;
+ bool disableSessionLog;
+ std::vector<std::string> filterParamsLog;
+
+ std::vector<ModuleSettings> modulesSettings;
+ ModuleSettings storeModuleSettings;
+};
+//-----------------------------------------------------------------------------
+
+}
--- /dev/null
+#include "stg_timer.h"
+
+#include "stg/common.h"
+
+#include <ctime>
+#include <cstring>
+#include <csignal>
+
+#include <pthread.h>
+
+void * StgTimer(void *);
+
+static int nonstop;
+static pthread_t thrStgTimer;
+static bool isTimerRunning = false;
+volatile time_t stgTime;
+
+#ifdef STG_TIMER_DEBUG
+const int TIME_SPEED = 1;
+/*
+ 1 - 1x speed
+ 2 - 2x speed
+ 5 - 5x speed
+ 10 - 10x speed
+ */
+
+const int START_TIME = 2;
+/*
+ 0 - as is
+ 1 - start before new day (3 min before) 29.11.2005 23:57:00
+ 2 - start before new month (3 min before) 30.11.2005 23:57:00
+ */
+#endif
+
+//-----------------------------------------------------------------------------
+void * StgTimer(void *)
+{
+#ifdef STG_TIMER_DEBUG
+struct tm lt;
+memset(<, 0, sizeof(lt));
+
+lt.tm_year = 2016 - 1900; // 2005
+lt.tm_mon = 7 - 1; // Nov
+lt.tm_hour = 23; // 23 h
+lt.tm_min = 57; // 50 min
+lt.tm_sec = 0; // 00 sec
+lt.tm_isdst = -1;
+
+switch (START_TIME)
+ {
+ case 0:
+ stgTime = time(NULL);
+ break;
+
+ case 1:
+ lt.tm_mday = 29;
+ stgTime = mktime(<);
+ break;
+
+ case 2:
+ lt.tm_mday = 31;
+ stgTime = mktime(<);
+ break;
+ }
+#else
+stgTime = time(NULL);
+#endif
+
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+nonstop = 1;
+isTimerRunning = true;
+while (nonstop)
+ {
+ #ifdef STG_TIMER_DEBUG
+ struct timespec ts;
+ if (TIME_SPEED == 1)
+ {
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ }
+ else
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000000 / TIME_SPEED;
+ }
+ nanosleep(&ts, NULL);
+ stgTime++;
+ #else
+ struct timespec ts = {0, 500000000};
+ nanosleep(&ts, NULL);
+ stgTime = time(NULL);
+ #endif
+ }
+isTimerRunning = false;
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int RunStgTimer()
+{
+static int a = 0;
+isTimerRunning = false;
+
+if (a == 0)
+ if (pthread_create(&thrStgTimer, NULL, &StgTimer, NULL))
+ {
+ isTimerRunning = false;
+ return -1;
+ }
+
+a = 1;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void StopStgTimer()
+{
+nonstop = 0;
+pthread_join(thrStgTimer, NULL); // Cleanup thread resources
+printfd(__FILE__, "STG_TIMER stopped\n");
+}
+//-----------------------------------------------------------------------------
+bool IsStgTimerRunning()
+{
+return isTimerRunning;
+}
+//-----------------------------------------------------------------------------
+int stgUsleep(unsigned long t)
+{
+#ifdef STG_TIMER_DEBUG
+struct timespec ts = {static_cast<time_t>((t / TIME_SPEED) / 1000000), static_cast<long>(((t / TIME_SPEED) % 1000000) * 1000)};
+return nanosleep(&ts, NULL);
+#else
+struct timespec ts = {static_cast<time_t>(t / 1000000), static_cast<long>((t % 1000000) * 1000)};
+return nanosleep(&ts, NULL);
+#endif
+}
+//-----------------------------------------------------------------------------
+void WaitTimer()
+{
+ for (int i = 0; i < 5 && !isTimerRunning; i++)
+ stgUsleep(200000);
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+ /*
+ $Revision: 1.9 $
+ $Date: 2010/11/03 10:37:52 $
+ $Author: faust $
+ */
+
+#ifndef STG_TIMER_H
+#define STG_TIMER_H
+
+#include <ctime>
+
+extern volatile time_t stgTime;
+int RunStgTimer();
+void StopStgTimer();
+void WaitTimer();
+bool IsStgTimerRunning();
+int stgUsleep(unsigned long t);
+
+#endif //STG_TIMER_H
+
+
--- /dev/null
+/*
+ * 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 <dlfcn.h>
+
+#include "stg/common.h"
+#include "stg/store.h"
+#include "store_loader.h"
+#include "settings_impl.h"
+
+using STG::StoreLoader;
+
+StoreLoader::StoreLoader(const SettingsImpl& settings) noexcept
+ : isLoaded(false),
+ handle(NULL),
+ plugin(NULL),
+ storeSettings(settings.GetStoreModuleSettings()),
+ pluginFileName(settings.GetModulesPath() + "/mod_" + storeSettings.moduleName + ".so")
+{
+}
+
+StoreLoader::~StoreLoader()
+{
+ unload();
+}
+
+bool StoreLoader::load() noexcept
+{
+ if (isLoaded)
+ {
+ errorStr = "Store plugin '" + pluginFileName + "' was already loaded!";
+ printfd(__FILE__, "StoreLoader::load() - %s\n", errorStr.c_str());
+ return false;
+ }
+
+ if (pluginFileName.empty())
+ {
+ errorStr = "Empty store plugin filename";
+ printfd(__FILE__, "StoreLoader::load() - %s\n", errorStr.c_str());
+ return true;
+ }
+
+ handle = dlopen(pluginFileName.c_str(), RTLD_NOW);
+
+ if (!handle)
+ {
+ errorStr = "Error loading plugin '"
+ + pluginFileName + "': '" + dlerror() + "'";
+ printfd(__FILE__, "StoreLoader::Load() - %s\n", errorStr.c_str());
+ return true;
+ }
+
+ isLoaded = true;
+
+ using Getter = Store* (*)();
+ auto GetStore = reinterpret_cast<Getter>(dlsym(handle, "GetStore"));
+ if (!GetStore)
+ {
+ errorStr = std::string("GetStore() not found! ") + dlerror();
+ printfd(__FILE__, "StoreLoader::load() - %s\n", errorStr.c_str());
+ return true;
+ }
+
+ plugin = GetStore();
+
+ if (!plugin)
+ {
+ errorStr = "Plugin was not created!";
+ printfd(__FILE__, "StoreLoader::Load() - %s\n");
+ return true;
+ }
+
+ plugin->SetSettings(storeSettings);
+ if (plugin->ParseSettings())
+ {
+ errorStr = plugin->GetStrError();
+ printfd(__FILE__, "StoreLoader::Load() - Failed to parse settings. Plugin reports: '%s'\n", errorStr.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+bool StoreLoader::unload() noexcept
+{
+ if (!isLoaded)
+ return true;
+
+ delete plugin;
+
+ if (dlclose(handle))
+ {
+ errorStr = "Failed to unload plugin '";
+ errorStr += pluginFileName + "': ";
+ errorStr += dlerror();
+ printfd(__FILE__, "StoreLoader::Unload() - %s\n", errorStr.c_str());
+ return true;
+ }
+
+ isLoaded = false;
+
+ return false;
+}
--- /dev/null
+/*
+ * 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>
+ */
+
+#pragma once
+
+#include "stg/module_settings.h"
+
+#include <string>
+
+namespace STG
+{
+
+struct Store;
+class SettingsImpl;
+
+class StoreLoader {
+ public:
+ explicit StoreLoader(const SettingsImpl& settings) noexcept;
+ ~StoreLoader();
+
+ StoreLoader(const StoreLoader&) = delete;
+ StoreLoader& operator=(const StoreLoader&) = delete;
+
+ bool load() noexcept;
+ bool unload() noexcept;
+
+ Store& get() noexcept { return *plugin; }
+
+ const std::string& GetStrError() const noexcept { return errorStr; }
+
+ private:
+ bool isLoaded;
+ void* handle;
+ Store* plugin;
+ std::string errorStr;
+ ModuleSettings storeSettings;
+ std::string pluginFileName;
+};
+
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 07.11.2007
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.11 $
+ $Date: 2010/10/07 16:57:21 $
+ $Author: faust $
+ */
+
+#include "tariff_impl.h"
+
+#include "stg_timer.h"
+#include "stg/common.h"
+
+#include <ctime>
+#include <algorithm> // std::max
+
+using STG::TariffImpl;
+
+//-----------------------------------------------------------------------------
+TariffImpl & TariffImpl::operator=(const TariffData & td)
+{
+tariffData = td;
+return *this;
+}
+//-----------------------------------------------------------------------------
+double TariffImpl::GetPriceWithTraffType(uint64_t up,
+ uint64_t down,
+ int dir,
+ time_t t) const
+{
+return GetPriceWithoutFreeMb(dir, GetTraffByType(up, down) / (1024 * 1024), t);
+}
+//-----------------------------------------------------------------------------
+int64_t TariffImpl::GetTraffByType(uint64_t up, uint64_t down) const
+{
+switch (tariffData.tariffConf.traffType)
+ {
+ case TRAFF_UP:
+ return up;
+
+ case TRAFF_DOWN:
+ return down;
+
+ case TRAFF_MAX:
+ return std::max(up, down);
+
+ default: //TRAFF_UP_DOWN:
+ return up + down;
+ }
+}
+//-----------------------------------------------------------------------------
+int TariffImpl::GetThreshold(int dir) const
+{
+ return tariffData.dirPrice[dir].threshold;
+}
+//-----------------------------------------------------------------------------
+void TariffImpl::Print() const
+{
+printfd(__FILE__, "Traiff name: %s\n", tariffData.tariffConf.name.c_str());
+}
+//-----------------------------------------------------------------------------
+int TariffImpl::Interval(int dir, time_t t) const
+{
+// Start of the day (and end of the night) in sec from 00:00:00
+int s1 = tariffData.dirPrice[dir].hDay * 3600 +
+ tariffData.dirPrice[dir].mDay * 60;
+// Start of the night (and end of the day) in sec from 00:00:00
+int s2 = tariffData.dirPrice[dir].hNight * 3600 +
+ tariffData.dirPrice[dir].mNight * 60;
+
+struct tm * lt;
+
+lt = localtime(&t);
+
+// Position of time t in sec from 00:00:00
+// Ignoring seconds due to minute precision
+int lts = lt->tm_hour * 3600 + lt->tm_min * 60;
+
+if (s1 < s2)
+ {
+ // Normal situation (00:00:00 is a night)
+ if (lts > s1 && lts < s2)
+ return TARIFF_DAY;
+ else
+ return TARIFF_NIGHT;
+ }
+else
+ {
+ // Not so common but possible situation (00:00:00 is a day)
+ if (lts < s1 && lts > s2)
+ return TARIFF_NIGHT;
+ else
+ return TARIFF_DAY;
+ }
+}
+//-----------------------------------------------------------------------------
+double TariffImpl::GetPriceWithoutFreeMb(int dir, int64_t mb, time_t t) const
+{
+int interval = Interval(dir, t);
+
+/*
+ * 0011 - NB
+ * *01* - NA
+ * 0**1 - DB
+ * **** - DA
+ */
+
+bool nd = tariffData.dirPrice[dir].noDiscount;
+bool sp = tariffData.dirPrice[dir].singlePrice;
+bool th = (interval == TARIFF_NIGHT);
+bool tr = (mb > tariffData.dirPrice[dir].threshold);
+
+if (!nd && !sp && th && tr)
+ return tariffData.dirPrice[dir].priceNightB;
+else if (!nd && tr)
+ return tariffData.dirPrice[dir].priceDayB;
+else if (!sp && th)
+ return tariffData.dirPrice[dir].priceNightA;
+else
+ return tariffData.dirPrice[dir].priceDayA;
+}
+//-----------------------------------------------------------------------------
+std::string TariffImpl::TariffChangeIsAllowed(const Tariff & to, time_t currentTime) const
+{
+time_t timeout = GetChangePolicyTimeout();
+if (currentTime > timeout && timeout != 0)
+ return "";
+switch (GetChangePolicy())
+ {
+ case Tariff::ALLOW:
+ return "";
+ case Tariff::TO_CHEAP:
+ if (to.GetFee() < GetFee())
+ return "";
+ else
+ return "New tariff '" + to.GetName() + "' is more expensive than current tariff '" + GetName() + "'. The policy is '" + Tariff::toString(GetChangePolicy()) + "'.";
+ case Tariff::TO_EXPENSIVE:
+ if (to.GetFee() >= GetFee())
+ return "";
+ else
+ return "New tariff '" + to.GetName() + "' is more cheap than current tariff '" + GetName() + "'. The policy is '" + Tariff::toString(GetChangePolicy()) + "'.";
+ case Tariff::DENY:
+ return "Current tariff '" + GetName() + "', new tariff '" + to.GetName() + "'. The policy is '" + Tariff::toString(GetChangePolicy()) + "'.";
+ }
+return "";
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 07.11.2007
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/tariff.h"
+#include "stg/tariff_conf.h"
+
+#include <string>
+
+#include <ctime>
+#include <cstdint>
+
+#define TARIFF_DAY 0
+#define TARIFF_NIGHT 1
+
+namespace STG
+{
+
+class TariffImpl : public Tariff {
+ public:
+ explicit TariffImpl(const std::string & name)
+ : tariffData(name)
+ {}
+ explicit TariffImpl(const TariffData & td)
+ : tariffData(td)
+ {}
+
+ TariffImpl(const TariffImpl&) = default;
+ TariffImpl& operator=(const TariffImpl&) = default;
+ TariffImpl(TariffImpl&&) = default;
+ TariffImpl& operator=(TariffImpl&&) = default;
+
+ double GetPriceWithTraffType(uint64_t up,
+ uint64_t down,
+ int dir,
+ time_t t) const;
+ double GetFreeMb() const { return tariffData.tariffConf.free; }
+ double GetPassiveCost() const { return tariffData.tariffConf.passiveCost; }
+ double GetFee() const { return tariffData.tariffConf.fee; }
+ double GetFree() const { return tariffData.tariffConf.free; }
+ Period GetPeriod() const { return tariffData.tariffConf.period; }
+ ChangePolicy GetChangePolicy() const { return tariffData.tariffConf.changePolicy; }
+ time_t GetChangePolicyTimeout() const { return tariffData.tariffConf.changePolicyTimeout; }
+
+ void Print() const;
+
+ const std::string & GetName() const { return tariffData.tariffConf.name; }
+ void SetName(const std::string & name) { tariffData.tariffConf.name = name; }
+
+ int GetTraffType() const { return tariffData.tariffConf.traffType; }
+ int64_t GetTraffByType(uint64_t up, uint64_t down) const;
+ int GetThreshold(int dir) const;
+ const TariffData & GetTariffData() const { return tariffData; }
+
+ TariffImpl & operator=(const TariffData & td);
+ bool operator==(const TariffImpl & rhs) const { return GetName() == rhs.GetName(); }
+ bool operator!=(const TariffImpl & rhs) const { return GetName() != rhs.GetName(); }
+ std::string TariffChangeIsAllowed(const Tariff & to, time_t currentTime) const;
+
+ private:
+ TariffData tariffData;
+
+ double GetPriceWithoutFreeMb(int dir, int64_t mb, time_t t) const;
+ int Interval(int dir, time_t t) const;
+};
+
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 07.11.2007
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.9 $
+ $Date: 2010/10/07 18:43:21 $
+ $Author: faust $
+ */
+
+#include <cassert>
+#include <algorithm>
+#include <vector>
+
+#include "stg/locker.h"
+#include "stg/logger.h"
+#include "stg/store.h"
+#include "stg/admin.h"
+#include "stg/admin_conf.h"
+#include "tariffs_impl.h"
+
+using STG::TariffsImpl;
+
+//-----------------------------------------------------------------------------
+TariffsImpl::TariffsImpl(Store * st)
+ : store(st),
+ WriteServLog(Logger::get()),
+ noTariff(NO_TARIFF_NAME)
+{
+ReadTariffs();
+}
+//-----------------------------------------------------------------------------
+int TariffsImpl::ReadTariffs()
+{
+std::lock_guard<std::mutex> lock(m_mutex);
+
+std::vector<std::string> tariffsList;
+if (store->GetTariffsList(&tariffsList))
+ {
+ WriteServLog("Cannot get tariffs list.");
+ WriteServLog("%s", store->GetStrError().c_str());
+ }
+
+Data::size_type tariffsNum = tariffsList.size();
+
+for (Data::size_type i = 0; i < tariffsNum; i++)
+ {
+ TariffData td;
+ if (store->RestoreTariff(&td, tariffsList[i]))
+ {
+ WriteServLog("Cannot read tariff %s.", tariffsList[i].c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ return -1;
+ }
+ tariffs.push_back(TariffImpl(td));
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+size_t TariffsImpl::Count() const
+{
+std::lock_guard<std::mutex> lock(m_mutex);
+return tariffs.size();
+}
+//-----------------------------------------------------------------------------
+const STG::Tariff* TariffsImpl::FindByName(const std::string & name) const
+{
+if (name == NO_TARIFF_NAME)
+ return &noTariff;
+
+std::lock_guard<std::mutex> lock(m_mutex);
+const auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(name));
+
+if (ti != tariffs.end())
+ return &(*ti);
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int TariffsImpl::Chg(const TariffData & td, const Admin * admin)
+{
+const auto& priv = admin->priv();
+
+if (!priv.tariffChg)
+ {
+ std::string s = admin->logStr() + " Change tariff \'"
+ + td.tariffConf.name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+std::lock_guard<std::mutex> lock(m_mutex);
+
+auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(td.tariffConf.name));
+
+if (ti == tariffs.end())
+ {
+ strError = "Tariff \'" + td.tariffConf.name + "\' cannot be changed. Tariff does not exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+*ti = td;
+
+if (store->SaveTariff(td, td.tariffConf.name))
+ {
+ std::string error = "Tariff " + td.tariffConf.name + " writing error. " + store->GetStrError();
+ WriteServLog(error.c_str());
+ return -1;
+ }
+
+WriteServLog("%s Tariff \'%s\' changed.",
+ admin->logStr().c_str(), td.tariffConf.name.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TariffsImpl::Del(const std::string & name, const Admin * admin)
+{
+const auto& priv = admin->priv();
+
+if (!priv.tariffChg)
+ {
+ std::string s = admin->logStr() + " Delete tariff \'"
+ + name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+TariffData td;
+
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ const auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(name));
+
+ if (ti == tariffs.end())
+ {
+ strError = "Tariff \'" + name + "\' cannot be deleted. Tariff does not exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+ if (store->DelTariff(name))
+ {
+ WriteServLog("Cannot delete tariff %s.", name.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ return -1;
+ }
+
+ td = ti->GetTariffData();
+
+ tariffs.erase(ti);
+ }
+
+auto ni = onDelNotifiers.begin();
+while (ni != onDelNotifiers.end())
+ {
+ (*ni)->Notify(td);
+ ++ni;
+ }
+
+WriteServLog("%s Tariff \'%s\' deleted.",
+ admin->logStr().c_str(),
+ name.c_str());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TariffsImpl::Add(const std::string & name, const Admin * admin)
+{
+const auto& priv = admin->priv();
+
+if (!priv.tariffChg)
+ {
+ std::string s = admin->logStr() + " Add tariff \'"
+ + name + "\'. Access denied.";
+ strError = "Access denied.";
+ WriteServLog(s.c_str());
+ return -1;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ const auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(name));
+
+ if (ti != tariffs.end())
+ {
+ strError = "Tariff \'" + name + "\' cannot be added. Tariff already exist.";
+ WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
+ return -1;
+ }
+
+ tariffs.push_back(TariffImpl(name));
+ }
+
+if (store->AddTariff(name) < 0)
+ {
+ strError = "Tariff " + name + " adding error. " + store->GetStrError();
+ WriteServLog(strError.c_str());
+ return -1;
+ }
+
+// Fire all "on add" notifiers
+auto ni = onAddNotifiers.begin();
+while (ni != onAddNotifiers.end())
+ {
+ (*ni)->Notify(tariffs.back().GetTariffData());
+ ++ni;
+ }
+
+WriteServLog("%s Tariff \'%s\' added.",
+ admin->logStr().c_str(), name.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void TariffsImpl::GetTariffsData(std::vector<TariffData> * tdl) const
+{
+assert(tdl != NULL && "Tariffs data list is not null");
+std::lock_guard<std::mutex> lock(m_mutex);
+
+auto it = tariffs.begin();
+for (; it != tariffs.end(); ++it)
+ {
+ tdl->push_back(it->GetTariffData());
+ }
+}
+//-----------------------------------------------------------------------------
+void TariffsImpl::AddNotifierAdd(NotifierBase<TariffData> * n)
+{
+std::lock_guard<std::mutex> lock(m_mutex);
+onAddNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+void TariffsImpl::DelNotifierAdd(NotifierBase<TariffData> * n)
+{
+std::lock_guard<std::mutex> lock(m_mutex);
+onAddNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+void TariffsImpl::AddNotifierDel(NotifierBase<TariffData> * n)
+{
+std::lock_guard<std::mutex> lock(m_mutex);
+onDelNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+void TariffsImpl::DelNotifierDel(NotifierBase<TariffData> * n)
+{
+std::lock_guard<std::mutex> lock(m_mutex);
+onDelNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 07.11.2007
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/tariff.h"
+#include "stg/tariffs.h"
+#include "stg/tariff_conf.h"
+#include "tariff_impl.h"
+
+#include <string>
+#include <vector>
+#include <set>
+#include <mutex>
+
+namespace STG
+{
+
+struct Store;
+class Logger;
+struct Admin;
+
+class TariffsImpl : public Tariffs {
+ public:
+ using Data = std::vector<TariffImpl>;
+
+ explicit TariffsImpl(Store * store);
+
+ int ReadTariffs () override;
+ const Tariff * FindByName(const std::string & name) const override;
+ const Tariff * GetNoTariff() const override { return &noTariff; }
+ size_t Count() const override;
+ int Del(const std::string & name, const Admin * admin) override;
+ int Add(const std::string & name, const Admin * admin) override;
+ int Chg(const TariffData & td, const Admin * admin) override;
+
+ void AddNotifierAdd(NotifierBase<TariffData> * notifier) override;
+ void DelNotifierAdd(NotifierBase<TariffData> * notifier) override;
+
+ void AddNotifierDel(NotifierBase<TariffData> * notifier) override;
+ void DelNotifierDel(NotifierBase<TariffData> * notifier) override;
+
+ void GetTariffsData(std::vector<TariffData> * tdl) const override;
+
+ const std::string & GetStrError() const override { return strError; }
+
+ private:
+ Data tariffs;
+ Store* store;
+ Logger& WriteServLog;
+ mutable std::mutex m_mutex;
+ std::string strError;
+ TariffImpl noTariff;
+
+ std::set<NotifierBase<TariffData>*> onAddNotifiers;
+ std::set<NotifierBase<TariffData>*> onDelNotifiers;
+};
+
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 27.10.2002
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.58 $
+ $Date: 2010/11/03 11:28:07 $
+ $Author: faust $
+ */
+
+/* inet_aton */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <csignal>
+#include <cassert>
+#include <cstdio> // fopen and similar
+#include <cstdlib> // strtol
+
+#include "stg/common.h"
+#include "stg/locker.h"
+#include "stg/const.h" // MONITOR_TIME_DELAY_SEC
+#include "traffcounter_impl.h"
+#include "stg_timer.h"
+#include "users_impl.h"
+
+#define FLUSH_TIME (10)
+#define REMOVE_TIME (31)
+
+using STG::TraffCounterImpl;
+
+const char protoName[PROTOMAX][8] =
+{"TCP", "UDP", "ICMP", "TCP_UDP", "ALL"};
+
+enum protoNum
+{
+tcp = 0, udp, icmp, tcp_udp, all
+};
+
+//-----------------------------------------------------------------------------
+TraffCounterImpl::TraffCounterImpl(UsersImpl * u, const std::string & fn)
+ : WriteServLog(Logger::get()),
+ rulesFileName(fn),
+ monitoring(false),
+ touchTimeP(stgTime - MONITOR_TIME_DELAY_SEC),
+ users(u),
+ running(false),
+ stopped(true),
+ addUserNotifier(*this),
+ delUserNotifier(*this)
+{
+for (int i = 0; i < DIR_NUM; i++)
+ strprintf(&dirName[i], "DIR%d", i);
+
+dirName[DIR_NUM] = "NULL";
+
+users->AddNotifierUserAdd(&addUserNotifier);
+users->AddNotifierUserDel(&delUserNotifier);
+
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+TraffCounterImpl::~TraffCounterImpl()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int TraffCounterImpl::Start()
+{
+STG_LOCKER lock(&mutex);
+
+if (!stopped)
+ return 0;
+
+if (ReadRules())
+ {
+ printfd(__FILE__, "TraffCounterImpl::Start() - Cannot read rules\n");
+ WriteServLog("TraffCounter: Cannot read rules.");
+ return -1;
+ }
+
+printfd(__FILE__, "TraffCounter::Start()\n");
+int h = users->OpenSearch();
+assert(h && "USERS::OpenSearch is always correct");
+UserImpl * u;
+
+while (users->SearchNext(h, &u) == 0)
+ SetUserNotifiers(u);
+users->CloseSearch(h);
+
+running = true;
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ printfd(__FILE__, "TraffCounterImpl::Start() - Cannot start thread\n");
+ WriteServLog("TraffCounter: Error: Cannot start thread.");
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TraffCounterImpl::Stop()
+{
+if (stopped)
+ return 0;
+
+running = false;
+
+int h = users->OpenSearch();
+assert(h && "USERS::OpenSearch is always correct");
+
+UserImpl * u;
+while (users->SearchNext(h, &u) == 0)
+ UnSetUserNotifiers(u);
+users->CloseSearch(h);
+
+//5 seconds to thread stops itself
+struct timespec ts = {0, 200000000};
+for (int i = 0; i < 25 && !stopped; i++)
+ {
+ nanosleep(&ts, NULL);
+ }
+
+if (!stopped)
+ return -1;
+
+printfd(__FILE__, "TraffCounter::Stop()\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * TraffCounterImpl::Run(void * data)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+TraffCounterImpl * tc = static_cast<TraffCounterImpl *>(data);
+tc->stopped = false;
+int c = 0;
+
+time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+struct timespec ts = {0, 500000000};
+while (tc->running)
+ {
+ nanosleep(&ts, 0);
+ if (!tc->running)
+ {
+ tc->FlushAndRemove();
+ break;
+ }
+
+ if (tc->monitoring && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
+ {
+ std::string monFile(tc->monitorDir + "/traffcounter_r");
+ printfd(__FILE__, "Monitor=%d file TraffCounter %s\n", tc->monitoring, monFile.c_str());
+ touchTime = stgTime;
+ TouchFile(monFile);
+ }
+
+ if (++c % FLUSH_TIME == 0)
+ tc->FlushAndRemove();
+ }
+
+tc->stopped = true;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::process(const RawPacket & rawPacket)
+{
+if (!running)
+ return;
+
+if (monitoring && (touchTimeP + MONITOR_TIME_DELAY_SEC <= stgTime))
+ {
+ std::string monFile = monitorDir + "/traffcounter_p";
+ printfd(__FILE__, "Monitor=%d file TraffCounter %s\n", monitoring, monFile.c_str());
+ touchTimeP = stgTime;
+ TouchFile(monFile);
+ }
+
+STG_LOCKER lock(&mutex);
+
+//printfd(__FILE__, "TraffCounter::Process()\n");
+//TODO replace find with lower_bound.
+
+// Searching a new packet in a tree.
+pp_iter pi = packets.find(rawPacket);
+
+// Packet found - update length and time
+if (pi != packets.end())
+ {
+ pi->second.lenU += rawPacket.GetLen();
+ pi->second.lenD += rawPacket.GetLen();
+ pi->second.updateTime = stgTime;
+ /*printfd(__FILE__, "=============================\n");
+ printfd(__FILE__, "Packet found!\n");
+ printfd(__FILE__, "Version=%d\n", rawPacket.GetIPVersion());
+ printfd(__FILE__, "HeaderLen=%d\n", rawPacket.GetHeaderLen());
+ printfd(__FILE__, "PacketLen=%d\n", rawPacket.GetLen());
+ printfd(__FILE__, "SIP=%s\n", inet_ntostring(rawPacket.GetSrcIP()).c_str());
+ printfd(__FILE__, "DIP=%s\n", inet_ntostring(rawPacket.GetDstIP()).c_str());
+ printfd(__FILE__, "src port=%d\n", rawPacket.GetSrcPort());
+ printfd(__FILE__, "pst port=%d\n", rawPacket.GetDstPort());
+ printfd(__FILE__, "len=%d\n", rawPacket.GetLen());
+ printfd(__FILE__, "proto=%d\n", rawPacket.GetProto());
+ printfd(__FILE__, "PacketDirU=%d\n", pi->second.dirU);
+ printfd(__FILE__, "PacketDirD=%d\n", pi->second.dirD);
+ printfd(__FILE__, "=============================\n");*/
+ return;
+ }
+
+PacketExtraData ed;
+
+// Packet not found - add new packet
+
+ed.updateTime = stgTime;
+ed.flushTime = stgTime;
+
+/*
+ userU is that whose user_ip == packet_ip_src
+ userD is that whose user_ip == packet_ip_dst
+ */
+
+uint32_t ipU = rawPacket.GetSrcIP();
+uint32_t ipD = rawPacket.GetDstIP();
+
+// Searching users with such IP
+if (users->FindByIPIdx(ipU, &ed.userU) == 0)
+ {
+ ed.userUPresent = true;
+ }
+
+if (users->FindByIPIdx(ipD, &ed.userD) == 0)
+ {
+ ed.userDPresent = true;
+ }
+
+if (ed.userUPresent ||
+ ed.userDPresent)
+ {
+ DeterminateDir(rawPacket, &ed.dirU, &ed.dirD);
+
+ ed.lenD = ed.lenU = rawPacket.GetLen();
+
+ //TODO use result of lower_bound to inserting new record
+
+ // Adding packet to a tree.
+ std::pair<pp_iter, bool> insertResult = packets.insert(std::make_pair(rawPacket, ed));
+ pp_iter newPacket = insertResult.first;
+
+ // Adding packet reference to an IP index.
+ ip2packets.insert(std::make_pair(ipU, newPacket));
+ ip2packets.insert(std::make_pair(ipD, newPacket));
+ }
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::FlushAndRemove()
+{
+STG_LOCKER lock(&mutex);
+
+Packets::size_type oldPacketsSize = packets.size();
+Index::size_type oldIp2packetsSize = ip2packets.size();
+
+pp_iter pi;
+pi = packets.begin();
+Packets newPackets;
+ip2packets.erase(ip2packets.begin(), ip2packets.end());
+while (pi != packets.end())
+ {
+ //Flushing
+ if (stgTime - pi->second.flushTime > FLUSH_TIME)
+ {
+ if (pi->second.userUPresent)
+ {
+ //printfd(__FILE__, "+++ Flushing U user %s (%s:%d) of length %d\n", pi->second.userU->GetLogin().c_str(), inet_ntostring(pi->first.GetSrcIP()).c_str(), pi->first.GetSrcPort(), pi->second.lenU);
+
+ // Add stat
+ if (pi->second.dirU < DIR_NUM)
+ {
+ #ifdef TRAFF_STAT_WITH_PORTS
+ pi->second.userU->AddTraffStatU(pi->second.dirU,
+ pi->first.GetDstIP(),
+ pi->first.GetDstPort(),
+ pi->second.lenU);
+ #else
+ pi->second.userU->AddTraffStatU(pi->second.dirU,
+ pi->first.GetDstIP(),
+ pi->second.lenU);
+ #endif
+ }
+
+ pi->second.lenU = 0;
+ pi->second.flushTime = stgTime;
+ }
+
+ if (pi->second.userDPresent)
+ {
+ //printfd(__FILE__, "+++ Flushing D user %s (%s:%d) of length %d\n", pi->second.userD->GetLogin().c_str(), inet_ntostring(pi->first.GetDstIP()).c_str(), pi->first.GetDstPort(), pi->second.lenD);
+
+ // Add stat
+ if (pi->second.dirD < DIR_NUM)
+ {
+ #ifdef TRAFF_STAT_WITH_PORTS
+ pi->second.userD->AddTraffStatD(pi->second.dirD,
+ pi->first.GetSrcIP(),
+ pi->first.GetSrcPort(),
+ pi->second.lenD);
+ #else
+ pi->second.userD->AddTraffStatD(pi->second.dirD,
+ pi->first.GetSrcIP(),
+ pi->second.lenD);
+ #endif
+ }
+
+ pi->second.lenD = 0;
+ pi->second.flushTime = stgTime;
+ }
+ }
+
+ if (stgTime - pi->second.updateTime < REMOVE_TIME)
+ {
+ std::pair<pp_iter, bool> res = newPackets.insert(*pi);
+ if (res.second)
+ {
+ ip2packets.insert(std::make_pair(pi->first.GetSrcIP(), res.first));
+ ip2packets.insert(std::make_pair(pi->first.GetDstIP(), res.first));
+ }
+ }
+ ++pi;
+ }
+swap(packets, newPackets);
+printfd(__FILE__, "FlushAndRemove() packets: %d(rem %d) ip2packets: %d(rem %d)\n",
+ packets.size(),
+ oldPacketsSize - packets.size(),
+ ip2packets.size(),
+ oldIp2packetsSize - ip2packets.size());
+
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::AddUser(UserImpl * user)
+{
+printfd(__FILE__, "AddUser: %s\n", user->GetLogin().c_str());
+uint32_t uip = user->GetCurrIP();
+std::pair<ip2p_iter, ip2p_iter> pi;
+
+STG_LOCKER lock(&mutex);
+// Find all packets with IP belongs to this user
+pi = ip2packets.equal_range(uip);
+
+while (pi.first != pi.second)
+ {
+ if (pi.first->second->first.GetSrcIP() == uip)
+ {
+ assert((!pi.first->second->second.userUPresent ||
+ pi.first->second->second.userU == user) &&
+ "U user present but it's not current user");
+
+ pi.first->second->second.lenU = 0;
+ pi.first->second->second.userU = user;
+ pi.first->second->second.userUPresent = true;
+ }
+
+ if (pi.first->second->first.GetDstIP() == uip)
+ {
+ assert((!pi.first->second->second.userDPresent ||
+ pi.first->second->second.userD == user) &&
+ "D user present but it's not current user");
+
+ pi.first->second->second.lenD = 0;
+ pi.first->second->second.userD = user;
+ pi.first->second->second.userDPresent = true;
+ }
+
+ ++pi.first;
+ }
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::DelUser(uint32_t uip)
+{
+printfd(__FILE__, "DelUser: %s \n", inet_ntostring(uip).c_str());
+std::pair<ip2p_iter, ip2p_iter> pi;
+
+STG_LOCKER lock(&mutex);
+pi = ip2packets.equal_range(uip);
+
+while (pi.first != pi.second)
+ {
+ if (pi.first->second->first.GetSrcIP() == uip)
+ {
+ if (pi.first->second->second.dirU < DIR_NUM && pi.first->second->second.userUPresent)
+ {
+ #ifdef TRAFF_STAT_WITH_PORTS
+ pi.first->second->second.userU->AddTraffStatU(pi.first->second->second.dirU,
+ pi.first->second->first.GetDstIP(),
+ pi.first->second->first.GetDstPort(),
+ pi.first->second->second.lenU);
+ #else
+ pi.first->second->second.userU->AddTraffStatU(pi.first->second->second.dirU,
+ pi.first->second->first.GetDstIP(),
+ pi.first->second->second.lenU);
+ #endif
+ }
+ pi.first->second->second.userUPresent = false;
+ }
+
+ if (pi.first->second->first.GetDstIP() == uip)
+ {
+ if (pi.first->second->second.dirD < DIR_NUM && pi.first->second->second.userDPresent)
+ {
+ #ifdef TRAFF_STAT_WITH_PORTS
+ pi.first->second->second.userD->AddTraffStatD(pi.first->second->second.dirD,
+ pi.first->second->first.GetSrcIP(),
+ pi.first->second->first.GetSrcPort(),
+ pi.first->second->second.lenD);
+ #else
+ pi.first->second->second.userD->AddTraffStatD(pi.first->second->second.dirD,
+ pi.first->second->first.GetSrcIP(),
+ pi.first->second->second.lenD);
+ #endif
+ }
+
+ pi.first->second->second.userDPresent = false;
+ }
+
+ ++pi.first;
+ }
+
+ip2packets.erase(pi.first, pi.second);
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::SetUserNotifiers(UserImpl * user)
+{
+// Adding user. Adding notifiers to user.
+TRF_IP_BEFORE ipBNotifier(*this, user);
+ipBeforeNotifiers.push_front(ipBNotifier);
+user->AddCurrIPBeforeNotifier(&(*ipBeforeNotifiers.begin()));
+
+TRF_IP_AFTER ipANotifier(*this, user);
+ipAfterNotifiers.push_front(ipANotifier);
+user->AddCurrIPAfterNotifier(&(*ipAfterNotifiers.begin()));
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::UnSetUserNotifiers(UserImpl * user)
+{
+// Removing user. Removing notifiers from user.
+std::list<TRF_IP_BEFORE>::iterator bi;
+std::list<TRF_IP_AFTER>::iterator ai;
+
+bi = ipBeforeNotifiers.begin();
+while (bi != ipBeforeNotifiers.end())
+ {
+ if (user->GetLogin() == bi->GetUser()->GetLogin())
+ {
+ user->DelCurrIPBeforeNotifier(&(*bi));
+ ipBeforeNotifiers.erase(bi);
+ break;
+ }
+ ++bi;
+ }
+
+ai = ipAfterNotifiers.begin();
+while (ai != ipAfterNotifiers.end())
+ {
+ if (user->GetLogin() == ai->GetUser()->GetLogin())
+ {
+ user->DelCurrIPAfterNotifier(&(*ai));
+ ipAfterNotifiers.erase(ai);
+ break;
+ }
+ ++ai;
+ }
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::DeterminateDir(const RawPacket & packet,
+ int * dirU, // Direction for incoming packet
+ int * dirD) const // Direction for outgoing packet
+{
+bool addrMatchU = false;
+bool portMatchU = false;
+bool addrMatchD = false;
+bool portMatchD = false;
+bool foundU = false; // Was rule for U found ?
+bool foundD = false; // Was rule for D found ?
+//printfd(__FILE__, "foundU=%d, foundD=%d\n", foundU, foundD);
+
+enum { ICMP_RPOTO = 1, TCP_PROTO = 6, UDP_PROTO = 17 };
+
+std::list<Rule>::const_iterator ln;
+ln = rules.begin();
+
+while (ln != rules.end())
+ {
+ if (!foundU)
+ {
+ portMatchU = false;
+
+ switch (ln->proto)
+ {
+ case all:
+ portMatchU = true;
+ break;
+
+ case icmp:
+ portMatchU = (packet.GetProto() == ICMP_RPOTO);
+ break;
+
+ case tcp_udp:
+ if (packet.GetProto() == TCP_PROTO || packet.GetProto() == UDP_PROTO)
+ portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
+ break;
+
+ case tcp:
+ if (packet.GetProto() == TCP_PROTO)
+ portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
+ break;
+
+ case udp:
+ if (packet.GetProto() == UDP_PROTO)
+ portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
+ break;
+
+ default:
+ printfd(__FILE__, "Error! Incorrect rule!\n");
+ break;
+ }
+
+ addrMatchU = (packet.GetDstIP() & ln->mask) == ln->ip;
+
+ if (!foundU && addrMatchU && portMatchU)
+ {
+ foundU = true;
+ *dirU = ln->dir;
+ //printfd(__FILE__, "Up rule ok! %d\n", ln->dir);
+ }
+
+ } //if (!foundU)
+
+ if (!foundD)
+ {
+ portMatchD = false;
+
+ switch (ln->proto)
+ {
+ case all:
+ portMatchD = true;
+ break;
+
+ case icmp:
+ portMatchD = (packet.GetProto() == ICMP_RPOTO);
+ break;
+
+ case tcp_udp:
+ if (packet.GetProto() == TCP_PROTO || packet.GetProto() == UDP_PROTO)
+ portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
+ break;
+
+ case tcp:
+ if (packet.GetProto() == TCP_PROTO)
+ portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
+ break;
+
+ case udp:
+ if (packet.GetProto() == UDP_PROTO)
+ portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
+ break;
+
+ default:
+ printfd(__FILE__, "Error! Incorrect rule!\n");
+ break;
+ }
+
+ addrMatchD = (packet.GetSrcIP() & ln->mask) == ln->ip;
+
+ if (!foundD && addrMatchD && portMatchD)
+ {
+ foundD = true;
+ *dirD = ln->dir;
+ //printfd(__FILE__, "Down rule ok! %d\n", ln->dir);
+ }
+ } //if (!foundD)
+
+ ++ln;
+ } //while (ln != rules.end())
+
+if (!foundU)
+ *dirU = DIR_NUM;
+
+if (!foundD)
+ *dirD = DIR_NUM;
+}
+//-----------------------------------------------------------------------------
+bool TraffCounterImpl::ReadRules(bool test)
+{
+//printfd(__FILE__, "TraffCounter::ReadRules()\n");
+
+Rule rul;
+FILE * f;
+char str[1024];
+char tp[100]; // protocol
+char ta[100]; // address
+char td[100]; // target direction
+int r;
+int lineNumber = 0;
+f = fopen(rulesFileName.c_str(), "rt");
+
+if (!f)
+ {
+ printfd(__FILE__, "TraffCounterImpl::ReadRules() - File '%s' cannot be opened.\n", rulesFileName.c_str());
+ WriteServLog("File '%s' cannot be oppened.", rulesFileName.c_str());
+ return true;
+ }
+
+while (fgets(str, 1023, f))
+ {
+ lineNumber++;
+ if (str[strspn(str," \t")] == '#' || str[strspn(str," \t")] == '\n')
+ {
+ continue;
+ }
+
+ r = sscanf(str,"%99s %99s %99s", tp, ta, td);
+ if (r != 3)
+ {
+ printfd(__FILE__, "TraffCounterImpl::ReadRules() - Error in file '%s' at line %d. There must be 3 parameters.\n", rulesFileName.c_str(), lineNumber);
+ WriteServLog("Error in file '%s' at line %d. There must be 3 parameters.", rulesFileName.c_str(), lineNumber);
+ fclose(f);
+ return true;
+ }
+
+ rul.proto = 0xff;
+ rul.dir = 0xff;
+
+ for (uint8_t i = 0; i < PROTOMAX; i++)
+ {
+ if (strcasecmp(tp, protoName[i]) == 0)
+ rul.proto = i;
+ }
+
+ for (uint32_t i = 0; i < DIR_NUM + 1; i++)
+ {
+ if (td == dirName[i])
+ rul.dir = i;
+ }
+
+ if (rul.dir == 0xff || rul.proto == 0xff)
+ {
+ printfd(__FILE__, "TraffCounterImpl::ReadRules() - Error in file '%s' at line %d.\n", rulesFileName.c_str(), lineNumber);
+ WriteServLog("Error in file %s. Line %d.",
+ rulesFileName.c_str(), lineNumber);
+ fclose(f);
+ return true;
+ }
+
+ if (ParseAddress(ta, &rul) != 0)
+ {
+ printfd(__FILE__, "TraffCounterImpl::ReadRules() - Error in file '%s' at line %d. Error in adress.\n", rulesFileName.c_str(), lineNumber);
+ WriteServLog("Error in file %s. Error in adress. Line %d.",
+ rulesFileName.c_str(), lineNumber);
+ fclose(f);
+ return true;
+ }
+ if (!test)
+ rules.push_back(rul);
+ }
+
+fclose(f);
+
+// Adding lastest rule: ALL 0.0.0.0/0 NULL
+rul.dir = DIR_NUM; //NULL
+rul.ip = 0; //0.0.0.0
+rul.mask = 0;
+rul.port1 = 0;
+rul.port2 = 65535;
+rul.proto = all;
+
+if (!test)
+ rules.push_back(rul);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+int TraffCounterImpl::Reload()
+{
+STG_LOCKER lock(&mutex);
+
+if (ReadRules(true))
+ {
+ printfd(__FILE__, "TraffCounterImpl::Reload() - Failed to reload rules.\n");
+ WriteServLog("TraffCounter: Cannot reload rules. Errors found.");
+ return -1;
+ }
+
+FreeRules();
+ReadRules();
+printfd(__FILE__, "TraffCounterImpl::Reload() - Reloaded rules successfully.\n");
+WriteServLog("TraffCounter: Reloaded rules successfully.");
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool TraffCounterImpl::ParseAddress(const char * ta, Rule * rule) const
+{
+char addr[50], mask[20], port1[20], port2[20], ports[40];
+
+size_t len = strlen(ta);
+char n = 0;
+size_t i, p;
+memset(addr, 0, sizeof(addr));
+for (i = 0; i < len; i++)
+ {
+ if (ta[i] == '/' || ta[i] == ':')
+ {
+ addr[i] = 0;
+ n = ta[i];
+ break;
+ }
+ addr[i] = ta[i];
+ n = 0;
+ }
+addr[i + 1] = 0;
+p = i + 1;
+
+if (n == '/')
+ {
+ // mask
+ for (; i < len; i++)
+ {
+ if (ta[i] == ':')
+ {
+ mask[i - p] = 0;
+ n = ':';
+ break;
+ }
+ mask[i - p] = ta[i];
+ }
+ mask[i - p] = 0;
+ }
+else
+ {
+ strcpy(mask, "32");
+ }
+
+p = i + 1;
+i++;
+
+if (n == ':')
+ {
+ // port
+ if (!(rule->proto == tcp || rule->proto == udp || rule->proto == tcp_udp))
+ {
+ printfd(__FILE__, "TraffCounterImpl::ParseAddress() - No ports specified for this protocol.\n");
+ WriteServLog("No ports specified for this protocol.");
+ return true;
+ }
+
+ for (; i < len; i++)
+ ports[i - p] = ta[i];
+
+ ports[i - p] = 0;
+ }
+else
+ {
+ strcpy(ports, "0-65535");
+ }
+
+char *sss;
+char pts[100];
+strcpy(pts, ports);
+
+if ((sss = strchr(ports, '-')) != NULL)
+ {
+ strncpy(port1, ports, int(sss-ports));
+ port1[int(sss - ports)] = 0;
+ strcpy(port2, sss + 1);
+ }
+else
+ {
+ strcpy(port1, ports);
+ strcpy(port2, ports);
+ }
+
+// Convert strings to mask, ports and IP
+uint16_t prt1, prt2, msk;
+struct in_addr ipaddr;
+char *res;
+
+msk = static_cast<uint16_t>(strtol(mask, &res, 10));
+if (*res != 0)
+ return true;
+
+prt1 = static_cast<uint16_t>(strtol(port1, &res, 10));
+if (*res != 0)
+ return true;
+
+prt2 = static_cast<uint16_t>(strtol(port2, &res, 10));
+if (*res != 0)
+ return true;
+
+int r = inet_aton(addr, &ipaddr);
+if (r == 0)
+ return true;
+
+rule->ip = ipaddr.s_addr;
+rule->mask = CalcMask(msk);
+
+if ((ipaddr.s_addr & rule->mask) != ipaddr.s_addr)
+ {
+ printfd(__FILE__, "TraffCounterImpl::ParseAddress() - Address does'n match mask.\n");
+ WriteServLog("Address does'n match mask.");
+ return true;
+ }
+
+rule->port1 = prt1;
+rule->port2 = prt2;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+uint32_t TraffCounterImpl::CalcMask(uint32_t msk) const
+{
+if (msk >= 32) return 0xFFffFFff;
+if (msk == 0) return 0;
+return htonl(0xFFffFFff << (32 - msk));
+}
+//---------------------------------------------------------------------------
+void TraffCounterImpl::FreeRules()
+{
+rules.clear();
+}
+//-----------------------------------------------------------------------------
+void TraffCounterImpl::SetMonitorDir(const std::string & dir)
+{
+monitorDir = dir;
+monitoring = !monitorDir.empty();
+}
+//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/traffcounter.h"
+#include "stg/logger.h"
+#include "stg/raw_ip_packet.h"
+#include "stg/noncopyable.h"
+#include "stg/notifer.h"
+#include "actions.h"
+#include "eventloop.h"
+#include "user_impl.h"
+
+#include <ctime>
+#include <list>
+#include <map>
+#include <string>
+#include <cstdint>
+
+#include <pthread.h>
+
+#define PROTOMAX (5)
+
+namespace STG
+{
+
+class UsersImpl;
+
+//-----------------------------------------------------------------------------
+struct Rule {
+uint32_t ip; // IP
+uint32_t mask; // Network mask
+uint16_t port1; // Min port
+uint16_t port2; // Max port
+uint8_t proto; // Protocol
+uint32_t dir; // Direction
+};
+//-----------------------------------------------------------------------------
+struct PacketExtraData {
+ PacketExtraData()
+ : flushTime(0),
+ updateTime(0),
+ userU(NULL),
+ userUPresent(false),
+ userD(NULL),
+ userDPresent(false),
+ dirU(DIR_NUM),
+ dirD(DIR_NUM),
+ lenU(0),
+ lenD(0)
+ {}
+
+ time_t flushTime; // Last flush time
+ time_t updateTime; // Last update time
+ UserImpl * userU; // Uploader
+ bool userUPresent; // Uploader is registered user
+ UserImpl * userD; // Downloader
+ bool userDPresent; // Downloader is registered user
+ int dirU; // Upload direction
+ int dirD; // Download direction
+ uint32_t lenU; // Upload length
+ uint32_t lenD; // Download length
+};
+//-----------------------------------------------------------------------------
+class TraffCounterImpl;
+//-----------------------------------------------------------------------------
+class TRF_IP_BEFORE: public PropertyNotifierBase<uint32_t> {
+public:
+ TRF_IP_BEFORE(TraffCounterImpl & t, UserImpl * u)
+ : PropertyNotifierBase<uint32_t>(),
+ traffCnt(t),
+ user(u)
+ {}
+ TRF_IP_BEFORE(const TRF_IP_BEFORE & rvalue)
+ : PropertyNotifierBase<uint32_t>(),
+ traffCnt(rvalue.traffCnt),
+ user(rvalue.user)
+ {}
+ void Notify(const uint32_t & oldValue, const uint32_t & newValue);
+ void SetUser(UserImpl * u) { user = u; }
+ UserImpl * GetUser() const { return user; }
+
+private:
+ TRF_IP_BEFORE & operator=(const TRF_IP_BEFORE & rvalue);
+
+ TraffCounterImpl & traffCnt;
+ UserImpl * user;
+};
+//-----------------------------------------------------------------------------
+class TRF_IP_AFTER: public PropertyNotifierBase<uint32_t> {
+public:
+ TRF_IP_AFTER(TraffCounterImpl & t, UserImpl * u)
+ : PropertyNotifierBase<uint32_t>(),
+ traffCnt(t),
+ user(u)
+ {}
+ TRF_IP_AFTER(const TRF_IP_AFTER & rvalue)
+ : PropertyNotifierBase<uint32_t>(),
+ traffCnt(rvalue.traffCnt),
+ user(rvalue.user)
+ {}
+ void Notify(const uint32_t & oldValue, const uint32_t & newValue);
+ void SetUser(UserImpl * u) { user = u; }
+ UserImpl * GetUser() const { return user; }
+private:
+ TRF_IP_AFTER & operator=(const TRF_IP_AFTER & rvalue);
+
+ TraffCounterImpl & traffCnt;
+ UserImpl * user;
+};
+
+using UserImplPtr = UserImpl*;
+//-----------------------------------------------------------------------------
+class ADD_USER_NONIFIER: public NotifierBase<UserImplPtr> {
+public:
+ explicit ADD_USER_NONIFIER(TraffCounterImpl & t) :
+ NotifierBase<UserImplPtr>(),
+ traffCnt(t)
+ {}
+ virtual ~ADD_USER_NONIFIER() {}
+ void Notify(const UserImplPtr & user);
+
+private:
+ ADD_USER_NONIFIER(const ADD_USER_NONIFIER & rvalue);
+ ADD_USER_NONIFIER & operator=(const ADD_USER_NONIFIER & rvalue);
+
+ TraffCounterImpl & traffCnt;
+};
+//-----------------------------------------------------------------------------
+class DEL_USER_NONIFIER: public NotifierBase<UserImplPtr> {
+public:
+ explicit DEL_USER_NONIFIER(TraffCounterImpl & t) :
+ NotifierBase<UserImplPtr>(),
+ traffCnt(t)
+ {}
+ virtual ~DEL_USER_NONIFIER() {}
+ void Notify(const UserImplPtr & user);
+
+private:
+ DEL_USER_NONIFIER(const DEL_USER_NONIFIER & rvalue);
+ DEL_USER_NONIFIER & operator=(const DEL_USER_NONIFIER & rvalue);
+
+ TraffCounterImpl & traffCnt;
+};
+//-----------------------------------------------------------------------------
+class TraffCounterImpl : public TraffCounter {
+ friend class ADD_USER_NONIFIER;
+ friend class DEL_USER_NONIFIER;
+ friend class TRF_IP_BEFORE;
+ friend class TRF_IP_AFTER;
+ public:
+ TraffCounterImpl(UsersImpl * users, const std::string & rulesFileName);
+ ~TraffCounterImpl();
+
+ int Reload();
+ int Start();
+ int Stop();
+
+ void process(const RawPacket & rawPacket) override;
+ void SetMonitorDir(const std::string & monitorDir);
+
+ size_t rulesCount() const override { return rules.size(); }
+
+ private:
+ bool ParseAddress(const char * ta, Rule * rule) const;
+ uint32_t CalcMask(uint32_t msk) const;
+ void FreeRules();
+ bool ReadRules(bool test = false);
+
+ static void * Run(void * data);
+
+ void DeterminateDir(const RawPacket & packet,
+ int * dirU, // Direction for upload
+ int * dirD) const; // Direction for download
+
+ void FlushAndRemove();
+
+ void AddUser(UserImpl * user);
+ void DelUser(uint32_t uip);
+ void SetUserNotifiers(UserImpl * user);
+ void UnSetUserNotifiers(UserImpl * user);
+
+ typedef std::list<Rule>::iterator rule_iter;
+
+ std::list<Rule> rules;
+
+ typedef std::map<RawPacket, PacketExtraData> Packets;
+ typedef Packets::iterator pp_iter;
+ typedef std::multimap<uint32_t, pp_iter> Index;
+ typedef Index::iterator ip2p_iter;
+ typedef Index::const_iterator ip2p_citer;
+
+ Packets packets; // Packets tree
+
+ Index ip2packets; // IP-to-Packet index
+
+ std::string dirName[DIR_NUM + 1];
+
+ Logger & WriteServLog;
+ std::string rulesFileName;
+
+ std::string monitorDir;
+ bool monitoring;
+ time_t touchTimeP;
+
+ UsersImpl * users;
+
+ bool running;
+ bool stopped;
+ pthread_mutex_t mutex;
+ pthread_t thread;
+
+ std::list<TRF_IP_BEFORE> ipBeforeNotifiers;
+ std::list<TRF_IP_AFTER> ipAfterNotifiers;
+
+ ADD_USER_NONIFIER addUserNotifier;
+ DEL_USER_NONIFIER delUserNotifier;
+};
+//-----------------------------------------------------------------------------
+inline
+void TRF_IP_BEFORE::Notify(const uint32_t & oldValue, const uint32_t &)
+{
+// User changes his address. Remove old IP
+if (!oldValue)
+ return;
+
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::DelUser, oldValue);
+}
+//-----------------------------------------------------------------------------
+inline
+void TRF_IP_AFTER::Notify(const uint32_t &, const uint32_t & newValue)
+{
+// User changes his address. Add new IP
+if (!newValue)
+ return;
+
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::AddUser, user);
+}
+//-----------------------------------------------------------------------------
+inline
+void ADD_USER_NONIFIER::Notify(const UserImplPtr & user)
+{
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::SetUserNotifiers, user);
+}
+//-----------------------------------------------------------------------------
+inline
+void DEL_USER_NONIFIER::Notify(const UserImplPtr & user)
+{
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::UnSetUserNotifiers, user);
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::DelUser, user->GetCurrIP());
+}
+//-----------------------------------------------------------------------------
+}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 27.10.2002
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.101 $
+ $Date: 2010/11/03 10:50:03 $
+ $Author: faust $
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "user_impl.h"
+#include "settings_impl.h"
+#include "stg_timer.h"
+
+#include "stg/users.h"
+#include "stg/common.h"
+#include "stg/scriptexecuter.h"
+#include "stg/tariff.h"
+#include "stg/tariffs.h"
+#include "stg/services.h"
+#include "stg/service_conf.h"
+#include "stg/admin.h"
+
+#include <algorithm>
+#include <functional>
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+
+#include <pthread.h>
+#include <unistd.h> // access
+
+using STG::UserImpl;
+
+namespace
+{
+
+std::string dirsToString(const bool * dirs)
+{
+std::string res;
+for (size_t i = 0; i < DIR_NUM; i++)
+ res += dirs[i] ? '1' : '0';
+return res;
+}
+
+void dirsFromBits(bool * dirs, uint32_t bits)
+{
+for (size_t i = 0; i < DIR_NUM; i++)
+ dirs[i] = bits & (1 << i);
+}
+
+}
+
+UserImpl::UserImpl(const Settings * s,
+ const Store * st,
+ const Tariffs * t,
+ const Admin * a,
+ const Users * u,
+ const Services & svcs)
+ : users(u),
+ properties(*s),
+ WriteServLog(Logger::get()),
+ lastScanMessages(0),
+ id(0),
+ __connected(0),
+ connected(__connected),
+ __currIP(0),
+ currIP(__currIP),
+ lastIPForDisconnect(0),
+ pingTime(0),
+ sysAdmin(a),
+ store(st),
+ tariffs(t),
+ tariff(NULL),
+ m_services(svcs),
+ settings(s),
+ authorizedModificationTime(0),
+ deleted(false),
+ lastWriteStat(0),
+ lastWriteDetailedStat(0),
+ cash(properties.cash),
+ up(properties.up),
+ down(properties.down),
+ lastCashAdd(properties.lastCashAdd),
+ passiveTime(properties.passiveTime),
+ lastCashAddTime(properties.lastCashAddTime),
+ freeMb(properties.freeMb),
+ lastActivityTime(properties.lastActivityTime),
+ password(properties.password),
+ passive(properties.passive),
+ disabled(properties.disabled),
+ disabledDetailStat(properties.disabledDetailStat),
+ alwaysOnline(properties.alwaysOnline),
+ tariffName(properties.tariffName),
+ nextTariff(properties.nextTariff),
+ address(properties.address),
+ note(properties.note),
+ group(properties.group),
+ email(properties.email),
+ phone(properties.phone),
+ realName(properties.realName),
+ credit(properties.credit),
+ creditExpire(properties.creditExpire),
+ ips(properties.ips),
+ userdata0(properties.userdata0),
+ userdata1(properties.userdata1),
+ userdata2(properties.userdata2),
+ userdata3(properties.userdata3),
+ userdata4(properties.userdata4),
+ userdata5(properties.userdata5),
+ userdata6(properties.userdata6),
+ userdata7(properties.userdata7),
+ userdata8(properties.userdata8),
+ userdata9(properties.userdata9),
+ sessionUploadModTime(stgTime),
+ sessionDownloadModTime(stgTime),
+ passiveNotifier(this),
+ disabledNotifier(this),
+ tariffNotifier(this),
+ cashNotifier(this),
+ ipNotifier(this)
+{
+Init();
+}
+//-----------------------------------------------------------------------------
+void UserImpl::Init()
+{
+password = "*_EMPTY_PASSWORD_*";
+tariffName = NO_TARIFF_NAME;
+tariff = tariffs->FindByName(tariffName);
+ips = UserIPs::parse("*");
+lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
+lastWriteDetailedStat = stgTime;
+
+properties.tariffName.AddBeforeNotifier(&tariffNotifier);
+properties.passive.AddBeforeNotifier(&passiveNotifier);
+properties.disabled.AddAfterNotifier(&disabledNotifier);
+properties.cash.AddBeforeNotifier(&cashNotifier);
+ips.AddAfterNotifier(&ipNotifier);
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+UserImpl::UserImpl(const UserImpl & u)
+ : users(u.users),
+ properties(*u.settings),
+ WriteServLog(Logger::get()),
+ lastScanMessages(0),
+ login(u.login),
+ id(u.id),
+ __connected(0),
+ connected(__connected),
+ __currIP(u.__currIP),
+ currIP(__currIP),
+ lastIPForDisconnect(0),
+ pingTime(u.pingTime),
+ sysAdmin(u.sysAdmin),
+ store(u.store),
+ tariffs(u.tariffs),
+ tariff(u.tariff),
+ m_services(u.m_services),
+ traffStat(u.traffStat),
+ traffStatSaved(u.traffStatSaved),
+ settings(u.settings),
+ authorizedModificationTime(u.authorizedModificationTime),
+ messages(u.messages),
+ deleted(u.deleted),
+ lastWriteStat(u.lastWriteStat),
+ lastWriteDetailedStat(u.lastWriteDetailedStat),
+ cash(properties.cash),
+ up(properties.up),
+ down(properties.down),
+ lastCashAdd(properties.lastCashAdd),
+ passiveTime(properties.passiveTime),
+ lastCashAddTime(properties.lastCashAddTime),
+ freeMb(properties.freeMb),
+ lastActivityTime(properties.lastActivityTime),
+ password(properties.password),
+ passive(properties.passive),
+ disabled(properties.disabled),
+ disabledDetailStat(properties.disabledDetailStat),
+ alwaysOnline(properties.alwaysOnline),
+ tariffName(properties.tariffName),
+ nextTariff(properties.nextTariff),
+ address(properties.address),
+ note(properties.note),
+ group(properties.group),
+ email(properties.email),
+ phone(properties.phone),
+ realName(properties.realName),
+ credit(properties.credit),
+ creditExpire(properties.creditExpire),
+ ips(properties.ips),
+ userdata0(properties.userdata0),
+ userdata1(properties.userdata1),
+ userdata2(properties.userdata2),
+ userdata3(properties.userdata3),
+ userdata4(properties.userdata4),
+ userdata5(properties.userdata5),
+ userdata6(properties.userdata6),
+ userdata7(properties.userdata7),
+ userdata8(properties.userdata8),
+ userdata9(properties.userdata9),
+ sessionUpload(),
+ sessionDownload(),
+ sessionUploadModTime(stgTime),
+ sessionDownloadModTime(stgTime),
+ passiveNotifier(this),
+ disabledNotifier(this),
+ tariffNotifier(this),
+ cashNotifier(this),
+ ipNotifier(this)
+{
+if (&u == this)
+ return;
+
+properties.tariffName.AddBeforeNotifier(&tariffNotifier);
+properties.passive.AddBeforeNotifier(&passiveNotifier);
+properties.disabled.AddAfterNotifier(&disabledNotifier);
+properties.cash.AddBeforeNotifier(&cashNotifier);
+ips.AddAfterNotifier(&ipNotifier);
+
+properties.SetProperties(u.properties);
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+UserImpl::~UserImpl()
+{
+properties.tariffName.DelBeforeNotifier(&tariffNotifier);
+properties.passive.DelBeforeNotifier(&passiveNotifier);
+properties.disabled.DelAfterNotifier(&disabledNotifier);
+properties.cash.DelBeforeNotifier(&cashNotifier);
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::SetLogin(const std::string & l)
+{
+STG_LOCKER lock(&mutex);
+static int idGen = 0;
+assert(login.empty() && "Login is already set");
+login = l;
+id = idGen++;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::ReadConf()
+{
+STG_LOCKER lock(&mutex);
+UserConf conf;
+
+if (store->RestoreUserConf(&conf, login))
+ {
+ WriteServLog("Cannot read conf for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
+ printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+ return -1;
+ }
+
+properties.SetConf(conf);
+
+tariff = tariffs->FindByName(tariffName);
+if (tariff == NULL)
+ {
+ WriteServLog("Cannot read user %s. Tariff %s not exist.",
+ login.c_str(), properties.tariffName.Get().c_str());
+ return -1;
+ }
+
+std::vector<Message::Header> hdrsList;
+
+if (store->GetMessageHdrs(&hdrsList, login))
+ {
+ printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
+ WriteServLog("Cannot read user %s. Error reading message headers: %s.",
+ login.c_str(),
+ store->GetStrError().c_str());
+ return -1;
+ }
+
+std::vector<Message::Header>::const_iterator it;
+for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
+ {
+ Message msg;
+ if (store->GetMessage(it->id, &msg, login) == 0)
+ {
+ messages.push_back(msg);
+ }
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::ReadStat()
+{
+STG_LOCKER lock(&mutex);
+UserStat stat;
+
+if (store->RestoreUserStat(&stat, login))
+ {
+ WriteServLog("Cannot read stat for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
+ printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+ return -1;
+ }
+
+properties.SetStat(stat);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::WriteConf()
+{
+STG_LOCKER lock(&mutex);
+UserConf conf(properties.GetConf());
+
+printfd(__FILE__, "UserImpl::WriteConf()\n");
+
+if (store->SaveUserConf(conf, login))
+ {
+ WriteServLog("Cannot write conf for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
+ printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::WriteStat()
+{
+STG_LOCKER lock(&mutex);
+UserStat stat(properties.GetStat());
+
+if (store->SaveUserStat(stat, login))
+ {
+ WriteServLog("Cannot write stat for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
+ printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+ return -1;
+ }
+
+lastWriteStat = stgTime;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::WriteMonthStat()
+{
+STG_LOCKER lock(&mutex);
+time_t tt = stgTime - 3600;
+struct tm t1;
+localtime_r(&tt, &t1);
+
+UserStat stat(properties.GetStat());
+if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
+ {
+ WriteServLog("Cannot write month stat for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
+ printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+ return -1;
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth)
+{
+STG_LOCKER lock(&mutex);
+/*
+ * Authorize user. It only means that user will be authorized. Nothing more.
+ * User can be connected or disconnected while authorized.
+ * Example: user is authorized but disconnected due to 0 money or blocking
+ */
+
+/*
+ * TODO: in fact "authorization" means allowing access to a service. What we
+ * call "authorization" here, int STG, is "authentication". So this should be
+ * fixed in future.
+ */
+
+/*
+ * Prevent double authorization by identical authorizers
+ */
+if (authorizedBy.find(auth) != authorizedBy.end())
+ return 0;
+
+if (!ip)
+ return -1;
+
+dirsFromBits(enabledDirs, dirs);
+
+if (!authorizedBy.empty())
+ {
+ if (currIP != ip)
+ {
+ // We are already authorized, but with different IP address
+ errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
+ return -1;
+ }
+
+ User * u = NULL;
+ if (!users->FindByIPIdx(ip, &u))
+ {
+ // Address presents in IP-index.
+ // If it's not our IP - report it.
+ if (u != this)
+ {
+ errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
+ return -1;
+ }
+ }
+ }
+else
+ {
+ if (users->IsIPInIndex(ip))
+ {
+ // Address is already present in IP-index.
+ errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
+ return -1;
+ }
+
+ if (ips.ConstData().find(ip))
+ {
+ currIP = ip;
+ lastIPForDisconnect = currIP;
+ }
+ else
+ {
+ printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().toString().c_str());
+ errorStr = "IP address " + inet_ntostring(ip) + " does not belong to user " + login;
+ return -1;
+ }
+ }
+
+if (authorizedBy.empty())
+ authorizedModificationTime = stgTime;
+authorizedBy.insert(auth);
+
+ScanMessage();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void UserImpl::Unauthorize(const Auth * auth, const std::string & reason)
+{
+STG_LOCKER lock(&mutex);
+/*
+ * Authorizer tries to unauthorize user, that was not authorized by it
+ */
+if (!authorizedBy.erase(auth))
+ return;
+
+authorizedModificationTime = stgTime;
+
+if (authorizedBy.empty())
+ {
+ lastDisconnectReason = reason;
+ lastIPForDisconnect = currIP;
+ currIP = 0; // DelUser in traffcounter
+ if (connected)
+ Disconnect(false, "not authorized");
+ return;
+ }
+}
+//-----------------------------------------------------------------------------
+bool UserImpl::IsAuthorizedBy(const Auth * auth) const
+{
+STG_LOCKER lock(&mutex);
+// Is this user authorized by specified authorizer?
+return authorizedBy.find(auth) != authorizedBy.end();
+}
+//-----------------------------------------------------------------------------
+std::vector<std::string> UserImpl::GetAuthorizers() const
+{
+ STG_LOCKER lock(&mutex);
+ std::vector<std::string> list;
+ std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), [](const auto auth){ return auth->GetVersion(); });
+ return list;
+}
+//-----------------------------------------------------------------------------
+void UserImpl::Connect(bool fakeConnect)
+{
+/*
+ * Connect user to Internet. This function is differ from Authorize() !!!
+ */
+
+STG_LOCKER lock(&mutex);
+
+if (!fakeConnect)
+ {
+ std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
+
+ if (access(scriptOnConnect.c_str(), X_OK) == 0)
+ {
+ std::string dirs = dirsToString(enabledDirs);
+
+ std::string scriptOnConnectParams;
+ strprintf(&scriptOnConnectParams,
+ "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
+ scriptOnConnect.c_str(),
+ login.c_str(),
+ inet_ntostring(currIP).c_str(),
+ cash.ConstData(),
+ id,
+ dirs.c_str());
+
+ std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
+ while (it != settings->GetScriptParams().end())
+ {
+ scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
+ ++it;
+ }
+
+ ScriptExec(scriptOnConnectParams.c_str());
+ }
+ else
+ {
+ WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
+ }
+
+ connected = true;
+ }
+
+if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, currIP))
+ {
+ WriteServLog("Cannot write connect for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ }
+
+if (!fakeConnect)
+ lastIPForDisconnect = currIP;
+}
+//-----------------------------------------------------------------------------
+void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason)
+{
+/*
+ * Disconnect user from Internet. This function is differ from UnAuthorize() !!!
+ */
+
+STG_LOCKER lock(&mutex);
+
+if (!lastIPForDisconnect)
+ {
+ printfd(__FILE__, "lastIPForDisconnect\n");
+ return;
+ }
+
+if (!fakeDisconnect)
+ {
+ lastDisconnectReason = reason;
+ std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
+
+ if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
+ {
+ std::string dirs = dirsToString(enabledDirs);
+
+ std::string scriptOnDisonnectParams;
+ strprintf(&scriptOnDisonnectParams,
+ "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
+ scriptOnDisonnect.c_str(),
+ login.c_str(),
+ inet_ntostring(lastIPForDisconnect).c_str(),
+ cash.ConstData(),
+ id,
+ dirs.c_str());
+
+ std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
+ while (it != settings->GetScriptParams().end())
+ {
+ scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
+ ++it;
+ }
+
+ ScriptExec(scriptOnDisonnectParams.c_str());
+ }
+ else
+ {
+ WriteServLog("Script OnDisconnect cannot be executed. File not found.");
+ }
+
+ connected = false;
+ }
+
+std::string reasonMessage(reason);
+if (!lastDisconnectReason.empty())
+ reasonMessage += ": " + lastDisconnectReason;
+
+if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
+ cash, freeMb, reasonMessage))
+ {
+ WriteServLog("Cannot write disconnect for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ }
+
+if (!fakeDisconnect)
+ lastIPForDisconnect = 0;
+
+sessionUpload.reset();
+sessionDownload.reset();
+sessionUploadModTime = stgTime;
+sessionDownloadModTime = stgTime;
+}
+//-----------------------------------------------------------------------------
+void UserImpl::Run()
+{
+STG_LOCKER lock(&mutex);
+
+if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
+ {
+ printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str());
+ WriteStat();
+ }
+if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
+ {
+ WriteServLog("User: %s. Credit expired.", login.c_str());
+ credit = 0;
+ creditExpire = 0;
+ WriteConf();
+ }
+
+if (passive.ConstData()
+ && (stgTime % 30 == 0)
+ && (passiveTime.ModificationTime() != stgTime))
+ {
+ passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
+ printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
+ }
+
+if (!authorizedBy.empty())
+ {
+ if (connected)
+ properties.Stat().lastActivityTime = stgTime;
+
+ if (!connected && IsInetable())
+ Connect();
+
+ if (connected && !IsInetable())
+ {
+ if (disabled)
+ Disconnect(false, "disabled");
+ else if (passive)
+ Disconnect(false, "passive");
+ else
+ Disconnect(false, "no cash");
+ }
+
+ if (stgTime - lastScanMessages > 10)
+ {
+ ScanMessage();
+ lastScanMessages = stgTime;
+ }
+ }
+else
+ {
+ if (connected)
+ Disconnect(false, "not authorized");
+ }
+
+}
+//-----------------------------------------------------------------------------
+void UserImpl::UpdatePingTime(time_t t)
+{
+STG_LOCKER lock(&mutex);
+if (t)
+ pingTime = t;
+else
+ pingTime = stgTime;
+}
+//-----------------------------------------------------------------------------
+bool UserImpl::IsInetable()
+{
+if (disabled || passive)
+ return false;
+
+if (settings->GetFreeMbAllowInet())
+ {
+ if (freeMb >= 0)
+ return true;
+ }
+
+if (settings->GetShowFeeInCash() || tariff == NULL)
+ return (cash >= -credit);
+
+return (cash - tariff->GetFee() >= -credit);
+}
+//-----------------------------------------------------------------------------
+std::string UserImpl::GetEnabledDirs() const
+{
+return dirsToString(enabledDirs);
+}
+//-----------------------------------------------------------------------------
+#ifdef TRAFF_STAT_WITH_PORTS
+void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
+#else
+void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
+#endif
+{
+STG_LOCKER lock(&mutex);
+
+if (!connected || tariff == NULL)
+ return;
+
+double cost = 0;
+DirTraff dt(up);
+
+int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
+int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
+
+dt[dir] += len;
+
+int tt = tariff->GetTraffType();
+if (tt == Tariff::TRAFF_UP ||
+ tt == Tariff::TRAFF_UP_DOWN ||
+ // Check NEW traff data
+ (tt == Tariff::TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
+ {
+ double dc = 0;
+ if (traff < threshold &&
+ traff + len >= threshold)
+ {
+ // cash = partBeforeThreshold * priceBeforeThreshold +
+ // partAfterThreshold * priceAfterThreshold
+ int64_t before = threshold - traff; // Chunk part before threshold
+ int64_t after = len - before; // Chunk part after threshold
+ dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
+ down.ConstData()[dir],
+ dir,
+ stgTime) * before +
+ tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
+ down.ConstData()[dir],
+ dir,
+ stgTime) * after;
+ }
+ else
+ {
+ dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
+ down.ConstData()[dir],
+ dir,
+ stgTime) * len;
+ }
+
+ if (freeMb.ConstData() <= 0) // FreeMb is exhausted
+ cost = dc;
+ else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
+ cost = dc - freeMb.ConstData();
+
+ // Direct access to internal data structures via friend-specifier
+ properties.Stat().freeMb -= dc;
+ properties.Stat().cash -= cost;
+ cash.ModifyTime();
+ freeMb.ModifyTime();
+ }
+
+up = dt;
+sessionUpload[dir] += len;
+sessionUploadModTime = stgTime;
+
+//Add detailed stat
+
+if (!settings->GetWriteFreeMbTraffCost() &&
+ freeMb.ConstData() >= 0)
+ cost = 0;
+
+#ifdef TRAFF_STAT_WITH_PORTS
+IPDirPair idp(ip, dir, port);
+#else
+IPDirPair idp(ip, dir);
+#endif
+
+std::map<IPDirPair, StatNode>::iterator lb;
+lb = traffStat.lower_bound(idp);
+if (lb == traffStat.end() || lb->first != idp)
+ {
+ traffStat.insert(lb,
+ std::make_pair(idp,
+ StatNode(len, 0, cost)));
+ }
+else
+ {
+ lb->second.cash += cost;
+ lb->second.up += len;
+ }
+}
+//-----------------------------------------------------------------------------
+#ifdef TRAFF_STAT_WITH_PORTS
+void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
+#else
+void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
+#endif
+{
+STG_LOCKER lock(&mutex);
+
+if (!connected || tariff == NULL)
+ return;
+
+double cost = 0;
+DirTraff dt(down);
+
+int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
+int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
+
+dt[dir] += len;
+
+int tt = tariff->GetTraffType();
+if (tt == Tariff::TRAFF_DOWN ||
+ tt == Tariff::TRAFF_UP_DOWN ||
+ // Check NEW traff data
+ (tt == Tariff::TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
+ {
+ double dc = 0;
+ if (traff < threshold &&
+ traff + len >= threshold)
+ {
+ // cash = partBeforeThreshold * priceBeforeThreshold +
+ // partAfterThreshold * priceAfterThreshold
+ int64_t before = threshold - traff; // Chunk part before threshold
+ int64_t after = len - before; // Chunk part after threshold
+ dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
+ down.ConstData()[dir], // Traff before chunk
+ dir,
+ stgTime) * before +
+ tariff->GetPriceWithTraffType(up.ConstData()[dir],
+ dt[dir], // Traff after chunk
+ dir,
+ stgTime) * after;
+ }
+ else
+ {
+ dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
+ down.ConstData()[dir],
+ dir,
+ stgTime) * len;
+ }
+
+ if (freeMb.ConstData() <= 0) // FreeMb is exhausted
+ cost = dc;
+ else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
+ cost = dc - freeMb.ConstData();
+
+ properties.Stat().freeMb -= dc;
+ properties.Stat().cash -= cost;
+ cash.ModifyTime();
+ freeMb.ModifyTime();
+ }
+
+down = dt;
+sessionDownload[dir] += len;
+sessionDownloadModTime = stgTime;
+
+//Add detailed stat
+
+if (!settings->GetWriteFreeMbTraffCost() &&
+ freeMb.ConstData() >= 0)
+ cost = 0;
+
+#ifdef TRAFF_STAT_WITH_PORTS
+IPDirPair idp(ip, dir, port);
+#else
+IPDirPair idp(ip, dir);
+#endif
+
+std::map<IPDirPair, StatNode>::iterator lb;
+lb = traffStat.lower_bound(idp);
+if (lb == traffStat.end() || lb->first != idp)
+ {
+ traffStat.insert(lb,
+ std::make_pair(idp,
+ StatNode(0, len, cost)));
+ }
+else
+ {
+ lb->second.cash += cost;
+ lb->second.down += len;
+ }
+}
+//-----------------------------------------------------------------------------
+void UserImpl::AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+currIP.AddBeforeNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+currIP.DelBeforeNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+currIP.AddAfterNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+currIP.DelAfterNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+connected.AddBeforeNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+connected.DelBeforeNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+connected.AddAfterNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier)
+{
+STG_LOCKER lock(&mutex);
+connected.DelAfterNotifier(notifier);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::OnAdd()
+{
+STG_LOCKER lock(&mutex);
+
+std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
+
+if (access(scriptOnAdd.c_str(), X_OK) == 0)
+ {
+ std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
+
+ ScriptExec(scriptOnAddParams.c_str());
+ }
+else
+ {
+ WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
+ }
+}
+//-----------------------------------------------------------------------------
+void UserImpl::OnDelete()
+{
+STG_LOCKER lock(&mutex);
+
+std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
+
+if (access(scriptOnDel.c_str(), X_OK) == 0)
+ {
+ std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
+
+ ScriptExec(scriptOnDelParams.c_str());
+ }
+else
+ {
+ WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
+ }
+
+Run();
+}
+//-----------------------------------------------------------------------------
+int UserImpl::WriteDetailStat(bool hard)
+{
+printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
+
+if (!traffStatSaved.second.empty())
+ {
+ if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
+ {
+ printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write detail stat from queue\n");
+ WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ return -1;
+ }
+ traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
+ }
+
+TraffStat ts;
+
+ {
+ STG_LOCKER lock(&mutex);
+ ts.swap(traffStat);
+ }
+
+printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size());
+
+if (ts.size() && !disabledDetailStat)
+ {
+ if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
+ {
+ printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write current detail stat\n");
+ WriteServLog("Cannot write detail stat for user %s.", login.c_str());
+ WriteServLog("%s", store->GetStrError().c_str());
+ if (!hard)
+ {
+ printfd(__FILE__, "UserImpl::WriteDetailStat() - pushing detail stat to queue\n");
+ STG_LOCKER lock(&mutex);
+ traffStatSaved.second.swap(ts);
+ traffStatSaved.first = lastWriteDetailedStat;
+ }
+ return -1;
+ }
+ }
+lastWriteDetailedStat = stgTime;
+return 0;
+}
+//-----------------------------------------------------------------------------
+double UserImpl::GetPassiveTimePart() const
+{
+STG_LOCKER lock(&mutex);
+
+static int daysInMonth[12] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+struct tm tms;
+time_t t = stgTime;
+localtime_r(&t, &tms);
+
+time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
+
+if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
+ {
+ // Leap year
+ secMonth += 24 * 3600;
+ }
+
+time_t dt = secMonth - passiveTime;
+
+if (dt < 0)
+ dt = 0;
+
+return static_cast<double>(dt) / secMonth;
+}
+//-----------------------------------------------------------------------------
+void UserImpl::SetPassiveTimeAsNewUser()
+{
+STG_LOCKER lock(&mutex);
+
+time_t t = stgTime;
+struct tm tm;
+localtime_r(&t, &tm);
+int daysCurrMon = DaysInCurrentMonth();
+double pt = tm.tm_mday - 1;
+pt /= daysCurrMon;
+
+passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
+}
+//-----------------------------------------------------------------------------
+void UserImpl::MidnightResetSessionStat()
+{
+STG_LOCKER lock(&mutex);
+
+if (connected)
+ {
+ Disconnect(true, "fake");
+ Connect(true);
+ }
+}
+//-----------------------------------------------------------------------------
+void UserImpl::ProcessNewMonth()
+{
+STG_LOCKER lock(&mutex);
+// Reset traff
+if (connected)
+ Disconnect(true, "fake");
+
+WriteMonthStat();
+
+properties.Stat().monthUp.reset();
+properties.Stat().monthDown.reset();
+
+if (connected)
+ Connect(true);
+
+// Set new tariff
+if (nextTariff.ConstData() != "")
+ {
+ const Tariff * nt = tariffs->FindByName(nextTariff);
+ if (nt == NULL)
+ {
+ WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
+ login.c_str(), properties.tariffName.Get().c_str());
+ }
+ else
+ {
+ std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime);
+ if (message.empty())
+ {
+ properties.tariffName.Set(nextTariff, *sysAdmin, login, *store);
+ }
+ else
+ {
+ WriteServLog("Tariff change is prohibited for user %s. %s",
+ login.c_str(),
+ message.c_str());
+ }
+ }
+ ResetNextTariff();
+ WriteConf();
+ }
+}
+//-----------------------------------------------------------------------------
+void UserImpl::ProcessDayFeeSpread()
+{
+STG_LOCKER lock(&mutex);
+
+if (passive.ConstData() || tariff == NULL)
+ return;
+
+if (tariff->GetPeriod() != Tariff::MONTH)
+ return;
+
+double fee = tariff->GetFee() / DaysInCurrentMonth();
+
+if (std::fabs(fee) < 1.0e-3)
+ return;
+
+double c = cash;
+switch (settings->GetFeeChargeType())
+ {
+ case 0:
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ case 1:
+ if (c + credit >= 0)
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ case 2:
+ if (c + credit >= fee)
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ case 3:
+ if (c >= 0)
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ }
+ResetPassiveTime();
+}
+//-----------------------------------------------------------------------------
+void UserImpl::ProcessDayFee()
+{
+STG_LOCKER lock(&mutex);
+
+if (tariff == NULL)
+ return;
+
+if (tariff->GetPeriod() != Tariff::MONTH)
+ return;
+
+double passiveTimePart = 1.0;
+if (!settings->GetFullFee())
+ {
+ passiveTimePart = GetPassiveTimePart();
+ }
+else
+ {
+ if (passive.ConstData())
+ {
+ printfd(__FILE__, "Don't charge fee `cause we are passive\n");
+ return;
+ }
+ }
+double fee = tariff->GetFee() * passiveTimePart;
+
+ResetPassiveTime();
+
+if (std::fabs(fee) < 1.0e-3)
+ {
+ SetPrepaidTraff();
+ return;
+ }
+
+double c = cash;
+printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
+ login.c_str(),
+ cash.ConstData(),
+ credit.ConstData(),
+ tariff->GetFee(),
+ passiveTimePart,
+ fee);
+switch (settings->GetFeeChargeType())
+ {
+ case 0:
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ break;
+ case 1:
+ if (c + credit >= 0)
+ {
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ }
+ break;
+ case 2:
+ if (c + credit >= fee)
+ {
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ }
+ break;
+ case 3:
+ if (c >= 0)
+ {
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ }
+ break;
+ }
+}
+//-----------------------------------------------------------------------------
+void UserImpl::ProcessDailyFee()
+{
+STG_LOCKER lock(&mutex);
+
+if (passive.ConstData() || tariff == NULL)
+ return;
+
+if (tariff->GetPeriod() != Tariff::DAY)
+ return;
+
+double fee = tariff->GetFee();
+
+if (fee == 0.0)
+ return;
+
+double c = cash;
+switch (settings->GetFeeChargeType())
+ {
+ case 0:
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ case 1:
+ if (c + credit >= 0)
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ case 2:
+ if (c + credit >= fee)
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ break;
+ }
+ResetPassiveTime();
+}
+//-----------------------------------------------------------------------------
+void UserImpl::ProcessServices()
+{
+struct tm tms;
+time_t t = stgTime;
+localtime_r(&t, &tms);
+
+double passiveTimePart = 1.0;
+if (!settings->GetFullFee())
+ {
+ passiveTimePart = GetPassiveTimePart();
+ }
+else
+ {
+ if (passive.ConstData())
+ {
+ printfd(__FILE__, "Don't charge fee `cause we are passive\n");
+ return;
+ }
+ }
+
+for (size_t i = 0; i < properties.Conf().services.size(); ++i)
+ {
+ ServiceConf conf;
+ if (m_services.Find(properties.Conf().services[i], &conf))
+ continue;
+ if (conf.payDay == tms.tm_mday ||
+ (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
+ {
+ double c = cash;
+ double fee = conf.cost * passiveTimePart;
+ printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
+ login.c_str(),
+ cash.ConstData(),
+ credit.ConstData(),
+ tariff->GetFee(),
+ passiveTimePart,
+ fee);
+ switch (settings->GetFeeChargeType())
+ {
+ case 0:
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ break;
+ case 1:
+ if (c + credit >= 0)
+ {
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ }
+ break;
+ case 2:
+ if (c + credit >= fee)
+ {
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ }
+ break;
+ case 3:
+ if (c >= 0)
+ {
+ properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
+ SetPrepaidTraff();
+ }
+ break;
+ }
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+void UserImpl::SetPrepaidTraff()
+{
+if (tariff != NULL)
+ properties.freeMb.Set(tariff->GetFree(), *sysAdmin, login, *store, "Prepaid traffic");
+}
+//-----------------------------------------------------------------------------
+int UserImpl::AddMessage(Message * msg)
+{
+STG_LOCKER lock(&mutex);
+
+if (SendMessage(*msg))
+ {
+ if (store->AddMessage(msg, login))
+ {
+ errorStr = store->GetStrError();
+ WriteServLog("Error adding message: '%s'", errorStr.c_str());
+ printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
+ return -1;
+ }
+ messages.push_back(*msg);
+ }
+else
+ {
+ if (msg->header.repeat > 0)
+ {
+ msg->header.repeat--;
+ #ifndef DEBUG
+ //TODO: gcc v. 4.x generate ICE on x86_64
+ msg->header.lastSendTime = static_cast<int>(time(NULL));
+ #else
+ msg->header.lastSendTime = static_cast<int>(stgTime);
+ #endif
+ if (store->AddMessage(msg, login))
+ {
+ errorStr = store->GetStrError();
+ WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
+ printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
+ return -1;
+ }
+ messages.push_back(*msg);
+ }
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UserImpl::SendMessage(Message & msg) const
+{
+// No lock `cause we are already locked from caller
+int ret = -1;
+std::set<const Auth*>::iterator it(authorizedBy.begin());
+while (it != authorizedBy.end())
+ {
+ if (!(*it++)->SendMessage(msg, currIP))
+ ret = 0;
+ }
+if (!ret)
+ {
+#ifndef DEBUG
+ //TODO: gcc v. 4.x generate ICE on x86_64
+ msg.header.lastSendTime = static_cast<int>(time(NULL));
+#else
+ msg.header.lastSendTime = static_cast<int>(stgTime);
+#endif
+ msg.header.repeat--;
+ }
+return ret;
+}
+//-----------------------------------------------------------------------------
+void UserImpl::ScanMessage()
+{
+// No lock `cause we are already locked from caller
+// We need not check for the authorizedBy `cause it has already checked by caller
+
+auto it = messages.begin();
+while (it != messages.end())
+ {
+ if (settings->GetMessageTimeout() > 0 &&
+ difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
+ {
+ // Timeout exceeded
+ if (store->DelMessage(it->header.id, login))
+ {
+ WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
+ printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
+ }
+ messages.erase(it++);
+ continue;
+ }
+ if (it->GetNextSendTime() <= stgTime)
+ {
+ if (SendMessage(*it))
+ {
+ // We need to check all messages in queue for timeout
+ ++it;
+ continue;
+ }
+ if (it->header.repeat < 0)
+ {
+ if (store->DelMessage(it->header.id, login))
+ {
+ WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
+ printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
+ }
+ messages.erase(it++);
+ }
+ else
+ {
+ if (store->EditMessage(*it, login))
+ {
+ WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
+ printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
+ }
+ ++it;
+ }
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+std::string UserImpl::GetParamValue(const std::string & name) const
+{
+ std::string lowerName = ToLower(name);
+ if (lowerName == "id")
+ {
+ std::ostringstream stream;
+ stream << id;
+ return stream.str();
+ }
+ if (lowerName == "login") return login;
+ if (lowerName == "currip") return currIP.ToString();
+ if (lowerName == "enableddirs") return GetEnabledDirs();
+ if (lowerName == "tariff") return properties.tariffName;
+ if (properties.Exists(lowerName))
+ return properties.GetPropertyValue(lowerName);
+ else
+ {
+ WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
+ return "";
+ }
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void STG::CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
+{
+if (newPassive && !oldPassive && user->tariff != NULL)
+ user->properties.cash.Set(user->cash - user->tariff->GetPassiveCost(),
+ *user->sysAdmin,
+ user->login,
+ *user->store,
+ "Freeze");
+}
+//-----------------------------------------------------------------------------
+void STG::CHG_DISABLED_NOTIFIER::Notify(const int & oldValue, const int & newValue)
+{
+if (oldValue && !newValue && user->GetConnected())
+ user->Disconnect(false, "disabled");
+else if (!oldValue && newValue && user->IsInetable())
+ user->Connect(false);
+}
+//-----------------------------------------------------------------------------
+void STG::CHG_TARIFF_NOTIFIER::Notify(const std::string &, const std::string & newTariff)
+{
+STG_LOCKER lock(&user->mutex);
+if (user->settings->GetReconnectOnTariffChange() && user->connected)
+ user->Disconnect(false, "Change tariff");
+user->tariff = user->tariffs->FindByName(newTariff);
+if (user->settings->GetReconnectOnTariffChange() &&
+ !user->authorizedBy.empty() &&
+ user->IsInetable())
+ {
+ // This notifier gets called *before* changing the tariff, and in Connect we want to see new tariff name.
+ user->properties.Conf().tariffName = newTariff;
+ user->Connect(false);
+ }
+}
+//-----------------------------------------------------------------------------
+void STG::CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
+{
+user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
+user->lastCashAdd = newCash - oldCash;
+}
+//-----------------------------------------------------------------------------
+void STG::CHG_IPS_NOTIFIER::Notify(const UserIPs & from, const UserIPs & to)
+{
+printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.toString().c_str(), to.toString().c_str());
+if (user->connected)
+ user->Disconnect(false, "Change IP");
+if (!user->authorizedBy.empty() && user->IsInetable())
+ user->Connect(false);
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include "stg/user.h"
+#include "stg/user_stat.h"
+#include "stg/user_conf.h"
+#include "stg/user_ips.h"
+#include "stg/user_property.h"
+#include "stg/auth.h"
+#include "stg/message.h"
+#include "stg/noncopyable.h"
+#include "stg/const.h"
+
+#include <vector>
+#include <string>
+#include <set>
+
+#include <ctime>
+#include <cstdint>
+
+namespace STG
+{
+
+//-----------------------------------------------------------------------------
+struct Tariff;
+struct Tariffs;
+struct Admin;
+class UserImpl;
+#ifdef USE_ABSTRACT_SETTINGS
+struct Settings;
+#else
+class SettingsImpl;
+#endif
+//-----------------------------------------------------------------------------
+class CHG_PASSIVE_NOTIFIER : public PropertyNotifierBase<int> {
+ public:
+ explicit CHG_PASSIVE_NOTIFIER(UserImpl * u) : user(u) {}
+ void Notify(const int & oldPassive, const int & newPassive);
+
+ private:
+ UserImpl * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_DISABLED_NOTIFIER : public PropertyNotifierBase<int> {
+public:
+ explicit CHG_DISABLED_NOTIFIER(UserImpl * u) : user(u) {}
+ void Notify(const int & oldValue, const int & newValue);
+
+private:
+ UserImpl * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_TARIFF_NOTIFIER : public PropertyNotifierBase<std::string> {
+public:
+ explicit CHG_TARIFF_NOTIFIER(UserImpl * u) : user(u) {}
+ void Notify(const std::string & oldTariff, const std::string & newTariff);
+
+private:
+ UserImpl * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_CASH_NOTIFIER : public PropertyNotifierBase<double> {
+public:
+ explicit CHG_CASH_NOTIFIER(UserImpl * u) : user(u) {}
+ void Notify(const double & oldCash, const double & newCash);
+
+private:
+ UserImpl * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_IPS_NOTIFIER : public PropertyNotifierBase<UserIPs> {
+public:
+ explicit CHG_IPS_NOTIFIER(UserImpl * u) : user(u) {}
+ void Notify(const UserIPs & oldIPs, const UserIPs & newIPs);
+
+private:
+ UserImpl * user;
+};
+//-----------------------------------------------------------------------------
+class UserImpl : public User {
+ friend class CHG_PASSIVE_NOTIFIER;
+ friend class CHG_DISABLED_NOTIFIER;
+ friend class CHG_TARIFF_NOTIFIER;
+ friend class CHG_CASH_NOTIFIER;
+ friend class CHG_IPS_NOTIFIER;
+ public:
+#ifdef USE_ABSTRACT_SETTINGS
+ using Settings = STG::Settings;
+#else
+ using Settings = STG::SettingsImpl;
+#endif
+ UserImpl(const Settings * settings,
+ const Store * store,
+ const Tariffs * tariffs,
+ const Admin * sysAdmin,
+ const Users * u,
+ const Services & svcs);
+ UserImpl(const UserImpl & u);
+ virtual ~UserImpl();
+
+ int ReadConf();
+ int ReadStat();
+ int WriteConf() override;
+ int WriteStat() override;
+ int WriteMonthStat();
+
+ const std::string & GetLogin() const override { return login; }
+ void SetLogin(std::string const & l);
+
+ uint32_t GetCurrIP() const override{ return currIP; }
+ time_t GetCurrIPModificationTime() const override { return currIP.ModificationTime(); }
+
+ void AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier) override;
+ void DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier) override;
+
+ void AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier) override;
+ void DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier) override;
+
+ void AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier) override;
+ void DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier) override;
+
+ void AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier) override;
+ void DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier) override;
+
+ int GetID() const override { return id; }
+
+ double GetPassiveTimePart() const override;
+ void ResetPassiveTime() { passiveTime = 0; }
+ void SetPassiveTimeAsNewUser();
+
+ int WriteDetailStat(bool hard = false);
+
+ const Tariff * GetTariff() const override { return tariff; }
+ void ResetNextTariff() override { nextTariff = ""; }
+
+ #ifdef TRAFF_STAT_WITH_PORTS
+ void AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len);
+ void AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len);
+ #else
+ void AddTraffStatU(int dir, uint32_t ip, uint32_t len);
+ void AddTraffStatD(int dir, uint32_t ip, uint32_t len);
+ #endif
+
+ const DirTraff & GetSessionUpload() const override { return sessionUpload; }
+ const DirTraff & GetSessionDownload() const override { return sessionDownload; }
+ time_t GetSessionUploadModificationTime() const override { return sessionUploadModTime; }
+ time_t GetSessionDownloadModificationTime() const override { return sessionDownloadModTime; }
+
+ bool GetConnected() const override { return connected; }
+ time_t GetConnectedModificationTime() const override { return connected.ModificationTime(); }
+ const std::string & GetLastDisconnectReason() const override { return lastDisconnectReason; }
+ int GetAuthorized() const override { return static_cast<int>(authorizedBy.size()); }
+ time_t GetAuthorizedModificationTime() const override { return authorizedModificationTime; }
+ int Authorize(uint32_t ip, uint32_t enabledDirs, const Auth * auth);
+ void Unauthorize(const Auth * auth,
+ const std::string & reason = std::string());
+ bool IsAuthorizedBy(const Auth * auth) const override;
+ std::vector<std::string> GetAuthorizers() const override;
+
+ int AddMessage(Message * msg) override;
+
+ void UpdatePingTime(time_t t = 0) override;
+ time_t GetPingTime() const override { return pingTime; }
+
+ void Run() override;
+
+ const std::string & GetStrError() const override { return errorStr; }
+
+ UserProperties & GetProperties() override { return properties; }
+ const UserProperties & GetProperties() const override { return properties; }
+
+ void SetDeleted() override { deleted = true; }
+ bool GetDeleted() const override { return deleted; }
+
+ time_t GetLastWriteStatTime() const override { return lastWriteStat; }
+
+ void MidnightResetSessionStat();
+ void ProcessDayFee();
+ void ProcessDayFeeSpread();
+ void ProcessNewMonth();
+ void ProcessDailyFee();
+ void ProcessServices();
+
+ bool IsInetable() override;
+ std::string GetEnabledDirs() const override;
+
+ void OnAdd() override;
+ void OnDelete() override;
+
+ virtual std::string GetParamValue(const std::string & name) const override;
+
+ private:
+ UserImpl & operator=(const UserImpl & rvalue);
+
+ void Init();
+
+ const Users* users;
+ UserProperties properties;
+ STG::Logger& WriteServLog;
+
+ void Connect(bool fakeConnect = false);
+ void Disconnect(bool fakeDisconnect, const std::string & reason);
+ int SaveMonthStat(int month, int year);
+
+ void SetPrepaidTraff();
+
+ int SendMessage(Message & msg) const;
+ void ScanMessage();
+
+ time_t lastScanMessages;
+
+ std::string login;
+ int id;
+ bool __connected;
+ UserProperty<bool> connected;
+
+ bool enabledDirs[DIR_NUM];
+
+ uint32_t __currIP; // Current user's ip
+ UserProperty<uint32_t> currIP;
+
+ uint32_t lastIPForDisconnect; // User's ip after unauth but before disconnect
+ std::string lastDisconnectReason;
+
+ time_t pingTime;
+
+ const Admin * sysAdmin;
+ const Store * store;
+
+ const Tariffs * tariffs;
+ const Tariff * tariff;
+
+ const Services & m_services;
+
+ TraffStat traffStat;
+ std::pair<time_t, TraffStat> traffStatSaved;
+
+ const Settings * settings;
+
+ std::set<const Auth *> authorizedBy;
+ time_t authorizedModificationTime;
+
+ std::vector<Message> messages;
+
+ bool deleted;
+
+ time_t lastWriteStat;
+ time_t lastWriteDetailedStat;
+
+ // Properties
+ UserProperty<double> & cash;
+ UserProperty<DirTraff> & up;
+ UserProperty<DirTraff> & down;
+ UserProperty<double> & lastCashAdd;
+ UserProperty<time_t> & passiveTime;
+ UserProperty<time_t> & lastCashAddTime;
+ UserProperty<double> & freeMb;
+ UserProperty<time_t> & lastActivityTime;
+ UserProperty<std::string> & password;
+ UserProperty<int> & passive;
+ UserProperty<int> & disabled;
+ UserProperty<int> & disabledDetailStat;
+ UserProperty<int> & alwaysOnline;
+ UserProperty<std::string> & tariffName;
+ UserProperty<std::string> & nextTariff;
+ UserProperty<std::string> & address;
+ UserProperty<std::string> & note;
+ UserProperty<std::string> & group;
+ UserProperty<std::string> & email;
+ UserProperty<std::string> & phone;
+ UserProperty<std::string> & realName;
+ UserProperty<double> & credit;
+ UserProperty<time_t> & creditExpire;
+ UserProperty<UserIPs> & ips;
+ UserProperty<std::string> & userdata0;
+ UserProperty<std::string> & userdata1;
+ UserProperty<std::string> & userdata2;
+ UserProperty<std::string> & userdata3;
+ UserProperty<std::string> & userdata4;
+ UserProperty<std::string> & userdata5;
+ UserProperty<std::string> & userdata6;
+ UserProperty<std::string> & userdata7;
+ UserProperty<std::string> & userdata8;
+ UserProperty<std::string> & userdata9;
+
+ // End properties
+
+ DirTraff sessionUpload;
+ DirTraff sessionDownload;
+ time_t sessionUploadModTime;
+ time_t sessionDownloadModTime;
+
+ CHG_PASSIVE_NOTIFIER passiveNotifier;
+ CHG_DISABLED_NOTIFIER disabledNotifier;
+ CHG_TARIFF_NOTIFIER tariffNotifier;
+ CHG_CASH_NOTIFIER cashNotifier;
+ CHG_IPS_NOTIFIER ipNotifier;
+
+ mutable pthread_mutex_t mutex;
+
+ std::string errorStr;
+};
+//-----------------------------------------------------------------------------
+
+}
--- /dev/null
+#include "stg/user_property.h"
+
+STG::UserProperties::UserProperties(const Settings& s)
+ : cash (stat.cash, "cash", false, true, s, properties),
+ up (stat.monthUp, "upload", false, true, s, properties),
+ down (stat.monthDown, "download", false, true, s, properties),
+ lastCashAdd (stat.lastCashAdd, "lastCashAdd", false, true, s, properties),
+ passiveTime (stat.passiveTime, "passiveTime", false, true, s, properties),
+ lastCashAddTime (stat.lastCashAddTime, "lastCashAddTime", false, true, s, properties),
+ freeMb (stat.freeMb, "freeMb", false, true, s, properties),
+ lastActivityTime(stat.lastActivityTime, "lastActivityTime", false, true, s, properties),
+
+ password (conf.password, "password", true, false, s, properties),
+ passive (conf.passive, "passive", false, false, s, properties),
+ disabled (conf.disabled, "disabled", false, false, s, properties),
+ disabledDetailStat(conf.disabledDetailStat, "DisabledDetailStat", false, false, s, properties),
+ alwaysOnline(conf.alwaysOnline, "alwaysOnline", false, false, s, properties),
+ tariffName (conf.tariffName, "tariffName", false, false, s, properties),
+ nextTariff (conf.nextTariff, "nextTariff", false, false, s, properties),
+ address (conf.address, "address", false, false, s, properties),
+ note (conf.note, "note", false, false, s, properties),
+ group (conf.group, "group", false, false, s, properties),
+ email (conf.email, "email", false, false, s, properties),
+ phone (conf.phone, "phone", false, false, s, properties),
+ realName (conf.realName, "realName", false, false, s, properties),
+ credit (conf.credit, "credit", false, false, s, properties),
+ creditExpire(conf.creditExpire, "creditExpire", false, false, s, properties),
+ ips (conf.ips, "ips", false, false, s, properties),
+ userdata0 (conf.userdata[0], "userdata0", false, false, s, properties),
+ userdata1 (conf.userdata[1], "userdata1", false, false, s, properties),
+ userdata2 (conf.userdata[2], "userdata2", false, false, s, properties),
+ userdata3 (conf.userdata[3], "userdata3", false, false, s, properties),
+ userdata4 (conf.userdata[4], "userdata4", false, false, s, properties),
+ userdata5 (conf.userdata[5], "userdata5", false, false, s, properties),
+ userdata6 (conf.userdata[6], "userdata6", false, false, s, properties),
+ userdata7 (conf.userdata[7], "userdata7", false, false, s, properties),
+ userdata8 (conf.userdata[8], "userdata8", false, false, s, properties),
+ userdata9 (conf.userdata[9], "userdata9", false, false, s, properties)
+{}
--- /dev/null
+/*
+ * 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
+ */
+
+/*
+ * Date: 27.10.2002
+ */
+
+/*
+ * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#include <pthread.h>
+
+#include <csignal>
+#include <cassert>
+#include <algorithm>
+#include <utility>
+#include <string>
+#include <vector>
+
+#include "stg/settings.h"
+#include "stg/common.h"
+
+#include "users_impl.h"
+#include "stg_timer.h"
+
+extern volatile time_t stgTime;
+
+using STG::UsersImpl;
+
+//-----------------------------------------------------------------------------
+UsersImpl::UsersImpl(SettingsImpl * s, Store * st,
+ Tariffs * t, Services & svcs,
+ const Admin& sa)
+ : settings(s),
+ tariffs(t),
+ m_services(svcs),
+ store(st),
+ sysAdmin(sa),
+ WriteServLog(Logger::get()),
+ nonstop(false),
+ isRunning(false),
+ handle(0)
+{
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+UsersImpl::~UsersImpl()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::FindByNameNonLock(const std::string & login, user_iter * user)
+{
+const std::map<std::string, user_iter>::const_iterator iter(loginIndex.find(login));
+if (iter == loginIndex.end())
+ return -1;
+if (user)
+ *user = iter->second;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::FindByNameNonLock(const std::string & login, const_user_iter * user) const
+{
+const std::map<std::string, user_iter>::const_iterator iter(loginIndex.find(login));
+if (iter == loginIndex.end())
+ return -1;
+if (user)
+ *user = iter->second;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::FindByName(const std::string & login, UserPtr * user)
+{
+STG_LOCKER lock(&mutex);
+user_iter u;
+if (FindByNameNonLock(login, &u))
+ return -1;
+*user = &(*u);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::FindByName(const std::string & login, ConstUserPtr * user) const
+{
+STG_LOCKER lock(&mutex);
+const_user_iter u;
+if (FindByNameNonLock(login, &u))
+ return -1;
+*user = &(*u);
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::Exists(const std::string & login) const
+{
+STG_LOCKER lock(&mutex);
+const std::map<std::string, user_iter>::const_iterator iter(loginIndex.find(login));
+return iter != loginIndex.end();
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::TariffInUse(const std::string & tariffName) const
+{
+STG_LOCKER lock(&mutex);
+std::list<UserImpl>::const_iterator iter;
+iter = users.begin();
+while (iter != users.end())
+ {
+ if (iter->GetProperties().tariffName.Get() == tariffName)
+ return true;
+ ++iter;
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::Add(const std::string & login, const Admin * admin)
+{
+STG_LOCKER lock(&mutex);
+const auto& priv = admin->priv();
+
+if (!priv.userAddDel)
+ {
+ WriteServLog("%s tried to add user \'%s\'. Access denied.",
+ admin->logStr().c_str(), login.c_str());
+ return -1;
+ }
+
+if (store->AddUser(login))
+ return -1;
+
+UserImpl u(settings, store, tariffs, &sysAdmin, this, m_services);
+
+u.SetLogin(login);
+
+u.SetPassiveTimeAsNewUser();
+
+u.WriteConf();
+u.WriteStat();
+
+WriteServLog("%s User \'%s\' added.",
+ admin->logStr().c_str(), login.c_str());
+
+u.OnAdd();
+
+users.push_front(u);
+
+AddUserIntoIndexes(users.begin());
+
+ {
+ // Fire all "on add" notifiers
+ std::set<NotifierBase<UserPtr> *>::iterator ni = onAddNotifiers.begin();
+ while (ni != onAddNotifiers.end())
+ {
+ (*ni)->Notify(&users.front());
+ ++ni;
+ }
+ }
+
+ {
+ // Fire all "on add" implementation notifiers
+ std::set<NotifierBase<UserImplPtr> *>::iterator ni = onAddNotifiersImpl.begin();
+ while (ni != onAddNotifiersImpl.end())
+ {
+ (*ni)->Notify(&users.front());
+ ++ni;
+ }
+ }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::Del(const std::string & login, const Admin * admin)
+{
+const auto& priv = admin->priv();
+user_iter u;
+
+if (!priv.userAddDel)
+ {
+ WriteServLog("%s tried to remove user \'%s\'. Access denied.",
+ admin->logStr().c_str(), login.c_str());
+ return;
+ }
+
+
+ {
+ STG_LOCKER lock(&mutex);
+
+ if (FindByNameNonLock(login, &u))
+ {
+ WriteServLog("%s tried to delete user \'%s\': not found.",
+ admin->logStr().c_str(),
+ login.c_str());
+ return;
+ }
+
+ u->SetDeleted();
+ }
+
+ {
+ std::set<NotifierBase<UserPtr> *>::iterator ni = onDelNotifiers.begin();
+ while (ni != onDelNotifiers.end())
+ {
+ (*ni)->Notify(&(*u));
+ ++ni;
+ }
+ }
+
+ {
+ std::set<NotifierBase<UserImplPtr> *>::iterator ni = onDelNotifiersImpl.begin();
+ while (ni != onDelNotifiersImpl.end())
+ {
+ (*ni)->Notify(&(*u));
+ ++ni;
+ }
+ }
+
+ {
+ STG_LOCKER lock(&mutex);
+
+ u->OnDelete();
+
+ USER_TO_DEL utd;
+ utd.iter = u;
+ utd.delTime = stgTime;
+ usersToDelete.push_back(utd);
+
+ DelUserFromIndexes(u);
+
+ WriteServLog("%s User \'%s\' deleted.",
+ admin->logStr().c_str(), login.c_str());
+
+ }
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::Authorize(const std::string & login, uint32_t ip,
+ uint32_t enabledDirs, const Auth * auth)
+{
+user_iter iter;
+STG_LOCKER lock(&mutex);
+if (FindByNameNonLock(login, &iter))
+ {
+ WriteServLog("Attempt to authorize non-existant user '%s'", login.c_str());
+ return false;
+ }
+
+if (FindByIPIdx(ip, iter))
+ {
+ if (iter->GetLogin() != login)
+ {
+ WriteServLog("Attempt to authorize user '%s' from ip %s which already occupied by '%s'",
+ login.c_str(), inet_ntostring(ip).c_str(),
+ iter->GetLogin().c_str());
+ return false;
+ }
+ if (iter->Authorize(ip, enabledDirs, auth))
+ return false;
+ return true;
+ }
+
+if (iter->Authorize(ip, enabledDirs, auth))
+ return false;
+
+AddToIPIdx(iter);
+return true;
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::Unauthorize(const std::string & login,
+ const Auth * auth,
+ const std::string & reason)
+{
+user_iter iter;
+STG_LOCKER lock(&mutex);
+if (FindByNameNonLock(login, &iter))
+ {
+ WriteServLog("Attempt to unauthorize non-existant user '%s'", login.c_str());
+ printfd(__FILE__, "Attempt to unauthorize non-existant user '%s'", login.c_str());
+ return false;
+ }
+
+uint32_t ip = iter->GetCurrIP();
+
+iter->Unauthorize(auth, reason);
+
+if (!iter->GetAuthorized())
+ DelFromIPIdx(ip);
+
+return true;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::ReadUsers()
+{
+std::vector<std::string> usersList;
+usersList.clear();
+if (store->GetUsersList(&usersList) < 0)
+ {
+ WriteServLog(store->GetStrError().c_str());
+ return -1;
+ }
+
+user_iter ui;
+
+unsigned errors = 0;
+for (unsigned int i = 0; i < usersList.size(); i++)
+ {
+ UserImpl u(settings, store, tariffs, &sysAdmin, this, m_services);
+
+ u.SetLogin(usersList[i]);
+ users.push_front(u);
+ ui = users.begin();
+
+ AddUserIntoIndexes(ui);
+
+ if (settings->GetStopOnError())
+ {
+ if (ui->ReadConf() < 0)
+ return -1;
+
+ if (ui->ReadStat() < 0)
+ return -1;
+ }
+ else
+ {
+ if (ui->ReadConf() < 0)
+ errors++;
+
+ if (ui->ReadStat() < 0)
+ errors++;
+ }
+ }
+
+if (errors > 0)
+ return -1;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * UsersImpl::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
+UsersImpl * us = static_cast<UsersImpl *>(d);
+
+struct tm t;
+time_t tt = stgTime;
+localtime_r(&tt, &t);
+
+int min = t.tm_min;
+int day = t.tm_mday;
+
+printfd(__FILE__,"Day = %d Min = %d\n", day, min);
+
+time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+std::string monFile = us->settings->GetMonitorDir() + "/users_r";
+printfd(__FILE__, "Monitor=%d file USERS %s\n", us->settings->GetMonitoring(), monFile.c_str());
+
+us->isRunning = true;
+while (us->nonstop)
+ {
+ //printfd(__FILE__,"New Minute. old = %02d current = %02d\n", min, t->tm_min);
+ //printfd(__FILE__,"New Day. old = %2d current = %2d\n", day, t->tm_mday);
+
+ for_each(us->users.begin(), us->users.end(), [](auto& user){ user.Run(); });
+
+ tt = stgTime;
+ localtime_r(&tt, &t);
+
+ if (min != t.tm_min)
+ {
+ printfd(__FILE__,"Sec = %d\n", stgTime);
+ printfd(__FILE__,"New Minute. old = %d current = %d\n", min, t.tm_min);
+ min = t.tm_min;
+
+ us->NewMinute(t);
+ }
+
+ if (day != t.tm_mday)
+ {
+ printfd(__FILE__,"Sec = %d\n", stgTime);
+ printfd(__FILE__,"New Day. old = %d current = %d\n", day, t.tm_mday);
+ day = t.tm_mday;
+ us->NewDay(t);
+ }
+
+ if (us->settings->GetMonitoring() && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
+ {
+ //printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", tc->monitoring, monFile.c_str());
+ touchTime = stgTime;
+ TouchFile(monFile);
+ }
+
+ stgUsleep(100000);
+ } //while (us->nonstop)
+
+std::list<USER_TO_DEL>::iterator iter(us->usersToDelete.begin());
+while (iter != us->usersToDelete.end())
+ {
+ iter->delTime -= 2 * userDeleteDelayTime;
+ ++iter;
+ }
+us->RealDelUser();
+
+us->isRunning = false;
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::NewMinute(const struct tm & t)
+{
+//Write traff, reset session traff. Fake disconnect-connect
+if (t.tm_hour == 23 && t.tm_min == 59)
+ {
+ printfd(__FILE__,"MidnightResetSessionStat\n");
+ for_each(users.begin(), users.end(), [](auto& user){ user.MidnightResetSessionStat(); });
+ }
+
+if (TimeToWriteDetailStat(t))
+ {
+ //printfd(__FILE__, "USER::WriteInetStat\n");
+ int usersCnt = 0;
+
+ // ðÉÛÅÍ ÀÚÅÒÏ× ÞÁÓÔÑÍÉ. ÷ ÐÅÒÅÒÙ×ÁÈ ×ÙÚÙ×ÁÅÍ USER::Run
+ std::list<UserImpl>::iterator usr = users.begin();
+ while (usr != users.end())
+ {
+ usersCnt++;
+ usr->WriteDetailStat();
+ ++usr;
+ if (usersCnt % 10 == 0)
+ for_each(users.begin(), users.end(), [](auto& user){ user.Run(); });
+ }
+ }
+
+RealDelUser();
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::NewDay(const struct tm & t)
+{
+struct tm t1;
+time_t tt = stgTime;
+localtime_r(&tt, &t1);
+int dayFee = settings->GetDayFee();
+
+if (dayFee == 0)
+ dayFee = DaysInCurrentMonth();
+
+printfd(__FILE__, "DayFee = %d\n", dayFee);
+printfd(__FILE__, "Today = %d DayResetTraff = %d\n", t1.tm_mday, settings->GetDayResetTraff());
+printfd(__FILE__, "DayFeeIsLastDay = %d\n", settings->GetDayFeeIsLastDay());
+
+if (!settings->GetDayFeeIsLastDay())
+ {
+ printfd(__FILE__, "DayResetTraff - 1 -\n");
+ DayResetTraff(t1);
+ //printfd(__FILE__, "DayResetTraff - 1 - 1 -\n");
+ }
+
+if (settings->GetSpreadFee())
+ {
+ printfd(__FILE__, "Spread DayFee\n");
+ for_each(users.begin(), users.end(), [](auto& user){ user.ProcessDayFeeSpread(); });
+ }
+else
+ {
+ if (t.tm_mday == dayFee)
+ {
+ printfd(__FILE__, "DayFee\n");
+ for_each(users.begin(), users.end(), [](auto& user){ user.ProcessDayFee(); });
+ }
+ }
+
+std::for_each(users.begin(), users.end(), [](auto& user){ user.ProcessDailyFee(); });
+std::for_each(users.begin(), users.end(), [](auto& user){ user.ProcessServices(); });
+
+if (settings->GetDayFeeIsLastDay())
+ {
+ printfd(__FILE__, "DayResetTraff - 2 -\n");
+ DayResetTraff(t1);
+ }
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DayResetTraff(const struct tm & t1)
+{
+int dayResetTraff = settings->GetDayResetTraff();
+if (dayResetTraff == 0)
+ dayResetTraff = DaysInCurrentMonth();
+if (t1.tm_mday == dayResetTraff)
+ {
+ printfd(__FILE__, "ResetTraff\n");
+ for_each(users.begin(), users.end(), [](auto& user){ user.ProcessNewMonth(); });
+ //for_each(users.begin(), users.end(), mem_fun_ref(&UserImpl::SetPrepaidTraff));
+ }
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::Start()
+{
+if (ReadUsers())
+ {
+ WriteServLog("USERS: Error: Cannot read users!");
+ return -1;
+ }
+
+nonstop = true;
+if (pthread_create(&thread, NULL, Run, this))
+ {
+ WriteServLog("USERS: Error: Cannot start thread!");
+ return -1;
+ }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::Stop()
+{
+printfd(__FILE__, "USERS::Stop()\n");
+
+if (!isRunning)
+ {
+ //printfd(__FILE__, "Alredy stopped\n");
+ return 0;
+ }
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+struct timespec ts = {0, 200000000};
+for (size_t i = 0; i < 25 * (users.size() / 50 + 1); i++)
+ {
+ if (!isRunning)
+ break;
+
+ nanosleep(&ts, NULL);
+ }
+
+//after 5 seconds waiting thread still running. now kill it
+if (isRunning)
+ {
+ printfd(__FILE__, "kill USERS thread.\n");
+ //TODO pthread_cancel()
+ if (pthread_kill(thread, SIGINT))
+ {
+ //errorStr = "Cannot kill USERS thread.";
+ //printfd(__FILE__, "Cannot kill USERS thread.\n");
+ //return 0;
+ }
+ printfd(__FILE__, "USERS killed\n");
+ }
+
+printfd(__FILE__, "Before USERS::Run()\n");
+for_each(users.begin(), users.end(), [](auto& user){ user.Run(); });
+
+// 'cause bind2st accepts only constant first param
+for (std::list<UserImpl>::iterator it = users.begin();
+ it != users.end();
+ ++it)
+ it->WriteDetailStat(true);
+
+for_each(users.begin(), users.end(), [](auto& user){ user.WriteStat(); });
+//for_each(users.begin(), users.end(), mem_fun_ref(&UserImpl::WriteConf));
+
+printfd(__FILE__, "USERS::Stop()\n");
+return 0;
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::RealDelUser()
+{
+STG_LOCKER lock(&mutex);
+
+printfd(__FILE__, "RealDelUser() users to del: %d\n", usersToDelete.size());
+
+std::list<USER_TO_DEL>::iterator iter;
+iter = usersToDelete.begin();
+while (iter != usersToDelete.end())
+ {
+ printfd(__FILE__, "RealDelUser() user=%s\n", iter->iter->GetLogin().c_str());
+ if (iter->delTime + userDeleteDelayTime < stgTime)
+ {
+ printfd(__FILE__, "RealDelUser() user=%s removed from DB\n", iter->iter->GetLogin().c_str());
+ if (store->DelUser(iter->iter->GetLogin()))
+ {
+ WriteServLog("Error removing user \'%s\' from database.", iter->iter->GetLogin().c_str());
+ }
+ users.erase(iter->iter);
+ usersToDelete.erase(iter++);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+return;
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::AddToIPIdx(user_iter user)
+{
+printfd(__FILE__, "USERS: Add IP Idx\n");
+uint32_t ip = user->GetCurrIP();
+//assert(ip && "User has non-null ip");
+if (!ip)
+ return; // User has disconnected
+
+STG_LOCKER lock(&mutex);
+
+const std::map<uint32_t, user_iter>::iterator it(
+ ipIndex.lower_bound(ip)
+);
+
+assert((it == ipIndex.end() || it->first != ip) && "User is not in index");
+
+ipIndex.insert(it, std::make_pair(ip, user));
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DelFromIPIdx(uint32_t ip)
+{
+printfd(__FILE__, "USERS: Del IP Idx\n");
+assert(ip && "User has non-null ip");
+
+STG_LOCKER lock(&mutex);
+
+const std::map<uint32_t, user_iter>::iterator it(
+ ipIndex.find(ip)
+);
+
+if (it == ipIndex.end())
+ return;
+
+ipIndex.erase(it);
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::FindByIPIdx(uint32_t ip, user_iter & iter) const
+{
+std::map<uint32_t, user_iter>::const_iterator it(ipIndex.find(ip));
+if (it == ipIndex.end())
+ return false;
+iter = it->second;
+return true;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::FindByIPIdx(uint32_t ip, UserPtr * usr) const
+{
+STG_LOCKER lock(&mutex);
+
+user_iter iter;
+if (FindByIPIdx(ip, iter))
+ {
+ *usr = &(*iter);
+ return 0;
+ }
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::FindByIPIdx(uint32_t ip, UserImpl ** usr) const
+{
+STG_LOCKER lock(&mutex);
+
+user_iter iter;
+if (FindByIPIdx(ip, iter))
+ {
+ *usr = &(*iter);
+ return 0;
+ }
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::IsIPInIndex(uint32_t ip) const
+{
+STG_LOCKER lock(&mutex);
+
+std::map<uint32_t, user_iter>::const_iterator it(ipIndex.find(ip));
+
+return it != ipIndex.end();
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::IsIPInUse(uint32_t ip, const std::string & login, ConstUserPtr * user) const
+{
+STG_LOCKER lock(&mutex);
+std::list<UserImpl>::const_iterator iter;
+iter = users.begin();
+while (iter != users.end())
+ {
+ if (iter->GetLogin() != login &&
+ !iter->GetProperties().ips.Get().isAnyIP() &&
+ iter->GetProperties().ips.Get().find(ip))
+ {
+ if (user != NULL)
+ *user = &(*iter);
+ return true;
+ }
+ ++iter;
+ }
+return false;
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::AddNotifierUserAdd(NotifierBase<UserPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onAddNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DelNotifierUserAdd(NotifierBase<UserPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onAddNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::AddNotifierUserDel(NotifierBase<UserPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onDelNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DelNotifierUserDel(NotifierBase<UserPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onDelNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::AddNotifierUserAdd(NotifierBase<UserImplPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onAddNotifiersImpl.insert(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DelNotifierUserAdd(NotifierBase<UserImplPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onAddNotifiersImpl.erase(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::AddNotifierUserDel(NotifierBase<UserImplPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onDelNotifiersImpl.insert(n);
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DelNotifierUserDel(NotifierBase<UserImplPtr> * n)
+{
+STG_LOCKER lock(&mutex);
+onDelNotifiersImpl.erase(n);
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::OpenSearch()
+{
+STG_LOCKER lock(&mutex);
+handle++;
+searchDescriptors[handle] = users.begin();
+return handle;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::SearchNext(int h, UserPtr * user)
+{
+ UserImpl * ptr = NULL;
+ if (SearchNext(h, &ptr))
+ return -1;
+ *user = ptr;
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::SearchNext(int h, UserImpl ** user)
+{
+STG_LOCKER lock(&mutex);
+
+if (searchDescriptors.find(h) == searchDescriptors.end())
+ {
+ WriteServLog("USERS. Incorrect search handle.");
+ return -1;
+ }
+
+if (searchDescriptors[h] == users.end())
+ return -1;
+
+while (searchDescriptors[h]->GetDeleted())
+ {
+ ++searchDescriptors[h];
+ if (searchDescriptors[h] == users.end())
+ {
+ return -1;
+ }
+ }
+
+*user = &(*searchDescriptors[h]);
+
+++searchDescriptors[h];
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int UsersImpl::CloseSearch(int h)
+{
+STG_LOCKER lock(&mutex);
+if (searchDescriptors.find(h) != searchDescriptors.end())
+ {
+ searchDescriptors.erase(searchDescriptors.find(h));
+ return 0;
+ }
+
+WriteServLog("USERS. Incorrect search handle.");
+return -1;
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::AddUserIntoIndexes(user_iter user)
+{
+STG_LOCKER lock(&mutex);
+loginIndex.insert(make_pair(user->GetLogin(), user));
+}
+//-----------------------------------------------------------------------------
+void UsersImpl::DelUserFromIndexes(user_iter user)
+{
+STG_LOCKER lock(&mutex);
+loginIndex.erase(user->GetLogin());
+}
+//-----------------------------------------------------------------------------
+bool UsersImpl::TimeToWriteDetailStat(const struct tm & t)
+{
+int statTime = settings->GetDetailStatWritePeriod();
+
+switch (statTime)
+ {
+ case dsPeriod_1:
+ if (t.tm_min == 0)
+ return true;
+ break;
+ case dsPeriod_1_2:
+ if (t.tm_min % 30 == 0)
+ return true;
+ break;
+ case dsPeriod_1_4:
+ if (t.tm_min % 15 == 0)
+ return true;
+ break;
+ case dsPeriod_1_6:
+ if (t.tm_min % 10 == 0)
+ return true;
+ break;
+ }
+return false;
+}
--- /dev/null
+/*
+ * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#include <string>
+#include <map>
+#include <list>
+#include <set>
+#include <ctime>
+#include <cstdint>
+
+#include "stg/store.h"
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/tariffs.h"
+#include "stg/logger.h"
+#include "stg/notifer.h"
+#include "stg/noncopyable.h"
+#include "actions.h"
+#include "eventloop.h"
+#include "settings_impl.h"
+#include "user_impl.h"
+
+namespace STG
+{
+
+const int userDeleteDelayTime = 120;
+
+typedef std::list<UserImpl>::iterator user_iter;
+typedef std::list<UserImpl>::const_iterator const_user_iter;
+
+class UsersImpl;
+//-----------------------------------------------------------------------------
+struct USER_TO_DEL {
+USER_TO_DEL()
+ : iter(),
+ delTime(0)
+{}
+
+std::list<UserImpl>::iterator iter;
+time_t delTime;
+};
+//-----------------------------------------------------------------------------
+class UsersImpl : public Users {
+ friend class PROPERTY_NOTIFER_IP_BEFORE;
+ friend class PROPERTY_NOTIFER_IP_AFTER;
+
+public:
+ using UserImplPtr = UserImpl*;
+
+ UsersImpl(SettingsImpl * s, Store * store,
+ Tariffs * tariffs, Services & svcs,
+ const Admin& sysAdmin);
+ virtual ~UsersImpl();
+
+ int FindByName(const std::string & login, UserPtr * user) override;
+ int FindByName(const std::string & login, ConstUserPtr * user) const override;
+ bool Exists(const std::string & login) const override;
+
+ bool TariffInUse(const std::string & tariffName) const override;
+
+ void AddNotifierUserAdd(NotifierBase<UserPtr> *) override;
+ void DelNotifierUserAdd(NotifierBase<UserPtr> *) override;
+
+ void AddNotifierUserDel(NotifierBase<UserPtr> *) override;
+ void DelNotifierUserDel(NotifierBase<UserPtr> *) override;
+
+ void AddNotifierUserAdd(NotifierBase<UserImplPtr> *);
+ void DelNotifierUserAdd(NotifierBase<UserImplPtr> *);
+
+ void AddNotifierUserDel(NotifierBase<UserImplPtr> *);
+ void DelNotifierUserDel(NotifierBase<UserImplPtr> *);
+
+ int Add(const std::string & login, const Admin * admin) override;
+ void Del(const std::string & login, const Admin * admin) override;
+
+ bool Authorize(const std::string & login, uint32_t ip,
+ uint32_t enabledDirs, const Auth * auth) override;
+ bool Unauthorize(const std::string & login,
+ const Auth * auth,
+ const std::string & reason) override;
+
+ int ReadUsers() override;
+ size_t Count() const override { return users.size(); }
+
+ int FindByIPIdx(uint32_t ip, UserPtr * user) const override;
+ int FindByIPIdx(uint32_t ip, UserImpl ** user) const;
+ bool IsIPInIndex(uint32_t ip) const override;
+ bool IsIPInUse(uint32_t ip, const std::string & login, ConstUserPtr * user) const override;
+
+ int OpenSearch() override;
+ int SearchNext(int handler, UserPtr * user) override;
+ int SearchNext(int handler, UserImpl ** user);
+ int CloseSearch(int handler) override;
+
+ int Start() override;
+ int Stop() override;
+
+private:
+ UsersImpl(const UsersImpl & rvalue);
+ UsersImpl & operator=(const UsersImpl & rvalue);
+
+ void AddToIPIdx(user_iter user);
+ void DelFromIPIdx(uint32_t ip);
+ bool FindByIPIdx(uint32_t ip, user_iter & iter) const;
+
+ int FindByNameNonLock(const std::string & login, user_iter * user);
+ int FindByNameNonLock(const std::string & login, const_user_iter * user) const;
+
+ void RealDelUser();
+ void ProcessActions();
+
+ void AddUserIntoIndexes(user_iter user);
+ void DelUserFromIndexes(user_iter user);
+
+ static void * Run(void *);
+ void NewMinute(const struct tm & t);
+ void NewDay(const struct tm & t);
+ void DayResetTraff(const struct tm & t);
+
+ bool TimeToWriteDetailStat(const struct tm & t);
+
+ std::list<UserImpl> users;
+ std::list<USER_TO_DEL> usersToDelete;
+
+ std::map<uint32_t, user_iter> ipIndex;
+ std::map<std::string, user_iter> loginIndex;
+
+ SettingsImpl * settings;
+ Tariffs * tariffs;
+ Services & m_services;
+ Store * store;
+ const Admin& sysAdmin;
+ Logger & WriteServLog;
+
+ bool nonstop;
+ bool isRunning;
+
+ mutable pthread_mutex_t mutex;
+ pthread_t thread;
+ mutable unsigned int handle;
+
+ mutable std::map<int, user_iter> searchDescriptors;
+
+ std::set<NotifierBase<UserPtr>*> onAddNotifiers;
+ std::set<NotifierBase<UserPtr>*> onDelNotifiers;
+ std::set<NotifierBase<UserImplPtr>*> onAddNotifiersImpl;
+ std::set<NotifierBase<UserImplPtr>*> onDelNotifiersImpl;
+};
+
+}
+++ /dev/null
-set ( CPP_FILES main.cpp listener.cpp pidfile.cpp )
-
-set ( THREADS_PREFER_PTHREAD_FLAG ON )
-find_package ( Threads REQUIRED )
-
-add_executable ( rscriptd ${CPP_FILES} )
-
-target_link_libraries ( rscriptd scriptexecuter conffiles logger crypto common Threads::Threads )
-
-# TODO: install
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include <arpa/inet.h>
-#include <sys/uio.h> // readv
-#include <sys/types.h> // for historical versions of BSD
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <csignal>
-#include <cerrno>
-#include <ctime>
-#include <cstring>
-#include <sstream>
-#include <algorithm>
-
-#include "stg/scriptexecuter.h"
-#include "stg/locker.h"
-#include "stg/common.h"
-#include "stg/const.h"
-#include "listener.h"
-
-void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password);
-void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
-
-//-----------------------------------------------------------------------------
-LISTENER::LISTENER()
- : WriteServLog(STG::Logger::get()),
- port(0),
- running(false),
- receiverStopped(true),
- processorStopped(true),
- userTimeout(0),
- listenSocket(0),
- version("rscriptd listener v.1.2")
-{
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-void LISTENER::SetPassword(const std::string & p)
-{
-password = p;
-printfd(__FILE__, "Encryption initiated with password \'%s\'\n", password.c_str());
-InitEncrypt(&ctxS, password);
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::Start()
-{
-printfd(__FILE__, "LISTENER::Start()\n");
-running = true;
-
-if (PrepareNet())
- {
- return true;
- }
-
-if (receiverStopped)
- {
- if (pthread_create(&receiverThread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- return true;
- }
- }
-
-if (processorStopped)
- {
- if (pthread_create(&processorThread, NULL, RunProcessor, this))
- {
- errorStr = "Cannot create thread.";
- return true;
- }
- }
-
-errorStr = "";
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::Stop()
-{
-running = false;
-
-printfd(__FILE__, "LISTENER::Stop()\n");
-
-struct timespec ts = {0, 500000000};
-nanosleep(&ts, NULL);
-
-if (!processorStopped)
- {
- //5 seconds to thread stops itself
- for (int i = 0; i < 25 && !processorStopped; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
- //after 5 seconds waiting thread still running. now killing it
- if (!processorStopped)
- {
- //TODO pthread_cancel()
- if (pthread_kill(processorThread, SIGINT))
- {
- errorStr = "Cannot kill thread.";
- return true;
- }
- printfd(__FILE__, "LISTENER killed Timeouter\n");
- }
- }
-
-if (!receiverStopped)
- {
- //5 seconds to thread stops itself
- for (int i = 0; i < 25 && !receiverStopped; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
- //after 5 seconds waiting thread still running. now killing it
- if (!receiverStopped)
- {
- //TODO pthread_cancel()
- if (pthread_kill(receiverThread, SIGINT))
- {
- errorStr = "Cannot kill thread.";
- return true;
- }
- printfd(__FILE__, "LISTENER killed Run\n");
- }
- }
-
-pthread_join(receiverThread, NULL);
-pthread_join(processorThread, NULL);
-
-pthread_mutex_destroy(&mutex);
-
-FinalizeNet();
-
-std::for_each(users.begin(), users.end(), DisconnectUser(*this));
-
-printfd(__FILE__, "LISTENER::Stoped successfully.\n");
-
-return false;
-}
-//-----------------------------------------------------------------------------
-void * LISTENER::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-LISTENER * listener = static_cast<LISTENER *>(d);
-
-listener->Runner();
-
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void LISTENER::Runner()
-{
-receiverStopped = false;
-
-while (running)
- {
- RecvPacket();
- }
-
-receiverStopped = true;
-}
-//-----------------------------------------------------------------------------
-void * LISTENER::RunProcessor(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-LISTENER * listener = static_cast<LISTENER *>(d);
-
-listener->ProcessorRunner();
-
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void LISTENER::ProcessorRunner()
-{
-processorStopped = false;
-
-while (running)
- {
- struct timespec ts = {0, 500000000};
- nanosleep(&ts, NULL);
- if (!pending.empty())
- ProcessPending();
- ProcessTimeouts();
- }
-
-processorStopped = true;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::PrepareNet()
-{
-listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
-
-if (listenSocket < 0)
- {
- errorStr = "Cannot create socket.";
- return true;
- }
-
-struct sockaddr_in listenAddr;
-listenAddr.sin_family = AF_INET;
-listenAddr.sin_port = htons(port);
-listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
-
-if (bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0)
- {
- errorStr = "LISTENER: Bind failed.";
- return true;
- }
-
-printfd(__FILE__, "LISTENER::PrepareNet() >>>> Start successfull.\n");
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::FinalizeNet()
-{
-close(listenSocket);
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::RecvPacket()
-{
-struct iovec iov[2];
-
-char buffer[RS_MAX_PACKET_LEN];
-RS::PACKET_HEADER packetHead;
-
-iov[0].iov_base = reinterpret_cast<char *>(&packetHead);
-iov[0].iov_len = sizeof(packetHead);
-iov[1].iov_base = buffer;
-iov[1].iov_len = sizeof(buffer) - sizeof(packetHead);
-
-size_t dataLen = 0;
-while (dataLen < sizeof(buffer))
- {
- if (!WaitPackets(listenSocket))
- {
- if (!running)
- return false;
- continue;
- }
- int portion = readv(listenSocket, iov, 2);
- if (portion < 0)
- {
- return true;
- }
- dataLen += portion;
- }
-
-if (CheckHeader(packetHead))
- {
- printfd(__FILE__, "Invalid packet or incorrect protocol version!\n");
- return true;
- }
-
-std::string userLogin((char *)packetHead.login);
-PendingData data;
-data.login = userLogin;
-data.ip = ntohl(packetHead.ip);
-data.id = ntohl(packetHead.id);
-
-if (packetHead.packetType == RS_ALIVE_PACKET)
- {
- data.type = PendingData::ALIVE;
- }
-else if (packetHead.packetType == RS_CONNECT_PACKET)
- {
- data.type = PendingData::CONNECT;
- if (GetParams(buffer, data))
- {
- return true;
- }
- }
-else if (packetHead.packetType == RS_DISCONNECT_PACKET)
- {
- data.type = PendingData::DISCONNECT;
- if (GetParams(buffer, data))
- {
- return true;
- }
- }
-
-STG_LOCKER lock(&mutex);
-pending.push_back(data);
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::GetParams(char * buffer, UserData & data)
-{
-RS::PACKET_TAIL packetTail;
-
-Decrypt(&ctxS, (char *)&packetTail, buffer, sizeof(packetTail) / 8);
-
-if (strncmp((char *)packetTail.magic, RS_ID, RS_MAGIC_LEN))
- {
- printfd(__FILE__, "Invalid crypto magic\n");
- return true;
- }
-
-std::ostringstream params;
-params << "\"" << data.login << "\" "
- << inet_ntostring(data.ip) << " "
- << data.id << " "
- << (char *)packetTail.params;
-
-data.params = params.str();
-
-return false;
-}
-//-----------------------------------------------------------------------------
-void LISTENER::ProcessPending()
-{
-std::list<PendingData>::iterator it(pending.begin());
-size_t count = 0;
-printfd(__FILE__, "Pending: %d\n", pending.size());
-while (it != pending.end() && count < 256)
- {
- std::vector<AliveData>::iterator uit(
- std::lower_bound(
- users.begin(),
- users.end(),
- it->login)
- );
- if (it->type == PendingData::CONNECT)
- {
- printfd(__FILE__, "Connect packet\n");
- if (uit == users.end() || uit->login != it->login)
- {
- printfd(__FILE__, "Connect new user '%s'\n", it->login.c_str());
- // Add new user
- Connect(*it);
- users.insert(uit, AliveData(static_cast<UserData>(*it)));
- }
- else if (uit->login == it->login)
- {
- printfd(__FILE__, "Update existing user '%s'\n", it->login.c_str());
- // Update already existing user
- time(&uit->lastAlive);
- uit->params = it->params;
- }
- else
- {
- printfd(__FILE__, "Hmmm... Strange connect for '%s'\n", it->login.c_str());
- }
- }
- else if (it->type == PendingData::ALIVE)
- {
- printfd(__FILE__, "Alive packet\n");
- if (uit != users.end() && uit->login == it->login)
- {
- printfd(__FILE__, "Alive user '%s'\n", it->login.c_str());
- // Update existing user
- time(&uit->lastAlive);
- }
- else
- {
- printfd(__FILE__, "Alive user '%s' is not found\n", it->login.c_str());
- }
- }
- else if (it->type == PendingData::DISCONNECT)
- {
- printfd(__FILE__, "Disconnect packet\n");
- if (uit != users.end() && uit->login == it->login.c_str())
- {
- printfd(__FILE__, "Disconnect user '%s'\n", it->login.c_str());
- // Disconnect existing user
- uit->params = it->params;
- Disconnect(*uit);
- users.erase(uit);
- }
- else
- {
- printfd(__FILE__, "Cannot find user '%s' for disconnect\n", it->login.c_str());
- }
- }
- else
- {
- printfd(__FILE__, "Unknown packet type\n");
- }
- ++it;
- ++count;
- }
-STG_LOCKER lock(&mutex);
-pending.erase(pending.begin(), it);
-}
-//-----------------------------------------------------------------------------
-void LISTENER::ProcessTimeouts()
-{
-const std::vector<AliveData>::iterator it(
- std::stable_partition(
- users.begin(),
- users.end(),
- IsNotTimedOut(userTimeout)
- )
- );
-
-if (it != users.end())
- {
- printfd(__FILE__, "Total users: %d, users to disconnect: %d\n", users.size(), std::distance(it, users.end()));
-
- std::for_each(
- it,
- users.end(),
- DisconnectUser(*this)
- );
-
- users.erase(it, users.end());
- }
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::Connect(const UserData & data) const
-{
-printfd(__FILE__, "Connect %s\n", data.login.c_str());
-if (access(scriptOnConnect.c_str(), X_OK) == 0)
- {
- if (ScriptExec((scriptOnConnect + " " + data.params).c_str()))
- {
- WriteServLog("Script %s cannot be executed for an unknown reason.", scriptOnConnect.c_str());
- return true;
- }
- }
-else
- {
- WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
- return true;
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::Disconnect(const UserData & data) const
-{
-printfd(__FILE__, "Disconnect %s\n", data.login.c_str());
-if (access(scriptOnDisconnect.c_str(), X_OK) == 0)
- {
- if (ScriptExec((scriptOnDisconnect + " " + data.params).c_str()))
- {
- WriteServLog("Script %s cannot be executed for an unknown reson.", scriptOnDisconnect.c_str());
- return true;
- }
- }
-else
- {
- WriteServLog("Script %s cannot be executed. File not found.", scriptOnDisconnect.c_str());
- return true;
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-bool LISTENER::CheckHeader(const RS::PACKET_HEADER & header) const
-{
-if (strncmp((char *)header.magic, RS_ID, RS_MAGIC_LEN))
- {
- return true;
- }
-if (strncmp((char *)header.protoVer, "02", RS_PROTO_VER_LEN))
- {
- return true;
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-inline
-void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password)
-{
-unsigned char keyL[PASSWD_LEN];
-memset(keyL, 0, PASSWD_LEN);
-strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
-Blowfish_Init(ctx, keyL, PASSWD_LEN);
-}
-//-----------------------------------------------------------------------------
-inline
-void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
-{
-if (dst != src)
- memcpy(dst, src, len8 * 8);
-
-for (int i = 0; i < len8; i++)
- Blowfish_Decrypt(ctx, (uint32_t *)(dst + i * 8), (uint32_t *)(dst + i * 8 + 4));
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include <pthread.h>
-
-#include <string>
-#include <vector>
-#include <list>
-#include <functional>
-#include <cstdint>
-
-#include "stg/blowfish.h"
-#include "stg/rs_packets.h"
-#include "stg/logger.h"
-
-struct UserData
-{
- std::string params;
- std::string login;
- uint32_t ip;
- uint32_t id;
-};
-
-struct PendingData : public UserData
-{
- enum {CONNECT, ALIVE, DISCONNECT} type;
-};
-
-struct AliveData : public UserData
-{
- explicit AliveData(const UserData & data)
- : UserData(data),
- lastAlive(time(NULL))
- {};
- bool operator<(const std::string & rvalue) const { return login < rvalue; };
- time_t lastAlive;
-};
-
-class IsNotTimedOut : public std::unary_function<const AliveData &, bool> {
- public:
- explicit IsNotTimedOut(double to) : timeout(to), now(time(NULL)) {}
- bool operator()(const AliveData & data) const
- {
- return difftime(now, data.lastAlive) < timeout;
- }
- private:
- double timeout;
- time_t now;
-};
-
-class LISTENER
-{
-public:
- LISTENER();
- ~LISTENER(){};
-
- void SetPort(uint16_t p) { port = p; };
- void SetPassword(const std::string & p);
- void SetUserTimeout(int t) { userTimeout = t; };
- void SetScriptOnConnect(const std::string & script) { scriptOnConnect = script; };
- void SetScriptOnDisconnect(const std::string & script) { scriptOnDisconnect = script; };
-
- bool Start();
- bool Stop();
- bool IsRunning() const { return !receiverStopped && !processorStopped; };
-
- const std::string & GetStrError() const { return errorStr; };
- const std::string & GetVersion() const { return version; };
-
-private:
- // Threading stuff
- static void * Run(void * self);
- static void * RunProcessor(void * self);
- void Runner();
- void ProcessorRunner();
- // Networking stuff
- bool PrepareNet();
- bool FinalizeNet();
- bool RecvPacket();
- // Parsing stuff
- bool CheckHeader(const RS::PACKET_HEADER & header) const;
- bool GetParams(char * buffer, UserData & data);
- // Processing stuff
- void ProcessPending();
- void ProcessTimeouts();
- bool Disconnect(const UserData & data) const;
- bool Connect(const UserData & data) const;
-
- BLOWFISH_CTX ctxS;
- STG::Logger& WriteServLog;
-
- mutable std::string errorStr;
- std::string scriptOnConnect;
- std::string scriptOnDisconnect;
- std::string password;
- uint16_t port;
-
- bool running;
- bool receiverStopped;
- bool processorStopped;
- std::vector<AliveData> users;
- std::list<PendingData> pending;
- int userTimeout;
-
- pthread_t receiverThread;
- pthread_t processorThread;
- pthread_mutex_t mutex;
-
- int listenSocket;
-
- std::string version;
-
- friend class DisconnectUser;
-};
-
-class DisconnectUser : public std::unary_function<const UserData &, void> {
- public:
- explicit DisconnectUser(LISTENER & l) : listener(l) {};
- void operator()(const UserData & data)
- {
- listener.Disconnect(data);
- };
- private:
- LISTENER & listener;
-};
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
- /*
- $Revision: 1.19 $
- $Author: faust $
- $Date: 2010/09/10 06:37:45 $
- */
-
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h> // creat
-#include <unistd.h>
-
-#include <cstdlib>
-#include <cstdio>
-#include <csignal>
-#include <cerrno>
-#include <cstring> // strerror
-#include <set>
-
-#include "stg/common.h"
-#include "stg/logger.h"
-#include "stg/scriptexecuter.h"
-#include "stg/conffiles.h"
-#include "stg/version.h"
-#include "listener.h"
-#include "pidfile.h"
-
-#ifdef DEBUG
-# define MAIN_DEBUG 1
-# define NO_DAEMON 1
-#endif
-
-#define START_FILE "/._ST_ART_ED_"
-
-std::set<pid_t> executersPid;
-volatile time_t stgTime = time(NULL);
-
-//-----------------------------------------------------------------------------
-void KillExecuters()
-{
-std::set<pid_t>::iterator pid;
-pid = executersPid.begin();
-while (pid != executersPid.end())
- {
- printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
- kill(*pid, SIGUSR1);
- ++pid;
- }
-}
-//-----------------------------------------------------------------------------
-#if defined(LINUX) || defined(DARWIN)
-int StartScriptExecuter(char * procName, int msgKey, int * msgID)
-#else
-int StartScriptExecuter(char *, int msgKey, int * msgID)
-#endif
-{
-auto & WriteServLog = STG::Logger::get();
-
-if (*msgID == -11) // If msgID == -11 - first call. Create queue
- {
- for (int i = 0; i < 2; i++)
- {
- *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
-
- if (*msgID == -1)
- {
- *msgID = msgget(msgKey, 0);
- if (*msgID == -1)
- {
- WriteServLog("Message queue not created.");
- return -1;
- }
- else
- {
- msgctl(*msgID, IPC_RMID, NULL);
- }
- }
- else
- {
- WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
- break;
- }
- }
- }
-
-pid_t executerPid = fork();
-
-switch (executerPid)
- {
- case -1: // Failure
- WriteServLog("Fork error!");
- return -1;
-
- case 0: // Child
- //close(0);
- //close(1);
- //close(2);
- //setsid();
-#if defined(LINUX) || defined(DARWIN)
- Executer(*msgID, executerPid, procName);
-#else
- Executer(*msgID, executerPid);
-#endif
- return 1;
-
- default: // Parent
- if (executersPid.empty())
-#if defined(LINUX) || defined(DARWIN)
- Executer(*msgID, executerPid, NULL);
-#else
- Executer(*msgID, executerPid);
-#endif
- executersPid.insert(executerPid);
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void StopScriptExecuter(int msgID)
-{
-auto & WriteServLog = STG::Logger::get();
-
-for (int i = 0; i < 5; ++i)
- {
- struct msqid_ds data;
- if (msgctl(msgID, IPC_STAT, &data))
- {
- int e = errno;
- printfd(__FILE__, "StopScriptExecuter() - msgctl for IPC_STAT failed: '%s'\n", strerror(e));
- WriteServLog( "Failed to check queue emptiness: '%s'", strerror(e));
- break;
- }
-
- WriteServLog("Messages in queue: %d", data.msg_qnum);
-
- if (data.msg_qnum == 0)
- break;
-
- struct timespec ts = {1, 0};
- nanosleep(&ts, NULL);
- }
-
-if (msgctl(msgID, IPC_RMID, NULL))
- {
- int e = errno;
- printfd(__FILE__, "StopScriptExecuter() - msgctl for IPC_STAT failed: '%s'\n", strerror(e));
- WriteServLog("Failed to remove queue: '%s'", strerror(e));
- }
-else
- {
- WriteServLog("Queue removed successfully.");
- }
-
-KillExecuters();
-}
-//-----------------------------------------------------------------------------
-#ifdef NO_DAEMON
-int ForkAndWait(const std::string &)
-#else
-int ForkAndWait(const std::string & confDir)
-#endif
-{
-#ifndef NO_DAEMON
-pid_t childPid = fork();
-
-switch (childPid)
- {
- case -1: // Failure
- return -1;
- break;
-
- case 0: // Child
- //close(0);
- close(1);
- close(2);
- setsid();
- break;
-
- default: // Parent
- exit(1);
- break;
- }
-#endif
-return 0;
-}
-//-----------------------------------------------------------------------------
-int main(int argc, char * argv[])
-{
-CONFIGFILE * cfg = NULL;
-LISTENER * listener = NULL;
-int msgID = -11;
-int execNum = 0;
-int execMsgKey = 0;
-
-std::string logFileName;
-std::string confDir;
-std::string password;
-std::string onConnect;
-std::string onDisconnect;
-int port;
-int userTimeout;
-
-if (getuid())
- {
- printf("You must be root. Exit.\n");
- exit(1);
- }
-
-if (argc == 2)
- cfg = new CONFIGFILE(argv[1]);
-else
- cfg = new CONFIGFILE("/etc/rscriptd/rscriptd.conf");
-
-if (cfg->Error())
- {
- auto & WriteServLog = STG::Logger::get();
- WriteServLog.setFileName("/var/log/rscriptd.log");
- WriteServLog("Error reading config file!");
- delete cfg;
- return EXIT_FAILURE;
- }
-
-cfg->ReadString("LogFileName", &logFileName, "/var/log/rscriptd.log");
-cfg->ReadInt("ExecutersNum", &execNum, 1);
-cfg->ReadInt("ExecMsgKey", &execMsgKey, 5555);
-cfg->ReadString("ConfigDir", &confDir, "/etc/rscriptd");
-cfg->ReadString("Password", &password, "");
-cfg->ReadInt("Port", &port, 5555);
-cfg->ReadInt("UserTimeout", &userTimeout, 60);
-cfg->ReadString("ScriptOnConnect", &onConnect, "/etc/rscriptd/OnConnect");
-cfg->ReadString("ScriptOnDisconnect", &onDisconnect, "/etc/rscriptd/OnDisconnect");
-
-if (ForkAndWait(confDir) < 0)
- {
- auto & WriteServLog = STG::Logger::get();
- WriteServLog("Fork error!");
- delete cfg;
- return EXIT_FAILURE;
- }
-
-auto & WriteServLog = STG::Logger::get();
-PIDFile pidFile("/var/run/rscriptd.pid");
-WriteServLog.setFileName(logFileName);
-WriteServLog("rscriptd v. %s", SERVER_VERSION);
-
-for (int i = 0; i < execNum; i++)
- {
- int ret = StartScriptExecuter(argv[0], execMsgKey, &msgID);
- if (ret < 0)
- {
- STG::Logger::get()("Start Script Executer error!");
- delete cfg;
- return EXIT_FAILURE;
- }
- if (ret == 1)
- {
- delete cfg;
- return EXIT_SUCCESS;
- }
- }
-
-listener = new LISTENER();
-listener->SetPort(port);
-listener->SetPassword(password);
-listener->SetUserTimeout(userTimeout);
-listener->SetScriptOnConnect(onConnect);
-listener->SetScriptOnDisconnect(onDisconnect);
-
-listener->Start();
-
-WriteServLog("rscriptd started successfully.");
-WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
-
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-while (true)
- {
- sigfillset(&signalSet);
- int sig = 0;
- printfd(__FILE__, "Before sigwait\n");
- sigwait(&signalSet, &sig);
- printfd(__FILE__, "After sigwait. Signal: %d\n", sig);
- bool stop = false;
- switch (sig)
- {
- case SIGTERM:
- stop = true;
- break;
- case SIGINT:
- stop = true;
- break;
- default:
- WriteServLog("Ignore signel %d", sig);
- break;
- }
- if (stop)
- break;
- }
-
-listener->Stop();
-
-WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
-
-StopScriptExecuter(msgID);
-
-WriteServLog("rscriptd stopped successfully.");
-WriteServLog("---------------------------------------------");
-
-delete listener;
-delete cfg;
-return EXIT_SUCCESS;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- $Revision: 1.1 $
- $Date: 2010/02/11 12:32:25 $
- $Author: faust $
- */
-
-/*
- * An implementation of RAII pid-file writer
- */
-
-#include <fstream>
-#include <unistd.h>
-
-#include "pidfile.h"
-
-PIDFile::PIDFile(const std::string & fn)
- : fileName(fn)
-{
-if (fileName != "")
- {
- std::ofstream pf(fileName.c_str());
- pf << getpid() << std::endl;
- pf.close();
- }
-}
-
-PIDFile::~PIDFile()
-{
-if (fileName != "")
- {
- unlink(fileName.c_str());
- }
-}
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Header file for RAII pid-file writer
- */
-
-/*
- $Revision: 1.1 $
- $Date: 2010/02/11 12:32:25 $
- $Author: faust $
- */
-
-#ifndef __PID_FILE_H__
-#define __PID_FILE_H__
-
-#include <string>
-
-class PIDFile {
-public:
- explicit PIDFile(const std::string & fn);
- ~PIDFile();
-private:
- std::string fileName;
-};
-
-#endif
+++ /dev/null
-################################################################################
-# Rscriptd Configuration file #
-################################################################################
-
-# LOG file name
-# Parameter: optional
-# Value: file path
-# Default: /var/log/rscriptd.log
-LogFileName = /var/log/rscriptd.log
-
-# Amount of rscriptd-exec processes.
-# These processes are responsible for the execution of scripts
-# OnConnect and OnDisconnect.
-# Amount of processes means how many scripts can be executed simultaneously.
-# Recommend to leave 1 to avoid errors when executing scripts
-# Parameter: optional
-# Value: 1 ... 1024
-# Default: 1
-ExecutersNum = 1
-
-# Message queue identifier for the script executer.
-# It may be changed if there're a needs to run multiple copies of rscriptd.
-# Warning: If you do not understand it, do not touch this setting!
-# Parameter: optional
-# Value: 0 ... 2 ^ 32
-# Default: 5555
-# ExecMsgKey = 5555
-
-# The path to directory where config files are
-# Parameter: optional
-# Value: directory path
-# Default: /etc/rscriptd
-ConfigDir = /etc/rscriptd
-
-# Defines password for the encryption exchange between
-# Stargazer server and rscriptd.
-# Parameter: optional
-# Value: any
-# Default: 123456
-Password = 123456
-
-# Defines port number for communication between
-# Stargazer server and rscriptd.
-# Parameter: optional
-# Value: 1 ... 65535
-# Default: 9999
-Port = 9999
-
-# User timeout. If Stargazer does not respond during this time,
-# the user will be disconnected.
-# Parameter: optional
-# Values: 5 ... 600
-# Default: 60
-UserTimeout = 60
-
-# Defines file which runs when user gets access
-# Parameter: optional
-# Value: file path
-# Default: /etc/rscriptd/OnConnect
-ScriptOnConnect = /etc/rscriptd/OnConnect
-
-# Defines file which runs when user loses access
-# Parameter: optional
-# Value: file path
-# Default: /etc/rscriptd/OnDisconnect
-ScriptOnDisconnect = /etc/rscriptd/OnDisconnect
-
-################################################################################
+++ /dev/null
-css.h
-sgauth
+++ /dev/null
-set ( CPP_FILES main.cpp settings_impl.cpp web.cpp )
-
-set ( THREADS_PREFER_PTHREAD_FLAG ON )
-find_package ( Threads REQUIRED )
-find_package ( Intl REQUIRED )
-
-file ( READ sgauth.css CSS_DATA )
-configure_file ( css.h.in css.h ESCAPE_QUOTES @ONLY )
-
-set ( CMAKE_INCLUDE_CURRENT_DIR ON )
-
-include_directories ( ${Intl_INCLUDE_DIRS} )
-
-add_executable ( sgauth ${CPP_FILES} )
-
-target_link_libraries ( sgauth conffiles ia crypto common ${Intl_LIBRARIES} Threads::Threads )
-
-# TODO: install
+++ /dev/null
-#pragma once
-
-namespace SGAuth
-{
-
-const auto css = R"EOR(
-@CSS_DATA@
-)EOR";
-
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
- /*
- $Revision: 1.13 $
- $Date: 2010/04/14 09:01:29 $
- $Author: faust $
- */
-
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <csignal>
-#include <cstdio>
-#include <cstring>
-#include <iostream>
-#include <vector>
-
-#include "stg/ia.h"
-#include "stg/common.h"
-#include "web.h"
-#include "settings_impl.h"
-
-int mes;
-char infoText[256];
-char messageText[256];
-
-const int winKOI = 0;
-
-IA_CLIENT_PROT * clnp;
-WEB * web = NULL;
-
-time_t stgTime;
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void Usage()
-{
-printf("sgauth <path_to_config>\n");
-}
-//-----------------------------------------------------------------------------
-void SetDirName(const std::vector<std::string> & dn, void *)
-{
-for (int j = 0; j < DIR_NUM; j++)
- {
- if (winKOI)
- {
- std::string dir;
- KOIToWin(dn[j], &dir);
- if (web)
- web->SetDirName(dir, j);
- }
- else
- {
- if (web)
- web->SetDirName(dn[j], j);
- }
- }
-}
-//-----------------------------------------------------------------------------
-void StatUpdate(const LOADSTAT & ls, void *)
-{
-if (web)
- web->UpdateStat(ls);
-}
-//-----------------------------------------------------------------------------
-void StatusChanged(int, void *)
-{
-}
-//-----------------------------------------------------------------------------
-void ShowMessage(const std::string & message, int i, int, int, void *)
-{
-if (web)
- web->AddMessage(message, i);
-}
-//-----------------------------------------------------------------------------
-void ShowError(const std::string & message, int, void *)
-{
-if (web)
- web->AddMessage(message, 0);
-}
-//-----------------------------------------------------------------------------
-void CatchUSR1(int)
-{
-if (clnp->GetAuthorized())
- {
- std::cout << "Connect" << std::endl;
- clnp->Connect();
- }
-}
-//-----------------------------------------------------------------------------
-void CatchUSR2(int)
-{
-std::cout << "Disconnect" << std::endl;
-clnp->Disconnect();
-}
-//-----------------------------------------------------------------------------
-void CatchTERM(int)
-{
-std::cout << "Terminated" << std::endl;
-clnp->Disconnect();
-sleep(2);
-exit(0);
-}
-//-----------------------------------------------------------------------------
-static void SetSignalHandlers()
-{
-struct sigaction newsa, oldsa;
-sigset_t sigmask;
-
-sigemptyset(&sigmask);
-sigaddset(&sigmask, SIGTERM);
-newsa.sa_handler = CatchTERM;
-newsa.sa_mask = sigmask;
-newsa.sa_flags = 0;
-sigaction(SIGTERM, &newsa, &oldsa);
-
-sigemptyset(&sigmask);
-sigaddset(&sigmask, SIGINT);
-newsa.sa_handler = CatchTERM;
-newsa.sa_mask = sigmask;
-newsa.sa_flags = 0;
-sigaction(SIGINT, &newsa, &oldsa);
-
-sigemptyset(&sigmask);
-sigaddset(&sigmask, SIGUSR1);
-newsa.sa_handler = CatchUSR1;
-newsa.sa_mask = sigmask;
-newsa.sa_flags = 0;
-sigaction(SIGUSR1, &newsa, &oldsa);
-
-sigemptyset(&sigmask);
-sigaddset(&sigmask, SIGUSR2);
-newsa.sa_handler = CatchUSR2;
-newsa.sa_mask = sigmask;
-newsa.sa_flags = 0;
-sigaction(SIGUSR2, &newsa, &oldsa);
-
-return;
-}
-//-----------------------------------------------------------------------------
-int main(int argc, char *argv[])
-{
-SETTINGS_IMPL settings;
-
-if (argc == 2)
- {
- settings.SetConfFile(argv[1]);
- }
-else
- {
- // Usage
- }
-
-if (settings.ReadSettings())
- {
- printf("ReadSettingsError\n");
- printf("%s\n", settings.GetStrError().c_str());
- exit(-1);
- }
-settings.Print();
-
-if (settings.GetDaemon())
- {
- switch (fork())
- {
- case -1:
- exit(1);
- break;
-
- case 0:
- setsid();
- break;
-
- default:
- exit(0);
- break;
- }
- }
-
-clnp = new IA_CLIENT_PROT(settings.GetServerName(), settings.GetServerPort(), settings.GetLocalName(), settings.GetLocalPort());
-
-if (!settings.GetNoWeb())
- {
- web = new WEB();
- web->SetRefreshPagePeriod(settings.GetRefreshPeriod());
- web->SetListenAddr(settings.GetListenWebIP());
- web->Start();
- }
-
-clnp->SetLogin(settings.GetLogin());
-clnp->SetPassword(settings.GetPassword());
-
-clnp->SetStatusChangedCb(StatusChanged, NULL);
-clnp->SetInfoCb(ShowMessage, NULL);
-clnp->SetErrorCb(ShowError, NULL);
-clnp->SetDirNameCb(SetDirName, NULL);
-clnp->SetStatChangedCb(StatUpdate, NULL);
-clnp->SetReconnect(settings.GetReconnect());
-
-clnp->Start();
-
-SetSignalHandlers();
-
-#ifdef LINUX
-for (int i = 1; i < argc; i++)
- memset(argv[i], 0, strlen(argv[i]));
-
-if(argc > 1)
- strcpy(argv[1], "Connecting...");
-#endif
-
-#ifdef FREEBSD
-setproctitle("Connecting...");
-#endif
-clnp->Connect();
-
-while (1)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
-
- char state[20];
-
- if (clnp->GetAuthorized())
- {
- if (settings.GetShowPid())
- sprintf(state, "On %d", getpid());
- else
- strcpy(state, "Online");
- }
- else
- {
- if (settings.GetShowPid())
- sprintf(state, "Off %d", getpid());
- else
- strcpy(state, "Offline");
- }
-
- #ifdef LINUX
- for (int i = 1; i < argc; i++)
- memset(argv[i], 0, strlen(argv[i]));
- if(argc > 1)
- strcpy(argv[1], state);
- #endif
-
- #ifdef FREEBSD
- setproctitle(state);
- #endif
-
- #ifdef FREEBSD_5
- setproctitle(state);
- #endif
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 <iostream>
-#include <cstring>
-
-#include "stg/common.h"
-#include "stg/conffiles.h"
-#include "settings_impl.h"
-
-SETTINGS_IMPL::SETTINGS_IMPL()
- : port(0),
- localPort(0),
- listenWebIP(0),
- refreshPeriod(0),
- daemon(false),
- noWeb(false),
- reconnect(false),
- showPid(false),
- confFile("/etc/sgauth.conf")
-{
-}
-//-----------------------------------------------------------------------------
-int SETTINGS_IMPL::ReadSettings()
-{
-CONFIGFILE cf(confFile);
-
-if (cf.Error())
- {
- strError = "Cannot read file '" + confFile + "'";
- return -1;
- }
-
-cf.ReadString("Login", &login, "/?--?--?*");
-if (login == "/?--?--?*")
- {
- strError = "Parameter 'Login' not found.";
- return -1;
- }
-
-cf.ReadString("Password", &password, "/?--?--?*");
-if (login == "/?--?--?*")
- {
- strError = "Parameter 'Password' not found.";
- return -1;
- }
-
-cf.ReadString("ServerName", &serverName, "?*?*?");
-if (serverName == "?*?*?")
- {
- strError = "Parameter 'ServerName' not found.";
- return -1;
- }
-
-std::string temp;
-cf.ReadString("ListenWebIP", &temp, "127.0.0.1");
-listenWebIP = inet_strington(temp);
-if (listenWebIP == 0)
- {
- strError = "Parameter 'ListenWebIP' is not valid.";
- return -1;
- }
-
-cf.ReadString("ServerPort", &temp, "5555");
-if (ParseIntInRange(temp, 1, 65535, &port))
- {
- strError = "Parameter 'ServerPort' is not valid.";
- return -1;
- }
-
-cf.ReadString("LocalName", &localName, "");
-
-cf.ReadString("LocalPort", &temp, "0");
-if (ParseIntInRange(temp, 0, 65535, &localPort))
- {
- strError = "Parameter 'LocalPort' is not valid.";
- return -1;
- }
-
-cf.ReadString("RefreshPeriod", &temp, "5");
-if (ParseIntInRange(temp, 1, 24*3600, &refreshPeriod))
- {
- strError = "Parameter 'RefreshPeriod' is not valid.";
- return -1;
- }
-
-cf.ReadString("Reconnect", &temp, "yes");
-if (ParseYesNo(temp, &reconnect))
- {
- strError = "Parameter 'Reconnect' is not valid.";
- return -1;
- }
-
-cf.ReadString("Daemon", &temp, "yes");
-if (ParseYesNo(temp, &daemon))
- {
- strError = "Parameter 'Daemon' is not valid.";
- return -1;
- }
-
-cf.ReadString("ShowPid", &temp, "no");
-if (ParseYesNo(temp, &showPid))
- {
- strError = "Parameter 'ShowPid' is not valid.";
- return -1;
- }
-
-cf.ReadString("DisableWeb", &temp, "no");
-if (ParseYesNo(temp, &noWeb))
- {
- strError = "Parameter 'DisableWeb' is not valid.";
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void SETTINGS_IMPL::Print() const
-{
-std::cout << "Login = " << login << "\n"
- << "Password = " << password << "\n"
- << "Ip = " << serverName << "\n"
- << "Port = " << port << "\n"
- << "LocalPort = " << localPort << "\n"
- << "ListenWebIP = " << inet_ntostring(listenWebIP) << "\n"
- << "RefreshPeriod = " << refreshPeriod << "\n"
- << "Daemon = " << daemon << "\n"
- << "DisableWeb = " << noWeb << "\n"
- << "Reconnect = " << reconnect << "\n"
- << "ShowPid = " << showPid << std::endl;
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#ifndef SETTINGS_IMPL_H
-#define SETTINGS_IMPL_H
-
-#include <string>
-#include <cstdint>
-
-class SETTINGS_IMPL {
-public:
- SETTINGS_IMPL();
- ~SETTINGS_IMPL() {}
- int Reload() { return 0; }
- void SetConfFile(const std::string & cf) { confFile = cf; }
- int ReadSettings();
-
- const std::string & GetStrError() const { return strError; }
-
- const std::string & GetServerName() const { return serverName; }
- uint16_t GetServerPort() const { return port; }
- const std::string & GetLocalName() const { return localName; }
- uint16_t GetLocalPort() const { return localPort; }
-
- const std::string & GetLogin() const { return login; }
- const std::string & GetPassword() const { return password; }
-
- bool GetDaemon() const { return daemon; }
- bool GetShowPid() const { return showPid; }
- bool GetNoWeb() const { return noWeb; }
- bool GetReconnect() const { return reconnect; }
- int GetRefreshPeriod() const { return refreshPeriod; }
- uint32_t GetListenWebIP() const { return listenWebIP; }
-
- void Print() const;
-
-private:
- std::string login;
- std::string password;
- std::string serverName;
- int port;
- std::string localName;
- int localPort;
- uint32_t listenWebIP;
- int refreshPeriod;
-
- bool daemon;
- bool noWeb;
- bool reconnect;
- bool showPid;
-
- std::string confFile;
- std::string strError;
-};
-
-#endif
+++ /dev/null
-################################################################################
-# Sgauth Configuration file #
-################################################################################
-
-# Stargazer server
-# Parameter: required
-# Values: IP address or DNS name
-# Default:
-ServerName = 192.168.1.2
-
-# Port on which Stargazer interacts with sgauth
-# Parameter: optional
-# Value: 1 ... 65535
-# Default: 5555
-ServerPort = 5555
-
-# User's login in Stargazer
-# Parameter: required
-# Value: any
-# Default:
-Login = test
-
-# Local host to bind
-# Parameter: optional
-# Values: IP address or DNS name
-# Default: 0.0.0.0
-LocalName = localhost
-
-# Port on which sgauth interacts with Stargazer
-# Parameter: optional
-# Value: 1 ... 65535
-# Default: 0
-LocalPort = 12345
-
-# User's password in Stargazer
-# Parameter: required
-# Value: any
-# Default:
-Password = 123456
-
-# Defines whether sgauth should try to reestablish connection to Stargazer
-# if it was lost
-# Parameter: optional
-# Value: yes, no
-# Default: yes
-Reconnect = yes
-
-# Defines whether sgauth should run as daemon
-# Parameter: optional
-# Value: yes, no
-# Default: yes
-Daemon = yes
-
-# Web-page refresh period in built-in webserver
-# Parameter: optional
-# Value: any numeric (minutes)
-# Default: 10
-RefreshPeriod = 10
-
-# Defines whether sgauth should use built-in webserver
-# Parameter: optional
-# Value: yes, no
-# Default: no
-DisableWeb = no
-
-# Defines address on which sgauth's built-in webserver will listen
-# Parameter: optional
-# Value: IP address or DNS name
-# Default: 127.0.0.1
-ListenWebIP = 127.0.0.1
-
-# Defines whether sgauth should show its process ID
-# Parameter: optional
-# Value: yes, no
-# Default: no
-ShowPid = no
-
-################################################################################
+++ /dev/null
-H3
-{
-color: black;
-}
-
-body
-{
-background-color: silver;
-}
-
-#TraffTable
-{
-background-color: white;
-}
-
-#TraffTableCaptionRow
-{
-background-color: silver;
-}
-
-#TraffTableCaptionCellC,
-#TraffTableUMCellC,
-#TraffTableDMCellC,
-#TraffTableUSCellC,
-#TraffTableDSCellC
-{
-background-color: silver;
-}
-
-#TraffTableDMRow,
-#TraffTableDSRow
-{
-background-color: #f2f0cc;
-}
-
-#TraffTableUMRow,
-#TraffTableUSRow
-{
-background-color: white;
-}
-
-#ConnectionStateOnline
-{
-color: green;
-font-size: 20px
-}
-
-#ConnectionStateOffline
-{
-color: red;
-font-size: 20px
-}
-
-p
-{
-padding: 2px;
-margin: 0px;
-}
-
-#MessagesTable
-{
-background-color: white;
-}
-
-#MessagesTableRowC
-{
-background-color: silver;
-}
-
-
-#MessagesTableRow0,
-#MessagesTableRow2,
-#MessagesTableRow4,
-#MessagesTableRow6,
-#MessagesTableRow8
-{
-background-color: #f2f0cc;
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
- /*
- $Revision: 1.7 $
- $Date: 2010/03/15 12:58:17 $
- */
-
-#include <libintl.h>
-
-#include <csignal>
-#include <cstdio>
-#include <cstring>
-#include <ctime>
-
-#include "stg/common.h"
-#include "stg/ia.h"
-#include "web.h"
-
-extern WEB * web;
-extern IA_CLIENT_PROT * clnp;
-
-#define LISTEN_PORT (5580)
-
-#include "css.h"
-
-//---------------------------------------------------------------------------
-#ifndef WIN32
-void * RunWeb(void *)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-#else
-unsigned long WINAPI RunWeb(void *)
-{
-#endif
-while (1)
- web->Run();
-return NULL;
-}
-//---------------------------------------------------------------------------
-WEB::WEB()
- : res(0),
- listenSocket(0),
- outerSocket(0),
- refreshPeriod(0),
- listenWebAddr(0)
-{
-#ifdef WIN32
-res = WSAStartup(MAKEWORD(2,0), &wsaData);
-#endif
-
-for (int i = 0; i < DIR_NUM; i++)
- dirName[i] = "-";
-
-refreshPeriod = 5;
-
-memset(&ls, 0, sizeof(ls));
-}
-//---------------------------------------------------------------------------
-void WEB::Start()
-{
-#ifdef WIN32
-unsigned long pt;
-CreateThread(
- NULL, // pointer to thread security attributes
- 16384, // initial thread stack size, in bytes
- RunWeb, // pointer to thread function
- NULL, // argument for new thread
- 0, // CREATE_SUSPENDED, // creation flags
- &pt // pointer to returned thread identifier
- );
-#else
-pthread_create(&thread, NULL, RunWeb, NULL);
-#endif
-}
-//---------------------------------------------------------------------------
-void WEB::PrepareNet()
-{
-listenSocket = socket(PF_INET, SOCK_STREAM, 0);
-
-struct sockaddr_in listenAddr;
-listenAddr.sin_family = AF_INET;
-listenAddr.sin_port = htons(LISTEN_PORT);
-listenAddr.sin_addr.s_addr = listenWebAddr;
-
-#ifndef WIN32
-int lng = 1;
-if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
- {
- printf("Setsockopt Fail\n");
- printf(">>> Error %s\n", strerror(errno));
- }
-#else
-//??? TODO
-#endif
-
-
-res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
-
-if (res == -1)
- {
- printf("Bind failed.\n");
- exit(0);
- }
-
-res = listen(listenSocket, 0);
-if (res == -1)
- {
- printf("Listen failed.\n");
- exit(0);
- }
-}
-//---------------------------------------------------------------------------
-void WEB::SetRefreshPagePeriod(int p)
-{
-refreshPeriod = p;
-if (refreshPeriod <= 0 || refreshPeriod > 24*3600)
- refreshPeriod = 5;
-}
-//---------------------------------------------------------------------------
-void WEB::SetListenAddr(uint32_t ip)
-{
-listenWebAddr = ip;
-}
-//---------------------------------------------------------------------------
-void WEB::Run()
-{
-PrepareNet();
-char recvBuffer[4096];
-while (1)
- {
- struct sockaddr_in outerAddr;
-
- #ifndef WIN32
- socklen_t outerAddrLen = sizeof(outerAddr);
- #else
- int outerAddrLen = sizeof(outerAddr);
- #endif
-
- outerSocket = accept(listenSocket, (struct sockaddr*)&outerAddr, &outerAddrLen);
- if (outerSocket == -1)
- {
- printf(">>> Error %s\n", strerror(errno));
- continue;
- }
- recv(outerSocket, recvBuffer, sizeof(recvBuffer), 0);
-
- if (strncmp(recvBuffer, "GET /sgauth.css", strlen("GET /sgauth.css")) == 0)
- {
- SendCSS();
- //printf("(1) recvBuffer=%s\n", recvBuffer);
- }
- else if (strncmp(recvBuffer, "GET /disconnect", strlen("GET /disconnect")) == 0)
- {
- clnp->Disconnect();
- Redirect("/");
- //printf("(2) recvBuffer=%s\n", recvBuffer);
- }
- else if (strncmp(recvBuffer, "GET /connect", strlen("GET /connect")) == 0)
- {
- clnp->Connect();
- Redirect("/");
- //printf("(3) recvBuffer=%s\n", recvBuffer);
- }
- else if (strncmp(recvBuffer, "GET /exit", strlen("GET /exit")) == 0)
- {
- Redirect("/");
- clnp->Disconnect();
- #ifdef WIN32
- Sleep(1000);
- #else
- struct timespec ts = {1, 0};
- nanosleep(&ts, NULL);
- #endif
- exit(0);
- }
- else
- {
- SendReply();
- //printf("(4) recvBuffer=%s\n", recvBuffer);
- }
-
- #ifdef WIN32
- closesocket(outerSocket);
- #else
- close(outerSocket);
- #endif
- }
-}
-//---------------------------------------------------------------------------
-int WEB::Redirect(const char * url)
-{
-const char * redirect =
- "HTTP/1.0 200 OK\n"
- "Content-Type: text/html\n"
- "Connection: close"
- "\n\n"
- "<html>\n"
- "<head>\n"
- "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;%s\">\n"
- "</head>\n"
- "<body>\n"
- "</body></html>\n\n";
-
-char buff[2000];
-sprintf(buff, redirect, url);
-send(outerSocket, buff, strlen(buff), 0);
-
-return 0;
-}
-//---------------------------------------------------------------------------
-int WEB::SendReply()
-{
-int j, rowNum;
-
-const char * replyHeader =
- "HTTP/1.0 200 OK\n"
- "Content-Type: text/html\n"
- "Connection: close"
- "\n\n"
- "<html>\n"
- "<head>\n"
- "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">\n"
- "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">\n"
- "<title>sgauth</title>\n"
- "<link rel=\"Stylesheet\" href=\"sgauth.css\">"
- "</head>\n"
- "<body>\n"
- "<H3>Stargazer</H3><p>\n";
-
-const char * replyFooter = "</body></html>\n\n";
-
-char replyHeaderBuffer[2000];
-sprintf(replyHeaderBuffer, replyHeader, refreshPeriod);
-
-send(outerSocket, replyHeaderBuffer, strlen(replyHeaderBuffer), 0);
-
-char str[512];
-
-int st = clnp->GetAuthorized();
-
-sprintf(str, "<a href=\"connect\">%s</a><p>\n", gettext("Connect"));
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<a href=\"disconnect\">%s</a><p>\n", gettext("Disconnect"));
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<a href=\"/\">%s</a><p>\n", gettext("Refresh"));
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<a href=\"exit\">%s</a><p>\n", gettext("Exit"));
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<div id=\"%s\">%s</div><p>\n" , st ? "ConnectionStateOnline":"ConnectionStateOffline", st ? "Online":"Offline");
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<div id=\"Cash\">%s: %.3f</div><p>\n" , gettext("Cash"), ls.cash / 1000.0);
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<div id=\"Prepaid Traffic\">%s: %s</div><p>\n" ,
- gettext("PrepaidTraffic"),
- ls.freeMb[0] == 'C' ? ls.freeMb + 1 : ls.freeMb);
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str, "<TABLE id=\"TraffTable\">\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str, " <TR id=\"TraffTableCaptionRow\">\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str, " <TD id=\"TraffTableCaptionCellC\"> </TD>\n");
-res = send(outerSocket, str, strlen(str), 0);
-
-rowNum = 0;
-for (j = 0; j < DIR_NUM; j++)
- {
- if (dirName[j][0] == 0)
- continue;
- std::string s;
- KOIToWin(dirName[j], &s);// +++++++++ sigsegv ========== TODO too long dir name crashes sgauth
- sprintf(str, " <TD id=\"TraffTableCaptionCell%d\">%s</TD>\n", rowNum++, s.c_str());
- send(outerSocket, str, strlen(str), 0);
- }
-
-sprintf(str," </TR>\n");
-send(outerSocket, str, strlen(str), 0);
-
-sprintf(str," <TR id=\"TraffTableUMRow\">\n");
-send(outerSocket, str, strlen(str), 0);
-
-sprintf(str," <TD id=\"TraffTableUMCellC\">%s</TD>\n", gettext("Month Upload"));
-send(outerSocket, str, strlen(str), 0);
-
-rowNum = 0;
-for (j = 0; j < DIR_NUM; j++)
- {
- if (dirName[j][0] == 0)
- continue;
- sprintf(str," <TD id=\"TraffTableUMCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.mu[j], ST_F));
- res = send(outerSocket, str, strlen(str), 0);
- }
-
-sprintf(str," </TR>\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str," <TR id=\"TraffTableDMRow\">\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str," <TD id=\"TraffTableDMCellC\">%s</TD>\n", gettext("Month Download"));
-res = send(outerSocket, str, strlen(str), 0);
-
-rowNum = 0;
-for (j = 0; j < DIR_NUM; j++)
- {
- if (dirName[j][0] == 0)
- continue;
- sprintf(str," <TD id=\"TraffTableDMCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.md[j], ST_F));
- res = send(outerSocket, str, strlen(str), 0);
- }
-sprintf(str," </TR>\n");
-res = send(outerSocket, str, strlen(str), 0);
-
-
-sprintf(str," <TR id=\"TraffTableUSRow\">\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str," <TD id=\"TraffTableUSCellC\">%s</TD>\n", gettext("Session Upload"));
-res = send(outerSocket, str, strlen(str), 0);
-
-rowNum = 0;
-for (j = 0; j < DIR_NUM; j++)
- {
- if (dirName[j][0] == 0)
- continue;
- sprintf(str," <TD id=\"TraffTableUSCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.su[j], ST_F));
- res = send(outerSocket, str, strlen(str), 0);
- }
-
-sprintf(str," </TR>\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str," <TR id=\"TraffTableDSRow\">\n");
-res = send(outerSocket, str, strlen(str), 0);
-sprintf(str," <TD id=\"TraffTableDSCellC\">%s</TD>\n", gettext("Session Download"));
-res = send(outerSocket, str, strlen(str), 0);
-
-for (j = 0; j < DIR_NUM; j++)
- {
- if (dirName[j][0] == 0)
- continue;
- sprintf(str," <TD id=\"TraffTableDSCell%d\">%s</TD>\n", j, IntToKMG(ls.sd[j], ST_F));
- res = send(outerSocket, str, strlen(str), 0);
- }
-
-sprintf(str," </TR>\n");
-res = send(outerSocket, str, strlen(str), 0);
-
-sprintf(str,"</TABLE>\n");
-res = send(outerSocket, str, strlen(str), 0);
-
-rowNum = 0;
-if (!messages.empty())
- {
- sprintf(str," <TABLE id=\"MessagesTable\">\n");
- res = send(outerSocket, str, strlen(str), 0);
-
- sprintf(str," <TR id=\"MessagesTableRowC\">\n");
- send(outerSocket, str, strlen(str), 0);
- sprintf(str," <TD>Date</TD>\n");
- send(outerSocket, str, strlen(str), 0);
- sprintf(str," <TD>Text</TD>\n");
- send(outerSocket, str, strlen(str), 0);
- sprintf(str," </TR>\n");
- send(outerSocket, str, strlen(str), 0);
-
- std::list<STG_MESSAGE>::reverse_iterator it;
- it = messages.rbegin();
- while (it != messages.rend())
- {
- sprintf(str," <TR id=\"MessagesTableRow%d\">\n", rowNum);
- send(outerSocket, str, strlen(str), 0);
- sprintf(str," <TD>%s</TD>\n", it->recvTime.c_str());
- send(outerSocket, str, strlen(str), 0);
- sprintf(str," <TD>%s</TD>\n", it->msg.c_str());
- send(outerSocket, str, strlen(str), 0);
- sprintf(str," </TR>\n");
- send(outerSocket, str, strlen(str), 0);
- ++it;
- ++rowNum;
- }
-
- sprintf(str," </TABLE>\n");
- res = send(outerSocket, str, strlen(str), 0);
- }
-
-time_t t = time(NULL);
-sprintf(str,"Îáíîâëåíî: %s</b>" , ctime(&t));
-res = send(outerSocket, str, strlen(str), 0);
-
-send(outerSocket, replyFooter, strlen(replyFooter), 0);
-
-return 0;
-}
-//---------------------------------------------------------------------------
-int WEB::SendCSS()
-{
-const char * replyHeader =
- "HTTP/1.0 200 OK\n"
- "Content-Type: text/css\n"
- "Connection: close\n\n";
-
-const char * replyFooter= "\n\n";
-
-send(outerSocket, replyHeader, strlen(replyHeader), 0);
-send(outerSocket, SGAuth::css, strlen(SGAuth::css), 0);
-send(outerSocket, replyFooter, strlen(replyFooter), 0);
-
-return 0;
-}
-//---------------------------------------------------------------------------
-void WEB::SetDirName(const std::string & dn, int n)
-{
-web->dirName[n] = dn;
-}
-//---------------------------------------------------------------------------
-void WEB::AddMessage(const std::string & message, int type)
-{
-time_t t = time(NULL);
-STG_MESSAGE m;
-
-m.msg = message;
-m.type = type;
-m.recvTime = ctime(&t);
-
-messages.push_back(m);
-
-if (messages.size() > MAX_MESSAGES)
- messages.pop_front();
-
-}
-//---------------------------------------------------------------------------
-void WEB::UpdateStat(const LOADSTAT & ls)
-{
-memcpy((void*)&(WEB::ls), &ls, sizeof(LOADSTAT));
-}
-//---------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
- /*
- $Revision: 1.3 $
- $Date: 2007/12/17 08:39:08 $
- */
-
-#ifndef WIN32
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#else
-#include <winsock2.h>
-#endif
-
-#include <string>
-#include <list>
-
-#include "stg/const.h"
-#include "stg/ia_packets.h"
-
-#define MAX_MESSAGES (10)
-//-----------------------------------------------------------------------------
-struct STG_MESSAGE
-{
-std::string msg;
-std::string recvTime;
-int type;
-};
-//-----------------------------------------------------------------------------
-class WEB
-{
-public:
- WEB();
- void Run();
- void SetDirName(const std::string & dn, int n);
- void SetRefreshPagePeriod(int p);
- void SetListenAddr(uint32_t ip);
- void AddMessage(const std::string & message, int type);
- void UpdateStat(const LOADSTAT & ls);
- void Start();
-private:
- void PrepareNet();
- int SendReply();
- int SendCSS();
- int Redirect(const char * url);
-
- #ifdef WIN32
- WSADATA wsaData;
- #else
- pthread_t thread;
- #endif
-
- std::string dirName[DIR_NUM];
- int res;
- int listenSocket;
- int outerSocket;
- int refreshPeriod;
-
- uint32_t listenWebAddr;
- LOADSTAT ls;
-
- std::list<STG_MESSAGE> messages;
-};
-//-----------------------------------------------------------------------------
+++ /dev/null
-find_package ( EXPAT REQUIRED )
-
-set ( CPP_FILES main.cpp options.cpp api_action.cpp actions.cpp admins.cpp tariffs.cpp users.cpp services.cpp corps.cpp info.cpp xml.cpp )
-
-set ( THREADS_PREFER_PTHREAD_FLAG ON )
-find_package ( Threads REQUIRED )
-
-add_executable ( sgconf ${CPP_FILES} )
-
-target_link_libraries ( sgconf srvconf crypto common EXPAT::EXPAT )
-
-# TODO: install
+++ /dev/null
-Compiling:
-> ./build
-
-
+++ /dev/null
-1. No default value for server.
-2. No default value for port.
+++ /dev/null
-/*
- * 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>
- */
-
-#ifndef __STG_SGCONF_ACTION_H__
-#define __STG_SGCONF_ACTION_H__
-
-#include <string>
-#include <map>
-#include <stdexcept>
-
-namespace SGCONF
-{
-
-class OPTION_BLOCK;
-struct PARSER_STATE;
-struct CONFIG;
-
-class ACTION
-{
- public:
- virtual ~ACTION() {}
-
- virtual ACTION * Clone() const = 0;
- virtual std::string ParamDescription() const = 0;
- virtual std::string DefaultDescription() const = 0;
- virtual OPTION_BLOCK & Suboptions() = 0;
- virtual PARSER_STATE Parse(int argc, char ** argv, void * data = NULL) = 0;
- virtual void ParseValue(const std::string &) {}
-
- class ERROR : public std::runtime_error
- {
- public:
- ERROR(const std::string & message)
- : std::runtime_error(message.c_str()) {}
- };
-};
-
-} // namespace SGCONF
-
-#endif
+++ /dev/null
-/*
- * 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>
- */
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "action.h"
-#include "options.h"
-#include "parser_state.h"
-
-#include "stg/common.h"
-#include "stg/optional.h"
-
-#include <string>
-
-#include <cassert>
-
-namespace SGCONF
-{
-
-typedef void (* FUNC0)();
-
-template <typename F>
-class FUNC0_ACTION : public ACTION
-{
- public:
- FUNC0_ACTION(const F & func) : m_func(func) {}
-
- virtual ACTION * Clone() const { return new FUNC0_ACTION<F>(*this); }
-
- virtual std::string ParamDescription() const { return ""; }
- virtual std::string DefaultDescription() const { return ""; }
- virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
- virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/)
- {
- m_func();
- return PARSER_STATE(true, argc, argv);
- }
-
- private:
- F m_func;
- OPTION_BLOCK m_suboptions;
-};
-
-template <typename F>
-inline
-FUNC0_ACTION<F> * MakeFunc0Action(F func)
-{
-return new FUNC0_ACTION<F>(func);
-}
-
-template <typename T>
-class PARAM_ACTION : public ACTION
-{
- public:
- PARAM_ACTION(STG::Optional<T> & param,
- const T & defaultValue,
- const std::string & paramDescription)
- : m_param(param),
- m_defaltValue(defaultValue),
- m_description(paramDescription),
- m_hasDefault(true)
- {}
- PARAM_ACTION(STG::Optional<T> & param)
- : m_param(param),
- m_hasDefault(false)
- {}
- PARAM_ACTION(STG::Optional<T> & param,
- const std::string & paramDescription)
- : m_param(param),
- m_description(paramDescription),
- m_hasDefault(false)
- {}
-
- virtual ACTION * Clone() const { return new PARAM_ACTION<T>(*this); }
-
- virtual std::string ParamDescription() const { return m_description; }
- virtual std::string DefaultDescription() const;
- virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
- virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
- virtual void ParseValue(const std::string & value);
-
- private:
- STG::Optional<T> & m_param;
- T m_defaltValue;
- std::string m_description;
- bool m_hasDefault;
- OPTION_BLOCK m_suboptions;
-};
-
-template <typename T>
-inline
-std::string PARAM_ACTION<T>::DefaultDescription() const
-{
-return m_hasDefault ? " (default: '" + std::to_string(m_defaltValue) + "')"
- : "";
-}
-
-template <>
-inline
-std::string PARAM_ACTION<std::string>::DefaultDescription() const
-{
-return m_hasDefault ? " (default: '" + m_defaltValue + "')"
- : "";
-}
-
-template <typename T>
-inline
-PARSER_STATE PARAM_ACTION<T>::Parse(int argc, char ** argv, void * /*data*/)
-{
-if (argc == 0 ||
- argv == NULL ||
- *argv == NULL)
- throw ERROR("Missing argument.");
-T value;
-if (str2x(*argv, value))
- throw ERROR(std::string("Bad argument: '") + *argv + "'");
-m_param = value;
-return PARSER_STATE(false, --argc, ++argv);
-}
-
-template <>
-inline
-PARSER_STATE PARAM_ACTION<bool>::Parse(int argc, char ** argv, void * /*data*/)
-{
-m_param = true;
-return PARSER_STATE(false, argc, argv);
-}
-
-template <typename T>
-inline
-void PARAM_ACTION<T>::ParseValue(const std::string & stringValue)
-{
-if (stringValue.empty())
- throw ERROR("Missing value.");
-T value;
-if (str2x(stringValue, value))
- throw ERROR(std::string("Bad value: '") + stringValue + "'");
-m_param = value;
-}
-
-template <>
-inline
-void PARAM_ACTION<std::string>::ParseValue(const std::string & stringValue)
-{
-m_param = stringValue;
-}
-
-template <>
-inline
-PARSER_STATE PARAM_ACTION<std::string>::Parse(int argc, char ** argv, void * /*data*/)
-{
-if (argc == 0 ||
- argv == NULL ||
- *argv == NULL)
- throw ERROR("Missing argument.");
-m_param = *argv;
-return PARSER_STATE(false, --argc, ++argv);
-}
-
-template <typename T>
-inline
-PARAM_ACTION<T> * MakeParamAction(STG::Optional<T> & param,
- const T & defaultValue,
- const std::string & paramDescription)
-{
-return new PARAM_ACTION<T>(param, defaultValue, paramDescription);
-}
-
-template <typename T>
-inline
-PARAM_ACTION<T> * MakeParamAction(STG::Optional<T> & param)
-{
-return new PARAM_ACTION<T>(param);
-}
-
-template <typename T>
-inline
-PARAM_ACTION<T> * MakeParamAction(STG::Optional<T> & param,
- const std::string & paramDescription)
-{
-return new PARAM_ACTION<T>(param, paramDescription);
-}
-
-class KV_ACTION : public ACTION
-{
- public:
- KV_ACTION(const std::string & name,
- const std::string & paramDescription)
- : m_name(name),
- m_description(paramDescription)
- {}
-
- virtual ACTION * Clone() const { return new KV_ACTION(*this); }
-
- virtual std::string ParamDescription() const { return m_description; }
- virtual std::string DefaultDescription() const { return ""; }
- virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
- virtual PARSER_STATE Parse(int argc, char ** argv, void * data);
-
- private:
- std::string m_name;
- std::string m_description;
- OPTION_BLOCK m_suboptions;
-};
-
-inline
-PARSER_STATE KV_ACTION::Parse(int argc, char ** argv, void * data)
-{
-if (argc == 0 ||
- argv == NULL ||
- *argv == NULL)
- throw ERROR("Missing argument.");
-assert(data != NULL && "Expecting container pointer.");
-std::map<std::string, std::string> & kvs = *static_cast<std::map<std::string, std::string>*>(data);
-kvs[m_name] = *argv;
-return PARSER_STATE(false, --argc, ++argv);
-}
-
-inline
-KV_ACTION * MakeKVAction(const std::string & name,
- const std::string & paramDescription)
-{
-return new KV_ACTION(name, paramDescription);
-}
-
-} // namespace SGCONF
+++ /dev/null
-#include "admins.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-#include "utils.h"
-
-#include "stg/servconf.h"
-#include "stg/servconf_types.h"
-#include "stg/admin_conf.h"
-
-#include <iostream>
-#include <string>
-#include <map>
-#include <cstdint>
-#include <cassert>
-
-namespace
-{
-
-std::string Indent(size_t level, bool dash = false)
-{
-if (level == 0)
- return "";
-return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
-}
-
-std::string PrivToString(const STG::Priv& priv)
-{
-return std::string("") +
- (priv.corpChg ? "1" : "0") +
- (priv.serviceChg ? "1" : "0") +
- (priv.tariffChg ? "1" : "0") +
- (priv.adminChg ? "1" : "0") +
- (priv.userAddDel ? "1" : "0") +
- (priv.userPasswd ? "1" : "0") +
- (priv.userCash ? "1" : "0") +
- (priv.userConf ? "1" : "0") +
- (priv.userStat ? "1" : "0");
-}
-
-void PrintAdmin(const STG::GetAdmin::Info & info, size_t level = 0)
-{
-std::cout << Indent(level, true) << "login: " << info.login << "\n"
- << Indent(level) << "priviledges: " << PrivToString(info.priv) << "\n";
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetAdminParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "password"));
-params.push_back(SGCONF::API_ACTION::PARAM("priv", "<priv>", "priviledges"));
-return params;
-}
-
-void ConvPriv(const std::string & value, STG::Optional<STG::Priv> & res)
-{
-if (value.length() != 9)
- throw SGCONF::ACTION::ERROR("Priviledges value should be a 9-digits length binary number.");
-STG::Priv priv;
-priv.corpChg = (value[0] == '0' ? 0 : 1);
-priv.serviceChg = (value[1] == '0' ? 0 : 1);
-priv.tariffChg = (value[2] == '0' ? 0 : 1);
-priv.adminChg = (value[3] == '0' ? 0 : 1);
-priv.userAddDel = (value[4] == '0' ? 0 : 1);
-priv.userPasswd = (value[5] == '0' ? 0 : 1);
-priv.userCash = (value[6] == '0' ? 0 : 1);
-priv.userConf = (value[7] == '0' ? 0 : 1);
-priv.userStat = (value[8] == '0' ? 0 : 1);
-res = priv;
-}
-
-void SimpleCallback(bool result,
- const std::string & reason,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Success.\n";
-}
-
-void GetAdminsCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetAdmin::Info> & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get admin list. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Admins:\n";
-for (size_t i = 0; i < info.size(); ++i)
- PrintAdmin(info[i], 1);
-}
-
-void GetAdminCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetAdmin::Info> & info,
- void * data)
-{
-assert(data != NULL && "Expecting pointer to std::string with the admin's login.");
-const std::string & login = *static_cast<const std::string *>(data);
-if (!result)
- {
- std::cerr << "Failed to get admin. Reason: '" << reason << "'." << std::endl;
- return;
- }
-for (size_t i = 0; i < info.size(); ++i)
- if (info[i].login == login)
- PrintAdmin(info[i]);
-}
-
-
-bool GetAdminsFunction(const SGCONF::CONFIG & config,
- const std::string & /*arg*/,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetAdmins(GetAdminsCallback, NULL) == STG::st_ok;
-}
-
-bool GetAdminFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-// STG currently doesn't support <GetAdmin login="..."/>.
-// So get a list of admins and filter it. 'data' param holds a pointer to 'login'.
-std::string login(arg);
-return proto.GetAdmins(GetAdminCallback, &login) == STG::st_ok;
-}
-
-bool DelAdminFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.DelAdmin(arg, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool AddAdminFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::AdminConfOpt conf;
-conf.login = arg;
-SGCONF::MaybeSet(options, "priv", conf.priv, ConvPriv);
-SGCONF::MaybeSet(options, "password", conf.password);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.AddAdmin(arg, conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool ChgAdminFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::AdminConfOpt conf;
-conf.login = arg;
-SGCONF::MaybeSet(options, "priv", conf.priv, ConvPriv);
-SGCONF::MaybeSet(options, "password", conf.password);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.ChgAdmin(conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-} // namespace anonymous
-
-void SGCONF::AppendAdminsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-std::vector<API_ACTION::PARAM> params(GetAdminParams());
-blocks.Add("Admin management options")
- .Add("get-admins", SGCONF::MakeAPIAction(commands, GetAdminsFunction), "\tget admin list")
- .Add("get-admin", SGCONF::MakeAPIAction(commands, "<login>", GetAdminFunction), "get admin")
- .Add("add-admin", SGCONF::MakeAPIAction(commands, "<login>", params, AddAdminFunction), "add admin")
- .Add("del-admin", SGCONF::MakeAPIAction(commands, "<login>", DelAdminFunction), "del admin")
- .Add("chg-admin", SGCONF::MakeAPIAction(commands, "<login>", params, ChgAdminFunction), "change admin");
-}
+++ /dev/null
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendAdminsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-} // namespace SGCONF
+++ /dev/null
-#include "api_action.h"
-
-#include "actions.h"
-#include "parser_state.h"
-
-SGCONF::PARSER_STATE SGCONF::API_ACTION::Parse(int argc, char ** argv, void * /*data*/)
-{
-PARSER_STATE state(false, argc, argv);
-if (!m_argument.empty())
- {
- if (argc == 0 ||
- argv == NULL ||
- *argv == NULL)
- throw ERROR("Missing argument.");
- m_argument = *argv;
- --state.argc;
- ++state.argv;
- }
-state = m_suboptions.Parse(state.argc, state.argv, &m_params);
-m_commands.Add(m_funPtr, m_argument, m_params);
-return state;
-}
-
-SGCONF::API_ACTION::API_ACTION(COMMANDS & commands,
- const std::string & paramDescription,
- bool needArgument,
- const std::vector<PARAM> & params,
- API_FUNCTION funPtr)
- : m_commands(commands),
- m_description(paramDescription),
- m_argument(needArgument ? "1" : ""), // Hack
- m_funPtr(funPtr)
-{
-std::vector<PARAM>::const_iterator it(params.begin());
-while (it != params.end())
- {
- m_suboptions.Add(it->name, MakeKVAction(it->name, it->shortDescr), it->longDescr);
- ++it;
- }
-}
+++ /dev/null
-#ifndef __STG_SGCONF_API_ACTION_H__
-#define __STG_SGCONF_API_ACTION_H__
-
-#include "action.h"
-
-#include "options.h"
-
-#include <string>
-#include <map>
-#include <vector>
-
-namespace SGCONF
-{
-
-typedef bool (* API_FUNCTION) (const CONFIG &,
- const std::string &,
- const std::map<std::string, std::string> &);
-
-class COMMAND
-{
- public:
- COMMAND(API_FUNCTION funPtr,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
- : m_funPtr(funPtr),
- m_arg(arg),
- m_options(options)
- {}
- bool Execute(const SGCONF::CONFIG & config) const
- {
- return m_funPtr(config, m_arg, m_options);
- }
-
- private:
- API_FUNCTION m_funPtr;
- std::string m_arg;
- std::map<std::string, std::string> m_options;
-};
-
-class COMMANDS
-{
- public:
- void Add(API_FUNCTION funPtr,
- const std::string & arg,
- const std::map<std::string, std::string> & options) { m_commands.push_back(COMMAND(funPtr, arg, options)); }
- bool Execute(const SGCONF::CONFIG & config) const
- {
- std::vector<COMMAND>::const_iterator it(m_commands.begin());
- bool res = true;
- while (it != m_commands.end() && res)
- {
- res = res && it->Execute(config);
- ++it;
- }
- return res;
- }
- private:
- std::vector<COMMAND> m_commands;
-};
-
-class API_ACTION : public ACTION
-{
- public:
- struct PARAM
- {
- PARAM(const std::string & n,
- const std::string & s,
- const std::string & l)
- : name(n),
- shortDescr(s),
- longDescr(l)
- {}
- std::string name;
- std::string shortDescr;
- std::string longDescr;
- };
-
- API_ACTION(COMMANDS & commands,
- const std::string & paramDescription,
- bool needArgument,
- const std::vector<PARAM> & params,
- API_FUNCTION funPtr);
- API_ACTION(COMMANDS & commands,
- const std::string & paramDescription,
- bool needArgument,
- API_FUNCTION funPtr)
- : m_commands(commands),
- m_description(paramDescription),
- m_argument(needArgument ? "1" : ""), // Hack
- m_funPtr(funPtr)
- {}
-
- virtual ACTION * Clone() const { return new API_ACTION(*this); }
-
- virtual std::string ParamDescription() const { return m_description; }
- virtual std::string DefaultDescription() const { return ""; }
- virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
- virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
-
- private:
- COMMANDS & m_commands;
- std::string m_description;
- std::string m_argument;
- OPTION_BLOCK m_suboptions;
- std::map<std::string, std::string> m_params;
- API_FUNCTION m_funPtr;
-};
-
-inline
-ACTION * MakeAPIAction(COMMANDS & commands,
- const std::string & paramDescription,
- const std::vector<API_ACTION::PARAM> & params,
- API_FUNCTION funPtr)
-{
-return new API_ACTION(commands, paramDescription, true, params, funPtr);
-}
-
-inline
-ACTION * MakeAPIAction(COMMANDS & commands,
- const std::vector<API_ACTION::PARAM> & params,
- API_FUNCTION funPtr)
-{
-return new API_ACTION(commands, "", false, params, funPtr);
-}
-
-inline
-ACTION * MakeAPIAction(COMMANDS & commands,
- const std::string & paramDescription,
- API_FUNCTION funPtr)
-{
-return new API_ACTION(commands, paramDescription, true, funPtr);
-}
-
-inline
-ACTION * MakeAPIAction(COMMANDS & commands,
- API_FUNCTION funPtr)
-{
-return new API_ACTION(commands, "", false, funPtr);
-}
-
-}
-
-#endif
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/common.h"
-#include "stg/optional.h"
-
-#include <string>
-#include <cstdint>
-
-namespace SGCONF
-{
-
-struct CONFIG
-{
- STG::Optional<std::string> configFile;
- STG::Optional<std::string> server;
- STG::Optional<uint16_t> port;
- STG::Optional<std::string> localAddress;
- STG::Optional<uint16_t> localPort;
- STG::Optional<std::string> userName;
- STG::Optional<std::string> userPass;
- STG::Optional<bool> showConfig;
-
- CONFIG & operator=(const CONFIG & rhs)
- {
- if (!rhs.configFile.empty())
- configFile = rhs.configFile;
- if (!rhs.server.empty())
- server = rhs.server;
- if (!rhs.port.empty())
- port = rhs.port;
- if (!rhs.localAddress.empty())
- localAddress = rhs.localAddress;
- if (!rhs.localPort.empty())
- localPort = rhs.localPort;
- if (!rhs.userName.empty())
- userName = rhs.userName;
- if (!rhs.userPass.empty())
- userPass = rhs.userPass;
- if (!rhs.showConfig.empty())
- showConfig = rhs.showConfig;
- return *this;
- }
-
- std::string Serialize() const
- {
- std::string res;
- if (!configFile.empty())
- res += "configFile: '" + configFile.data() + "'\n";
- if (!server.empty())
- res += "server: '" + server.data() + "'\n";
- if (!port.empty())
- res += "port: " + std::to_string(port.data()) + "\n";
- if (!localAddress.empty())
- res += "local address: '" + localAddress.data() + "'\n";
- if (!localPort.empty())
- res += "local port: " + std::to_string(localPort.data()) + "\n";
- if (!userName.empty())
- res += "userName: '" + userName.data() + "'\n";
- if (!userPass.empty())
- res += "userPass: '" + userPass.data() + "\n";
- return res;
- }
-};
-
-} // namespace SGCONF
+++ /dev/null
-#include "corps.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-#include "utils.h"
-
-#include "stg/servconf.h"
-#include "stg/servconf_types.h"
-#include "stg/corp_conf.h"
-#include "stg/common.h"
-
-#include <iostream>
-#include <string>
-#include <map>
-
-namespace
-{
-
-std::string Indent(size_t level, bool dash = false)
-{
-if (level == 0)
- return "";
-return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
-}
-
-void PrintCorp(const STG::GetCorp::Info & info, size_t level = 0)
-{
-std::cout << Indent(level, true) << "name: " << info.name << "\n"
- << Indent(level) << "cash: " << info.cash << "\n";
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetCorpParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("cash", "<cash>", "\tcorporation's cash"));
-return params;
-}
-
-void SimpleCallback(bool result,
- const std::string & reason,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Success.\n";
-}
-
-void GetCorpsCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetCorp::Info> & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get corp list. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Corps:\n";
-for (size_t i = 0; i < info.size(); ++i)
- PrintCorp(info[i], 1);
-}
-
-void GetCorpCallback(bool result,
- const std::string & reason,
- const STG::GetCorp::Info & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get corp. Reason: '" << reason << "'." << std::endl;
- return;
- }
-PrintCorp(info);
-}
-
-bool GetCorpsFunction(const SGCONF::CONFIG & config,
- const std::string & /*arg*/,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetCorporations(GetCorpsCallback, NULL) == STG::st_ok;
-}
-
-bool GetCorpFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetCorp(arg, GetCorpCallback, NULL) == STG::st_ok;
-}
-
-bool DelCorpFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.DelCorp(arg, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool AddCorpFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::CorpConfOpt conf;
-conf.name = arg;
-SGCONF::MaybeSet(options, "cash", conf.cash);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.AddCorp(arg, conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool ChgCorpFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::CorpConfOpt conf;
-conf.name = arg;
-SGCONF::MaybeSet(options, "cash", conf.cash);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.ChgCorp(conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-} // namespace anonymous
-
-void SGCONF::AppendCorpsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-std::vector<API_ACTION::PARAM> params(GetCorpParams());
-blocks.Add("Corporation management options")
- .Add("get-corps", SGCONF::MakeAPIAction(commands, GetCorpsFunction), "\tget corporation list")
- .Add("get-corp", SGCONF::MakeAPIAction(commands, "<name>", GetCorpFunction), "get corporation")
- .Add("add-corp", SGCONF::MakeAPIAction(commands, "<name>", params, AddCorpFunction), "add corporation")
- .Add("del-corp", SGCONF::MakeAPIAction(commands, "<name>", DelCorpFunction), "delete corporation")
- .Add("chg-corp", SGCONF::MakeAPIAction(commands, "<name>", params, ChgCorpFunction), "change corporation");
-}
+++ /dev/null
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendCorpsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-} // namespace SGCONF
+++ /dev/null
-#include "info.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-
-#include "stg/servconf.h"
-
-#include <iostream>
-#include <string>
-#include <map>
-
-#include <expat.h>
-
-namespace
-{
-
-void PrintInfo(const STG::ServerInfo::Info& info)
-{
- std::cout << "Server version: '" << info.version << "'\n"
- << "Number of tariffs: " << info.tariffNum << "\n"
- << "Tariff subsystem version: " << info.tariffType << "\n"
- << "Number of users: " << info.usersNum << "\n"
- << "UName: '" << info.uname << "\n"
- << "Number of directions: " << info.dirNum << "\n"
- << "Dirs:\n";
- for (size_t i = 0; i < info.dirName.size(); ++i)
- std::cout << "\t - '" << info.dirName[i] << "'\n";
-}
-
-void InfoCallback(bool result, const std::string & reason, const STG::ServerInfo::Info & info, void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get server info. Reason: '" << reason << "'." << std::endl;
- return;
- }
-PrintInfo(info);
-}
-
-bool InfoFunction(const SGCONF::CONFIG & config,
- const std::string& /*arg*/,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.ServerInfo(InfoCallback, NULL) == STG::st_ok;
-}
-
-}
-
-void SGCONF::AppendServerInfoBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-blocks.Add("Server info")
- .Add("server-info", SGCONF::MakeAPIAction(commands, InfoFunction), "\tget server info");
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendServerInfoBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "xml.h"
-#include "admins.h"
-#include "tariffs.h"
-#include "users.h"
-#include "services.h"
-#include "corps.h"
-#include "info.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "actions.h"
-#include "config.h"
-
-#include <string>
-#include <iostream>
-
-#include <cstdlib> // getenv
-#include <cstring> // str*
-
-#include <unistd.h> // access
-#include <libgen.h> // basename
-
-namespace
-{
-
-template <typename T>
-struct nullary_function
-{
-typedef T result_type;
-};
-
-template <typename F>
-class binder0 : public nullary_function<typename F::result_type>
-{
- public:
- binder0(const F & func, const typename F::argument_type & arg)
- : m_func(func), m_arg(arg) {}
- typename F::result_type operator()() const { return m_func(m_arg); }
- private:
- F m_func;
- typename F::argument_type m_arg;
-};
-
-template <typename F>
-inline
-binder0<F> bind0(const F & func, const typename F::argument_type & arg)
-{
-return binder0<F>(func, arg);
-}
-
-template <typename A, typename R>
-class FUNC1_ADAPTER : public std::unary_function<A, R>
-{
- public:
- FUNC1_ADAPTER(R (*func)(A)) : m_func(func) {}
- const R operator()(A arg) const { return (m_func)(arg); }
- private:
- R (*m_func)(A);
-};
-
-template <typename C, typename A, typename R>
-class METHOD1_ADAPTER : public std::unary_function<A, R>
-{
- public:
- METHOD1_ADAPTER(R (C::* func)(A), C & obj) : m_func(func), m_obj(obj) {}
- R operator()(A arg) { return (m_obj.*m_func)(arg); }
- private:
- R (C::* m_func)(A);
- C & m_obj;
-};
-
-template <typename C, typename A, typename R>
-class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
-{
- public:
- CONST_METHOD1_ADAPTER(R (C::* func)(A) const, C & obj) : m_func(func), m_obj(obj) {}
- R operator()(A arg) const { return (m_obj.*m_func)(arg); }
- private:
- R (C::* m_func)(A) const;
- C & m_obj;
-};
-
-template <typename A, typename R>
-FUNC1_ADAPTER<A, R> Func1Adapt(R (func)(A))
-{
-return FUNC1_ADAPTER<A, R>(func);
-}
-
-template <typename C, typename A, typename R>
-METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
-{
-return METHOD1_ADAPTER<C, A, R>(func, obj);
-}
-
-template <typename C, typename A, typename R>
-CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
-{
-return CONST_METHOD1_ADAPTER<C, A, R>(func, obj);
-}
-
-void Version(const std::string & self)
-{
-std::cout << self << ", version: 2.0.0.\n";
-}
-
-void ReadUserConfigFile(SGCONF::OPTION_BLOCK & block)
-{
-std::vector<std::string> paths;
-const char * configHome = getenv("XDG_CONFIG_HOME");
-if (configHome == NULL)
- {
- const char * home = getenv("HOME");
- if (home == NULL)
- return;
- paths.push_back(std::string(home) + "/.config/sgconf/sgconf.conf");
- paths.push_back(std::string(home) + "/.sgconf/sgconf.conf");
- }
-else
- paths.push_back(std::string(configHome) + "/sgconf/sgconf.conf");
-for (std::vector<std::string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
- if (access(it->c_str(), R_OK) == 0)
- {
- block.ParseFile(*it);
- return;
- }
-}
-
-} // namespace anonymous
-
-namespace SGCONF
-{
-
-class CONFIG_ACTION : public ACTION
-{
- public:
- CONFIG_ACTION(SGCONF::CONFIG & config,
- const std::string & paramDescription)
- : m_config(config),
- m_description(paramDescription)
- {}
-
- virtual ACTION * Clone() const { return new CONFIG_ACTION(*this); }
-
- virtual std::string ParamDescription() const { return m_description; }
- virtual std::string DefaultDescription() const { return ""; }
- virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
- virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
-
- private:
- SGCONF::CONFIG & m_config;
- std::string m_description;
- OPTION_BLOCK m_suboptions;
-
- void ParseCredentials(const std::string & credentials);
- void ParseHostAndPort(const std::string & hostAndPort);
-};
-
-
-PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv, void * /*data*/)
-{
-if (argc == 0 ||
- argv == NULL ||
- *argv == NULL)
- throw ERROR("Missing argument.");
-char * pos = strchr(*argv, '@');
-if (pos != NULL)
- {
- ParseCredentials(std::string(*argv, pos));
- ParseHostAndPort(std::string(pos + 1));
- }
-else
- {
- ParseHostAndPort(std::string(*argv));
- }
-return PARSER_STATE(false, --argc, ++argv);
-}
-
-void CONFIG_ACTION::ParseCredentials(const std::string & credentials)
-{
-std::string::size_type pos = credentials.find_first_of(':');
-if (pos != std::string::npos)
- {
- m_config.userName = credentials.substr(0, pos);
- m_config.userPass = credentials.substr(pos + 1);
- }
-else
- {
- m_config.userName = credentials;
- }
-}
-
-void CONFIG_ACTION::ParseHostAndPort(const std::string & hostAndPort)
-{
-std::string::size_type pos = hostAndPort.find_first_of(':');
-if (pos != std::string::npos)
- {
- m_config.server = hostAndPort.substr(0, pos);
- uint16_t port = 0;
- if (str2x(hostAndPort.substr(pos + 1), port))
- throw ERROR("Invalid port value: '" + hostAndPort.substr(pos + 1) + "'");
- m_config.port = port;
- }
-else
- {
- m_config.server = hostAndPort;
- }
-}
-
-inline
-CONFIG_ACTION * MakeParamAction(SGCONF::CONFIG & config,
- const std::string & paramDescription)
-{
-return new CONFIG_ACTION(config, paramDescription);
-}
-
-} // namespace SGCONF
-
-//-----------------------------------------------------------------------------
-int main(int argc, char **argv)
-{
-std::string self(basename(argv[0]));
-SGCONF::CONFIG config;
-SGCONF::COMMANDS commands;
-
-SGCONF::OPTION_BLOCKS blocks;
-blocks.Add("General options")
- .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), "<config file>"), "override default config file")
- .Add("h", "help", SGCONF::MakeFunc0Action(bind0(Method1Adapt(&SGCONF::OPTION_BLOCKS::Help, blocks), 0)), "\t\tshow this help and exit")
- //.Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "\t\tshow full help and exit")
- .Add("v", "version", SGCONF::MakeFunc0Action(bind0(Func1Adapt(Version), self)), "\t\tshow version information and exit");
-SGCONF::OPTION_BLOCK & block = blocks.Add("Connection options")
- .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "<address>"), "\t\thost to connect")
- .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "\t\tport to connect")
- .Add("local-address", SGCONF::MakeParamAction(config.localAddress, std::string(""), "<address>"), "\tlocal address to bind")
- .Add("local-port", SGCONF::MakeParamAction(config.localPort, uint16_t(0), "<port>"), "\t\tlocal port to bind")
- .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "\tadministrative login")
- .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "\tpassword for the administrative login")
- .Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
-blocks.Add("Debug options")
- .Add("show-config", SGCONF::MakeParamAction(config.showConfig), "\tshow config and exit");
-SGCONF::AppendXMLOptionBlock(commands, blocks);
-SGCONF::AppendServerInfoBlock(commands, blocks);
-SGCONF::AppendAdminsOptionBlock(commands, blocks);
-SGCONF::AppendTariffsOptionBlock(commands, blocks);
-SGCONF::AppendUsersOptionBlock(commands, blocks);
-SGCONF::AppendServicesOptionBlock(commands, blocks);
-SGCONF::AppendCorpsOptionBlock(commands, blocks);
-
-SGCONF::PARSER_STATE state(false, argc, argv);
-
-try
-{
-state = blocks.Parse(--argc, ++argv); // Skipping self name
-}
-catch (const SGCONF::OPTION::ERROR& ex)
-{
-std::cerr << ex.what() << "\n";
-return -1;
-}
-
-if (state.stop)
- return 0;
-
-if (state.argc > 0)
- {
- std::cerr << "Unknown option: '" << *state.argv << "'\n";
- return -1;
- }
-
-try
-{
-SGCONF::CONFIG configOverride(config);
-
-if (config.configFile.empty())
- {
- const char * mainConfigFile = "/etc/sgconf/sgconf.conf";
- if (access(mainConfigFile, R_OK) == 0)
- block.ParseFile(mainConfigFile);
- ReadUserConfigFile(block);
- }
-else
- {
- block.ParseFile(config.configFile.data());
- }
-
-config = configOverride;
-
-if (!config.showConfig.empty() && config.showConfig.data())
- {
- std::cout << config.Serialize() << std::endl;
- return 0;
- }
-return commands.Execute(config) ? 0 : -1;
-}
-catch (const std::exception& ex)
-{
-std::cerr << ex.what() << "\n";
-return -1;
-}
-}
-//-----------------------------------------------------------------------------
-
-namespace
-{
-
-/*void UsageTariffs(bool full)
-{
-std::cout << "Tariffs management options:\n"
- << "\t--get-tariffs\t\t\t\tget a list of tariffs (subsequent options will define what to show)\n";
-if (full)
- std::cout << "\t\t--name\t\t\t\tshow tariff's name\n"
- << "\t\t--fee\t\t\t\tshow tariff's fee\n"
- << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
- << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
- << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
- << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
-std::cout << "\t--get-tariff\t\t\t\tget the information about tariff\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the tariff to show\n"
- << "\t\t--fee\t\t\t\tshow tariff's fee\n"
- << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
- << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
- << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
- << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
-std::cout << "\t--add-tariff\t\t\t\tadd a new tariff\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the tariff to add\n"
- << "\t\t--fee <fee>\t\t\tstariff's fee\n"
- << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
- << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
- << "\t\t--traff-type <type>\t\twhat type of traffi will be accounted by the tariff\n"
- << "\t\t--times <times>\t\t\tslash-separated list of \"day\" time-spans (in form \"hh:mm-hh:mm\") for each direction\n"
- << "\t\t--prices-day-a <prices>\t\tslash-separated list of prices for \"day\" traffic before threshold for each direction\n"
- << "\t\t--prices-night-a <prices>\tslash-separated list of prices for \"night\" traffic before threshold for each direction\n"
- << "\t\t--prices-day-b <prices>\t\tslash-separated list of prices for \"day\" traffic after threshold for each direction\n"
- << "\t\t--prices-night-b <prices>\tslash-separated list of prices for \"night\" traffic after threshold for each direction\n"
- << "\t\t--single-prices <yes|no>\tslash-separated list of \"single price\" flags for each direction\n"
- << "\t\t--no-discounts <yes|no>\t\tslash-separated list of \"no discount\" flags for each direction\n"
- << "\t\t--thresholds <thresholds>\tslash-separated list of thresholds (in Mb) for each direction\n\n";
-std::cout << "\t--del-tariff\t\t\t\tdelete an existing tariff\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the tariff to delete\n\n";
-std::cout << "\t--chg-tariff\t\t\t\tchange an existing tariff\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the tariff to change\n"
- << "\t\t--fee <fee>\t\t\tstariff's fee\n"
- << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
- << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
- << "\t\t--traff-type <type>\t\twhat type of traffix will be accounted by the tariff\n"
- << "\t\t--dir <N>\t\t\tnumber of direction data to change\n"
- << "\t\t\t--time <time>\t\t\"day\" time-span (in form \"hh:mm-hh:mm\")\n"
- << "\t\t\t--price-day-a <price>\tprice for \"day\" traffic before threshold\n"
- << "\t\t\t--price-night-a <price>\tprice for \"night\" traffic before threshold\n"
- << "\t\t\t--price-day-b <price>\tprice for \"day\" traffic after threshold\n"
- << "\t\t\t--price-night-b <price>\tprice for \"night\" traffic after threshold\n"
- << "\t\t\t--single-price <yes|no>\t\"single price\" flag\n"
- << "\t\t\t--no-discount <yes|no>\t\"no discount\" flag\n"
- << "\t\t\t--threshold <threshold>\tthreshold (in Mb)\n\n";
-}
-//-----------------------------------------------------------------------------
-void UsageUsers(bool full)
-{
-std::cout << "Users management options:\n"
- << "\t--get-users\t\t\t\tget a list of users (subsequent options will define what to show)\n";
-if (full)
- std::cout << "\n\n";
-std::cout << "\t--get-user\t\t\t\tget the information about user\n";
-if (full)
- std::cout << "\n\n";
-std::cout << "\t--add-user\t\t\t\tadd a new user\n";
-if (full)
- std::cout << "\n\n";
-std::cout << "\t--del-user\t\t\t\tdelete an existing user\n";
-if (full)
- std::cout << "\n\n";
-std::cout << "\t--chg-user\t\t\t\tchange an existing user\n";
-if (full)
- std::cout << "\n\n";
-std::cout << "\t--check-user\t\t\t\tcheck credentials is valid\n";
-if (full)
- std::cout << "\n\n";
-std::cout << "\t--send-message\t\t\t\tsend a message to a user\n";
-if (full)
- std::cout << "\n\n";
-}
-//-----------------------------------------------------------------------------
-void UsageServices(bool full)
-{
-std::cout << "Services management options:\n"
- << "\t--get-services\t\t\t\tget a list of services (subsequent options will define what to show)\n";
-if (full)
- std::cout << "\t\t--name\t\t\t\tshow service's name\n"
- << "\t\t--comment\t\t\tshow a comment to the service\n"
- << "\t\t--cost\t\t\t\tshow service's cost\n"
- << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
-std::cout << "\t--get-service\t\t\t\tget the information about service\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the service to show\n"
- << "\t\t--comment\t\t\tshow a comment to the service\n"
- << "\t\t--cost\t\t\t\tshow service's cost\n"
- << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
-std::cout << "\t--add-service\t\t\t\tadd a new service\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the service to add\n"
- << "\t\t--comment <comment>\t\ta comment to the service\n"
- << "\t\t--cost <cost>\t\t\tservice's cost\n"
- << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
-std::cout << "\t--del-service\t\t\t\tdelete an existing service\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the service to delete\n\n";
-std::cout << "\t--chg-service\t\t\t\tchange an existing service\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the service to change\n"
- << "\t\t--comment <comment>\t\ta comment to the service\n"
- << "\t\t--cost <cost>\t\t\tservice's cost\n"
- << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
-}
-//-----------------------------------------------------------------------------
-void UsageCorporations(bool full)
-{
-std::cout << "Corporations management options:\n"
- << "\t--get-corporations\t\t\tget a list of corporations (subsequent options will define what to show)\n";
-if (full)
- std::cout << "\t\t--name\t\t\t\tshow corporation's name\n"
- << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
-std::cout << "\t--get-corp\t\t\t\tget the information about corporation\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the corporation to show\n"
- << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
-std::cout << "\t--add-corp\t\t\t\tadd a new corporation\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the corporation to add\n"
- << "\t\t--cash <cash>\t\t\tinitial corporation's cash (default: \"0\")\n\n";
-std::cout << "\t--del-corp\t\t\t\tdelete an existing corporation\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the corporation to delete\n\n";
-std::cout << "\t--chg-corp\t\t\t\tchange an existing corporation\n";
-if (full)
- std::cout << "\t\t--name <name>\t\t\tname of the corporation to change\n"
- << "\t\t--add-cash <amount>[:<message>]\tadd cash to the corporation's account and optional comment message\n"
- << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
-}*/
-
-} // namespace anonymous
+++ /dev/null
-/*
- * 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 "options.h"
-
-#include "action.h"
-#include "parser_state.h"
-
-#include "stg/common.h"
-
-#include <fstream>
-#include <sstream>
-#include <iostream>
-#include <functional>
-#include <algorithm>
-
-#include <unistd.h>
-
-namespace
-{
-
-template <class C>
-void ReadConfigFile(const std::string & filePath, void (C::* callback)(const std::string&, const std::string&), C * obj)
-{
-std::ifstream stream(filePath.c_str());
-std::string line;
-size_t num = 0;
-while (std::getline(stream, line))
- {
- ++num;
- line = Trim(line);
- std::string::size_type pos = line.find_first_of('#');
- if (pos != std::string::npos)
- line = line.substr(0, pos);
- if (line.empty())
- continue;
- pos = line.find_first_of('=');
- if (pos == std::string::npos)
- {
- std::ostringstream error;
- error << "Bad file format, missing '=' in '" << filePath << ":" << num << "'.";
- throw std::runtime_error(error.str().c_str());
- }
- (obj->*callback)(Trim(line.substr(0, pos)), Trim(line.substr(pos + 1, line.length() - pos - 1)));
- }
-}
-
-} // namespace anonymous
-
-using SGCONF::OPTION;
-using SGCONF::OPTION_BLOCK;
-using SGCONF::OPTION_BLOCKS;
-using SGCONF::ACTION;
-using SGCONF::PARSER_STATE;
-
-OPTION::OPTION(const std::string & shortName,
- const std::string & longName,
- ACTION * action,
- const std::string & description)
- : m_shortName(shortName),
- m_longName(longName),
- m_action(action),
- m_description(description)
-{
-}
-
-OPTION::OPTION(const std::string & longName,
- ACTION * action,
- const std::string & description)
- : m_longName(longName),
- m_action(action),
- m_description(description)
-{
-}
-
-OPTION::OPTION(const OPTION & rhs)
- : m_shortName(rhs.m_shortName),
- m_longName(rhs.m_longName),
- m_action(rhs.m_action->Clone()),
- m_description(rhs.m_description)
-{
-}
-
-OPTION::~OPTION()
-{
-delete m_action;
-}
-
-OPTION & OPTION::operator=(const OPTION & rhs)
-{
-m_shortName = rhs.m_shortName;
-m_longName = rhs.m_longName;
-m_action = rhs.m_action->Clone();
-m_description = rhs.m_description;
-return *this;
-}
-
-void OPTION::Help(size_t level) const
-{
-if (!m_action)
- throw ERROR("Option is not defined.");
-std::string indent(level, '\t');
-std::cout << indent;
-if (!m_shortName.empty())
- std::cout << "-" << m_shortName << ", ";
-std::cout << "--" << m_longName << " " << m_action->ParamDescription()
- << "\t" << m_description << m_action->DefaultDescription() << "\n";
-m_action->Suboptions().Help(level);
-}
-
-bool OPTION::Check(const char * arg) const
-{
-if (arg == NULL)
- return false;
-
-if (*arg++ != '-')
- return false;
-
-if (*arg == '-')
-{
- return m_longName == arg + 1;
-}
-
-return m_shortName == arg;
-}
-
-PARSER_STATE OPTION::Parse(int argc, char ** argv, void * data)
-{
-if (!m_action)
- throw ERROR("Option is not defined.");
-try
- {
- return m_action->Parse(argc, argv, data);
- }
-catch (const ACTION::ERROR & ex)
- {
- if (m_longName.empty())
- throw ERROR("-" + m_shortName + ": " + ex.what());
- else
- throw m_shortName.empty() ? ERROR("--" + m_longName + ": " + ex.what())
- : ERROR("--" + m_longName + ", -" + m_shortName + ": " + ex.what());
- }
-}
-
-void OPTION::ParseValue(const std::string & value)
-{
-if (!m_action)
- throw ERROR("Option is not defined.");
-try
- {
- return m_action->ParseValue(value);
- }
-catch (const ACTION::ERROR & ex)
- {
- throw ERROR(m_longName + ": " + ex.what());
- }
-}
-
-OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & shortName,
- const std::string & longName,
- ACTION * action,
- const std::string & description)
-{
-m_options.push_back(OPTION(shortName, longName, action, description));
-return *this;
-}
-
-OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & longName,
- ACTION * action,
- const std::string & description)
-{
-m_options.push_back(OPTION(longName, action, description));
-return *this;
-}
-
-void OPTION_BLOCK::Help(size_t level) const
-{
-if (m_options.empty())
- return;
-if (!m_description.empty())
- std::cout << m_description << ":\n";
-std::for_each(m_options.begin(),
- m_options.end(),
- [&level](const auto& opt){ opt.Help(level + 1); });
-}
-
-PARSER_STATE OPTION_BLOCK::Parse(int argc, char ** argv, void * data)
-{
-PARSER_STATE state(false, argc, argv);
-if (state.argc == 0)
- return state;
-while (state.argc > 0 && !state.stop)
- {
- const auto it = std::find_if(m_options.begin(), m_options.end(), [&state](const auto& opt){ return opt.Check(*state.argv); });
- if (it != m_options.end())
- state = it->Parse(--state.argc, ++state.argv, data);
- else
- break;
- }
-return state;
-}
-
-void OPTION_BLOCK::ParseFile(const std::string & filePath)
-{
-if (access(filePath.c_str(), R_OK))
- throw ERROR("File '" + filePath + "' does not exists.");
-ReadConfigFile(filePath, &OPTION_BLOCK::OptionCallback, this);
-}
-
-void OPTION_BLOCK::OptionCallback(const std::string & key, const std::string & value)
-{
-for (std::vector<OPTION>::iterator it = m_options.begin(); it != m_options.end(); ++it)
- if (it->Name() == key)
- it->ParseValue(value);
-}
-
-void OPTION_BLOCKS::Help(size_t level) const
-{
-std::list<OPTION_BLOCK>::const_iterator it(m_blocks.begin());
-while (it != m_blocks.end())
- {
- it->Help(level);
- std::cout << "\n";
- ++it;
- }
-}
-
-PARSER_STATE OPTION_BLOCKS::Parse(int argc, char ** argv)
-{
-PARSER_STATE state(false, argc, argv);
-std::list<OPTION_BLOCK>::iterator it(m_blocks.begin());
-while (state.argc > 0 && !state.stop && it != m_blocks.end())
- {
- state = it->Parse(state.argc, state.argv);
- ++it;
- }
-return state;
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#ifndef __STG_SGCONF_OPTIONS_H__
-#define __STG_SGCONF_OPTIONS_H__
-
-#include <string>
-#include <vector>
-#include <list>
-#include <utility>
-#include <stdexcept>
-#include <cstddef> // size_t
-
-namespace SGCONF
-{
-
-class ACTION;
-struct PARSER_STATE;
-
-class OPTION
-{
- public:
- OPTION(const std::string & shortName,
- const std::string & longName,
- ACTION * action,
- const std::string & description);
- OPTION(const std::string & longName,
- ACTION * action,
- const std::string & description);
- OPTION(const OPTION & rhs);
- ~OPTION();
-
- OPTION & operator=(const OPTION & rhs);
-
- void Help(size_t level = 0) const;
- PARSER_STATE Parse(int argc, char ** argv, void * data);
- void ParseValue(const std::string & value);
- bool Check(const char * arg) const;
- const std::string & Name() const { return m_longName; }
-
- class ERROR : public std::runtime_error
- {
- public:
- ERROR(const std::string & message)
- : std::runtime_error(message.c_str()) {}
- };
-
- private:
- std::string m_shortName;
- std::string m_longName;
- ACTION * m_action;
- std::string m_description;
-};
-
-class OPTION_BLOCK
-{
- public:
- OPTION_BLOCK() {}
- OPTION_BLOCK(const std::string & description)
- : m_description(description) {}
- OPTION_BLOCK & Add(const std::string & shortName,
- const std::string & longName,
- ACTION * action,
- const std::string & description);
- OPTION_BLOCK & Add(const std::string & longName,
- ACTION * action,
- const std::string & description);
-
- void Help(size_t level) const;
-
- PARSER_STATE Parse(int argc, char ** argv, void * data = NULL);
- void ParseFile(const std::string & filePath);
-
- class ERROR : public std::runtime_error
- {
- public:
- ERROR(const std::string & message)
- : std::runtime_error(message.c_str()) {}
- };
-
- private:
- std::vector<OPTION> m_options;
- std::string m_description;
-
- void OptionCallback(const std::string & key, const std::string & value);
-};
-
-class OPTION_BLOCKS
-{
- public:
- OPTION_BLOCK & Add(const std::string & description)
- { m_blocks.push_back(OPTION_BLOCK(description)); return m_blocks.back(); }
- void Add(const OPTION_BLOCK & block) { m_blocks.push_back(block); }
- void Help(size_t level) const;
- PARSER_STATE Parse(int argc, char ** argv);
-
- private:
- std::list<OPTION_BLOCK> m_blocks;
-};
-
-} // namespace SGCONF
-
-#endif
+++ /dev/null
-/*
- * 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>
- */
-
-#ifndef __STG_SGCONF_PARSER_STATE_H__
-#define __STG_SGCONF_PARSER_STATE_H__
-
-namespace SGCONF
-{
-
-struct PARSER_STATE
-{
- PARSER_STATE(bool s, int c, char ** v) : stop(s), argc(c), argv(v) {}
- bool stop;
- int argc;
- char ** argv;
-};
-
-}
-
-#endif
+++ /dev/null
-#include "services.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-#include "utils.h"
-
-#include "stg/servconf.h"
-#include "stg/servconf_types.h"
-#include "stg/service_conf.h"
-#include "stg/common.h"
-
-#include <iostream>
-#include <string>
-#include <map>
-
-namespace
-{
-
-std::string Indent(size_t level, bool dash = false)
-{
-if (level == 0)
- return "";
-return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
-}
-
-void PrintService(const STG::GetService::Info & info, size_t level = 0)
-{
-std::cout << Indent(level, true) << "name: " << info.name << "\n"
- << Indent(level) << "cost: " << info.cost << "\n"
- << Indent(level) << "payment day: " << static_cast<unsigned>(info.payDay) << "\n"
- << Indent(level) << "comment: " << info.comment << "\n";
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetServiceParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("cost", "<cost>", "\tcost of the service"));
-params.push_back(SGCONF::API_ACTION::PARAM("pay-day", "<month day>", "payment day"));
-params.push_back(SGCONF::API_ACTION::PARAM("comment", "<text>", "comment"));
-return params;
-}
-
-void SimpleCallback(bool result,
- const std::string & reason,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Success.\n";
-}
-
-void GetServicesCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetService::Info> & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get service list. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Services:\n";
-for (size_t i = 0; i < info.size(); ++i)
- PrintService(info[i], 1);
-}
-
-void GetServiceCallback(bool result,
- const std::string & reason,
- const STG::GetService::Info & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get service. Reason: '" << reason << "'." << std::endl;
- return;
- }
-PrintService(info);
-}
-
-bool GetServicesFunction(const SGCONF::CONFIG & config,
- const std::string & /*arg*/,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetServices(GetServicesCallback, NULL) == STG::st_ok;
-}
-
-bool GetServiceFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetService(arg, GetServiceCallback, NULL) == STG::st_ok;
-}
-
-bool DelServiceFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.DelService(arg, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool AddServiceFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::ServiceConfOpt conf;
-conf.name = arg;
-SGCONF::MaybeSet(options, "cost", conf.cost);
-SGCONF::MaybeSet(options, "pay-day", conf.payDay);
-SGCONF::MaybeSet(options, "comment", conf.comment);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.AddService(arg, conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool ChgServiceFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::ServiceConfOpt conf;
-conf.name = arg;
-SGCONF::MaybeSet(options, "cost", conf.cost);
-SGCONF::MaybeSet(options, "pay-day", conf.payDay);
-SGCONF::MaybeSet(options, "comment", conf.comment);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.ChgService(conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-} // namespace anonymous
-
-void SGCONF::AppendServicesOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-std::vector<API_ACTION::PARAM> params(GetServiceParams());
-blocks.Add("Service management options")
- .Add("get-services", SGCONF::MakeAPIAction(commands, GetServicesFunction), "\tget service list")
- .Add("get-service", SGCONF::MakeAPIAction(commands, "<name>", GetServiceFunction), "get service")
- .Add("add-service", SGCONF::MakeAPIAction(commands, "<name>", params, AddServiceFunction), "add service")
- .Add("del-service", SGCONF::MakeAPIAction(commands, "<name>", DelServiceFunction), "delete service")
- .Add("chg-service", SGCONF::MakeAPIAction(commands, "<name>", params, ChgServiceFunction), "change service");
-}
+++ /dev/null
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendServicesOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-} // namespace SGCONF
+++ /dev/null
-#include "tariffs.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-#include "utils.h"
-
-#include "stg/servconf.h"
-#include "stg/servconf_types.h"
-#include "stg/tariff_conf.h"
-#include "stg/common.h"
-
-#include <iostream>
-#include <algorithm>
-#include <sstream>
-#include <string>
-#include <map>
-#include <cstdint>
-#include <cassert>
-
-namespace
-{
-
-std::string Indent(size_t level, bool dash = false)
-{
-if (level == 0)
- return "";
-return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
-}
-
-std::string ChangePolicyToString(STG::Tariff::ChangePolicy changePolicy)
-{
-switch (changePolicy)
- {
- case STG::Tariff::ALLOW: return "allow";
- case STG::Tariff::TO_CHEAP: return "to_cheap";
- case STG::Tariff::TO_EXPENSIVE: return "to_expensive";
- case STG::Tariff::DENY: return "deny";
- }
-return "unknown";
-}
-
-std::string PeriodToString(STG::Tariff::Period period)
-{
-switch (period)
- {
- case STG::Tariff::DAY:
- return "daily";
- case STG::Tariff::MONTH:
- return "monthly";
- }
-return "unknown";
-}
-
-std::string TraffTypeToString(STG::Tariff::TraffType traffType)
-{
-switch (traffType)
- {
- case STG::Tariff::TRAFF_UP:
- return "upload";
- case STG::Tariff::TRAFF_DOWN:
- return "download";
- case STG::Tariff::TRAFF_UP_DOWN:
- return "upload + download";
- case STG::Tariff::TRAFF_MAX:
- return "max(upload, download)";
- }
-return "unknown";
-}
-
-void ConvPeriod(const std::string & value, STG::Optional<STG::Tariff::Period> & res)
-{
-std::string lowered = ToLower(value);
-if (lowered == "daily")
- res = STG::Tariff::DAY;
-else if (lowered == "monthly")
- res = STG::Tariff::MONTH;
-else
- throw SGCONF::ACTION::ERROR("Period should be 'daily' or 'monthly'. Got: '" + value + "'");
-}
-
-void ConvChangePolicy(const std::string & value, STG::Optional<STG::Tariff::ChangePolicy> & res)
-{
-std::string lowered = ToLower(value);
-if (lowered == "allow")
- res = STG::Tariff::ALLOW;
-else if (lowered == "to_cheap")
- res = STG::Tariff::TO_CHEAP;
-else if (lowered == "to_expensive")
- res = STG::Tariff::TO_EXPENSIVE;
-else if (lowered == "deny")
- res = STG::Tariff::DENY;
-else
- throw SGCONF::ACTION::ERROR("Change policy should be 'allow', 'to_cheap', 'to_expensive' or 'deny'. Got: '" + value + "'");
-}
-
-void ConvChangePolicyTimeout(const std::string & value, STG::Optional<time_t> & res)
-{
-struct tm brokenTime;
-if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
- throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
-res = stg_timegm(&brokenTime);
-}
-
-void ConvTraffType(const std::string & value, STG::Optional<STG::Tariff::TraffType> & res)
-{
-std::string lowered = ToLower(value);
-lowered.erase(std::remove(lowered.begin(), lowered.end(), ' '), lowered.end());
-if (lowered == "upload")
- res = STG::Tariff::TRAFF_UP;
-else if (lowered == "download")
- res = STG::Tariff::TRAFF_DOWN;
-else if (lowered == "upload+download")
- res = STG::Tariff::TRAFF_UP_DOWN;
-else if (lowered.substr(0, 3) == "max")
- res = STG::Tariff::TRAFF_MAX;
-else
- throw SGCONF::ACTION::ERROR("Traff type should be 'upload', 'download', 'upload + download' or 'max'. Got: '" + value + "'");
-}
-
-STG::DirPriceDataOpt ConvTimeSpan(const std::string & value)
-{
-size_t dashPos = value.find_first_of('-');
-if (dashPos == std::string::npos)
- throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
-size_t fromColon = value.find_first_of(':');
-if (fromColon == std::string::npos || fromColon > dashPos)
- throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
-size_t toColon = value.find_first_of(':', dashPos);
-if (toColon == std::string::npos)
- throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
-STG::DirPriceDataOpt res;
-res.hDay = FromString<int>(value.substr(0, fromColon));
-if (res.hDay.data() < 0 || res.hDay.data() > 23)
- throw SGCONF::ACTION::ERROR("Invalid 'from' hours. Got: '" + value.substr(0, fromColon) + "'");
-res.mDay = FromString<int>(value.substr(fromColon + 1, dashPos - fromColon - 1));
-if (res.mDay.data() < 0 || res.mDay.data() > 59)
- throw SGCONF::ACTION::ERROR("Invalid 'from' minutes. Got: '" + value.substr(fromColon + 1, dashPos - fromColon - 1) + "'");
-res.hNight = FromString<int>(value.substr(dashPos + 1, toColon - dashPos - 1));
-if (res.hNight.data() < 0 || res.hNight.data() > 23)
- throw SGCONF::ACTION::ERROR("Invalid 'to' hours. Got: '" + value.substr(dashPos + 1, toColon - dashPos - 1) + "'");
-res.mNight = FromString<int>(value.substr(toColon + 1, value.length() - toColon));
-if (res.mNight.data() < 0 || res.mNight.data() > 59)
- throw SGCONF::ACTION::ERROR("Invalid 'to' minutes. Got: '" + value.substr(toColon + 1, value.length() - toColon) + "'");
-return res;
-}
-
-void splice(std::vector<STG::DirPriceDataOpt> & lhs, const std::vector<STG::DirPriceDataOpt> & rhs)
-{
-for (size_t i = 0; i < lhs.size() && i < rhs.size(); ++i)
- lhs[i].splice(rhs[i]);
-}
-
-void ConvTimes(std::string value, std::vector<STG::DirPriceDataOpt> & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvTimeSpan));
-}
-
-struct ConvPrice : public std::unary_function<std::string, STG::DirPriceDataOpt>
-{
- typedef STG::Optional<double> (STG::DirPriceDataOpt::* MemPtr);
- ConvPrice(MemPtr before, MemPtr after)
- : m_before(before), m_after(after)
- {}
-
- STG::DirPriceDataOpt operator()(const std::string & value)
- {
- STG::DirPriceDataOpt res;
- size_t slashPos = value.find_first_of('/');
- if (slashPos == std::string::npos)
- {
- double price = 0;
- if (str2x(value, price) < 0)
- throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value + "'");
- (res.*m_before) = (res.*m_after) = price;
- res.noDiscount = true;
- }
- else
- {
- double price = 0;
- if (str2x(value.substr(0, slashPos), price) < 0)
- throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value.substr(0, slashPos) + "'");
- (res.*m_before) = price;
- if (str2x(value.substr(slashPos + 1, value.length() - slashPos), price) < 0)
- throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
- (res.*m_after) = price;
- res.noDiscount = false;
- }
- return res;
- }
-
- MemPtr m_before;
- MemPtr m_after;
-};
-
-void ConvDayPrices(std::string value, std::vector<STG::DirPriceDataOpt> & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvPrice(&STG::DirPriceDataOpt::priceDayA, &STG::DirPriceDataOpt::priceDayB)));
-}
-
-void ConvNightPrices(std::string value, std::vector<STG::DirPriceDataOpt> & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvPrice(&STG::DirPriceDataOpt::priceNightA, &STG::DirPriceDataOpt::priceNightB)));
-}
-
-STG::DirPriceDataOpt ConvThreshold(std::string value)
-{
- STG::DirPriceDataOpt res;
-double threshold = 0;
-if (str2x(value, threshold) < 0)
- throw SGCONF::ACTION::ERROR("Threshold should be a floating point value. Got: '" + value + "'");
-res.threshold = threshold;
-return res;
-}
-
-void ConvThresholds(std::string value, std::vector<STG::DirPriceDataOpt> & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-splice(res, Split<std::vector<STG::DirPriceDataOpt> >(value, ',', ConvThreshold));
-}
-
-std::string TimeToString(int h, int m)
-{
-std::ostringstream stream;
-stream << (h < 10 ? "0" : "") << h << ":"
- << (m < 10 ? "0" : "") << m;
-return stream.str();
-}
-
-void PrintDirPriceData(size_t dir, const STG::DirPriceData & data, size_t level)
-{
-std::string night = TimeToString(data.hNight, data.mNight);
-std::string day = TimeToString(data.hDay, data.mDay);
-std::cout << Indent(level, true) << "dir: " << dir << "\n"
- << Indent(level) << "'" << night << "' - '" << day << "': " << data.priceDayA << "/" << data.priceDayB << "\n"
- << Indent(level) << "'" << day << "' - '" << night << "': " << data.priceNightA << "/" << data.priceNightB << "\n"
- << Indent(level) << "threshold: " << data.threshold << "\n"
- << Indent(level) << "single price: " << (data.singlePrice ? "yes" : "no") << "\n"
- << Indent(level) << "discount: " << (data.noDiscount ? "no" : "yes") << "\n"; // Attention!
-}
-
-void PrintTariffConf(const STG::TariffConf & conf, size_t level)
-{
-std::cout << Indent(level, true) << "name: " << conf.name << "\n"
- << Indent(level) << "fee: " << conf.fee << "\n"
- << Indent(level) << "free mb: " << conf.free << "\n"
- << Indent(level) << "passive cost: " << conf.passiveCost << "\n"
- << Indent(level) << "traff type: " << TraffTypeToString(conf.traffType) << "\n"
- << Indent(level) << "period: " << PeriodToString(conf.period) << "\n"
- << Indent(level) << "change policy: " << ChangePolicyToString(conf.changePolicy) << "\n"
- << Indent(level) << "change policy timeout: " << formatTime(conf.changePolicyTimeout) << "\n";
-}
-
-void PrintTariff(const STG::GetTariff::Info & info, size_t level = 0)
-{
-PrintTariffConf(info.tariffConf, level);
-std::cout << Indent(level) << "dir prices:\n";
-for (size_t i = 0; i < info.dirPrice.size(); ++i)
- PrintDirPriceData(i, info.dirPrice[i], level + 1);
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetTariffParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("fee", "<fee>", "\t\ttariff fee"));
-params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traffic"));
-params.push_back(SGCONF::API_ACTION::PARAM("passive-cost", "<cost>", "\tpassive cost"));
-params.push_back(SGCONF::API_ACTION::PARAM("traff-type", "<type>", "\ttraffic type (up, down, up+down, max)"));
-params.push_back(SGCONF::API_ACTION::PARAM("period", "<period>", "\ttarification period (daily, monthly)"));
-params.push_back(SGCONF::API_ACTION::PARAM("change-policy", "<policy>", "tariff change policy (allow, to_cheap, to_expensive, deny)"));
-params.push_back(SGCONF::API_ACTION::PARAM("change-policy-timeout", "<yyyy-mm-dd hh:mm:ss>", "tariff change policy timeout"));
-params.push_back(SGCONF::API_ACTION::PARAM("times", "<hh:mm-hh:mm, ...>", "coma-separated day time-spans for each direction"));
-params.push_back(SGCONF::API_ACTION::PARAM("day-prices", "<price/price, ...>", "coma-separated day prices for each direction"));
-params.push_back(SGCONF::API_ACTION::PARAM("night-prices", "<price/price, ...>", "coma-separated night prices for each direction"));
-params.push_back(SGCONF::API_ACTION::PARAM("thresholds", "<threshold, ...>", "coma-separated thresholds for each direction"));
-return params;
-}
-
-void SimpleCallback(bool result,
- const std::string & reason,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Success.\n";
-}
-
-void GetTariffsCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetTariff::Info> & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get tariff list. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Tariffs:\n";
-for (size_t i = 0; i < info.size(); ++i)
- PrintTariff(info[i], 1);
-}
-
-void GetTariffCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetTariff::Info> & info,
- void * data)
-{
-assert(data != NULL && "Expecting pointer to std::string with the tariff's name.");
-const std::string & name = *static_cast<const std::string *>(data);
-if (!result)
- {
- std::cerr << "Failed to get tariff. Reason: '" << reason << "'." << std::endl;
- return;
- }
-for (size_t i = 0; i < info.size(); ++i)
- if (info[i].tariffConf.name == name)
- PrintTariff(info[i]);
-}
-
-bool GetTariffsFunction(const SGCONF::CONFIG & config,
- const std::string & /*arg*/,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetTariffs(GetTariffsCallback, NULL) == STG::st_ok;
-}
-
-bool GetTariffFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-// STG currently doesn't support <GetTariff name="..."/>.
-// So get a list of tariffs and filter it. 'data' param holds a pointer to 'name'.
-std::string name(arg);
-return proto.GetTariffs(GetTariffCallback, &name) == STG::st_ok;
-}
-
-bool DelTariffFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.DelTariff(arg, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool AddTariffFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::TariffDataOpt conf;
-conf.tariffConf.name = arg;
-SGCONF::MaybeSet(options, "fee", conf.tariffConf.fee);
-SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
-SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
-SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
-SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
-SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
-SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
-SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
-SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
-SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
-SGCONF::MaybeSet(options, "thresholds", conf.dirPrice, ConvThresholds);
-for (size_t i = 0; i < conf.dirPrice.size(); ++i)
- {
- if (!conf.dirPrice[i].priceDayA.empty() &&
- !conf.dirPrice[i].priceNightA.empty() &&
- !conf.dirPrice[i].priceDayB.empty() &&
- !conf.dirPrice[i].priceNightB.empty())
- conf.dirPrice[i].singlePrice = conf.dirPrice[i].priceDayA.data() == conf.dirPrice[i].priceNightA.data() &&
- conf.dirPrice[i].priceDayB.data() == conf.dirPrice[i].priceNightB.data();
- }
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.AddTariff(arg, conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool ChgTariffFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::TariffDataOpt conf;
-conf.tariffConf.name = arg;
-SGCONF::MaybeSet(options, "fee", conf.tariffConf.fee);
-SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
-SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
-SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
-SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
-SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
-SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
-SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
-SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
-SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
-SGCONF::MaybeSet(options, "thresholds", conf.dirPrice, ConvThresholds);
-for (size_t i = 0; i < conf.dirPrice.size(); ++i)
- {
- if (!conf.dirPrice[i].priceDayA.empty() &&
- !conf.dirPrice[i].priceNightA.empty() &&
- !conf.dirPrice[i].priceDayB.empty() &&
- !conf.dirPrice[i].priceNightB.empty())
- conf.dirPrice[i].singlePrice = conf.dirPrice[i].priceDayA.data() == conf.dirPrice[i].priceNightA.data() &&
- conf.dirPrice[i].priceDayB.data() == conf.dirPrice[i].priceNightB.data();
- }
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.ChgTariff(conf, SimpleCallback, NULL) == STG::st_ok;
-}
-
-} // namespace anonymous
-
-void SGCONF::AppendTariffsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-std::vector<API_ACTION::PARAM> params(GetTariffParams());
-blocks.Add("Tariff management options")
- .Add("get-tariffs", SGCONF::MakeAPIAction(commands, GetTariffsFunction), "\tget tariff list")
- .Add("get-tariff", SGCONF::MakeAPIAction(commands, "<name>", GetTariffFunction), "get tariff")
- .Add("add-tariff", SGCONF::MakeAPIAction(commands, "<name>", params, AddTariffFunction), "add tariff")
- .Add("del-tariff", SGCONF::MakeAPIAction(commands, "<name>", DelTariffFunction), "delete tariff")
- .Add("chg-tariff", SGCONF::MakeAPIAction(commands, "<name>", params, ChgTariffFunction), "change tariff");
-}
+++ /dev/null
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendTariffsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-} // namespace SGCONF
+++ /dev/null
-#include "users.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-#include "utils.h"
-
-#include "stg/servconf.h"
-#include "stg/servconf_types.h"
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/user_ips.h"
-#include "stg/common.h"
-
-#include <iostream>
-#include <algorithm>
-#include <string>
-#include <map>
-
-namespace
-{
-
-std::string Indent(size_t level, bool dash = false)
-{
-if (level == 0)
- return "";
-return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
-}
-
-void PrintUser(const STG::GetUser::Info & info, size_t level = 0)
-{
-std::cout << Indent(level, true) << "login: " << info.login << "\n"
- << Indent(level) << "password: " << info.password << "\n"
- << Indent(level) << "cash: " << info.cash << "\n"
- << Indent(level) << "credit: " << info.credit << "\n"
- << Indent(level) << "credit expire: " << TimeToString(info.creditExpire) << "\n"
- << Indent(level) << "last cash add: " << info.lastCashAdd << "\n"
- << Indent(level) << "last cash add time: " << TimeToString(info.lastCashAddTime) << "\n"
- << Indent(level) << "prepaid traffic: " << info.prepaidTraff << "\n"
- << Indent(level) << "disabled: " << (info.disabled ? "t" : "f") << "\n"
- << Indent(level) << "passive: " << (info.passive ? "t" : "f") << "\n"
- << Indent(level) << "disabled detail stat: " << (info.disableDetailStat ? "t" : "f") << "\n"
- << Indent(level) << "connected: " << (info.connected ? "t" : "f") << "\n"
- << Indent(level) << "always on-line: " << (info.alwaysOnline ? "t" : "f") << "\n"
- << Indent(level) << "IP: " << inet_ntostring(info.ip) << "\n"
- << Indent(level) << "IPs: " << info.ips << "\n"
- << Indent(level) << "tariff: " << info.tariff << "\n"
- << Indent(level) << "group: " << info.group << "\n"
- << Indent(level) << "note: " << info.note << "\n"
- << Indent(level) << "email: " << info.email << "\n"
- << Indent(level) << "name: " << info.name << "\n"
- << Indent(level) << "address: " << info.address << "\n"
- << Indent(level) << "phone: " << info.phone << "\n"
- << Indent(level) << "corporation: " << info.corp << "\n"
- << Indent(level) << "last ping time: " << TimeToString(info.pingTime) << "\n"
- << Indent(level) << "last activity time: " << TimeToString(info.lastActivityTime) << "\n"
- << Indent(level) << "traffic:\n";
-for (size_t i = 0; i < DIR_NUM; ++i)
- {
- std::cout << Indent(level + 1, true) << "dir: " << i << "\n"
- << Indent(level + 1) << "session upload: " << info.stat.su[i] << "\n"
- << Indent(level + 1) << "session download: " << info.stat.sd[i] << "\n"
- << Indent(level + 1) << "month upload: " << info.stat.mu[i] << "\n"
- << Indent(level + 1) << "month download: " << info.stat.md[i] << "\n";
- }
-std::cout << Indent(level) << "user data:\n";
-for (size_t i = 0; i < USERDATA_NUM; ++i)
- std::cout << Indent(level + 1, true) << "user data " << i << ": " << info.userData[i] << "\n";
-if (!info.services.empty())
- {
- std::cout << Indent(level) << "services:\n";
- for (size_t i = 0; i < info.services.size(); ++i)
- std::cout << Indent(level + 1, true) << info.services[i] << "\n";
- }
-if (!info.authBy.empty())
- {
- std::cout << Indent(level) << "auth by:\n";
- for (size_t i = 0; i < info.authBy.size(); ++i)
- std::cout << Indent(level + 1, true) << info.authBy[i] << "\n";
- }
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetUserParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "\tuser's password"));
-params.push_back(SGCONF::API_ACTION::PARAM("cash-add", "<cash[:message]>", "cash to add (with optional comment)"));
-params.push_back(SGCONF::API_ACTION::PARAM("cash-set", "<cash[:message]>", "cash to set (with optional comment)"));
-params.push_back(SGCONF::API_ACTION::PARAM("credit", "<amount>", "\tuser's credit"));
-params.push_back(SGCONF::API_ACTION::PARAM("credit-expire", "<date>", "\tcredit expiration"));
-params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traffic"));
-params.push_back(SGCONF::API_ACTION::PARAM("disabled", "<flag>", "\tdisable user (y|n)"));
-params.push_back(SGCONF::API_ACTION::PARAM("passive", "<flag>", "\tmake user passive (y|n)"));
-params.push_back(SGCONF::API_ACTION::PARAM("disable-detail-stat", "<flag>", "disable detail stat (y|n)"));
-params.push_back(SGCONF::API_ACTION::PARAM("always-online", "<flag>", "\tmake user always online (y|n)"));
-params.push_back(SGCONF::API_ACTION::PARAM("ips", "<ips>", "\t\tcoma-separated list of ips"));
-params.push_back(SGCONF::API_ACTION::PARAM("tariff", "<tariff name>", "\tcurrent tariff"));
-params.push_back(SGCONF::API_ACTION::PARAM("next-tariff", "<tariff name>", "tariff starting from the next month"));
-params.push_back(SGCONF::API_ACTION::PARAM("group", "<group>", "\t\tuser's group"));
-params.push_back(SGCONF::API_ACTION::PARAM("note", "<note>", "\t\tuser's note"));
-params.push_back(SGCONF::API_ACTION::PARAM("email", "<email>", "\t\tuser's email"));
-params.push_back(SGCONF::API_ACTION::PARAM("name", "<real name>", "\tuser's real name"));
-params.push_back(SGCONF::API_ACTION::PARAM("address", "<address>", "\tuser's postal address"));
-params.push_back(SGCONF::API_ACTION::PARAM("phone", "<phone>", "\t\tuser's phone number"));
-params.push_back(SGCONF::API_ACTION::PARAM("corp", "<corp name>", "\tcorporation name"));
-params.push_back(SGCONF::API_ACTION::PARAM("session-traffic", "<up/dn, ...>", "coma-separated session upload and download"));
-params.push_back(SGCONF::API_ACTION::PARAM("month-traffic", "<up/dn, ...>", "coma-separated month upload and download"));
-params.push_back(SGCONF::API_ACTION::PARAM("user-data", "<value, ...>", "coma-separated user data values"));
-return params;
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetCheckParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "\tuser's password"));
-return params;
-}
-
-std::vector<SGCONF::API_ACTION::PARAM> GetMessageParams()
-{
-std::vector<SGCONF::API_ACTION::PARAM> params;
-params.push_back(SGCONF::API_ACTION::PARAM("logins", "<login, ...>", "\tlist of logins to send a message"));
-params.push_back(SGCONF::API_ACTION::PARAM("text", "<text>", "\t\tmessage text"));
-return params;
-}
-
-void ConvBool(const std::string & value, STG::Optional<int> & res)
-{
-res = !value.empty() && value[0] == 'y';
-}
-
-void Splice(std::vector<STG::Optional<std::string> > & lhs, const std::vector<STG::Optional<std::string> > & rhs)
-{
-for (size_t i = 0; i < lhs.size() && i < rhs.size(); ++i)
- lhs[i].splice(rhs[i]);
-}
-
-STG::Optional<std::string> ConvString(const std::string & value)
-{
-return STG::Optional<std::string>(value);
-}
-
-void ConvStringList(std::string value, std::vector<STG::Optional<std::string> > & res)
-{
-Splice(res, Split<std::vector<STG::Optional<std::string> > >(value, ',', ConvString));
-}
-
-void ConvServices(std::string value, STG::Optional<std::vector<std::string> > & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-res = Split<std::vector<std::string> >(value, ',');
-}
-
-void ConvCreditExpire(const std::string & value, STG::Optional<time_t> & res)
-{
-struct tm brokenTime;
-if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
- throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
-res = stg_timegm(&brokenTime);
-}
-
-void ConvIPs(const std::string & value, STG::Optional<STG::UserIPs> & res)
-{
-res = STG::UserIPs::parse(value);
-}
-
-struct TRAFF
-{
- uint64_t up;
- uint64_t down;
-};
-
-TRAFF ConvTraff(const std::string & value)
-{
-TRAFF res;
-size_t slashPos = value.find_first_of('/');
-if (slashPos == std::string::npos)
- throw SGCONF::ACTION::ERROR("Traffic record should be in format 'upload/download'. Got: '" + value + "'");
-
-if (str2x(value.substr(0, slashPos), res.up) < 0)
- throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(0, slashPos) + "'");
-if (str2x(value.substr(slashPos + 1, value.length() - slashPos), res.down) < 0)
- throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
-return res;
-}
-
-void ConvSessionTraff(std::string value, STG::UserStatOpt & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
-if (traff.size() != DIR_NUM)
- throw SGCONF::ACTION::ERROR("There should be prcisely " + std::to_string(DIR_NUM) + " records of session traffic.");
-for (size_t i = 0; i < DIR_NUM; ++i)
- {
- res.sessionUp[i] = traff[i].up;
- res.sessionDown[i] = traff[i].down;
- }
-}
-
-void ConvMonthTraff(std::string value, STG::UserStatOpt & res)
-{
-value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
-std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
-if (traff.size() != DIR_NUM)
- throw SGCONF::ACTION::ERROR("There should be prcisely " + std::to_string(DIR_NUM) + " records of month traffic.");
-for (size_t i = 0; i < DIR_NUM; ++i)
- {
- res.monthUp[i] = traff[i].up;
- res.monthDown[i] = traff[i].down;
- }
-}
-
-void ConvCashInfo(const std::string & value, STG::Optional<STG::CashInfo> & res)
-{
-STG::CashInfo info;
-size_t pos = value.find_first_of(':');
-if (pos == std::string::npos)
- {
- if (str2x(value, info.first) < 0)
- throw SGCONF::ACTION::ERROR("Cash should be a double value. Got: '" + value + "'");
- }
-else
- {
- if (str2x(value.substr(0, pos), info.first) < 0)
- throw SGCONF::ACTION::ERROR("Cash should be a double value. Got: '" + value + "'");
- info.second = value.substr(pos + 1);
- }
-res = info;
-}
-
-void SimpleCallback(bool result,
- const std::string & reason,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Success.\n";
-}
-
-void GetUsersCallback(bool result,
- const std::string & reason,
- const std::vector<STG::GetUser::Info> & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get user list. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Users:\n";
-for (size_t i = 0; i < info.size(); ++i)
- PrintUser(info[i], 1);
-}
-
-void GetUserCallback(bool result,
- const std::string & reason,
- const STG::GetUser::Info & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get user. Reason: '" << reason << "'." << std::endl;
- return;
- }
-PrintUser(info);
-}
-
-void AuthByCallback(bool result,
- const std::string & reason,
- const std::vector<std::string> & info,
- void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get authorizer list. Reason: '" << reason << "'." << std::endl;
- return;
- }
-std::cout << "Authorized by:\n";
-for (size_t i = 0; i < info.size(); ++i)
- std::cout << Indent(1, true) << info[i] << "\n";
-}
-
-bool GetUsersFunction(const SGCONF::CONFIG & config,
- const std::string & /*arg*/,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetUsers(GetUsersCallback, NULL) == STG::st_ok;
-}
-
-bool GetUserFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.GetUser(arg, GetUserCallback, NULL) == STG::st_ok;
-}
-
-bool DelUserFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.DelUser(arg, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool AddUserFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::UserConfOpt conf;
-SGCONF::MaybeSet(options, "password", conf.password);
-SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
-SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
-SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
-SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
-SGCONF::MaybeSet(options, "tariff", conf.tariffName);
-SGCONF::MaybeSet(options, "address", conf.address);
-SGCONF::MaybeSet(options, "phone", conf.phone);
-SGCONF::MaybeSet(options, "email", conf.email);
-SGCONF::MaybeSet(options, "note", conf.note);
-SGCONF::MaybeSet(options, "name", conf.realName);
-SGCONF::MaybeSet(options, "corp", conf.corp);
-SGCONF::MaybeSet(options, "services", conf.services, ConvServices);
-SGCONF::MaybeSet(options, "group", conf.group);
-SGCONF::MaybeSet(options, "credit", conf.credit);
-SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
-SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
-SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
-SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
-STG::UserStatOpt stat;
-SGCONF::MaybeSet(options, "cash-set", stat.cashSet, ConvCashInfo);
-SGCONF::MaybeSet(options, "free", stat.freeMb);
-SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
-SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.AddUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool ChgUserFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-STG::UserConfOpt conf;
-SGCONF::MaybeSet(options, "password", conf.password);
-SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
-SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
-SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
-SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
-SGCONF::MaybeSet(options, "tariff", conf.tariffName);
-SGCONF::MaybeSet(options, "address", conf.address);
-SGCONF::MaybeSet(options, "phone", conf.phone);
-SGCONF::MaybeSet(options, "email", conf.email);
-SGCONF::MaybeSet(options, "note", conf.note);
-SGCONF::MaybeSet(options, "name", conf.realName);
-SGCONF::MaybeSet(options, "corp", conf.corp);
-SGCONF::MaybeSet(options, "services", conf.services, ConvServices);
-SGCONF::MaybeSet(options, "group", conf.group);
-SGCONF::MaybeSet(options, "credit", conf.credit);
-SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
-SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
-SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
-SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
-STG::UserStatOpt stat;
-SGCONF::MaybeSet(options, "cash-add", stat.cashAdd, ConvCashInfo);
-SGCONF::MaybeSet(options, "cash-set", stat.cashSet, ConvCashInfo);
-SGCONF::MaybeSet(options, "free", stat.freeMb);
-SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
-SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.ChgUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool CheckUserFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & options)
-{
-std::map<std::string, std::string>::const_iterator it(options.find("password"));
-if (it == options.end())
- throw SGCONF::ACTION::ERROR("Password is not specified.");
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.CheckUser(arg, it->second, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool SendMessageFunction(const SGCONF::CONFIG & config,
- const std::string & /*arg*/,
- const std::map<std::string, std::string> & options)
-{
-std::map<std::string, std::string>::const_iterator it(options.find("logins"));
-if (it == options.end())
- throw SGCONF::ACTION::ERROR("Logins are not specified.");
-std::string logins = it->second;
-for (size_t i = 0; i < logins.length(); ++i)
- if (logins[i] == ',')
- logins[i] = ':';
-it = options.find("text");
-if (it == options.end())
- throw SGCONF::ACTION::ERROR("Message text is not specified.");
-std::string text = it->second;
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.SendMessage(logins, text, SimpleCallback, NULL) == STG::st_ok;
-}
-
-bool AuthByFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.AuthBy(arg, AuthByCallback, NULL) == STG::st_ok;
-}
-
-} // namespace anonymous
-
-void SGCONF::AppendUsersOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-std::vector<API_ACTION::PARAM> params(GetUserParams());
-blocks.Add("User management options")
- .Add("get-users", SGCONF::MakeAPIAction(commands, GetUsersFunction), "\tget user list")
- .Add("get-user", SGCONF::MakeAPIAction(commands, "<login>", GetUserFunction), "get user")
- .Add("add-user", SGCONF::MakeAPIAction(commands, "<login>", params, AddUserFunction), "add user")
- .Add("del-user", SGCONF::MakeAPIAction(commands, "<login>", DelUserFunction), "delete user")
- .Add("chg-user", SGCONF::MakeAPIAction(commands, "<login>", params, ChgUserFunction), "change user")
- .Add("check-user", SGCONF::MakeAPIAction(commands, "<login>", GetCheckParams(), CheckUserFunction), "check user existance and credentials")
- .Add("send-message", SGCONF::MakeAPIAction(commands, GetMessageParams(), SendMessageFunction), "send message")
- .Add("auth-by", SGCONF::MakeAPIAction(commands, "<login>", AuthByFunction), "a list of authorizers user authorized by");
-}
+++ /dev/null
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendUsersOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-}
+++ /dev/null
-#pragma once
-
-#include "stg/common.h"
-#include "stg/optional.h"
-
-#include <string>
-#include <map>
-
-namespace SGCONF
-{
-
-template <typename T>
-inline
-void MaybeSet(const std::map<std::string, std::string> & options, const std::string & name, STG::Optional<T> & res)
-{
-std::map<std::string, std::string>::const_iterator it(options.find(name));
-if (it == options.end())
- return;
-T value;
-if (str2x(it->second, value) < 0)
- return;
-res = value;
-}
-
-template <typename T, typename F>
-inline
-void MaybeSet(const std::map<std::string, std::string> & options, const std::string & name, T & res, F conv)
-{
-std::map<std::string, std::string>::const_iterator it(options.find(name));
-if (it == options.end())
- return;
-conv(it->second, res);
-}
-
-template <>
-inline
-void MaybeSet<std::string>(const std::map<std::string, std::string> & options, const std::string & name, STG::Optional<std::string> & res)
-{
-std::map<std::string, std::string>::const_iterator it(options.find(name));
-if (it == options.end())
- return;
-res = it->second;
-}
-
-} // namespace SGCONF
+++ /dev/null
-#include "xml.h"
-
-#include "api_action.h"
-#include "options.h"
-#include "config.h"
-
-#include "stg/servconf.h"
-
-#include <iostream>
-#include <string>
-#include <map>
-
-#include <expat.h>
-
-namespace
-{
-
-struct ParserState
-{
-size_t level;
-};
-
-std::string Indent(size_t level)
-{
-return std::string(level * 4, ' ');
-}
-
-std::string PrintAttr(const char ** attr)
-{
-std::string res;
-if (attr == NULL)
- return res;
-while (*attr)
- {
- if (*(attr + 1) == NULL)
- return res;
- res += std::string(" ") + *attr + "=\"" + *(attr + 1) + "\"";
- ++attr; ++attr;
- }
-return res;
-}
-
-void Start(void * data, const char * el, const char ** attr)
-{
-ParserState * state = static_cast<ParserState *>(data);
-if (el != NULL)
- std::cout << Indent(state->level) << "<" << el << PrintAttr(attr) << ">\n";
-++state->level;
-}
-
-void End(void * data, const char * el)
-{
-ParserState * state = static_cast<ParserState *>(data);
---state->level;
-if (el != NULL)
- std::cout << Indent(state->level) << "</" << el << ">\n";
-}
-
-void PrintXML(const std::string& xml)
-{
-ParserState state = { 0 };
-
-XML_Parser parser = XML_ParserCreate(NULL);
-XML_ParserReset(parser, NULL);
-XML_SetElementHandler(parser, Start, End);
-XML_SetUserData(parser, &state);
-
-if (XML_Parse(parser, xml.c_str(), xml.length(), true) == XML_STATUS_ERROR)
- std::cerr << "XML parse error at line " << XML_GetCurrentLineNumber(parser)
- << ": '" << XML_ErrorString(XML_GetErrorCode(parser)) << "'"
- << std::endl;
-
-XML_ParserFree(parser);
-}
-
-void RawXMLCallback(bool result, const std::string & reason, const std::string & response, void * /*data*/)
-{
-if (!result)
- {
- std::cerr << "Failed to get raw XML response. Reason: '" << reason << "'." << std::endl;
- return;
- }
-PrintXML(response);
-}
-
-bool RawXMLFunction(const SGCONF::CONFIG & config,
- const std::string & arg,
- const std::map<std::string, std::string> & /*options*/)
-{
-STG::ServConf proto(config.server.data(),
- config.port.data(),
- config.localAddress.data(),
- config.localPort.data(),
- config.userName.data(),
- config.userPass.data());
-return proto.RawXML(arg, RawXMLCallback, NULL) == STG::st_ok;
-}
-
-}
-
-void SGCONF::AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
-{
-blocks.Add("Raw XML")
- .Add("r", "raw", SGCONF::MakeAPIAction(commands, "<xml>", RawXMLFunction), "\tmake raw XML request");
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-namespace SGCONF
-{
-
-class OPTION_BLOCKS;
-class COMMANDS;
-
-void AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
-
-}
+++ /dev/null
-set ( CPP_FILES main.cpp
- admins_impl.cpp
- users_impl.cpp
- tariffs_impl.cpp
- corps_impl.cpp
- services_impl.cpp
- user_impl.cpp
- tariff_impl.cpp
- eventloop.cpp
- pidfile.cpp
- plugin_runner.cpp
- plugin_mgr.cpp
- settings_impl.cpp
- stg_timer.cpp
- store_loader.cpp
- traffcounter_impl.cpp
- user_property.cpp )
-
-set ( THREADS_PREFER_PTHREAD_FLAG ON )
-find_package ( Threads REQUIRED )
-
-add_executable ( stargazer ${CPP_FILES} )
-
-target_link_libraries ( stargazer scriptexecuter dotconfpp logger common Threads::Threads ${CMAKE_DL_LIBS} )
-
-add_subdirectory ( plugins )
-
-# TODO: install
+++ /dev/null
-Инсталяция и запуск.
-1. > ./build
-2. > make install
-3. Правка конфигурационных файлов
-4. > stargazer
-
+++ /dev/null
-#ifndef __ACTIONS_H__
-#define __ACTIONS_H__
-
-// Usage:
-//
-// ACTIONS_LIST actionsList;
-// CLASS myClass;
-// DATA1 myData1;
-// DATA2 myData2;
-//
-// actionsList.Enqueue(myClass, &CLASS::myMethod1, myData1);
-// actionsList.Enqueue(myClass, &CLASS::myMethod2, myData2);
-//
-// actionsList.InvokeAll();
-
-#include <pthread.h>
-#include <vector>
-#include <functional>
-
-// Generalized actor type - a method of some class with one argument
-template <class ACTIVE_CLASS, typename DATA_TYPE>
-struct ACTOR
-{
-typedef void (ACTIVE_CLASS::*TYPE)(DATA_TYPE);
-};
-
-// Abstract base action class for polymorphic action invocation
-class BASE_ACTION
-{
-public:
- virtual ~BASE_ACTION() {}
- virtual void Invoke() = 0;
-};
-
-// Concrete generalized action type - an actor with it's data and owner
-template <class ACTIVE_CLASS, typename DATA_TYPE>
-class ACTION : public BASE_ACTION,
- public std::unary_function<ACTIVE_CLASS &, void>
-{
-public:
- ACTION(ACTIVE_CLASS & ac,
- typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
- DATA_TYPE d)
- : activeClass(ac), actor(a), data(d) {}
- void Invoke();
-private:
- ACTION(const ACTION<ACTIVE_CLASS, DATA_TYPE> & rvalue);
- ACTION<ACTIVE_CLASS, DATA_TYPE> & operator=(const ACTION<ACTIVE_CLASS, DATA_TYPE> & rvalue);
-
- ACTIVE_CLASS & activeClass;
- typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE actor;
- DATA_TYPE data;
-};
-
-// A list of an actions
-// All methods are thread-safe
-class ACTIONS_LIST : private std::vector<BASE_ACTION *>
-{
-public:
- // Just a typedef for parent class
- typedef std::vector<BASE_ACTION *> parent;
-
- // Initialize mutex
- ACTIONS_LIST();
- // Delete actions and destroy mutex
- virtual ~ACTIONS_LIST();
-
- parent::iterator begin();
- parent::iterator end();
- parent::const_iterator begin() const;
- parent::const_iterator end() const;
-
- bool empty() const;
- size_t size() const;
- void swap(ACTIONS_LIST & list);
-
- // Add an action to list
- template <class ACTIVE_CLASS, typename DATA_TYPE>
- void Enqueue(ACTIVE_CLASS & ac,
- typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
- DATA_TYPE d);
- // Invoke all actions in the list
- void InvokeAll();
-private:
- mutable pthread_mutex_t mutex;
-};
-
-#include "actions.inl.h"
-
-#endif
+++ /dev/null
-#ifndef __ACTIONS_INL_H__
-#define __ACTIONS_INL_H__
-
-#include <algorithm>
-
-#include "stg/locker.h"
-
-// Polymorphick action invocation
-template <class ACTIVE_CLASS, typename DATA_TYPE>
-inline
-void ACTION<ACTIVE_CLASS, DATA_TYPE>::Invoke()
-{
-(activeClass.*actor)(data);
-}
-
-inline
-ACTIONS_LIST::ACTIONS_LIST()
- : mutex()
-{
-pthread_mutex_init(&mutex, NULL);
-}
-
-// Delete all actions before deleting list
-inline
-ACTIONS_LIST::~ACTIONS_LIST()
-{
-
- {
- STG_LOCKER lock(&mutex);
-
- parent::iterator it(parent::begin());
- while (it != parent::end())
- {
- delete *it++;
- }
- }
-
-pthread_mutex_destroy(&mutex);
-}
-
-inline
-ACTIONS_LIST::parent::iterator ACTIONS_LIST::begin()
-{
-STG_LOCKER lock(&mutex);
-return parent::begin();
-}
-
-inline
-ACTIONS_LIST::parent::iterator ACTIONS_LIST::end()
-{
-STG_LOCKER lock(&mutex);
-return parent::end();
-}
-
-inline
-ACTIONS_LIST::parent::const_iterator ACTIONS_LIST::begin() const
-{
-STG_LOCKER lock(&mutex);
-return parent::begin();
-}
-
-inline
-ACTIONS_LIST::parent::const_iterator ACTIONS_LIST::end() const
-{
-STG_LOCKER lock(&mutex);
-return parent::end();
-}
-
-inline
-bool ACTIONS_LIST::empty() const
-{
-STG_LOCKER lock(&mutex);
-return parent::empty();
-}
-
-inline
-size_t ACTIONS_LIST::size() const
-{
-STG_LOCKER lock(&mutex);
-return parent::size();
-}
-
-inline
-void ACTIONS_LIST::swap(ACTIONS_LIST & list)
-{
-STG_LOCKER lock(&mutex);
-parent::swap(list);
-}
-
-template <class ACTIVE_CLASS, typename DATA_TYPE>
-inline
-void ACTIONS_LIST::Enqueue(ACTIVE_CLASS & ac,
- typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
- DATA_TYPE d)
-{
-STG_LOCKER lock(&mutex);
-push_back(new ACTION<ACTIVE_CLASS, DATA_TYPE>(ac, a, d));
-}
-
-inline
-void ACTIONS_LIST::InvokeAll()
-{
-STG_LOCKER lock(&mutex);
-std::for_each(
- parent::begin(),
- parent::end(),
- [](auto action){ action->Invoke(); });
-}
-
-#endif
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 27.10.2002
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include "admins_impl.h"
-
-#include "stg/common.h"
-
-using STG::AdminsImpl;
-
-//-----------------------------------------------------------------------------
-AdminsImpl::AdminsImpl(Store& st)
- : m_stg(Priv(0xFFFF), "@stargazer", ""),
- m_noAdmin(Priv(0xFFFF), "NO-ADMIN", ""),
- m_store(st),
- WriteServLog(Logger::get())
-{
- read();
-}
-//-----------------------------------------------------------------------------
-int AdminsImpl::add(const std::string& login, const Admin& admin)
-{
- if (!admin.priv().adminChg)
- {
- const std::string s = admin.logStr() + " Add administrator \'" + login + "\'. Access denied.";
- m_strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
- std::lock_guard<std::mutex> lock(m_mutex);
- const auto it = find(login);
-
- if (it != m_data.end())
- {
- m_strError = "Administrator \'" + login + "\' cannot not be added. Administrator already exists.";
- WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
- return -1;
- }
-
- m_data.push_back(Admin(Priv(0), login, {}));
-
- if (m_store.AddAdmin(login) == 0)
- {
- WriteServLog("%s Administrator \'%s\' added.",
- admin.logStr().c_str(), login.c_str());
- return 0;
- }
-
- m_strError = "Administrator \'" + login + "\' was not added. Error: " + m_store.GetStrError();
- WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
-
- return -1;
-}
-//-----------------------------------------------------------------------------
-int AdminsImpl::del(const std::string& login, const Admin& admin)
-{
- if (!admin.priv().adminChg)
- {
- const std::string s = admin.logStr() + " Delete administrator \'" + login + "\'. Access denied.";
- m_strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
- std::lock_guard<std::mutex> lock(m_mutex);
- const auto it = find(login);
-
- if (it == m_data.end())
- {
- m_strError = "Administrator \'" + login + "\' cannot be deleted. Administrator does not exist.";
- WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
- return -1;
- }
-
- m_data.erase(it);
- if (m_store.DelAdmin(login) < 0)
- {
- m_strError = "Administrator \'" + login + "\' was not deleted. Error: " + m_store.GetStrError();
- WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
-
- return -1;
- }
-
- WriteServLog("%s Administrator \'%s\' deleted.", admin.logStr().c_str(), login.c_str());
- return 0;
-}
-//-----------------------------------------------------------------------------
-int AdminsImpl::change(const AdminConf& ac, const Admin& admin)
-{
- if (!admin.priv().adminChg)
- {
- const std::string s = admin.logStr() + " Change administrator \'" + ac.login + "\'. Access denied.";
- m_strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
- std::lock_guard<std::mutex> lock(m_mutex);
- const auto it = find(ac.login);
-
- if (it == m_data.end())
- {
- m_strError = "Administrator \'" + ac.login + "\' cannot be changed " + ". Administrator does not exist.";
- WriteServLog("%s %s", admin.logStr().c_str(), m_strError.c_str());
- return -1;
- }
-
- *it = ac;
- if (m_store.SaveAdmin(ac))
- {
- WriteServLog("Cannot write admin %s.", ac.login.c_str());
- WriteServLog("%s", m_store.GetStrError().c_str());
- return -1;
- }
-
- WriteServLog("%s Administrator \'%s\' changed.",
- admin.logStr().c_str(), ac.login.c_str());
-
- return 0;
-}
-//-----------------------------------------------------------------------------
-void AdminsImpl::read()
-{
- std::vector<std::string> logins;
- if (m_store.GetAdminsList(&logins) < 0)
- {
- WriteServLog(m_store.GetStrError().c_str());
- return;
- }
-
- std::vector<Admin> admins;
- for (const auto& login : logins)
- {
- AdminConf ac(Priv(0), login, "");
-
- if (m_store.RestoreAdmin(&ac, login))
- {
- WriteServLog(m_store.GetStrError().c_str());
- return;
- }
-
- m_data.push_back(Admin(ac));
- }
-
- std::lock_guard<std::mutex> lock(m_mutex);
- m_data.swap(admins);
-}
-//-----------------------------------------------------------------------------
-bool AdminsImpl::find(const std::string& login, Admin** admin)
-{
- std::lock_guard<std::mutex> lock(m_mutex);
- if (m_data.empty())
- {
- printfd(__FILE__, "No admin in system!\n");
- if (admin != nullptr)
- *admin = &m_noAdmin;
- return false;
- }
-
- auto it = find(login);
-
- if (it != m_data.end())
- {
- if (admin != nullptr)
- *admin = &(*it);
- return false;
- }
-
- return true;
-}
-//-----------------------------------------------------------------------------
-bool AdminsImpl::exists(const std::string& login) const
-{
- std::lock_guard<std::mutex> lock(m_mutex);
- if (m_data.empty())
- {
- printfd(__FILE__, "No admin in system!\n");
- return true;
- }
-
- return find(login) != m_data.end();
-}
-//-----------------------------------------------------------------------------
-bool AdminsImpl::correct(const std::string& login, const std::string& password, Admin** admin)
-{
- std::lock_guard<std::mutex> lock(m_mutex);
- if (m_data.empty())
- {
- printfd(__FILE__, "No admin in system!\n");
- return true;
- }
-
- const auto it = find(login);
-
- if (it == m_data.end() || it->password() != password)
- return false;
-
- if (admin != nullptr)
- *admin = &(*it);
-
- return true;
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 27.10.2002
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/admins.h"
-#include "stg/admin.h"
-#include "stg/store.h"
-#include "stg/logger.h"
-
-#include <vector>
-#include <string>
-#include <algorithm>
-#include <mutex>
-
-namespace STG
-{
-
-class AdminsImpl : public Admins
-{
- public:
- explicit AdminsImpl(Store& st);
-
- AdminsImpl(const AdminsImpl&) = delete;
- AdminsImpl& operator=(const AdminsImpl&) = delete;
-
- int add(const std::string& login, const Admin& admin) override;
- int del(const std::string& login, const Admin& admin) override;
- int change(const AdminConf& ac, const Admin& admin) override;
- const Admin& sysAdmin() const override { return m_stg; }
- const Admin& noAdmin() const override { return m_noAdmin; }
- bool find(const std::string& login, Admin** admin) override;
- bool exists(const std::string& login) const override;
- bool correct(const std::string& login,
- const std::string& password,
- Admin** admin) override;
-
- const std::string& strError() const override { return m_strError; }
-
- size_t count() const override { return m_data.size(); }
-
- void fmap(std::function<void (const Admin&)> callback) const
- {
- for (const auto& admin : m_data)
- callback(admin);
- }
-
- private:
- void read();
- auto find(const std::string& login) { return std::find(m_data.begin(), m_data.end(), Admin(Priv(0), login, "")); }
- auto find(const std::string& login) const { return std::find(m_data.begin(), m_data.end(), Admin(Priv(0), login, "")); }
-
- Admin m_stg;
- Admin m_noAdmin;
- std::vector<Admin> m_data;
- Store& m_store;
- Logger& WriteServLog;
- mutable std::mutex m_mutex;
- std::string m_strError;
-};
-
-}
+++ /dev/null
-/*
- * 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 "corps_impl.h"
-
-#include "stg/admin.h"
-#include "stg/admin_conf.h"
-#include "stg/store.h"
-#include "stg/common.h"
-
-#include <algorithm>
-#include <cassert>
-
-using STG::CorporationsImpl;
-
-//-----------------------------------------------------------------------------
-CorporationsImpl::CorporationsImpl(Store * st)
- : store(st),
- WriteServLog(Logger::get()),
- handle(0)
-{
-Read();
-}
-//-----------------------------------------------------------------------------
-int CorporationsImpl::Add(const CorpConf & corp, const Admin * admin)
-{
-std::lock_guard<std::mutex> lock(mutex);
-const auto& priv = admin->priv();
-
-if (!priv.corpChg)
- {
- std::string s = admin->logStr() + " Add corporation \'" + corp.name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-crp_iter si(find(data.begin(), data.end(), corp));
-
-if (si != data.end())
- {
- strError = "Corporation \'" + corp.name + "\' cannot not be added. Corporation already exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
-
- return -1;
- }
-
-data.push_back(corp);
-
-if (store->AddCorp(corp.name) == 0)
- {
- WriteServLog("%s Corporation \'%s\' added.",
- admin->logStr().c_str(), corp.name.c_str());
- return 0;
- }
-
-strError = "Corporation \'" + corp.name + "\' was not added. Error: " + store->GetStrError();
-WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
-
-return -1;
-}
-//-----------------------------------------------------------------------------
-int CorporationsImpl::Del(const std::string & name, const Admin * admin)
-{
-std::lock_guard<std::mutex> lock(mutex);
-const auto& priv = admin->priv();
-
-if (!priv.corpChg)
- {
- std::string s = admin->logStr() + " Delete corporation \'" + name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-crp_iter si(find(data.begin(), data.end(), CorpConf(name)));
-
-if (si == data.end())
- {
- strError = "Corporation \'" + name + "\' cannot be deleted. Corporation does not exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
-std::map<int, const_crp_iter>::iterator csi;
-csi = searchDescriptors.begin();
-while (csi != searchDescriptors.end())
- {
- if (csi->second == si)
- (csi->second)++;
- ++csi;
- }
-
-data.erase(si);
-if (store->DelCorp(name) < 0)
- {
- strError = "Corporation \'" + name + "\' was not deleted. Error: " + store->GetStrError();
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
-
- return -1;
- }
-
-WriteServLog("%s Corporation \'%s\' deleted.", admin->logStr().c_str(), name.c_str());
-return 0;
-}
-//-----------------------------------------------------------------------------
-int CorporationsImpl::Change(const CorpConf & corp, const Admin * admin)
-{
-std::lock_guard<std::mutex> lock(mutex);
-const auto& priv = admin->priv();
-
-if (!priv.corpChg)
- {
- std::string s = admin->logStr() + " Change corporation \'" + corp.name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-crp_iter si(find(data.begin(), data.end(), corp));
-
-if (si == data.end())
- {
- strError = "Corporation \'" + corp.name + "\' cannot be changed " + ". Corporation does not exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
-*si = corp;
-if (store->SaveCorp(corp))
- {
- WriteServLog("Cannot write corporation %s.", corp.name.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- return -1;
- }
-
-WriteServLog("%s Corporation \'%s\' changed.",
- admin->logStr().c_str(), corp.name.c_str());
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-bool CorporationsImpl::Read()
-{
-std::lock_guard<std::mutex> lock(mutex);
-std::vector<std::string> corpsList;
-if (store->GetCorpsList(&corpsList) < 0)
- {
- WriteServLog(store->GetStrError().c_str());
- return true;
- }
-
-for (size_t i = 0; i < corpsList.size(); i++)
- {
- CorpConf corp;
-
- if (store->RestoreCorp(&corp, corpsList[i]))
- {
- WriteServLog(store->GetStrError().c_str());
- return true;
- }
-
- data.push_back(corp);
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-bool CorporationsImpl::Find(const std::string & name, CorpConf * corp)
-{
-assert(corp != NULL && "Pointer to corporation is not null");
-
-std::lock_guard<std::mutex> lock(mutex);
-if (data.empty())
- return false;
-
-crp_iter si(find(data.begin(), data.end(), CorpConf(name)));
-
-if (si != data.end())
- {
- *corp = *si;
- return false;
- }
-
-return true;
-}
-//-----------------------------------------------------------------------------
-bool CorporationsImpl::Exists(const std::string & name) const
-{
-std::lock_guard<std::mutex> lock(mutex);
-if (data.empty())
- {
- printfd(__FILE__, "no corporations in system!\n");
- return true;
- }
-
-const_crp_iter si(find(data.begin(), data.end(), CorpConf(name)));
-
-if (si != data.end())
- return true;
-
-return false;
-}
-//-----------------------------------------------------------------------------
-int CorporationsImpl::OpenSearch() const
-{
-std::lock_guard<std::mutex> lock(mutex);
-handle++;
-searchDescriptors[handle] = data.begin();
-return handle;
-}
-//-----------------------------------------------------------------------------
-int CorporationsImpl::SearchNext(int h, CorpConf * corp) const
-{
-std::lock_guard<std::mutex> lock(mutex);
-if (searchDescriptors.find(h) == searchDescriptors.end())
- {
- WriteServLog("CORPORATIONS. Incorrect search handle.");
- return -1;
- }
-
-if (searchDescriptors[h] == data.end())
- return -1;
-
-*corp = *searchDescriptors[h]++;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int CorporationsImpl::CloseSearch(int h) const
-{
-std::lock_guard<std::mutex> lock(mutex);
-if (searchDescriptors.find(h) != searchDescriptors.end())
- {
- searchDescriptors.erase(searchDescriptors.find(h));
- return 0;
- }
-
-WriteServLog("CORPORATIONS. Incorrect search handle.");
-return -1;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/corporations.h"
-#include "stg/corp_conf.h"
-#include "stg/locker.h"
-#include "stg/logger.h"
-
-#include <vector>
-#include <map>
-#include <string>
-#include <mutex>
-
-namespace STG
-{
-
-struct Admin;
-struct Store;
-
-class CorporationsImpl : public Corporations {
-public:
- explicit CorporationsImpl(Store* st);
-
- int Add(const CorpConf& corp, const Admin* admin) override;
- int Del(const std::string& name, const Admin* admin) override;
- int Change(const CorpConf& corp, const Admin* admin) override;
- bool Find(const std::string& name, CorpConf* corp) override;
- bool Exists(const std::string& name) const override;
- const std::string& GetStrError() const override { return strError; }
-
- size_t Count() const override { return data.size(); }
-
- int OpenSearch() const override;
- int SearchNext(int, CorpConf* corp) const override;
- int CloseSearch(int) const override;
-
-private:
- typedef std::vector<CorpConf>::iterator crp_iter;
- typedef std::vector<CorpConf>::const_iterator const_crp_iter;
-
- bool Read();
-
- std::vector<CorpConf> data;
- Store* store;
- Logger& WriteServLog;
- mutable std::map<int, const_crp_iter> searchDescriptors;
- mutable unsigned int handle;
- mutable std::mutex mutex;
- std::string strError;
-};
-
-}
+++ /dev/null
-#include <csignal>
-#include <cerrno>
-#include <cstring>
-
-#include "stg/locker.h"
-#include "stg/common.h"
-#include "eventloop.h"
-
-EVENT_LOOP::EVENT_LOOP()
- : ACTIONS_LIST(),
- _running(false),
- _stopped(true),
- _tid(),
- _mutex(),
- _condition()
-{
-pthread_mutex_init(&_mutex, NULL);
-pthread_cond_init(&_condition, NULL);
-}
-
-EVENT_LOOP::~EVENT_LOOP()
-{
-pthread_cond_destroy(&_condition);
-pthread_mutex_destroy(&_mutex);
-}
-
-bool EVENT_LOOP::Start()
-{
-_running = true;
-if (pthread_create(&_tid, NULL, Run, this))
- {
- printfd(__FILE__, "EVENT_LOOP::Start - Failed to create thread: '%s'\n", strerror(errno));
- return true;
- }
-return false;
-}
-
-bool EVENT_LOOP::Stop()
-{
-_running = false;
-// Wake up thread
-pthread_cond_signal(&_condition);
-// Wait until thread exit
-pthread_join(_tid, NULL);
-return false;
-}
-
-void * EVENT_LOOP::Run(void * self)
-{
-EVENT_LOOP * ev = static_cast<EVENT_LOOP *>(self);
-ev->Runner();
-return NULL;
-}
-
-void EVENT_LOOP::Runner()
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-_stopped = false;
-printfd(__FILE__, "EVENT_LOOP::Runner - Before start\n");
-while (_running)
- {
- {
- STG_LOCKER lock(&_mutex);
- // Check for any actions...
- if (empty())
- {
- // ... and sleep until new actions added
- printfd(__FILE__, "EVENT_LOOP::Runner - Sleeping until new actions arrived\n");
- pthread_cond_wait(&_condition, &_mutex);
- }
- // Check for running after wake up
- if (!_running)
- {
- // Don't process any actions if stopping
- break;
- }
- }
- // Create new empty actions list
- ACTIONS_LIST local;
- // Fast swap with current
- swap(local);
- // Invoke all current actions
- printfd(__FILE__, "EVENT_LOOP::Runner - Invoke %d actions\n", local.size());
- local.InvokeAll();
- }
-printfd(__FILE__, "EVENT_LOOP::Runner - Before stop\n");
-_stopped = true;
-}
-
-namespace {
-
-pthread_mutex_t singletonMutex;
-
-}
-
-EVENT_LOOP & EVENT_LOOP_SINGLETON::GetInstance()
-{
-// Double-checking technique
-if (!_instance)
- {
- STG_LOCKER lock(&singletonMutex);
- if (!_instance)
- {
- CreateInstance();
- }
- }
-return *_instance;
-}
-
-void EVENT_LOOP_SINGLETON::CreateInstance()
-{
-static EVENT_LOOP loop;
-_instance = &loop;
-}
-
-EVENT_LOOP * EVENT_LOOP_SINGLETON::_instance = NULL;
+++ /dev/null
-#ifndef __EVENT_LOOP_H__
-#define __EVENT_LOOP_H__
-
-#include <pthread.h>
-
-#include "stg/noncopyable.h"
-#include "actions.h"
-
-class EVENT_LOOP : private NONCOPYABLE,
- private ACTIONS_LIST
-{
- public:
- bool Start();
- bool Stop();
- bool IsRunning() const { return _running; }
-
- template <class ACTIVE_CLASS, typename DATA_TYPE>
- void Enqueue(ACTIVE_CLASS & ac,
- typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
- DATA_TYPE d);
-
- private:
- bool _running;
- bool _stopped;
- pthread_t _tid;
- pthread_mutex_t _mutex;
- pthread_cond_t _condition;
-
- EVENT_LOOP();
- virtual ~EVENT_LOOP();
-
- static void * Run(void *);
- void Runner();
-
- friend class EVENT_LOOP_SINGLETON;
-};
-
-class EVENT_LOOP_SINGLETON : private NONCOPYABLE
-{
- public:
- static EVENT_LOOP & GetInstance();
-
- private:
- static EVENT_LOOP * _instance;
- static void CreateInstance();
-
- EVENT_LOOP_SINGLETON() {}
- ~EVENT_LOOP_SINGLETON() {}
-};
-
-template <class ACTIVE_CLASS, typename DATA_TYPE>
-void EVENT_LOOP::Enqueue(ACTIVE_CLASS & ac,
- typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
- DATA_TYPE d)
-{
-STG_LOCKER lock(&_mutex);
-// Add new action
-ACTIONS_LIST::Enqueue(ac, a, d);
-// Signal about new action
-pthread_cond_signal(&_condition);
-}
-
-#endif
+++ /dev/null
-#! /bin/sh
-
-login=$1
-param=$2
-oldValue=$3
-newValue=$4
-
-#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
\ No newline at end of file
+++ /dev/null
-#! /bin/sh
-
-#Этот скрипт вызывается в момент, когда пользователь
-#успешно прошел авторизацию на сервере. Задача скрипта - перестроить
-#файрвол так, что бы пользователь получил доступ в интернет
-
-# Login
-LOGIN=$1
-
-#user IP
-IP=$2
-
-#cash
-CASH=$3
-
-#user ID
-ID=$4
-
-#Selected dirs to connect
-DIRS=$5
-
-
-#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
-
+++ /dev/null
-#! /bin/sh
-
-# Этот скрипт вызывается в момент, когда пользователь
-# желает отключится от интернета или вышел таймаут у пользователя
-# и сервер сам отключает пользователя
-# Задача скрипта подобна задаче скрипта OnConnect - перестроить
-# файрвол так, что бы пользователю закрыть доступ в интернет
-
-# Login
-LOGIN=$1
-
-#user IP
-IP=$2
-
-#cash
-CASH=$3
-
-#user ID
-ID=$4
-
-#Selected dirs to disconnect
-DIRS=$5
-
-#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+++ /dev/null
-#! /bin/sh
-
-# Использование (неиспользование) этого скрипта дело вкуса.
-# Он не выполняет критических функций. Его задача автматизировать
-# действия характерные при добавлении пользователя сети, например добавлекние
-# пользователю почты
-
-# Login
-login=$1
-
-#echo "added user $login" >> /var/stargazer/add_del.log
-
-
-
+++ /dev/null
-#! /bin/sh
-
-# Login
-login=$1
-
-#echo "deleted user $login" >> /var/stargazer/add_del.log
-
+++ /dev/null
-# Enable the authorization module Always Online "mod_auth_ao.so"
-<Module auth_ao>
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the traffic capture module "mod_cap_ipq.so" using Berkeley Packet Filter
-<Module cap_bpf>
- # Define interface(s) for traffic capture
- iface = rl0
- iface = rl1
- iface = dc0
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the traffic capture module "mod_cap_divert.so" using Divert-sockets
-<Module cap_divert>
- # Port for traffic
- # Parameter: optional
- # Value: 1 ... 65535
- # Default: 15701
- Port = 15701
-
- # Disable packet forwarding
- # Parameter: optional
- # Value: yes, no
- # Default: no
- DisableForwarding = no
-</Module>
+++ /dev/null
-# Enable the traffic capture module "mod_cap_ipq.so" using NetFlow protocol
-<Module cap_nf>
- # Port for TCP connections
- # Note: Parameters TCPPort and UDPPort can be equal
- # Parameter: optional
- # Value: 1 ... 65535
- # Default: 9996
- #TCPPort = 9996
-
- # Port for UDP connections
- # Note: Parameters TCPPort and UDPPort can be equal
- # Parameter: optional
- # Value: 1 ... 65535
- # Default: 9996
- UDPPort = 9996
-</Module>
+++ /dev/null
-# Enable the authorization module InetAccess "mod_auth_ia.so"
-<Module auth_ia>
- # Port on which the server interacts with authorizator
- # Parameter: required
- # Value: 1 ... 65535
- # Default: 5555
- Port = 5555
-
- # The time interval between sending an alive query to the user
- # and updating statistics
- # Parameter: required
- # Values: 5 ... 600 (seconds)
- # Default: 60
- UserDelay = 60
-
- # User timeout. If authorizer does not respond during this time,
- # the user will be disconnected
- # Parameter: required
- # Values: 5 ... 600
- # Default: 60
- UserTimeout = 65
-
- # Define which information will be transmitted from the server to InetAccess
- # as a residue of prepaid traffic
- # FreeMb = 0 — amount of free megabytes in terms of cost of zero direction
- # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
- # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
- # FreeMb = 2 — amount of free megabytes in terms of cost of the second direction
- # ........................
- # FreeMb = 9 — amount of free megabytes in terms of cost of the ninth direction
- # FreeMb = cash - amount of money for which the user can download for free
- # FreeMb = none - no transfer
- # Default: cash
- # Parameter: required
- # Values: different, see above
- # Default: cash
- FreeMb = cash
-
- # Enable protocol errors logging
- # Parameter: optional
- # Values: yes, no
- # Default: no
- # LogProtocolErrors = no
-</Module>
+++ /dev/null
-# Enable the module that pings users "mod_ping.so"
-<Module ping>
- # The time interval between pings
- # Parameter: required
- # Value: 10 ... 3600 (seconds)
- # Default: 15
- PingDelay = 15
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the interaction module for FreeRADIUS "mod_radius.so"
-<Module radius>
- # FreeRADIUS password
- # Parameter: required
- # Values: any, supported by software
- # Default: 123456
- Password = 123456
-
- # FreeRADIUS server
- # Parameter: required
- # Values: IP address or DNS name
- # Default: 127.0.0.1
- ServerIP = 127.0.0.1
-
- # FreeRADIUS port
- # Parameter: required
- # Value: 1 ... 65535
- # Default: 6666
- Port = 6666
-
- # List of services for which will be carried out FreeRADIUS authentication
- # Note: Parameter can be blank
- # Parameter: required
- # Value: any, supported by software
- # Default: Login-User
- AuthServices = Login-User
-
- # List of services for which will be carried out FreeRADIUS Accounting
- # Note: Parameter can be blank
- # Parameter: required
- # Value: any, supported by software
- # Default: Framed-User
- AcctServices = Framed-User
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the module for remote execution of scripts OnConnect and OnDisconnect "mod_remote_script.so"
-<Module remote_script>
- # The time interval between sending confirmations that the user is online
- # Parametr: required
- # Values: 10 ... 600 (seconds)
- # Default: 60
- SendPeriod = 15
-
- # Define mapping between subnet(s) and remote server(s)
- # File format: <subnet> <Router1> <Router2> ...
- # Example:
- # 192.168.1.0/24 192.168.1.7 192.168.1.8
- # 192.168.2.0/24 192.168.2.5 192.168.2.6 192.168.2.7
- # 192.168.3.0/24 192.168.3.5
- # 192.168.4.0/24 192.168.4.5
- # Parametr: required
- # Values: file path
- # Default: subnets
- SubnetFile = subnets
-
- # The password to encrypt packets between the stg-server and remote server
- # Parameter: required
- # Values: any
- # Default: 123456
- Password = 123456
-
- # Define which user parameters are transferred to a remote server in addition to
- # other parameters that transfered by default (ID, IP, Login, Cash, Dirs).
- # Note: Parameter can be blank.
- # Parameter: required
- # Values: Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName,
- # NextTariff, Address, Note, Group, Email, RealName, Credit, EnabledDirs,
- # Userdata0...Userdata9
- # Default: Cash Tariff EnabledDirs
- UserParams = Cash Tariff EnabledDirs
-
- # Port on which the server interacts with remote server
- # Parameter: required
- # Value: 1...65535
- # Default: 9999
- Port = 9999
-</Module>
+++ /dev/null
-# Enable the configuration module ConfRPC "mod_conf_rpc.so"
-<Module conf_rpc>
- # Port on which the server interacts with configurator
- # Parameter: required
- # Value: 1...65535
- # Default:
- Port = 8080
-
- # Session timeout in seconds
- # Parameter: required
- # Value: positive integer
- # Default: 1800
- CookieTimeout = 1800
-</Module>
+++ /dev/null
-# Enable the configuration module SgConfig "mod_conf_sg.so"
-<Module conf_sg>
- # Port on which the server interacts with configurator
- # Parameter: required
- # Value: 1...65535
- # Default: 5555
- Port = 5555
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enables SMUX-peer for SNMPd.
-<Module smux>
- # IP-address of a server to connect to
- # Parameter: required
- # Value: X.X.X.X
- # Default: 127.0.0.1
- Server = 127.0.0.1
-
- # Port number on a server to connect to
- # Parameter: required
- # Value: 1 ... 65535
- # Default: 199
- Port = 199
-
- # Password for authentication on a server
- # Parameter: required
- # Value: any text
- Password =
-</Module>
+++ /dev/null
-# Enables plain file backend.
-<StoreModule store_files>
-
- # Working server directory, provides data on tariffs, users, administrators.
- # Parameter: required
- # Value: directory path
- WorkDir = /var/stargazer
-
- # Owner, group and permissions of the files of user statistics (stat)
- # Parameter: required
- # Values: any, supported by OS
- ConfOwner = root
- ConfGroup = root
- ConfMode = 640
-
- # Owner, group and permissions on user configuration files (conf)
- # Parameter: required
- # Values: any, supported by OS
- StatOwner = root
- StatGroup = root
- StatMode = 640
-
- # Owner, group and permissions for user log files (log)
- # Parameter: required
- # Values: any, supported by OS
- UserLogOwner = root
- UserLogGroup = root
- UserLogMode = 640
-
-</StoreModule>
+++ /dev/null
-# Enables Firebird backend.
-<StoreModule store_firebird>
- # Database server address
- # Parameter: optional
- # Value: IP address or DNS name
- # Default: localhost
- # Server = localhost
-
- # Path to the database on the server or its alias
- # Parameter: optional
- # Value: file path
- # Default: /var/stg/stargazer.fdb
- # Database = /var/stg/stargazer.fdb
-
- # Database username
- # Parameter: optional
- # Value: any, supported by database
- # Default: stg
- # User = stg
-
- # Database password
- # Parameter: optional
- # Value: any, supported by database
- # Default: 123456
- # Password = 123456
-
- # The transaction isolation level
- # Parameter: optional
- # Values: concurrency, dirtyread, readcommitted, consistency
- # Defalt: concurrency
- # IsolationLevel = concurrency
-
- # Responding to lock (optional, defaults to wait):
- # Parameter: optional
- # Values: wait, nowait
- # Defalt: wait
- # LockResolution = wait
-</StoreModule>
+++ /dev/null
-# Enables MySQL backend.
-<StoreModule store_mysql>
- # Database server address
- # Parameter: required
- # Value: IP address or DNS name
- # Default: localhost
- Server = localhost
-
- # Database name
- # Parameter: required
- # Value: any, supported by database
- # Default: stg
- Database = stg
-
- # Database username
- # Parameter: required
- # Value: any, supported by database
- # Default: stg
- User = stg
-
- # Database password
- # Parameter: required
- # Value: any, supported by database
- # Default: 123456
- Password = 123456
-</StoreModule>
+++ /dev/null
-# Enables PostgreSQL backend.
-<StoreModule store_postgresql>
- # Database server address
- # Parameter: optional
- # Value: IP address or DNS name
- # Default: localhost
- # Server = localhost
-
- # Database name
- # Parameter: optional
- # Value: any, supported by database
- # Default: stargazer
- # Database = stargazer
-
- # Database username
- # Parameter: optional
- # Value: any, supported by database
- # Default: stg
- # User = stg
-
- # Database password
- # Parameter: optional
- # Value: any, supported by database
- # Default: 123456
- # Password = 123456
-
- # Number of tries to reconnect
- # Parameter: optional
- # Value: positive integer
- # Default: 3
- # Retries = 3
-</StoreModule>
+++ /dev/null
-../conf-available.d/mod_ao.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_cap_bpf.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_ia.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_ping.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_sg.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/store_files.conf
\ No newline at end of file
+++ /dev/null
-ALL 192.168.0.0/16 DIR1
-ALL 10.0.0.0/8 DIR2
-ALL 0.0.0.0/0 DIR0
\ No newline at end of file
+++ /dev/null
-################################################################################
-# Stargazer Configuration file #
-################################################################################
-
-# LOG file name
-# Parameter: required
-# Value: file path
-# Default: /var/log/stargazer.log
-LogFile = /var/log/stargazer.log
-
-# PID file name
-# Parameter: optional
-# Value: file path
-# Default: /var/run/stargazer.pid
-PIDFile = /var/run/stargazer.pid
-
-# Traffic classification rules
-# Parameter: required
-# Value: file path
-# Default: /etc/stargazer/rules
-Rules = /etc/stargazer/rules
-
-# The time interval between writing detailed user's statistics into the database
-# Note: With a large number of users this value should be increased,
-# since writting into the database can take a long time.
-# Parameter: required
-# Values: 1 (hourly), 1/2 (every half hour), 1/4 (every 15 m), 1/6 (every 10 m)
-# Default: 1/2
-DetailStatWritePeriod = 1/2
-
-# The time interval between writing summary user's statistics into the database
-# Parameter: optional
-# Value: 1 ... 1440 (minutes)
-# Default: 10
-StatWritePeriod = 10
-
-# Day of charging fee
-# Note: 0 - The last day of the month
-# Parameter: required
-# Value: 0 ... 31
-# Default: 1
-DayFee = 1
-
-# When set to 'no' Stargazer will continue reading database after error and show all of them.
-# Parameter: optional
-# Values: yes, no
-# Default: yes
-# StopOnError = yes
-
-# Fee charged at the last (yes) or first (no) day of tariffication period.
-# Defines how the fee will be charged in the transition to the new tariff.
-# User has tariff A with fee 100. Changing it to tariff B with fee 200
-# will result in charging user's account at 100 if DayFeeIsLastDay = yes
-# and at 200, if DayFeeIsLastDay = no
-# Parameter: required
-# Values: yes, no
-# Default: no
-DayFeeIsLastDay = no
-
-# Day of changing delayed tariffs and resetting summary user's statistics.
-# Defines the edge of the tariffication period.
-# Parameter: required
-# Value: 0 ... 31. 0 - The last day of the month
-# Default: 1
-DayResetTraff = 1
-
-# Defines whether to charge fee daily (yes) or monthly (no)
-# Parameter: required
-# Values: yes, no
-# Default: no
-SpreadFee = no
-
-# Defines whether the user can access the internet if it has no cash,
-# but remained prepaid traffic
-# Parameter: required
-# Values: yes, no
-# Default: no
-FreeMbAllowInet = no
-
-# Defines what will be written in the traffic cost in detail_stat.
-# If user still has the prepaid traffic and WriteFreeMbTraffCost = no,
-# then the traffic cost willn't be written in detail_stat.
-# If user doestn't have prepaid traffic and WriteFreeMbTraffCost = no,
-# then the traffic cost will be written in detail_stat.
-# When WriteFreeMbTraffCost = yes the traffic cost will be recorded in any case.
-# Parameter: required
-# Values: yes, no
-# Default: yes
-WriteFreeMbTraffCost = yes
-
-# Charge a full monthly fee even if user was "frozen" a part
-# of the tariffication period
-# Parameter: optional
-# Values: yes, no
-# Default: no
-FullFee = no
-
-# Allow user to see and use a full cash (yes) or hide a part of it (no)
-# for the next fee charge
-# Parameter: optional
-# Values: yes, no
-# Default: yes
-# ShowFeeInCash=yes
-
-# The names of directions. Direction without names will not appear in
-# authorizer and configurator.
-# Note: Names consisting of several words should be quoted
-# Parameter: optional
-# Values:
-<DirNames>
- DirName0 = Internet
- DirName1 =
- DirName2 =
- DirName3 =
- DirName4 =
- DirName5 =
- DirName6 =
- DirName7 =
- DirName8 =
- DirName9 =
-</DirNames>
-
-# Amount of stg-exec processes.
-# These processes are responsible for the execution of scripts OnConnect,
-# OnDisconnect, etc.
-# Amount of processes means how many scripts can be executed simultaneously.
-# Recommend to leave 1 to avoid errors when executing scripts
-# Parameter: optional
-# Value: 1 ... 1024
-# Default: 1
-ExecutersNum = 1
-
-# Message queue identifier for the script executer.
-# It may be changed if there're a needs to run multiple copies of stargazer.
-# Warning: If you do not understand it, do not touch this setting!
-# Parameter: optional
-# Value: 0 ... 2 ^ 32
-# Default: 5555
-# ExecMsgKey = 5555
-
-# The path to directory with server modules
-# Parameter: required
-# Value: directory path
-# Default: /usr/lib/stg
-ModulesPath = /usr/lib/stg
-
-# Directory where the "monitor" files are located.
-# A blank files will be created in this directory. The modification time of such
-# files will be changed about once a minute. If server crashes or some of server
-# component hang, the files will stop refreshing, and on this basis we can define
-# the failure of the server and if necessary restart.
-# If option is omitted or blank, the monitoring is not performed.
-# Parameter: optional
-# Value: file path
-# Default: /var/stargazer/monitor
-#MonitorDir=/var/stargazer/monitor
-
-# Defines message maximum lifetime
-# Note: 0 - unlimited
-# Parameter: optional
-# Value: any numeric
-# Default: 0 (day)
-# MessagesTimeout = 0
-
-# Defines fee charging rules.
-# 0 - classic rules, allow fee charge even cash is negative;
-# 1 - disallow fee charge if cash value is negative;
-# 2 - disallow fee charge if there is not enought cash (cash < fee).
-# Parameter: optional
-# Value: 0 ... 2
-# Default: 0 (classic)
-# FeeChargeType = 0
-
-# Enable or disable reconnect on tariff change
-# Parameter: optional
-# Values: yes, no
-# Default: no
-# ReconnectOnTariffChange = no
-
-# Definest set of parameters passed to OnConnect and OnDisconnect scripts
-# This set is added to the end of the default param list, which are, respectively:
-# login, ip, cash, id, dirs
-# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
-# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
-# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
-# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
-# "userdata0" ... "userdata9".
-# Parameter: optional
-# Values: parameter names, case insensitive
-# Default:
-# ScriptParams =
-
-# Enable or disable writing session log
-# Parameter: optional
-# Values: yes, no
-# Default: no (session log is enabled)
-# DisableSessionLog = no
-
-# Filter for logging parameter changes
-# Defines which parameters will be logged to parameter log in database. Allows
-# to specify multiuple parameter names or asterisk (*), which means "log all params".
-# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
-# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
-# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
-# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
-# "userdata0" ... "userdata9".
-# Parameter: optional
-# Values: parameter names, case insensitive, or "*"
-# Default: *
-# FilterParamsLog = *
-
-################################################################################
-# Store module
-# Configure the module that works with the database server
-
-# Warning: Only one store module could be used at the same time!
-
-<IncludeFile "conf-enabled.d/store_*.conf">
-</IncludeFile>
-
-
-################################################################################
-# Other modules
-
-<Modules>
-
- <IncludeFile "conf-enabled.d/mod_*.conf">
- </IncludeFile>
-
-</Modules>
-################################################################################
+++ /dev/null
-#!/sbin/runscript
-
-extra_commands="reload"
-
-DAEMON=/usr/sbin/stargazer
-STARGAZER_OPTS=""
-PIDFILE=/var/run/stargazer.pid
-
-depend() {
- need net
- use postgresql firebird mysql
- provide stargazer
-}
-
-start() {
- ebegin "Starting stargazer"
- start-stop-daemon --start --quiet --pidfile ${PIDFILE} --exec ${DAEMON} -- ${STARGAZER_OPTS}
- eend $?
-}
-
-stop() {
- ebegin "Stopping stargazer"
- start-stop-daemon --stop --quiet --pidfile ${PIDFILE} --retry=INT/120/KILL/5
- rm -f ${PIDFILE}
- eend $?
-}
-
-reload() {
- ebegin "Reloading stargazer rules"
- start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE
- return 0
- eend $?
-}
+++ /dev/null
-#!/bin/bash
-#
-# processname: stargazer
-# config: /etc/stargazer/stargazer.conf
-# pidfile: /var/run/stargazer.pid
-
-# Source function library.
-. /etc/init.d/functions
-
-# Source networking configuration.
-. /etc/sysconfig/network
-
-# Source stargazer configureation.
-DAEMON=yes
-QUEUE=1h
-
-# Check that networking is up.
-[ ${NETWORKING} = "no" ] && exit 0
-
-[ -f /sbin/stargazer ] || exit 0
-
-RETVAL=0
-prog="stargazer"
-
-start() {
- # Start daemons.
-
- echo -n $"Starting $prog: "
- /etc/stargazer/first 2> /dev/null
- daemon /sbin/stargazer
- RETVAL=$?
- /etc/stargazer/last 2> /dev/null
- echo
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/stargazer
- return $RETVAL
-}
-
-stop() {
- # Stop daemons.
- echo -n $"Shutting down $prog: "
- killproc stargazer
- RETVAL=$?
- echo
- [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/stargazer
- return $RETVAL
-}
-
-# See how we were called.
-case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart|reload)
- stop
- start
- RETVAL=$?
- ;;
- status)
- status stargazer
- RETVAL=$?
- ;;
- *)
- echo $"Usage: $0 {start|stop|restart|status}"
- exit 1
-esac
-
-exit $RETVAL
+++ /dev/null
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: stargazer
-# Required-Start: $local_fs $remote_fs
-# Required-Stop: $local_fs $remote_fs
-# Default-Start: 2 3 4 5
-# Default-Stop: S 0 1 6
-# Short-Description: Stargazer initscript
-# Description: This file should be used to start and stop stargazer daemon
-### END INIT INFO
-
-# Author: Boris Mikhailenko <stg34@stg.dp.ua>
-
-# Do NOT "set -e"
-
-# PATH should only include /usr/* if it runs after the mountnfs.sh script
-PATH=/usr/sbin:/usr/bin:/sbin:/bin
-DESC="Billing system"
-NAME=stargazer
-DAEMON=/usr/sbin/$NAME
-DAEMON_ARGS=""
-PIDFILE=/var/run/$NAME.pid
-SCRIPTNAME=/etc/init.d/$NAME
-
-# Exit if the package is not installed
-[ -x "$DAEMON" ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/$NAME ] && . /etc/default/$NAME
-
-# Load the VERBOSE setting and other rcS variables
-[ -f /etc/default/rcS ] && . /etc/default/rcS
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
-. /lib/lsb/init-functions
-
-#
-# Function that starts the daemon/service
-#
-do_start()
-{
- # Return
- # 0 if daemon has been started
- # 1 if daemon was already running
- # 2 if daemon could not be started
- start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
- || return 1
-
- # ps x | grep $DAEMON | grep -v grep | cut -f1 -d" " > $PIDFILE
-
- start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
- $DAEMON_ARGS \
- || return 2
-
- # ps x | grep $DAEMON | grep -v grep | cut -f1 -d" " > $PIDFILE
- # Add code here, if necessary, that waits for the process to be ready
- # to handle requests from services started subsequently which depend
- # on this one. As a last resort, sleep for some time.
-}
-
-#
-# Function that stops the daemon/service
-#
-do_stop()
-{
- # Return
- # 0 if daemon has been stopped
- # 1 if daemon was already stopped
- # 2 if daemon could not be stopped
- # other if a failure occurred
- start-stop-daemon --stop --quiet --retry=INT/60/KILL/5 --pidfile $PIDFILE --name $NAME
- RETVAL="$?"
- [ "$RETVAL" = 2 ] && return 2
- # Wait for children to finish too if this is a daemon that forks
- # and if the daemon is only ever run from this initscript.
- # If the above conditions are not satisfied then add some other code
- # that waits for the process to drop all resources that could be
- # needed by services started subsequently. A last resort is to
- # sleep for some time.
- start-stop-daemon --stop --quiet --oknodo --retry=0/60/KILL/5 --exec $DAEMON
- [ "$?" = 2 ] && return 2
- # Many daemons don't delete their pidfiles when they exit.
- rm -f $PIDFILE
- return "$RETVAL"
-}
-
-#
-# Function that sends a SIGHUP to the daemon/service
-#
-do_reload() {
- # If the daemon can reload its configuration without
- # restarting (for example, when it is sent a SIGHUP),
- # then implement that here.
- start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
- return 0
-}
-
-case "$1" in
- start)
- [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
- do_start
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- stop)
- [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- reload)
- # If do_reload() is not implemented then leave this commented out
- # and leave 'force-reload' as an alias for 'restart'.
- log_daemon_msg "Reloading $DESC" "$NAME"
- do_reload
- log_end_msg $?
- ;;
- restart)
- #
- # If the "reload" option is implemented then remove the
- # 'force-reload' alias
- #
- log_daemon_msg "Restarting $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1)
- do_start
- case "$?" in
- 0) log_end_msg 0 ;;
- 1) log_end_msg 1 ;; # Old process is still running
- *) log_end_msg 1 ;; # Failed to start
- esac
- ;;
- *)
- # Failed to stop
- log_end_msg 1
- ;;
- esac
- ;;
- *)
- #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
- echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
- exit 3
- ;;
-esac
-
-:
+++ /dev/null
-#! /bin/sh
-
-# About: This script is called when user account is changed.
-# Common Task: Notify about various events.
-# Priority: optional
-
-# User login
-LOGIN=$1
-
-# User parameter
-PARAMETER=$2
-
-# User parameter old value
-OLDVALUE=$3
-
-# User parameter new value
-NEWVALUE=$4
-
-# Usage examples:
-#echo "User: '$LOGIN'. Parameter $PARAMETER changed from '$OLDVALUE' to '$NEWVALUE'" >> /var/stargazer/user.change.log
\ No newline at end of file
+++ /dev/null
-#! /bin/sh
-
-# About: This script is called when the user successfully authenticated on the server.
-# Common Task: Rebuild firewall to allow user to access the Internet.
-# Priority: required
-
-# User login
-LOGIN=$1
-
-# User IP
-IP=$2
-
-# User cash
-CASH=$3
-
-# User ID
-ID=$4
-
-# Selected DIRs (from rules file) to connect
-DIRS=$5
-
-# Usage examples:
-#echo "Connected `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
\ No newline at end of file
+++ /dev/null
-#! /bin/sh
-
-# About: This script is called when the user wants to disconnect or authorization timeout has passed.
-# Common task: Rebuild firewall to disallow user to access the Internet.
-# Priority: required
-
-# User login
-LOGIN=$1
-
-# User IP
-IP=$2
-
-# User cash
-CASH=$3
-
-# User ID
-ID=$4
-
-# Selected DIRs (from rules file) to disconnect
-DIRS=$5
-
-# Usage examples:
-#echo "Disconnected `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+++ /dev/null
-#! /bin/sh
-
-# About: This script is called when the user is added to the Stargazer.
-# Common task: Automate typical actions on adding user to the network,
-# such as creating email or IM account.
-# Priority: optional
-
-# User login
-LOGIN=$1
-
-# Usage examples:
-#echo "Added user $login" >> /var/stargazer/add_del.log
\ No newline at end of file
+++ /dev/null
-#! /bin/sh
-
-# About: This script is called when the user is removed from the Stargazer.
-# Common task: Automate typical actions on removing user from the network,
-# such as removing email or IM account.
-# Priority: optional
-
-# User login
-LOGIN=$1
-
-# Usage examples:
-#echo "Deleted user $LOGIN" >> /var/stargazer/add_del.log
-
+++ /dev/null
-# Enable the authorization module Always Online "mod_auth_ao.so"
-<Module auth_ao>
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the traffic capture module "mod_cap_ether.so" using Packet-sockets
-<Module cap_ether>
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the traffic capture module "mod_cap_ipq.so" using mechanism of IP Queueing
-<Module cap_ipq>
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the traffic capture module "mod_cap_ipq.so" using NetFlow protocol
-<Module cap_nf>
- # Port for TCP connections
- # Note: Parameters TCPPort and UDPPort can be equal
- # Parameter: optional
- # Value: 1 ... 65535
- # Default: 9996
- #TCPPort = 9996
-
- # Port for UDP connections
- # Note: Parameters TCPPort and UDPPort can be equal
- # Parameter: optional
- # Value: 1 ... 65535
- # Default: 9996
- UDPPort = 9996
-</Module>
+++ /dev/null
-# Enable the authorization module InetAccess "mod_auth_ia.so"
-<Module auth_ia>
- # Port on which the server interacts with authorizator
- # Parameter: required
- # Value: 1 ... 65535
- # Default: 5555
- Port = 5555
-
- # The time interval between sending an alive query to the user
- # and updating statistics
- # Parameter: required
- # Values: 5 ... 600 (seconds)
- # Default: 60
- UserDelay = 60
-
- # User timeout. If authorizer does not respond during this time,
- # the user will be disconnected
- # Parameter: required
- # Values: 5 ... 600
- # Default: 60
- UserTimeout = 65
-
- # Define which information will be transmitted from the server to InetAccess
- # as a residue of prepaid traffic
- # FreeMb = 0 — amount of free megabytes in terms of cost of zero direction
- # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
- # FreeMb = 1 — amount of free megabytes in terms of cost of the first direction
- # FreeMb = 2 — amount of free megabytes in terms of cost of the second direction
- # ........................
- # FreeMb = 9 — amount of free megabytes in terms of cost of the ninth direction
- # FreeMb = cash - amount of money for which the user can download for free
- # FreeMb = none - no transfer
- # Default: cash
- # Parameter: required
- # Values: different, see above
- # Default: cash
- FreeMb = cash
-
- # Enable protocol errors logging
- # Parameter: optional
- # Values: yes, no
- # Default: no
- # LogProtocolErrors = no
-</Module>
+++ /dev/null
-# Enable the module that pings users "mod_ping.so"
-<Module ping>
- # The time interval between pings
- # Parameter: required
- # Value: 10 ... 3600 (seconds)
- # Default: 15
- PingDelay = 15
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the interaction module for FreeRADIUS "mod_radius.so"
-<Module radius>
- # FreeRADIUS password
- # Parameter: required
- # Values: any, supported by software
- # Default: 123456
- Password = 123456
-
- # FreeRADIUS server
- # Parameter: required
- # Values: IP address or DNS name
- # Default: 127.0.0.1
- ServerIP = 127.0.0.1
-
- # FreeRADIUS port
- # Parameter: required
- # Value: 1 ... 65535
- # Default: 6666
- Port = 6666
-
- # List of services for which will be carried out FreeRADIUS authentication
- # Note: Parameter can be blank
- # Parameter: required
- # Value: any, supported by software
- # Default: Login-User
- AuthServices = Login-User
-
- # List of services for which will be carried out FreeRADIUS Accounting
- # Note: Parameter can be blank
- # Parameter: required
- # Value: any, supported by software
- # Default: Framed-User
- AcctServices = Framed-User
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enable the module for remote execution of scripts OnConnect and OnDisconnect "mod_remote_script.so"
-<Module remote_script>
- # The time interval between sending confirmations that the user is online
- # Parametr: required
- # Values: 10 ... 600 (seconds)
- # Default: 60
- SendPeriod = 15
-
- # Define mapping between subnet(s) and remote server(s)
- # File format: <subnet> <Router1> <Router2> ...
- # Example:
- # 192.168.1.0/24 192.168.1.7 192.168.1.8
- # 192.168.2.0/24 192.168.2.5 192.168.2.6 192.168.2.7
- # 192.168.3.0/24 192.168.3.5
- # 192.168.4.0/24 192.168.4.5
- # Parametr: required
- # Values: file path
- # Default: subnets
- SubnetFile = subnets
-
- # The password to encrypt packets between the stg-server and remote server
- # Parameter: required
- # Values: any
- # Default: 123456
- Password = 123456
-
- # Define which user parameters are transferred to a remote server in addition to
- # other parameters that transfered by default (ID, IP, Login, Cash, Dirs).
- # Note: Parameter can be blank.
- # Parameter: required
- # Values: Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName,
- # NextTariff, Address, Note, Group, Email, RealName, Credit, EnabledDirs,
- # Userdata0...Userdata9
- # Default: Cash Tariff EnabledDirs
- UserParams = Cash Tariff EnabledDirs
-
- # Port on which the server interacts with remote server
- # Parameter: required
- # Value: 1...65535
- # Default: 9999
- Port = 9999
-</Module>
+++ /dev/null
-# Enable the configuration module ConfRPC "mod_conf_rpc.so"
-<Module conf_rpc>
- # Port on which the server interacts with configurator
- # Parameter: required
- # Value: 1...65535
- # Default:
- Port = 8080
-
- # Session timeout in seconds
- # Parameter: required
- # Value: positive integer
- # Default: 1800
- CookieTimeout = 1800
-</Module>
+++ /dev/null
-# Enable the configuration module SgConfig "mod_conf_sg.so"
-<Module conf_sg>
- # Port on which the server interacts with configurator
- # Parameter: required
- # Value: 1...65535
- # Default: 5555
- Port = 5555
-</Module>
\ No newline at end of file
+++ /dev/null
-# Enables SMUX-peer for SNMPd.
-<Module smux>
- # IP-address of a server to connect to
- # Parameter: required
- # Value: X.X.X.X
- # Default: 127.0.0.1
- Server = 127.0.0.1
-
- # Port number on a server to connect to
- # Parameter: required
- # Value: 1 ... 65535
- # Default: 199
- Port = 199
-
- # Password for authentication on a server
- # Parameter: required
- # Value: any text
- Password =
-</Module>
+++ /dev/null
-# Enables plain file backend.
-<StoreModule store_files>
-
- # Working server directory, provides data on tariffs, users, administrators.
- # Parameter: required
- # Value: directory path
- WorkDir = /var/stargazer
-
- # Owner, group and permissions of the files of user statistics (stat)
- # Parameter: required
- # Values: any, supported by OS
- ConfOwner = root
- ConfGroup = root
- ConfMode = 640
-
- # Owner, group and permissions on user configuration files (conf)
- # Parameter: required
- # Values: any, supported by OS
- StatOwner = root
- StatGroup = root
- StatMode = 640
-
- # Owner, group and permissions for user log files (log)
- # Parameter: required
- # Values: any, supported by OS
- UserLogOwner = root
- UserLogGroup = root
- UserLogMode = 640
-
-</StoreModule>
+++ /dev/null
-# Enables Firebird backend.
-<StoreModule store_firebird>
- # Database server address
- # Parameter: optional
- # Value: IP address or DNS name
- # Default: localhost
- # Server = localhost
-
- # Path to the database on the server or its alias
- # Parameter: optional
- # Value: file path
- # Default: /var/stg/stargazer.fdb
- # Database = /var/stg/stargazer.fdb
-
- # Database username
- # Parameter: optional
- # Value: any, supported by database
- # Default: stg
- # User = stg
-
- # Database password
- # Parameter: optional
- # Value: any, supported by database
- # Default: 123456
- # Password = 123456
-
- # The transaction isolation level
- # Parameter: optional
- # Values: concurrency, dirtyread, readcommitted, consistency
- # Defalt: concurrency
- # IsolationLevel = concurrency
-
- # Responding to lock (optional, defaults to wait):
- # Parameter: optional
- # Values: wait, nowait
- # Defalt: wait
- # LockResolution = wait
-</StoreModule>
+++ /dev/null
-# Enables MySQL backend.
-<StoreModule store_mysql>
- # Database server address
- # Parameter: required
- # Value: IP address or DNS name
- # Default: localhost
- Server = localhost
-
- # Database name
- # Parameter: required
- # Value: any, supported by database
- # Default: stg
- Database = stg
-
- # Database username
- # Parameter: required
- # Value: any, supported by database
- # Default: stg
- User = stg
-
- # Database password
- # Parameter: required
- # Value: any, supported by database
- # Default: 123456
- Password = 123456
-</StoreModule>
+++ /dev/null
-# Enables PostgreSQL backend.
-<StoreModule store_postgresql>
- # Database server address
- # Parameter: optional
- # Value: IP address or DNS name
- # Default: localhost
- # Server = localhost
-
- # Database name
- # Parameter: optional
- # Value: any, supported by database
- # Default: stargazer
- # Database = stargazer
-
- # Database username
- # Parameter: optional
- # Value: any, supported by database
- # Default: stg
- # User = stg
-
- # Database password
- # Parameter: optional
- # Value: any, supported by database
- # Default: 123456
- # Password = 123456
-
- # Number of tries to reconnect
- # Parameter: optional
- # Value: positive integer
- # Default: 3
- # Retries = 3
-</StoreModule>
+++ /dev/null
-../conf-available.d/mod_ao.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_cap_ether.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_ia.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_ping.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/mod_sg.conf
\ No newline at end of file
+++ /dev/null
-../conf-available.d/store_files.conf
\ No newline at end of file
+++ /dev/null
-ALL 192.168.0.0/16 DIR1
-ALL 10.0.0.0/8 DIR2
-ALL 0.0.0.0/0 DIR0
\ No newline at end of file
+++ /dev/null
-################################################################################
-# Stargazer Configuration file #
-################################################################################
-
-# LOG file name
-# Parameter: required
-# Value: file path
-# Default: /var/log/stargazer.log
-LogFile = /var/log/stargazer.log
-
-# PID file name
-# Parameter: optional
-# Value: file path
-# Default: /var/run/stargazer.pid
-PIDFile = /var/run/stargazer.pid
-
-# Traffic classification rules
-# Parameter: required
-# Value: file path
-# Default: /etc/stargazer/rules
-Rules = /etc/stargazer/rules
-
-# The time interval between writing detailed user's statistics into the database
-# Note: With a large number of users this value should be increased,
-# since writting into the database can take a long time.
-# Parameter: required
-# Values: 1 (hourly), 1/2 (every half hour), 1/4 (every 15 m), 1/6 (every 10 m)
-# Default: 1/2
-DetailStatWritePeriod = 1/2
-
-# The time interval between writing summary user's statistics into the database
-# Parameter: optional
-# Value: 1 ... 1440 (minutes)
-# Default: 10
-StatWritePeriod = 10
-
-# Day of charging fee
-# Note: 0 - The last day of the month
-# Parameter: required
-# Value: 0 ... 31
-# Default: 1
-DayFee = 1
-
-# When set to 'no' Stargazer will continue reading database after error and show all of them.
-# Parameter: optional
-# Values: yes, no
-# Default: yes
-# StopOnError = yes
-
-# Fee charged at the last (yes) or first (no) day of tariffication period.
-# Defines how the fee will be charged in the transition to the new tariff.
-# User has tariff A with fee 100. Changing it to tariff B with fee 200
-# will result in charging user's account at 100 if DayFeeIsLastDay = yes
-# and at 200, if DayFeeIsLastDay = no
-# Parameter: required
-# Values: yes, no
-# Default: no
-DayFeeIsLastDay = no
-
-# Day of changing delayed tariffs and resetting summary user's statistics.
-# Defines the edge of the tariffication period.
-# Parameter: required
-# Value: 0 ... 31. 0 - The last day of the month
-# Default: 1
-DayResetTraff = 1
-
-# Defines whether to charge fee daily (yes) or monthly (no)
-# Parameter: required
-# Values: yes, no
-# Default: no
-SpreadFee = no
-
-# Defines whether the user can access the internet if it has no cash,
-# but remained prepaid traffic
-# Parameter: required
-# Values: yes, no
-# Default: no
-FreeMbAllowInet = no
-
-# Defines what will be written in the traffic cost in detail_stat.
-# If user still has the prepaid traffic and WriteFreeMbTraffCost = no,
-# then the traffic cost willn't be written in detail_stat.
-# If user doestn't have prepaid traffic and WriteFreeMbTraffCost = no,
-# then the traffic cost will be written in detail_stat.
-# When WriteFreeMbTraffCost = yes the traffic cost will be recorded in any case.
-# Parameter: required
-# Values: yes, no
-# Default: yes
-WriteFreeMbTraffCost = yes
-
-# Charge a full monthly fee even if user was "frozen" a part
-# of the tariffication period
-# Parameter: optional
-# Values: yes, no
-# Default: no
-FullFee = no
-
-# Allow user to see and use a full cash (yes) or hide a part of it (no)
-# for the next fee charge
-# Parameter: optional
-# Values: yes, no
-# Default: yes
-# ShowFeeInCash=yes
-
-# The names of directions. Direction without names will not appear in
-# authorizer and configurator.
-# Note: Names consisting of several words should be quoted
-# Parameter: optional
-# Values:
-<DirNames>
- DirName0 = Internet
- DirName1 =
- DirName2 =
- DirName3 =
- DirName4 =
- DirName5 =
- DirName6 =
- DirName7 =
- DirName8 =
- DirName9 =
-</DirNames>
-
-# Amount of stg-exec processes.
-# These processes are responsible for the execution of scripts OnConnect,
-# OnDisconnect, etc.
-# Amount of processes means how many scripts can be executed simultaneously.
-# Recommend to leave 1 to avoid errors when executing scripts
-# Parameter: optional
-# Value: 1 ... 1024
-# Default: 1
-ExecutersNum = 1
-
-# Message queue identifier for the script executer.
-# It may be changed if there're a needs to run multiple copies of stargazer.
-# Warning: If you do not understand it, do not touch this setting!
-# Parameter: optional
-# Value: 0 ... 2 ^ 32
-# Default: 5555
-# ExecMsgKey = 5555
-
-# The path to directory with server modules
-# Parameter: required
-# Value: directory path
-# Default: /usr/lib/stg
-ModulesPath = /usr/lib/stg
-
-# Directory where the "monitor" files are located.
-# A blank files will be created in this directory. The modification time of such
-# files will be changed about once a minute. If server crashes or some of server
-# component hang, the files will stop refreshing, and on this basis we can define
-# the failure of the server and if necessary restart.
-# If option is omitted or blank, the monitoring is not performed.
-# Parameter: optional
-# Value: file path
-# Default: /var/stargazer/monitor
-#MonitorDir=/var/stargazer/monitor
-
-# Defines message maximum lifetime
-# Note: 0 - unlimited
-# Parameter: optional
-# Value: any numeric
-# Default: 0 (day)
-# MessagesTimeout = 0
-
-# Defines fee charging rules.
-# 0 - classic rules, allow fee charge even cash is negative;
-# 1 - disallow fee charge if cash value is negative;
-# 2 - disallow fee charge if there is not enought cash (cash < fee).
-# Parameter: optional
-# Value: 0 ... 2
-# Default: 0 (classic)
-# FeeChargeType = 0
-
-# Enable or disable reconnect on tariff change
-# Parameter: optional
-# Values: yes, no
-# Default: no
-# ReconnectOnTariffChange = no
-
-# Definest set of parameters passed to OnConnect and OnDisconnect scripts
-# This set is added to the end of the default param list, which are, respectively:
-# login, ip, cash, id, dirs
-# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
-# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
-# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
-# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
-# "userdata0" ... "userdata9".
-# Parameter: optional
-# Values: parameter names, case insensitive
-# Default:
-# ScriptParams =
-
-# Enable or disable writing session log
-# Parameter: optional
-# Values: yes, no
-# Default: no (session log is enabled)
-# DisableSessionLog = no
-
-# Filter for logging parameter changes
-# Defines which parameters will be logged to parameter log in database. Allows
-# to specify multiuple parameter names or asterisk (*), which means "log all params".
-# Valid parameter names: "cash", "upload", "download", "lastCashAdd", "passiveTime",
-# "lastCashAddTime", "freeMb", "lastActivityTime", "password", "passive", "disabled",
-# "disabledDetailStat", "alwaysOnline", "tariffName", "nextTariff", "address",
-# "note", "group", "email", "phone", "realName", "credit", "creditExpire", "ips",
-# "userdata0" ... "userdata9".
-# Parameter: optional
-# Values: parameter names, case insensitive, or "*"
-# Default: *
-# FilterParamsLog = *
-
-################################################################################
-# Store module
-# Configure the module that works with the database server
-
-# Warning: Only one store module could be used at the same time!
-
-<IncludeFile "conf-enabled.d/store_*.conf">
-</IncludeFile>
-
-
-################################################################################
-# Other modules
-
-<Modules>
-
- <IncludeFile "conf-enabled.d/mod_*.conf">
- </IncludeFile>
-
-</Modules>
-################################################################################
+++ /dev/null
-/*
- * DB migration from v00 to v01 (postgres)
- */
-
-ALTER TABLE tb_sessions_log ADD free_mb dm_money;
-ALTER TABLE tb_sessions_log ADD reason TEXT;
-
-DROP FUNCTION sp_add_session_log_entry ( dm_name, timestamp without time zone, dm_session_event_type, inet, dm_money);
-
-CREATE FUNCTION sp_add_session_log_entry(_login dm_name,
- _event_time TIMESTAMP,
- _event_type dm_session_event_type,
- _ip INET,
- _cash dm_money,
- _free_mb dm_money,
- _reason TEXT)
-RETURNS INTEGER
-AS $$
-DECLARE
- _pk_user INTEGER;
- _pk_session_log INTEGER;
-BEGIN
- SELECT pk_user INTO _pk_user
- FROM tb_users
- WHERE name = _login;
- IF _pk_user IS NULL THEN
- RAISE EXCEPTION 'User % not found', _login;
- RETURN -1;
- END IF;
-
- INSERT INTO tb_sessions_log
- (fk_user,
- event_time,
- event_type,
- ip,
- cash,
- free_mb,
- reason)
- VALUES
- (_pk_user,
- _event_time,
- _event_type,
- _ip,
- _cash,
- _free_mb,
- _reason);
-
- SELECT CURRVAL('tb_sessions_log_pk_session_log_seq') INTO _pk_session_log;
-
- RETURN _pk_session_log;
-END;
-$$ LANGUAGE plpgsql;
-
-UPDATE tb_info SET version = 6;
+++ /dev/null
-/*
- * DB migration from v00 to v01 (firebird)
- */
-
-alter table tb_users add disabled_detail_stat dm_bool;
-
-drop procedure sp_add_user;
-
-set term !! ;
-create procedure sp_add_user(name varchar(32), dirs integer)
-as
-declare variable pk_user integer;
-declare variable pk_stat integer;
-begin
- pk_user = gen_id(gn_pk_user, 1);
- insert into tb_users(pk_user, fk_tariff, fk_tariff_change, fk_corporation, address, always_online, credit, credit_expire, disabled, disabled_detail_stat, email, grp, note, passive, passwd, phone, name, real_name) values (:pk_user, NULL, NULL, NULL, '', 0, 0, 'now', 0, 0, '', '_', '', 0, '', '', :name, '');
- pk_stat = gen_id(gn_pk_stat, 1);
- insert into tb_stats values (:pk_stat, :pk_user, 0, 0, 'now', 0, 'now', 0, 'now');
- while (dirs > 0) do
- begin
- insert into tb_stats_traffic (fk_stat, dir_num, upload, download) values (:pk_stat, :dirs - 1, 0, 0);
- dirs = dirs - 1;
- end
-end!!
-set term ; !!
+++ /dev/null
-/*
- * 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
- */
-
-/*
- *****************************************************************************
- *
- * Скрипт генерации структуры базы для хранения данных Stargazer-a
- *
- * Примечание.
- * * dm_permission_flag. Представляет собой битовую маску - rw.
- * r - чтение, w - изменение параметра.
- * 0 - дествие запрещено, 1 - действие разрешено
- *
- * * dm_traff_type. Число определяющее тип подсчета трафика:
- * 0 - up - считается по upload
- * 1 - down - считается по download
- * 2 - max - считается по максимальному среди upload/download
- * 3 - up+down - считается по сумме upload и download
- *
- * * dm_session_event_type. Указывает тип записи в логе о сессии.
- * 'c' - connect, 'd' - disconnect.
- *
- *****************************************************************************
- */
-
-/*
- * $Revision: 1.12 $
- * $Date: 2009/08/20 14:58:43 $
- */
-
-
-/*
- *****************************************************************************
- * -= Создание типов и доменов =-
- *****************************************************************************
- */
-
-CREATE DOMAIN dm_name AS VARCHAR(32) NOT NULL;
-CREATE DOMAIN dm_password AS VARCHAR(64) NOT NULL;
-CREATE DOMAIN dm_permission_flag AS SMALLINT NOT NULL
- CHECK ( value BETWEEN 0 AND 3 );
-CREATE DOMAIN dm_money AS NUMERIC(12, 4) NOT NULL DEFAULT 0;
-CREATE DOMAIN dm_traff_type AS SMALLINT NOT NULL
- CHECK ( value BETWEEN 0 AND 3 );
-CREATE DOMAIN dm_day AS SMALLINT NOT NULL
- CHECK ( value BETWEEN 0 AND 31 )
- DEFAULT 0;
-CREATE DOMAIN dm_session_event_type AS CHAR(1) NOT NULL
- CHECK ( value = 'c' OR value = 'd' );
-
-/*
- *****************************************************************************
- * -= Создание таблиц =-
- *****************************************************************************
- */
-
-CREATE TABLE tb_info
-(
- version INTEGER NOT NULL
-);
-
-CREATE TABLE tb_admins
-(
- pk_admin SERIAL PRIMARY KEY,
- login dm_name UNIQUE,
- passwd dm_password NOT NULL,
- chg_conf dm_permission_flag,
- chg_password dm_permission_flag,
- chg_stat dm_permission_flag,
- chg_cash dm_permission_flag,
- usr_add_del dm_permission_flag,
- chg_tariff dm_permission_flag,
- chg_admin dm_permission_flag,
- chg_service dm_permission_flag,
- chg_corporation dm_permission_flag
-);
-
-CREATE TABLE tb_tariffs
-(
- pk_tariff SERIAL PRIMARY KEY,
- name dm_name UNIQUE,
- fee dm_money,
- free dm_money,
- passive_cost dm_money,
- traff_type dm_traff_type
-);
-
-CREATE TABLE tb_tariffs_params
-(
- pk_tariff_param SERIAL PRIMARY KEY,
- fk_tariff INTEGER NOT NULL,
- dir_num SMALLINT NOT NULL,
- price_day_a dm_money,
- price_day_b dm_money,
- price_night_a dm_money,
- price_night_b dm_money,
- threshold INTEGER NOT NULL,
- time_day_begins TIME NOT NULL,
- time_day_ends TIME NOT NULL,
-
- FOREIGN KEY (fk_tariff)
- REFERENCES tb_tariffs (pk_tariff)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_corporations
-(
- pk_corporation SERIAL PRIMARY KEY,
- name dm_name UNIQUE,
- cash dm_money
-);
-
-CREATE TABLE tb_users
-(
- pk_user SERIAL PRIMARY KEY,
- fk_tariff INTEGER,
- fk_tariff_change INTEGER,
- fk_corporation INTEGER,
- address VARCHAR(256) NOT NULL,
- always_online BOOLEAN NOT NULL,
- credit dm_money,
- credit_expire TIMESTAMP NOT NULL,
- disabled BOOLEAN NOT NULL,
- disabled_detail_stat BOOLEAN NOT NULL,
- email VARCHAR(256) NOT NULL,
- grp dm_name,
- note TEXT NOT NULL,
- passive BOOLEAN NOT NULL,
- passwd dm_password,
- phone VARCHAR(256) NOT NULL,
- name dm_name UNIQUE,
- real_name VARCHAR(256) NOT NULL,
- cash dm_money,
- free_mb dm_money,
- last_activity_time TIMESTAMP NOT NULL,
- last_cash_add dm_money,
- last_cash_add_time TIMESTAMP NOT NULL,
- passive_time INTEGER NOT NULL,
-
- FOREIGN KEY (fk_tariff)
- REFERENCES tb_tariffs (pk_tariff)
- ON DELETE CASCADE,
- FOREIGN KEY (fk_tariff_change)
- REFERENCES tb_tariffs (pk_tariff)
- ON DELETE CASCADE,
- FOREIGN KEY (fk_corporation)
- REFERENCES tb_corporations (pk_corporation)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_detail_stats
-(
- pk_detail_stat BIGSERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- dir_num SMALLINT NOT NULL,
- ip INET NOT NULL,
- download BIGINT NOT NULL,
- upload BIGINT NOT NULL,
- cost dm_money,
- from_time TIMESTAMP NOT NULL,
- till_time TIMESTAMP NOT NULL,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_services
-(
- pk_service SERIAL PRIMARY KEY,
- name dm_name UNIQUE,
- comment TEXT NOT NULL,
- cost dm_money,
- pay_day dm_day
-);
-
-CREATE TABLE tb_users_services
-(
- pk_user_service SERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- fk_service INTEGER NOT NULL,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE,
- FOREIGN KEY (fk_service)
- REFERENCES tb_services (pk_service)
-);
-
-CREATE TABLE tb_messages
-(
- pk_message SERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- ver SMALLINT NOT NULL,
- msg_type SMALLINT NOT NULL,
- last_send_time TIMESTAMP NOT NULL,
- creation_time TIMESTAMP NOT NULL,
- show_time INTEGER NOT NULL,
- repeat SMALLINT NOT NULL,
- repeat_period INTEGER NOT NULL,
- msg_text TEXT NOT NULL,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_stats_traffic
-(
- pk_stat_traffic BIGSERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- stats_date DATE NOT NULL,
- dir_num SMALLINT NOT NULL,
- download BIGINT NOT NULL,
- upload BIGINT NOT NULL,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE,
- UNIQUE (fk_user, stats_date, dir_num)
-);
-
-CREATE TABLE tb_users_data
-(
- pk_user_data SERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- num SMALLINT NOT NULL,
- data VARCHAR(256) NOT NULL,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_allowed_ip
-(
- pk_allowed_ip SERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- ip INET NOT NULL,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_sessions_log
-(
- pk_session_log SERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- event_time TIMESTAMP NOT NULL,
- event_type dm_session_event_type,
- ip INET NOT NULL,
- cash dm_money,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_sessions_data
-(
- pk_session_data SERIAL PRIMARY KEY,
- fk_session_log INTEGER NOT NULL,
- dir_num SMALLINT NOT NULL,
- session_upload BIGINT NOT NULL,
- session_download BIGINT NOT NULL,
- month_upload BIGINT NOT NULL,
- month_download BIGINT NOT NULL,
-
- FOREIGN KEY (fk_session_log)
- REFERENCES tb_sessions_log (pk_session_log)
- ON DELETE CASCADE
-);
-
-CREATE TABLE tb_parameters
-(
- pk_parameter SERIAL PRIMARY KEY,
- name dm_name UNIQUE
-);
-
-CREATE TABLE tb_params_log
-(
- pk_param_log SERIAL PRIMARY KEY,
- fk_user INTEGER NOT NULL,
- fk_parameter INTEGER NOT NULL,
- fk_admin INTEGER NOT NULL,
- ip INET NOT NULL,
- event_time TIMESTAMP NOT NULL,
- from_val VARCHAR(256),
- to_val VARCHAR(256),
- comment TEXT,
-
- FOREIGN KEY (fk_user)
- REFERENCES tb_users (pk_user)
- ON DELETE CASCADE,
- FOREIGN KEY (fk_parameter)
- REFERENCES tb_parameters (pk_parameter),
- FOREIGN KEY (fk_admin)
- REFERENCES tb_admins (pk_admin)
- ON DELETE CASCADE
-);
-
-/*
- *****************************************************************************
- * -= Создание хранимых процедур =-
- *****************************************************************************
- */
-
-CREATE FUNCTION sp_add_message(_login dm_name,
- _ver SMALLINT,
- _msg_type SMALLINT,
- _last_send_time TIMESTAMP,
- _creation_time TIMESTAMP,
- _show_time INTEGER,
- _repeat SMALLINT,
- _repeat_period INTEGER,
- _msg_text TEXT)
-RETURNS INTEGER
-AS $$
-DECLARE
- _pk_user INTEGER;
-BEGIN
- SELECT pk_user INTO _pk_user
- FROM tb_users
- WHERE name = _login;
- IF _pk_user IS NULL THEN
- RAISE EXCEPTION 'User % not found', _login;
- RETURN -1;
- END IF;
- INSERT INTO tb_messages
- (fk_user,
- ver,
- msg_type,
- last_send_time,
- creation_time,
- show_time,
- repeat,
- repeat_period,
- msg_text)
- VALUES
- (_pk_user,
- _ver,
- _msg_type,
- _last_send_time,
- _creation_time,
- _show_time,
- _repeat,
- _repeat_period,
- _msg_text);
- RETURN CURRVAL('tb_messages_pk_message_seq');
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE FUNCTION sp_add_tariff(_name dm_name, _dirs INTEGER)
-RETURNS INTEGER
-AS $$
-DECLARE
- pk_tariff INTEGER;
-BEGIN
- INSERT INTO tb_tariffs
- (name,
- fee,
- free,
- passive_cost,
- traff_type)
- VALUES
- (_name,
- 0, 0, 0, 0);
- SELECT CURRVAL('tb_tariffs_pk_tariff_seq') INTO pk_tariff;
- FOR i IN 1.._dirs LOOP
- INSERT INTO tb_tariffs_params
- (fk_tariff,
- dir_num,
- price_day_a,
- price_day_b,
- price_night_a,
- price_night_b,
- threshold,
- time_day_begins,
- time_day_ends)
- VALUES
- (pk_tariff,
- i - 1,
- 0, 0, 0, 0, 0,
- CAST('1970-01-01 00:00:00+00' AS TIMESTAMP),
- CAST('1970-01-01 00:00:00+00' AS TIMESTAMP));
- END LOOP;
- RETURN pk_tariff;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE FUNCTION sp_add_user(_name dm_name)
-RETURNS INTEGER
-AS $$
-DECLARE
- pk_user INTEGER;
-BEGIN
- INSERT INTO tb_users
- (fk_tariff,
- fk_tariff_change,
- fk_corporation,
- address,
- always_online,
- credit,
- credit_expire,
- disabled,
- disabled_detail_stat,
- email,
- grp,
- note,
- passive,
- passwd,
- phone,
- name,
- real_name,
- cash,
- free_mb,
- last_activity_time,
- last_cash_add,
- last_cash_add_time,
- passive_time)
- VALUES
- (NULL, NULL, NULL, '', FALSE, 0, CAST('now' AS TIMESTAMP),
- FALSE, FALSE, '', '', '', FALSE, '', '', _name, '', 0, 0,
- CAST('now' AS TIMESTAMP), 0, CAST('now' AS TIMESTAMP), 0);
- SELECT CURRVAL('tb_users_pk_user_seq') INTO pk_user;
- RETURN pk_user;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE FUNCTION sp_add_stats_traffic (_login dm_name,
- _stats_date DATE,
- _dir_num SMALLINT,
- _upload BIGINT,
- _download BIGINT)
-RETURNS INTEGER
-AS $$
-DECLARE
- _pk_user INTEGER;
-BEGIN
- SELECT pk_user INTO _pk_user
- FROM tb_users
- WHERE name = _login;
-
- IF _pk_user IS NULL THEN
- RAISE EXCEPTION 'User % not found', _login;
- RETURN -1;
- END IF;
-
- UPDATE tb_stats_traffic SET
- upload = _upload,
- download = _download
- WHERE fk_user = _pk_user AND
- dir_num = _dir_num AND
- stats_date = _stats_date;
-
- IF NOT FOUND THEN
- INSERT INTO tb_stats_traffic
- (fk_user,
- dir_num,
- stats_date,
- upload,
- download)
- VALUES
- (_pk_user,
- _dir_num,
- _stats_date,
- _upload,
- _download);
- END IF;
-
- RETURN 1;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE FUNCTION sp_set_user_data (_pk_user INTEGER,
- _num SMALLINT,
- _data VARCHAR(256))
-RETURNS INTEGER
-AS $$
-BEGIN
- UPDATE tb_users_data SET
- data = _data
- WHERE fk_user = _pk_user AND num = _num;
-
- IF NOT FOUND THEN
- INSERT INTO tb_users_data
- (fk_user,
- num,
- data)
- VALUES
- (_pk_user,
- _num,
- _data);
- END IF;
-
- RETURN 1;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE FUNCTION sp_add_param_log_entry(_login dm_name,
- _admin_login dm_name,
- _ip INET,
- _param_name dm_name,
- _event_time TIMESTAMP,
- _from VARCHAR(256),
- _to VARCHAR(256),
- _comment TEXT)
-RETURNS INTEGER
-AS $$
-DECLARE
- _pk_user INTEGER;
- _pk_admin INTEGER;
- _pk_param INTEGER;
-BEGIN
- SELECT pk_user INTO _pk_user
- FROM tb_users
- WHERE name = _login;
- IF _pk_user IS NULL THEN
- RAISE EXCEPTION 'User % not found', _login;
- RETURN -1;
- END IF;
-
- SELECT pk_admin INTO _pk_admin
- FROM tb_admins
- WHERE login = _admin_login;
- IF _pk_admin IS NULL THEN
- RAISE EXCEPTION 'Admin % not found', _admin_login;
- RETURN -1;
- END IF;
-
- SELECT pk_parameter INTO _pk_param
- FROM tb_parameters
- WHERE name = _param_name;
-
- IF NOT FOUND THEN
- INSERT INTO tb_parameters (name) VALUES (_param_name);
- SELECT CURRVAL('tb_parameters_pk_parameter_seq') INTO _pk_param;
- END IF;
-
- INSERT INTO tb_params_log
- (fk_user,
- fk_parameter,
- fk_admin,
- ip,
- event_time,
- from_val,
- to_val,
- comment)
- VALUES
- (_pk_user,
- _pk_param,
- _pk_admin,
- _ip,
- _event_time,
- _from,
- _to,
- _comment);
-
- RETURN 1;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE FUNCTION sp_add_session_log_entry(_login dm_name,
- _event_time TIMESTAMP,
- _event_type dm_session_event_type,
- _ip INET,
- _cash dm_money)
-RETURNS INTEGER
-AS $$
-DECLARE
- _pk_user INTEGER;
- _pk_session_log INTEGER;
-BEGIN
- SELECT pk_user INTO _pk_user
- FROM tb_users
- WHERE name = _login;
- IF _pk_user IS NULL THEN
- RAISE EXCEPTION 'User % not found', _login;
- RETURN -1;
- END IF;
-
- INSERT INTO tb_sessions_log
- (fk_user,
- event_time,
- event_type,
- ip,
- cash)
- VALUES
- (_pk_user,
- _event_time,
- _event_type,
- _ip,
- _cash);
-
- SELECT CURRVAL('tb_sessions_log_pk_session_log_seq') INTO _pk_session_log;
-
- RETURN _pk_session_log;
-END;
-$$ LANGUAGE plpgsql;
-
-/*
- *****************************************************************************
- * -= Создание администратора =-
- *
- * Двоичные права доступа пока не поддерживаются, по этому используются флаги
- *****************************************************************************
- */
-INSERT INTO tb_admins
- (login, passwd,
- chg_conf, chg_password, chg_stat,
- chg_cash, usr_add_del, chg_tariff,
- chg_admin, chg_service, chg_corporation)
-VALUES
- ('admin',
- 'geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmk',
- 1, 1, 1, 1, 1, 1, 1, 1, 1);
-INSERT INTO tb_admins
- (login, passwd,
- chg_conf, chg_password, chg_stat,
- chg_cash, usr_add_del, chg_tariff,
- chg_admin, chg_service, chg_corporation)
-VALUES
- ('@stargazer',
- '',
- 0, 0, 0, 0, 0, 0, 0, 0, 0);
-
-INSERT INTO tb_info
- (version)
-VALUES
- (5);
+++ /dev/null
-/*
- * 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
- */
-
-/*
- *****************************************************************************
- *
- * Скрипт генерации структуры базы для хранения данных Stargazer-a
- *
- * $Id: 00-base-00.sql,v 1.7 2010/01/06 14:41:13 faust Exp $
- *
- * Примечание.
- * * dm_permission_flag. Представляет собой битовую маску - rw.
- * r - чтение, w - изменение параметра.
- * 0 - дествие запрещено, 1 - действие разрешено
- *
- * * dm_traff_type. Число определяющее тип подсчета трафика:
- * 0 - up - считается по upload
- * 1 - down - считается по download
- * 2 - max - считается по максимальному среди upload/download
- * 3 - up+down - считается по сумме upload и download
- *
- * * dm_ip. IP адресс в виде четырех байтового целого числа со знаком.
- * Выполнять приведение к знаковуму целому при занесении IP в БД!!!
- *
- * * dm_period. Задает периодичность показа сообщения пользователю.
- * Период задается целым числом (int16). Если значение равно 0 то
- * сообщение показывается только при подключении пользователя.
- * Также этот домен определяет промежуток времени в течении которого
- * сообщение показывается пользователю.
- *
- * * dm_session_event_type. Указывает тип записи в логе о сессии.
- * 'c' - connect, 'd' - disconnect.
- *
- *****************************************************************************
- */
-
-/*
- * CONNECT 'localhost:/var/stg/stargazer.fdb' USER 'stg' PASSWORD '123456';
- * DROP DATABASE;
- *
- * CREATE DATABASE 'localhost:/var/stg/stargazer.fdb' USER 'stg' PASSWORD '123456' DEFAULT CHARACTER SET UTF8;
- */
-
-
-
-/*
- *****************************************************************************
- * -= Создание ДОМЕНОВ =-
- *****************************************************************************
- */
-
-CREATE DOMAIN dm_id AS INTEGER NOT NULL;
-CREATE DOMAIN dm_null_id AS INTEGER;
-CREATE DOMAIN dm_login AS VARCHAR(32) NOT NULL;
-CREATE DOMAIN dm_tariff_name AS VARCHAR(32) NOT NULL;
-CREATE DOMAIN dm_group_name AS VARCHAR(32);
-CREATE DOMAIN dm_corporation_name AS VARCHAR(32);
-CREATE DOMAIN dm_parameter_name AS VARCHAR(32);
-
-CREATE DOMAIN dm_password AS VARCHAR(64) NOT NULL;
-/* bitmask - rw => Read, Write */
-CREATE DOMAIN dm_permission_flag AS SMALLINT NOT NULL
- CHECK ( VALUE BETWEEN 0 AND 3 );
-CREATE DOMAIN dm_money AS NUMERIC(10,6) NOT NULL;
-/* (0, 1, 2, 3) => (up, down, max, up+down) */
-CREATE DOMAIN dm_traff_type AS SMALLINT NOT NULL
- CHECK ( VALUE BETWEEN 0 AND 3 );
-CREATE DOMAIN dm_dir_num AS SMALLINT NOT NULL;
-CREATE DOMAIN dm_num AS SMALLINT NOT NULL;
-CREATE DOMAIN dm_traffic_mb AS INTEGER NOT NULL;
-CREATE DOMAIN dm_traffic_byte AS BIGINT NOT NULL;
-CREATE DOMAIN dm_time AS TIME NOT NULL;
-CREATE DOMAIN dm_moment AS TIMESTAMP NOT NULL;
-CREATE DOMAIN dm_credit_moment AS TIMESTAMP;
-CREATE DOMAIN dm_ip AS INTEGER NOT NULL;
-CREATE DOMAIN dm_mask AS INTEGER NOT NULL;
-CREATE DOMAIN dm_user_address AS VARCHAR(256) DEFAULT '';
-CREATE DOMAIN dm_bool AS CHAR(1) NOT NULL
- CHECK ( VALUE IN ('0', '1', 't', 'f', 'T', 'F') );
-CREATE DOMAIN dm_email AS VARCHAR(256) DEFAULT '';
-CREATE DOMAIN dm_note AS VARCHAR(256) DEFAULT '';
-CREATE DOMAIN dm_phone AS VARCHAR(256) DEFAULT '';
-CREATE DOMAIN dm_user_name AS VARCHAR(256) DEFAULT '';
-CREATE DOMAIN dm_service_comment AS VARCHAR(256) DEFAULT '';
-CREATE DOMAIN dm_service_name AS VARCHAR(32) DEFAULT '';
-
-CREATE DOMAIN dm_pay_day AS SMALLINT NOT NULL
- CHECK ( VALUE BETWEEN 0 AND 31 );
-CREATE DOMAIN dm_period AS INTEGER NOT NULL;
-CREATE DOMAIN dm_counter AS SMALLINT NOT NULL;
-
-CREATE DOMAIN dm_message_ver AS INTEGER NOT NULL;
-CREATE DOMAIN dm_message_type AS INTEGER NOT NULL;
-
-CREATE DOMAIN dm_message AS VARCHAR(256) NOT NULL;
-CREATE DOMAIN dm_user_data AS VARCHAR(256) NOT NULL;
-CREATE DOMAIN dm_session_event_type AS CHAR(1) NOT NULL
- CHECK ( VALUE IN ('c', 'd') );
-CREATE DOMAIN dm_char_value AS VARCHAR(64) NOT NULL;
-CREATE DOMAIN dm_date AS DATE NOT NULL;
-
-
-
-/*
- *****************************************************************************
- * -= Создание ТАБЛИЦ =-
- *****************************************************************************
- */
-
-CREATE TABLE tb_admins
-(
- pk_admin dm_id PRIMARY KEY,
- login dm_login UNIQUE,
- passwd dm_password,
- chg_conf dm_permission_flag,
- chg_password dm_permission_flag,
- chg_stat dm_permission_flag,
- chg_cash dm_permission_flag,
- usr_add_del dm_permission_flag,
- chg_tariff dm_permission_flag,
- chg_admin dm_permission_flag,
- chg_service dm_permission_flag,
- chg_corporation dm_permission_flag
-);
-
-CREATE TABLE tb_tariffs
-(
- pk_tariff dm_id PRIMARY KEY,
- name dm_tariff_name UNIQUE,
- fee dm_money,
- free dm_money,
- passive_cost dm_money,
- traff_type dm_traff_type
-);
-
-CREATE TABLE tb_tariffs_params
-(
- pk_tariff_param dm_id PRIMARY KEY,
- fk_tariff dm_id,
- dir_num dm_dir_num,
- price_day_a dm_money,
- price_day_b dm_money,
- price_night_a dm_money,
- price_night_b dm_money,
- threshold dm_traffic_mb,
- time_day_begins dm_time,
- time_day_ends dm_time,
-
- FOREIGN KEY (fk_tariff) REFERENCES tb_tariffs (pk_tariff)
-);
-
-CREATE TABLE tb_corporations
-(
- pk_corporation dm_id PRIMARY KEY,
- name dm_corporation_name UNIQUE,
- cash dm_money
-);
-
-CREATE TABLE tb_users
-(
- pk_user dm_id PRIMARY KEY,
- fk_tariff dm_null_id,
- fk_tariff_change dm_null_id,
- fk_corporation dm_null_id,
- address dm_user_address,
- always_online dm_bool,
- credit dm_money,
- credit_expire dm_credit_moment,
- disabled dm_bool,
- disabled_detail_stat dm_bool,
- email dm_email,
- grp dm_group_name,
- note dm_note,
- passive dm_bool,
- passwd dm_password,
- phone dm_phone,
- name dm_login UNIQUE,
- real_name dm_user_name,
-
- FOREIGN KEY (fk_tariff) REFERENCES tb_tariffs (pk_tariff),
- FOREIGN KEY (fk_tariff_change) REFERENCES tb_tariffs (pk_tariff),
- FOREIGN KEY (fk_corporation) REFERENCES tb_corporations (pk_corporation)
-);
-
-CREATE TABLE tb_detail_stats
-(
- pk_detail_stat dm_id PRIMARY KEY,
- fk_user dm_id,
- dir_num dm_dir_num,
- ip dm_ip,
- download dm_traffic_byte,
- upload dm_traffic_byte,
- cost dm_money,
- from_time dm_moment,
- till_time dm_moment,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
-);
-
-CREATE TABLE tb_services
-(
- pk_service dm_id PRIMARY KEY,
- name dm_service_name UNIQUE,
- comment dm_service_comment,
- cost dm_money,
- pay_day dm_pay_day
-);
-
-CREATE TABLE tb_users_services
-(
- pk_user_service dm_id PRIMARY KEY,
- fk_user dm_id,
- fk_service dm_id,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user),
- FOREIGN KEY (fk_service) REFERENCES tb_services (pk_service)
-);
-
-CREATE TABLE tb_messages
-(
- pk_message dm_id PRIMARY KEY,
- fk_user dm_id,
- ver dm_message_ver,
- msg_type dm_message_type,
- last_send_time dm_period,
- creation_time dm_period,
- show_time dm_period,
- repeat dm_counter,
- repeat_period dm_period,
- msg_text dm_message,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
-);
-
-CREATE TABLE tb_stats
-(
- pk_stat dm_id PRIMARY KEY,
- fk_user dm_id,
- cash dm_money,
- free_mb dm_money,
- last_activity_time dm_moment,
- last_cash_add dm_money,
- last_cash_add_time dm_moment,
- passive_time dm_period,
- stats_date dm_date,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
-);
-
-CREATE TABLE tb_stats_traffic
-(
- pk_stat_traffic dm_id PRIMARY KEY,
- fk_stat dm_id,
- dir_num dm_dir_num,
- download dm_traffic_byte,
- upload dm_traffic_byte,
-
- FOREIGN KEY (fk_stat) REFERENCES tb_stats (pk_stat)
-);
-
-CREATE TABLE tb_users_data
-(
- pk_user_data dm_id PRIMARY KEY,
- fk_user dm_id,
- num dm_num,
- data dm_user_data,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
-);
-
-CREATE TABLE tb_allowed_ip
-(
- pk_allowed_ip dm_id PRIMARY KEY,
- fk_user dm_id,
- ip dm_ip,
- mask dm_mask,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
-);
-
-CREATE TABLE tb_sessions_log
-(
- pk_session_log dm_id PRIMARY KEY,
- fk_user dm_id,
- event_time dm_moment,
- event_type dm_session_event_type,
- ip dm_ip,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
-);
-
-CREATE TABLE tb_sessions_data
-(
- pk_session_data dm_id PRIMARY KEY,
- fk_session_log dm_id,
- dir_num dm_dir_num,
- session_upload dm_traffic_byte,
- session_download dm_traffic_byte,
- month_upload dm_traffic_byte,
- month_download dm_traffic_byte,
-
- FOREIGN KEY (fk_session_log) REFERENCES tb_sessions_log (pk_session_log)
-);
-
-CREATE TABLE tb_parameters
-(
- pk_parameter dm_id PRIMARY KEY,
- name dm_parameter_name UNIQUE
-);
-
-CREATE TABLE tb_params_log
-(
- pk_param_log dm_id PRIMARY KEY,
- fk_user dm_id,
- fk_parameter dm_id,
- event_time dm_moment,
- from_val dm_char_value,
- to_val dm_char_value,
- comment dm_service_comment,
-
- FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user),
- FOREIGN KEY (fk_parameter) REFERENCES tb_parameters (pk_parameter)
-);
-
-
-/*
- *****************************************************************************
- * -= Создание ИНДЕКСОВ =-
- *****************************************************************************
- */
-
-
-
-/*
- *****************************************************************************
- * -= Создание ГЕНЕРАТОРОВ =-
- *****************************************************************************
- */
-
-CREATE GENERATOR gn_pk_admin;
-SET GENERATOR gn_pk_admin TO 0;
-CREATE GENERATOR gn_pk_tariff;
-SET GENERATOR gn_pk_tariff TO 0;
-CREATE GENERATOR gn_pk_tariff_param;
-SET GENERATOR gn_pk_tariff_param TO 0;
-CREATE GENERATOR gn_pk_corporation;
-SET GENERATOR gn_pk_corporation TO 0;
-CREATE GENERATOR gn_pk_user;
-SET GENERATOR gn_pk_user TO 0;
-CREATE GENERATOR gn_pk_detail_stat;
-SET GENERATOR gn_pk_detail_stat TO 0;
-CREATE GENERATOR gn_pk_service;
-SET GENERATOR gn_pk_service TO 0;
-CREATE GENERATOR gn_pk_user_service;
-SET GENERATOR gn_pk_user_service TO 0;
-CREATE GENERATOR gn_pk_message;
-SET GENERATOR gn_pk_message TO 0;
-CREATE GENERATOR gn_pk_stat;
-SET GENERATOR gn_pk_stat TO 0;
-CREATE GENERATOR gn_pk_stat_traffic;
-SET GENERATOR gn_pk_stat_traffic TO 0;
-CREATE GENERATOR gn_pk_user_data;
-SET GENERATOR gn_pk_user_data TO 0;
-CREATE GENERATOR gn_pk_allowed_ip;
-SET GENERATOR gn_pk_allowed_ip TO 0;
-CREATE GENERATOR gn_pk_session;
-SET GENERATOR gn_pk_session TO 0;
-CREATE GENERATOR gn_pk_session_log;
-SET GENERATOR gn_pk_session_log TO 0;
-CREATE GENERATOR gn_pk_session_data;
-SET GENERATOR gn_pk_session_data TO 0;
-CREATE GENERATOR gn_pk_parameter;
-SET GENERATOR gn_pk_parameter TO 0;
-CREATE GENERATOR gn_pk_param_log;
-SET GENERATOR gn_pk_param_log TO 0;
-
-
-/*
- *****************************************************************************
- * -= Создание ТРИГГЕРОВ =-
- *****************************************************************************
- */
-
-SET TERM !! ;
-CREATE TRIGGER tr_admin_bi FOR tb_admins
-ACTIVE BEFORE INSERT POSITION 0
-AS
-BEGIN
- IF (new.pk_admin IS NULL)
- THEN new.pk_admin = GEN_ID(gn_pk_admin, 1);
-END !!
-SET TERM ; !!
-
-set term !! ;
-create trigger tr_tariff_param_bi for tb_tariffs_params active
-before insert position 0
-as
-begin
- if (new.pk_tariff_param is null)
- then new.pk_tariff_param = gen_id(gn_pk_tariff_param, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_corporation_bi for tb_corporations active
-before insert position 0
-as
-begin
- if (new.pk_corporation is null)
- then new.pk_corporation = gen_id(gn_pk_corporation, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_detail_stat_bi for tb_detail_stats active
-before insert position 0
-as
-begin
- if (new.pk_detail_stat is null)
- then new.pk_detail_stat = gen_id(gn_pk_detail_stat, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_service_bi for tb_services active
-before insert position 0
-as
-begin
- if (new.pk_service is null)
- then new.pk_service = gen_id(gn_pk_service, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_user_service_bi for tb_users_services active
-before insert position 0
-as
-begin
- if (new.pk_user_service is null)
- then new.pk_user_service = gen_id(gn_pk_user_service, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_stat_traffic_bi for tb_stats_traffic active
-before insert position 0
-as
-begin
- if (new.pk_stat_traffic is null)
- then new.pk_stat_traffic = gen_id(gn_pk_stat_traffic, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_user_data_bi for tb_users_data active
-before insert position 0
-as
-begin
- if (new.pk_user_data is null)
- then new.pk_user_data = gen_id(gn_pk_user_data, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_allowed_ip_bi for tb_allowed_ip active
-before insert position 0
-as
-begin
- if (new.pk_allowed_ip is null)
- then new.pk_allowed_ip = gen_id(gn_pk_allowed_ip, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_session_data_bi for tb_sessions_data active
-before insert position 0
-as
-begin
- if (new.pk_session_data is null)
- then new.pk_session_data = gen_id(gn_pk_session_data, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_parameter_bi for tb_parameters active
-before insert position 0
-as
-begin
- if (new.pk_parameter is null)
- then new.pk_parameter = gen_id(gn_pk_parameter, 1);
-end !!
-set term ; !!
-
-set term !! ;
-create trigger tr_param_log_bi for tb_params_log active
-before insert position 0
-as
-begin
- if (new.pk_param_log is null)
- then new.pk_param_log = gen_id(gn_pk_param_log, 1);
-end !!
-set term ; !!
-
-/*
- *****************************************************************************
- * -= Создание stored procedure =-
- *****************************************************************************
- */
-
-/*
- * Add a message returning it's ID
- */
-set term !! ;
-create procedure sp_add_message(pk_message integer, login varchar(32), ver integer, msg_type integer, last_send_time integer, creation_time integer, show_time integer, repeat integer, repeat_period integer, msg_text varchar(256))
-returns(res integer)
-as
-begin
- if (:pk_message is null) then
- begin
- pk_message = gen_id(gn_pk_message, 1);
- insert into tb_messages values (:pk_message,
- (select pk_user from tb_users where name = :login),
- :ver,
- :msg_type,
- :last_send_time,
- :creation_time,
- :show_time,
- :repeat,
- :repeat_period,
- :msg_text);
- end
- else
- begin
- update tb_messages set fk_user = (select pk_user from tb_users where name = :login),
- ver = :ver,
- msg_type = :msg_type,
- last_send_time = :last_send_time,
- creation_time = :creation_time,
- show_time = :show_time,
- repeat = :repeat_period,
- repeat_period = :repeat_period,
- msg_text = :msg_text
- where pk_message = :pk_message;
- end
- res = :pk_message;
-end !!
-set term ; !!
-
-set term !! ;
-create procedure sp_delete_service(name varchar(32))
-as
-declare variable pk_service integer;
-begin
- select pk_service from tb_services where name = :name into pk_service;
- if (pk_service is not null) then
- begin
- delete from tb_users_services where fk_service = :pk_service;
- delete from tb_services where pk_service = :pk_service;
- end
-end !!
-set term ; !!
-
-set term !! ;
-create procedure sp_add_tariff(name varchar(32), dirs integer)
-as
-declare variable pk_tariff integer;
-begin
- pk_tariff = gen_id(gn_pk_tariff, 1);
- insert into tb_tariffs (pk_tariff, name, fee, free, passive_cost, traff_type) values (:pk_tariff, :name, 0, 0, 0, 0);
- while (dirs > 0) do
- begin
- insert into tb_tariffs_params (fk_tariff, dir_num, price_day_a,
- price_day_b, price_night_a, price_night_b,
- threshold, time_day_begins, time_day_ends)
- values (:pk_tariff, :dirs - 1, 0, 0, 0, 0, 0, '0:0', '0:0');
- dirs = dirs - 1;
- end
-end !!
-set term ; !!
-
-set term !! ;
-create procedure sp_delete_tariff(name varchar(32))
-as
-declare variable pk_tariff integer;
-begin
- select pk_tariff from tb_tariffs where name = :name into pk_tariff;
- if (pk_tariff is not null) then
- begin
- delete from tb_tariffs_params where fk_tariff = :pk_tariff;
- delete from tb_tariffs where pk_tariff = :pk_tariff;
- end
-end !!
-set term ; !!
-
-set term !! ;
-create procedure sp_add_user(name varchar(32), dirs integer)
-as
-declare variable pk_user integer;
-declare variable pk_stat integer;
-begin
- pk_user = gen_id(gn_pk_user, 1);
- insert into tb_users(pk_user, fk_tariff, fk_tariff_change, fk_corporation, address, always_online, credit, credit_expire, disabled, disabled_detail_stat, email, grp, note, passive, passwd, phone, name, real_name) values (:pk_user, NULL, NULL, NULL, '', 0, 0, 'now', 0, 0, '', '_', '', 0, '', '', :name, '');
- pk_stat = gen_id(gn_pk_stat, 1);
- insert into tb_stats values (:pk_stat, :pk_user, 0, 0, 'now', 0, 'now', 0, 'now');
- while (dirs > 0) do
- begin
- insert into tb_stats_traffic (fk_stat, dir_num, upload, download) values (:pk_stat, :dirs - 1, 0, 0);
- dirs = dirs - 1;
- end
-end!!
-set term ; !!
-
-set term !! ;
-create procedure sp_delete_user(name varchar(32))
-as
-declare variable pk_user integer;
-begin
- select pk_user from tb_users where name = :name into pk_user;
- if (pk_user is not null) then
- begin
- delete from tb_users_services where fk_user = :pk_user;
- delete from tb_params_log where fk_user = :pk_user;
- delete from tb_detail_stats where fk_user = :pk_user;
- delete from tb_stats_traffic where fk_stat in (select pk_stat from tb_stats where fk_user = :pk_user);
- delete from tb_stats where fk_user = :pk_user;
- delete from tb_sessions_data where fk_session_log in (select pk_session_log from tb_sessions_log where fk_user = :pk_user);
- delete from tb_sessions_log where fk_user = :pk_user;
- delete from tb_allowed_ip where fk_user = :pk_user;
- delete from tb_users_data where fk_user = :pk_user;
- delete from tb_messages where fk_user = :pk_user;
- delete from tb_users where pk_user = :pk_user;
- end
-end !!
-set term ; !!
-
-set term !! ;
-create procedure sp_append_session_log(name varchar(32), event_time timestamp, event_type char(1), ip integer)
-returns(pk_session_log integer)
-as
-begin
- pk_session_log = gen_id(gn_pk_session_log, 1);
- insert into tb_sessions_log (pk_session_log, fk_user, event_time, event_type, ip) values (:pk_session_log, (select pk_user from tb_users where name = :name), :event_time, :event_type, :ip);
-end !!
-set term ; !!
-
-set term !! ;
-create procedure sp_add_stat(name varchar(32), cash numeric(10,6), free_mb numeric(10,6), last_activity_time timestamp, last_cash_add numeric(10,6), last_cash_add_time timestamp, passive_time integer, stats_date date)
-returns(pk_stat integer)
-as
-begin
- pk_stat = gen_id(gn_pk_stat, 1);
- insert into tb_stats (pk_stat, fk_user, cash, free_mb, last_activity_time, last_cash_add, last_cash_add_time, passive_time, stats_date) values (:pk_stat, (select pk_user from tb_users where name = :name), :cash, :free_mb, :last_activity_time, :last_cash_add, :last_cash_add_time, :passive_time, :stats_date);
-end !!
-set term ; !!
-
-/*
- *****************************************************************************
- * -= Создание администратора =-
- *****************************************************************************
- */
-
-insert into tb_admins values(0, 'admin', 'geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmk', 1, 1, 1, 1, 1, 1, 1, 1, 1);
-
-/* EOF */
+++ /dev/null
-/*
- * DB migration from v00 to v01 (mysql)
- */
-
-ALTER TABLE users ADD DisabledDetailStat INT(3) DEFAULT 0;
+++ /dev/null
-/*
- * DB migration from v01 to v02 (mysql)
- */
-
-ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month';
-
-CREATE TABLE info
-(
- version INTEGER NOT NULL
-);
-
-INSERT INTO info VALUES (1);
+++ /dev/null
-/*
- * DB migration from v01 to v02 (postgres)
- */
-BEGIN;
-
-CREATE DOMAIN DM_TARIFF_PERIOD AS TEXT NOT NULL
- CONSTRAINT valid_value CHECK (VALUE = 'month' OR VALUE = 'day');
-
-ALTER TABLE tb_tariffs ADD period DM_TARIFF_PERIOD DEFAULT 'month';
-
-UPDATE tb_info SET version = 7;
-
-COMMIT;
+++ /dev/null
-/*
- * DB migration from v01 to v02 (firebird)
- */
-
-CREATE DOMAIN DM_TARIFF_PERIOD AS VARCHAR(32) NOT NULL
- CHECK (VALUE = 'month' OR VALUE = 'day');
-
-ALTER TABLE tb_tariffs ADD period DM_TARIFF_PERIOD DEFAULT 'month';
-
-CREATE TABLE tb_info
-(
- version INTEGER NOT NULL
-);
-
-INSERT INTO tb_info VALUES (1);
+++ /dev/null
-/*
- * DB migration from v02 to v03 (postgres)
- */
-BEGIN;
-
-CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS TEXT NOT NULL
- CONSTRAINT valid_value CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny'));
-
-ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow';
-ALTER TABLE tb_tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:00';
-ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT;
-ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT;
-
-UPDATE tb_info SET version = 8;
-
-COMMIT;
+++ /dev/null
-/*
- * DB migration from v02 to v03 (firebird)
- */
-
-CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS VARCHAR(32) NOT NULL
- CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny'));
-
-ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow';
-ALTER TABLE tb_tariffs ADD change_policy_timeout DM_MOMENT DEFAULT '1970-01-01 00:00:00';
-
-UPDATE tb_tariffs SET change_policy = 'allow', change_policy_timeout = '1970-01-01 00:00:00';
-
-ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT;
-ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT;
-
-UPDATE tb_info SET version = 2;
+++ /dev/null
-password=geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa
-ChgConf=1
-ChgPassword=1
-ChgStat=1
-ChgCash=1
-UsrAddDel=1
-ChgTariff=1
-ChgAdmin=1
+++ /dev/null
-Fee=10.000000
-Free=0
-NoDiscount0=1
-NoDiscount1=1
-NoDiscount2=1
-NoDiscount3=1
-NoDiscount4=1
-NoDiscount5=1
-NoDiscount6=1
-NoDiscount7=1
-NoDiscount8=1
-NoDiscount9=1
-PassiveCost=0.000000
-PriceDayA0=0.000000
-PriceDayA1=0.750000
-PriceDayA2=0.000000
-PriceDayA3=0.000000
-PriceDayA4=0.000000
-PriceDayA5=0.000000
-PriceDayA6=0.000000
-PriceDayA7=0.000000
-PriceDayA8=0.000000
-PriceDayA9=0.000000
-PriceDayB0=0.000000
-PriceDayB1=0.750000
-PriceDayB2=0.000000
-PriceDayB3=0.000000
-PriceDayB4=0.000000
-PriceDayB5=0.000000
-PriceDayB6=0.000000
-PriceDayB7=0.000000
-PriceDayB8=0.000000
-PriceDayB9=0.000000
-PriceNightA0=1.000000
-PriceNightA1=0.000000
-PriceNightA2=0.000000
-PriceNightA3=0.000000
-PriceNightA4=0.000000
-PriceNightA5=0.000000
-PriceNightA6=0.000000
-PriceNightA7=0.000000
-PriceNightA8=0.000000
-PriceNightA9=0.000000
-PriceNightB0=1.000000
-PriceNightB1=0.000000
-PriceNightB2=0.000000
-PriceNightB3=0.000000
-PriceNightB4=0.000000
-PriceNightB5=0.000000
-PriceNightB6=0.000000
-PriceNightB7=0.000000
-PriceNightB8=0.000000
-PriceNightB9=0.000000
-SinglePrice0=1
-SinglePrice1=1
-SinglePrice2=0
-SinglePrice3=0
-SinglePrice4=0
-SinglePrice5=0
-SinglePrice6=0
-SinglePrice7=0
-SinglePrice8=0
-SinglePrice9=0
-Threshold0=0
-Threshold1=0
-Threshold2=0
-Threshold3=0
-Threshold4=0
-Threshold5=0
-Threshold6=0
-Threshold7=0
-Threshold8=0
-Threshold9=0
-Time0=0:0-0:0
-Time1=0:0-0:0
-Time2=0:0-0:0
-Time3=0:0-0:0
-Time4=0:0-0:0
-Time5=0:0-0:0
-Time6=0:0-0:0
-Time7=0:0-0:0
-Time8=0:0-0:0
-Time9=0:0-0:0
-TraffType=up+down
+++ /dev/null
-Address=
-AlwaysOnline=0
-CreationTime=1123487395
-Credit=0.000000
-CreditExpire=0
-Down=0
-Email=
-Group=
-Iface=eth1
-IP=192.168.1.1
-Note=
-Passive=0
-Password=123456
-Phone=
-RealName=
-Tariff=tariff
-TariffChange=
-Userdata0=
-Userdata1=
+++ /dev/null
-Cash=10.000000
-D0=0
-D1=0
-D2=0
-D3=0
-D4=0
-D5=0
-D6=0
-D7=0
-D8=0
-D9=0
-FreeMb=0.000000
-LastActivityTime=0
-LastCashAdd=0
-LastCashAddTime=0
-PassiveTime=0
-U0=0
-U1=0
-U2=0
-U3=0
-U4=0
-U5=0
-U6=0
-U7=0
-U8=0
-U9=0
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include "store_loader.h"
-#include "plugin_mgr.h"
-#include "plugin_runner.h"
-#include "users_impl.h"
-#include "admins_impl.h"
-#include "tariffs_impl.h"
-#include "services_impl.h"
-#include "corps_impl.h"
-#include "traffcounter_impl.h"
-#include "settings_impl.h"
-#include "pidfile.h"
-#include "eventloop.h"
-#include "stg_timer.h"
-
-#include "stg/user.h"
-#include "stg/common.h"
-#include "stg/plugin.h"
-#include "stg/logger.h"
-#include "stg/scriptexecuter.h"
-#include "stg/version.h"
-
-#include <fstream>
-#include <vector>
-#include <set>
-#include <csignal>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib> // srandom, exit
-
-#include <unistd.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h> // S_IRUSR
-#include <fcntl.h> // create
-
-#ifdef DEBUG
- #define NO_DAEMON (1)
-#endif
-
-#define START_FILE "/._ST_ART_ED_"
-
-using STG::SettingsImpl;
-using STG::AdminsImpl;
-using STG::TraffCounterImpl;
-using STG::UsersImpl;
-using STG::TariffsImpl;
-using STG::ServicesImpl;
-using STG::CorporationsImpl;
-using STG::StoreLoader;
-
-namespace
-{
-std::set<pid_t> executers;
-
-void StartTimer();
-int StartScriptExecuter(char* procName, int msgKey, int* msgID);
-int ForkAndWait(const std::string& confDir);
-void KillExecuters();
-
-//-----------------------------------------------------------------------------
-void StartTimer()
-{
- auto& WriteServLog = STG::Logger::get();
-
- if (RunStgTimer())
- {
- WriteServLog("Cannot start timer. Fatal.");
- exit(1);
- }
- else
- WriteServLog("Timer thread started successfully.");
-}
-//-----------------------------------------------------------------------------
-#if defined(LINUX) || defined(DARWIN)
-int StartScriptExecuter(char* procName, int msgKey, int* msgID)
-#else
-int StartScriptExecuter(char*, int msgKey, int* msgID)
-#endif
-{
- auto& WriteServLog = STG::Logger::get();
-
- if (*msgID == -11) // If msgID == -11 - first call. Create queue
- {
- for (int i = 0; i < 2; i++)
- {
- *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
-
- if (*msgID == -1)
- {
- *msgID = msgget(msgKey, 0);
- if (*msgID == -1)
- {
- WriteServLog("Message queue not created.");
- return -1;
- }
- else
- msgctl(*msgID, IPC_RMID, NULL);
- }
- else
- {
- WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
- break;
- }
- }
- }
-
- const auto pid = fork();
-
- switch (pid)
- {
- case -1:
- WriteServLog("Fork error!");
- return -1;
-
- case 0:
-#if defined(LINUX) || defined(DARWIN)
- Executer(*msgID, pid, procName);
-#else
- Executer(*msgID, pid);
-#endif
- return 1;
-
- default:
- if (executers.empty()) {
-#if defined(LINUX) || defined(DARWIN)
- Executer(*msgID, pid, NULL);
-#else
- Executer(*msgID, pid);
-#endif
- }
- executers.insert(pid);
- }
- return 0;
-}
-//-----------------------------------------------------------------------------
-#ifndef NO_DAEMON
-int ForkAndWait(const std::string& confDir)
-#else
-int ForkAndWait(const std::string&)
-#endif
-{
-#ifndef NO_DAEMON
- const auto pid = fork();
- const auto startFile = confDir + START_FILE;
- unlink(startFile.c_str());
-
- switch (pid)
- {
- case -1:
- return -1;
- break;
-
- case 0:
- close(1);
- close(2);
- setsid();
- break;
-
- default:
- struct timespec ts = {0, 200000000};
- for (int i = 0; i < 120 * 5; i++)
- {
- if (access(startFile.c_str(), F_OK) == 0)
- {
- unlink(startFile.c_str());
- exit(0);
- }
-
- nanosleep(&ts, NULL);
- }
- unlink(startFile.c_str());
- exit(1);
- break;
- }
-#endif
- return 0;
-}
-//-----------------------------------------------------------------------------
-void KillExecuters()
-{
- auto pid = executers.begin();
- while (pid != executers.end())
- {
- printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
- kill(*pid, SIGUSR1);
- ++pid;
- }
-}
-//-----------------------------------------------------------------------------
-} // namespace anonymous
-//-----------------------------------------------------------------------------
-int main(int argc, char* argv[])
-{
- int msgID = -11;
-
- STG::Logger::get().setFileName("/var/log/stargazer.log");
-
- if (getuid())
- {
- printf("You must be root. Exit.\n");
- return 1;
- }
-
- SettingsImpl settings(argc == 2 ? argv[1] : "");
-
- if (settings.ReadSettings())
- {
- auto& WriteServLog = STG::Logger::get();
-
- if (settings.GetLogFileName() != "")
- WriteServLog.setFileName(settings.GetLogFileName());
-
- WriteServLog("ReadSettings error. %s", settings.GetStrError().c_str());
- return -1;
- }
-
-#ifndef NO_DAEMON
- const auto startFile = settings.GetConfDir() + START_FILE;
-#endif
-
- if (ForkAndWait(settings.GetConfDir()) < 0)
- {
- STG::Logger::get()("Fork error!");
- return -1;
- }
-
- auto& WriteServLog = STG::Logger::get();
- WriteServLog.setFileName(settings.GetLogFileName());
- WriteServLog("Stg v. %s", SERVER_VERSION);
-
- for (size_t i = 0; i < settings.GetExecutersNum(); i++)
- {
- auto ret = StartScriptExecuter(argv[0], settings.GetExecMsgKey(), &msgID);
- if (ret < 0)
- {
- STG::Logger::get()("Start Script Executer error!");
- return -1;
- }
- if (ret == 1)
- return 0;
- }
-
- PIDFile pidFile(settings.GetPIDFileName());
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
- sigaction(SIGHUP, &sa, NULL); // Apparently FreeBSD ignores SIGHUP by default when launched from rc.d at bot time.
-
- sigset_t signalSet;
- sigfillset(&signalSet);
- pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
- StartTimer();
- WaitTimer();
- if (!IsStgTimerRunning())
- {
- printfd(__FILE__, "Timer thread not started in 1 sec!\n");
- WriteServLog("Timer thread not started in 1 sec!");
- return -1;
- }
-
- auto& loop = EVENT_LOOP_SINGLETON::GetInstance();
-
- StoreLoader storeLoader(settings);
- if (storeLoader.load())
- {
- printfd(__FILE__, "Storage plugin: '%s'\n", storeLoader.GetStrError().c_str());
- WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str());
- return -1;
- }
-
- if (loop.Start())
- {
- printfd(__FILE__, "Event loop not started.\n");
- WriteServLog("Event loop not started.");
- return -1;
- }
-
- auto& store = storeLoader.get();
- WriteServLog("Storage plugin: %s. Loading successfull.", store.GetVersion().c_str());
-
- AdminsImpl admins(store);
- TariffsImpl tariffs(&store);
- ServicesImpl services(&store);
- CorporationsImpl corps(&store);
- UsersImpl users(&settings, &store, &tariffs, services, admins.sysAdmin());
- TraffCounterImpl traffCnt(&users, settings.GetRulesFileName());
- traffCnt.SetMonitorDir(settings.GetMonitorDir());
-
- if (users.Start())
- return -1;
-
- WriteServLog("Users started successfully.");
-
- if (traffCnt.Start())
- return -1;
-
- WriteServLog("Traffcounter started successfully.");
-
- STG::PluginManager manager(settings, store, admins, tariffs, services, corps, users, traffCnt);
-
- srandom(static_cast<unsigned int>(stgTime));
-
- WriteServLog("Stg started successfully.");
- WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
-
-#ifndef NO_DAEMON
- creat(startFile.c_str(), S_IRUSR);
-#endif
-
- bool running = true;
- while (running)
- {
- sigfillset(&signalSet);
- int sig = 0;
- sigwait(&signalSet, &sig);
- int status;
- switch (sig)
- {
- case SIGHUP:
- {
- SettingsImpl newSettings(settings);
- if (newSettings.ReadSettings())
- WriteServLog("ReadSettings error. %s", newSettings.GetStrError().c_str());
- else
- settings = newSettings;
- WriteServLog.setFileName(settings.GetLogFileName());
- traffCnt.Reload();
- manager.reload(settings);
- break;
- }
- case SIGTERM:
- running = false;
- break;
- case SIGINT:
- running = false;
- break;
- case SIGPIPE:
- WriteServLog("Broken pipe!");
- break;
- case SIGCHLD:
- executers.erase(waitpid(-1, &status, WNOHANG));
- if (executers.empty())
- running = false;
- break;
- default:
- WriteServLog("Ignore signal %d", sig);
- break;
- }
- }
-
- WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
-
- manager.stop();
-
- if (loop.Stop())
- WriteServLog("Event loop not stopped.");
-
- if (!traffCnt.Stop())
- WriteServLog("Traffcounter: Stop successfull.");
-
- if (!users.Stop())
- WriteServLog("Users: Stop successfull.");
-
- sleep(1);
- int res = msgctl(msgID, IPC_RMID, NULL);
- if (res)
- WriteServLog("Queue was not removed. id=%d", msgID);
- else
- WriteServLog("Queue removed successfully.");
-
- KillExecuters();
-
- StopStgTimer();
- WriteServLog("StgTimer: Stop successfull.");
-
- WriteServLog("Stg stopped successfully.");
- WriteServLog("---------------------------------------------");
-
- return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- $Revision: 1.2 $
- $Date: 2009/06/09 09:07:32 $
- $Author: faust $
- */
-
-/*
- * An implementation of RAII pid-file writer
- */
-
-#include <fstream>
-#include <unistd.h>
-
-#include "pidfile.h"
-
-PIDFile::PIDFile(const std::string & fn)
- : fileName(fn)
-{
-if (fileName != "")
- {
- std::ofstream pf(fileName.c_str());
- pf << getpid() << std::endl;
- pf.close();
- }
-}
-
-PIDFile::~PIDFile()
-{
-if (fileName != "")
- {
- unlink(fileName.c_str());
- }
-}
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Header file for RAII pid-file writer
- */
-
-/*
- $Revision: 1.2 $
- $Date: 2009/06/09 09:07:32 $
- $Author: faust $
- */
-
-#ifndef __PID_FILE_H__
-#define __PID_FILE_H__
-
-#include <string>
-
-class PIDFile {
-public:
- explicit PIDFile(const std::string & fn);
- ~PIDFile();
-private:
- std::string fileName;
-};
-
-#endif
+++ /dev/null
-/*
- * 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 "plugin_mgr.h"
-
-#include "plugin_runner.h"
-
-#include "admins_impl.h"
-#include "tariffs_impl.h"
-#include "services_impl.h"
-#include "corps_impl.h"
-#include "users_impl.h"
-#include "traffcounter_impl.h"
-#include "settings_impl.h"
-
-#include "stg/logger.h"
-
-using STG::PluginManager;
-using STG::PluginRunner;
-
-namespace
-{
-
-bool StartModCmp(const PluginRunner * lhs, const PluginRunner * rhs)
-{
- return lhs->GetStartPosition() < rhs->GetStartPosition();
-}
-
-bool StopModCmp(const PluginRunner * lhs, const PluginRunner * rhs)
-{
- return lhs->GetStopPosition() > rhs->GetStopPosition();
-}
-
-} // namespace anonymous
-
-PluginManager::PluginManager(const SettingsImpl& settings,
- Store& store, AdminsImpl& admins, TariffsImpl& tariffs,
- ServicesImpl& services, CorporationsImpl& corporations,
- UsersImpl& users, TraffCounterImpl& traffcounter)
- : m_log(Logger::get())
-{
- std::string basePath = settings.GetModulesPath();
- const std::vector<ModuleSettings> & modSettings(settings.GetModulesSettings());
- for (size_t i = 0; i < modSettings.size(); i++)
- {
- std::string moduleName = modSettings[i].moduleName;
- std::string modulePath = basePath + "/mod_" + moduleName + ".so";
- printfd(__FILE__, "Module: %s\n", modulePath.c_str());
- try
- {
- m_modules.push_back(
- new PluginRunner(modulePath, moduleName, modSettings[i], admins, tariffs,
- users, services, corporations, traffcounter,
- store, settings)
- );
- }
- catch (const PluginRunner::Error & ex)
- {
- m_log(ex.what());
- printfd(__FILE__, "%s\n", ex.what());
- // TODO: React
- }
- }
- std::sort(m_modules.begin(), m_modules.end(), StartModCmp);
- for (size_t i = 0; i < m_modules.size(); ++i)
- {
- auto& plugin = m_modules[i]->GetPlugin();
- if (m_modules[i]->Start())
- {
- m_log("Failed to start module '%s': '%s'", plugin.GetVersion().c_str(),
- plugin.GetStrError().c_str());
- printfd(__FILE__, "Failed to start module '%s': '%s'\n", plugin.GetVersion().c_str(),
- plugin.GetStrError().c_str());
- }
- else
- {
- m_log("Module '%s' started successfully.", plugin.GetVersion().c_str());
- printfd(__FILE__, "Module '%s' started successfully.\n", plugin.GetVersion().c_str());
- }
- }
-}
-
-PluginManager::~PluginManager()
-{
- stop();
- for (size_t i = 0; i < m_modules.size(); ++i)
- delete m_modules[i];
-}
-
-void PluginManager::reload(const SettingsImpl& settings)
-{
- const std::vector<ModuleSettings> & modSettings(settings.GetModulesSettings());
- for (size_t i = 0; i < m_modules.size(); ++i)
- {
- for (size_t j = 0; j < modSettings.size(); j++)
- {
- if (modSettings[j].moduleName == m_modules[i]->GetName())
- {
- auto& plugin = m_modules[i]->GetPlugin();
- if (m_modules[i]->Reload(modSettings[j]))
- {
- m_log("Error reloading module '%s': '%s'", plugin.GetVersion().c_str(),
- plugin.GetStrError().c_str());
- printfd(__FILE__, "Error reloading module '%s': '%s'\n", plugin.GetVersion().c_str(),
- plugin.GetStrError().c_str());
- }
- break;
- }
- }
- }
-}
-
-void PluginManager::stop()
-{
- std::sort(m_modules.begin(), m_modules.end(), StopModCmp);
- for (size_t i = 0; i < m_modules.size(); ++i)
- {
- if (!m_modules[i]->IsRunning())
- continue;
- auto& plugin = m_modules[i]->GetPlugin();
- if (m_modules[i]->Stop())
- {
- m_log("Failed to stop module '%s': '%s'", plugin.GetVersion().c_str(),
- plugin.GetStrError().c_str());
- printfd(__FILE__, "Failed to stop module '%s': '%s'\n", plugin.GetVersion().c_str(),
- plugin.GetStrError().c_str());
- }
- else
- {
- m_log("Module '%s' stopped successfully.", plugin.GetVersion().c_str());
- printfd(__FILE__, "Module '%s' stopped successfully.\n", plugin.GetVersion().c_str());
- }
- }
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/module_settings.h"
-
-#include <vector>
-
-namespace STG
-{
-
-class SettingsImpl;
-class PluginRunner;
-struct Store;
-class AdminsImpl;
-class TariffsImpl;
-class ServicesImpl;
-class CorporationsImpl;
-class UsersImpl;
-class TraffCounterImpl;
-class Logger;
-
-class PluginManager
-{
- public:
- PluginManager(const SettingsImpl& settings,
- Store& store, AdminsImpl& admins, TariffsImpl& tariffs,
- ServicesImpl& services, CorporationsImpl& corporations,
- UsersImpl& users, TraffCounterImpl& traffcounter);
- ~PluginManager();
-
- void reload(const SettingsImpl& settings);
- void stop();
-
- private:
- std::vector<PluginRunner*> m_modules;
- Logger & m_log;
-};
-
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "plugin_runner.h"
-
-#include "stg/common.h"
-
-#include <dlfcn.h>
-#include <unistd.h>
-
-using STG::PluginRunner;
-using STG::Plugin;
-
-//-----------------------------------------------------------------------------
-PluginRunner::PluginRunner(const std::string& fileName,
- const std::string& name,
- const ModuleSettings& ms,
- Admins& admins,
- Tariffs& tariffs,
- Users& users,
- Services& services,
- Corporations& corporations,
- TraffCounter& traffcounter,
- Store& store,
- const Settings& settings)
- : pluginFileName(fileName),
- pluginName(name),
- libHandle(NULL),
- m_plugin(load(ms, admins, tariffs, users, services, corporations,
- traffcounter, store, settings))
-{
-}
-//-----------------------------------------------------------------------------
-PluginRunner::~PluginRunner()
-{
- delete &m_plugin;
- if (dlclose(libHandle))
- {
- errorStr = "Failed to unload plugin '" + pluginFileName + "': " + dlerror();
- printfd(__FILE__, "PluginRunner::Unload() - %s", errorStr.c_str());
- }
-}
-//-----------------------------------------------------------------------------
-int PluginRunner::Start()
-{
- int res = m_plugin.Start();
- errorStr = m_plugin.GetStrError();
- return res;
-}
-//-----------------------------------------------------------------------------
-int PluginRunner::Stop()
-{
- int res = m_plugin.Stop();
- errorStr = m_plugin.GetStrError();
- return res;
-}
-//-----------------------------------------------------------------------------
-int PluginRunner::Reload(const ModuleSettings& ms)
-{
- int res = m_plugin.Reload(ms);
- errorStr = m_plugin.GetStrError();
- return res;
-}
-//-----------------------------------------------------------------------------
-Plugin & PluginRunner::load(const ModuleSettings& ms,
- Admins& admins,
- Tariffs& tariffs,
- Users& users,
- Services& services,
- Corporations& corporations,
- TraffCounter& traffcounter,
- Store& store,
- const Settings& settings)
-{
- if (pluginFileName.empty())
- {
- const std::string msg = "Empty plugin file name.";
- printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
- throw Error(msg);
- }
-
- if (access(pluginFileName.c_str(), R_OK))
- {
- const std::string msg = "Plugin file '" + pluginFileName + "' is missing or inaccessible.";
- printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
- throw Error(msg);
- }
-
- libHandle = dlopen(pluginFileName.c_str(), RTLD_NOW);
-
- if (!libHandle)
- {
- std::string msg = "Error loading plugin '" + pluginFileName + "'";
- const char* error = dlerror();
- if (error)
- msg = msg + ": '" + error + "'";
- printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
- throw Error(msg);
- }
-
- using Getter = Plugin* (*)();
- auto GetPlugin = reinterpret_cast<Getter>(dlsym(libHandle, "GetPlugin"));
- if (!GetPlugin)
- {
- const std::string msg = "Plugin '" + pluginFileName + "' does not have GetPlugin() function. ";
- printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
- throw Error(msg);
- }
-
- Plugin* plugin = GetPlugin();
-
- if (!plugin)
- {
- const std::string msg = "Failed to create an instance of plugin '" + pluginFileName + "'.";
- printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
- throw Error(msg);
- }
-
- plugin->SetSettings(ms);
- plugin->SetTariffs(&tariffs);
- plugin->SetAdmins(&admins);
- plugin->SetUsers(&users);
- plugin->SetServices(&services);
- plugin->SetCorporations(&corporations);
- plugin->SetTraffcounter(&traffcounter);
- plugin->SetStore(&store);
- plugin->SetStgSettings(&settings);
-
- if (plugin->ParseSettings())
- {
- const std::string msg = "Plugin '" + pluginFileName + "' is unable to parse settings. " + plugin->GetStrError();
- printfd(__FILE__, "PluginRunner::load() - %s\n", msg.c_str());
- throw Error(msg);
- }
-
- return *plugin;
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/plugin.h"
-
-#include <string>
-#include <stdexcept>
-#include <cstdint>
-
-namespace STG
-{
-
-struct ModuleSettings;
-struct Settings;
-struct Admins;
-struct Tariffs;
-struct Users;
-struct Services;
-struct Corporations;
-struct TraffCounter;
-struct Store;
-
-//-----------------------------------------------------------------------------
-class PluginRunner {
-public:
- struct Error : public std::runtime_error {
- explicit Error(const std::string & msg) : runtime_error(msg) {}
- };
-
- PluginRunner(const std::string& pluginFileName,
- const std::string& pluginName,
- const ModuleSettings& ms,
- Admins& admins,
- Tariffs& tariffs,
- Users& users,
- Services& services,
- Corporations& corporations,
- TraffCounter& traffcounter,
- Store& store,
- const Settings & settings);
- ~PluginRunner();
-
- int Start();
- int Stop();
- int Reload(const ModuleSettings& ms);
- int Restart();
- bool IsRunning() { return m_plugin.IsRunning(); }
-
- const std::string& GetStrError() const { return errorStr; }
- Plugin& GetPlugin() { return m_plugin; }
- const std::string& GetFileName() const { return pluginFileName; }
- const std::string& GetName() const { return pluginName; }
-
- uint16_t GetStartPosition() const { return m_plugin.GetStartPosition(); }
- uint16_t GetStopPosition() const { return m_plugin.GetStopPosition(); }
-
-private:
- Plugin & load(const ModuleSettings& ms,
- Admins& admins,
- Tariffs& tariffs,
- Users& users,
- Services& services,
- Corporations& corporations,
- TraffCounter& traffcounter,
- Store& store,
- const Settings& settings);
-
- std::string pluginFileName;
- std::string pluginName;
- void* libHandle;
-
- Plugin& m_plugin;
- std::string errorStr;
-};
-//-----------------------------------------------------------------------------
-}
+++ /dev/null
-if ( BUILD_MOD_AO )
- add_library ( mod_auth_ao MODULE authorization/ao/ao.cpp )
- target_link_libraries ( mod_auth_ao scriptexecuter logger common )
- set_target_properties ( mod_auth_ao PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_AO )
-
-if ( BUILD_MOD_IA )
- add_library ( mod_auth_ia MODULE authorization/inetaccess/inetaccess.cpp )
- target_link_libraries ( mod_auth_ia scriptexecuter crypto logger common )
- set_target_properties ( mod_auth_ia PROPERTIES PREFIX "" )
- if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
- set_target_properties ( mod_auth_ia PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
- endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
-endif ( BUILD_MOD_IA )
-
-if ( BUILD_MOD_CAP_NF )
- add_library ( mod_cap_nf MODULE capture/cap_nf/cap_nf.cpp )
- target_link_libraries ( mod_cap_nf logger common )
- set_target_properties ( mod_cap_nf PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_CAP_NF )
-
-if ( BUILD_MOD_CAP_DIVERT )
- add_library ( mod_cap_divert MODULE capture/divert_freebsd/divert_cap.cpp )
- target_link_libraries ( mod_cap_divert logger common )
- set_target_properties ( mod_cap_divert PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_CAP_DIVERT )
-
-if ( BUILD_MOD_CAP_ETHER_FREEBSD )
- add_library ( mod_cap_bpf MODULE capture/ether_freebsd/ether_cap.cpp )
- target_link_libraries ( mod_cap_bpf logger common )
- set_target_properties ( mod_cap_bpf PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_CAP_ETHER_FREEBSD )
-
-if ( BUILD_MOD_CAP_ETHER_LINUX )
- add_library ( mod_cap_ether MODULE capture/ether_linux/ether_cap.cpp )
- target_link_libraries ( mod_cap_ether logger common )
- set_target_properties ( mod_cap_ether PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_CAP_ETHER_LINUX )
-
-if ( BUILD_MOD_CAP_PCAP )
- find_package ( PCap REQUIRED )
- add_library ( mod_cap_pcap MODULE capture/pcap/pcap_cap.cpp )
- target_link_libraries ( mod_cap_pcap logger common PCap::PCap )
- set_target_properties ( mod_cap_pcap PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_CAP_PCAP )
-
-if ( BUILD_MOD_CAP_NFQUEUE )
- find_package ( NFQueue REQUIRED )
- find_package ( NFNetLink REQUIRED )
- find_package ( MNL REQUIRED )
- add_library ( mod_cap_nfqueue MODULE capture/nfqueue/nfqueue.cpp )
- target_link_libraries ( mod_cap_nfqueue logger common NF::Queue NF::NetLink MNL::MNL )
- set_target_properties ( mod_cap_nfqueue PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_CAP_NFQUEUE )
-
-if ( BUILD_MOD_SGCONFIG )
- find_package ( EXPAT REQUIRED )
- add_library ( mod_conf_sg MODULE configuration/sgconfig/stgconfig.cpp
- configuration/sgconfig/conn.cpp
- configuration/sgconfig/configproto.cpp
- configuration/sgconfig/parser.cpp
- configuration/sgconfig/parser_tariffs.cpp
- configuration/sgconfig/parser_admins.cpp
- configuration/sgconfig/parser_users.cpp
- configuration/sgconfig/parser_services.cpp
- configuration/sgconfig/parser_message.cpp
- configuration/sgconfig/parser_auth_by.cpp
- configuration/sgconfig/parser_user_info.cpp
- configuration/sgconfig/parser_server_info.cpp )
- target_link_libraries ( mod_conf_sg scriptexecuter crypto logger common EXPAT::EXPAT )
- set_target_properties ( mod_conf_sg PROPERTIES PREFIX "" )
- if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
- set_target_properties ( mod_conf_sg PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
- endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
-endif ( BUILD_MOD_SGCONFIG )
-
-if ( BUILD_MOD_RPCCONFIG )
- find_package ( XMLRPC REQUIRED c++ abyss-server )
- include_directories ( ${XMLRPC_INCLUDE_DIRS} )
- add_library ( mod_conf_rpc MODULE configuration/rpcconfig/rpcconfig.cpp
- configuration/rpcconfig/user_helper.cpp
- configuration/rpcconfig/tariff_helper.cpp
- configuration/rpcconfig/info_methods.cpp
- configuration/rpcconfig/users_methods.cpp
- configuration/rpcconfig/tariffs_methods.cpp
- configuration/rpcconfig/admins_methods.cpp
- configuration/rpcconfig/messages_methods.cpp )
- target_link_libraries ( mod_conf_rpc scriptexecuter logger common ${XMLRPC_LIBRARIES} )
- set_target_properties ( mod_conf_rpc PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_RPCCONFIG )
-
-if ( BUILD_MOD_PING )
- add_library ( mod_ping MODULE other/ping/ping.cpp )
- target_link_libraries ( mod_ping scriptexecuter logger pinger common )
- set_target_properties ( mod_ping PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_PING )
-
-if ( BUILD_MOD_RSCRYPT )
- add_library ( mod_remote_script MODULE other/rscript/rscript.cpp other/rscript/nrmap_parser.cpp )
- target_link_libraries ( mod_remote_script crypto scriptexecuter logger common )
- set_target_properties ( mod_remote_script PROPERTIES PREFIX "" )
- if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
- set_target_properties ( mod_remote_script PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
- endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" )
-endif ( BUILD_MOD_RSCRYPT )
-
-if ( BUILD_MOD_SMUX )
- add_library ( mod_smux MODULE other/smux/smux.cpp
- other/smux/sensors.cpp
- other/smux/tables.cpp
- other/smux/handlers.cpp
- other/smux/utils.cpp
- other/smux/types.cpp )
- target_link_libraries ( mod_smux scriptexecuter logger smux common )
- set_target_properties ( mod_smux PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_SMUX )
-
-if ( BUILD_MOD_STORE_FILES )
- add_library ( mod_store_files MODULE store/files/file_store.cpp )
- target_link_libraries ( mod_store_files crypto conffiles logger common )
- set_target_properties ( mod_store_files PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_STORE_FILES )
-
-if ( BUILD_MOD_STORE_FIREBIRD )
- find_package ( FBClient REQUIRED )
- add_library ( mod_store_firebird MODULE store/firebird/firebird_store.cpp
- store/firebird/firebird_store_admins.cpp
- store/firebird/firebird_store_corporations.cpp
- store/firebird/firebird_store_messages.cpp
- store/firebird/firebird_store_services.cpp
- store/firebird/firebird_store_tariffs.cpp
- store/firebird/firebird_store_users.cpp
- store/firebird/firebird_store_utils.cpp )
- target_link_libraries ( mod_store_firebird crypto common logger ibpp FBClient::FBClient )
- set_target_properties ( mod_store_firebird PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_STORE_FIREBIRD )
-
-if ( BUILD_MOD_STORE_MYSQL )
- find_package ( MySQLConnector REQUIRED )
- add_library ( mod_store_mysql MODULE store/mysql/mysql_store.cpp )
- target_link_libraries ( mod_store_mysql crypto logger common MySQL::Connector )
- set_target_properties ( mod_store_mysql PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_STORE_MYSQL )
-
-if ( BUILD_MOD_STORE_POSTGRESQL )
- find_package ( PostgreSQL REQUIRED )
- include_directories ( ${PostgreSQL_INCLUDE_DIRS} )
- add_library ( mod_store_postgresql MODULE store/postgresql/postgresql_store.cpp
- store/postgresql/postgresql_store_admins.cpp
- store/postgresql/postgresql_store_corporations.cpp
- store/postgresql/postgresql_store_messages.cpp
- store/postgresql/postgresql_store_services.cpp
- store/postgresql/postgresql_store_tariffs.cpp
- store/postgresql/postgresql_store_users.cpp
- store/postgresql/postgresql_store_utils.cpp )
- target_link_libraries ( mod_store_postgresql crypto logger common ${PostgreSQL_LIBRARIES} )
- set_target_properties ( mod_store_postgresql PROPERTIES PREFIX "" )
-endif ( BUILD_MOD_STORE_POSTGRESQL )
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include "ao.h"
-
-#include "stg/user.h"
-#include "stg/users.h"
-#include "stg/user_property.h"
-#include "stg/common.h"
-
-#include <algorithm> // for_each
-#include <functional> // mem_fun_ref
-#include <csignal>
-#include <cassert>
-
-#include <unistd.h>
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static AUTH_AO plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-std::string AUTH_AO::GetVersion() const
-{
-return "Always Online authorizator v.1.0";
-}
-//-----------------------------------------------------------------------------
-AUTH_AO::AUTH_AO()
- : users(NULL),
- isRunning(false),
- onAddUserNotifier(*this),
- onDelUserNotifier(*this),
- logger(STG::PluginLogger::get("auth_ao"))
-{
-}
-//-----------------------------------------------------------------------------
-int AUTH_AO::Start()
-{
-printfd(__FILE__, "AUTH_AO::Start()\n");
-GetUsers();
-
-users->AddNotifierUserAdd(&onAddUserNotifier);
-users->AddNotifierUserDel(&onDelUserNotifier);
-
-std::for_each(userList.begin(), userList.end(), [this](auto user){ UpdateUserAuthorization(user); });
-
-isRunning = true;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_AO::Stop()
-{
-printfd(__FILE__, "AUTH_AO::Stop()\n");
-if (!isRunning)
- return 0;
-
-users->DelNotifierUserAdd(&onAddUserNotifier);
-users->DelNotifierUserDel(&onDelUserNotifier);
-
-auto it = userList.begin();
-while (it != userList.end())
- {
- if ((*it)->IsAuthorizedBy(this))
- users->Unauthorize((*it)->GetLogin(), this);
- UnSetUserNotifiers(*it);
- ++it;
- }
-isRunning = false;
-return 0;
-}
-//-----------------------------------------------------------------------------
-void AUTH_AO::SetUserNotifiers(UserPtr u)
-{
-// ---------- AlwaysOnline -------------------
-CHG_BEFORE_NOTIFIER<int> BeforeChgAONotifier(*this, u);
-CHG_AFTER_NOTIFIER<int> AfterChgAONotifier(*this, u);
-
-BeforeChgAONotifierList.push_front(BeforeChgAONotifier);
-AfterChgAONotifierList.push_front(AfterChgAONotifier);
-
-u->GetProperties().alwaysOnline.AddBeforeNotifier(&BeforeChgAONotifierList.front());
-u->GetProperties().alwaysOnline.AddAfterNotifier(&AfterChgAONotifierList.front());
-// ---------- AlwaysOnline end ---------------
-
-// ---------- IP -------------------
-CHG_BEFORE_NOTIFIER<STG::UserIPs> BeforeChgIPNotifier(*this, u);
-CHG_AFTER_NOTIFIER<STG::UserIPs> AfterChgIPNotifier(*this, u);
-
-BeforeChgIPNotifierList.push_front(BeforeChgIPNotifier);
-AfterChgIPNotifierList.push_front(AfterChgIPNotifier);
-
-u->GetProperties().ips.AddBeforeNotifier(&BeforeChgIPNotifierList.front());
-u->GetProperties().ips.AddAfterNotifier(&AfterChgIPNotifierList.front());
-// ---------- IP end ---------------
-}
-//-----------------------------------------------------------------------------
-void AUTH_AO::UnSetUserNotifiers(UserPtr u)
-{
-// --- AlwaysOnline ---
-auto aoBIter = find_if(BeforeChgAONotifierList.begin(),
- BeforeChgAONotifierList.end(),
- [u](auto notifier){ return notifier.GetUser() == u; });
-
-if (aoBIter != BeforeChgAONotifierList.end())
- {
- aoBIter->GetUser()->GetProperties().alwaysOnline.DelBeforeNotifier(&(*aoBIter));
- BeforeChgAONotifierList.erase(aoBIter);
- }
-
-auto aoAIter = find_if(AfterChgAONotifierList.begin(),
- AfterChgAONotifierList.end(),
- [u](auto notifier){ return notifier.GetUser() == u; });
-
-if (aoAIter != AfterChgAONotifierList.end())
- {
- aoAIter->GetUser()->GetProperties().alwaysOnline.DelAfterNotifier(&(*aoAIter));
- AfterChgAONotifierList.erase(aoAIter);
- }
-// --- AlwaysOnline end ---
-
-// --- IP ---
-auto ipBIter = std::find_if(BeforeChgIPNotifierList.begin(),
- BeforeChgIPNotifierList.end(),
- [u](auto notifier){ return notifier.GetUser() == u; });
-
-if (ipBIter != BeforeChgIPNotifierList.end())
- {
- ipBIter->GetUser()->GetProperties().ips.DelBeforeNotifier(&(*ipBIter));
- BeforeChgIPNotifierList.erase(ipBIter);
- }
-
-auto ipAIter = find_if(AfterChgIPNotifierList.begin(),
- AfterChgIPNotifierList.end(),
- [u](auto notifier){ return notifier.GetUser() == u; });
-
-if (ipAIter != AfterChgIPNotifierList.end())
- {
- ipAIter->GetUser()->GetProperties().ips.DelAfterNotifier(&(*ipAIter));
- AfterChgIPNotifierList.erase(ipAIter);
- }
-// --- IP end ---
-}
-//-----------------------------------------------------------------------------
-void AUTH_AO::GetUsers()
-{
-UserPtr u;
-int h = users->OpenSearch();
-assert(h && "USERS::OpenSearch is always correct");
-
-while (!users->SearchNext(h, &u))
- {
- userList.push_back(u);
- SetUserNotifiers(u);
- }
-
-users->CloseSearch(h);
-}
-//-----------------------------------------------------------------------------
-void AUTH_AO::UpdateUserAuthorization(ConstUserPtr u) const
-{
-if (u->GetProperties().alwaysOnline)
- {
- auto ips = u->GetProperties().ips.get();
- if (ips.onlyOneIP())
- {
- users->Authorize(u->GetLogin(), ips[0].ip, 0xFFffFFff, this);
- }
- }
-}
-//-----------------------------------------------------------------------------
-void AUTH_AO::AddUser(UserPtr u)
-{
-SetUserNotifiers(u);
-userList.push_back(u);
-UpdateUserAuthorization(u);
-}
-//-----------------------------------------------------------------------------
-void AUTH_AO::DelUser(UserPtr u)
-{
-if (u->IsAuthorizedBy(this))
- users->Unauthorize(u->GetLogin(), this);
-UnSetUserNotifiers(u);
-userList.erase(std::remove(userList.begin(), userList.end(), u), userList.end());
-}
-//-----------------------------------------------------------------------------
-int AUTH_AO::SendMessage(const STG::Message &, uint32_t) const
-{
-errorStr = "Authorization modele \'AlwaysOnline\' does not support sending messages";
-return -1;
-}
-//-----------------------------------------------------------------------------
-template <typename varParamType>
-void CHG_BEFORE_NOTIFIER<varParamType>::Notify(const varParamType &, const varParamType &)
-{
-//EVENT_LOOP_SINGLETON::GetInstance().Enqueue(auth, &AUTH_AO::Unauthorize, user);
-if (user->IsAuthorizedBy(&auth))
- auth.users->Unauthorize(user->GetLogin(), &auth);
-}
-//-----------------------------------------------------------------------------
-template <typename varParamType>
-void CHG_AFTER_NOTIFIER<varParamType>::Notify(const varParamType &, const varParamType &)
-{
-//EVENT_LOOP_SINGLETON::GetInstance().Enqueue(auth, &AUTH_AO::UpdateUserAuthorization, user);
-auth.UpdateUserAuthorization(user);
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/auth.h"
-#include "stg/module_settings.h"
-#include "stg/store.h"
-#include "stg/notifer.h"
-#include "stg/user_ips.h"
-#include "stg/user.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <vector>
-#include <list>
-
-#include <pthread.h>
-
-namespace STG
-{
-struct Users;
-}
-
-class AUTH_AO;
-
-using UserPtr = STG::User*;
-using ConstUserPtr = const STG::User*;
-
-template <typename T>
-class CHG_BEFORE_NOTIFIER : public STG::PropertyNotifierBase<T> {
-public:
- CHG_BEFORE_NOTIFIER(AUTH_AO & a, UserPtr u)
- : user(u), auth(a) {}
- CHG_BEFORE_NOTIFIER(const CHG_BEFORE_NOTIFIER<T> & rvalue)
- : user(rvalue.user), auth(rvalue.auth) {}
- void Notify(const T & oldValue, const T & newValue);
- UserPtr GetUser() const { return user; }
-
-private:
- CHG_BEFORE_NOTIFIER<T> & operator=(const CHG_BEFORE_NOTIFIER<T> & rvalue);
-
- UserPtr user;
- const AUTH_AO & auth;
-};
-//-----------------------------------------------------------------------------
-template <typename T>
-class CHG_AFTER_NOTIFIER : public STG::PropertyNotifierBase<T> {
-public:
- CHG_AFTER_NOTIFIER(AUTH_AO & a, UserPtr u)
- : user(u), auth(a) {}
- CHG_AFTER_NOTIFIER(const CHG_AFTER_NOTIFIER<T> & rvalue)
- : user(rvalue.user), auth(rvalue.auth) {}
- void Notify(const T & oldValue, const T & newValue);
- UserPtr GetUser() const { return user; }
-
-private:
- CHG_AFTER_NOTIFIER<T> & operator=(const CHG_AFTER_NOTIFIER<T> & rvalue);
-
- UserPtr user;
- const AUTH_AO & auth;
-};
-//-----------------------------------------------------------------------------
-class AUTH_AO : public STG::Auth {
-public:
- AUTH_AO();
-
- void SetUsers(STG::Users * u) override { users = u; }
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return isRunning; }
- void SetSettings(const STG::ModuleSettings &) override {}
- int ParseSettings() override { return 0; }
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override;
- uint16_t GetStartPosition() const override { return 30; }
- uint16_t GetStopPosition() const override { return 30; }
-
- int SendMessage(const STG::Message & msg, uint32_t ip) const override;
-
-private:
- AUTH_AO(const AUTH_AO & rvalue);
- AUTH_AO & operator=(const AUTH_AO & rvalue);
-
- void AddUser(UserPtr u);
- void DelUser(UserPtr u);
-
- void GetUsers();
- void SetUserNotifiers(UserPtr u);
- void UnSetUserNotifiers(UserPtr u);
- void UpdateUserAuthorization(ConstUserPtr u) const;
-
- mutable std::string errorStr;
- STG::Users * users;
- std::vector<UserPtr> userList;
- bool isRunning;
- STG::ModuleSettings settings;
-
- std::list<CHG_BEFORE_NOTIFIER<int> > BeforeChgAONotifierList;
- std::list<CHG_AFTER_NOTIFIER<int> > AfterChgAONotifierList;
-
- std::list<CHG_BEFORE_NOTIFIER<STG::UserIPs> > BeforeChgIPNotifierList;
- std::list<CHG_AFTER_NOTIFIER<STG::UserIPs> > AfterChgIPNotifierList;
-
- class ADD_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
- public:
- explicit ADD_USER_NONIFIER(AUTH_AO & a) : auth(a) {}
- virtual ~ADD_USER_NONIFIER() {}
- void Notify(const UserPtr & user) { auth.AddUser(user); }
-
- private:
- ADD_USER_NONIFIER(const ADD_USER_NONIFIER & rvalue);
- ADD_USER_NONIFIER & operator=(const ADD_USER_NONIFIER & rvalue);
-
- AUTH_AO & auth;
- } onAddUserNotifier;
-
- class DEL_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
- public:
- explicit DEL_USER_NONIFIER(AUTH_AO & a) : auth(a) {}
- virtual ~DEL_USER_NONIFIER() {}
- void Notify(const UserPtr & user) { auth.DelUser(user); }
-
- private:
- DEL_USER_NONIFIER(const DEL_USER_NONIFIER & rvalue);
- DEL_USER_NONIFIER & operator=(const DEL_USER_NONIFIER & rvalue);
-
- AUTH_AO & auth;
- } onDelUserNotifier;
-
- STG::PluginLogger logger;
-
- friend class CHG_BEFORE_NOTIFIER<int>;
- friend class CHG_AFTER_NOTIFIER<int>;
- friend class CHG_BEFORE_NOTIFIER<STG::UserIPs>;
- friend class CHG_AFTER_NOTIFIER<STG::UserIPs>;
-
-};
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include "inetaccess.h"
-
-#include "stg/common.h"
-#include "stg/locker.h"
-#include "stg/tariff.h"
-#include "stg/settings.h"
-
-#include <algorithm>
-#include <csignal>
-#include <cstdlib>
-#include <cstdio> // snprintf
-#include <cerrno>
-#include <cmath>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h> // close
-
-#define IA_PROTO_VER (6)
-
-extern volatile time_t stgTime;
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static AUTH_IA plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-AUTH_IA_SETTINGS::AUTH_IA_SETTINGS()
- : userDelay(0),
- userTimeout(0),
- port(0),
- freeMbShowType(freeMbCash),
- logProtocolErrors(false)
-{
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-int p;
-STG::ParamValue pv;
-std::vector<STG::ParamValue>::const_iterator pvi;
-///////////////////////////
-pv.param = "Port";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Port\' not found.";
- printfd(__FILE__, "Parameter 'Port' not found\n");
- return -1;
- }
-if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
- {
- errorStr = "Cannot parse parameter \'Port\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'Port'\n");
- return -1;
- }
-port = static_cast<uint16_t>(p);
-///////////////////////////
-pv.param = "UserDelay";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'UserDelay\' not found.";
- printfd(__FILE__, "Parameter 'UserDelay' not found\n");
- return -1;
- }
-
-if (ParseIntInRange(pvi->value[0], 5, 600, &userDelay))
- {
- errorStr = "Cannot parse parameter \'UserDelay\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'UserDelay'\n");
- return -1;
- }
-///////////////////////////
-pv.param = "UserTimeout";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'UserTimeout\' not found.";
- printfd(__FILE__, "Parameter 'UserTimeout' not found\n");
- return -1;
- }
-
-if (ParseIntInRange(pvi->value[0], 15, 1200, &userTimeout))
- {
- errorStr = "Cannot parse parameter \'UserTimeout\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'UserTimeout'\n");
- return -1;
- }
-///////////////////////////
-pv.param = "LogProtocolErrors";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- logProtocolErrors = false;
-else if (ParseYesNo(pvi->value[0], &logProtocolErrors))
- {
- errorStr = "Cannot parse parameter \'LogProtocolErrors\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'LogProtocolErrors'\n");
- return -1;
- }
-/////////////////////////////////////////////////////////////
-std::string freeMbType;
-int n = 0;
-pv.param = "FreeMb";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'FreeMb\' not found.";
- printfd(__FILE__, "Parameter 'FreeMb' not found\n");
- return -1;
- }
-freeMbType = pvi->value[0];
-
-if (strcasecmp(freeMbType.c_str(), "cash") == 0)
- {
- freeMbShowType = freeMbCash;
- }
-else if (strcasecmp(freeMbType.c_str(), "none") == 0)
- {
- freeMbShowType = freeMbNone;
- }
-else if (!str2x(freeMbType.c_str(), n))
- {
- if (n < 0 || n >= DIR_NUM)
- {
- errorStr = "Incorrect parameter \'" + freeMbType + "\'.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
- freeMbShowType = (FREEMB)(freeMb0 + n);
- }
-else
- {
- errorStr = "Incorrect parameter \'" + freeMbType + "\'.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-/////////////////////////////////////////////////////////////
-return 0;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-#ifdef IA_PHASE_DEBUG
-IA_PHASE::IA_PHASE()
- : phase(1),
- flog(NULL)
-{
-gettimeofday(&phaseTime, NULL);
-}
-#else
-IA_PHASE::IA_PHASE()
- : phase(1)
-{
-gettimeofday(&phaseTime, NULL);
-}
-#endif
-//-----------------------------------------------------------------------------
-IA_PHASE::~IA_PHASE()
-{
-#ifdef IA_PHASE_DEBUG
-flog = fopen(log.c_str(), "at");
-if (flog)
- {
- fprintf(flog, "IA %s D\n", login.c_str());
- fclose(flog);
- }
-#endif
-}
-//-----------------------------------------------------------------------------
-#ifdef IA_PHASE_DEBUG
-void IA_PHASE::SetLogFileName(const string & logFileName)
-{
-log = logFileName + ".ia.log";
-}
-//-----------------------------------------------------------------------------
-void IA_PHASE::SetUserLogin(const string & login)
-{
-IA_PHASE::login = login;
-}
-//-----------------------------------------------------------------------------
-void IA_PHASE::WritePhaseChange(int newPhase)
-{
-UTIME newPhaseTime;
-gettimeofday(&newPhaseTime, NULL);
-flog = fopen(log.c_str(), "at");
-if (flog)
- {
- string action = newPhase == phase ? "U" : "C";
- double delta = newPhaseTime.GetSec() - phaseTime.GetSec();
- delta += (newPhaseTime.GetUSec() - phaseTime.GetUSec()) * 1.0e-6;
- fprintf(flog, "IA %s %s oldPhase = %d, newPhase = %d. dt = %.6f\n",
- login.c_str(),
- action.c_str(),
- phase,
- newPhase,
- delta);
- fclose(flog);
- }
-}
-#endif
-//-----------------------------------------------------------------------------
-void IA_PHASE::SetPhase1()
-{
-#ifdef IA_PHASE_DEBUG
-WritePhaseChange(1);
-#endif
-phase = 1;
-gettimeofday(&phaseTime, NULL);
-}
-//-----------------------------------------------------------------------------
-void IA_PHASE::SetPhase2()
-{
-#ifdef IA_PHASE_DEBUG
-WritePhaseChange(2);
-#endif
-phase = 2;
-gettimeofday(&phaseTime, NULL);
-}
-//-----------------------------------------------------------------------------
-void IA_PHASE::SetPhase3()
-{
-#ifdef IA_PHASE_DEBUG
-WritePhaseChange(3);
-#endif
-phase = 3;
-gettimeofday(&phaseTime, NULL);
-}
-//-----------------------------------------------------------------------------
-void IA_PHASE::SetPhase4()
-{
-#ifdef IA_PHASE_DEBUG
-WritePhaseChange(4);
-#endif
-phase = 4;
-gettimeofday(&phaseTime, NULL);
-}
-//-----------------------------------------------------------------------------
-int IA_PHASE::GetPhase() const
-{
-return phase;
-}
-//-----------------------------------------------------------------------------
-void IA_PHASE::UpdateTime()
-{
-#ifdef IA_PHASE_DEBUG
-WritePhaseChange(phase);
-#endif
-gettimeofday(&phaseTime, NULL);
-}
-//-----------------------------------------------------------------------------
-const UTIME & IA_PHASE::GetTime() const
-{
-return phaseTime;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-AUTH_IA::AUTH_IA()
- : nonstop(false),
- isRunningRun(false),
- isRunningRunTimeouter(false),
- users(NULL),
- stgSettings(NULL),
- listenSocket(-1),
- enabledDirs(0xFFffFFff),
- onDelUserNotifier(*this),
- logger(STG::PluginLogger::get("auth_ia"))
-{
-InitContext("pr7Hhen", 7, &ctxS);
-
-pthread_mutexattr_t attr;
-pthread_mutexattr_init(&attr);
-pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-pthread_mutex_init(&mutex, &attr);
-
-memset(&connSynAck6, 0, sizeof(CONN_SYN_ACK_6));
-memset(&connSynAck8, 0, sizeof(CONN_SYN_ACK_8));
-memset(&disconnSynAck6, 0, sizeof(DISCONN_SYN_ACK_6));
-memset(&disconnSynAck8, 0, sizeof(DISCONN_SYN_ACK_8));
-memset(&aliveSyn6, 0, sizeof(ALIVE_SYN_6));
-memset(&aliveSyn8, 0, sizeof(ALIVE_SYN_8));
-memset(&fin6, 0, sizeof(FIN_6));
-memset(&fin8, 0, sizeof(FIN_8));
-
-printfd(__FILE__, "sizeof(CONN_SYN_6) = %d %d\n", sizeof(CONN_SYN_6), Min8(sizeof(CONN_SYN_6)));
-printfd(__FILE__, "sizeof(CONN_SYN_8) = %d %d\n", sizeof(CONN_SYN_8), Min8(sizeof(CONN_SYN_8)));
-printfd(__FILE__, "sizeof(CONN_SYN_ACK_6) = %d %d\n", sizeof(CONN_SYN_ACK_6), Min8(sizeof(CONN_SYN_ACK_6)));
-printfd(__FILE__, "sizeof(CONN_SYN_ACK_8) = %d %d\n", sizeof(CONN_SYN_ACK_8), Min8(sizeof(CONN_SYN_ACK_8)));
-printfd(__FILE__, "sizeof(CONN_ACK_6) = %d %d\n", sizeof(CONN_ACK_6), Min8(sizeof(CONN_ACK_6)));
-printfd(__FILE__, "sizeof(ALIVE_SYN_6) = %d %d\n", sizeof(ALIVE_SYN_6), Min8(sizeof(ALIVE_SYN_6)));
-printfd(__FILE__, "sizeof(ALIVE_SYN_8) = %d %d\n", sizeof(ALIVE_SYN_8), Min8(sizeof(ALIVE_SYN_8)));
-printfd(__FILE__, "sizeof(ALIVE_ACK_6) = %d %d\n", sizeof(ALIVE_ACK_6), Min8(sizeof(ALIVE_ACK_6)));
-printfd(__FILE__, "sizeof(DISCONN_SYN_6) = %d %d\n", sizeof(DISCONN_SYN_6), Min8(sizeof(DISCONN_SYN_6)));
-printfd(__FILE__, "sizeof(DISCONN_SYN_ACK_6) = %d %d\n", sizeof(DISCONN_SYN_ACK_6), Min8(sizeof(DISCONN_SYN_ACK_6)));
-printfd(__FILE__, "sizeof(DISCONN_SYN_ACK_8) = %d %d\n", sizeof(DISCONN_SYN_ACK_8), Min8(sizeof(DISCONN_SYN_ACK_8)));
-printfd(__FILE__, "sizeof(DISCONN_ACK_6) = %d %d\n", sizeof(DISCONN_ACK_6), Min8(sizeof(DISCONN_ACK_6)));
-printfd(__FILE__, "sizeof(FIN_6) = %d %d\n", sizeof(FIN_6), Min8(sizeof(FIN_6)));
-printfd(__FILE__, "sizeof(FIN_8) = %d %d\n", sizeof(FIN_8), Min8(sizeof(FIN_8)));
-printfd(__FILE__, "sizeof(ERR) = %d %d\n", sizeof(ERR), Min8(sizeof(ERR)));
-printfd(__FILE__, "sizeof(INFO_6) = %d %d\n", sizeof(INFO_6), Min8(sizeof(INFO_6)));
-printfd(__FILE__, "sizeof(INFO_7) = %d %d\n", sizeof(INFO_7), Min8(sizeof(INFO_7)));
-printfd(__FILE__, "sizeof(INFO_8) = %d %d\n", sizeof(INFO_8), Min8(sizeof(INFO_8)));
-
-packetTypes["CONN_SYN"] = CONN_SYN_N;
-packetTypes["CONN_SYN_ACK"] = CONN_SYN_ACK_N;
-packetTypes["CONN_ACK"] = CONN_ACK_N;
-packetTypes["ALIVE_SYN"] = ALIVE_SYN_N;
-packetTypes["ALIVE_ACK"] = ALIVE_ACK_N;
-packetTypes["DISCONN_SYN"] = DISCONN_SYN_N;
-packetTypes["DISCONN_SYN_ACK"] = DISCONN_SYN_ACK_N;
-packetTypes["DISCONN_ACK"] = DISCONN_ACK_N;
-packetTypes["FIN"] = FIN_N;
-packetTypes["ERR"] = ERROR_N;
-}
-//-----------------------------------------------------------------------------
-AUTH_IA::~AUTH_IA()
-{
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Start()
-{
-users->AddNotifierUserDel(&onDelUserNotifier);
-nonstop = true;
-
-if (PrepareNet())
- {
- return -1;
- }
-
-if (!isRunningRun)
- {
- if (pthread_create(&recvThread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- printfd(__FILE__, "Cannot create recv thread\n");
- logger("Cannot create recv thread.");
- return -1;
- }
- }
-
-if (!isRunningRunTimeouter)
- {
- if (pthread_create(&timeouterThread, NULL, RunTimeouter, this))
- {
- errorStr = "Cannot create thread.";
- printfd(__FILE__, "Cannot create timeouter thread\n");
- logger("Cannot create timeouter thread.");
- return -1;
- }
- }
-errorStr = "";
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Stop()
-{
-if (!IsRunning())
- return 0;
-
-nonstop = false;
-
-std::for_each(
- ip2user.begin(),
- ip2user.end(),
- UnauthorizeUser(this)
- );
-
-if (isRunningRun)
- {
- //5 seconds to thread stops itself
- for (int i = 0; i < 25 && isRunningRun; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- }
-
-FinalizeNet();
-
-if (isRunningRunTimeouter)
- {
- //5 seconds to thread stops itself
- for (int i = 0; i < 25 && isRunningRunTimeouter; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- }
-
-users->DelNotifierUserDel(&onDelUserNotifier);
-
-if (isRunningRun || isRunningRunTimeouter)
- return -1;
-
-printfd(__FILE__, "AUTH_IA::Stoped successfully.\n");
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * AUTH_IA::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-AUTH_IA * ia = static_cast<AUTH_IA *>(d);
-
-ia->isRunningRun = true;
-
-char buffer[512];
-
-time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
-
-while (ia->nonstop)
- {
- ia->RecvData(buffer, sizeof(buffer));
- if ((touchTime + MONITOR_TIME_DELAY_SEC <= stgTime) && ia->stgSettings->GetMonitoring())
- {
- touchTime = stgTime;
- std::string monFile = ia->stgSettings->GetMonitorDir() + "/inetaccess_r";
- TouchFile(monFile);
- }
- }
-
-ia->isRunningRun = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void * AUTH_IA::RunTimeouter(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-AUTH_IA * ia = static_cast<AUTH_IA *>(d);
-
-ia->isRunningRunTimeouter = true;
-
-int a = -1;
-std::string monFile = ia->stgSettings->GetMonitorDir() + "/inetaccess_t";
-while (ia->nonstop)
- {
- struct timespec ts = {0, 20000000};
- nanosleep(&ts, NULL);
- ia->Timeouter();
- // TODO change counter to timer and MONITOR_TIME_DELAY_SEC
- if (++a % (50 * 60) == 0 && ia->stgSettings->GetMonitoring())
- {
- TouchFile(monFile);
- }
- }
-
-ia->isRunningRunTimeouter = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::ParseSettings()
-{
-int ret = iaSettings.ParseSettings(settings);
-if (ret)
- errorStr = iaSettings.GetStrError();
-return ret;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Reload(const STG::ModuleSettings & ms)
-{
-AUTH_IA_SETTINGS newIaSettings;
-if (newIaSettings.ParseSettings(ms))
- {
- printfd(__FILE__, "AUTH_IA::Reload() - Failed to reload InetAccess.\n");
- logger("AUTH_IA: Cannot reload InetAccess. Errors found.");
- return -1;
- }
-
-printfd(__FILE__, "AUTH_IA::Reload() - Reloaded InetAccess successfully.\n");
-logger("AUTH_IA: Reloaded InetAccess successfully.");
-iaSettings = newIaSettings;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::PrepareNet()
-{
-struct sockaddr_in listenAddr;
-
-listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
-
-if (listenSocket < 0)
- {
- errorStr = "Cannot create socket.";
- logger("Cannot create a socket: %s", strerror(errno));
- return -1;
- }
-
-listenAddr.sin_family = AF_INET;
-listenAddr.sin_port = htons(static_cast<uint16_t>(iaSettings.GetUserPort()));
-listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
-
-if (bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0)
- {
- errorStr = "AUTH_IA: Bind failed.";
- logger("Cannot bind the socket: %s", strerror(errno));
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::FinalizeNet()
-{
-close(listenSocket);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::RecvData(char * buffer, int bufferSize)
-{
-if (!WaitPackets(listenSocket)) // Timeout
- {
- return 0;
- }
-
-struct sockaddr_in outerAddr;
-socklen_t outerAddrLen(sizeof(outerAddr));
-ssize_t dataLen = recvfrom(listenSocket, buffer, bufferSize, 0, (struct sockaddr *)&outerAddr, &outerAddrLen);
-
-if (!dataLen) // EOF
- {
- return 0;
- }
-
-if (dataLen <= 0) // Error
- {
- if (errno != EINTR)
- {
- printfd(__FILE__, "recvfrom res=%d, error: '%s'\n", dataLen, strerror(errno));
- logger("recvfrom error: %s", strerror(errno));
- return -1;
- }
- return 0;
- }
-
-if (dataLen > 256)
- return -1;
-
-uint32_t sip = outerAddr.sin_addr.s_addr;
-uint16_t sport = htons(outerAddr.sin_port);
-
-int protoVer;
-if (CheckHeader(buffer, sip, &protoVer))
- return -1;
-
-char login[PASSWD_LEN]; //TODO why PASSWD_LEN ?
-memset(login, 0, PASSWD_LEN);
-
-DecryptString(login, buffer + 8, PASSWD_LEN, &ctxS);
-
-UserPtr user;
-if (users->FindByName(login, &user))
- {
- logger("User's connect failed: user '%s' not found. IP %s",
- login,
- inet_ntostring(sip).c_str());
- printfd(__FILE__, "User '%s' NOT found!\n", login);
- SendError(sip, sport, protoVer, IconvString("Неправильный логин.", "utf8", "koi8-ru"));
- return -1;
- }
-
-printfd(__FILE__, "User '%s' FOUND!\n", user->GetLogin().c_str());
-
-if (user->GetProperties().disabled.Get())
- {
- logger("Cannont authorize '%s', user is disabled.", login);
- SendError(sip, sport, protoVer, IconvString("Учетная запись заблокирована.", "utf8", "koi8-ru"));
- return 0;
- }
-
-if (user->GetProperties().passive.Get())
- {
- logger("Cannont authorize '%s', user is passive.", login);
- SendError(sip, sport, protoVer, IconvString("Учетная запись заморожена.", "utf8", "koi8-ru"));
- return 0;
- }
-
-if (!user->GetProperties().ips.Get().find(sip))
- {
- printfd(__FILE__, "User %s. IP address is incorrect. IP %s\n",
- user->GetLogin().c_str(), inet_ntostring(sip).c_str());
- logger("User %s. IP address is incorrect. IP %s",
- user->GetLogin().c_str(), inet_ntostring(sip).c_str());
- SendError(sip, sport, protoVer, IconvString("Пользователь не опознан. Проверьте IP-адрес.", "utf8", "koi8-ru"));
- return 0;
- }
-
-return PacketProcessor(buffer, dataLen, sip, sport, protoVer, user);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::CheckHeader(const char * buffer, uint32_t sip, int * protoVer)
-{
-if (strncmp(IA_ID, buffer, strlen(IA_ID)) != 0)
- {
- printfd(__FILE__, "update needed - IA_ID\n");
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. Header: invalid packed signature.", inet_ntostring(sip).c_str());
- return -1;
- }
-
-if (buffer[6] != 0) //proto[0] shoud be 0
- {
- printfd(__FILE__, "update needed - PROTO major: %d\n", buffer[6]);
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. Header: invalid protocol major version: %d.", inet_ntostring(sip).c_str(), buffer[6]);
- return -1;
- }
-
-if (buffer[7] < 6)
- {
- // need update
- printfd(__FILE__, "update needed - PROTO minor: %d\n", buffer[7]);
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. Header: invalid protocol minor version: %d.", inet_ntostring(sip).c_str(), buffer[7]);
- return -1;
- }
-else
- {
- *protoVer = buffer[7];
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Timeouter()
-{
-STG_LOCKER lock(&mutex);
-
-std::map<uint32_t, IA_USER>::iterator it;
-it = ip2user.begin();
-
-while (it != ip2user.end())
- {
- uint32_t sip = it->first;
-
- static UTIME currTime;
- gettimeofday(&currTime, NULL);
-
- if ((it->second.phase.GetPhase() == 2)
- && (currTime - it->second.phase.GetTime()) > iaSettings.GetUserDelay())
- {
- if (iaSettings.LogProtocolErrors())
- logger("User '%s'. Protocol version: %d. Phase 2: connect request timeout (%f > %d).", it->second.login.c_str(), it->second.protoVer, (currTime - it->second.phase.GetTime()).AsDouble(), iaSettings.GetUserDelay().GetSec());
- it->second.phase.SetPhase1();
- printfd(__FILE__, "Phase changed from 2 to 1. Reason: timeout\n");
- ip2user.erase(it++);
- continue;
- }
-
- if (it->second.phase.GetPhase() == 3)
- {
- if (!it->second.messagesToSend.empty())
- {
- if (it->second.protoVer == 6)
- RealSendMessage6(*it->second.messagesToSend.begin(), sip, it->second);
-
- if (it->second.protoVer == 7)
- RealSendMessage7(*it->second.messagesToSend.begin(), sip, it->second);
-
- if (it->second.protoVer == 8)
- RealSendMessage8(*it->second.messagesToSend.begin(), sip, it->second);
-
- it->second.messagesToSend.erase(it->second.messagesToSend.begin());
- }
-
- if((currTime - it->second.lastSendAlive) > iaSettings.GetUserDelay())
- {
- switch (it->second.protoVer)
- {
- case 6:
- Send_ALIVE_SYN_6(&(it->second), sip);
- break;
- case 7:
- Send_ALIVE_SYN_7(&(it->second), sip);
- break;
- case 8:
- Send_ALIVE_SYN_8(&(it->second), sip);
- break;
- }
-
- gettimeofday(&it->second.lastSendAlive, NULL);
- }
-
- if ((currTime - it->second.phase.GetTime()) > iaSettings.GetUserTimeout())
- {
- if (iaSettings.LogProtocolErrors())
- logger("User '%s'. Protocol version: %d. Phase 3: alive timeout (%f > %d).", it->second.login.c_str(), it->second.protoVer, (currTime - it->second.phase.GetTime()).AsDouble(), iaSettings.GetUserTimeout().GetSec());
- users->Unauthorize(it->second.user->GetLogin(), this);
- ip2user.erase(it++);
- continue;
- }
- }
-
- if ((it->second.phase.GetPhase() == 4)
- && ((currTime - it->second.phase.GetTime()) > iaSettings.GetUserDelay()))
- {
- if (iaSettings.LogProtocolErrors())
- logger("User '%s'. Protocol version: %d. Phase 4: disconnect request timeout (%f > %d).", it->second.login.c_str(), it->second.protoVer, (currTime - it->second.phase.GetTime()).AsDouble(), iaSettings.GetUserDelay().GetSec());
- it->second.phase.SetPhase3();
- printfd(__FILE__, "Phase changed from 4 to 3. Reason: timeout\n");
- }
-
- ++it;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::PacketProcessor(void * buff, size_t dataLen, uint32_t sip, uint16_t sport, int protoVer, UserPtr user)
-{
-std::string login(user->GetLogin());
-const size_t offset = LOGIN_LEN + 2 + 6; // LOGIN_LEN + sizeOfMagic + sizeOfVer;
-
-STG_LOCKER lock(&mutex);
-std::map<uint32_t, IA_USER>::iterator it(ip2user.find(sip));
-
-if (it == ip2user.end())
- {
- UserPtr userPtr;
- if (!users->FindByIPIdx(sip, &userPtr))
- {
- if (userPtr->GetID() != user->GetID())
- {
- printfd(__FILE__, "IP address already in use by user '%s'. IP %s, login: '%s'\n",
- userPtr->GetLogin().c_str(),
- inet_ntostring(sip).c_str(),
- login.c_str());
- logger("IP address is already in use by user '%s'. IP %s, login: '%s'",
- userPtr->GetLogin().c_str(),
- inet_ntostring(sip).c_str(),
- login.c_str());
- SendError(sip, sport, protoVer, IconvString("IP-адрес уже сипользуется.", "utf8", "koi8-ru"));
- return 0;
- }
- }
-
- printfd(__FILE__, "Add new user '%s' from ip %s\n",
- login.c_str(), inet_ntostring(sip).c_str());
- std::pair<std::map<uint32_t, IA_USER>::iterator, bool> res;
- res = ip2user.insert(std::make_pair(sip, IA_USER(login, user, sport, protoVer)));
- it = res.first;
- #ifdef IA_PHASE_DEBUG
- it->second.phase.SetLogFileName(stgSettings->GetLogFileName());
- it->second.phase.SetUserLogin(login);
- #endif
- }
-else if (user->GetID() != it->second.user->GetID())
- {
- printfd(__FILE__, "IP address already in use by user '%s'. IP %s, login: '%s'\n",
- it->second.user->GetLogin().c_str(),
- inet_ntostring(sip).c_str(),
- user->GetLogin().c_str());
- logger("IP address is already in use by user '%s'. IP %s, login: '%s'",
- it->second.user->GetLogin().c_str(),
- inet_ntostring(sip).c_str(),
- user->GetLogin().c_str());
- SendError(sip, sport, protoVer, IconvString("IP-адрес уже используется.", "utf8", "koi8-ru"));
- return 0;
- }
-
-IA_USER * iaUser = &(it->second);
-
-if (iaUser->password != user->GetProperties().password.Get())
- {
- const std::string & password = user->GetProperties().password.Get();
- InitContext(password.c_str(), password.length(), &iaUser->ctx);
- iaUser->password = user->GetProperties().password.Get();
- }
-
-DecryptString(static_cast<char *>(buff) + offset, static_cast<char *>(buff) + offset, (dataLen - offset), &iaUser->ctx);
-
-char packetName[IA_MAX_TYPE_LEN];
-strncpy(packetName, static_cast<char *>(buff) + offset + 4, IA_MAX_TYPE_LEN);
-packetName[IA_MAX_TYPE_LEN - 1] = 0;
-
-std::map<std::string, int>::iterator pi(packetTypes.find(packetName));
-if (pi == packetTypes.end())
- {
- SendError(sip, sport, protoVer, IconvString("Неправильный логин или пароль.", "utf8", "koi8-ru"));
- printfd(__FILE__, "Login or password is wrong!\n");
- logger("User's connect failed. User: '%s', ip %s. Wrong login or password",
- login.c_str(),
- inet_ntostring(sip).c_str());
- ip2user.erase(it);
- return 0;
- }
-
-if (user->IsAuthorizedBy(this) && user->GetCurrIP() != sip)
- {
- printfd(__FILE__, "Login %s already in use from ip %s. IP %s\n",
- login.c_str(), inet_ntostring(user->GetCurrIP()).c_str(),
- inet_ntostring(sip).c_str());
- logger("Login '%s' is already in use from ip %s. IP %s",
- login.c_str(),
- inet_ntostring(user->GetCurrIP()).c_str(),
- inet_ntostring(sip).c_str());
- SendError(sip, sport, protoVer, IconvString("Логин уже используется.", "utf8", "koi8-ru"));
- ip2user.erase(it);
- return 0;
- }
-
-switch (pi->second)
- {
- case CONN_SYN_N:
- switch (protoVer)
- {
- case 6:
- if (Process_CONN_SYN_6(static_cast<CONN_SYN_6 *>(buff), &(it->second), sip))
- return -1;
- return Send_CONN_SYN_ACK_6(iaUser, sip);
- case 7:
- if (Process_CONN_SYN_7(static_cast<CONN_SYN_7 *>(buff), &(it->second), sip))
- return -1;
- return Send_CONN_SYN_ACK_7(iaUser, sip);
- case 8:
- if (Process_CONN_SYN_8(static_cast<CONN_SYN_8 *>(buff), &(it->second), sip))
- return -1;
- return Send_CONN_SYN_ACK_8(iaUser, sip);
- }
- break;
-
- case CONN_ACK_N:
- switch (protoVer)
- {
- case 6:
- if (Process_CONN_ACK_6(static_cast<CONN_ACK_6 *>(buff), iaUser, sip))
- return -1;
- return Send_ALIVE_SYN_6(iaUser, sip);
- case 7:
- if (Process_CONN_ACK_7(static_cast<CONN_ACK_6 *>(buff), iaUser, sip))
- return -1;
- return Send_ALIVE_SYN_7(iaUser, sip);
- case 8:
- if (Process_CONN_ACK_8(static_cast<CONN_ACK_8 *>(buff), iaUser, sip))
- return -1;
- return Send_ALIVE_SYN_8(iaUser, sip);
- }
- break;
-
- case ALIVE_ACK_N:
- switch (protoVer)
- {
- case 6:
- return Process_ALIVE_ACK_6(static_cast<ALIVE_ACK_6 *>(buff), iaUser, sip);
- case 7:
- return Process_ALIVE_ACK_7(static_cast<ALIVE_ACK_6 *>(buff), iaUser, sip);
- case 8:
- return Process_ALIVE_ACK_8(static_cast<ALIVE_ACK_8 *>(buff), iaUser, sip);
- }
- break;
-
- case DISCONN_SYN_N:
- switch (protoVer)
- {
- case 6:
- if (Process_DISCONN_SYN_6(static_cast<DISCONN_SYN_6 *>(buff), iaUser, sip))
- return -1;
- return Send_DISCONN_SYN_ACK_6(iaUser, sip);
- case 7:
- if (Process_DISCONN_SYN_7(static_cast<DISCONN_SYN_6 *>(buff), iaUser, sip))
- return -1;
- return Send_DISCONN_SYN_ACK_7(iaUser, sip);
- case 8:
- if (Process_DISCONN_SYN_8(static_cast<DISCONN_SYN_8 *>(buff), iaUser, sip))
- return -1;
- return Send_DISCONN_SYN_ACK_8(iaUser, sip);
- }
- break;
-
- case DISCONN_ACK_N:
- switch (protoVer)
- {
- case 6:
- if (Process_DISCONN_ACK_6(static_cast<DISCONN_ACK_6 *>(buff), iaUser, sip, it))
- return -1;
- return Send_FIN_6(iaUser, sip, it);
- case 7:
- if (Process_DISCONN_ACK_7(static_cast<DISCONN_ACK_6 *>(buff), iaUser, sip, it))
- return -1;
- return Send_FIN_7(iaUser, sip, it);
- case 8:
- if (Process_DISCONN_ACK_8(static_cast<DISCONN_ACK_8 *>(buff), iaUser, sip, it))
- return -1;
- return Send_FIN_8(iaUser, sip, it);
- }
- break;
- }
-
-return -1;
-}
-//-----------------------------------------------------------------------------
-void AUTH_IA::DelUser(UserPtr u)
-{
-
-uint32_t ip = u->GetCurrIP();
-
-if (!ip)
- return;
-
-std::map<uint32_t, IA_USER>::iterator it;
-
-STG_LOCKER lock(&mutex);
-it = ip2user.find(ip);
-if (it == ip2user.end())
- {
- //Nothing to delete
- printfd(__FILE__, "Nothing to delete\n");
- return;
- }
-
-if (it->second.user == u)
- {
- printfd(__FILE__, "User removed!\n");
- users->Unauthorize(u->GetLogin(), this);
- ip2user.erase(it);
- }
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::SendError(uint32_t ip, uint16_t port, int protoVer, const std::string & text)
-{
-struct sockaddr_in sendAddr;
-ssize_t res;
-switch (protoVer)
- {
- case 6:
- case 7:
- ERR err;
- memset(&err, 0, sizeof(ERR));
-
- sendAddr.sin_family = AF_INET;
- sendAddr.sin_port = htons(port);
- sendAddr.sin_addr.s_addr = ip;
-
- err.len = 1;
- strncpy((char*)err.type, "ERR", 16);
- strncpy((char*)err.text, text.c_str(), MAX_MSG_LEN);
-
- #ifdef ARCH_BE
- SwapBytes(err.len);
- #endif
-
- res = sendto(listenSocket, &err, sizeof(err), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
- printfd(__FILE__, "SendError %d bytes sent\n", res);
- break;
-
- case 8:
- ERR_8 err8;
- memset(&err8, 0, sizeof(ERR_8));
-
- sendAddr.sin_family = AF_INET;
- sendAddr.sin_port = htons(port);
- sendAddr.sin_addr.s_addr = ip;
-
- err8.len = 256;
- strncpy((char*)err8.type, "ERR", 16);
- strncpy((char*)err8.text, text.c_str(), MAX_MSG_LEN);
-
- #ifdef ARCH_BE
- SwapBytes(err8.len);
- #endif
-
- res = sendto(listenSocket, &err8, sizeof(err8), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
- printfd(__FILE__, "SendError_8 %d bytes sent\n", res);
- break;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send(uint32_t ip, uint16_t port, const char * buffer, size_t len)
-{
-struct sockaddr_in sendAddr;
-
-sendAddr.sin_family = AF_INET;
-sendAddr.sin_port = htons(port);
-sendAddr.sin_addr.s_addr = ip;
-
-if (sendto(listenSocket, buffer, len, 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr)) == static_cast<ssize_t>(len))
- return 0;
-
-return -1;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::SendMessage(const STG::Message & msg, uint32_t ip) const
-{
-printfd(__FILE__, "SendMessage userIP=%s\n", inet_ntostring(ip).c_str());
-
-std::map<uint32_t, IA_USER>::iterator it;
-
-STG_LOCKER lock(&mutex);
-it = ip2user.find(ip);
-if (it == ip2user.end())
- {
- errorStr = "Unknown user.";
- return -1;
- }
-it->second.messagesToSend.push_back(msg);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::RealSendMessage6(const STG::Message & msg, uint32_t ip, IA_USER & user)
-{
-printfd(__FILE__, "RealSendMessage 6 user=%s\n", user.login.c_str());
-
-INFO_6 info;
-memset(&info, 0, sizeof(INFO_6));
-
-info.len = 256;
-strncpy((char*)info.type, "INFO", 16);
-info.infoType = 'I';
-strncpy((char*)info.text, msg.text.c_str(), 235);
-info.text[234] = 0;
-
-size_t len = info.len;
-#ifdef ARCH_BE
-SwapBytes(info.len);
-#endif
-
-char buffer[256];
-memcpy(buffer, &info, sizeof(INFO_6));
-EncryptString(buffer, buffer, len, &user.ctx);
-return Send(ip, iaSettings.GetUserPort(), buffer, len);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::RealSendMessage7(const STG::Message & msg, uint32_t ip, IA_USER & user)
-{
-printfd(__FILE__, "RealSendMessage 7 user=%s\n", user.login.c_str());
-
-INFO_7 info;
-memset(&info, 0, sizeof(INFO_7));
-
-info.len = 264;
-strncpy((char*)info.type, "INFO_7", 16);
-info.infoType = static_cast<int8_t>(msg.header.type);
-info.showTime = static_cast<int8_t>(msg.header.showTime);
-info.sendTime = msg.header.creationTime;
-
-size_t len = info.len;
-#ifdef ARCH_BE
-SwapBytes(info.len);
-SwapBytes(info.sendTime);
-#endif
-
-strncpy((char*)info.text, msg.text.c_str(), MAX_MSG_LEN - 1);
-info.text[MAX_MSG_LEN - 1] = 0;
-
-char buffer[300];
-memcpy(buffer, &info, sizeof(INFO_7));
-
-EncryptString(buffer, buffer, len, &user.ctx);
-return Send(ip, iaSettings.GetUserPort(), buffer, len);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::RealSendMessage8(const STG::Message & msg, uint32_t ip, IA_USER & user)
-{
-printfd(__FILE__, "RealSendMessage 8 user=%s\n", user.login.c_str());
-
-INFO_8 info;
-memset(&info, 0, sizeof(INFO_8));
-
-info.len = 1056;
-strncpy((char*)info.type, "INFO_8", 16);
-info.infoType = static_cast<int8_t>(msg.header.type);
-info.showTime = static_cast<int8_t>(msg.header.showTime);
-info.sendTime = msg.header.creationTime;
-
-strncpy((char*)info.text, msg.text.c_str(), IA_MAX_MSG_LEN_8 - 1);
-info.text[IA_MAX_MSG_LEN_8 - 1] = 0;
-
-size_t len = info.len;
-#ifdef ARCH_BE
-SwapBytes(info.len);
-SwapBytes(info.sendTime);
-#endif
-
-char buffer[1500];
-memcpy(buffer, &info, sizeof(INFO_8));
-
-EncryptString(buffer, buffer, len, &user.ctx);
-return Send(ip, user.port, buffer, len);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_CONN_SYN_6(CONN_SYN_6 *, IA_USER * iaUser, uint32_t)
-{
-if (!(iaUser->phase.GetPhase() == 1 || iaUser->phase.GetPhase() == 3))
- return -1;
-
-enabledDirs = 0xFFffFFff;
-
-iaUser->phase.SetPhase2();
-printfd(__FILE__, "Phase changed from %d to 2. Reason: CONN_SYN_6\n", iaUser->phase.GetPhase());
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_CONN_SYN_7(CONN_SYN_7 * connSyn, IA_USER * iaUser, uint32_t sip)
-{
-return Process_CONN_SYN_6(connSyn, iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_CONN_SYN_8(CONN_SYN_8 * connSyn, IA_USER * iaUser, uint32_t sip)
-{
-#ifdef ARCH_BE
-SwapBytes(connSyn->dirs);
-#endif
-int ret = Process_CONN_SYN_6(reinterpret_cast<CONN_SYN_6 *>(connSyn), iaUser, sip);
-enabledDirs = connSyn->dirs;
-return ret;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_CONN_ACK_6(CONN_ACK_6 * connAck, IA_USER * iaUser, uint32_t sip)
-{
-#ifdef ARCH_BE
-SwapBytes(connAck->len);
-SwapBytes(connAck->rnd);
-#endif
-printfd( __FILE__, "CONN_ACK_6 %s\n", connAck->type);
-
-if ((iaUser->phase.GetPhase() == 2) && (connAck->rnd == iaUser->rnd + 1))
- {
- iaUser->phase.UpdateTime();
-
- iaUser->lastSendAlive = iaUser->phase.GetTime();
- if (users->Authorize(iaUser->login, sip, enabledDirs, this))
- {
- iaUser->phase.SetPhase3();
- printfd(__FILE__, "Phase changed from 2 to 3. Reason: CONN_ACK_6\n");
- return 0;
- }
- else
- {
- errorStr = iaUser->user->GetStrError();
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: phase 2, authorization error ('%s').", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, errorStr.c_str());
- iaUser->phase.SetPhase1();
- ip2user.erase(sip);
- printfd(__FILE__, "Phase changed from 2 to 1. Reason: failed to authorize user\n");
- return -1;
- }
- }
-printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d, expected: %d\n", iaUser->phase.GetPhase(), connAck->rnd, iaUser->rnd + 1);
-if (iaSettings.LogProtocolErrors())
- {
- if (iaUser->phase.GetPhase() != 2)
- logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid phase, expected 2, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
- if (connAck->rnd != iaUser->rnd + 1)
- logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), connAck->rnd);
- }
-return -1;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_CONN_ACK_7(CONN_ACK_7 * connAck, IA_USER * iaUser, uint32_t sip)
-{
-return Process_CONN_ACK_6(connAck, iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_CONN_ACK_8(CONN_ACK_8 * connAck, IA_USER * iaUser, uint32_t sip)
-{
-#ifdef ARCH_BE
-SwapBytes(connAck->len);
-SwapBytes(connAck->rnd);
-#endif
-printfd( __FILE__, "CONN_ACK_8 %s\n", connAck->type);
-
-if ((iaUser->phase.GetPhase() == 2) && (connAck->rnd == iaUser->rnd + 1))
- {
- iaUser->phase.UpdateTime();
- iaUser->lastSendAlive = iaUser->phase.GetTime();
- if (users->Authorize(iaUser->login, sip, enabledDirs, this))
- {
- iaUser->phase.SetPhase3();
- printfd(__FILE__, "Phase changed from 2 to 3. Reason: CONN_ACK_8\n");
- return 0;
- }
- else
- {
- errorStr = iaUser->user->GetStrError();
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: phase 2, authorization error ('%s').", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, errorStr.c_str());
- iaUser->phase.SetPhase1();
- ip2user.erase(sip);
- printfd(__FILE__, "Phase changed from 2 to 1. Reason: failed to authorize user\n");
- return -1;
- }
- }
-printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d, expected: %d\n", iaUser->phase.GetPhase(), connAck->rnd, iaUser->rnd + 1);
-if (iaSettings.LogProtocolErrors())
- {
- if (iaUser->phase.GetPhase() != 2)
- logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid phase, expected 2, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
- if (connAck->rnd != iaUser->rnd + 1)
- logger("IP: %s. User '%s'. Protocol version: %d. CONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), connAck->rnd);
- }
-return -1;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_ALIVE_ACK_6(ALIVE_ACK_6 * aliveAck, IA_USER * iaUser, uint32_t)
-{
-#ifdef ARCH_BE
-SwapBytes(aliveAck->len);
-SwapBytes(aliveAck->rnd);
-#endif
-printfd(__FILE__, "ALIVE_ACK_6\n");
-if ((iaUser->phase.GetPhase() == 3) && (aliveAck->rnd == iaUser->rnd + 1))
- {
- iaUser->phase.UpdateTime();
- #ifdef IA_DEBUG
- iaUser->aliveSent = false;
- #endif
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_ALIVE_ACK_7(ALIVE_ACK_7 * aliveAck, IA_USER * iaUser, uint32_t sip)
-{
-return Process_ALIVE_ACK_6(aliveAck, iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_ALIVE_ACK_8(ALIVE_ACK_8 * aliveAck, IA_USER * iaUser, uint32_t)
-{
-#ifdef ARCH_BE
-SwapBytes(aliveAck->len);
-SwapBytes(aliveAck->rnd);
-#endif
-printfd(__FILE__, "ALIVE_ACK_8\n");
-if ((iaUser->phase.GetPhase() == 3) && (aliveAck->rnd == iaUser->rnd + 1))
- {
- iaUser->phase.UpdateTime();
- #ifdef IA_DEBUG
- iaUser->aliveSent = false;
- #endif
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_DISCONN_SYN_6(DISCONN_SYN_6 *, IA_USER * iaUser, uint32_t sip)
-{
-printfd(__FILE__, "DISCONN_SYN_6\n");
-if (iaUser->phase.GetPhase() != 3)
- {
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_SYN: invalid phase, expected 3, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
- printfd(__FILE__, "Invalid phase. Expected 3, actual %d\n", iaUser->phase.GetPhase());
- errorStr = "Incorrect request DISCONN_SYN";
- return -1;
- }
-
-iaUser->phase.SetPhase4();
-printfd(__FILE__, "Phase changed from 3 to 4. Reason: DISCONN_SYN_6\n");
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_DISCONN_SYN_7(DISCONN_SYN_7 * disconnSyn, IA_USER * iaUser, uint32_t sip)
-{
-return Process_DISCONN_SYN_6(disconnSyn, iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_DISCONN_SYN_8(DISCONN_SYN_8 *, IA_USER * iaUser, uint32_t sip)
-{
-if (iaUser->phase.GetPhase() != 3)
- {
- if (iaSettings.LogProtocolErrors())
- logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_SYN: invalid phase, expected 3, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
- errorStr = "Incorrect request DISCONN_SYN";
- printfd(__FILE__, "Invalid phase. Expected 3, actual %d\n", iaUser->phase.GetPhase());
- return -1;
- }
-
-iaUser->phase.SetPhase4();
-printfd(__FILE__, "Phase changed from 3 to 4. Reason: DISCONN_SYN_6\n");
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_DISCONN_ACK_6(DISCONN_ACK_6 * disconnAck,
- IA_USER * iaUser,
- uint32_t sip,
- std::map<uint32_t, IA_USER>::iterator)
-{
-#ifdef ARCH_BE
-SwapBytes(disconnAck->len);
-SwapBytes(disconnAck->rnd);
-#endif
-printfd(__FILE__, "DISCONN_ACK_6\n");
-if (!((iaUser->phase.GetPhase() == 4) && (disconnAck->rnd == iaUser->rnd + 1)))
- {
- if (iaSettings.LogProtocolErrors())
- {
- if (iaUser->phase.GetPhase() != 4)
- logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid phase, expected 4, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
- if (disconnAck->rnd != iaUser->rnd + 1)
- logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), disconnAck->rnd);
- }
- printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), disconnAck->rnd);
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_DISCONN_ACK_7(DISCONN_ACK_7 * disconnAck, IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
-{
-return Process_DISCONN_ACK_6(disconnAck, iaUser, sip, it);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Process_DISCONN_ACK_8(DISCONN_ACK_8 * disconnAck, IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator)
-{
-#ifdef ARCH_BE
-SwapBytes(disconnAck->len);
-SwapBytes(disconnAck->rnd);
-#endif
-printfd(__FILE__, "DISCONN_ACK_8\n");
-if (!((iaUser->phase.GetPhase() == 4) && (disconnAck->rnd == iaUser->rnd + 1)))
- {
- if (iaSettings.LogProtocolErrors())
- {
- if (iaUser->phase.GetPhase() != 4)
- logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid phase, expected 4, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, iaUser->phase.GetPhase());
- if (disconnAck->rnd != iaUser->rnd + 1)
- logger("IP: %s. User '%s'. Protocol version: %d. DISCONN_ACK: invalid control number, expected %d, got %d.", inet_ntostring(sip).c_str(), iaUser->login.c_str(), iaUser->protoVer, (iaUser->rnd + 1), disconnAck->rnd);
- }
- printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), disconnAck->rnd);
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_CONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip)
-{
-//+++ Fill static data in connSynAck +++
-// TODO Move this code. It must be executed only once
-connSynAck6.len = Min8(sizeof(CONN_SYN_ACK_6));
-strcpy((char*)connSynAck6.type, "CONN_SYN_ACK");
-for (int j = 0; j < DIR_NUM; j++)
- {
- strncpy((char*)connSynAck6.dirName[j],
- stgSettings->GetDirName(j).c_str(),
- sizeof(string16));
-
- connSynAck6.dirName[j][sizeof(string16) - 1] = 0;
- }
-//--- Fill static data in connSynAck ---
-
-iaUser->rnd = static_cast<uint32_t>(random());
-connSynAck6.rnd = iaUser->rnd;
-
-printfd(__FILE__, "Sending CONN_SYN_ACK with control number %d.\n", iaUser->rnd);
-
-connSynAck6.userTimeOut = iaSettings.GetUserTimeout().GetSec();
-connSynAck6.aliveDelay = iaSettings.GetUserDelay().GetSec();
-
-#ifdef ARCH_BE
-SwapBytes(connSynAck6.len);
-SwapBytes(connSynAck6.rnd);
-SwapBytes(connSynAck6.userTimeOut);
-SwapBytes(connSynAck6.aliveDelay);
-#endif
-
-EncryptString((char*)&connSynAck6, (char*)&connSynAck6, Min8(sizeof(CONN_SYN_ACK_6)), &iaUser->ctx);
-return Send(sip, iaSettings.GetUserPort(), (char*)&connSynAck6, Min8(sizeof(CONN_SYN_ACK_6)));;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_CONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip)
-{
-return Send_CONN_SYN_ACK_6(iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_CONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip)
-{
-strcpy((char*)connSynAck8.hdr.magic, IA_ID);
-connSynAck8.hdr.protoVer[0] = 0;
-connSynAck8.hdr.protoVer[1] = 8;
-
-//+++ Fill static data in connSynAck +++
-// TODO Move this code. It must be executed only once
-connSynAck8.len = Min8(sizeof(CONN_SYN_ACK_8));
-strcpy((char*)connSynAck8.type, "CONN_SYN_ACK");
-for (int j = 0; j < DIR_NUM; j++)
- {
- strncpy((char*)connSynAck8.dirName[j],
- stgSettings->GetDirName(j).c_str(),
- sizeof(string16));
-
- connSynAck8.dirName[j][sizeof(string16) - 1] = 0;
- }
-//--- Fill static data in connSynAck ---
-
-iaUser->rnd = static_cast<uint32_t>(random());
-connSynAck8.rnd = iaUser->rnd;
-
-printfd(__FILE__, "Sending CONN_SYN_ACK with control number %d.\n", iaUser->rnd);
-
-connSynAck8.userTimeOut = iaSettings.GetUserTimeout().GetSec();
-connSynAck8.aliveDelay = iaSettings.GetUserDelay().GetSec();
-
-#ifdef ARCH_BE
-SwapBytes(connSynAck8.len);
-SwapBytes(connSynAck8.rnd);
-SwapBytes(connSynAck8.userTimeOut);
-SwapBytes(connSynAck8.aliveDelay);
-#endif
-
-EncryptString((char*)&connSynAck8, (char*)&connSynAck8, Min8(sizeof(CONN_SYN_ACK_8)), &iaUser->ctx);
-return Send(sip, iaUser->port, (char*)&connSynAck8, Min8(sizeof(CONN_SYN_ACK_8)));
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_ALIVE_SYN_6(IA_USER * iaUser, uint32_t sip)
-{
-aliveSyn6.len = Min8(sizeof(ALIVE_SYN_6));
-aliveSyn6.rnd = iaUser->rnd = static_cast<uint32_t>(random());
-
-strcpy((char*)aliveSyn6.type, "ALIVE_SYN");
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- aliveSyn6.md[i] = iaUser->user->GetProperties().down.Get()[i];
- aliveSyn6.mu[i] = iaUser->user->GetProperties().up.Get()[i];
-
- aliveSyn6.sd[i] = iaUser->user->GetSessionDownload()[i];
- aliveSyn6.su[i] = iaUser->user->GetSessionUpload()[i];
- }
-
-//TODO
-int dn = iaSettings.GetFreeMbShowType();
-const auto tf = iaUser->user->GetTariff();
-
-if (dn < DIR_NUM)
- {
- double p = tf->GetPriceWithTraffType(aliveSyn6.mu[dn],
- aliveSyn6.md[dn],
- dn,
- stgTime);
- p *= 1024 * 1024;
- if (std::fabs(p) < 1.0e-3)
- {
- snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "---");
- }
- else
- {
- double fmb = iaUser->user->GetProperties().freeMb;
- fmb = fmb < 0 ? 0 : fmb;
- snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "%.3f", fmb / p);
- }
- }
-else
- {
- if (freeMbNone == iaSettings.GetFreeMbShowType())
- {
- aliveSyn6.freeMb[0] = 0;
- }
- else
- {
- double fmb = iaUser->user->GetProperties().freeMb;
- fmb = fmb < 0 ? 0 : fmb;
- snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "C%.3f", fmb);
- }
- }
-
-#ifdef IA_DEBUG
-if (iaUser->aliveSent)
- {
- printfd(__FILE__, "========= ALIVE_ACK_6(7) TIMEOUT !!! %s =========\n", iaUser->login.c_str());
- }
-iaUser->aliveSent = true;
-#endif
-
-aliveSyn6.cash =(int64_t) (iaUser->user->GetProperties().cash.Get() * 1000.0);
-if (!stgSettings->GetShowFeeInCash())
- aliveSyn6.cash -= (int64_t)(tf->GetFee() * 1000.0);
-
-#ifdef ARCH_BE
-SwapBytes(aliveSyn6.len);
-SwapBytes(aliveSyn6.rnd);
-SwapBytes(aliveSyn6.cash);
-for (int i = 0; i < DIR_NUM; ++i)
- {
- SwapBytes(aliveSyn6.mu[i]);
- SwapBytes(aliveSyn6.md[i]);
- SwapBytes(aliveSyn6.su[i]);
- SwapBytes(aliveSyn6.sd[i]);
- }
-#endif
-
-EncryptString((char*)&aliveSyn6, (char*)&aliveSyn6, Min8(sizeof(aliveSyn6)), &iaUser->ctx);
-return Send(sip, iaSettings.GetUserPort(), (char*)&aliveSyn6, Min8(sizeof(aliveSyn6)));
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_ALIVE_SYN_7(IA_USER * iaUser, uint32_t sip)
-{
-return Send_ALIVE_SYN_6(iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_ALIVE_SYN_8(IA_USER * iaUser, uint32_t sip)
-{
-strcpy((char*)aliveSyn8.hdr.magic, IA_ID);
-aliveSyn8.hdr.protoVer[0] = 0;
-aliveSyn8.hdr.protoVer[1] = 8;
-
-aliveSyn8.len = Min8(sizeof(ALIVE_SYN_8));
-aliveSyn8.rnd = iaUser->rnd = static_cast<uint32_t>(random());
-
-strcpy((char*)aliveSyn8.type, "ALIVE_SYN");
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- aliveSyn8.md[i] = iaUser->user->GetProperties().down.Get()[i];
- aliveSyn8.mu[i] = iaUser->user->GetProperties().up.Get()[i];
-
- aliveSyn8.sd[i] = iaUser->user->GetSessionDownload()[i];
- aliveSyn8.su[i] = iaUser->user->GetSessionUpload()[i];
- }
-
-//TODO
-int dn = iaSettings.GetFreeMbShowType();
-
-if (dn < DIR_NUM)
- {
- const auto tf = iaUser->user->GetTariff();
- double p = tf->GetPriceWithTraffType(aliveSyn8.mu[dn],
- aliveSyn8.md[dn],
- dn,
- stgTime);
- p *= 1024 * 1024;
- if (std::fabs(p) < 1.0e-3)
- {
- snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "---");
- }
- else
- {
- double fmb = iaUser->user->GetProperties().freeMb;
- fmb = fmb < 0 ? 0 : fmb;
- snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "%.3f", fmb / p);
- }
- }
-else
- {
- if (freeMbNone == iaSettings.GetFreeMbShowType())
- {
- aliveSyn8.freeMb[0] = 0;
- }
- else
- {
- double fmb = iaUser->user->GetProperties().freeMb;
- fmb = fmb < 0 ? 0 : fmb;
- snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "C%.3f", fmb);
- }
- }
-
-#ifdef IA_DEBUG
-if (iaUser->aliveSent)
- {
- printfd(__FILE__, "========= ALIVE_ACK_8 TIMEOUT !!! =========\n");
- }
-iaUser->aliveSent = true;
-#endif
-
-const auto tf = iaUser->user->GetTariff();
-
-aliveSyn8.cash =(int64_t) (iaUser->user->GetProperties().cash.Get() * 1000.0);
-if (!stgSettings->GetShowFeeInCash())
- aliveSyn8.cash -= (int64_t)(tf->GetFee() * 1000.0);
-
-#ifdef ARCH_BE
-SwapBytes(aliveSyn8.len);
-SwapBytes(aliveSyn8.rnd);
-SwapBytes(aliveSyn8.cash);
-SwapBytes(aliveSyn8.status);
-for (int i = 0; i < DIR_NUM; ++i)
- {
- SwapBytes(aliveSyn8.mu[i]);
- SwapBytes(aliveSyn8.md[i]);
- SwapBytes(aliveSyn8.su[i]);
- SwapBytes(aliveSyn8.sd[i]);
- }
-#endif
-
-EncryptString((char*)&aliveSyn8, (char*)&aliveSyn8, Min8(sizeof(aliveSyn8)), &iaUser->ctx);
-return Send(sip, iaUser->port, (char*)&aliveSyn8, Min8(sizeof(aliveSyn8)));
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_DISCONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip)
-{
-disconnSynAck6.len = Min8(sizeof(DISCONN_SYN_ACK_6));
-strcpy((char*)disconnSynAck6.type, "DISCONN_SYN_ACK");
-disconnSynAck6.rnd = iaUser->rnd = static_cast<uint32_t>(random());
-
-#ifdef ARCH_BE
-SwapBytes(disconnSynAck6.len);
-SwapBytes(disconnSynAck6.rnd);
-#endif
-
-EncryptString((char*)&disconnSynAck6, (char*)&disconnSynAck6, Min8(sizeof(disconnSynAck6)), &iaUser->ctx);
-return Send(sip, iaSettings.GetUserPort(), (char*)&disconnSynAck6, Min8(sizeof(disconnSynAck6)));
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_DISCONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip)
-{
-return Send_DISCONN_SYN_ACK_6(iaUser, sip);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_DISCONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip)
-{
-strcpy((char*)disconnSynAck8.hdr.magic, IA_ID);
-disconnSynAck8.hdr.protoVer[0] = 0;
-disconnSynAck8.hdr.protoVer[1] = 8;
-
-disconnSynAck8.len = Min8(sizeof(DISCONN_SYN_ACK_8));
-strcpy((char*)disconnSynAck8.type, "DISCONN_SYN_ACK");
-disconnSynAck8.rnd = iaUser->rnd = static_cast<uint32_t>(random());
-
-#ifdef ARCH_BE
-SwapBytes(disconnSynAck8.len);
-SwapBytes(disconnSynAck8.rnd);
-#endif
-
-EncryptString((char*)&disconnSynAck8, (char*)&disconnSynAck8, Min8(sizeof(disconnSynAck8)), &iaUser->ctx);
-return Send(sip, iaUser->port, (char*)&disconnSynAck8, Min8(sizeof(disconnSynAck8)));
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_FIN_6(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
-{
-fin6.len = Min8(sizeof(FIN_6));
-strcpy((char*)fin6.type, "FIN");
-strcpy((char*)fin6.ok, "OK");
-
-#ifdef ARCH_BE
-SwapBytes(fin6.len);
-#endif
-
-EncryptString((char*)&fin6, (char*)&fin6, Min8(sizeof(fin6)), &iaUser->ctx);
-
-users->Unauthorize(iaUser->login, this);
-
-int res = Send(sip, iaSettings.GetUserPort(), (char*)&fin6, Min8(sizeof(fin6)));
-
-ip2user.erase(it);
-
-return res;
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_FIN_7(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
-{
-return Send_FIN_6(iaUser, sip, it);
-}
-//-----------------------------------------------------------------------------
-int AUTH_IA::Send_FIN_8(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it)
-{
-strcpy((char*)fin8.hdr.magic, IA_ID);
-fin8.hdr.protoVer[0] = 0;
-fin8.hdr.protoVer[1] = 8;
-
-fin8.len = Min8(sizeof(FIN_8));
-strcpy((char*)fin8.type, "FIN");
-strcpy((char*)fin8.ok, "OK");
-
-#ifdef ARCH_BE
-SwapBytes(fin8.len);
-#endif
-
-EncryptString((char*)&fin8, (char*)&fin8, Min8(sizeof(fin8)), &iaUser->ctx);
-
-users->Unauthorize(iaUser->login, this);
-
-int res = Send(sip, iaUser->port, (char*)&fin8, Min8(sizeof(fin8)));
-
-ip2user.erase(it);
-
-return res;
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-#pragma once
-
-#include "stg/auth.h"
-#include "stg/store.h"
-#include "stg/module_settings.h"
-#include "stg/notifer.h"
-#include "stg/user_ips.h"
-#include "stg/user.h"
-#include "stg/users.h"
-#include "stg/user_property.h"
-#include "stg/ia_packets.h"
-#include "stg/blowfish.h"
-#include "stg/logger.h"
-#include "stg/utime.h"
-#include "stg/logger.h"
-
-#include <cstring>
-#include <ctime>
-#include <cstdint>
-#include <string>
-#include <map>
-#include <list>
-#include <functional>
-#include <utility>
-
-#include <sys/time.h>
-#include <pthread.h>
-
-//#define IA_DEBUG (1)
-//#define IA_PHASE_DEBUG (1)
-
-class AUTH_IA;
-//-----------------------------------------------------------------------------
-enum FREEMB {
- freeMb0 = 0,
- freeMb1,
- freeMb2,
- freeMb3,
- freeMb4,
- freeMb5,
- freeMb6,
- freeMb7,
- freeMb8,
- freeMb9,
- freeMb10,
- freeMb11,
- freeMb12,
- freeMb13,
- freeMb14,
- freeMb15,
- freeMb16,
- freeMb17,
- freeMb18,
- freeMb19,
- freeMbCash = 100,
- freeMbNone = 101
-};
-//-----------------------------------------------------------------------------
-class IA_PHASE {
-public:
- IA_PHASE();
- ~IA_PHASE();
-
- void SetPhase1();
- void SetPhase2();
- void SetPhase3();
- void SetPhase4();
- int GetPhase() const;
-
- void UpdateTime();
- const UTIME & GetTime() const;
-
- #ifdef IA_PHASE_DEBUG
- void SetUserLogin(const std::string & login);
- void SetLogFileName(const std::string & logFileName);
- #endif
-
-private:
- int phase;
- UTIME phaseTime;
-
- #ifdef IA_PHASE_DEBUG
- void WritePhaseChange(int newPhase);
- std::string log;
- std::string login;
- FILE * flog;
- #endif
-};
-//-----------------------------------------------------------------------------
-struct IA_USER {
- using ConstUserPtr = const STG::User*;
- IA_USER()
- : user(NULL),
- lastSendAlive(0),
- rnd(static_cast<uint32_t>(random())),
- port(0),
- protoVer(0),
- password("NO PASSWORD")
- {
- unsigned char keyL[PASSWD_LEN];
- memset(keyL, 0, PASSWD_LEN);
- strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
- Blowfish_Init(&ctx, keyL, PASSWD_LEN);
-
- #ifdef IA_DEBUG
- aliveSent = false;
- #endif
- }
-
- IA_USER(const IA_USER & u)
- : login(u.login),
- user(u.user),
- phase(u.phase),
- lastSendAlive(u.lastSendAlive),
- rnd(u.rnd),
- port(u.port),
- ctx(),
- messagesToSend(u.messagesToSend),
- protoVer(u.protoVer),
- password(u.password)
- {
- #ifdef IA_DEBUG
- aliveSent = u.aliveSent;
- #endif
- memcpy(&ctx, &u.ctx, sizeof(BLOWFISH_CTX));
- }
-
- IA_USER(const std::string & l,
- ConstUserPtr u,
- uint16_t p,
- int ver)
- : login(l),
- user(u),
- lastSendAlive(0),
- rnd(static_cast<uint32_t>(random())),
- port(p),
- messagesToSend(),
- protoVer(ver),
- password(user->GetProperties().password.Get())
- {
- unsigned char keyL[PASSWD_LEN];
- memset(keyL, 0, PASSWD_LEN);
- strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
- Blowfish_Init(&ctx, keyL, PASSWD_LEN);
-
- #ifdef IA_DEBUG
- aliveSent = false;
- #endif
- }
-
- std::string login;
- ConstUserPtr user;
- IA_PHASE phase;
- UTIME lastSendAlive;
- uint32_t rnd;
- uint16_t port;
- BLOWFISH_CTX ctx;
- std::vector<STG::Message> messagesToSend;
- int protoVer;
- std::string password;
- #ifdef IA_DEBUG
- bool aliveSent;
- #endif
-
-private:
- IA_USER & operator=(const IA_USER & rvalue);
-};
-//-----------------------------------------------------------------------------
-class AUTH_IA_SETTINGS {
-public:
- AUTH_IA_SETTINGS();
- virtual ~AUTH_IA_SETTINGS() {}
- const std::string & GetStrError() const { return errorStr; }
- int ParseSettings(const STG::ModuleSettings & s);
- UTIME GetUserDelay() const { return UTIME(userDelay); }
- UTIME GetUserTimeout() const { return UTIME(userTimeout); }
- uint16_t GetUserPort() const { return port; }
- FREEMB GetFreeMbShowType() const { return freeMbShowType; }
- bool LogProtocolErrors() const { return logProtocolErrors; }
-
-private:
- int userDelay;
- int userTimeout;
- uint16_t port;
- std::string errorStr;
- FREEMB freeMbShowType;
- bool logProtocolErrors;
-};
-//-----------------------------------------------------------------------------
-class AUTH_IA;
-using UserPtr = STG::User*;
-//-----------------------------------------------------------------------------
-class DEL_USER_NOTIFIER: public STG::NotifierBase<UserPtr> {
-public:
- explicit DEL_USER_NOTIFIER(AUTH_IA & a) : auth(a) {}
- virtual ~DEL_USER_NOTIFIER() {}
-
- void Notify(const UserPtr & user);
-private:
- DEL_USER_NOTIFIER(const DEL_USER_NOTIFIER & rvalue);
- DEL_USER_NOTIFIER & operator=(const DEL_USER_NOTIFIER & rvalue);
-
- AUTH_IA & auth;
-};
-//-----------------------------------------------------------------------------
-class AUTH_IA : public STG::Auth {
-friend class DEL_USER_NOTIFIER;
-public:
- AUTH_IA();
- ~AUTH_IA() override;
-
- void SetUsers(STG::Users * u) override { users = u; }
- void SetStgSettings(const STG::Settings * s) override { stgSettings = s; }
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & ms) override;
- bool IsRunning() override { return isRunningRunTimeouter || isRunningRun; }
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override { return "InetAccess authorization plugin v.1.4"; }
- uint16_t GetStartPosition() const override { return 30; }
- uint16_t GetStopPosition() const override { return 30; }
-
- int SendMessage(const STG::Message & msg, uint32_t ip) const override;
-
-private:
- AUTH_IA(const AUTH_IA & rvalue);
- AUTH_IA & operator=(const AUTH_IA & rvalue);
-
- static void * Run(void *);
- static void * RunTimeouter(void * d);
- int PrepareNet();
- int FinalizeNet();
- void DelUser(UserPtr u);
- int RecvData(char * buffer, int bufferSize);
- int CheckHeader(const char * buffer, uint32_t sip, int * protoVer);
- int PacketProcessor(void * buff, size_t dataLen, uint32_t sip, uint16_t sport, int protoVer, UserPtr user);
-
- int Process_CONN_SYN_6(CONN_SYN_6 * connSyn, IA_USER * iaUser, uint32_t sip);
- int Process_CONN_SYN_7(CONN_SYN_7 * connSyn, IA_USER * iaUser, uint32_t sip);
- int Process_CONN_SYN_8(CONN_SYN_8 * connSyn, IA_USER * iaUser, uint32_t sip);
-
- int Process_CONN_ACK_6(CONN_ACK_6 * connAck, IA_USER * iaUser, uint32_t sip);
- int Process_CONN_ACK_7(CONN_ACK_7 * connAck, IA_USER * iaUser, uint32_t sip);
- int Process_CONN_ACK_8(CONN_ACK_8 * connAck, IA_USER * iaUser, uint32_t sip);
-
- int Process_ALIVE_ACK_6(ALIVE_ACK_6 * aliveAck, IA_USER * iaUser, uint32_t sip);
- int Process_ALIVE_ACK_7(ALIVE_ACK_7 * aliveAck, IA_USER * iaUser, uint32_t sip);
- int Process_ALIVE_ACK_8(ALIVE_ACK_8 * aliveAck, IA_USER * iaUser, uint32_t sip);
-
- int Process_DISCONN_SYN_6(DISCONN_SYN_6 * disconnSyn, IA_USER * iaUser, uint32_t sip);
- int Process_DISCONN_SYN_7(DISCONN_SYN_7 * disconnSyn, IA_USER * iaUser, uint32_t sip);
- int Process_DISCONN_SYN_8(DISCONN_SYN_8 * disconnSyn, IA_USER * iaUser, uint32_t sip);
-
- int Process_DISCONN_ACK_6(DISCONN_ACK_6 * disconnSyn,
- IA_USER * iaUser,
- uint32_t sip,
- std::map<uint32_t, IA_USER>::iterator it);
- int Process_DISCONN_ACK_7(DISCONN_ACK_7 * disconnSyn,
- IA_USER * iaUser,
- uint32_t sip,
- std::map<uint32_t, IA_USER>::iterator it);
- int Process_DISCONN_ACK_8(DISCONN_ACK_8 * disconnSyn,
- IA_USER * iaUser,
- uint32_t sip,
- std::map<uint32_t, IA_USER>::iterator it);
-
- int Send_CONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip);
- int Send_CONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip);
- int Send_CONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip);
-
- int Send_ALIVE_SYN_6(IA_USER * iaUser, uint32_t sip);
- int Send_ALIVE_SYN_7(IA_USER * iaUser, uint32_t sip);
- int Send_ALIVE_SYN_8(IA_USER * iaUser, uint32_t sip);
-
- int Send_DISCONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip);
- int Send_DISCONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip);
- int Send_DISCONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip);
-
- int Send_FIN_6(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it);
- int Send_FIN_7(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it);
- int Send_FIN_8(IA_USER * iaUser, uint32_t sip, std::map<uint32_t, IA_USER>::iterator it);
-
- int Timeouter();
-
- int SendError(uint32_t ip, uint16_t port, int protoVer, const std::string & text);
- int Send(uint32_t ip, uint16_t port, const char * buffer, size_t len);
- int RealSendMessage6(const STG::Message & msg, uint32_t ip, IA_USER & user);
- int RealSendMessage7(const STG::Message & msg, uint32_t ip, IA_USER & user);
- int RealSendMessage8(const STG::Message & msg, uint32_t ip, IA_USER & user);
-
- BLOWFISH_CTX ctxS; //for loginS
-
- mutable std::string errorStr;
- AUTH_IA_SETTINGS iaSettings;
- STG::ModuleSettings settings;
-
- bool nonstop;
-
- bool isRunningRun;
- bool isRunningRunTimeouter;
-
- STG::Users * users;
- const STG::Settings * stgSettings;
-
- mutable std::map<uint32_t, IA_USER> ip2user;
-
- pthread_t recvThread;
- pthread_t timeouterThread;
- mutable pthread_mutex_t mutex;
-
- int listenSocket;
-
- CONN_SYN_ACK_6 connSynAck6;
- CONN_SYN_ACK_8 connSynAck8;
-
- DISCONN_SYN_ACK_6 disconnSynAck6;
- DISCONN_SYN_ACK_8 disconnSynAck8;
-
- ALIVE_SYN_6 aliveSyn6;
- ALIVE_SYN_8 aliveSyn8;
- FIN_6 fin6;
- FIN_8 fin8;
-
- std::map<std::string, int> packetTypes;
-
- uint32_t enabledDirs;
-
- DEL_USER_NOTIFIER onDelUserNotifier;
-
- STG::PluginLogger logger;
-
- friend class UnauthorizeUser;
-};
-//-----------------------------------------------------------------------------
-class UnauthorizeUser : std::unary_function<const std::pair<uint32_t, IA_USER> &, void> {
- public:
- explicit UnauthorizeUser(AUTH_IA * a) : auth(a) {}
- UnauthorizeUser(const UnauthorizeUser & rvalue) : auth(rvalue.auth) {}
- void operator()(const std::pair<uint32_t, IA_USER> & p)
- {
- auth->users->Unauthorize(p.second.user->GetLogin(), auth);
- }
- private:
- UnauthorizeUser & operator=(const UnauthorizeUser & rvalue);
-
- AUTH_IA * auth;
-};
-//-----------------------------------------------------------------------------
-inline
-void DEL_USER_NOTIFIER::Notify(const UserPtr & user)
-{
- auth.DelUser(user);
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
-Date: 16.05.2008
-*/
-
-/*
-* Author : Maxim Mamontov <faust@stg.dp.ua>
-*/
-
-/*
-$Revision: 1.11 $
-$Date: 2010/09/10 06:41:06 $
-$Author: faust $
-*/
-
-#include "cap_nf.h"
-
-#include "stg/common.h"
-#include "stg/raw_ip_packet.h"
-#include "stg/traffcounter.h"
-
-#include <vector>
-
-#include <csignal>
-#include <cerrno>
-#include <cstring>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-namespace
-{
-
-struct NF_HEADER {
- uint16_t version; // Protocol version
- uint16_t count; // Flows count
- uint32_t uptime; // System uptime
- uint32_t timestamp; // UNIX timestamp
- uint32_t nsecs; // Residual nanoseconds
- uint32_t flowSeq; // Sequence counter
- uint8_t eType; // Engine type
- uint8_t eID; // Engine ID
- uint16_t sInterval; // Sampling mode and interval
-};
-
-struct NF_DATA {
- uint32_t srcAddr; // Flow source address
- uint32_t dstAddr; // Flow destination address
- uint32_t nextHop; // IP addres on next hop router
- uint16_t inSNMP; // SNMP index of input iface
- uint16_t outSNMP; // SNMP index of output iface
- uint32_t packets; // Packets in flow
- uint32_t octets; // Total number of bytes in flow
- uint32_t timeStart; // Uptime on first packet in flow
- uint32_t timeFinish;// Uptime on last packet in flow
- uint16_t srcPort; // Flow source port
- uint16_t dstPort; // Flow destination port
- uint8_t pad1; // 1-byte padding
- uint8_t TCPFlags; // Cumulative OR of TCP flags
- uint8_t proto; // IP protocol type (tcp, udp, etc.)
- uint8_t tos; // IP Type of Service (ToS)
- uint16_t srcAS; // Source BGP autonomous system number
- uint16_t dstAS; // Destination BGP autonomus system number
- uint8_t srcMask; // Source address mask in "slash" notation
- uint8_t dstMask; // Destination address mask in "slash" notation
- uint16_t pad2; // 2-byte padding
-};
-
-#define BUF_SIZE (sizeof(NF_HEADER) + 30 * sizeof(NF_DATA))
-
-}
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static NF_CAP plugin;
- return &plugin;
-}
-
-NF_CAP::NF_CAP()
- : traffCnt(NULL),
- runningTCP(false),
- runningUDP(false),
- stoppedTCP(true),
- stoppedUDP(true),
- portT(0),
- portU(0),
- sockTCP(-1),
- sockUDP(-1),
- logger(STG::PluginLogger::get("cap_nf"))
-{
-}
-
-int NF_CAP::ParseSettings()
-{
-std::vector<STG::ParamValue>::iterator it;
-for (it = settings.moduleParams.begin(); it != settings.moduleParams.end(); ++it)
- {
- if (it->param == "TCPPort" && !it->value.empty())
- {
- if (str2x(it->value[0], portT))
- {
- errorStr = "Invalid TCPPort value";
- printfd(__FILE__, "Error: Invalid TCPPort value\n");
- return -1;
- }
- continue;
- }
- if (it->param == "UDPPort" && !it->value.empty())
- {
- if (str2x(it->value[0], portU))
- {
- errorStr = "Invalid UDPPort value";
- printfd(__FILE__, "Error: Invalid UDPPort value\n");
- return -1;
- }
- continue;
- }
- printfd(__FILE__, "'%s' is not a valid module param\n", it->param.c_str());
- }
-return 0;
-}
-
-int NF_CAP::Start()
-{
-if (portU > 0)
- {
- if (OpenUDP())
- {
- return -1;
- }
- runningUDP = true;
- if (pthread_create(&tidUDP, NULL, RunUDP, this))
- {
- runningUDP = false;
- CloseUDP();
- errorStr = "Cannot create UDP thread";
- logger("Cannot create UDP thread.");
- printfd(__FILE__, "Error: Cannot create UDP thread\n");
- return -1;
- }
- }
-if (portT > 0)
- {
- if (OpenTCP())
- {
- return -1;
- }
- runningTCP = true;
- if (pthread_create(&tidTCP, NULL, RunTCP, this))
- {
- runningTCP = false;
- CloseTCP();
- logger("Cannot create TCP thread.");
- errorStr = "Cannot create TCP thread";
- printfd(__FILE__, "Error: Cannot create TCP thread\n");
- return -1;
- }
- }
-return 0;
-}
-
-int NF_CAP::Stop()
-{
-runningTCP = runningUDP = false;
-if (portU && !stoppedUDP)
- {
- CloseUDP();
- for (int i = 0; i < 25 && !stoppedUDP; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- if (stoppedUDP)
- {
- pthread_join(tidUDP, NULL);
- }
- else
- {
- if (pthread_kill(tidUDP, SIGUSR1))
- {
- errorStr = "Error sending signal to UDP thread";
- logger("Error sending sugnal to UDP thread.");
- printfd(__FILE__, "Error: Error sending signal to UDP thread\n");
- return -1;
- }
- printfd(__FILE__, "UDP thread NOT stopped\n");
- logger("Cannot stop UDP thread.");
- }
- }
-if (portT && !stoppedTCP)
- {
- CloseTCP();
- for (int i = 0; i < 25 && !stoppedTCP; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- if (stoppedTCP)
- {
- pthread_join(tidTCP, NULL);
- }
- else
- {
- if (pthread_kill(tidTCP, SIGUSR1))
- {
- errorStr = "Error sending signal to TCP thread";
- logger("Error sending signal to TCP thread.");
- printfd(__FILE__, "Error: Error sending signal to TCP thread\n");
- return -1;
- }
- printfd(__FILE__, "TCP thread NOT stopped\n");
- logger("Cannot stop TCP thread.");
- }
- }
-return 0;
-}
-
-bool NF_CAP::OpenUDP()
-{
-struct sockaddr_in sin;
-sockUDP = socket(PF_INET, SOCK_DGRAM, 0);
-if (sockUDP <= 0)
- {
- errorStr = "Error opening UDP socket";
- logger("Cannot create UDP socket: %s", strerror(errno));
- printfd(__FILE__, "Error: Error opening UDP socket\n");
- return true;
- }
-sin.sin_family = AF_INET;
-sin.sin_port = htons(portU);
-sin.sin_addr.s_addr = inet_addr("0.0.0.0");
-if (bind(sockUDP, (struct sockaddr *)&sin, sizeof(sin)))
- {
- errorStr = "Error binding UDP socket";
- logger("Cannot bind UDP socket: %s", strerror(errno));
- printfd(__FILE__, "Error: Error binding UDP socket\n");
- return true;
- }
-return false;
-}
-
-bool NF_CAP::OpenTCP()
-{
-struct sockaddr_in sin;
-sockTCP = socket(PF_INET, SOCK_STREAM, 0);
-if (sockTCP <= 0)
- {
- errorStr = "Error opening TCP socket";
- logger("Cannot create TCP socket: %s", strerror(errno));
- printfd(__FILE__, "Error: Error opening TCP socket\n");
- return true;
- }
-sin.sin_family = AF_INET;
-sin.sin_port = htons(portT);
-sin.sin_addr.s_addr = inet_addr("0.0.0.0");
-if (bind(sockTCP, (struct sockaddr *)&sin, sizeof(sin)))
- {
- errorStr = "Error binding TCP socket";
- logger("Cannot bind TCP socket: %s", strerror(errno));
- printfd(__FILE__, "Error: Error binding TCP socket\n");
- return true;
- }
-if (listen(sockTCP, 1))
- {
- errorStr = "Error listening on TCP socket";
- logger("Cannot listen on TCP socket: %s", strerror(errno));
- printfd(__FILE__, "Error: Error listening TCP socket\n");
- return true;
- }
-return false;
-}
-
-void * NF_CAP::RunUDP(void * c)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-NF_CAP * cap = static_cast<NF_CAP *>(c);
-cap->stoppedUDP = false;
-while (cap->runningUDP)
- {
- if (!WaitPackets(cap->sockUDP))
- {
- continue;
- }
-
- // Data
- struct sockaddr_in sin;
- socklen_t slen = sizeof(sin);
- uint8_t buf[BUF_SIZE];
- ssize_t res = recvfrom(cap->sockUDP, buf, BUF_SIZE, 0, reinterpret_cast<struct sockaddr *>(&sin), &slen);
- if (!cap->runningUDP)
- break;
-
- if (res < 0)
- {
- cap->logger("recvfrom error: %s", strerror(errno));
- continue;
- }
-
- if (res == 0) // EOF
- {
- continue;
- }
-
- if (res < 24)
- {
- if (errno != EINTR)
- {
- cap->errorStr = "Invalid data received";
- printfd(__FILE__, "Error: Invalid data received through UDP\n");
- }
- continue;
- }
-
- cap->ParseBuffer(buf, res);
- }
-cap->stoppedUDP = true;
-return NULL;
-}
-
-void * NF_CAP::RunTCP(void * c)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-NF_CAP * cap = static_cast<NF_CAP *>(c);
-cap->stoppedTCP = false;
-while (cap->runningTCP)
- {
- if (!WaitPackets(cap->sockTCP))
- {
- continue;
- }
-
- // Data
- struct sockaddr_in sin;
- socklen_t slen = sizeof(sin);
- int sd = accept(cap->sockTCP, reinterpret_cast<struct sockaddr *>(&sin), &slen);
- if (!cap->runningTCP)
- break;
-
- if (sd <= 0)
- {
- if (sd < 0)
- cap->logger("accept error: %s", strerror(errno));
- continue;
- }
-
- if (!WaitPackets(sd))
- {
- close(sd);
- continue;
- }
-
- uint8_t buf[BUF_SIZE];
- ssize_t res = recv(sd, buf, BUF_SIZE, MSG_WAITALL);
-
- if (res < 0)
- cap->logger("recv error: %s", strerror(errno));
-
- close(sd);
-
- if (!cap->runningTCP)
- break;
-
- if (res == 0) // EOF
- {
- continue;
- }
-
- // Wrong logic!
- // Need to check actual data length and wait all data to receive
- if (res < 24)
- {
- continue;
- }
-
- cap->ParseBuffer(buf, res);
- }
-cap->stoppedTCP = true;
-return NULL;
-}
-
-void NF_CAP::ParseBuffer(uint8_t * buf, ssize_t size)
-{
-STG::RawPacket ip;
-NF_HEADER * hdr = reinterpret_cast<NF_HEADER *>(buf);
-if (htons(hdr->version) != 5)
- {
- return;
- }
-
-int packets = htons(hdr->count);
-
-if (packets < 0 || packets > 30)
- {
- return;
- }
-
-if (24 + 48 * packets != size)
- {
- // See 'wrong logic' upper
- return;
- }
-
-for (int i = 0; i < packets; ++i)
- {
- NF_DATA * data = reinterpret_cast<NF_DATA *>(buf + 24 + i * 48);
-
- ip.rawPacket.header.ipHeader.ip_v = 4;
- ip.rawPacket.header.ipHeader.ip_hl = 5;
- ip.rawPacket.header.ipHeader.ip_p = data->proto;
- ip.dataLen = ntohl(data->octets);
- ip.rawPacket.header.ipHeader.ip_src.s_addr = data->srcAddr;
- ip.rawPacket.header.ipHeader.ip_dst.s_addr = data->dstAddr;
- ip.rawPacket.header.sPort = data->srcPort;
- ip.rawPacket.header.dPort = data->dstPort;
-
- traffCnt->process(ip);
- }
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
-Date: 16.05.2008
-*/
-
-/*
-* Author : Maxim Mamontov <faust@stg.dp.ua>
-*/
-
-/*
-$Revision: 1.5 $
-$Date: 2009/12/13 12:56:07 $
-$Author: faust $
-*/
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <cstdint>
-
-#include <pthread.h>
-#include <unistd.h> // close
-
-#define VERSION "cap_nf v. 0.4"
-#define START_POS 40
-#define STOP_POS 40
-
-namespace STG
-{
-
-struct Users;
-struct Tariffs;
-struct Admins;
-struct TraffCounter;
-struct Store;
-struct Settings;
-
-}
-
-class NF_CAP : public STG::Plugin {
-public:
- NF_CAP();
-
- void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
-
- bool IsRunning() override { return runningTCP || runningUDP; }
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override { return VERSION; }
- uint16_t GetStartPosition() const override { return START_POS; }
- uint16_t GetStopPosition() const override { return STOP_POS; }
-
-private:
- NF_CAP(const NF_CAP & rvalue);
- NF_CAP & operator=(const NF_CAP & rvalue);
-
- STG::TraffCounter * traffCnt;
- STG::ModuleSettings settings;
- pthread_t tidTCP;
- pthread_t tidUDP;
- bool runningTCP;
- bool runningUDP;
- bool stoppedTCP;
- bool stoppedUDP;
- uint16_t portT;
- uint16_t portU;
- int sockTCP;
- int sockUDP;
- mutable std::string errorStr;
- STG::PluginLogger logger;
-
- static void * RunUDP(void *);
- static void * RunTCP(void *);
- void ParseBuffer(uint8_t * buf, ssize_t size);
-
- bool OpenTCP();
- bool OpenUDP();
- void CloseTCP() { close(sockTCP); }
- void CloseUDP() { close(sockUDP); }
-};
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stg.dp.ua>
-*/
-
-/*
-$Revision: 1.13 $
-$Date: 2010/09/10 06:43:03 $
-*/
-
-#include "divert_cap.h"
-
-#include "stg/traffcounter.h"
-#include "stg/raw_ip_packet.h"
-#include "stg/common.h"
-
-#include <algorithm>
-#include <vector>
-
-#include <cstdio>
-#include <cstring>
-#include <cerrno>
-#include <cstdlib>
-#include <csignal>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <sys/uio.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <sys/poll.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#define BUFF_LEN (16384) /* max mtu -> lo=16436 TODO why?*/
-
-//-----------------------------------------------------------------------------
-struct DIVERT_DATA {
-int sock;
-short int port;
-char iface[10];
-};
-//-----------------------------------------------------------------------------
-pollfd pollddiv;
-DIVERT_DATA cddiv; //capture data
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static DIVERT_CAP plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-std::string DIVERT_CAP::GetVersion() const
-{
-return "cap_divert v.1.0";
-}
-//-----------------------------------------------------------------------------
-DIVERT_CAP::DIVERT_CAP()
- : port(0),
- disableForwarding(false),
- nonstop(false),
- isRunning(false),
- traffCnt(NULL),
- logger(STG::PluginLogger::get("cap_divert"))
-{
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::Start()
-{
-if (isRunning)
- return 0;
-
-if (DivertCapOpen() < 0)
- {
- errorStr = "Cannot open socket!";
- printfd(__FILE__, "Cannot open socket\n");
- return -1;
- }
-
-nonstop = true;
-
-if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::Stop()
-{
-if (!isRunning)
- return 0;
-
-DivertCapClose();
-
-nonstop = false;
-
-//5 seconds to thread stops itself
-int i;
-for (i = 0; i < 25; i++)
- {
- if (!isRunning)
- break;
-
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
-//after 5 seconds waiting thread still running. now killing it
-if (isRunning)
- {
- if (pthread_kill(thread, SIGINT))
- {
- errorStr = "Cannot kill thread.";
- logger("Cannot send signal to thread.");
- printfd(__FILE__, "Cannot kill thread\n");
- return -1;
- }
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * DIVERT_CAP::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-DIVERT_CAP * dc = static_cast<DIVERT_CAP *>(d);
-dc->isRunning = true;
-
-char buffer[STG::packetSize + 14];
-while (dc->nonstop)
- {
- STG::RawPacket rp;
- dc->DivertCapRead(buffer, sizeof(buffer), NULL);
-
- if (buffer[12] != 0x8)
- continue;
-
- memcpy(&rp.rawPacket, &buffer[14], STG::packetSize);
-
- dc->traffCnt->process(rp);
- }
-
-dc->isRunning = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::DivertCapOpen()
-{
-memset(&pollddiv, 0, sizeof(pollddiv));
-memset(&cddiv, 0, sizeof(DIVERT_DATA));
-
-strcpy(cddiv.iface, "foo");
-cddiv.port = port;
-
-DivertCapOpen(0);
-pollddiv.events = POLLIN;
-pollddiv.fd = cddiv.sock;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::DivertCapOpen(int)
-{
-int ret;
-cddiv.sock = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
-if (cddiv.sock < 0)
- {
- errorStr = "Create divert socket error.";
- logger("Cannot create a socket: %s", strerror(errno));
- printfd(__FILE__, "Cannot create divert socket\n");
- return -1;
- }
-
-struct sockaddr_in divAddr;
-
-memset(&divAddr, 0, sizeof(divAddr));
-
-divAddr.sin_family = AF_INET;
-divAddr.sin_port = htons(cddiv.port);
-divAddr.sin_addr.s_addr = INADDR_ANY;
-
-ret = bind(cddiv.sock, (struct sockaddr *)&divAddr, sizeof(divAddr));
-
-if (ret < 0)
- {
- errorStr = "Bind divert socket error.";
- logger("Cannot bind the scoket: %s", strerror(errno));
- printfd(__FILE__, "Cannot bind divert socket\n");
- return -1;
- }
-
-return cddiv.sock;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface)
-{
-poll(&pollddiv, 1, -1);
-
-if (pollddiv.revents & POLLIN)
- {
- DivertCapRead(b, blen, iface, 0);
- pollddiv.revents = 0;
- return 0;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface, int)
-{
-static char buf[BUFF_LEN];
-static struct sockaddr_in divertaddr;
-static int bytes;
-static socklen_t divertaddrSize = sizeof(divertaddr);
-
-if ((bytes = recvfrom (cddiv.sock, buf, BUFF_LEN,
- 0, (struct sockaddr*) &divertaddr, &divertaddrSize)) > 50)
- {
- memcpy(b + 14, buf, blen - 14);
- b[12] = 0x8;
-
- if (iface)
- *iface = cddiv.iface;
-
- if (!disableForwarding)
- {
- if (sendto(cddiv.sock, buf, bytes, 0, (struct sockaddr*)&divertaddr, divertaddrSize) < 0)
- logger("sendto error: %s", strerror(errno));
- }
- }
-else
- {
- if (bytes < 0)
- logger("recvfrom error: %s", strerror(errno));
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::DivertCapClose()
-{
-close(cddiv.sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int DIVERT_CAP::ParseSettings()
-{
-int p;
-STG::ParamValue pv;
-std::vector<STG::ParamValue>::const_iterator pvi;
-
-pv.param = "Port";
-pvi = std::find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
-if (pvi == settings.moduleParams.end() || pvi->value.empty())
- {
- p = 15701;
- }
-else if (ParseIntInRange(pvi->value[0], 1, 65535, &p))
- {
- errorStr = "Cannot parse parameter \'Port\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'Port'\n");
- return -1;
- }
-
-port = p;
-
-bool d = false;
-pv.param = "DisableForwarding";
-pvi = std::find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
-if (pvi == settings.moduleParams.end() || pvi->value.empty())
- {
- disableForwarding = false;
- }
-else if (ParseYesNo(pvi->value[0], &d))
- {
- errorStr = "Cannot parse parameter \'DisableForwarding\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'DisableForwarding'\n");
- return -1;
- }
-
-disableForwarding = d;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stg.dp.ua>
-*/
-
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <string>
-
-#include <pthread.h>
-
-namespace STG
-{
-struct Users;
-struct Tariffs;
-struct Admins;
-struct TraffCounter;
-struct Settings;
-}
-
-//-----------------------------------------------------------------------------
-class DIVERT_CAP : public STG::Plugin {
-public:
- DIVERT_CAP();
-
- void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return isRunning; }
-
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override;
- uint16_t GetStartPosition() const override { return 40; }
- uint16_t GetStopPosition() const override { return 40; }
-
-private:
- DIVERT_CAP(const DIVERT_CAP & rvalue);
- DIVERT_CAP & operator=(const DIVERT_CAP & rvalue);
-
- static void * Run(void *);
-
- int DivertCapOpen();
- int DivertCapOpen(int n);
- int DivertCapRead(char * buffer, int blen, char ** iface);
- int DivertCapRead(char * buffer, int blen, char ** iface, int n);
- int DivertCapClose();
-
- STG::ModuleSettings settings;
-
- int port;
- bool disableForwarding;
-
- mutable std::string errorStr;
-
- pthread_t thread;
-
- bool nonstop;
- bool isRunning;
-
- STG::TraffCounter * traffCnt;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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
- */
-
-/*
-Date: 18.09.2002
-*/
-
-/*
-* Author : Boris Mikhailenko <stg34@stg.dp.ua>
-*/
-
-/*
-$Revision: 1.19 $
-$Date: 2009/03/24 11:20:15 $
-$Author: faust $
-*/
-
-#include "ether_cap.h"
-
-#include "stg/common.h"
-#include "stg/raw_ip_packet.h"
-#include "stg/traffcounter.h"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-#include <csignal>
-
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-
-#include <net/bpf.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-//#define CAP_DEBUG 1
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static BPF_CAP plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-int BPF_CAP_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-iface.erase(iface.begin(), iface.end());
-
-if (s.moduleParams.empty())
- {
- errorStr = "Parameter \'iface\' not found.";
- printfd(__FILE__, "Parameter 'iface' not found\n");
- return -1;
- }
-
-for (unsigned i = 0; i < s.moduleParams.size(); i++)
- {
- if (s.moduleParams[i].param != "iface")
- {
- errorStr = "Parameter \'" + s.moduleParams[i].param + "\' unrecognized.";
- printfd(__FILE__, "Invalid parameter: '%s'\n", s.moduleParams[i].param.c_str());
- return -1;
- }
- for (unsigned j = 0; j < s.moduleParams[i].value.size(); j++)
- {
- iface.push_back(s.moduleParams[i].value[j]);
- }
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-std::string BPF_CAP_SETTINGS::GetIface(unsigned int num)
-{
-if (num >= iface.size())
- {
- return "";
- }
-return iface[num];
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-std::string BPF_CAP::GetVersion() const
-{
-return "cap_bpf v.1.0";
-}
-//-----------------------------------------------------------------------------
-BPF_CAP::BPF_CAP()
- : nonstop(false),
- isRunning(false),
- capSock(-1),
- traffCnt(NULL),
- logger(STG::PluginLogger::get("cap_bpf"))
-{
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::ParseSettings()
-{
-int ret = capSettings.ParseSettings(settings);
-if (ret)
- {
- errorStr = capSettings.GetStrError();
- return ret;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::Start()
-{
-if (isRunning)
- return 0;
-
-if (BPFCapOpen() < 0)
- {
- //errorStr = "Cannot open bpf device!";
- return -1;
- }
-
-nonstop = true;
-
-if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::Stop()
-{
-if (!isRunning)
- return 0;
-
-BPFCapClose();
-
-nonstop = false;
-
-//5 seconds to thread stops itself
-int i;
-for (i = 0; i < 25; i++)
- {
- if (!isRunning)
- break;
-
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
-//after 5 seconds waiting thread still running. now killing it
-if (isRunning)
- {
- //TODO pthread_cancel()
- if (pthread_kill(thread, SIGINT))
- {
- errorStr = "Cannot kill thread.";
- logger("Cannot send signal to thread.");
- printfd(__FILE__, "Cannot kill thread\n");
- return -1;
- }
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * BPF_CAP::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-BPF_CAP * dc = static_cast<BPF_CAP *>(d);
-dc->isRunning = true;
-
-uint8_t hdr[96]; //68 + 14 + 4(size) + 9(SYS_IFACE) + 1(align to 4) = 96
-
-STG::RawPacket * rpp = (STG::RawPacket *)&hdr[14];
-memset(hdr, 0, sizeof(hdr));
-
-rpp->dataLen = -1;
-char * iface;
-
-while (dc->nonstop)
- {
- if (dc->BPFCapRead((char*)&hdr, 68 + 14, &iface))
- continue;
-
- if (!(hdr[12] == 0x8 && hdr[13] == 0x0))
- continue;
-
- dc->traffCnt->process(*rpp);
- }
-
-dc->isRunning = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::BPFCapOpen()
-{
-int i = 0;
-BPF_DATA bd;
-pollfd pd;
-
-while ((bd.iface = capSettings.GetIface(i)) != "")
- {
- bpfData.push_back(bd);
- if (BPFCapOpen(&bpfData[i]) < 0)
- {
- return -1;
- }
-
- pd.events = POLLIN;
- pd.fd = bpfData[i].fd;
- polld.push_back(pd);
- i++;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::BPFCapOpen(BPF_DATA * bd)
-{
-char devbpf[20];
-int i = 0;
-int l = BUFF_LEN;
-int im = 1;
-struct ifreq ifr;
-
-do
- {
- sprintf(devbpf, "/dev/bpf%d", i);
- i++;
- bd->fd = open(devbpf, O_RDONLY);
- } while(bd->fd < 0 && errno == EBUSY);
-
-if (bd->fd < 0)
- {
- errorStr = "Can't capture packets. Open bpf device for " + bd->iface + " error.";
- logger("Cannot open device for interface '%s': %s", bd->iface.c_str(), strerror(errno));
- printfd(__FILE__, "Cannot open BPF device\n");
- return -1;
- }
-
-strncpy(ifr.ifr_name, bd->iface.c_str(), sizeof(ifr.ifr_name));
-
-if (ioctl(bd->fd, BIOCSBLEN, (caddr_t)&l) < 0)
- {
- errorStr = bd->iface + " BIOCSBLEN " + std::string(strerror(errno));
- logger("ioctl (BIOCSBLEN) error for interface '%s': %s", bd->iface.c_str(), strerror(errno));
- printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
- return -1;
- }
-
-if (ioctl(bd->fd, BIOCSETIF, (caddr_t)&ifr) < 0)
- {
- errorStr = bd->iface + " BIOCSETIF " + std::string(strerror(errno));
- logger("ioctl (BIOCSETIF) error for interface '%s': %s", bd->iface.c_str(), strerror(errno));
- printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
- return -1;
- }
-
-if (ioctl(bd->fd, BIOCIMMEDIATE, &im) < 0)
- {
- errorStr = bd->iface + " BIOCIMMEDIATE " + std::string(strerror(errno));
- logger("ioctl (BIOCIMMEDIATE) error for interface '%s': %s", bd->iface.c_str(), strerror(errno));
- printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
- return -1;
- }
-
-return bd->fd;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::BPFCapClose()
-{
-for (unsigned int i = 0; i < bpfData.size(); i++)
- close(bpfData[i].fd);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::BPFCapRead(char * buffer, int blen, char ** capIface)
-{
-poll(&polld[0], polld.size(), -1);
-
-for (unsigned int i = 0; i < polld.size(); i++)
- {
- if (polld[i].revents & POLLIN)
- {
- if (BPFCapRead(buffer, blen, capIface, &bpfData[i]))
- {
- polld[i].revents = 0;
- continue;
- }
- polld[i].revents = 0;
- return 0;
- }
- }
-return -1;
-}
-//-----------------------------------------------------------------------------
-int BPF_CAP::BPFCapRead(char * buffer, int blen, char **, BPF_DATA * bd)
-{
-if (bd->canRead)
- {
- bd->r = read(bd->fd, bd->buffer, BUFF_LEN);
- if (bd->r < 0)
- {
- logger("read error: %s", strerror(errno));
- struct timespec ts = {0, 20000000};
- nanosleep(&ts, NULL);
- return -1;
- }
-
- bd->p = bd->buffer;
- bd->bh = (struct bpf_hdr*)bd->p;
- bd->canRead = 0;
- }
-
-if(bd->r > bd->sum)
- {
- memcpy(buffer, (char*)(bd->p) + bd->bh->bh_hdrlen, blen);
-
- bd->sum += BPF_WORDALIGN(bd->bh->bh_hdrlen + bd->bh->bh_caplen);
- bd->p = bd->p + BPF_WORDALIGN(bd->bh->bh_hdrlen + bd->bh->bh_caplen);
- bd->bh = (struct bpf_hdr*)bd->p;
- }
-
-if(bd->r <= bd->sum)
- {
- bd->canRead = 1;
- bd->sum = 0;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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
- */
-
- /*
- $Revision: 1.11 $
- $Date: 2009/06/23 11:32:27 $
- $Author: faust $
- */
-
-/*
-* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
-*/
-
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <vector>
-#include <cstdint>
-
-#include <pthread.h>
-#include <sys/poll.h>
-
-#define BUFF_LEN (128)
-
-namespace STG
-{
-struct TraffCounter;
-}
-
-//-----------------------------------------------------------------------------
-struct BPF_DATA {
- BPF_DATA()
- {
- fd = 0;
- p = NULL;
- r = 0;
- sum = 0;
- memset(buffer, 0, BUFF_LEN);
- bh = NULL;
- canRead = 1;
- iface = "";
- };
-
- BPF_DATA(const BPF_DATA & bd)
- {
- fd = bd.fd;
- p = bd.p;
- r = bd.r;
- sum = bd.sum;
- memcpy(buffer, bd.buffer, BUFF_LEN);
- bh = bd.bh;
- canRead = bd.canRead;
- iface = bd.iface;
- };
-
-int fd;
-uint8_t * p;
-int r;
-int sum;
-uint8_t buffer[BUFF_LEN];
-struct bpf_hdr * bh;
-int canRead;
-std::string iface;
-};
-//-----------------------------------------------------------------------------
-class BPF_CAP_SETTINGS {
-public:
- const std::string & GetStrError() const { return errorStr; }
- int ParseSettings(const STG::ModuleSettings & s);
- std::string GetIface(unsigned int num);
-
-private:
- std::vector<std::string> iface;
- mutable std::string errorStr;
-};
-//-----------------------------------------------------------------------------
-class BPF_CAP : public STG::Plugin {
-public:
- BPF_CAP();
-
- void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return isRunning; }
-
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override;
- uint16_t GetStartPosition() const override { return 40; }
- uint16_t GetStopPosition() const override { return 40; }
-
-private:
- BPF_CAP(const BPF_CAP & rvalue);
- BPF_CAP & operator=(const BPF_CAP & rvalue);
-
- static void * Run(void *);
- int BPFCapOpen();
- int BPFCapOpen(BPF_DATA * bd);
- int BPFCapClose();
- int BPFCapRead(char * buffer, int blen, char ** iface);
- int BPFCapRead(char * buffer, int blen, char ** iface, BPF_DATA * bd);
-
- BPF_CAP_SETTINGS capSettings;
-
- mutable std::string errorStr;
-
- std::vector<BPF_DATA> bpfData;
- std::vector<pollfd> polld;
-
- pthread_t thread;
- bool nonstop;
- bool isRunning;
- int capSock;
- STG::ModuleSettings settings;
-
- STG::TraffCounter * traffCnt;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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
- */
-
-/*
-Date: 18.09.2002
-*/
-
-/*
-* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
-*/
-
-/*
-$Revision: 1.23 $
-$Date: 2009/12/13 13:45:13 $
-*/
-
-#include "ether_cap.h"
-
-#include "stg/common.h"
-#include "stg/raw_ip_packet.h"
-#include "stg/traffcounter.h"
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cerrno>
-#include <csignal>
-
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-
-//#define CAP_DEBUG 1
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static ETHER_CAP plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-std::string ETHER_CAP::GetVersion() const
-{
-return "cap_ether v.1.2";
-}
-//-----------------------------------------------------------------------------
-ETHER_CAP::ETHER_CAP()
- : nonstop(false),
- isRunning(false),
- capSock(-1),
- traffCnt(NULL),
- logger(STG::PluginLogger::get("cap_ether"))
-{
-}
-//-----------------------------------------------------------------------------
-int ETHER_CAP::Start()
-{
-if (isRunning)
- return 0;
-
-if (EthCapOpen() < 0)
- {
- errorStr = "Cannot open socket!";
- printfd(__FILE__, "Cannot open socket\n");
- return -1;
- }
-
-nonstop = true;
-
-if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int ETHER_CAP::Stop()
-{
-if (!isRunning)
- return 0;
-
-nonstop = false;
-
-//5 seconds to thread stops itself
-for (int i = 0; i < 25 && isRunning; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-//after 5 seconds waiting thread still running. now killing it
-if (isRunning)
- {
- if (pthread_kill(thread, SIGUSR1))
- {
- errorStr = "Cannot kill thread.";
- logger("Cannot send signal to thread.");
- return -1;
- }
- for (int i = 0; i < 25 && isRunning; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- if (isRunning)
- {
- errorStr = "ETHER_CAP not stopped.";
- logger("Cannot stop thread.");
- printfd(__FILE__, "Cannot stop thread\n");
- return -1;
- }
- else
- {
- pthread_join(thread, NULL);
- }
- }
-
-EthCapClose();
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * ETHER_CAP::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-ETHER_CAP * dc = static_cast<ETHER_CAP *>(d);
-dc->isRunning = true;
-
-struct ETH_IP
-{
-uint16_t ethHdr[8];
-STG::RawPacket rp;
-char padding[4];
-char padding1[8];
-};
-
-char ethip[sizeof(ETH_IP)];
-
-memset(ðip, 0, sizeof(ETH_IP));
-
-ETH_IP * ethIP = static_cast<ETH_IP *>(static_cast<void *>(ðip));
-ethIP->rp.dataLen = -1;
-
-char * iface = NULL;
-
-while (dc->nonstop)
- {
- if (dc->EthCapRead(ðip, 68 + 14, &iface))
- {
- continue;
- }
-
- if (ethIP->ethHdr[7] != 0x8)
- continue;
-
- dc->traffCnt->process(ethIP->rp);
- }
-
-dc->isRunning = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int ETHER_CAP::EthCapOpen()
-{
-capSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-if (capSock < 0)
- logger("Cannot create socket: %s", strerror(errno));
-return capSock;
-}
-//-----------------------------------------------------------------------------
-int ETHER_CAP::EthCapClose()
-{
-close(capSock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int ETHER_CAP::EthCapRead(void * buffer, int blen, char **)
-{
-struct sockaddr_ll addr;
-int addrLen;
-
-if (!WaitPackets(capSock))
- {
- return ENODATA;
- }
-
-addrLen = sizeof(addr);
-
-if (recvfrom(capSock, ((char*)buffer) + 2, blen, 0, (struct sockaddr *)&addr, (socklen_t*)&addrLen) < 0)
- {
- logger("recvfrom error: %s", strerror(errno));
- return ENODATA;
- }
-
-return 0;
-}
+++ /dev/null
-/*
- * 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
- */
-
- /*
- $Revision: 1.12 $
- $Date: 2009/12/13 13:45:13 $
- */
-
-/*
-* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
-*/
-
-#pragma once
-
-#include <pthread.h>
-
-#include <string>
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-namespace STG
-{
-
-struct Users;
-struct Tariffs;
-struct Admins;
-struct TraffCounter;
-struct Settings;
-
-}
-
-//-----------------------------------------------------------------------------
-class ETHER_CAP : public STG::Plugin {
-public:
- ETHER_CAP();
-
- void SetTraffcounter(STG::TraffCounter * tc) { traffCnt = tc; }
-
- int Start();
- int Stop();
- int Reload(const STG::ModuleSettings & /*ms*/) { return 0; }
- bool IsRunning() { return isRunning; }
-
- int ParseSettings() { return 0; }
- const std::string & GetStrError() const { return errorStr; }
- std::string GetVersion() const;
- uint16_t GetStartPosition() const { return 40; }
- uint16_t GetStopPosition() const { return 40; }
-
-private:
- ETHER_CAP(const ETHER_CAP & rvalue);
- ETHER_CAP & operator=(const ETHER_CAP & rvalue);
-
- static void * Run(void *);
- int EthCapOpen();
- int EthCapClose();
- int EthCapRead(void * buffer, int blen, char ** iface);
-
- mutable std::string errorStr;
-
- pthread_t thread;
- bool nonstop;
- bool isRunning;
- int capSock;
-
- STG::TraffCounter * traffCnt;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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 "nfqueue.h"
-
-#include "stg/traffcounter.h"
-#include "stg/common.h"
-#include "stg/raw_ip_packet.h"
-
-extern "C" {
-
-#include <linux/netfilter.h> /* Defines verdicts (NF_ACCEPT, etc) */
-#include <libnetfilter_queue/libnetfilter_queue.h>
-
-}
-
-#include <cerrno>
-#include <csignal>
-
-#include <arpa/inet.h> // ntohl
-
-#include <unistd.h> // read
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-namespace
-{
-
-int Callback(struct nfq_q_handle * queueHandle, struct nfgenmsg * /*msg*/,
- struct nfq_data * nfqData, void *data)
-{
-int id = 0;
-
-struct nfqnl_msg_packet_hdr * packetHeader = nfq_get_msg_packet_hdr(nfqData);
-if (packetHeader == NULL)
- return 0;
-
-id = ntohl(packetHeader->packet_id);
-
-unsigned char * payload = NULL;
-
-if (nfq_get_payload(nfqData, &payload) < 0 || payload == NULL)
- return id;
-
-STG::RawPacket packet;
-
-memcpy(&packet.rawPacket, payload, sizeof(packet.rawPacket));
-
-NFQ_CAP * cap = static_cast<NFQ_CAP *>(data);
-
-cap->Process(packet);
-
-return nfq_set_verdict(queueHandle, id, NF_ACCEPT, 0, NULL);
-}
-
-}
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static NFQ_CAP plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-std::string NFQ_CAP::GetVersion() const
-{
-return "cap_nfqueue v.1.0";
-}
-//-----------------------------------------------------------------------------
-NFQ_CAP::NFQ_CAP()
- : nonstop(false),
- isRunning(false),
- queueNumber(0),
- nfqHandle(NULL),
- queueHandle(NULL),
- traffCnt(NULL),
- logger(STG::PluginLogger::get("cap_nfqueue"))
-{
-}
-//-----------------------------------------------------------------------------
-int NFQ_CAP::ParseSettings()
-{
-for (size_t i = 0; i < settings.moduleParams.size(); i++)
- if (settings.moduleParams[i].param == "queueNumber" && !settings.moduleParams[i].value.empty())
- if (str2x(settings.moduleParams[i].value[0], queueNumber) < 0)
- {
- errorStr = "Queue number should be a number. Got: '" + settings.moduleParams[i].param + "'";
- logger(errorStr);
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int NFQ_CAP::Start()
-{
-if (isRunning)
- return 0;
-
-nfqHandle = nfq_open();
-if (nfqHandle == NULL)
- {
- errorStr = "Failed to initialize netfilter queue.";
- logger(errorStr);
- return -1;
- }
-
-if (nfq_unbind_pf(nfqHandle, AF_INET) < 0)
- {
- errorStr = "Failed to unbind netfilter queue from IP handling.";
- logger(errorStr);
- return -1;
- }
-
-if (nfq_bind_pf(nfqHandle, AF_INET) < 0)
- {
- errorStr = "Failed to bind netfilter queue to IP handling.";
- logger(errorStr);
- return -1;
- }
-
-queueHandle = nfq_create_queue(nfqHandle, queueNumber, &Callback, this);
-if (queueHandle == NULL)
- {
- errorStr = "Failed to create queue " + std::to_string(queueNumber) + ".";
- logger(errorStr);
- return -1;
- }
-
-if (nfq_set_mode(queueHandle, NFQNL_COPY_PACKET, 0xffFF) < 0)
- {
- errorStr = "Failed to set queue " + std::to_string(queueNumber) + " mode.";
- logger(errorStr);
- return -1;
- }
-
-nonstop = true;
-
-if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int NFQ_CAP::Stop()
-{
-if (!isRunning)
- return 0;
-
-nonstop = false;
-
-//5 seconds to thread stops itself
-for (int i = 0; i < 25 && isRunning; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-//after 5 seconds waiting thread still running. now killing it
-if (isRunning)
- {
- if (pthread_kill(thread, SIGUSR1))
- {
- errorStr = "Cannot kill thread.";
- logger("Cannot send signal to thread.");
- return -1;
- }
- for (int i = 0; i < 25 && isRunning; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- if (isRunning)
- {
- errorStr = "NFQ_CAP not stopped.";
- logger("Cannot stop thread.");
- printfd(__FILE__, "Cannot stop thread\n");
- return -1;
- }
- }
-
-pthread_join(thread, NULL);
-
-nfq_destroy_queue(queueHandle);
-nfq_close(nfqHandle);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * NFQ_CAP::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-NFQ_CAP * dc = static_cast<NFQ_CAP *>(d);
-dc->isRunning = true;
-
-int fd = nfq_fd(dc->nfqHandle);
-char buf[4096];
-
-while (dc->nonstop)
- {
- if (!WaitPackets(fd))
- continue;
-
- int rv = read(fd, buf, sizeof(buf));
- if (rv < 0)
- {
- dc->errorStr = std::string("Read error: ") + strerror(errno);
- dc->logger(dc->errorStr);
- break;
- }
- nfq_handle_packet(dc->nfqHandle, buf, rv);
- }
-
-dc->isRunning = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void NFQ_CAP::Process(const STG::RawPacket & packet)
-{
-traffCnt->process(packet);
-}
+++ /dev/null
-/*
- * 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>
-*/
-
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <vector>
-
-#include <pthread.h>
-
-namespace STG
-{
-
-struct Users;
-struct Tariffs;
-struct Admins;
-struct TraffCounter;
-struct Settings;
-struct RawPacket;
-
-}
-
-struct nfq_handle;
-struct nfq_q_handle;
-
-class NFQ_CAP : public STG::Plugin {
-public:
- NFQ_CAP();
-
- void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return isRunning; }
-
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override;
- uint16_t GetStartPosition() const override { return 40; }
- uint16_t GetStopPosition() const override { return 40; }
-
- void Process(const STG::RawPacket & packet);
-
-private:
- NFQ_CAP(const NFQ_CAP & rvalue);
- NFQ_CAP & operator=(const NFQ_CAP & rvalue);
-
- static void * Run(void *);
-
- mutable std::string errorStr;
-
- pthread_t thread;
- bool nonstop;
- bool isRunning;
- STG::ModuleSettings settings;
-
- size_t queueNumber;
-
- struct nfq_handle * nfqHandle;
- struct nfq_q_handle * queueHandle;
-
- STG::TraffCounter * traffCnt;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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 "pcap_cap.h"
-
-#include "stg/traffcounter.h"
-#include "stg/common.h"
-#include "stg/raw_ip_packet.h"
-
-#include <signal.h>
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-namespace
-{
-
-const size_t SNAP_LEN = 1518;
-const size_t ETHER_ADDR_LEN = 6;
-
-struct ETH
-{
-u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */
-u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */
-u_short ether_type; /* IP? ARP? RARP? etc */
-};
-
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-extern "C" STG::Plugin* GetPlugin()
-{
- static PCAP_CAP plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-std::string PCAP_CAP::GetVersion() const
-{
-return "pcap_cap v.1.0";
-}
-//-----------------------------------------------------------------------------
-PCAP_CAP::PCAP_CAP()
- : nonstop(false),
- isRunning(false),
- traffCnt(NULL),
- logger(STG::PluginLogger::get("pcap_cap"))
-{
-}
-//-----------------------------------------------------------------------------
-int PCAP_CAP::ParseSettings()
-{
-devices.erase(devices.begin(), devices.end());
-
-if (settings.moduleParams.empty())
- {
- devices.push_back(DEV());
- logger("Defaulting to pseudo-device 'any'.");
- return 0;
- }
-
-for (size_t i = 0; i < settings.moduleParams.size(); i++)
- if (settings.moduleParams[i].param == "interfaces")
- for (size_t j = 0; j < settings.moduleParams[i].value.size(); j++)
- devices.push_back(DEV(settings.moduleParams[i].value[j]));
-
-for (size_t i = 0; i < settings.moduleParams.size(); i++)
- if (settings.moduleParams[i].param == "filters")
- for (size_t j = 0; j < settings.moduleParams[i].value.size(); j++)
- if (j < devices.size())
- devices[j].filterExpression = settings.moduleParams[i].value[j];
-
-if (devices.empty())
- {
- devices.push_back(DEV());
- logger("Defaulting to pseudo-device 'all'.");
- return 0;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int PCAP_CAP::Start()
-{
-if (isRunning)
- return 0;
-
-DEV_MAP::iterator it(devices.begin());
-while (it != devices.end())
- {
- bpf_u_int32 mask;
- bpf_u_int32 net;
- char errbuf[PCAP_ERRBUF_SIZE];
-
- /* get network number and mask associated with capture device */
- if (pcap_lookupnet(it->device.c_str(), &net, &mask, errbuf) == -1)
- {
- errorStr = "Couldn't get netmask for device " + it->device + ": " + errbuf;
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- /* open capture device */
- it->handle = pcap_open_live(it->device.c_str(), SNAP_LEN, 1, 1000, errbuf);
- if (it->handle == NULL)
- {
- errorStr = "Couldn't open device " + it->device + ": " + errbuf;
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- if (pcap_setnonblock(it->handle, true, errbuf) == -1)
- {
- errorStr = "Couldn't put device " + it->device + " into non-blocking mode: " + errbuf;
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- /* make sure we're capturing on an Ethernet device [2] */
- if (pcap_datalink(it->handle) != DLT_EN10MB)
- {
- errorStr = it->device + " is not an Ethernet";
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- /* compile the filter expression */
- if (pcap_compile(it->handle, &it->filter, it->filterExpression.c_str(), 0, net) == -1)
- {
- errorStr = "Couldn't parse filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- /* apply the compiled filter */
- if (pcap_setfilter(it->handle, &it->filter) == -1)
- {
- errorStr = "Couldn't install filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- it->fd = pcap_get_selectable_fd(it->handle);
- if (it->fd == -1)
- {
- errorStr = "Couldn't get a file descriptor for " + it->device + ": " + pcap_geterr(it->handle);
- logger(errorStr);
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
- ++it;
- }
-
-nonstop = true;
-
-if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int PCAP_CAP::Stop()
-{
-if (!isRunning)
- return 0;
-
-nonstop = false;
-
-//5 seconds to thread stops itself
-for (int i = 0; i < 25 && isRunning; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-//after 5 seconds waiting thread still running. now killing it
-if (isRunning)
- {
- if (pthread_kill(thread, SIGUSR1))
- {
- errorStr = "Cannot kill thread.";
- logger("Cannot send signal to thread.");
- return -1;
- }
- for (int i = 0; i < 25 && isRunning; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- if (isRunning)
- {
- errorStr = "PCAP_CAP not stopped.";
- logger("Cannot stop thread.");
- printfd(__FILE__, "Cannot stop thread\n");
- return -1;
- }
- }
-
-pthread_join(thread, NULL);
-
-for (DEV_MAP::iterator it(devices.begin()); it != devices.end(); ++it)
- {
- pcap_freecode(&it->filter);
- pcap_close(it->handle);
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * PCAP_CAP::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-PCAP_CAP * dc = static_cast<PCAP_CAP *>(d);
-dc->isRunning = true;
-
-fd_set fds;
-FD_ZERO(&fds);
-int maxFd = 0;
-for (DEV_MAP::const_iterator it(dc->devices.begin()); it != dc->devices.end(); ++it)
- {
- FD_SET(it->fd, &fds);
- maxFd = std::max(maxFd, it->fd);
- }
-
-while (dc->nonstop)
- {
- fd_set rfds = fds;
- struct timeval tv = {0, 500000};
-
- if (select(maxFd + 1, &rfds, NULL, NULL, &tv) > 0)
- dc->TryRead(rfds);
- }
-
-dc->isRunning = false;
-return NULL;
-}
-
-void PCAP_CAP::TryRead(const fd_set & set)
-{
-for (DEV_MAP::const_iterator it(devices.begin()); it != devices.end(); ++it)
- if (FD_ISSET(it->fd, &set))
- TryReadDev(*it);
-}
-
-void PCAP_CAP::TryReadDev(const DEV & dev)
-{
-struct pcap_pkthdr * header;
-const u_char * packet;
-if (pcap_next_ex(dev.handle, &header, &packet) == -1)
- {
- printfd(__FILE__, "Failed to read data from '%s': %s\n", dev.device.c_str(), pcap_geterr(dev.handle));
- return;
- }
-
-const ETH * eth = reinterpret_cast<const ETH *>(packet);
-if (eth->ether_type != 0x8)
- return;
-
-STG::RawPacket ip;
-memcpy(&ip.rawPacket, packet + 14, sizeof(ip.rawPacket));
-traffCnt->process(ip);
-}
+++ /dev/null
-/*
- * 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>
-*/
-
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <vector>
-
-#include <pcap.h>
-#include <pthread.h>
-#include <sys/select.h>
-
-namespace STG
-{
-
-struct Users;
-struct Tariffs;
-struct Admins;
-struct TraffCounter;
-struct Settings;
-
-}
-
-struct DEV
-{
- DEV() : device("any"), filterExpression("ip"), handle(NULL), fd(-1) {}
- DEV(const std::string & d) : device(d), filterExpression("ip"), handle(NULL), fd(-1) {}
- DEV(const std::string & d, const std::string & f)
- : device(d), filterExpression(f), handle(NULL), fd(-1) {}
-
- std::string device;
- std::string filterExpression;
- pcap_t * handle;
- struct bpf_program filter;
- int fd;
-};
-
-typedef std::vector<DEV> DEV_MAP;
-
-class PCAP_CAP : public STG::Plugin {
-public:
- PCAP_CAP();
-
- void SetTraffcounter(STG::TraffCounter * tc) override { traffCnt = tc; }
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return isRunning; }
-
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override;
- uint16_t GetStartPosition() const override { return 40; }
- uint16_t GetStopPosition() const override { return 40; }
-
-private:
- PCAP_CAP(const PCAP_CAP & rvalue);
- PCAP_CAP & operator=(const PCAP_CAP & rvalue);
-
- void TryRead(const fd_set & set);
- void TryReadDev(const DEV & dev);
-
- static void * Run(void *);
-
- mutable std::string errorStr;
-
- pthread_t thread;
- bool nonstop;
- bool isRunning;
- STG::ModuleSettings settings;
- DEV_MAP devices;
-
- STG::TraffCounter * traffCnt;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-#include "admins_methods.h"
-#include "rpcconfig.h"
-
-#include "stg/common.h"
-
-#include "stg/admins.h"
-#include "stg/admin.h"
-#include "stg/admin_conf.h"
-
-#include <ostream> // xmlrpc-c devs have missed something :)
-
-//------------------------------------------------------------------------------
-
-void METHOD_ADMIN_GET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(login, &admin))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-structVal["result"] = xmlrpc_c::value_boolean(true);
-structVal["login"] = xmlrpc_c::value_string(admin->login());
-structVal["password"] = xmlrpc_c::value_string(admin->password());
-
-const auto priv = admin->priv();
-
-structVal["user_stat"] = xmlrpc_c::value_boolean(priv.userStat);
-structVal["user_conf"] = xmlrpc_c::value_boolean(priv.userConf);
-structVal["user_cash"] = xmlrpc_c::value_boolean(priv.userCash);
-structVal["user_passwd"] = xmlrpc_c::value_boolean(priv.userPasswd);
-structVal["user_add_del"] = xmlrpc_c::value_boolean(priv.userAddDel);
-structVal["admin_chg"] = xmlrpc_c::value_boolean(priv.adminChg);
-structVal["tariff_chg"] = xmlrpc_c::value_boolean(priv.tariffChg);
-
-*retvalPtr = xmlrpc_c::value_struct(structVal);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_ADMIN_ADD::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Not logged or cookie timeout'\n");
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Invalid admin (logged)'\n");
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (admins->add(login, *admin))
- {
- printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Failed to add admin'\n");
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_ADMIN_DEL::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (admins->del(login, *admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_ADMIN_CHG::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-xmlrpc_c::value_struct info(paramList.getStruct(2));
-paramList.verifyEnd(3);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * loggedAdmin;
-
-if (admins->find(adminInfo.admin, &loggedAdmin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(login, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::AdminConf conf;
-
-conf.priv = admin->priv();
-conf.password = admin->password();
-conf.login = login;
-
-std::map<std::string, xmlrpc_c::value> structVal = info;
-
-std::map<std::string, xmlrpc_c::value>::iterator it;
-
-if ((it = structVal.find("password")) != structVal.end())
- {
- conf.password = xmlrpc_c::value_string(it->second);
- }
-
-if ((it = structVal.find("user_stat")) != structVal.end())
- {
- conf.priv.userStat = xmlrpc_c::value_boolean(it->second);
- }
-
-if ((it = structVal.find("user_conf")) != structVal.end())
- {
- conf.priv.userConf = xmlrpc_c::value_boolean(it->second);
- }
-
-if ((it = structVal.find("user_cash")) != structVal.end())
- {
- conf.priv.userCash = xmlrpc_c::value_boolean(it->second);
- }
-
-if ((it = structVal.find("user_passwd")) != structVal.end())
- {
- conf.priv.userPasswd = xmlrpc_c::value_boolean(it->second);
- }
-
-if ((it = structVal.find("user_add_del")) != structVal.end())
- {
- conf.priv.userAddDel = xmlrpc_c::value_boolean(it->second);
- }
-
-if ((it = structVal.find("admin_chg")) != structVal.end())
- {
- conf.priv.adminChg = xmlrpc_c::value_boolean(it->second);
- }
-
-if ((it = structVal.find("tariff_chg")) != structVal.end())
- {
- conf.priv.tariffChg = xmlrpc_c::value_boolean(it->second);
- }
-
-if (admins->change(conf, *loggedAdmin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_ADMINS_GET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-paramList.verifyEnd(1);
-
-std::map<std::string, xmlrpc_c::value> mainStructVal;
-std::vector<xmlrpc_c::value> retval;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- mainStructVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(mainStructVal);
- return;
- }
-
-admins->fmap([&retval](const auto& admin)
- {
- const std::map<std::string, xmlrpc_c::value> structVal{
- {"result", xmlrpc_c::value_boolean(true)},
- {"login", xmlrpc_c::value_string(admin.login())},
- {"password", xmlrpc_c::value_string(admin.password())},
- {"user_stat", xmlrpc_c::value_boolean(admin.priv().userStat)},
- {"user_conf", xmlrpc_c::value_boolean(admin.priv().userConf)},
- {"user_cash", xmlrpc_c::value_boolean(admin.priv().userCash)},
- {"user_passwd", xmlrpc_c::value_boolean(admin.priv().userPasswd)},
- {"user_add_del", xmlrpc_c::value_boolean(admin.priv().userAddDel)},
- {"admin_chg", xmlrpc_c::value_boolean(admin.priv().adminChg)},
- {"tariff_chg", xmlrpc_c::value_boolean(admin.priv().tariffChg)}
- };
- retval.push_back(xmlrpc_c::value_struct(structVal));
- });
-
-*retvalPtr = xmlrpc_c::value_array(retval);
-}
+++ /dev/null
-#pragma once
-
-#include <xmlrpc-c/base.hpp>
-#include <xmlrpc-c/registry.hpp>
-
-namespace STG
-{
-
-struct Admins;
-
-}
-
-class RPC_CONFIG;
-
-class METHOD_ADMIN_GET : public xmlrpc_c::method {
-public:
- METHOD_ADMIN_GET(RPC_CONFIG * c,
- STG::Admins * a)
- : config(c),
- admins(a)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_ADMIN_GET(const METHOD_ADMIN_GET & rvalue);
- METHOD_ADMIN_GET & operator=(const METHOD_ADMIN_GET & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
-};
-
-class METHOD_ADMIN_ADD : public xmlrpc_c::method {
-public:
- METHOD_ADMIN_ADD(RPC_CONFIG * c,
- STG::Admins * a)
- : config(c),
- admins(a)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_ADMIN_ADD(const METHOD_ADMIN_ADD & rvalue);
- METHOD_ADMIN_ADD & operator=(const METHOD_ADMIN_ADD & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
-};
-
-class METHOD_ADMIN_DEL : public xmlrpc_c::method {
-public:
- METHOD_ADMIN_DEL(RPC_CONFIG * c,
- STG::Admins * a)
- : config(c),
- admins(a)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_ADMIN_DEL(const METHOD_ADMIN_DEL & rvalue);
- METHOD_ADMIN_DEL & operator=(const METHOD_ADMIN_DEL & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
-};
-
-class METHOD_ADMIN_CHG : public xmlrpc_c::method {
-public:
- METHOD_ADMIN_CHG(RPC_CONFIG * c,
- STG::Admins * a)
- : config(c),
- admins(a)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_ADMIN_CHG(const METHOD_ADMIN_CHG & rvalue);
- METHOD_ADMIN_CHG & operator=(const METHOD_ADMIN_CHG & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
-};
-
-class METHOD_ADMINS_GET : public xmlrpc_c::method {
-public:
- METHOD_ADMINS_GET(RPC_CONFIG * c,
- STG::Admins * a)
- : config(c),
- admins(a)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_ADMINS_GET(const METHOD_ADMINS_GET & rvalue);
- METHOD_ADMINS_GET & operator=(const METHOD_ADMINS_GET & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
-};
+++ /dev/null
-#include "info_methods.h"
-#include "rpcconfig.h"
-
-#include "stg/users.h"
-#include "stg/tariffs.h"
-#include "stg/version.h"
-#include "stg/common.h"
-#include "stg/const.h"
-
-#include <ostream> // xmlrpc-c devs have missed something :)
-
-#include <sys/utsname.h>
-
-void METHOD_INFO::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-paramList.verifyEnd(0);
-std::map<std::string, xmlrpc_c::value> structVal;
-
-std::string un;
-struct utsname utsn;
-
-uname(&utsn);
-un[0] = 0;
-
-un += utsn.sysname;
-un += " ";
-un += utsn.release;
-un += " ";
-un += utsn.machine;
-un += " ";
-un += utsn.nodename;
-
-structVal["version"] = xmlrpc_c::value_string(SERVER_VERSION);
-structVal["tariff_num"] = xmlrpc_c::value_int(static_cast<int>(tariffs->Count()));
-structVal["tariff"] = xmlrpc_c::value_int(2);
-structVal["users_num"] = xmlrpc_c::value_int(static_cast<int>(users->Count()));
-structVal["uname"] = xmlrpc_c::value_string(un);
-structVal["dir_num"] = xmlrpc_c::value_int(DIR_NUM);
-structVal["day_fee"] = xmlrpc_c::value_int(static_cast<int>(dayFee));
-
-std::vector<xmlrpc_c::value> dirnameVal;
-
-for (int i = 0; i< DIR_NUM; i++)
- {
- dirnameVal.push_back(xmlrpc_c::value_string(IconvString(dirNames[i], "KOI8-RU", "UTF-8")));
- }
-
-structVal["dir_names"] = xmlrpc_c::value_array(dirnameVal);
-
-*retvalPtr = xmlrpc_c::value_struct(structVal);
-}
-
-void METHOD_LOGIN::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string login = paramList.getString(0);
-std::string password = paramList.getString(1);
-paramList.verifyEnd(2);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-
-std::string cookie;
-if (config->CheckAdmin(login, password, &cookie))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- structVal["cookie"] = xmlrpc_c::value_string("");
- }
-else
- {
- structVal["result"] = xmlrpc_c::value_boolean(true);
- structVal["cookie"] = xmlrpc_c::value_string(cookie);
- }
-
-*retvalPtr = xmlrpc_c::value_struct(structVal);
-}
-
-void METHOD_LOGOUT::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-paramList.verifyEnd(1);
-
-if (config->LogoutAdmin(cookie))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- }
-else
- {
- *retvalPtr = xmlrpc_c::value_boolean(true);
- }
-}
+++ /dev/null
-#pragma once
-
-#include <xmlrpc-c/base.hpp>
-#include <xmlrpc-c/registry.hpp>
-
-#include <string>
-#include <vector>
-
-namespace STG
-{
-
-struct Settings;
-struct Users;
-struct Tariffs;
-
-}
-
-// Forward declaration
-class RPC_CONFIG;
-
-class METHOD_INFO : public xmlrpc_c::method
-{
-public:
- METHOD_INFO(STG::Tariffs * t,
- STG::Users * u,
- size_t df,
- const std::vector<std::string> & dn)
- : tariffs(t),
- users(u),
- dayFee(df),
- dirNames(dn)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_INFO(const METHOD_INFO & rvalue);
- METHOD_INFO & operator=(const METHOD_INFO & rvalue);
-
- STG::Tariffs * tariffs;
- STG::Users * users;
- size_t dayFee;
- const std::vector<std::string> & dirNames;
-};
-
-class METHOD_LOGIN : public xmlrpc_c::method
-{
-public:
- explicit METHOD_LOGIN(RPC_CONFIG * c)
- : config(c)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_LOGIN(const METHOD_LOGIN & rvalue);
- METHOD_LOGIN & operator=(const METHOD_LOGIN & rvalue);
-
- RPC_CONFIG * config;
-};
-
-class METHOD_LOGOUT : public xmlrpc_c::method
-{
-public:
- explicit METHOD_LOGOUT(RPC_CONFIG * c)
- : config(c)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_LOGOUT(const METHOD_LOGOUT & rvalue);
- METHOD_LOGOUT & operator=(const METHOD_LOGOUT & rvalue);
-
- RPC_CONFIG * config;
-};
+++ /dev/null
-#include "messages_methods.h"
-#include "rpcconfig.h"
-
-#include "stg/users.h"
-#include "stg/user.h"
-#include "stg/message.h"
-#include "stg/common.h"
-
-#include <ostream> // xmlrpc-c devs have missed something :)
-
-extern volatile time_t stgTime;
-
-//------------------------------------------------------------------------------
-
-void METHOD_MESSAGE_SEND::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::vector<xmlrpc_c::value> logins(paramList.getArray(1));
-std::map<std::string, xmlrpc_c::value> msgInfo(paramList.getStruct(2));
-paramList.verifyEnd(3);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Message message;
-
-std::map<std::string, xmlrpc_c::value>::iterator it;
-
-if ((it = msgInfo.find("version")) == msgInfo.end())
- {
- message.header.ver = 1; // Default value
- }
-else
- {
- message.header.ver = xmlrpc_c::value_int(it->second);
- }
-
-if ((it = msgInfo.find("type")) == msgInfo.end())
- {
- message.header.type = 1; // default value
- }
-else
- {
- message.header.type = xmlrpc_c::value_int(it->second);
- }
-
-if ((it = msgInfo.find("repeat")) == msgInfo.end())
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-message.header.repeat = xmlrpc_c::value_int(it->second);
-
-if ((it = msgInfo.find("repeat_period")) == msgInfo.end())
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-message.header.repeatPeriod = xmlrpc_c::value_int(it->second);
-
-if ((it = msgInfo.find("show_time")) == msgInfo.end())
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-message.header.showTime = xmlrpc_c::value_int(it->second);
-
-if ((it = msgInfo.find("text")) == msgInfo.end())
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-message.text = IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "CP1251");
-
-message.header.creationTime = static_cast<int>(stgTime);
-message.header.lastSendTime = 0;
-
-std::vector<xmlrpc_c::value>::iterator lit;
-for (lit = logins.begin(); lit != logins.end(); ++lit)
- {
- using UserPtr = STG::User*;
- UserPtr ui;
- if (users->FindByName(xmlrpc_c::value_string(*lit), &ui))
- {
- printfd(__FILE__, "METHOD_MESSAGE_SEND::execute(): 'User '%s' not found'\n", std::string(xmlrpc_c::value_string(*lit)).c_str());
- }
- else
- {
- ui->AddMessage(&message);
- }
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
+++ /dev/null
-#pragma once
-
-#include <xmlrpc-c/base.hpp>
-#include <xmlrpc-c/registry.hpp>
-
-namespace STG
-{
-
-struct Users;
-
-}
-
-class RPC_CONFIG;
-
-class METHOD_MESSAGE_SEND : public xmlrpc_c::method {
-public:
- METHOD_MESSAGE_SEND(RPC_CONFIG * c,
- STG::Users * u)
- : config(c),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_MESSAGE_SEND(const METHOD_MESSAGE_SEND & rvalue);
- METHOD_MESSAGE_SEND & operator=(const METHOD_MESSAGE_SEND & rvalue);
-
- RPC_CONFIG * config;
- STG::Users * users;
-};
+++ /dev/null
-#include "rpcconfig.h"
-
-#include "info_methods.h"
-#include "users_methods.h"
-#include "tariffs_methods.h"
-#include "admins_methods.h"
-#include "messages_methods.h"
-
-#include "stg/admins.h"
-#include "stg/admin.h"
-#include "stg/module_settings.h"
-#include "stg/settings.h"
-#include "stg/common.h"
-#include "stg/const.h"
-
-#include <algorithm>
-#include <vector>
-#include <ostream> // xmlrpc-c devs have missed something :)
-#include <cstdlib>
-#include <csignal>
-#include <cerrno>
-#include <cstring>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-
-RPC_CONFIG_SETTINGS::RPC_CONFIG_SETTINGS()
- : port(0),
- cookieTimeout(0)
-{
-}
-
-int RPC_CONFIG_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-STG::ParamValue pv;
-pv.param = "Port";
-std::vector<STG::ParamValue>::const_iterator pvi;
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Port\' not found.";
- printfd(__FILE__, "Parameter 'Port' not found\n");
- return -1;
- }
-int p;
-if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
- {
- errorStr = "Cannot parse parameter \'Port\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'Port'\n");
- return -1;
- }
-port = static_cast<uint16_t>(p);
-
-pv.param = "CookieTimeout";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- cookieTimeout = 1800; // 30 * 60
- }
-else
- {
- if (str2x(pvi->value[0], cookieTimeout))
- {
- errorStr = "Incorrect value of CookieTimeout: \'" + pvi->value[0] + "\'";
- printfd(__FILE__, "Incorrect value of 'CookieTimeout'\n");
- return -1;
- }
- }
-
-return 0;
-}
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static RPC_CONFIG plugin;
- return &plugin;
-}
-
-RPC_CONFIG::RPC_CONFIG()
- : users(NULL),
- admins(NULL),
- tariffs(NULL),
- store(NULL),
- fd(-1),
- rpcServer(NULL),
- running(false),
- stopped(true),
- dayFee(0),
- logger(STG::PluginLogger::get("conf_rpc"))
-{
-}
-
-RPC_CONFIG::~RPC_CONFIG()
-{
-// delete server
-delete rpcServer;
-}
-
-int RPC_CONFIG::ParseSettings()
-{
-int ret = rpcConfigSettings.ParseSettings(settings);
-
-if (ret)
- errorStr = rpcConfigSettings.GetStrError();
-
-return ret;
-}
-
-void RPC_CONFIG::SetStgSettings(const STG::Settings * s)
-{
- dayFee = s->GetDayFee();
- dirNames.erase(dirNames.begin(), dirNames.end());
- for (size_t i = 0; i < DIR_NUM; ++i) {
- dirNames.push_back(s->GetDirName(i));
- }
-}
-
-int RPC_CONFIG::Start()
-{
-InitiateRegistry();
-running = true;
-
-fd = socket(AF_INET, SOCK_STREAM, 0);
-if (fd < 0)
- {
- errorStr = "Failed to create socket";
- logger("Cannot create a socket: %s", strerror(errno));
- printfd(__FILE__, "Failed to create listening socket: %s\n", strerror(errno));
- return -1;
- }
-
-int flag = 1;
-
-if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
- {
- errorStr = "Setsockopt failed.";
- logger("setsockopt error: %s", strerror(errno));
- printfd(__FILE__, "Setsockopt failed: %s\n", strerror(errno));
- return -1;
- }
-
-struct sockaddr_in addr;
-addr.sin_family = AF_INET;
-addr.sin_port = htons(rpcConfigSettings.GetPort());
-addr.sin_addr.s_addr = inet_addr("0.0.0.0");
-
-if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
- {
- logger("Cannot bind the socket: %s", strerror(errno));
- errorStr = "Failed to bind socket";
- printfd(__FILE__, "Failed to bind listening socket: %s\n", strerror(errno));
- return -1;
- }
-
-if (listen(fd, 10))
- {
- logger("Cannot listen the socket: %s", strerror(errno));
- errorStr = "Failed to listen socket";
- printfd(__FILE__, "Failed to listen listening socket: %s\n", strerror(errno));
- return -1;
- }
-
-rpcServer = new xmlrpc_c::serverAbyss(
- xmlrpc_c::serverAbyss::constrOpt()
- .registryP(&rpcRegistry)
- .logFileName("/var/log/stargazer_rpc.log")
- .socketFd(fd)
- );
-
-if (pthread_create(&tid, NULL, Run, this))
- {
- errorStr = "Failed to create RPC thread";
- logger("Cannot create RPC thread.");
- printfd(__FILE__, "Failed to crate RPC thread\n");
- return -1;
- }
-
-return 0;
-}
-
-int RPC_CONFIG::Stop()
-{
-running = false;
-for (int i = 0; i < 5 && !stopped; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
-if (!stopped)
- {
- running = true;
- logger("Cannot stop RPC thread.");
- printfd(__FILE__, "Failed to stop RPC thread\n");
- errorStr = "Failed to stop RPC thread";
- return -1;
- }
-else
- {
- pthread_join(tid, NULL);
- }
-
-close(fd);
-
-return 0;
-}
-
-void * RPC_CONFIG::Run(void * rc)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-RPC_CONFIG * config = static_cast<RPC_CONFIG *>(rc);
-
-config->stopped = false;
-while (config->running)
- {
- if (WaitPackets(config->fd))
- config->rpcServer->runOnce();
- }
-config->stopped = true;
-
-return NULL;
-}
-
-bool RPC_CONFIG::GetAdminInfo(const std::string & cookie,
- ADMIN_INFO * info)
-{
-std::map<std::string,
- ADMIN_INFO>::iterator it;
-
-it = cookies.find(cookie);
-
-if (it == cookies.end())
- {
- return true;
- }
-
-if (difftime(it->second.accessTime, time(NULL)) >
- rpcConfigSettings.GetCookieTimeout())
- {
- cookies.erase(it);
- return true;
- }
-
-// Update access time
-time(&it->second.accessTime);
-*info = it->second;
-return false;
-}
-
-bool RPC_CONFIG::CheckAdmin(const std::string & login,
- const std::string & password,
- std::string * cookie)
-{
-STG::Admin * admin = NULL;
-
-if (!admins->correct(login, password, &admin))
- {
- logger("Attempt to connect with invalid credentials. Login: %s", login.c_str());
- return true;
- }
-
-ADMIN_INFO info;
-time(&info.accessTime);
-info.admin = login;
-info.priviledges = admin->priv();
-*cookie = GetCookie();
-cookies[*cookie] = info;
-
-return false;
-}
-
-bool RPC_CONFIG::LogoutAdmin(const std::string & cookie)
-{
-std::map<std::string,
- ADMIN_INFO>::iterator it;
-
-it = cookies.find(cookie);
-
-if (it == cookies.end())
- {
- return true;
- }
-
-cookies.erase(it);
-
-return false;
-}
-
-std::string RPC_CONFIG::GetCookie() const
-{
-std::string charset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
-std::string cookie;
-
-for (int i = 0; i < 64; ++i)
- {
- cookie += charset[rand() % charset.length()];
- };
-
-return cookie;
-}
-
-void RPC_CONFIG::InitiateRegistry()
-{
-// manage registry
-xmlrpc_c::methodPtr const methodInfoPtr(new METHOD_INFO(
- tariffs,
- users,
- dayFee,
- dirNames
- ));
-rpcRegistry.addMethod("stargazer.info", methodInfoPtr);
-
-xmlrpc_c::methodPtr const methodLoginPtr(new METHOD_LOGIN(
- this
- ));
-rpcRegistry.addMethod("stargazer.login", methodLoginPtr);
-
-xmlrpc_c::methodPtr const methodLogoutPtr(new METHOD_LOGOUT(
- this
- ));
-rpcRegistry.addMethod("stargazer.logout", methodLogoutPtr);
-
-xmlrpc_c::methodPtr const methodGetUserPtr(new METHOD_USER_GET(
- this,
- users
- ));
-rpcRegistry.addMethod("stargazer.get_user", methodGetUserPtr);
-
-xmlrpc_c::methodPtr const methodAddUserPtr(new METHOD_USER_ADD(
- this,
- admins,
- users
- ));
-rpcRegistry.addMethod("stargazer.add_user", methodAddUserPtr);
-
-xmlrpc_c::methodPtr const methodDelUserPtr(new METHOD_USER_DEL(
- this,
- admins,
- users
- ));
-rpcRegistry.addMethod("stargazer.del_user", methodDelUserPtr);
-
-xmlrpc_c::methodPtr const methodGetUsersPtr(new METHOD_USERS_GET(
- this,
- users
- ));
-rpcRegistry.addMethod("stargazer.get_users", methodGetUsersPtr);
-
-xmlrpc_c::methodPtr const methodChgUserPtr(new METHOD_USER_CHG(
- this,
- admins,
- tariffs,
- store,
- users
- ));
-rpcRegistry.addMethod("stargazer.chg_user", methodChgUserPtr);
-
-xmlrpc_c::methodPtr const methodAddCashPtr(new METHOD_USER_CASH_ADD(
- this,
- admins,
- store,
- users
- ));
-rpcRegistry.addMethod("stargazer.add_user_cash", methodAddCashPtr);
-
-xmlrpc_c::methodPtr const methodSetCashPtr(new METHOD_USER_CASH_SET(
- this,
- admins,
- store,
- users
- ));
-rpcRegistry.addMethod("stargazer.set_user_cash", methodSetCashPtr);
-
-xmlrpc_c::methodPtr const methodTariffChangePtr(new METHOD_USER_TARIFF_CHANGE(
- this,
- admins,
- tariffs,
- store,
- users
- ));
-rpcRegistry.addMethod("stargazer.chg_user_tariff", methodTariffChangePtr);
-
-xmlrpc_c::methodPtr const methodGetTariffPtr(new METHOD_TARIFF_GET(
- this,
- tariffs
- ));
-rpcRegistry.addMethod("stargazer.get_tariff", methodGetTariffPtr);
-
-xmlrpc_c::methodPtr const methodChgTariffPtr(new METHOD_TARIFF_CHG(
- this,
- admins,
- tariffs
- ));
-rpcRegistry.addMethod("stargazer.chg_tariff", methodChgTariffPtr);
-
-xmlrpc_c::methodPtr const methodGetTariffsPtr(new METHOD_TARIFFS_GET(
- this,
- tariffs
- ));
-rpcRegistry.addMethod("stargazer.get_tariffs", methodGetTariffsPtr);
-
-xmlrpc_c::methodPtr const methodAddTariffPtr(new METHOD_TARIFF_ADD(
- this,
- admins,
- tariffs
- ));
-rpcRegistry.addMethod("stargazer.add_tariff", methodAddTariffPtr);
-
-xmlrpc_c::methodPtr const methodDelTariffPtr(new METHOD_TARIFF_DEL(
- this,
- admins,
- tariffs,
- users
- ));
-rpcRegistry.addMethod("stargazer.del_tariff", methodDelTariffPtr);
-
-xmlrpc_c::methodPtr const methodGetAdminPtr(new METHOD_ADMIN_GET(
- this,
- admins
- ));
-rpcRegistry.addMethod("stargazer.get_admin", methodGetAdminPtr);
-
-xmlrpc_c::methodPtr const methodAddAdminPtr(new METHOD_ADMIN_ADD(
- this,
- admins
- ));
-rpcRegistry.addMethod("stargazer.add_admin", methodAddAdminPtr);
-
-xmlrpc_c::methodPtr const methodDelAdminPtr(new METHOD_ADMIN_DEL(
- this,
- admins
- ));
-rpcRegistry.addMethod("stargazer.del_admin", methodDelAdminPtr);
-
-xmlrpc_c::methodPtr const methodChgAdminPtr(new METHOD_ADMIN_CHG(
- this,
- admins
- ));
-rpcRegistry.addMethod("stargazer.chg_admin", methodChgAdminPtr);
-
-xmlrpc_c::methodPtr const methodGetAdminsPtr(new METHOD_ADMINS_GET(
- this,
- admins
- ));
-rpcRegistry.addMethod("stargazer.get_admins", methodGetAdminsPtr);
-
-xmlrpc_c::methodPtr const methodSendMessagePtr(new METHOD_MESSAGE_SEND(
- this,
- users
- ));
-rpcRegistry.addMethod("stargazer.send_user_message", methodSendMessagePtr);
-
-xmlrpc_c::methodPtr const methodGetOnlinIPsPtr(new METHOD_GET_ONLINE_IPS(
- this,
- users
- ));
-rpcRegistry.addMethod("stargazer.get_online_ips", methodGetOnlinIPsPtr);
-
-xmlrpc_c::methodPtr const methodGetUserAuthByPtr(new METHOD_GET_USER_AUTH_BY(
- this,
- users
- ));
-rpcRegistry.addMethod("stargazer.get_user_auth_by", methodGetUserAuthByPtr);
-}
-
+++ /dev/null
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/admin_conf.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <xmlrpc-c/base.hpp>
-#include <xmlrpc-c/registry.hpp>
-#include <xmlrpc-c/server_abyss.hpp>
-
-#include <ctime>
-#include <cstdint>
-#include <string>
-#include <map>
-#include <vector>
-
-#include <pthread.h>
-
-#define RPC_CONFIG_VERSION "Stargazer RPC v. 0.2"
-
-namespace STG
-{
-
-struct Admins;
-struct Tariffs;
-struct Users;
-struct Store;
-
-}
-
-class RPC_CONFIG_SETTINGS
-{
-public:
- RPC_CONFIG_SETTINGS();
- virtual ~RPC_CONFIG_SETTINGS() {}
- const std::string & GetStrError() const { return errorStr; }
- int ParseSettings(const STG::ModuleSettings & s);
- uint16_t GetPort() const { return port; }
- double GetCookieTimeout() const { return cookieTimeout; }
-
-private:
- std::string errorStr;
- uint16_t port;
- double cookieTimeout;
-};
-
-struct ADMIN_INFO
-{
- ADMIN_INFO()
- : admin(),
- accessTime(0),
- priviledges()
- {}
-
- std::string admin;
- time_t accessTime;
- STG::Priv priviledges;
-};
-
-class RPC_CONFIG : public STG::Plugin
-{
-public:
- RPC_CONFIG();
- ~RPC_CONFIG() override;
-
- void SetUsers(STG::Users * u) override { users = u; }
- void SetTariffs(STG::Tariffs * t) override { tariffs = t; }
- void SetAdmins(STG::Admins * a) override { admins = a; }
- void SetStore(STG::Store * s) override { store = s; }
- void SetStgSettings(const STG::Settings * s) override;
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return running && !stopped; }
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override { return RPC_CONFIG_VERSION; }
- uint16_t GetStartPosition() const override { return 20; }
- uint16_t GetStopPosition() const override { return 20; }
-
- bool GetAdminInfo(const std::string & cookie,
- ADMIN_INFO * info);
- bool CheckAdmin(const std::string & login,
- const std::string & password,
- std::string * cookie);
- bool LogoutAdmin(const std::string & cookie);
-
-private:
- RPC_CONFIG(const RPC_CONFIG & rvalue);
- RPC_CONFIG & operator=(const RPC_CONFIG & rvalue);
-
- static void * Run(void *);
- std::string GetCookie() const;
- void InitiateRegistry();
-
- mutable std::string errorStr;
- RPC_CONFIG_SETTINGS rpcConfigSettings;
- STG::Users * users;
- STG::Admins * admins;
- STG::Tariffs * tariffs;
- STG::Store * store;
- STG::ModuleSettings settings;
- int fd;
- xmlrpc_c::registry rpcRegistry;
- xmlrpc_c::serverAbyss * rpcServer;
- bool running;
- bool stopped;
- pthread_t tid;
- std::map<std::string,
- ADMIN_INFO> cookies;
- size_t dayFee;
- std::vector<std::string> dirNames;
- STG::PluginLogger logger;
-};
+++ /dev/null
-#include "tariff_helper.h"
-
-#include "stg/tariff_conf.h"
-#include "stg/common.h"
-#include "stg/const.h"
-
-#include <ostream> // xmlrpc-c devs have missed something :)
-
-void TARIFF_HELPER::GetTariffInfo(xmlrpc_c::value * info) const
-{
-std::map<std::string, xmlrpc_c::value> structVal;
-
-structVal["result"] = xmlrpc_c::value_boolean(true);
-structVal["name"] = xmlrpc_c::value_string(data.tariffConf.name);
-structVal["fee"] = xmlrpc_c::value_double(data.tariffConf.fee);
-structVal["freemb"] = xmlrpc_c::value_double(data.tariffConf.free);
-structVal["passivecost"] = xmlrpc_c::value_double(data.tariffConf.passiveCost);
-structVal["traffType"] = xmlrpc_c::value_int(data.tariffConf.traffType);
-structVal["period"] = xmlrpc_c::value_string(STG::Tariff::toString(data.tariffConf.period));
-structVal["changePolicy"] = xmlrpc_c::value_string(STG::Tariff::toString(data.tariffConf.changePolicy));
-structVal["changePolicyTimeout"] = xmlrpc_c::value_string(formatTime(data.tariffConf.changePolicyTimeout));
-
-std::vector<xmlrpc_c::value> prices(DIR_NUM);
-
-for (unsigned i = 0; i < DIR_NUM; ++i)
- {
- std::map<std::string, xmlrpc_c::value> dirPrice;
- dirPrice["hday"] = xmlrpc_c::value_int(data.dirPrice[i].hDay);
- dirPrice["mday"] = xmlrpc_c::value_int(data.dirPrice[i].mDay);
- dirPrice["hnight"] = xmlrpc_c::value_int(data.dirPrice[i].hNight);
- dirPrice["mnight"] = xmlrpc_c::value_int(data.dirPrice[i].mNight);
- dirPrice["pricedaya"] = xmlrpc_c::value_double(data.dirPrice[i].priceDayA * 1024 * 1024);
- dirPrice["pricedayb"] = xmlrpc_c::value_double(data.dirPrice[i].priceDayB * 1024 * 1024);
- dirPrice["pricenighta"] = xmlrpc_c::value_double(data.dirPrice[i].priceNightA * 1024 * 1024);
- dirPrice["pricenightb"] = xmlrpc_c::value_double(data.dirPrice[i].priceNightB * 1024 * 1024);
- dirPrice["threshold"] = xmlrpc_c::value_int(data.dirPrice[i].threshold);
- dirPrice["singleprice"] = xmlrpc_c::value_boolean(data.dirPrice[i].singlePrice);
- dirPrice["nodiscount"] = xmlrpc_c::value_boolean(data.dirPrice[i].noDiscount);
- prices[i] = xmlrpc_c::value_struct(dirPrice);
- }
-
-structVal["dirprices"] = xmlrpc_c::value_array(prices);
-
-*info = xmlrpc_c::value_struct(structVal);
-}
-
-bool TARIFF_HELPER::SetTariffInfo(const xmlrpc_c::value & info)
-{
-std::map<std::string, xmlrpc_c::value> structVal(
- static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
- );
-
-std::map<std::string, xmlrpc_c::value>::iterator it;
-
-if ((it = structVal.find("fee")) != structVal.end())
- {
- data.tariffConf.fee = xmlrpc_c::value_double(it->second);
- }
-
-if ((it = structVal.find("freemb")) != structVal.end())
- {
- data.tariffConf.free = xmlrpc_c::value_double(it->second);
- }
-
-if ((it = structVal.find("passivecost")) != structVal.end())
- {
- data.tariffConf.passiveCost = xmlrpc_c::value_double(it->second);
- }
-
-if ((it = structVal.find("traffType")) != structVal.end())
- {
- data.tariffConf.traffType = static_cast<STG::Tariff::TraffType>(xmlrpc_c::value_int(it->second).cvalue());
- }
-
-if ((it = structVal.find("period")) != structVal.end())
- {
- data.tariffConf.period = STG::Tariff::parsePeriod(xmlrpc_c::value_string(it->second));
- }
-
-if ((it = structVal.find("changePolicy")) != structVal.end())
- {
- data.tariffConf.changePolicy = STG::Tariff::parseChangePolicy(xmlrpc_c::value_string(it->second));
- }
-
-if ((it = structVal.find("changePolicyTimeout")) != structVal.end())
- {
- data.tariffConf.changePolicyTimeout = readTime(xmlrpc_c::value_string(it->second));
- }
-
-if ((it = structVal.find("dirprices")) != structVal.end())
- {
- std::vector<xmlrpc_c::value> prices(
- xmlrpc_c::value_array(it->second).vectorValueValue()
- );
-
- for (unsigned i = 0; i < DIR_NUM; ++i)
- {
- std::map<std::string, xmlrpc_c::value> dirPrice(
- static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(prices[i]))
- );
- data.dirPrice[i].mDay = xmlrpc_c::value_int(dirPrice["mday"]);
- data.dirPrice[i].hDay = xmlrpc_c::value_int(dirPrice["hday"]);
- data.dirPrice[i].mNight = xmlrpc_c::value_int(dirPrice["mnight"]);
- data.dirPrice[i].hNight = xmlrpc_c::value_int(dirPrice["hnight"]);
- data.dirPrice[i].priceDayA = xmlrpc_c::value_double(dirPrice["pricedaya"]) / 1024 / 1024;
- data.dirPrice[i].priceDayB = xmlrpc_c::value_double(dirPrice["pricedayb"]) / 1024 / 1024;
- data.dirPrice[i].priceNightA = xmlrpc_c::value_double(dirPrice["pricenighta"]) / 1024 / 1024;
- data.dirPrice[i].priceNightB = xmlrpc_c::value_double(dirPrice["pricenightb"]) / 1024 / 1024;
- data.dirPrice[i].threshold = xmlrpc_c::value_int(dirPrice["threshold"]);
- data.dirPrice[i].singlePrice = xmlrpc_c::value_boolean(dirPrice["singleprice"]);
- data.dirPrice[i].noDiscount = xmlrpc_c::value_boolean(dirPrice["nodiscount"]);
- }
- }
-
-return false;
-}
+++ /dev/null
-#pragma once
-
-#include <xmlrpc-c/base.hpp>
-
-namespace STG
-{
-
-struct TariffData;
-
-}
-
-class TARIFF_HELPER
-{
-public:
- explicit TARIFF_HELPER(STG::TariffData & td)
- : data(td)
- {}
-
- void GetTariffInfo(xmlrpc_c::value * info) const;
- bool SetTariffInfo(const xmlrpc_c::value & info);
-private:
- STG::TariffData & data;
-};
+++ /dev/null
-#include <ostream> // xmlrpc-c devs have missed something :)
-
-#include "tariffs_methods.h"
-#include "rpcconfig.h"
-#include "tariff_helper.h"
-
-#include "stg/tariffs.h"
-#include "stg/tariff.h"
-#include "stg/tariff_conf.h"
-#include "stg/users.h"
-#include "stg/admins.h"
-#include "stg/admin.h"
-
-void METHOD_TARIFF_GET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string name = paramList.getString(1);
-paramList.verifyEnd(2);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-const auto tariff = tariffs->FindByName(name);
-
-if (!tariff)
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-auto td = tariff->GetTariffData();
-
-TARIFF_HELPER helper(td);
-
-helper.GetTariffInfo(retvalPtr);
-}
-
-void METHOD_TARIFF_CHG::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string name = paramList.getString(1);
-xmlrpc_c::value_struct info(paramList.getStruct(2));
-paramList.verifyEnd(3);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-const auto tariff = tariffs->FindByName(name);
-
-if (!tariff)
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-auto td = tariff->GetTariffData();
-
-TARIFF_HELPER helper(td);
-
-helper.SetTariffInfo(info);
-
-if (tariffs->Chg(td, admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-void METHOD_TARIFFS_GET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-paramList.verifyEnd(1);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-std::vector<xmlrpc_c::value> tariffsInfo;
-
-
-std::vector<STG::TariffData> dataList;
-tariffs->GetTariffsData(&dataList);
-auto it = dataList.begin();
-for (; it != dataList.end(); ++it)
- {
- xmlrpc_c::value info;
- auto td = *it; // 'cause TARIFF_HELPER work in both ways and take not const referense
- TARIFF_HELPER helper(td);
- helper.GetTariffInfo(&info);
- tariffsInfo.push_back(info);
- }
-
-*retvalPtr = xmlrpc_c::value_array(tariffsInfo);
-}
-
-void METHOD_TARIFF_ADD::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string tariff = paramList.getString(1);
-paramList.verifyEnd(2);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (tariffs->Add(tariff, admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-void METHOD_TARIFF_DEL::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string tariff = paramList.getString(1);
-paramList.verifyEnd(2);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (users->TariffInUse(tariff))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (tariffs->Del(tariff, admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
+++ /dev/null
-#pragma once
-
-#include <xmlrpc-c/base.hpp>
-#include <xmlrpc-c/registry.hpp>
-
-namespace STG
-{
-
-struct Tariffs;
-struct Users;
-struct Admins;
-
-}
-
-class RPC_CONFIG;
-
-class METHOD_TARIFF_GET : public xmlrpc_c::method {
-public:
- METHOD_TARIFF_GET(RPC_CONFIG * c,
- STG::Tariffs * t)
- : config(c),
- tariffs(t)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_TARIFF_GET(const METHOD_TARIFF_GET & rvalue);
- METHOD_TARIFF_GET & operator=(const METHOD_TARIFF_GET & rvalue);
-
- RPC_CONFIG * config;
- STG::Tariffs * tariffs;
-};
-
-class METHOD_TARIFF_CHG : public xmlrpc_c::method {
-public:
- METHOD_TARIFF_CHG(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Tariffs * t)
- : config(c),
- admins(a),
- tariffs(t)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_TARIFF_CHG(const METHOD_TARIFF_CHG & rvalue);
- METHOD_TARIFF_CHG & operator=(const METHOD_TARIFF_CHG & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Tariffs * tariffs;
-};
-
-class METHOD_TARIFFS_GET : public xmlrpc_c::method {
-public:
- METHOD_TARIFFS_GET(RPC_CONFIG * c,
- STG::Tariffs * t)
- : config(c),
- tariffs(t)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr);
-
-private:
- METHOD_TARIFFS_GET(const METHOD_TARIFFS_GET & rvalue);
- METHOD_TARIFFS_GET & operator=(const METHOD_TARIFFS_GET & rvalue);
-
- RPC_CONFIG * config;
- STG::Tariffs * tariffs;
-};
-
-class METHOD_TARIFF_ADD : public xmlrpc_c::method {
-public:
- METHOD_TARIFF_ADD(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Tariffs * t)
- : config(c),
- admins(a),
- tariffs(t)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_TARIFF_ADD(const METHOD_TARIFF_ADD & rvalue);
- METHOD_TARIFF_ADD & operator=(const METHOD_TARIFF_ADD & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Tariffs * tariffs;
-};
-
-class METHOD_TARIFF_DEL : public xmlrpc_c::method {
-public:
- METHOD_TARIFF_DEL(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Tariffs * t,
- STG::Users * u)
- : config(c),
- admins(a),
- tariffs(t),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_TARIFF_DEL(const METHOD_TARIFF_DEL & rvalue);
- METHOD_TARIFF_DEL & operator=(const METHOD_TARIFF_DEL & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Tariffs * tariffs;
- STG::Users * users;
-};
+++ /dev/null
-#include "user_helper.h"
-
-#include "stg/tariffs.h"
-#include "stg/tariff.h"
-#include "stg/admin.h"
-#include "stg/store.h"
-#include "stg/users.h"
-#include "stg/user.h"
-#include "stg/user_ips.h"
-#include "stg/user_property.h"
-#include "stg/common.h"
-#include "stg/const.h"
-
-#include <cmath>
-
-//------------------------------------------------------------------------------
-
-void USER_HELPER::GetUserInfo(xmlrpc_c::value * info,
- bool hidePassword)
-{
-std::map<std::string, xmlrpc_c::value> structVal;
-
-structVal["result"] = xmlrpc_c::value_boolean(true);
-structVal["login"] = xmlrpc_c::value_string(ptr->GetLogin());
-
-if (!hidePassword)
- {
- structVal["password"] = xmlrpc_c::value_string(ptr->GetProperties().password.Get());
- }
-else
- {
- structVal["password"] = xmlrpc_c::value_string("++++++++");
- }
-
-structVal["cash"] = xmlrpc_c::value_double(ptr->GetProperties().cash.Get());
-structVal["freemb"] = xmlrpc_c::value_double(ptr->GetProperties().freeMb.Get());
-structVal["credit"] = xmlrpc_c::value_double(ptr->GetProperties().credit.Get());
-
-if (ptr->GetProperties().nextTariff.Get() != "")
- {
- structVal["tariff"] = xmlrpc_c::value_string(
- ptr->GetProperties().tariffName.Get() +
- "/" +
- ptr->GetProperties().nextTariff.Get()
- );
- }
-else
- {
- structVal["tariff"] = xmlrpc_c::value_string(ptr->GetProperties().tariffName.Get());
- }
-
-structVal["note"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().note, "KOI8-RU", "UTF-8"));
-
-structVal["phone"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().phone, "KOI8-RU", "UTF-8"));
-
-structVal["address"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().address, "KOI8-RU", "UTF-8"));
-
-structVal["email"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().email, "KOI8-RU", "UTF-8"));
-
-std::vector<xmlrpc_c::value> userdata;
-
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata0.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata1.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata2.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata3.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata4.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata5.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata6.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata7.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata8.Get(), "KOI8-RU", "UTF-8")));
-userdata.push_back(xmlrpc_c::value_string(IconvString(ptr->GetProperties().userdata9.Get(), "KOI8-RU", "UTF-8")));
-
-structVal["userdata"] = xmlrpc_c::value_array(userdata);
-
-structVal["name"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().realName, "KOI8-RU", "UTF-8"));
-
-structVal["group"] = xmlrpc_c::value_string(IconvString(ptr->GetProperties().group, "KOI8-RU", "UTF-8"));
-
-structVal["status"] = xmlrpc_c::value_boolean(ptr->GetConnected());
-structVal["aonline"] = xmlrpc_c::value_boolean(ptr->GetProperties().alwaysOnline.Get());
-structVal["currip"] = xmlrpc_c::value_string(inet_ntostring(ptr->GetCurrIP()));
-structVal["pingtime"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetPingTime()));
-structVal["ips"] = xmlrpc_c::value_string(ptr->GetProperties().ips.Get().toString());
-
-std::map<std::string, xmlrpc_c::value> traffInfo;
-std::vector<xmlrpc_c::value> mu(DIR_NUM);
-std::vector<xmlrpc_c::value> md(DIR_NUM);
-std::vector<xmlrpc_c::value> su(DIR_NUM);
-std::vector<xmlrpc_c::value> sd(DIR_NUM);
-
-auto upload = ptr->GetProperties().up.Get();
-auto download = ptr->GetProperties().down.Get();
-auto supload = ptr->GetSessionUpload();
-auto sdownload = ptr->GetSessionDownload();
-
-for (int j = 0; j < DIR_NUM; j++)
- {
- mu[j] = xmlrpc_c::value_string(std::to_string(upload[j]));
- md[j] = xmlrpc_c::value_string(std::to_string(download[j]));
- su[j] = xmlrpc_c::value_string(std::to_string(supload[j]));
- sd[j] = xmlrpc_c::value_string(std::to_string(sdownload[j]));
- }
-
-traffInfo["mu"] = xmlrpc_c::value_array(mu);
-traffInfo["md"] = xmlrpc_c::value_array(md);
-traffInfo["su"] = xmlrpc_c::value_array(su);
-traffInfo["sd"] = xmlrpc_c::value_array(sd);
-
-structVal["traff"] = xmlrpc_c::value_struct(traffInfo);
-
-structVal["down"] = xmlrpc_c::value_boolean(ptr->GetProperties().disabled.Get());
-structVal["disableddetailstat"] = xmlrpc_c::value_boolean(ptr->GetProperties().disabledDetailStat.Get());
-structVal["passive"] = xmlrpc_c::value_boolean(ptr->GetProperties().passive.Get());
-structVal["lastcash"] = xmlrpc_c::value_double(ptr->GetProperties().lastCashAdd.Get());
-structVal["lasttimecash"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetProperties().lastCashAddTime.Get()));
-structVal["lastactivitytime"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetProperties().lastActivityTime.Get()));
-structVal["creditexpire"] = xmlrpc_c::value_int(static_cast<int>(ptr->GetProperties().creditExpire.Get()));
-
-*info = xmlrpc_c::value_struct(structVal);
-}
-
-//------------------------------------------------------------------------------
-
-bool USER_HELPER::SetUserInfo(const xmlrpc_c::value & info,
- const STG::Admin& admin,
- const std::string & login,
- const STG::Store & store,
- STG::Tariffs * tariffs)
-{
-std::map<std::string, xmlrpc_c::value> structVal(
- static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
- );
-
-std::map<std::string, xmlrpc_c::value>::iterator it;
-
-bool check = false;
-bool alwaysOnline = ptr->GetProperties().alwaysOnline;
-if ((it = structVal.find("aonline")) != structVal.end())
- {
- check = true;
- alwaysOnline = xmlrpc_c::value_boolean(it->second);
- }
-bool onlyOneIP = ptr->GetProperties().ips.ConstData().onlyOneIP();
-if ((it = structVal.find("ips")) != structVal.end())
- {
- check = true;
- onlyOneIP = STG::UserIPs::parse(xmlrpc_c::value_string(it->second)).onlyOneIP();
- }
-
-if (check && alwaysOnline && !onlyOneIP)
- {
- printfd(__FILE__, "Requested change leads to a forbidden state: AlwaysOnline with multiple IP's\n");
- return true;
- }
-
-if ((it = structVal.find("ips")) != structVal.end())
- {
- auto ips = STG::UserIPs::parse(xmlrpc_c::value_string(it->second));
-
- for (size_t i = 0; i < ips.count(); ++i)
- {
- using ConstUserPtr = const STG::User*;
- ConstUserPtr user;
- uint32_t ip = ips[i].ip;
- if (users.IsIPInUse(ip, login, &user))
- {
- printfd(__FILE__, "Trying to assign an IP %s to '%s' that is already in use by '%s'\n", inet_ntostring(ip).c_str(), login.c_str(), user->GetLogin().c_str());
- return true;
- }
- }
-
- if (!ptr->GetProperties().ips.Set(ips, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("aonline")) != structVal.end())
- {
- bool value(xmlrpc_c::value_boolean(it->second));
- if (ptr->GetProperties().alwaysOnline.Get() != value)
- if (!ptr->GetProperties().alwaysOnline.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("password")) != structVal.end())
- {
- std::string value(xmlrpc_c::value_string(it->second));
- if (ptr->GetProperties().password.Get() != value)
- if (!ptr->GetProperties().password.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("address")) != structVal.end())
- {
- std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
- if (ptr->GetProperties().address.Get() != value)
- if (!ptr->GetProperties().address.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("phone")) != structVal.end())
- {
- std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
- if (ptr->GetProperties().phone.Get() != value)
- if (!ptr->GetProperties().phone.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("email")) != structVal.end())
- {
- std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
- if (ptr->GetProperties().email.Get() != value)
- if (!ptr->GetProperties().email.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("cash")) != structVal.end())
- {
- double value(xmlrpc_c::value_double(it->second));
- if (std::fabs(ptr->GetProperties().cash.Get() - value) > 1.0e-3)
- if (!ptr->GetProperties().cash.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("creditexpire")) != structVal.end())
- {
- time_t value(xmlrpc_c::value_int(it->second));
- if (ptr->GetProperties().creditExpire.Get() != value)
- if (!ptr->GetProperties().creditExpire.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("credit")) != structVal.end())
- {
- double value(xmlrpc_c::value_double(it->second));
- if (std::fabs(ptr->GetProperties().credit.Get() - value) > 1.0e-3)
- if (!ptr->GetProperties().credit.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("freemb")) != structVal.end())
- {
- double value(xmlrpc_c::value_double(it->second));
- if (std::fabs(ptr->GetProperties().freeMb.Get() - value) > 1.0e-3)
- if (!ptr->GetProperties().freeMb.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("down")) != structVal.end())
- {
- bool value(xmlrpc_c::value_boolean(it->second));
- if (ptr->GetProperties().disabled.Get() != value)
- if (!ptr->GetProperties().disabled.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("passive")) != structVal.end())
- {
- bool value(xmlrpc_c::value_boolean(it->second));
- if (ptr->GetProperties().passive.Get() != value)
- if (!ptr->GetProperties().passive.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("disableddetailstat")) != structVal.end())
- {
- bool value(xmlrpc_c::value_boolean(it->second));
- if (ptr->GetProperties().disabledDetailStat.Get() != value)
- if (!ptr->GetProperties().disabledDetailStat.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("name")) != structVal.end())
- {
- std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
- if (ptr->GetProperties().realName.Get() != value)
- if (!ptr->GetProperties().realName.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("group")) != structVal.end())
- {
- std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
- if (ptr->GetProperties().group.Get() != value)
- if (!ptr->GetProperties().group.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("note")) != structVal.end())
- {
- std::string value(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-RU"));
- if (ptr->GetProperties().note.Get() != value)
- if (!ptr->GetProperties().note.Set(value, admin, login, store))
- return true;
- }
-
-if ((it = structVal.find("userdata")) != structVal.end())
- {
- std::vector<STG::UserPropertyLogged<std::string> *> userdata;
- userdata.push_back(ptr->GetProperties().userdata0.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata1.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata2.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata3.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata4.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata5.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata6.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata7.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata8.GetPointer());
- userdata.push_back(ptr->GetProperties().userdata9.GetPointer());
-
- std::vector<xmlrpc_c::value> udata(
- xmlrpc_c::value_array(it->second).vectorValueValue()
- );
-
- for (unsigned i = 0; i < userdata.size(); ++i)
- {
- std::string value(IconvString(xmlrpc_c::value_string(udata[i]), "UTF-8", "KOI8-RU"));
- if (userdata[i]->Get() != value)
- if (!userdata[i]->Set(value, admin, login, store))
- return true;
- }
- }
-
-if ((it = structVal.find("traff")) != structVal.end())
- {
- std::map<std::string, xmlrpc_c::value> traff(
- static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(it->second))
- );
-
- auto dtData = ptr->GetProperties().up.Get();
- if ((it = traff.find("mu")) != traff.end())
- {
- std::vector<xmlrpc_c::value> data(xmlrpc_c::value_array(it->second).vectorValueValue());
-
- for (int i = 0; i < std::min(DIR_NUM, static_cast<int>(data.size())); ++i)
- {
- int64_t value;
- if (str2x(xmlrpc_c::value_string(data[i]), value))
- printfd(__FILE__, "USER_HELPER::SetUserInfo(): 'Invalid month upload value'\n");
- else
- dtData[i] = value;
- }
- if (!ptr->GetProperties().up.Set(dtData, admin, login, store))
- return true;
- }
- dtData = ptr->GetProperties().down.Get();
- if ((it = traff.find("md")) != traff.end())
- {
- std::vector<xmlrpc_c::value> data(xmlrpc_c::value_array(it->second).vectorValueValue());
-
- for (int i = 0; i < std::min(DIR_NUM, static_cast<int>(data.size())); ++i)
- {
- int64_t value;
- if (str2x(xmlrpc_c::value_string(data[i]), value))
- printfd(__FILE__, "USER_HELPER::SetUserInfo(): 'Invalid month download value'\n");
- else
- dtData[i] = value;
- }
- if (!ptr->GetProperties().down.Set(dtData, admin, login, store))
- return true;
- }
- }
-
-if ((it = structVal.find("tariff")) != structVal.end())
- {
- std::string tariff(xmlrpc_c::value_string(it->second));
- size_t pos = tariff.find('/');
- std::string nextTariff;
- if (pos != std::string::npos)
- {
- nextTariff = tariff.substr(pos + 1);
- tariff = tariff.substr(0, pos);
- }
-
- const auto newTariff = tariffs->FindByName(tariff);
- if (newTariff)
- {
- const auto currentTariff = ptr->GetTariff();
- std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime);
- if (message.empty())
- {
- if (ptr->GetProperties().tariffName.Get() != tariff)
- {
- if (!ptr->GetProperties().tariffName.Set(tariff, admin, login, store))
- return true;
- }
- }
- else
- {
- STG::PluginLogger::get("conf_rpc")("Tariff change is prohibited for user %s. %s", ptr->GetLogin().c_str(), message.c_str());
- }
- }
-
- if (nextTariff != "" &&
- tariffs->FindByName(nextTariff))
- if (ptr->GetProperties().nextTariff.Get() != nextTariff)
- if (!ptr->GetProperties().nextTariff.Set(tariff, admin, login, store))
- return true;
- }
-
-return false;
-}
+++ /dev/null
-#pragma once
-
-#include <string>
-
-#include <xmlrpc-c/base.hpp>
-
-namespace STG
-{
-
-struct Admin;
-struct Store;
-struct Tariffs;
-struct User;
-struct Users;
-
-}
-
-class USER_HELPER
-{
-public:
- using UserPtr = STG::User*;
- USER_HELPER(UserPtr & p, STG::Users & us)
- : ptr(p),
- users(us)
- {
- }
-
- void GetUserInfo(xmlrpc_c::value * info,
- bool hidePassword = false);
- bool SetUserInfo(const xmlrpc_c::value & info,
- const STG::Admin& admin,
- const std::string & login,
- const STG::Store & store,
- STG::Tariffs * tariffs);
-private:
- UserPtr & ptr;
- STG::Users & users;
-};
+++ /dev/null
-#include "users_methods.h"
-#include "rpcconfig.h"
-#include "user_helper.h"
-
-#include "stg/users.h"
-#include "stg/admins.h"
-#include "stg/tariffs.h"
-#include "stg/tariff.h"
-#include "stg/user.h"
-#include "stg/user_property.h"
-#include "stg/common.h"
-
-#include <cerrno>
-
-using UserPtr = STG::User*;
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_GET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-USER_HELPER uhelper(u, *users);
-
-if (!adminInfo.priviledges.userConf || !adminInfo.priviledges.userPasswd)
- {
- uhelper.GetUserInfo(retvalPtr, true);
- return;
- }
-
-uhelper.GetUserInfo(retvalPtr);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_ADD::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin = NULL;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- if (users->Add(login, admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
- *retvalPtr = xmlrpc_c::value_boolean(true);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(false);
-return;
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_DEL::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-UserPtr u;
-
-if (!users->FindByName(login, &u))
- {
- users->Del(login, admin);
- *retvalPtr = xmlrpc_c::value_boolean(true);
- return;
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(false);
-return;
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USERS_GET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-paramList.verifyEnd(1);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-std::vector<xmlrpc_c::value> retval;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-bool hidePassword = !adminInfo.priviledges.userConf ||
- !adminInfo.priviledges.userPasswd;
-
-UserPtr u;
-
-int h = users->OpenSearch();
-if (!h)
- {
- printfd(__FILE__, "users->OpenSearch() error\n");
- users->CloseSearch(h);
- return;
- }
-
-while (1)
- {
- if (users->SearchNext(h, &u))
- {
- break;
- }
-
- xmlrpc_c::value info;
-
- USER_HELPER uhelper(u, *users);
-
- uhelper.GetUserInfo(&info, hidePassword);
-
- retval.push_back(info);
- }
-
-*retvalPtr = xmlrpc_c::value_array(retval);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_CHG::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-xmlrpc_c::value_struct info(paramList.getStruct(2));
-paramList.verifyEnd(3);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-USER_HELPER uhelper(u, *users);
-
-if (!adminInfo.priviledges.userConf || !adminInfo.priviledges.userPasswd)
- {
- uhelper.SetUserInfo(info, *admin, login, *store, tariffs);
- }
-else
- {
- uhelper.SetUserInfo(info, *admin, login, *store, tariffs);
- }
-
-u->WriteConf();
-u->WriteStat();
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_CASH_ADD::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-double amount = paramList.getDouble(2);
-std::string comment = IconvString(paramList.getString(3), "UTF-8", "KOI8-R");
-paramList.verifyEnd(4);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-double cash = u->GetProperties().cash.Get();
-cash += amount;
-
-if (!u->GetProperties().cash.Set(cash, *admin, login, *store, comment))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-u->WriteStat();
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_CASH_SET::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-double cash = paramList.getDouble(2);
-std::string comment = IconvString(paramList.getString(3), "UTF-8", "KOI8-R");
-paramList.verifyEnd(4);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (!u->GetProperties().cash.Set(cash, *admin, login, *store, comment))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-u->WriteStat();
-
-*retvalPtr = xmlrpc_c::value_boolean(true);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_USER_TARIFF_CHANGE::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-std::string tariff = paramList.getString(2);
-bool delayed = paramList.getBoolean(3);
-std::string comment = IconvString(paramList.getString(4), "UTF-8", "KOI8-R");
-paramList.verifyEnd(5);
-
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-STG::Admin * admin;
-
-if (admins->find(adminInfo.admin, &admin))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- *retvalPtr = xmlrpc_c::value_boolean(false);
- return;
- }
-
-if (tariffs->FindByName(tariff))
- {
- if (delayed)
- {
- if (u->GetProperties().nextTariff.Set(tariff, *admin, login, *store, comment))
- {
- u->WriteConf();
- *retvalPtr = xmlrpc_c::value_boolean(true);
- return;
- }
- }
- else
- {
- const auto newTariff = tariffs->FindByName(tariff);
- if (newTariff)
- {
- const auto currentTariff = u->GetTariff();
- std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime);
- if (message.empty())
- {
- if (u->GetProperties().tariffName.Set(tariff, *admin, login, *store, comment))
- {
- u->ResetNextTariff();
- u->WriteConf();
- *retvalPtr = xmlrpc_c::value_boolean(true);
- return;
- }
- }
- else
- {
- STG::PluginLogger::get("conf_rpc")("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str());
- }
- }
- }
- }
-
-*retvalPtr = xmlrpc_c::value_boolean(false);
-}
-
-//------------------------------------------------------------------------------
-
-void METHOD_GET_ONLINE_IPS::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-typedef std::vector<xmlrpc_c::value> ValueVector;
-ValueVector subnetsStr = paramList.getArray(1);
-paramList.verifyEnd(2);
-
-std::vector<STG::IPMask> subnets;
-
-for (ValueVector::const_iterator it(subnetsStr.begin()); it != subnetsStr.end(); ++it)
- {
- STG::IPMask ipm;
- if (ParseNet(xmlrpc_c::value_string(*it), ipm))
- {
- printfd(__FILE__, "METHOD_GET_ONLINE_IPS::execute(): Failed to parse subnet ('%s')\n", std::string(xmlrpc_c::value_string(*it)).c_str());
- }
- else
- {
- subnets.push_back(ipm);
- }
- }
-
-std::map<std::string, xmlrpc_c::value> structVal;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-ValueVector ips;
-
-UserPtr u;
-
-int handle = users->OpenSearch();
-if (!handle)
- {
- printfd(__FILE__, "users->OpenSearch() error\n");
- users->CloseSearch(handle);
- return;
- }
-
-while (1)
- {
- if (users->SearchNext(handle, &u))
- {
- break;
- }
-
- if (u->GetAuthorized())
- {
- uint32_t ip = u->GetCurrIP();
-
- for (std::vector<STG::IPMask>::const_iterator it(subnets.begin()); it != subnets.end(); ++it)
- {
- if ((it->ip & it->mask) == (ip & it->mask))
- {
- ips.push_back(xmlrpc_c::value_string(inet_ntostring(u->GetCurrIP())));
- break;
- }
- }
- }
- }
-
-structVal["ips"] = xmlrpc_c::value_array(ips);
-
-*retvalPtr = xmlrpc_c::value_struct(structVal);
-}
-
-bool METHOD_GET_ONLINE_IPS::ParseNet(const std::string & net, STG::IPMask & ipm) const
-{
-size_t pos = net.find_first_of('/');
-
-if (pos == std::string::npos)
- {
- printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Network address is not in CIDR-notation\n");
- return true;
- }
-
-int res = inet_pton(AF_INET, net.substr(0, pos).c_str(), &ipm.ip);
-
-if (res < 0)
- {
- printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): '%s'\n", strerror(errno));
- return true;
- }
-else if (res == 0)
- {
- printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Invalid network address\n", strerror(errno));
- return true;
- }
-
-if (str2x(net.substr(pos + 1, net.length() - pos - 1), ipm.mask))
- {
- printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Invalid network mask\n");
- return true;
- }
-if (ipm.mask > 32)
- {
- printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Network mask is out of range\n");
- return true;
- }
-ipm.mask = htonl(0xffFFffFF << (32 - ipm.mask));
-
-return false;
-}
-
-void METHOD_GET_USER_AUTH_BY::execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalPtr)
-{
-std::string cookie = paramList.getString(0);
-std::string login = paramList.getString(1);
-paramList.verifyEnd(2);
-
-std::map<std::string, xmlrpc_c::value> structVal;
-ADMIN_INFO adminInfo;
-
-if (config->GetAdminInfo(cookie, &adminInfo))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-UserPtr u;
-
-if (users->FindByName(login, &u))
- {
- structVal["result"] = xmlrpc_c::value_boolean(false);
- *retvalPtr = xmlrpc_c::value_struct(structVal);
- return;
- }
-
-std::vector<std::string> list(u->GetAuthorizers());
-std::vector<xmlrpc_c::value> authList;
-for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
- authList.push_back(xmlrpc_c::value_string(*it));
-*retvalPtr = xmlrpc_c::value_array(authList);
-}
+++ /dev/null
-#pragma once
-
-#include <xmlrpc-c/base.hpp>
-#include <xmlrpc-c/registry.hpp>
-
-namespace STG
-{
-
-struct Admins;
-struct Tariffs;
-struct Users;
-struct Store;
-struct IPMask;
-
-}
-
-class RPC_CONFIG;
-
-class METHOD_USER_GET : public xmlrpc_c::method {
-public:
- METHOD_USER_GET(RPC_CONFIG * c,
- STG::Users * u)
- : config(c),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_GET(const METHOD_USER_GET & rvalue);
- METHOD_USER_GET & operator=(const METHOD_USER_GET & rvalue);
-
- RPC_CONFIG * config;
- STG::Users * users;
-};
-
-class METHOD_USER_ADD : public xmlrpc_c::method {
-public:
- METHOD_USER_ADD(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Users * u)
- : config(c),
- admins(a),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_ADD(const METHOD_USER_ADD & rvalue);
- METHOD_USER_ADD & operator=(const METHOD_USER_ADD & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Users * users;
-};
-
-class METHOD_USER_DEL : public xmlrpc_c::method {
-public:
- METHOD_USER_DEL(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Users * u)
- : config(c),
- admins(a),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_DEL(const METHOD_USER_DEL & rvalue);
- METHOD_USER_DEL & operator=(const METHOD_USER_DEL & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Users * users;
-};
-
-class METHOD_USERS_GET : public xmlrpc_c::method {
-public:
- METHOD_USERS_GET(RPC_CONFIG * c,
- STG::Users * u)
- : config(c),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USERS_GET(const METHOD_USERS_GET & rvalue);
- METHOD_USERS_GET & operator=(const METHOD_USERS_GET & rvalue);
-
- RPC_CONFIG * config;
- STG::Users * users;
-};
-
-class METHOD_USER_CHG : public xmlrpc_c::method {
-public:
- METHOD_USER_CHG(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Tariffs * t,
- STG::Store * s,
- STG::Users * u)
- : config(c),
- admins(a),
- tariffs(t),
- store(s),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_CHG(const METHOD_USER_CHG & rvalue);
- METHOD_USER_CHG & operator=(const METHOD_USER_CHG & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Tariffs * tariffs;
- STG::Store * store;
- STG::Users * users;
-};
-
-class METHOD_USER_CASH_ADD : public xmlrpc_c::method {
-public:
- METHOD_USER_CASH_ADD(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Store * s,
- STG::Users * u)
- : config(c),
- admins(a),
- store(s),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_CASH_ADD(const METHOD_USER_CASH_ADD & rvalue);
- METHOD_USER_CASH_ADD & operator=(const METHOD_USER_CASH_ADD & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Store * store;
- STG::Users * users;
-};
-
-class METHOD_USER_CASH_SET : public xmlrpc_c::method {
-public:
- METHOD_USER_CASH_SET(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Store * s,
- STG::Users * u)
- : config(c),
- admins(a),
- store(s),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_CASH_SET(const METHOD_USER_CASH_SET & rvalue);
- METHOD_USER_CASH_SET & operator=(const METHOD_USER_CASH_SET & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Store * store;
- STG::Users * users;
-};
-
-class METHOD_USER_TARIFF_CHANGE : public xmlrpc_c::method {
-public:
- METHOD_USER_TARIFF_CHANGE(RPC_CONFIG * c,
- STG::Admins * a,
- STG::Tariffs * t,
- STG::Store * s,
- STG::Users * u)
- : config(c),
- admins(a),
- tariffs(t),
- store(s),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_USER_TARIFF_CHANGE(const METHOD_USER_TARIFF_CHANGE & rvalue);
- METHOD_USER_TARIFF_CHANGE & operator=(const METHOD_USER_TARIFF_CHANGE & rvalue);
-
- RPC_CONFIG * config;
- STG::Admins * admins;
- STG::Tariffs * tariffs;
- STG::Store * store;
- STG::Users * users;
-};
-
-class METHOD_GET_ONLINE_IPS : public xmlrpc_c::method {
-public:
- METHOD_GET_ONLINE_IPS(RPC_CONFIG * c,
- STG::Users * u)
- : config(c),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_GET_ONLINE_IPS(const METHOD_GET_ONLINE_IPS & rvalue);
- METHOD_GET_ONLINE_IPS & operator=(const METHOD_GET_ONLINE_IPS & rvalue);
-
- RPC_CONFIG * config;
- STG::Users * users;
-
- bool ParseNet(const std::string & net, STG::IPMask & ipm) const;
-};
-
-class METHOD_GET_USER_AUTH_BY : public xmlrpc_c::method {
-public:
- METHOD_GET_USER_AUTH_BY(RPC_CONFIG * c,
- STG::Users * u)
- : config(c),
- users(u)
- {
- }
-
- void execute(xmlrpc_c::paramList const & paramList,
- xmlrpc_c::value * const retvalP);
-
-private:
- METHOD_GET_USER_AUTH_BY(const METHOD_GET_ONLINE_IPS & rvalue);
- METHOD_GET_USER_AUTH_BY & operator=(const METHOD_GET_ONLINE_IPS & rvalue);
-
- RPC_CONFIG * config;
- STG::Users * users;
-};
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "configproto.h"
-
-#include "conn.h"
-
-#include "parser_server_info.h"
-#include "parser_admins.h"
-#include "parser_tariffs.h"
-#include "parser_users.h"
-#include "parser_services.h"
-#include "parser_message.h"
-#include "parser_user_info.h"
-#include "parser_auth_by.h"
-
-#include "stg/common.h"
-#include "stg/logger.h"
-
-#include <algorithm>
-#include <functional>
-#include <vector>
-#include <csignal>
-#include <cstring>
-#include <cerrno>
-#include <cassert>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-namespace SP = STG::PARSER;
-
-CONFIGPROTO::CONFIGPROTO(STG::PluginLogger & l)
- : m_settings(NULL),
- m_admins(NULL),
- m_tariffs(NULL),
- m_users(NULL),
- m_services(NULL),
- m_corporations(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::~CONFIGPROTO()
-{
- {
- std::deque<STG::Conn *>::iterator it;
- for (it = m_conns.begin(); it != m_conns.end(); ++it)
- delete *it;
- }
- {
- BASE_PARSER::REGISTRY::iterator it;
- for (it = m_registry.begin(); it != m_registry.end(); ++it)
- delete it->second;
- }
-}
-
-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)
- {
- m_errorStr = std::string("Cannot create listen socket: '") + strerror(errno) + "'.";
- m_logger(m_errorStr);
- return -1;
- }
-
- int dummy = 1;
-
- if (setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &dummy, 4) != 0)
- {
- 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;
-}
-
-int CONFIGPROTO::Stop()
-{
- m_running = false;
- for (int i = 0; i < 5 && !m_stopped; ++i)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
- if (!m_stopped)
- {
- m_errorStr = "Cannot stop listenign thread.";
- m_logger(m_errorStr);
- return -1;
- }
-
- shutdown(m_listenSocket, SHUT_RDWR);
- close(m_listenSocket);
- return 0;
-}
-
-void CONFIGPROTO::Run()
-{
- 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_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;
-}
-
-bool CONFIGPROTO::Bind()
-{
- const hostent * he = gethostbyname(m_bindAddress.c_str());
- if (he == NULL)
- {
- 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<in_addr_t *>(*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<sockaddr *>(&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;
-}
-
-void CONFIGPROTO::RegisterParsers()
-{
- assert(m_settings != NULL);
- assert(m_store != NULL);
- assert(m_admins != NULL);
- assert(m_users != NULL);
- assert(m_tariffs != NULL);
- assert(m_services != NULL);
- assert(m_corporations != NULL);
-
- SP::GET_SERVER_INFO::FACTORY::Register(m_registry, *m_settings, *m_users, *m_tariffs);
-
- 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);
-
- 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);
-
- 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);
-
- SP::GET_SERVICES::FACTORY::Register(m_registry, *m_services);
- SP::GET_SERVICE::FACTORY::Register(m_registry, *m_services);
- SP::ADD_SERVICE::FACTORY::Register(m_registry, *m_services);
- SP::DEL_SERVICE::FACTORY::Register(m_registry, *m_services);
- SP::CHG_SERVICE::FACTORY::Register(m_registry, *m_services);
-
- SP::SEND_MESSAGE::FACTORY::Register(m_registry, *m_users);
-
- SP::AUTH_BY::FACTORY::Register(m_registry, *m_users);
-
- SP::USER_INFO::FACTORY::Register(m_registry, *m_users);
-}
-
-int CONFIGPROTO::MaxFD() const
-{
- 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;
-}
-
-void CONFIGPROTO::BuildFDSet(fd_set & fds) const
-{
- 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);
-}
-
-void CONFIGPROTO::CleanupConns()
-{
- 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());
-}
-
-void CONFIGPROTO::HandleEvents(const fd_set & fds)
-{
- 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();
- }
-}
-
-void CONFIGPROTO::AcceptConnection()
-{
- struct sockaddr_in outerAddr;
- socklen_t outerAddrLen(sizeof(outerAddr));
- int sock = accept(m_listenSocket, reinterpret_cast<sockaddr *>(&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() + "'.");
- }
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/module_settings.h"
-
-#include <string>
-#include <deque>
-#include <cstdint>
-
-#include <sys/select.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-namespace STG
-{
-
-struct Settings;
-struct Admins;
-struct Tariffs;
-struct Users;
-struct Services;
-struct Corporations;
-struct Store;
-class PluginLogger;
-
-class Conn;
-
-}
-
-class CONFIGPROTO {
-public:
- explicit CONFIGPROTO(STG::PluginLogger & l);
- ~CONFIGPROTO();
-
- void SetPort(uint16_t port) { m_port = port; }
- void SetBindAddress(const std::string & address) { m_bindAddress = address; }
- void SetSettings(const STG::Settings * settings) { m_settings = settings; }
- void SetAdmins(STG::Admins * admins) { m_admins = admins; }
- void SetTariffs(STG::Tariffs * tariffs) { m_tariffs = tariffs; }
- void SetUsers(STG::Users * users) { m_users = users; }
- void SetStore(STG::Store * store) { m_store = store; }
- void SetServices(STG::Services * services) { m_services = services; }
- void SetCorporations(STG::Corporations * corporations) { m_corporations = corporations; }
-
- int Prepare();
- int Stop();
- const std::string & GetStrError() const { return m_errorStr; }
- void Run();
-
-private:
- CONFIGPROTO(const CONFIGPROTO & rvalue);
- CONFIGPROTO & operator=(const CONFIGPROTO & rvalue);
-
- const STG::Settings * m_settings;
- STG::Admins * m_admins;
- STG::Tariffs * m_tariffs;
- STG::Users * m_users;
- STG::Services * m_services;
- STG::Corporations * m_corporations;
- STG::Store * m_store;
-
- uint16_t m_port;
- std::string m_bindAddress;
- bool m_running;
- bool m_stopped;
- STG::PluginLogger & m_logger;
- int m_listenSocket;
-
- std::string m_errorStr;
-
- BASE_PARSER::REGISTRY m_registry;
- std::deque<STG::Conn *> m_conns;
-
- bool Bind();
-
- void RegisterParsers();
-
- int MaxFD() const;
- void BuildFDSet(fd_set & fds) const;
- void CleanupConns();
- void HandleEvents(const fd_set & fds);
- void AcceptConnection();
-};
+++ /dev/null
-/*
- * 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 "conn.h"
-
-#include "stg/admins.h"
-#include "stg/admin.h"
-#include "stg/logger.h"
-#include "stg/blowfish.h"
-#include "stg/bfstream.h"
-#include "stg/common.h"
-
-#include <cassert>
-#include <cstring>
-#include <cerrno>
-
-#include <unistd.h>
-#include <sys/socket.h>
-
-using STG::Conn;
-
-const char Conn::STG_HEADER[] = "SG04";
-const char Conn::OK_HEADER[] = "OKHD";
-const char Conn::ERR_HEADER[] = "ERHD";
-const char Conn::OK_LOGIN[] = "OKLG";
-const char Conn::ERR_LOGIN[] = "ERLG";
-const char Conn::OK_LOGINS[] = "OKLS";
-const char Conn::ERR_LOGINS[] = "ERLS";
-
-Conn::Conn(const BASE_PARSER::REGISTRY & registry,
- Admins & admins, int sock, const sockaddr_in& addr,
- PluginLogger & logger)
- : m_registry(registry),
- m_admins(admins),
- m_admin(NULL),
- m_sock(sock),
- m_addr(addr),
- m_keepAlive(false),
- m_parser(NULL),
- m_xmlParser(XML_ParserCreate(NULL)),
- m_state(HEADER),
- m_buffer(m_header),
- m_bufferSize(sizeof(m_header)),
- m_stream(NULL),
- m_logger(logger),
-#ifdef DUMPCRYPTO
- m_dataState(false, *this),
- m_dumper(endpoint())
-#else
- m_dataState(false, *this)
-#endif
-{
- if (m_xmlParser == NULL)
- throw Error("Failed to create XML parser.");
-
- XML_ParserReset(m_xmlParser, NULL);
- XML_SetElementHandler(m_xmlParser, ParseXMLStart, ParseXMLEnd);
- XML_SetUserData(m_xmlParser, this);
-}
-
-Conn::~Conn()
-{
- shutdown(m_sock, SHUT_RDWR);
- close(m_sock);
-
- XML_ParserFree(m_xmlParser);
-
- delete m_stream;
- delete m_parser;
-}
-
-bool Conn::Read()
-{
- ssize_t res = read(m_sock, m_buffer, m_bufferSize);
- if (res < 0)
- {
- m_state = ERROR;
- Log(__FILE__, "Failed to read data from " + endpoint() + ". Reason: '" + strerror(errno) + "'");
- return false;
- }
- if (res == 0 && m_state != DATA) // EOF is ok for data.
- {
- m_state = ERROR;
- Log(__FILE__, "Failed to read data from " + endpoint() + ". Unexpected EOF.");
- return false;
- }
-#ifdef DUMPCRYPTO
- m_dumper.write(m_buffer, res);
-#endif
- m_bufferSize -= res;
- m_buffer = static_cast<char*>(m_buffer) + res;
- return HandleBuffer(res);
-}
-
-bool Conn::WriteAnswer(const void* buffer, size_t size)
-{
- ssize_t res = write(m_sock, buffer, size);
- if (res < 0)
- {
- m_state = ERROR;
- Log(__FILE__, "Failed to write data to " + endpoint() + ". Reason: '" + strerror(errno) + "'.");
- return false;
- }
- return true;
-}
-
-BASE_PARSER * Conn::GetParser(const std::string & tag) const
-{
- BASE_PARSER::REGISTRY::const_iterator it = m_registry.find(ToLower(tag));
- if (it == m_registry.end())
- return NULL;
- return it->second->create(*m_admin);
-}
-
-bool Conn::HandleBuffer(size_t size)
-{
- if (m_state == DATA)
- return HandleData(size);
-
- if (m_bufferSize > 0)
- return true;
-
- switch (m_state)
- {
- case HEADER: return HandleHeader();
- case LOGIN: return HandleLogin();
- case CRYPTO_LOGIN: return HandleCryptoLogin();
- default: return true;
- }
-
- return true;
-}
-
-bool Conn::HandleHeader()
-{
- if (strncmp(m_header, STG_HEADER, sizeof(m_header)) != 0)
- {
- Log(__FILE__, "Received invalid header from " + endpoint() + ".");
- WriteAnswer(ERR_HEADER, sizeof(ERR_HEADER) - 1); // Without \0
- m_state = ERROR;
- return false;
- }
- m_state = LOGIN;
- m_buffer = m_login;
- m_bufferSize = sizeof(m_login);
- return WriteAnswer(OK_HEADER, sizeof(OK_HEADER) - 1); // Without \0
-}
-
-bool Conn::HandleLogin()
-{
- if (m_admins.find(m_login, &m_admin)) // ADMINS::Find returns true on error.
- {
- std::string login(m_login, strnlen(m_login, sizeof(m_login)));
- Log(__FILE__, "Received invalid login '" + ToPrintable(login) + "' from " + endpoint() + ".");
- WriteAnswer(ERR_LOGIN, sizeof(ERR_LOGIN) - 1); // Without \0
- m_state = ERROR;
- return false;
- }
- m_admin->setIP(IP());
- m_state = CRYPTO_LOGIN;
- m_buffer = m_cryptoLogin;
- m_bufferSize = sizeof(m_cryptoLogin);
- return WriteAnswer(OK_LOGIN, sizeof(OK_LOGIN) - 1); // Without \0
-}
-
-bool Conn::HandleCryptoLogin()
-{
- char login[ADM_LOGIN_LEN + 1];
- BLOWFISH_CTX ctx;
- InitContext(m_admin->password().c_str(), ADM_PASSWD_LEN, &ctx);
- DecryptString(login, m_cryptoLogin, ADM_LOGIN_LEN, &ctx);
-
- if (strncmp(m_login, login, sizeof(login)) != 0)
- {
- Log(__FILE__, "Attempt to connect with wrong password from " + m_admin->login() + "@" + endpoint() + ".");
- WriteAnswer(ERR_LOGINS, sizeof(ERR_LOGINS) - 1); // Without \0
- m_state = ERROR;
- return false;
- }
-
- m_state = DATA;
- m_buffer = m_data;
- m_bufferSize = sizeof(m_data);
- m_stream = new STG::DECRYPT_STREAM(m_admin->password(), DataCallback, &m_dataState);
- return WriteAnswer(OK_LOGINS, sizeof(OK_LOGINS) - 1); // Without \0
-}
-
-bool Conn::HandleData(size_t size)
-{
- m_stream->Put(m_data, size, size == 0 || memchr(m_data, 0, size) != NULL);
- m_buffer = m_data;
- return m_stream->IsOk();
-}
-
-bool Conn::DataCallback(const void * block, size_t size, void * data)
-{
- assert(data != NULL);
- DataState& state = *static_cast<DataState *>(data);
-
- const char * xml = static_cast<const char *>(block);
- size_t length = strnlen(xml, size);
-
- state.final = state.final || length < size || size == 0;
-
- if (XML_Parse(state.conn.m_xmlParser, xml, length, state.final) == XML_STATUS_ERROR)
- {
- state.conn.Log(__FILE__, "Received invalid XML from " + state.conn.m_admin->login() + "@" + state.conn.endpoint() + ".");
- printfd(__FILE__, "XML parse error at line %d, %d: %s. Is final: %d\n",
- static_cast<int>(XML_GetCurrentLineNumber(state.conn.m_xmlParser)),
- static_cast<int>(XML_GetCurrentColumnNumber(state.conn.m_xmlParser)),
- XML_ErrorString(XML_GetErrorCode(state.conn.m_xmlParser)), (int)state.final);
- printfd(__FILE__, "Data block: '%s' of size %d\n", xml, length);
- state.conn.m_state = ERROR;
- return false;
- }
-
- if (state.final)
- {
- if (!state.conn.WriteResponse())
- {
- state.conn.Log(__FILE__, "Failed to write response to " + state.conn.m_admin->login() + "@" + state.conn.endpoint() + ".");
- state.conn.m_state = ERROR;
- return false;
- }
- state.conn.m_state = DONE;
- }
-
- return true;
-}
-
-void Conn::ParseXMLStart(void * data, const char * el, const char ** attr)
-{
- assert(data != NULL);
- Conn & conn = *static_cast<Conn *>(data);
-
- if (conn.m_parser == NULL)
- conn.m_parser = conn.GetParser(el);
-
- if (conn.m_parser == NULL)
- {
- conn.Log(__FILE__, "Received unknown command '" + std::string(el) + "' from " + conn.m_admin->login() + "@" + conn.endpoint() + ".");
- conn.m_state = ERROR;
- return;
- }
-
- conn.m_parser->Start(data, el, attr);
-}
-
-void Conn::ParseXMLEnd(void * data, const char * el)
-{
- assert(data != NULL);
- Conn & conn = *static_cast<Conn *>(data);
-
- if (conn.m_parser == NULL)
- {
- // No need to log it.
- conn.m_state = ERROR;
- return;
- }
-
- conn.m_parser->End(data, el);
-}
-
-bool Conn::WriteResponse()
-{
- STG::ENCRYPT_STREAM stream(m_admin->password(), WriteCallback, this);
- std::string answer;
- if (m_parser != NULL)
- answer = m_parser->GetAnswer();
- else
- answer = "<Error result=\"Unknown command.\"/>";
- delete m_parser;
- m_parser = NULL;
- printfd(__FILE__, "Writing %d bytes of answer.\n", answer.length());
- stream.Put(answer.c_str(), answer.length() + 1 /* including \0 */, true /* final */);
- return stream.IsOk();
-}
-
-bool Conn::WriteCallback(const void * block, size_t size, void * data)
-{
- assert(data != NULL);
- Conn & conn = *static_cast<Conn *>(data);
- return WriteAll(conn.m_sock, block, size);;
-}
-
-void Conn::Log(const char * file, const std::string & message)
-{
- printfd(file, "%s\n", message.c_str());
- m_logger(message);
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "dumphelpers.h"
-
-#include "stg/const.h"
-
-#include <stdexcept>
-#include <string>
-#include <cstdint>
-
-#include <expat.h>
-
-#include <netinet/in.h>
-
-namespace STG
-{
-
-struct Settings;
-struct Admins;
-struct Users;
-struct Tariffs;
-struct Admin;
-class PluginLogger;
-
-class DECRYPT_STREAM;
-
-class Conn
-{
- public:
- struct Error : public std::runtime_error
- {
- explicit Error(const std::string& message) : runtime_error(message.c_str()) {}
- };
-
- Conn(const BASE_PARSER::REGISTRY & registry,
- Admins & admins, int sock, const sockaddr_in& addr,
- PluginLogger & logger);
- ~Conn();
-
- int Sock() const { return m_sock; }
- uint32_t IP() const { return *(uint32_t *)(&m_addr.sin_addr); }
- uint16_t Port() const { return ntohs(m_addr.sin_port); }
-
- std::string endpoint() const { return inet_ntostring(IP()) + ":" + std::to_string(Port()); }
-
- bool Read();
-
- bool IsOk() const { return m_state != ERROR; }
- bool IsDone() const { return m_state == DONE; }
- bool IsKeepAlive() const { return m_keepAlive; }
-
- void SetKeepAlive() { m_keepAlive = true; }
-
- private:
-
- static const char STG_HEADER[5];
- static const char OK_HEADER[5];
- static const char ERR_HEADER[5];
- static const char OK_LOGIN[5];
- static const char ERR_LOGIN[5];
- static const char OK_LOGINS[5];
- static const char ERR_LOGINS[5];
-
- const BASE_PARSER::REGISTRY & m_registry;
-
- Admins & m_admins;
-
- Admin * m_admin;
-
- int m_sock;
- sockaddr_in m_addr;
- bool m_keepAlive;
-
- BASE_PARSER * m_parser;
-
- XML_Parser m_xmlParser;
-
- enum { HEADER, LOGIN, CRYPTO_LOGIN, DATA, DONE, ERROR } m_state;
-
- void * m_buffer;
- size_t m_bufferSize;
- char m_header[sizeof(STG_HEADER) - 1]; // Without \0
- char m_login[ADM_LOGIN_LEN]; // Without \0
- char m_cryptoLogin[ADM_LOGIN_LEN]; // Without \0
- char m_data[1024];
- STG::DECRYPT_STREAM * m_stream;
- PluginLogger & m_logger;
-
- BASE_PARSER * GetParser(const std::string & tag) const;
-
- bool HandleBuffer(size_t size);
-
- bool HandleHeader();
- bool HandleLogin();
- bool HandleCryptoLogin();
- bool HandleData(size_t size);
-
- bool WriteAnswer(const void* buffer, size_t size);
- bool WriteResponse();
-
- void Log(const char * file, const std::string & message);
-
- struct DataState
- {
- DataState(bool f, Conn & c) : final(f), conn(c) {}
- bool final;
- Conn & conn;
- } m_dataState;
-
-#ifdef DUMPCRYPTO
- Dumper m_dumper;
-#endif
-
- static bool DataCallback(const void * block, size_t size, void * data);
- static void ParseXMLStart(void * data, const char * el, const char ** attr);
- static void ParseXMLEnd(void * data, const char * el);
- static bool WriteCallback(const void * block, size_t size, void * data);
-};
-
-}
+++ /dev/null
-#ifndef __STG_DUMP_HELPERS_H__
-#define __STG_DUMP_HELPERS_H__
-
-#include "stg/common.h"
-
-#include <string>
-#include <fstream>
-#include <sstream>
-#include <iomanip>
-
-#include <cstddef>
-#include <ctime>
-
-namespace STG
-{
-
-class Dumper
-{
- public:
- explicit Dumper(const std::string& tag)
- : m_stream(getName(tag).c_str())
- {
- }
- ~Dumper() {}
-
- void write(const void* data, size_t size)
- {
- writePrefix();
- m_stream << " ";
- writeHEX(data, size);
- }
-
- private:
- std::ofstream m_stream;
-
- tm getTime() const
- {
- time_t now = time(NULL);
- tm localTime;
- localtime_r(&now, &localTime);
- return localTime;
- }
-
- std::string getName(const std::string& tag) const
- {
- tm localTime = getTime();
-
- std::ostringstream res;
- res << tag
- << "-" << (localTime.tm_year + 1900) << twoDigit(localTime.tm_mon + 1) << twoDigit(localTime.tm_mday)
- << "-" << twoDigit(localTime.tm_hour) << twoDigit(localTime.tm_min) << twoDigit(localTime.tm_sec)
- << ".data";
-
- return res.str();
- }
-
- void writePrefix()
- {
- tm localTime = getTime();
- m_stream << "[" << (localTime.tm_year + 1900) << "-" << twoDigit(localTime.tm_mon + 1) << "-" << twoDigit(localTime.tm_mday)
- << " " << twoDigit(localTime.tm_hour) << ":" << twoDigit(localTime.tm_min) << ":" << twoDigit(localTime.tm_sec)
- << "]";
- }
-
- void writeHEX(const void* data, size_t size)
- {
- m_stream << "(" << std::setw(4) << std::setfill(' ') << size << ") ";
- const unsigned char* pos = static_cast<const unsigned char*>(data);
- for (size_t i = 0; i < size; ++i)
- m_stream << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*pos++);
- m_stream << std::dec << "\n";
- }
-
- std::string twoDigit(int value) const
- {
- std::string res = std::to_string(value);
- if (res.length() < 2)
- res = "0" + res;
- return res;
- }
-};
-
-} // namespace STG
-
-#endif
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include "parser.h"
-
-#include <cstring>
-
-//-----------------------------------------------------------------------------
-// BASE PARSER
-//-----------------------------------------------------------------------------
-int BASE_PARSER::Start(void *, const char * el, const char **)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- return 0;
-
- return -1;
-}
-//-----------------------------------------------------------------------------
-int BASE_PARSER::End(void *, const char * el)
-{
- if (m_depth < 2)
- {
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
- CreateAnswer();
- }
-
- --m_depth;
- return 0;
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include <string>
-#include <map>
-
-namespace STG
-{
-struct Admin;
-}
-
-class BASE_PARSER
-{
- public:
- struct FACTORY
- {
- virtual ~FACTORY() {}
- virtual BASE_PARSER * create(const STG::Admin & admin) = 0;
- };
- typedef std::map<std::string, FACTORY *> REGISTRY;
-
- BASE_PARSER(const STG::Admin & admin, const std::string & t)
- : m_currAdmin(admin),
- m_depth(0),
- m_tag(t)
- {}
- virtual ~BASE_PARSER() {}
- virtual int Start(void * data, const char * el, const char ** attr);
- virtual int End(void * data, const char * el);
-
- const std::string & GetAnswer() const { return m_answer; }
- const std::string & GetTag() const { return m_tag; }
- std::string GetOpenTag() const { return "<" + m_tag + ">"; }
- std::string GetCloseTag() const { return "</" + m_tag + ">"; }
-
- protected:
- BASE_PARSER(const BASE_PARSER & rvalue);
- BASE_PARSER & operator=(const BASE_PARSER & rvalue);
-
- const STG::Admin & m_currAdmin;
- size_t m_depth;
- std::string m_answer;
- std::string m_tag;
-
- private:
- virtual void CreateAnswer() = 0;
-};
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "parser_admins.h"
-
-#include "stg/admins.h"
-#include "stg/admin.h"
-#include "stg/admin_conf.h"
-
-#include <strings.h> // strcasecmp
-
-using STG::PARSER::GET_ADMINS;
-using STG::PARSER::ADD_ADMIN;
-using STG::PARSER::DEL_ADMIN;
-using STG::PARSER::CHG_ADMIN;
-
-const char * GET_ADMINS::tag = "GetAdmins";
-const char * ADD_ADMIN::tag = "AddAdmin";
-const char * DEL_ADMIN::tag = "DelAdmin";
-const char * CHG_ADMIN::tag = "ChgAdmin";
-
-void GET_ADMINS::CreateAnswer()
-{
- const auto& priv = m_currAdmin.priv();
- if (!priv.adminChg)
- {
- m_answer = "<Error Result=\"Error. Access denied.\"/>";
- return;
- }
-
- m_answer = "<Admins>";
- m_admins.fmap([this](const Admin& admin)
- {
- const unsigned int p = (admin.priv().userStat << 0) +
- (admin.priv().userConf << 2) +
- (admin.priv().userCash << 4) +
- (admin.priv().userPasswd << 6) +
- (admin.priv().userAddDel << 8) +
- (admin.priv().adminChg << 10) +
- (admin.priv().tariffChg << 12);
- m_answer += "<admin login=\"" + admin.login() + "\" priv=\"" + std::to_string(p) + "\"/>";
- });
- m_answer += "</Admins>";
-}
-
-int DEL_ADMIN::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- m_admin = attr[1];
- return 0;
- }
- return -1;
-}
-
-void DEL_ADMIN::CreateAnswer()
-{
- if (m_admins.del(m_admin, m_currAdmin) == 0)
- m_answer = "<" + m_tag + " Result=\"Ok\"/>";
- else
- m_answer = "<" + m_tag + " Result=\"Error. " + m_admins.strError() + "\"/>";
-}
-
-int ADD_ADMIN::Start(void *, const char *el, const char **attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- m_admin = attr[1];
- return 0;
- }
- return -1;
-}
-
-void ADD_ADMIN::CreateAnswer()
-{
- if (m_admins.add(m_admin, m_currAdmin) == 0)
- m_answer = "<" + m_tag + " Result=\"Ok\"/>";
- else
- m_answer = "<" + m_tag + " Result=\"Error. " + m_admins.strError() + "\"/>";
-}
-
-int CHG_ADMIN::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- for (size_t i = 0; i < 6; i += 2)
- {
- printfd(__FILE__, "PARSER_CHG_ADMIN::attr[%d] = %s\n", i, attr[i]);
- if (attr[i] == NULL)
- break;
-
- if (strcasecmp(attr[i], "Login") == 0)
- {
- login = attr[i + 1];
- continue;
- }
-
- if (strcasecmp(attr[i], "Priv") == 0)
- {
- privAsString = attr[i + 1];
- continue;
- }
-
- if (strcasecmp(attr[i], "Password") == 0)
- {
- password = attr[i + 1];
- continue;
- }
- }
-
- return 0;
- }
- return -1;
-}
-
-void CHG_ADMIN::CreateAnswer()
-{
- if (!login.empty())
- {
- Admin * origAdmin = NULL;
-
- if (m_admins.find(login, &origAdmin))
- {
- m_answer = "<" + m_tag + " Result = \"Admin '" + login + "' is not found.\"/>";
- return;
- }
-
- AdminConf conf(origAdmin->conf());
-
- if (!password.empty())
- conf.password = password.data();
-
- if (!privAsString.empty())
- {
- int p = 0;
- if (str2x(privAsString.data().c_str(), p) < 0)
- {
- m_answer = "<" + m_tag + " Result = \"Incorrect parameter Priv.\"/>";
- return;
- }
-
- conf.priv = Priv(p);
- }
-
- if (m_admins.change(conf, m_currAdmin) != 0)
- m_answer = "<" + m_tag + " Result = \"" + m_admins.strError() + "\"/>";
- else
- m_answer = "<" + m_tag + " Result = \"Ok\"/>";
- }
- else
- m_answer = "<" + m_tag + " Result = \"Incorrect parameter login.\"/>";
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/common.h"
-#include "stg/optional.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Admins;
-struct Admin;
-
-namespace PARSER
-{
-
-class GET_ADMINS: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(const Admins & admins) : m_admins(admins) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_ADMINS(admin, m_admins); }
- static void Register(REGISTRY & registry, const Admins & admins)
- { registry[ToLower(tag)] = new FACTORY(admins); }
- private:
- const Admins & m_admins;
- };
-
- static const char * tag;
-
- GET_ADMINS(const Admin & admin, const Admins & admins)
- : BASE_PARSER(admin, tag), m_admins(admins) {}
-
- private:
- const Admins & m_admins;
-
- void CreateAnswer();
-};
-
-class ADD_ADMIN: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Admins & admins) : m_admins(admins) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new ADD_ADMIN(admin, m_admins); }
- static void Register(REGISTRY & registry, Admins & admins)
- { registry[ToLower(tag)] = new FACTORY(admins); }
- private:
- Admins & m_admins;
- };
-
- static const char * tag;
-
- ADD_ADMIN(const Admin & admin, Admins & admins)
- : BASE_PARSER(admin, tag), m_admins(admins) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string m_admin;
- Admins & m_admins;
-
- void CreateAnswer();
-};
-
-class DEL_ADMIN: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Admins & admins) : m_admins(admins) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new DEL_ADMIN(admin, m_admins); }
- static void Register(REGISTRY & registry, Admins & admins)
- { registry[ToLower(tag)] = new FACTORY(admins); }
- private:
- Admins & m_admins;
- };
-
- static const char * tag;
-
- DEL_ADMIN(const Admin & admin, Admins & admins)
- : BASE_PARSER(admin, tag), m_admins(admins) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string m_admin;
- Admins & m_admins;
-
- void CreateAnswer();
-};
-
-class CHG_ADMIN: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Admins & admins) : m_admins(admins) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new CHG_ADMIN(admin, m_admins); }
- static void Register(REGISTRY & registry, Admins & admins)
- { registry[ToLower(tag)] = new FACTORY(admins); }
- private:
- Admins & m_admins;
- };
-
- static const char * tag;
-
- CHG_ADMIN(const Admin & admin, Admins & admins)
- : BASE_PARSER(admin, tag), m_admins(admins) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string login;
- Optional<std::string> password;
- Optional<std::string> privAsString;
- Admins & m_admins;
-
- void CreateAnswer();
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 "parser_auth_by.h"
-
-#include "stg/users.h"
-#include "stg/user.h"
-
-#include <cstring>
-
-using STG::PARSER::AUTH_BY;
-
-const char * AUTH_BY::tag = "GetUserAuthBy";
-
-int AUTH_BY::Start(void * /*data*/, const char *el, const char **attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- if (!attr[1])
- return -1;
-
- m_login = attr[1];
- return 0;
-}
-
-void AUTH_BY::CreateAnswer()
-{
- using ConstUserPtr = const User*;
- ConstUserPtr u;
- if (m_users.FindByName(m_login, &u))
- {
- m_answer = "<AuthorizedBy result=\"error\" reason=\"User not found.\"/>";
- return;
- }
-
- m_answer = "<AuthorizedBy result=\"ok\">";
- std::vector<std::string> list(u->GetAuthorizers());
- for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
- m_answer += "<Auth name=\"" + *it + "\"/>";
- m_answer += "</AuthorizedBy>";
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/common.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Admin;
-struct Users;
-
-namespace PARSER
-{
-
-class AUTH_BY : public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(const Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new AUTH_BY(admin, m_users); }
- static void Register(REGISTRY & registry, const Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- const Users & m_users;
- };
-
- static const char * tag;
-
- AUTH_BY(const Admin & admin, const Users & users)
- : BASE_PARSER(admin, tag), m_users(users) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- const Users & m_users;
- std::string m_login;
-
- void CreateAnswer();
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "parser_message.h"
-
-#include "stg/users.h"
-#include "stg/user.h"
-
-#include <cstring>
-
-extern volatile time_t stgTime; // So sad...
-
-using STG::PARSER::SEND_MESSAGE;
-
-const char * SEND_MESSAGE::tag = "Message";
-
-int SEND_MESSAGE::Start(void *, const char *el, const char **attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- for (size_t i = 0; i < 14; i++)
- if (attr[i] == NULL)
- {
- m_result = res_params_error;
- CreateAnswer();
- printfd(__FILE__, "To few parameters\n");
- return 0;
- }
-
- for (size_t i = 0; i < 14; i += 2)
- {
- if (strcasecmp(attr[i], "login") == 0)
- ParseLogins(attr[i + 1]);
-
- if (strcasecmp(attr[i], "MsgVer") == 0)
- {
- str2x(attr[i + 1], m_msg.header.ver);
- if (m_msg.header.ver != 1)
- m_result = res_params_error;
- }
-
- if (strcasecmp(attr[i], "MsgType") == 0)
- {
- str2x(attr[i + 1], m_msg.header.type);
- if (m_msg.header.type != 1)
- m_result = res_params_error;
- }
-
- if (strcasecmp(attr[i], "Repeat") == 0)
- {
- str2x(attr[i + 1], m_msg.header.repeat);
- if (m_msg.header.repeat < 0)
- m_result = res_params_error;
- }
-
- if (strcasecmp(attr[i], "RepeatPeriod") == 0)
- str2x(attr[i + 1], m_msg.header.repeatPeriod);
-
- if (strcasecmp(attr[i], "ShowTime") == 0)
- str2x(attr[i + 1], m_msg.header.showTime);
-
- if (strcasecmp(attr[i], "Text") == 0)
- {
- Decode21str(m_msg.text, attr[i + 1]);
- m_result = res_ok;
- }
- }
- return 0;
-}
-
-int SEND_MESSAGE::End(void *, const char *el)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- m_result = res_unknown;
- for (unsigned i = 0; i < m_logins.size(); i++)
- {
- if (m_users.FindByName(m_logins[i], &m_user))
- {
- printfd(__FILE__, "User not found. %s\n", m_logins[i].c_str());
- continue;
- }
- m_msg.header.creationTime = static_cast<unsigned int>(stgTime);
- m_user->AddMessage(&m_msg);
- m_result = res_ok;
- }
- CreateAnswer();
- return 0;
-}
-
-int SEND_MESSAGE::ParseLogins(const char * login)
-{
- char * p;
- char * l = new char[strlen(login) + 1];
- strcpy(l, login);
- p = strtok(l, ":");
- m_logins.clear();
- while (p)
- {
- m_logins.push_back(p);
- p = strtok(NULL, ":");
- }
-
- delete[] l;
- return 0;
-}
-
-void SEND_MESSAGE::CreateAnswer()
-{
- switch (m_result)
- {
- case res_ok:
- m_answer = "<SendMessageResult value=\"ok\"/>";
- break;
- case res_params_error:
- m_answer = "<SendMessageResult value=\"Parameters error.\"/>";
- break;
- case res_unknown:
- m_answer = "<SendMessageResult value=\"Unknown user.\"/>";
- break;
- }
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/message.h"
-#include "stg/common.h"
-
-#include <vector>
-#include <string>
-
-namespace STG
-{
-
-struct Users;
-struct User;
-
-namespace PARSER
-{
-
-class SEND_MESSAGE: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new SEND_MESSAGE(admin, m_users); }
- static void Register(REGISTRY & registry, Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- Users & m_users;
- };
-
- static const char * tag;
-
- SEND_MESSAGE(const Admin & admin, Users & users)
- : BASE_PARSER(admin, tag), m_users(users), m_result(res_ok), m_user(NULL) {}
- int Start(void *data, const char *el, const char **attr);
- int End(void *data, const char *el);
-
- private:
- Users & m_users;
- std::vector<std::string> m_logins;
- enum { res_ok, res_params_error, res_unknown } m_result;
- STG::Message m_msg;
- User * m_user;
-
- int ParseLogins(const char * logins);
- void CreateAnswer();
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "parser_server_info.h"
-
-#include "stg/settings.h"
-#include "stg/users.h"
-#include "stg/tariffs.h"
-#include "stg/version.h"
-#include "stg/const.h"
-
-#include <string>
-#include <cstring>
-
-#include <sys/utsname.h>
-
-using STG::PARSER::GET_SERVER_INFO;
-
-const char * GET_SERVER_INFO::tag = "GetServerInfo";
-
-void GET_SERVER_INFO::CreateAnswer()
-{
- struct utsname utsn;
- uname(&utsn);
-
- std::string name = std::string(utsn.sysname) + " " +
- utsn.release + " " +
- utsn.machine + " " +
- utsn.nodename;
-
- m_answer = std::string("<ServerInfo><version value=\"") + SERVER_VERSION + "\"/>" +
- "<tariff_num value=\"" + std::to_string(m_tariffs.Count()) + "\"/>" +
- "<tariff value=\"2\"/>" +
- "<user_num value=\"" + std::to_string(m_users.Count()) + "\"/>" +
- "<uname value=\"" + name + "\"/>" +
- "<dir_num value=\"" + std::to_string(DIR_NUM) + "\"/>" +
- "<day_fee value=\"" + std::to_string(m_settings.GetDayFee()) + "\"/>";
-
- for (size_t i = 0; i< DIR_NUM; i++)
- m_answer += "<dir_name_" + std::to_string(i) + " value=\"" + Encode12str(m_settings.GetDirName(i)) + "\"/>";
-
- m_answer += "</ServerInfo>";
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/common.h"
-
-namespace STG
-{
-
-struct Admin;
-struct Settings;
-struct Users;
-struct Tariffs;
-
-namespace PARSER
-{
-
-class GET_SERVER_INFO: public BASE_PARSER {
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(const Settings & settings, const Users & users, const Tariffs & tariffs)
- : m_settings(settings), m_users(users), m_tariffs(tariffs) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_SERVER_INFO(admin, m_settings, m_users, m_tariffs); }
- static void Register(REGISTRY & registry, const Settings & settings, const Users & users, const Tariffs & tariffs)
- { registry[ToLower(tag)] = new FACTORY(settings, users, tariffs); }
- private:
- const Settings & m_settings;
- const Users & m_users;
- const Tariffs & m_tariffs;
- };
-
- static const char * tag;
-
- GET_SERVER_INFO(const Admin & admin,
- const Settings & settings,
- const Users & users,
- const Tariffs & tariffs)
- : BASE_PARSER(admin, tag),
- m_settings(settings),
- m_users(users),
- m_tariffs(tariffs)
- {}
-
- private:
- const Settings & m_settings;
- const Users & m_users;
- const Tariffs & m_tariffs;
-
- void CreateAnswer();
-};
-
-}
-}
+++ /dev/null
-/*
- * 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 "parser_services.h"
-
-#include "stg/services.h"
-
-#include <strings.h> // strcasecmp
-
-using STG::PARSER::GET_SERVICES;
-using STG::PARSER::GET_SERVICE;
-using STG::PARSER::ADD_SERVICE;
-using STG::PARSER::DEL_SERVICE;
-using STG::PARSER::CHG_SERVICE;
-
-const char * GET_SERVICES::tag = "GetServices";
-const char * GET_SERVICE::tag = "AddService";
-const char * ADD_SERVICE::tag = "AddService";
-const char * DEL_SERVICE::tag = "DelService";
-const char * CHG_SERVICE::tag = "SetService";
-
-void GET_SERVICES::CreateAnswer()
-{
- // TODO: no priviledges implemented yet
- /*const PRIV * priv = m_currAdmin.GetPriv();
- if (!priv->serviceChg)
- {
- m_answer = "<Error Result=\"Error. Access denied.\"/>";
- return;
- }*/
-
- m_answer = "<Services>";
- ServiceConf conf;
- int h = m_services.OpenSearch();
- while (m_services.SearchNext(h, &conf) == 0)
- {
- m_answer += "<Service name=\"" + conf.name +
- "\" comment=\"" + Encode12str(conf.comment) +
- "\" cost=\"" + std::to_string(conf.cost) +
- "\" payDay=\"" + std::to_string(conf.payDay) + "\"/>";
- }
- m_services.CloseSearch(h);
- m_answer += "</Services>";
-}
-
-int GET_SERVICE::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- m_name = attr[1];
- return 0;
- }
- return -1;
-}
-
-void GET_SERVICE::CreateAnswer()
-{
- // TODO: no priviledges implemented yet
- /*const PRIV * priv = m_currAdmin.GetPriv();
- if (!priv->serviceChg)
- {
- m_answer = "<Error Result=\"Error. Access denied.\"/>";
- return;
- }*/
-
- ServiceConf conf;
- if (!m_services.Find(m_name, &conf))
- m_answer = "<Error result=\"Service '" + m_name + "' does not exist.\"/>";
- else
- m_answer += "<" + m_tag + " name=\"" + conf.name +
- "\" comment=\"" + Encode12str(conf.comment) +
- "\" cost=\"" + std::to_string(conf.cost) +
- "\" payDay=\"" + std::to_string(conf.payDay) + "\"/>";
-}
-
-int ADD_SERVICE::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- m_name = attr[1];
- return 0;
- }
- return -1;
-}
-
-void ADD_SERVICE::CreateAnswer()
-{
- ServiceConf conf(m_name);
- if (m_services.Add(conf, &m_currAdmin) == 0)
- m_answer = "<" + m_tag + " result=\"Ok\"/>";
- else
- m_answer = "<" + m_tag + " result=\"" + m_services.GetStrError() + "\"/>";
-}
-
-int DEL_SERVICE::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- m_name = attr[1];
- return 0;
- }
- return -1;
-}
-
-void DEL_SERVICE::CreateAnswer()
-{
- if (m_services.Del(m_name, &m_currAdmin) == 0)
- m_answer = "<" + m_tag + " result=\"Ok\"/>";
- else
- m_answer = "<" + m_tag + " result=\"" + m_services.GetStrError() + "\"/>";
-}
-
-int CHG_SERVICE::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- for (size_t i = 0; i < 8; i += 2)
- {
- if (attr[i] == NULL)
- break;
-
- if (strcasecmp(attr[i], "name") == 0)
- {
- m_service.name = attr[i + 1];
- continue;
- }
-
- if (strcasecmp(attr[i], "comment") == 0)
- {
- m_service.comment = Decode21str(attr[i + 1]);
- continue;
- }
-
- if (strcasecmp(attr[i], "cost") == 0)
- {
- double cost = 0;
- if (str2x(attr[i + 1], cost) == 0)
- m_service.cost = cost;
- else
- printfd(__FILE__, "Bad cast from '%s' to double\n", attr[i + 1]);
- // TODO: log it
- continue;
- }
-
- if (strcasecmp(attr[i], "payDay") == 0)
- {
- unsigned payDay;
- if (str2x(attr[i + 1], payDay) == 0)
- m_service.payDay = payDay;
- else
- printfd(__FILE__, "Bad cast from '%s' to unsigned\n", attr[i + 1]);
- // TODO: log it
- continue;
- }
- }
-
- return 0;
- }
- return -1;
-}
-
-void CHG_SERVICE::CreateAnswer()
-{
- if (m_service.name.empty())
- {
- m_answer = "<" + m_tag + " result=\"Empty service name.\"/>";
- return;
- }
-
- if (!m_services.Exists(m_service.name.const_data()))
- {
- m_answer = "<" + m_tag + " result = \"Service '" + m_service.name.const_data() + "' does not exist.\"/>";
- return;
- }
-
- ServiceConf orig;
- m_services.Find(m_service.name.const_data(), &orig);
-
- ServiceConfOpt conf(orig);
- conf.splice(m_service);
-
- if (m_services.Change(conf.get({}), &m_currAdmin) != 0)
- m_answer = "<" + m_tag + " result = \"" + m_services.GetStrError() + "\"/>";
- else
- m_answer = "<" + m_tag + " result = \"Ok\"/>";
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/service_conf.h"
-
-#include "stg/common.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Services;
-
-namespace PARSER
-{
-
-class GET_SERVICES: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(const Services & services) : m_services(services) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_SERVICES(admin, m_services); }
- static void Register(REGISTRY & registry, const Services & services)
- { registry[ToLower(tag)] = new FACTORY(services); }
- private:
- const Services & m_services;
- };
-
- static const char * tag;
-
- GET_SERVICES(const Admin & admin, const Services & services)
- : BASE_PARSER(admin, tag), m_services(services) {}
-
- private:
- const Services & m_services;
-
- void CreateAnswer();
-};
-
-class GET_SERVICE: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(const Services & services) : m_services(services) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_SERVICE(admin, m_services); }
- static void Register(REGISTRY & registry, Services & services)
- { registry[ToLower(tag)] = new FACTORY(services); }
- private:
- const Services & m_services;
- };
-
- static const char * tag;
-
- GET_SERVICE(const Admin & admin, const Services & services)
- : BASE_PARSER(admin, tag), m_services(services) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string m_name;
- const Services & m_services;
-
- void CreateAnswer();
-};
-
-class ADD_SERVICE: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(Services & services) : m_services(services) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new ADD_SERVICE(admin, m_services); }
- static void Register(REGISTRY & registry, Services & services)
- { registry[ToLower(tag)] = new FACTORY(services); }
- private:
- Services & m_services;
- };
-
- static const char * tag;
-
- ADD_SERVICE(const Admin & admin, Services & services)
- : BASE_PARSER(admin, tag), m_services(services) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string m_name;
- Services & m_services;
-
- void CreateAnswer();
-};
-
-class DEL_SERVICE: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(Services & services) : m_services(services) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new DEL_SERVICE(admin, m_services); }
- static void Register(REGISTRY & registry, Services & services)
- { registry[ToLower(tag)] = new FACTORY(services); }
- private:
- Services & m_services;
- };
-
- static const char * tag;
-
- DEL_SERVICE(const Admin & admin, Services & services)
- : BASE_PARSER(admin, tag), m_services(services) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string m_name;
- Services & m_services;
-
- void CreateAnswer();
-};
-
-class CHG_SERVICE: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(Services & services) : m_services(services) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new CHG_SERVICE(admin, m_services); }
- static void Register(REGISTRY & registry, Services & services)
- { registry[ToLower(tag)] = new FACTORY(services); }
- private:
- Services & m_services;
- };
-
- static const char * tag;
-
- CHG_SERVICE(const Admin & admin, Services & services)
- : BASE_PARSER(admin, tag), m_services(services) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- ServiceConfOpt m_service;
- Services & m_services;
-
- void CreateAnswer();
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "parser_tariffs.h"
-
-#include "stg/tariffs.h"
-#include "stg/users.h"
-#include "stg/optional.h"
-
-#include <cstdio> // snprintf
-#include <cstring>
-
-using STG::PARSER::GET_TARIFFS;
-using STG::PARSER::ADD_TARIFF;
-using STG::PARSER::DEL_TARIFF;
-using STG::PARSER::CHG_TARIFF;
-
-const char * GET_TARIFFS::tag = "GetTariffs";
-const char * ADD_TARIFF::tag = "AddTariff";
-const char * DEL_TARIFF::tag = "DelTariff";
-const char * CHG_TARIFF::tag = "SetTariff";
-
-namespace
-{
-
-const double pt_mega = 1024 * 1024;
-
-template <typename A, typename C, typename F>
-std::string AOS2String(const A & array, size_t size, const F C::* field, F multiplier)
-{
- std::string res;
- for (size_t i = 0; i < size; ++i)
- {
- if (!res.empty())
- res += "/";
- res += std::to_string((array[i].*field) * multiplier);
- }
- return res;
-}
-
-template <typename T>
-bool str2res(const std::string& source, STG::Optional<T>& dest, T divisor)
-{
- T value = 0;
- if (str2x(source, value))
- return false;
- dest = value / divisor;
- return true;
-}
-
-template <typename A, typename C, typename F>
-bool String2AOS(const std::string & source, A & array, size_t size, STG::Optional<F> C::* field, F divisor)
-{
- size_t index = 0;
- std::string::size_type from = 0;
- std::string::size_type pos = 0;
- while (index < size && (pos = source.find('/', from)) != std::string::npos)
- {
- if (!str2res(source.substr(from, pos - from), array[index].*field, divisor))
- return false;
- from = pos + 1;
- ++index;
- }
- if (str2res(source.substr(from), array[index].*field, divisor))
- return false;
- return true;
-}
-
-}
-
-void GET_TARIFFS::CreateAnswer()
-{
- m_answer = "<Tariffs>";
-
- std::vector<TariffData> dataList;
- m_tariffs.GetTariffsData(&dataList);
- auto it = dataList.begin();
- for (; it != dataList.end(); ++it)
- {
- m_answer += "<tariff name=\"" + it->tariffConf.name + "\">";
-
- for (size_t i = 0; i < DIR_NUM; i++)
- m_answer += "<Time" + std::to_string(i) + " value=\"" +
- std::to_string(it->dirPrice[i].hDay) + ":" + std::to_string(it->dirPrice[i].mDay) + "-" +
- std::to_string(it->dirPrice[i].hNight) + ":" + std::to_string(it->dirPrice[i].mNight) + "\"/>";
-
- m_answer += "<PriceDayA value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceDayA, pt_mega) + "\"/>" +
- "<PriceDayB value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceDayB, pt_mega) + "\"/>" +
- "<PriceNightA value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceNightA, pt_mega) + "\"/>" +
- "<PriceNightB value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::priceNightB, pt_mega) + "\"/>" +
- "<Threshold value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::threshold, 1) + "\"/>" +
- "<SinglePrice value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::singlePrice, 1) + "\"/>" +
- "<NoDiscount value=\"" + AOS2String(it->dirPrice, DIR_NUM, &DirPriceData::noDiscount, 1) + "\"/>" +
- "<Fee value=\"" + std::to_string(it->tariffConf.fee) + "\"/>" +
- "<PassiveCost value=\"" + std::to_string(it->tariffConf.passiveCost) + "\"/>" +
- "<Free value=\"" + std::to_string(it->tariffConf.free) + "\"/>" +
- "<TraffType value=\"" + Tariff::toString(it->tariffConf.traffType) + "\"/>" +
- "<Period value=\"" + Tariff::toString(it->tariffConf.period) + "\"/>" +
- "<ChangePolicy value=\"" + Tariff::toString(it->tariffConf.changePolicy) + "\"/>" +
- "<ChangePolicyTimeout value=\"" + std::to_string(it->tariffConf.changePolicyTimeout) + "\"/>" +
- "</tariff>";
- }
-
- m_answer += "</Tariffs>";
-}
-
-int ADD_TARIFF::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- if (attr[1] == NULL)
- return -1;
-
- tariff = attr[1];
- return 0;
-}
-
-void ADD_TARIFF::CreateAnswer()
-{
- if (m_tariffs.Add(tariff, &m_currAdmin) == 0)
- m_answer = "<" + m_tag + " Result=\"Ok\"/>";
- else
- m_answer = "<" + m_tag + " Result=\"Error. " + m_tariffs.GetStrError() + "\"/>";
-}
-
-int DEL_TARIFF::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- if (attr[1] == NULL)
- return -1;
-
- tariff = attr[1];
- return 0;
-}
-
-void DEL_TARIFF::CreateAnswer()
-{
- if (m_users.TariffInUse(tariff))
- m_answer = "<" + m_tag + " Result=\"Error. Tariff \'" + tariff + "\' cannot be deleted, it is in use.\"/>";
- else if (m_tariffs.Del(tariff, &m_currAdmin) == 0)
- m_answer = "<" + m_tag + " Result=\"Ok\"/>";
- else
- m_answer = "<" + m_tag + " Result=\"Error. " + m_tariffs.GetStrError() + "\"/>";
-}
-
-int CHG_TARIFF::Start(void *, const char * el, const char ** attr)
-{
- m_depth++;
-
- if (m_depth == 1)
- {
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- const auto tariff = m_tariffs.FindByName(attr[1]);
- if (tariff != NULL)
- td = tariff->GetTariffData();
- else
- return -1;
- return 0;
- }
- }
- else
- {
- if (strcasecmp(el, "PriceDayA") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceDayA, pt_mega))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- if (strcasecmp(el, "PriceDayB") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceDayB, pt_mega))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- if (strcasecmp(el, "PriceNightA") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceNightA, pt_mega))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- if (strcasecmp(el, "PriceNightB") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::priceNightB, pt_mega))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- if (strcasecmp(el, "Threshold") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::threshold, 1))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- if (strcasecmp(el, "SinglePrice") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::singlePrice, 1))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- if (strcasecmp(el, "NoDiscount") == 0)
- {
- if (!String2AOS(attr[1], td.dirPrice, DIR_NUM, &DirPriceDataOpt::noDiscount, 1))
- return -1; // TODO: log it
- else
- return 0;
- }
-
- for (int j = 0; j < DIR_NUM; j++)
- {
- char st[50];
- snprintf(st, 50, "Time%d", j);
- if (strcasecmp(el, st) == 0)
- {
- int h1 = 0;
- int m1 = 0;
- int h2 = 0;
- int m2 = 0;
- if (ParseTariffTimeStr(attr[1], h1, m1, h2, m2) == 0)
- {
- td.dirPrice[j].hDay = h1;
- td.dirPrice[j].mDay = m1;
- td.dirPrice[j].hNight = h2;
- td.dirPrice[j].mNight = m2;
- }
- return 0;
- }
- }
-
- if (strcasecmp(el, "Fee") == 0)
- {
- double fee;
- if (strtodouble2(attr[1], fee) == 0)
- td.tariffConf.fee = fee;
- return 0;
- }
-
- if (strcasecmp(el, "PassiveCost") == 0)
- {
- double pc;
- if (strtodouble2(attr[1], pc) == 0)
- td.tariffConf.passiveCost = pc;
- return 0;
- }
-
- if (strcasecmp(el, "Free") == 0)
- {
- double free;
- if (strtodouble2(attr[1], free) == 0)
- td.tariffConf.free = free;
- return 0;
- }
-
- if (strcasecmp(el, "TraffType") == 0)
- {
- td.tariffConf.traffType = Tariff::parseTraffType(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "Period") == 0)
- {
- td.tariffConf.period = Tariff::parsePeriod(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "ChangePolicy") == 0)
- {
- td.tariffConf.changePolicy = Tariff::parseChangePolicy(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "ChangePolicyTimeout") == 0)
- {
- int64_t policyTime = 0;
- if (str2x(attr[1], policyTime) == 0)
- td.tariffConf.changePolicyTimeout = (time_t)policyTime;
- return 0;
- }
- }
- return -1;
-}
-
-void CHG_TARIFF::CreateAnswer()
-{
- if (!td.tariffConf.name.data().empty())
- {
- auto tariffData = td.get({});
- if (m_tariffs.Chg(tariffData, &m_currAdmin) == 0)
- m_answer = "<" + m_tag + " Result=\"ok\"/>";
- else
- m_answer = "<" + m_tag + " Result=\"Change tariff error! " + m_tariffs.GetStrError() + "\"/>";
- }
- else
- m_answer = "<" + m_tag + " Result=\"Change tariff error!\"/>";
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/tariff_conf.h"
-#include "stg/common.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Tariffs;
-struct Users;
-struct Admin;
-
-namespace PARSER
-{
-
-class GET_TARIFFS: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(const Tariffs & tariffs) : m_tariffs(tariffs) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_TARIFFS(admin, m_tariffs); }
- static void Register(REGISTRY & registry, const Tariffs & tariffs)
- { registry[ToLower(tag)] = new FACTORY(tariffs); }
- private:
- const Tariffs & m_tariffs;
- };
-
- static const char * tag;
-
- GET_TARIFFS(const Admin & admin, const Tariffs & tariffs)
- : BASE_PARSER(admin, tag), m_tariffs(tariffs) {}
-
- private:
- const Tariffs & m_tariffs;
-
- void CreateAnswer();
-};
-
-class ADD_TARIFF: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Tariffs & tariffs) : m_tariffs(tariffs) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new ADD_TARIFF(admin, m_tariffs); }
- static void Register(REGISTRY & registry, Tariffs & tariffs)
- { registry[ToLower(tag)] = new FACTORY(tariffs); }
- private:
- Tariffs & m_tariffs;
- };
-
- static const char * tag;
-
- ADD_TARIFF(const Admin & admin, Tariffs & tariffs)
- : BASE_PARSER(admin, tag), m_tariffs(tariffs) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string tariff;
- Tariffs & m_tariffs;
-
- void CreateAnswer();
-};
-
-class DEL_TARIFF: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(Tariffs & tariffs, const Users & users) : m_tariffs(tariffs), m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new DEL_TARIFF(admin, m_users, m_tariffs); }
- static void Register(REGISTRY & registry, Tariffs & tariffs, const Users & users)
- { registry[ToLower(tag)] = new FACTORY(tariffs, users); }
- private:
- Tariffs & m_tariffs;
- const Users & m_users;
- };
-
- static const char * tag;
-
- DEL_TARIFF(const Admin & admin, const Users & users, Tariffs & tariffs)
- : BASE_PARSER(admin, tag), m_users(users), m_tariffs(tariffs) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- std::string tariff;
- const Users & m_users;
- Tariffs & m_tariffs;
-
- void CreateAnswer();
-};
-
-class CHG_TARIFF: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Tariffs & tariffs) : m_tariffs(tariffs) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new CHG_TARIFF(admin, m_tariffs); }
- static void Register(REGISTRY & registry, Tariffs & tariffs)
- { registry[ToLower(tag)] = new FACTORY(tariffs); }
- private:
- Tariffs & m_tariffs;
- };
-
- static const char * tag;
-
- CHG_TARIFF(const Admin & admin, Tariffs & tariffs)
- : BASE_PARSER(admin, tag), m_tariffs(tariffs) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- TariffDataOpt td;
- Tariffs & m_tariffs;
-
- int CheckTariffData();
- void CreateAnswer();
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 "parser_user_info.h"
-
-#include "stg/users.h"
-#include "stg/user.h"
-
-#include <strings.h> // strcasecmp
-
-using STG::PARSER::USER_INFO;
-
-const char * USER_INFO::tag = "GetUserInfo";
-
-int USER_INFO::Start(void * /*data*/, const char *el, const char **attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- if (!attr[1])
- return -1;
-
- m_login = attr[1];
- return 0;
-}
-
-void USER_INFO::CreateAnswer()
-{
- using ConstUserPtr = const User*;
- ConstUserPtr u;
- if (m_users.FindByName(m_login, &u))
- {
- m_answer = "<UserInfo result=\"error\"/>";
- return;
- }
-
- m_answer = "<UserInfo lastAuthTime=\"" + std::to_string(u->GetAuthorizedModificationTime()) + "\"" +
- " lastDisconnectTime=\"" + std::to_string(u->GetConnectedModificationTime()) + "\"" +
- " connected=\"" + (u->GetConnected() ? "true" : "false") + "\"" +
- " lastDisconnectReason=\"" + u->GetLastDisconnectReason() + "\">";
- std::vector<std::string> list(u->GetAuthorizers());
- for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
- m_answer += "<Auth name=\"" + *it + "\"/>";
- m_answer += "</UserInfo>";
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/common.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Users;
-
-namespace PARSER
-{
-
-class USER_INFO : public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(const Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new USER_INFO(admin, m_users); }
- static void Register(REGISTRY & registry, const Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- const Users & m_users;
- };
-
- static const char * tag;
-
- USER_INFO(const Admin & admin, const Users & users)
- : BASE_PARSER(admin, tag), m_users(users) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- const Users & m_users;
- std::string m_login;
-
- void CreateAnswer();
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "parser_users.h"
-
-#include "stg/users.h"
-#include "stg/user.h"
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/tariffs.h"
-#include "stg/tariff.h"
-#include "stg/user_property.h"
-
-#include <cstdio>
-#include <cassert>
-
-using STG::PARSER::GET_USERS;
-using STG::PARSER::GET_USER;
-using STG::PARSER::ADD_USER;
-using STG::PARSER::DEL_USER;
-using STG::PARSER::CHG_USER;
-using STG::PARSER::CHECK_USER;
-
-const char * GET_USERS::tag = "GetUsers";
-const char * GET_USER::tag = "GetUser";
-const char * ADD_USER::tag = "AddUser";
-const char * CHG_USER::tag = "SetUser";
-const char * DEL_USER::tag = "DelUser";
-const char * CHECK_USER::tag = "CheckUser";
-
-using UserPtr = STG::User*;
-using ConstUserPtr = const STG::User*;
-
-namespace
-{
-
-std::string UserToXML(const STG::User & user, bool loginInStart, bool showPass, time_t lastTime = 0)
-{
- std::string answer;
-
- if (loginInStart)
- answer += "<User login=\"" + user.GetLogin() + "\" result=\"ok\">";
- else
- answer += "<User result=\"ok\">";
-
- answer += "<Login value=\"" + user.GetLogin() + "\"/>";
-
- if (user.GetProperties().password.ModificationTime() > lastTime)
- {
- if (showPass)
- answer += "<Password value=\"" + user.GetProperties().password.Get() + "\" />";
- else
- answer += "<Password value=\"++++++\"/>";
- }
-
- if (user.GetProperties().cash.ModificationTime() > lastTime)
- answer += "<Cash value=\"" + std::to_string(user.GetProperties().cash.Get()) + "\"/>";
- if (user.GetProperties().freeMb.ModificationTime() > lastTime)
- answer += "<FreeMb value=\"" + std::to_string(user.GetProperties().freeMb.Get()) + "\"/>";
- if (user.GetProperties().credit.ModificationTime() > lastTime)
- answer += "<Credit value=\"" + std::to_string(user.GetProperties().credit.Get()) + "\"/>";
-
- if (user.GetProperties().nextTariff.Get() != "")
- {
- if (user.GetProperties().tariffName.ModificationTime() > lastTime ||
- user.GetProperties().nextTariff.ModificationTime() > lastTime)
- answer += "<Tariff value=\"" + user.GetProperties().tariffName.Get() + "/" + user.GetProperties().nextTariff.Get() + "\"/>";
- }
- else
- {
- if (user.GetProperties().tariffName.ModificationTime() > lastTime)
- answer += "<Tariff value=\"" + user.GetProperties().tariffName.Get() + "\"/>";
- }
-
- if (user.GetProperties().note.ModificationTime() > lastTime)
- answer += "<Note value=\"" + Encode12str(user.GetProperties().note) + "\"/>";
- if (user.GetProperties().phone.ModificationTime() > lastTime)
- answer += "<Phone value=\"" + Encode12str(user.GetProperties().phone) + "\"/>";
- if (user.GetProperties().address.ModificationTime() > lastTime)
- answer += "<Address value=\"" + Encode12str(user.GetProperties().address) + "\"/>";
- if (user.GetProperties().email.ModificationTime() > lastTime)
- answer += "<Email value=\"" + Encode12str(user.GetProperties().email) + "\"/>";
-
- std::vector<const STG::UserPropertyLogged<std::string> *> userdata;
- userdata.push_back(user.GetProperties().userdata0.GetPointer());
- userdata.push_back(user.GetProperties().userdata1.GetPointer());
- userdata.push_back(user.GetProperties().userdata2.GetPointer());
- userdata.push_back(user.GetProperties().userdata3.GetPointer());
- userdata.push_back(user.GetProperties().userdata4.GetPointer());
- userdata.push_back(user.GetProperties().userdata5.GetPointer());
- userdata.push_back(user.GetProperties().userdata6.GetPointer());
- userdata.push_back(user.GetProperties().userdata7.GetPointer());
- userdata.push_back(user.GetProperties().userdata8.GetPointer());
- userdata.push_back(user.GetProperties().userdata9.GetPointer());
-
- for (size_t i = 0; i < userdata.size(); i++)
- if (userdata[i]->ModificationTime() > lastTime)
- answer += "<UserData" + std::to_string(i) + " value=\"" + Encode12str(userdata[i]->Get()) + "\" />";
-
- if (user.GetProperties().realName.ModificationTime() > lastTime)
- answer += "<Name value=\"" + Encode12str(user.GetProperties().realName) + "\"/>";
- if (user.GetProperties().group.ModificationTime() > lastTime)
- answer += "<Group value=\"" + Encode12str(user.GetProperties().group) + "\"/>";
- if (user.GetConnectedModificationTime() > lastTime)
- answer += std::string("<Status value=\"") + (user.GetConnected() ? "1" : "0") + "\"/>";
- if (user.GetProperties().alwaysOnline.ModificationTime() > lastTime)
- answer += std::string("<AOnline value=\"") + (user.GetProperties().alwaysOnline.Get() ? "1" : "0") + "\"/>";
- if (user.GetCurrIPModificationTime() > lastTime)
- answer += "<CurrIP value=\"" + inet_ntostring(user.GetCurrIP()) + "\"/>";
- if (user.GetPingTime() > lastTime)
- answer += "<PingTime value=\"" + std::to_string(user.GetPingTime()) + "\"/>";
- if (user.GetProperties().ips.ModificationTime() > lastTime)
- answer += "<IP value=\"" + user.GetProperties().ips.Get().toString() + "\"/>";
-
- answer += "<Traff";
- const auto & upload(user.GetProperties().up.Get());
- const auto & download(user.GetProperties().down.Get());
- if (user.GetProperties().up.ModificationTime() > lastTime)
- for (size_t j = 0; j < DIR_NUM; j++)
- answer += " MU" + std::to_string(j) + "=\"" + std::to_string(upload[j]) + "\"";
- if (user.GetProperties().down.ModificationTime() > lastTime)
- for (size_t j = 0; j < DIR_NUM; j++)
- answer += " MD" + std::to_string(j) + "=\"" + std::to_string(download[j]) + "\"";
- if (user.GetSessionUploadModificationTime() > lastTime)
- for (size_t j = 0; j < DIR_NUM; j++)
- answer += " SU" + std::to_string(j) + "=\"" + std::to_string(user.GetSessionUpload()[j]) + "\"";
- if (user.GetSessionDownloadModificationTime() > lastTime)
- for (size_t j = 0; j < DIR_NUM; j++)
- answer += " SD" + std::to_string(j) + "=\"" + std::to_string(user.GetSessionDownload()[j]) + "\"";
- answer += "/>";
-
- if (user.GetProperties().disabled.ModificationTime() > lastTime)
- answer += std::string("<Down value=\"") + (user.GetProperties().disabled.Get() ? "1" : "0") + "\"/>";
- if (user.GetProperties().disabledDetailStat.ModificationTime() > lastTime)
- answer += std::string("<DisableDetailStat value=\"") + (user.GetProperties().disabledDetailStat.Get() ? "1" : "0") + "\"/>";
- if (user.GetProperties().passive.ModificationTime() > lastTime)
- answer += std::string("<Passive value=\"") + (user.GetProperties().passive.Get() ? "1" : "0") + "\"/>";
- if (user.GetProperties().lastCashAdd.ModificationTime() > lastTime)
- answer += "<LastCash value=\"" + std::to_string(user.GetProperties().lastCashAdd.Get()) + "\"/>";
- if (user.GetProperties().lastCashAddTime.ModificationTime() > lastTime)
- answer += "<LastTimeCash value=\"" + std::to_string(user.GetProperties().lastCashAddTime.Get()) + "\"/>";
- if (user.GetProperties().lastActivityTime.ModificationTime() > lastTime)
- answer += "<LastActivityTime value=\"" + std::to_string(user.GetProperties().lastActivityTime.Get()) + "\"/>";
- if (user.GetProperties().creditExpire.ModificationTime() > lastTime)
- answer += "<CreditExpire value=\"" + std::to_string(user.GetProperties().creditExpire.Get()) + "\"/>";
-
- if (lastTime == 0)
- {
- answer += "<AuthorizedBy>";
- std::vector<std::string> list(user.GetAuthorizers());
- for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
- answer += "<Auth name=\"" + *it + "\"/>";
- answer += "</AuthorizedBy>";
- }
-
- answer += "</User>";
-
- return answer;
-}
-
-} // namespace anonymous
-
-int GET_USERS::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- {
- printfd(__FILE__, "Got wrong tag: '%s' instead of '%s'\n", el, m_tag.c_str());
- return -1;
- }
-
- while (attr && *attr && *(attr + 1))
- {
- if (strcasecmp(*attr, "LastUpdate") == 0)
- str2x(*(attr + 1), m_lastUserUpdateTime);
- ++attr;
- }
-
- return 0;
-}
-
-void GET_USERS::CreateAnswer()
-{
- int h = m_users.OpenSearch();
- assert(h);
-
- if (m_lastUserUpdateTime > 0)
- m_answer = "<Users LastUpdate=\"" + std::to_string(time(NULL)) + "\">";
- else
- m_answer = "<Users>";
-
- UserPtr u;
-
- while (m_users.SearchNext(h, &u) == 0)
- m_answer += UserToXML(*u, true, m_currAdmin.priv().userConf || m_currAdmin.priv().userPasswd, m_lastUserUpdateTime);
-
- m_users.CloseSearch(h);
-
- m_answer += "</Users>";
-}
-
-int GET_USER::Start(void *, const char * el, const char ** attr)
-{
- if (strcasecmp(el, m_tag.c_str()) != 0)
- return -1;
-
- if (attr[1] == NULL)
- return -1;
-
- m_login = attr[1];
- return 0;
-}
-
-void GET_USER::CreateAnswer()
-{
- ConstUserPtr u;
-
- if (m_users.FindByName(m_login, &u))
- m_answer = "<User result=\"error\" reason=\"User not found.\"/>";
- else
- m_answer = UserToXML(*u, false, m_currAdmin.priv().userConf || m_currAdmin.priv().userPasswd);
-}
-
-int ADD_USER::Start(void *, const char * el, const char ** attr)
-{
- m_depth++;
-
- if (m_depth == 1)
- {
- if (strcasecmp(el, m_tag.c_str()) == 0)
- return 0;
- }
- else
- {
- if (strcasecmp(el, "login") == 0)
- {
- m_login = attr[1];
- return 0;
- }
- }
- return -1;
-}
-
-void ADD_USER::CreateAnswer()
-{
- if (m_users.Exists(m_login))
- m_answer = "<" + m_tag + " result=\"error\" reason=\"User '" + m_login + "' exists.\"/>";
- else if (m_users.Add(m_login, &m_currAdmin) == 0)
- m_answer = "<" + m_tag + " result=\"ok\"/>";
- else
- m_answer = "<" + m_tag + " result=\"error\" reason=\"Access denied\"/>";
-}
-
-int CHG_USER::Start(void *, const char * el, const char ** attr)
-{
- m_depth++;
-
- if (m_depth == 1)
- {
- if (strcasecmp(el, m_tag.c_str()) == 0)
- return 0;
- }
- else
- {
- if (strcasecmp(el, "login") == 0)
- {
- m_login = attr[1];
- return 0;
- }
-
- if (strcasecmp(el, "ip") == 0)
- {
- m_ucr.ips = UserIPs::parse(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "password") == 0)
- {
- m_ucr.password = attr[1];
- return 0;
- }
-
- if (strcasecmp(el, "address") == 0)
- {
- m_ucr.address = Decode21str(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "aonline") == 0)
- {
- m_ucr.alwaysOnline = (*(attr[1]) != '0');
- return 0;
- }
-
- if (strcasecmp(el, "cash") == 0)
- {
- if (attr[2] && (strcasecmp(attr[2], "msg") == 0))
- m_cashMsg = Decode21str(attr[3]);
-
- double cash = 0;
- if (strtodouble2(attr[1], cash) == 0)
- m_usr.cash = cash;
-
- m_cashMustBeAdded = (strcasecmp(attr[0], "add") == 0);
-
- return 0;
- }
-
- if (strcasecmp(el, "CreditExpire") == 0)
- {
- long int creditExpire = 0;
- if (str2x(attr[1], creditExpire) == 0)
- m_ucr.creditExpire = (time_t)creditExpire;
-
- return 0;
- }
-
- if (strcasecmp(el, "credit") == 0)
- {
- double credit = 0;
- if (strtodouble2(attr[1], credit) == 0)
- m_ucr.credit = credit;
- return 0;
- }
-
- if (strcasecmp(el, "freemb") == 0)
- {
- double freeMb = 0;
- if (strtodouble2(attr[1], freeMb) == 0)
- m_usr.freeMb = freeMb;
- return 0;
- }
-
- if (strcasecmp(el, "down") == 0)
- {
- int down = 0;
- if (str2x(attr[1], down) == 0)
- m_ucr.disabled = down;
- return 0;
- }
-
- if (strcasecmp(el, "DisableDetailStat") == 0)
- {
- int disabledDetailStat = 0;
- if (str2x(attr[1], disabledDetailStat) == 0)
- m_ucr.disabledDetailStat = disabledDetailStat;
- return 0;
- }
-
- if (strcasecmp(el, "email") == 0)
- {
- m_ucr.email = Decode21str(attr[1]);
- return 0;
- }
-
- for (int i = 0; i < USERDATA_NUM; i++)
- {
- char name[15];
- sprintf(name, "userdata%d", i);
- if (strcasecmp(el, name) == 0)
- {
- m_ucr.userdata[i] = Decode21str(attr[1]);
- return 0;
- }
- }
-
- if (strcasecmp(el, "group") == 0)
- {
- m_ucr.group = Decode21str(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "note") == 0)
- {
- m_ucr.note = Decode21str(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "passive") == 0)
- {
- int passive = 0;
- if (str2x(attr[1], passive) == 0)
- m_ucr.passive = passive;
- return 0;
- }
-
- if (strcasecmp(el, "phone") == 0)
- {
- m_ucr.phone = Decode21str(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "Name") == 0)
- {
- m_ucr.realName = Decode21str(attr[1]);
- return 0;
- }
-
- if (strcasecmp(el, "traff") == 0)
- {
- int j = 0;
- while (attr[j])
- {
- int dir = attr[j][2] - '0';
-
- if (strncasecmp(attr[j], "md", 2) == 0)
- {
- uint64_t t = 0;
- str2x(attr[j + 1], t);
- m_downr[dir] = t;
- }
- if (strncasecmp(attr[j], "mu", 2) == 0)
- {
- uint64_t t = 0;
- str2x(attr[j + 1], t);
- m_upr[dir] = t;
- }
- j += 2;
- }
- return 0;
- }
-
- if (strcasecmp(el, "tariff") == 0)
- {
- if (strcasecmp(attr[0], "now") == 0)
- m_ucr.tariffName = attr[1];
-
- if (strcasecmp(attr[0], "delayed") == 0)
- m_ucr.nextTariff = attr[1];
-
- return 0;
- }
- }
- return -1;
-}
-
-void CHG_USER::CreateAnswer()
-{
- if (ApplyChanges() == 0)
- m_answer = "<" + m_tag + " result=\"ok\"/>";
- else
- m_answer = "<" + m_tag + " result=\"error\"/>";
-}
-
-int CHG_USER::ApplyChanges()
-{
- printfd(__FILE__, "PARSER_CHG_USER::ApplyChanges()\n");
- UserPtr u;
-
- if (m_users.FindByName(m_login, &u))
- return -1;
-
- bool check = false;
- bool alwaysOnline = u->GetProperties().alwaysOnline;
- if (!m_ucr.alwaysOnline.empty())
- {
- check = true;
- alwaysOnline = m_ucr.alwaysOnline.const_data();
- }
- bool onlyOneIP = u->GetProperties().ips.ConstData().onlyOneIP();
- if (!m_ucr.ips.empty())
- {
- check = true;
- onlyOneIP = m_ucr.ips.const_data().onlyOneIP();
- }
-
- if (check && alwaysOnline && !onlyOneIP)
- {
- printfd(__FILE__, "Requested change leads to a forbidden state: AlwaysOnline with multiple IP's\n");
- PluginLogger::get("conf_sg")("%s Requested change leads to a forbidden state: AlwaysOnline with multiple IP's", m_currAdmin.logStr().c_str());
- return -1;
- }
-
- for (size_t i = 0; i < m_ucr.ips.const_data().count(); ++i)
- {
- ConstUserPtr user;
- uint32_t ip = m_ucr.ips.const_data().operator[](i).ip;
- if (m_users.IsIPInUse(ip, m_login, &user))
- {
- printfd(__FILE__, "Trying to assign an IP %s to '%s' that is already in use by '%s'\n", inet_ntostring(ip).c_str(), m_login.c_str(), user->GetLogin().c_str());
- PluginLogger::get("conf_sg")("%s trying to assign an IP %s to '%s' that is currently in use by '%s'", m_currAdmin.logStr().c_str(), inet_ntostring(ip).c_str(), m_login.c_str(), user->GetLogin().c_str());
- return -1;
- }
- }
-
- if (!m_ucr.ips.empty())
- if (!u->GetProperties().ips.Set(m_ucr.ips.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.alwaysOnline.empty())
- if (!u->GetProperties().alwaysOnline.Set(m_ucr.alwaysOnline.const_data(),
- m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.address.empty())
- if (!u->GetProperties().address.Set(m_ucr.address.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.creditExpire.empty())
- if (!u->GetProperties().creditExpire.Set(m_ucr.creditExpire.const_data(),
- m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.credit.empty())
- if (!u->GetProperties().credit.Set(m_ucr.credit.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_usr.freeMb.empty())
- if (!u->GetProperties().freeMb.Set(m_usr.freeMb.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.disabled.empty())
- if (!u->GetProperties().disabled.Set(m_ucr.disabled.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.disabledDetailStat.empty())
- if (!u->GetProperties().disabledDetailStat.Set(m_ucr.disabledDetailStat.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.email.empty())
- if (!u->GetProperties().email.Set(m_ucr.email.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.group.empty())
- if (!u->GetProperties().group.Set(m_ucr.group.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.note.empty())
- if (!u->GetProperties().note.Set(m_ucr.note.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- std::vector<STG::UserPropertyLogged<std::string> *> userdata;
- userdata.push_back(u->GetProperties().userdata0.GetPointer());
- userdata.push_back(u->GetProperties().userdata1.GetPointer());
- userdata.push_back(u->GetProperties().userdata2.GetPointer());
- userdata.push_back(u->GetProperties().userdata3.GetPointer());
- userdata.push_back(u->GetProperties().userdata4.GetPointer());
- userdata.push_back(u->GetProperties().userdata5.GetPointer());
- userdata.push_back(u->GetProperties().userdata6.GetPointer());
- userdata.push_back(u->GetProperties().userdata7.GetPointer());
- userdata.push_back(u->GetProperties().userdata8.GetPointer());
- userdata.push_back(u->GetProperties().userdata9.GetPointer());
-
- for (int i = 0; i < (int)userdata.size(); i++)
- if (!m_ucr.userdata[i].empty())
- if(!userdata[i]->Set(m_ucr.userdata[i].const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.passive.empty())
- if (!u->GetProperties().passive.Set(m_ucr.passive.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.password.empty())
- if (!u->GetProperties().password.Set(m_ucr.password.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.phone.empty())
- if (!u->GetProperties().phone.Set(m_ucr.phone.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_ucr.realName.empty())
- if (!u->GetProperties().realName.Set(m_ucr.realName.const_data(), m_currAdmin, m_login, m_store))
- return -1;
-
- if (!m_usr.cash.empty())
- {
- if (m_cashMustBeAdded)
- {
- if (!u->GetProperties().cash.Set(m_usr.cash.const_data() + u->GetProperties().cash,
- m_currAdmin,
- m_login,
- m_store,
- m_cashMsg))
- return -1;
- }
- else
- {
- if (!u->GetProperties().cash.Set(m_usr.cash.const_data(), m_currAdmin, m_login, m_store, m_cashMsg))
- return -1;
- }
- }
-
- if (!m_ucr.tariffName.empty())
- {
- const auto newTariff = m_tariffs.FindByName(m_ucr.tariffName.const_data());
- if (newTariff)
- {
- const auto tariff = u->GetTariff();
- std::string message = tariff->TariffChangeIsAllowed(*newTariff, stgTime);
- if (message.empty())
- {
- if (!u->GetProperties().tariffName.Set(m_ucr.tariffName.const_data(), m_currAdmin, m_login, m_store))
- return -1;
- u->ResetNextTariff();
- }
- else
- {
- PluginLogger::get("conf_sg")("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str());
- }
- }
- else
- {
- //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
- return -1;
- }
- }
-
- if (!m_ucr.nextTariff.empty())
- {
- if (m_tariffs.FindByName(m_ucr.nextTariff.const_data()))
- {
- if (!u->GetProperties().nextTariff.Set(m_ucr.nextTariff.const_data(), m_currAdmin, m_login, m_store))
- return -1;
- }
- else
- {
- //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
- return -1;
- }
- }
-
- auto up = u->GetProperties().up.get();
- auto down = u->GetProperties().down.get();
- int upCount = 0;
- int downCount = 0;
- for (int i = 0; i < DIR_NUM; i++)
- {
- if (!m_upr[i].empty())
- {
- up[i] = m_upr[i].data();
- upCount++;
- }
- if (!m_downr[i].empty())
- {
- down[i] = m_downr[i].data();
- downCount++;
- }
- }
-
- if (upCount)
- if (!u->GetProperties().up.Set(up, m_currAdmin, m_login, m_store))
- return -1;
-
- if (downCount)
- if (!u->GetProperties().down.Set(down, m_currAdmin, m_login, m_store))
- return -1;
-
- u->WriteConf();
- u->WriteStat();
-
- return 0;
-}
-
-int DEL_USER::Start(void *, const char *el, const char **attr)
-{
- res = 0;
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- if (attr[0] == NULL || attr[1] == NULL)
- {
- //CreateAnswer("Parameters error!");
- CreateAnswer();
- return 0;
- }
-
- if (m_users.FindByName(attr[1], &u))
- {
- res = 1;
- CreateAnswer();
- return 0;
- }
- CreateAnswer();
- return 0;
- }
- return -1;
-}
-
-int DEL_USER::End(void *, const char *el)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- if (!res)
- m_users.Del(u->GetLogin(), &m_currAdmin);
-
- return 0;
- }
- return -1;
-}
-
-void DEL_USER::CreateAnswer()
-{
- if (res)
- m_answer = "<" + m_tag + " value=\"error\" reason=\"User not found\"/>";
- else
- m_answer = "<" + m_tag + " value=\"ok\"/>";
-}
-
-int CHECK_USER::Start(void *, const char *el, const char **attr)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- {
- if (attr[0] == NULL || attr[1] == NULL ||
- attr[2] == NULL || attr[3] == NULL)
- {
- CreateAnswer("Invalid parameters.");
- printfd(__FILE__, "PARSER_CHECK_USER - attr err\n");
- return 0;
- }
-
- ConstUserPtr user;
- if (m_users.FindByName(attr[1], &user))
- {
- CreateAnswer("User not found.");
- printfd(__FILE__, "PARSER_CHECK_USER - login err\n");
- return 0;
- }
-
- if (strcmp(user->GetProperties().password.Get().c_str(), attr[3]))
- {
- CreateAnswer("Wrong password.");
- printfd(__FILE__, "PARSER_CHECK_USER - passwd err\n");
- return 0;
- }
-
- CreateAnswer(NULL);
- return 0;
- }
- return -1;
-}
-
-int CHECK_USER::End(void *, const char *el)
-{
- if (strcasecmp(el, m_tag.c_str()) == 0)
- return 0;
- return -1;
-}
-
-void CHECK_USER::CreateAnswer(const char * error)
-{
- if (error)
- m_answer = "<" + m_tag + " value=\"Err\" reason=\"" + error + "\"/>";
- else
- m_answer = "<" + m_tag + " value=\"Ok\"/>";
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "parser.h"
-
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/common.h"
-#include "stg/optional.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Users;
-struct User;
-struct Tariffs;
-struct Admin;
-struct Store;
-
-namespace PARSER
-{
-
-class GET_USERS: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_USERS(admin, m_users); }
- static void Register(REGISTRY & registry, Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- Users & m_users;
- };
-
- static const char * tag;
-
- GET_USERS(const Admin & admin, Users & users)
- : BASE_PARSER(admin, tag), m_users(users),
- m_lastUserUpdateTime(0) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- Users & m_users;
- time_t m_lastUserUpdateTime;
-
- void CreateAnswer();
-};
-
-class GET_USER: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(const Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new GET_USER(admin, m_users); }
- static void Register(REGISTRY & registry, const Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- const Users & m_users;
- };
-
- static const char * tag;
-
- GET_USER(const Admin & admin, const Users & users)
- : BASE_PARSER(admin, tag), m_users(users) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- const Users & m_users;
- std::string m_login;
-
- void CreateAnswer();
-};
-
-class ADD_USER: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new ADD_USER(admin, m_users); }
- static void Register(REGISTRY & registry, Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- Users & m_users;
- };
-
- static const char * tag;
-
- ADD_USER(const Admin & admin, Users & users)
- : BASE_PARSER(admin, tag), m_users(users) {}
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- Users & m_users;
- std::string m_login;
-
- void CreateAnswer();
-};
-
-class CHG_USER: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- FACTORY(Users & users, Store & store, const Tariffs & tariffs)
- : m_users(users), m_store(store), m_tariffs(tariffs)
- {}
- virtual BASE_PARSER * create(const Admin & admin) { return new CHG_USER(admin, m_users, m_store, m_tariffs); }
- static void Register(REGISTRY & registry, Users & users, Store & store, const Tariffs & tariffs)
- { registry[ToLower(tag)] = new FACTORY(users, store, tariffs); }
- private:
- Users & m_users;
- Store & m_store;
- const Tariffs & m_tariffs;
- };
-
- static const char * tag;
-
- CHG_USER(const Admin & admin, Users & users,
- Store & store, const Tariffs & tariffs)
- : BASE_PARSER(admin, tag),
- m_users(users),
- m_store(store),
- m_tariffs(tariffs),
- m_cashMustBeAdded(false) {}
-
- int Start(void * data, const char * el, const char ** attr);
-
- private:
- Users & m_users;
- Store & m_store;
- const Tariffs & m_tariffs;
- UserStatOpt m_usr;
- UserConfOpt m_ucr;
- Optional<uint64_t> m_upr[DIR_NUM];
- Optional<uint64_t> m_downr[DIR_NUM];
- std::string m_cashMsg;
- std::string m_login;
- bool m_cashMustBeAdded;
-
- int ApplyChanges();
- void CreateAnswer();
-};
-
-class DEL_USER: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new DEL_USER(admin, m_users); }
- static void Register(REGISTRY & registry, Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- Users & m_users;
- };
-
- static const char * tag;
-
- DEL_USER(const Admin & admin, Users & users)
- : BASE_PARSER(admin, tag), m_users(users), res(0), u(NULL) {}
- int Start(void * data, const char * el, const char ** attr);
- int End(void * data, const char * el);
-
- private:
- Users & m_users;
- int res;
- User * u;
-
- void CreateAnswer();
-};
-
-class CHECK_USER: public BASE_PARSER
-{
- public:
- class FACTORY : public BASE_PARSER::FACTORY
- {
- public:
- explicit FACTORY(const Users & users) : m_users(users) {}
- virtual BASE_PARSER * create(const Admin & admin) { return new CHECK_USER(admin, m_users); }
- static void Register(REGISTRY & registry, const Users & users)
- { registry[ToLower(tag)] = new FACTORY(users); }
- private:
- const Users & m_users;
- };
-
- static const char * tag;
-
- CHECK_USER(const Admin & admin, const Users & users)
- : BASE_PARSER(admin, tag), m_users(users) {}
- int Start(void * data, const char * el, const char ** attr);
- int End(void * data, const char * el);
-
- private:
- const Users & m_users;
-
- void CreateAnswer(const char * error);
- void CreateAnswer() {} // dummy
-};
-
-} // namespace PARSER
-} // namespace STG
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include "stgconfig.h"
-
-#include "stg/common.h"
-
-#include <algorithm>
-#include <csignal>
-#include <cstring>
-#include <cerrno>
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool STG_CONFIG_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
- STG::ParamValue pv;
- std::vector<STG::ParamValue>::const_iterator pvi;
- ///////////////////////////
- pv.param = "Port";
- pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
- if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Port\' is not found.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return false;
- }
- int p;
- if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
- {
- errorStr = "Parameter \'Port\' should be an integral value in range (2, 65535). Actual value: '" + pvi->value[0] + "'.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return false;
- }
- m_port = static_cast<uint16_t>(p);
-
- pv.param = "BindAddress";
- pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
- if (pvi != s.moduleParams.end() && !pvi->value.empty())
- m_bindAddress = pvi->value[0];
-
- return true;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-extern "C" STG::Plugin * GetPlugin()
-{
- static STG_CONFIG plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-STG_CONFIG::STG_CONFIG()
- : nonstop(false),
- isRunning(false),
- logger(STG::PluginLogger::get("conf_sg")),
- config(logger)
-{
-}
-//-----------------------------------------------------------------------------
-int STG_CONFIG::ParseSettings()
-{
- if (stgConfigSettings.ParseSettings(settings))
- return 0;
- errorStr = stgConfigSettings.GetStrError();
- return -1;
-}
-//-----------------------------------------------------------------------------
-int STG_CONFIG::Start()
-{
- if (isRunning)
- return 0;
-
- nonstop = true;
-
- config.SetPort(stgConfigSettings.GetPort());
- config.SetBindAddress(stgConfigSettings.GetBindAddress());
-
- if (config.Prepare())
- {
- errorStr = config.GetStrError();
- return -1;
- }
-
- if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = std::string("Cannot create thread: '") + strerror(errno) + "'.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- logger(errorStr);
- return -1;
- }
-
- return 0;
-}
-//-----------------------------------------------------------------------------
-int STG_CONFIG::Stop()
-{
- if (!isRunning)
- return 0;
-
- config.Stop();
-
- //5 seconds to thread stops itself
- for (size_t i = 0; i < 25; ++i)
- {
- if (!isRunning)
- break;
-
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
-
- if (isRunning)
- return -1;
-
- return 0;
-}
-//-----------------------------------------------------------------------------
-void * STG_CONFIG::Run(void * d)
-{
- sigset_t signalSet;
- sigfillset(&signalSet);
- pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
- STG_CONFIG & stgConf = *static_cast<STG_CONFIG *>(d);
- stgConf.isRunning = true;
-
- stgConf.config.Run();
-
- stgConf.isRunning = false;
-
- return NULL;
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "configproto.h"
-
-#include "stg/plugin.h"
-#include "stg/logger.h"
-
-#include <string>
-
-#include <pthread.h>
-
-class STG_CONFIG_SETTINGS
-{
- public:
- STG_CONFIG_SETTINGS() : m_port(0), m_bindAddress("0.0.0.0") {}
- const std::string & GetStrError() const { return errorStr; }
- bool ParseSettings(const STG::ModuleSettings & s);
- uint16_t GetPort() const { return m_port; }
- const std::string & GetBindAddress() const { return m_bindAddress; }
- private:
- std::string errorStr;
- uint16_t m_port;
- std::string m_bindAddress;
-};
-
-class STG_CONFIG : public STG::Plugin
-{
- public:
- STG_CONFIG();
-
- void SetUsers(STG::Users * users) override { config.SetUsers(users); }
- void SetTariffs(STG::Tariffs * tariffs) override { config.SetTariffs(tariffs); }
- void SetAdmins(STG::Admins * admins) override { config.SetAdmins(admins); }
- void SetServices(STG::Services * services) override { config.SetServices(services); }
- void SetCorporations(STG::Corporations * corporations) override { config.SetCorporations( corporations); }
- void SetStore(STG::Store * store) override { config.SetStore(store); }
- void SetStgSettings(const STG::Settings * s) override { config.SetSettings(s); }
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override { return isRunning; }
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override { return "Stg Configurator v. 2.0"; }
- uint16_t GetStartPosition() const override { return 20; }
- uint16_t GetStopPosition() const override { return 20; }
-
- private:
- STG_CONFIG(const STG_CONFIG & rvalue);
- STG_CONFIG & operator=(const STG_CONFIG & rvalue);
-
- static void * Run(void *);
-
- mutable std::string errorStr;
- STG_CONFIG_SETTINGS stgConfigSettings;
- pthread_t thread;
- bool nonstop;
- bool isRunning;
- STG::PluginLogger logger;
- CONFIGPROTO config;
- STG::ModuleSettings settings;
-};
+++ /dev/null
-#include "ping.h"
-
-#include "stg/user.h"
-#include "stg/locker.h"
-#include "stg/user_property.h"
-
-#include <cstdio>
-#include <cassert>
-#include <csignal>
-#include <ctime>
-#include <algorithm>
-
-namespace
-{
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-template <typename varType>
-class HAS_USER: public std::binary_function<varType, UserPtr, bool>
-{
-public:
- explicit HAS_USER(const UserPtr & u) : user(u) {}
- bool operator()(varType notifier) const
- {
- return notifier.GetUser() == user;
- }
-private:
- const UserPtr & user;
-};
-}
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static PING plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-int PING_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-STG::ParamValue pv;
-std::vector<STG::ParamValue>::const_iterator pvi;
-
-pv.param = "PingDelay";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'PingDelay\' not found.";
- printfd(__FILE__, "Parameter 'PingDelay' not found\n");
- return -1;
- }
-if (ParseIntInRange(pvi->value[0], 5, 3600, &pingDelay))
- {
- errorStr = "Cannot parse parameter \'PingDelay\': " + errorStr;
- printfd(__FILE__, "Canot parse parameter 'PingDelay'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-PING::PING()
- : users(NULL),
- nonstop(false),
- isRunning(false),
- onAddUserNotifier(*this),
- onDelUserNotifier(*this),
- logger(STG::PluginLogger::get("ping"))
-{
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-PING::~PING()
-{
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-int PING::ParseSettings()
-{
-int ret = pingSettings.ParseSettings(settings);
-if (ret)
- errorStr = pingSettings.GetStrError();
-return ret;
-}
-//-----------------------------------------------------------------------------
-int PING::Start()
-{
-GetUsers();
-
-users->AddNotifierUserAdd(&onAddUserNotifier);
-users->AddNotifierUserDel(&onDelUserNotifier);
-
-nonstop = true;
-
-pinger.SetDelayTime(pingSettings.GetPingDelay());
-pinger.Start();
-
-if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot start thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot start thread\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int PING::Stop()
-{
-STG_LOCKER lock(&mutex);
-
-if (!isRunning)
- return 0;
-
-pinger.Stop();
-nonstop = false;
-//5 seconds to thread stops itself
-struct timespec ts = {0, 200000000};
-for (int i = 0; i < 25; i++)
- {
- if (!isRunning)
- break;
-
- nanosleep(&ts, NULL);
- }
-
-users->DelNotifierUserAdd(&onAddUserNotifier);
-users->DelNotifierUserDel(&onDelUserNotifier);
-
-std::list<UserPtr>::iterator users_iter;
-users_iter = usersList.begin();
-while (users_iter != usersList.end())
- {
- UnSetUserNotifiers(*users_iter);
- ++users_iter;
- }
-
-if (isRunning)
- return -1;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-bool PING::IsRunning()
-{
-return isRunning;
-}
-//-----------------------------------------------------------------------------
-void * PING::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-PING * ping = static_cast<PING *>(d);
-ping->isRunning = true;
-
-long delay = (10000000 * ping->pingSettings.GetPingDelay()) / 3 + 50000000;
-
-while (ping->nonstop)
- {
- std::list<UserPtr>::iterator iter = ping->usersList.begin();
- {
- STG_LOCKER lock(&ping->mutex);
- while (iter != ping->usersList.end())
- {
- if ((*iter)->GetProperties().ips.ConstData().onlyOneIP())
- {
- uint32_t ip = (*iter)->GetProperties().ips.ConstData()[0].ip;
- time_t t;
- if (ping->pinger.GetIPTime(ip, &t) == 0)
- {
- if (t)
- (*iter)->UpdatePingTime(t);
- }
- }
- else
- {
- uint32_t ip = (*iter)->GetCurrIP();
- if (ip)
- {
- time_t t;
- if (ping->pinger.GetIPTime(ip, &t) == 0)
- {
- if (t)
- (*iter)->UpdatePingTime(t);
- }
- }
- }
- ++iter;
- }
- }
- struct timespec ts = {delay / 1000000000, delay % 1000000000};
- for (int i = 0; i < 100; i++)
- {
- if (ping->nonstop)
- {
- nanosleep(&ts, NULL);
- }
- }
- }
-
-ping->isRunning = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void PING::SetUserNotifiers(UserPtr u)
-{
-CHG_CURRIP_NOTIFIER_PING ChgCurrIPNotifier(*this, u);
-CHG_IPS_NOTIFIER_PING ChgIPNotifier(*this, u);
-
-ChgCurrIPNotifierList.push_front(ChgCurrIPNotifier);
-ChgIPNotifierList.push_front(ChgIPNotifier);
-
-u->AddCurrIPAfterNotifier(&(*ChgCurrIPNotifierList.begin()));
-u->GetProperties().ips.AddAfterNotifier(&(*ChgIPNotifierList.begin()));
-}
-//-----------------------------------------------------------------------------
-void PING::UnSetUserNotifiers(UserPtr u)
-{
-// --- CurrIP ---
-HAS_USER<CHG_CURRIP_NOTIFIER_PING> IsContainsUserCurrIP(u);
-HAS_USER<CHG_IPS_NOTIFIER_PING> IsContainsUserIP(u);
-
-std::list<CHG_CURRIP_NOTIFIER_PING>::iterator currIPter;
-std::list<CHG_IPS_NOTIFIER_PING>::iterator IPIter;
-
-currIPter = find_if(ChgCurrIPNotifierList.begin(),
- ChgCurrIPNotifierList.end(),
- IsContainsUserCurrIP);
-
-if (currIPter != ChgCurrIPNotifierList.end())
- {
- currIPter->GetUser()->DelCurrIPAfterNotifier(&(*currIPter));
- ChgCurrIPNotifierList.erase(currIPter);
- }
-// --- CurrIP end ---
-
-// --- IP ---
-IPIter = find_if(ChgIPNotifierList.begin(),
- ChgIPNotifierList.end(),
- IsContainsUserIP);
-
-if (IPIter != ChgIPNotifierList.end())
- {
- IPIter->GetUser()->GetProperties().ips.DelAfterNotifier(&(*IPIter));
- ChgIPNotifierList.erase(IPIter);
- }
-// --- IP end ---
-}
-//-----------------------------------------------------------------------------
-void PING::GetUsers()
-{
-STG_LOCKER lock(&mutex);
-
-UserPtr u;
-int h = users->OpenSearch();
-assert(h && "USERS::OpenSearch is always correct");
-
-while (users->SearchNext(h, &u) == 0)
- {
- usersList.push_back(u);
- SetUserNotifiers(u);
- if (u->GetProperties().ips.ConstData().onlyOneIP())
- {
- pinger.AddIP(u->GetProperties().ips.ConstData()[0].ip);
- }
- else
- {
- uint32_t ip = u->GetCurrIP();
- if (ip)
- pinger.AddIP(ip);
- }
- }
-
-users->CloseSearch(h);
-}
-//-----------------------------------------------------------------------------
-void PING::AddUser(UserPtr u)
-{
-STG_LOCKER lock(&mutex);
-
-SetUserNotifiers(u);
-usersList.push_back(u);
-}
-//-----------------------------------------------------------------------------
-void PING::DelUser(UserPtr u)
-{
-STG_LOCKER lock(&mutex);
-
-UnSetUserNotifiers(u);
-
-std::list<UserPtr>::iterator users_iter;
-users_iter = usersList.begin();
-
-while (users_iter != usersList.end())
- {
- if (u == *users_iter)
- {
- usersList.erase(users_iter);
- break;
- }
- ++users_iter;
- }
-}
-//-----------------------------------------------------------------------------
-void CHG_CURRIP_NOTIFIER_PING::Notify(const uint32_t & oldIP, const uint32_t & newIP)
-{
-ping.pinger.DelIP(oldIP);
-if (newIP)
- ping.pinger.AddIP(newIP);
-}
-//-----------------------------------------------------------------------------
-void CHG_IPS_NOTIFIER_PING::Notify(const STG::UserIPs & oldIPS, const STG::UserIPs & newIPS)
-{
-if (oldIPS.onlyOneIP())
- ping.pinger.DelIP(oldIPS[0].ip);
-
-if (newIPS.onlyOneIP())
- ping.pinger.AddIP(newIPS[0].ip);
-}
-//-----------------------------------------------------------------------------
-void ADD_USER_NONIFIER_PING::Notify(const UserPtr & user)
-{
-ping.AddUser(user);
-}
-//-----------------------------------------------------------------------------
-void DEL_USER_NONIFIER_PING::Notify(const UserPtr & user)
-{
-ping.DelUser(user);
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/notifer.h"
-#include "stg/user_ips.h"
-#include "stg/pinger.h"
-#include "stg/users.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <list>
-#include <cstdint>
-
-#include <pthread.h>
-
-class PING;
-
-namespace STG
-{
-struct USER;
-struct SETTINGS;
-}
-
-using UserPtr = STG::User*;
-//-----------------------------------------------------------------------------*/
-class CHG_CURRIP_NOTIFIER_PING: public STG::PropertyNotifierBase<uint32_t> {
-public:
- CHG_CURRIP_NOTIFIER_PING(const PING & p, UserPtr u)
- : user(u), ping(p) {}
- void Notify(const uint32_t & oldIP, const uint32_t & newIP);
- UserPtr GetUser() const { return user; }
-
-private:
- CHG_CURRIP_NOTIFIER_PING & operator=(const CHG_CURRIP_NOTIFIER_PING &);
-
- UserPtr user;
- const PING & ping;
-};
-//-----------------------------------------------------------------------------
-class CHG_IPS_NOTIFIER_PING: public STG::PropertyNotifierBase<STG::UserIPs> {
-public:
- CHG_IPS_NOTIFIER_PING(const PING & p, UserPtr u)
- : user(u), ping(p) {}
- void Notify(const STG::UserIPs & oldIPS, const STG::UserIPs & newIPS);
- UserPtr GetUser() const { return user; }
-
-private:
- CHG_IPS_NOTIFIER_PING & operator=(const CHG_IPS_NOTIFIER_PING &);
-
- UserPtr user;
- const PING & ping;
-};
-//-----------------------------------------------------------------------------
-class ADD_USER_NONIFIER_PING: public STG::NotifierBase<UserPtr> {
-public:
- explicit ADD_USER_NONIFIER_PING(PING & p) : ping(p) {}
- void Notify(const UserPtr & user);
-
-private:
- ADD_USER_NONIFIER_PING(const ADD_USER_NONIFIER_PING &);
- ADD_USER_NONIFIER_PING & operator=(const ADD_USER_NONIFIER_PING &);
-
- PING & ping;
-};
-//-----------------------------------------------------------------------------
-class DEL_USER_NONIFIER_PING: public STG::NotifierBase<UserPtr> {
-public:
- explicit DEL_USER_NONIFIER_PING(PING & p) : ping(p) {}
- void Notify(const UserPtr & user);
-
-private:
- DEL_USER_NONIFIER_PING(const DEL_USER_NONIFIER_PING &);
- DEL_USER_NONIFIER_PING & operator=(const DEL_USER_NONIFIER_PING &);
-
- PING & ping;
-};
-//-----------------------------------------------------------------------------
-class PING_SETTINGS {
-public:
- PING_SETTINGS() : pingDelay(0) {}
- const std::string & GetStrError() const { return errorStr; }
- int ParseSettings(const STG::ModuleSettings & s);
- int GetPingDelay() const { return pingDelay; }
-private:
- int pingDelay;
- mutable std::string errorStr;
-};
-//-----------------------------------------------------------------------------
-class PING : public STG::Plugin {
-friend class CHG_CURRIP_NOTIFIER_PING;
-friend class CHG_IPS_NOTIFIER_PING;
-public:
- PING();
- ~PING() override;
-
- void SetUsers(STG::Users * u) override { users = u; }
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & /*ms*/) override { return 0; }
- bool IsRunning() override;
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override { return "Pinger v.1.01"; }
- uint16_t GetStartPosition() const override { return 10; }
- uint16_t GetStopPosition() const override { return 10; }
-
- void AddUser(UserPtr u);
- void DelUser(UserPtr u);
-
-private:
- explicit PING(const PING & rvalue);
- PING & operator=(const PING & rvalue);
-
- void GetUsers();
- void SetUserNotifiers(UserPtr u);
- void UnSetUserNotifiers(UserPtr u);
- static void * Run(void * d);
-
- mutable std::string errorStr;
- PING_SETTINGS pingSettings;
- STG::ModuleSettings settings;
- STG::Users * users;
- std::list<UserPtr> usersList;
-
- pthread_t thread;
- pthread_mutex_t mutex;
- bool nonstop;
- bool isRunning;
- mutable STG_PINGER pinger;
-
- std::list<CHG_CURRIP_NOTIFIER_PING> ChgCurrIPNotifierList;
- std::list<CHG_IPS_NOTIFIER_PING> ChgIPNotifierList;
-
- ADD_USER_NONIFIER_PING onAddUserNotifier;
- DEL_USER_NONIFIER_PING onDelUserNotifier;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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>
- */
-
- /*
- $Revision: 1.8 $
- $Author: faust $
- $Date: 2009/10/22 09:58:53 $
- */
-
-#include <fstream>
-#include <cerrno>
-#include <cstring>
-#include <algorithm>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include "stg/common.h"
-#include "nrmap_parser.h"
-
-bool NRMapParser::ReadFile(const std::string & fileName)
-{
-std::ifstream source(fileName.c_str());
-
-if (!source)
- {
- errorStr = "Error opening file ";
- errorStr += fileName;
- printfd(__FILE__, "NRMapParser::ReadFile(): %s\n", errorStr.c_str());
- return true;
- }
-
-int lineNumber = 0;
-std::string line;
-std::vector<NET_ROUTER> _nrmap;
-
-while (getline(source, line))
- {
- ++lineNumber;
- NET_ROUTER nr;
-
- if (Trim(line) == "")
- {
- continue;
- }
-
- if (ParseLine(line, nr))
- {
- printfd(__FILE__, "NRMapParser::ReadFile(): Error parsing line %d: '%s'\n", lineNumber, errorStr.c_str());
- return true;
- }
-
- _nrmap.push_back(nr);
- }
-
-nrmap = _nrmap;
-
-return false;
-}
-
-bool NRMapParser::ParseLine(const std::string & line, NET_ROUTER & nr) const
-{
-// xxx.xxx.xxx.xxx/yy zzz.zzz.zzz.zzz
-size_t pos = line.find_first_of(" \t");
-
-if (pos == std::string::npos)
- {
- errorStr = "No space between subnet and router";
- return true;
- }
-
-std::string subnet(line.substr(0, pos)); // xxx.xxx.xxx.xxx/yy
-
-uint32_t ip = 0;
-uint32_t mask = 0;
-
-if (ParseNet(subnet, ip, mask))
- {
- return true;
- }
-
-nr.subnetIP = ip;
-nr.subnetMask = mask;
-
-pos = line.find_first_not_of(" \t", pos);
-
-if (pos == std::string::npos)
- {
- errorStr = "No router address found";
- return true;
- }
-
-size_t pos2 = line.find_first_of(" \t", pos);
-
-std::string router(line.substr(pos, pos2 == std::string::npos ? line.length() - pos2 - 1 : pos2 - pos)); //zzz.zzz.zzz.zzz
-
-uint32_t routerIP;
-
-if (ParseRouter(router, routerIP))
- {
- return true;
- }
-
-std::vector<uint32_t>::iterator it;
-
-it = std::lower_bound(
- nr.routers.begin(),
- nr.routers.end(),
- routerIP
- );
-nr.routers.insert(it, routerIP);
-
-//nr.routers.push_back(routerIP);
-
-while (pos2 != std::string::npos)
- {
- pos = line.find_first_not_of(" \t", pos2);
-
- if (pos == std::string::npos)
- {
- return false;
- }
-
- pos2 = line.find_first_of(" \t", pos);
-
- if (ParseRouter(line.substr(
- pos,
- pos2 == std::string::npos ? line.length() - pos2 - 1 : pos2 - pos),
- routerIP))
- {
- return true;
- }
-
- it = std::lower_bound(
- nr.routers.begin(),
- nr.routers.end(),
- routerIP
- );
- nr.routers.insert(it, routerIP);
-
- //nr.routers.push_back(routerIP);
-
- }
-
-return false;
-}
-
-bool NRMapParser::ParseNet(const std::string & line, uint32_t & ip, uint32_t & mask) const
-{
-// xxx.xxx.xxx.xxx/yy
-
-size_t pos = line.find_first_of('/');
-
-if (pos == std::string::npos)
- {
- errorStr = "Subnet is not in CIDR notation";
- return true;
- }
-
-int res = inet_pton(AF_INET, line.substr(0, pos).c_str(), &ip); //xxx.xxx.xxx.xxx
-
-if (res < 0)
- {
- errorStr = strerror(errno);
- return true;
- }
-else if (res == 0)
- {
- errorStr = "Invalid subnet address";
- return true;
- }
-
-if (str2x(line.substr(pos + 1, line.length() - pos - 1), mask)) //yy
- {
- errorStr = "Invalid subnet mask";
- return true;
- }
-if (mask > 32)
- {
- errorStr = "Subnet mask is out of range [0..32]";
- return true;
- }
-mask = htonl(0xffFFffFF << (32 - mask)); //bitmask
-
-return false;
-}
-
-bool NRMapParser::ParseRouter(const std::string & line, uint32_t & ip) const
-{
-int res = inet_pton(AF_INET, line.c_str(), &ip); //zzz.zzz.zzz.zzz
-
-if (res < 0)
- {
- errorStr = strerror(errno);
- return true;
- }
-else if (res == 0)
- {
- printfd(__FILE__, "NRMapParser::ParseRouter(): IP '%s' is invalid\n", line.c_str());
- errorStr = "Invalid router address";
- return true;
- }
-return false;
-}
+++ /dev/null
-/*
- * 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>
- */
-
- /*
- $Revision: 1.2 $
- $Author: faust $
- $Date: 2009/09/23 12:51:42 $
- */
-
-#ifndef __NRMAP_PARSER_H__
-#define __NRMAP_PARSER_H__
-
-#include <string>
-#include <vector>
-#include <cstdint>
-
-struct NET_ROUTER
-{
- NET_ROUTER() : subnetIP(0), subnetMask(0), routers() {}
- NET_ROUTER(const NET_ROUTER & rvalue)
- : subnetIP(rvalue.subnetIP),
- subnetMask(rvalue.subnetMask),
- routers(rvalue.routers)
- {}
-
- uint32_t subnetIP;
- uint32_t subnetMask;
- std::vector<uint32_t> routers;
-
- NET_ROUTER & operator=(const NET_ROUTER & rvalue)
- {
- subnetIP = rvalue.subnetIP;
- subnetMask = rvalue.subnetMask;
- routers = rvalue.routers;
- return *this;
- }
-};
-
-class NRMapParser {
-public:
- NRMapParser() : nrmap(), errorStr() {}
- ~NRMapParser() {}
-
- bool ReadFile(const std::string & fileName);
- const std::vector<NET_ROUTER> & GetMap() const { return nrmap; }
- const std::string & GetErrorStr() const { return errorStr; }
-
-private:
- NRMapParser(const NRMapParser & rvalue);
- NRMapParser & operator=(const NRMapParser & rvalue);
-
- std::vector<NET_ROUTER> nrmap;
- mutable std::string errorStr;
-
- bool ParseLine(const std::string & line, NET_ROUTER & nr) const;
- bool ParseNet(const std::string & line, uint32_t & ip, uint32_t & mask) const;
- bool ParseRouter(const std::string & line, uint32_t & ip) const;
-};
-
-#endif
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#include "rscript.h"
-
-#include "ur_functor.h"
-#include "send_functor.h"
-
-#include "stg/common.h"
-#include "stg/locker.h"
-#include "stg/users.h"
-#include "stg/user_property.h"
-#include "stg/logger.h"
-
-#include <algorithm>
-
-#include <csignal>
-#include <cassert>
-#include <cstdlib>
-#include <cerrno>
-#include <cstring>
-
-#include <sys/time.h>
-#include <netinet/ip.h>
-
-#define RS_DEBUG (1)
-#define MAX_SHORT_PCKT (3)
-
-extern volatile time_t stgTime;
-
-using RS::REMOTE_SCRIPT;
-
-namespace {
-
-template<typename T>
-struct USER_IS
-{
- explicit USER_IS(RS::UserPtr u) : user(u) {}
- bool operator()(const T & notifier) { return notifier.GetUser() == user; }
-
- RS::UserPtr user;
-};
-
-} // namespace anonymous
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static REMOTE_SCRIPT plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-RS::SETTINGS::SETTINGS()
- : sendPeriod(0),
- port(0)
-{
-}
-//-----------------------------------------------------------------------------
-int RS::SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-int p;
-STG::ParamValue pv;
-std::vector<STG::ParamValue>::const_iterator pvi;
-netRouters.clear();
-///////////////////////////
-pv.param = "Port";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Port\' not found.";
- printfd(__FILE__, "Parameter 'Port' not found\n");
- return -1;
- }
-if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
- {
- errorStr = "Cannot parse parameter \'Port\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'Port'\n");
- return -1;
- }
-port = static_cast<uint16_t>(p);
-///////////////////////////
-pv.param = "SendPeriod";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'SendPeriod\' not found.";
- printfd(__FILE__, "Parameter 'SendPeriod' not found\n");
- return -1;
- }
-
-if (ParseIntInRange(pvi->value[0], 5, 600, &sendPeriod))
- {
- errorStr = "Cannot parse parameter \'SendPeriod\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'SendPeriod'\n");
- return -1;
- }
-///////////////////////////
-pv.param = "UserParams";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'UserParams\' not found.";
- printfd(__FILE__, "Parameter 'UserParams' not found\n");
- return -1;
- }
-userParams = pvi->value;
-///////////////////////////
-pv.param = "Password";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Password\' not found.";
- printfd(__FILE__, "Parameter 'Password' not found\n");
- return -1;
- }
-password = pvi->value[0];
-///////////////////////////
-pv.param = "SubnetFile";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'SubnetFile\' not found.";
- printfd(__FILE__, "Parameter 'SubnetFile' not found\n");
- return -1;
- }
-subnetFile = pvi->value[0];
-
-NRMapParser nrMapParser;
-
-if (!nrMapParser.ReadFile(subnetFile))
- {
- netRouters = nrMapParser.GetMap();
- }
-else
- {
- STG::PluginLogger::get("rscript")("mod_rscript: error opening subnets file '%s'", subnetFile.c_str());
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-REMOTE_SCRIPT::REMOTE_SCRIPT()
- : sendPeriod(15),
- halfPeriod(8),
- nonstop(false),
- isRunning(false),
- users(NULL),
- sock(0),
- onAddUserNotifier(*this),
- onDelUserNotifier(*this),
- logger(STG::PluginLogger::get("rscript"))
-{
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-REMOTE_SCRIPT::~REMOTE_SCRIPT()
-{
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-void * REMOTE_SCRIPT::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-REMOTE_SCRIPT * rs = static_cast<REMOTE_SCRIPT *>(d);
-
-rs->isRunning = true;
-
-while (rs->nonstop)
- {
- rs->PeriodicSend();
- sleep(2);
- }
-
-rs->isRunning = false;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int REMOTE_SCRIPT::ParseSettings()
-{
-int ret = rsSettings.ParseSettings(settings);
-if (ret)
- errorStr = rsSettings.GetStrError();
-
-sendPeriod = rsSettings.GetSendPeriod();
-halfPeriod = sendPeriod / 2;
-
-return ret;
-}
-//-----------------------------------------------------------------------------
-int REMOTE_SCRIPT::Start()
-{
-netRouters = rsSettings.GetSubnetsMap();
-
-InitEncrypt(&ctx, rsSettings.GetPassword());
-
-users->AddNotifierUserAdd(&onAddUserNotifier);
-users->AddNotifierUserDel(&onDelUserNotifier);
-
-nonstop = true;
-
-if (GetUsers())
- {
- return -1;
- }
-
-if (PrepareNet())
- {
- return -1;
- }
-
-if (!isRunning)
- {
- if (pthread_create(&thread, NULL, Run, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
- }
-
-errorStr = "";
-return 0;
-}
-//-----------------------------------------------------------------------------
-int REMOTE_SCRIPT::Stop()
-{
-if (!IsRunning())
- return 0;
-
-nonstop = false;
-
-std::for_each(
- authorizedUsers.begin(),
- authorizedUsers.end(),
- DisconnectUser(*this)
- );
-
-FinalizeNet();
-
-if (isRunning)
- {
- //5 seconds to thread stops itself
- for (int i = 0; i < 25 && isRunning; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- }
-
-users->DelNotifierUserDel(&onDelUserNotifier);
-users->DelNotifierUserAdd(&onAddUserNotifier);
-
-if (isRunning)
- {
- logger("Cannot stop thread.");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int REMOTE_SCRIPT::Reload(const STG::ModuleSettings & /*ms*/)
-{
-NRMapParser nrMapParser;
-
-if (nrMapParser.ReadFile(rsSettings.GetMapFileName()))
- {
- errorStr = nrMapParser.GetErrorStr();
- logger("Map file reading error: %s", errorStr.c_str());
- return -1;
- }
-
- {
- STG_LOCKER lock(&mutex);
-
- printfd(__FILE__, "REMOTE_SCRIPT::Reload()\n");
-
- netRouters = nrMapParser.GetMap();
- }
-
-std::for_each(authorizedUsers.begin(),
- authorizedUsers.end(),
- UpdateRouter(*this));
-
-logger("%s reloaded successfully.", rsSettings.GetMapFileName().c_str());
-printfd(__FILE__, "REMOTE_SCRIPT::Reload() %s reloaded successfully.\n");
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-bool REMOTE_SCRIPT::PrepareNet()
-{
-sock = socket(AF_INET, SOCK_DGRAM, 0);
-
-if (sock < 0)
- {
- errorStr = "Cannot create socket.";
- logger("Canot create a socket: %s", strerror(errno));
- printfd(__FILE__, "Cannot create socket\n");
- return true;
- }
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool REMOTE_SCRIPT::FinalizeNet()
-{
-close(sock);
-return false;
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::PeriodicSend()
-{
-STG_LOCKER lock(&mutex);
-
-std::map<uint32_t, RS::USER>::iterator it(authorizedUsers.begin());
-while (it != authorizedUsers.end())
- {
- if (difftime(stgTime, it->second.lastSentTime) - (rand() % halfPeriod) > sendPeriod)
- {
- Send(it->second);
- }
- ++it;
- }
-}
-//-----------------------------------------------------------------------------
-#ifdef NDEBUG
-bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t, RS::USER & rsu, bool forceDisconnect) const
-#else
-bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t bufSize, RS::USER & rsu, bool forceDisconnect) const
-#endif
-{
-RS::PACKET_HEADER packetHead;
-
-memset(packetHead.padding, 0, sizeof(packetHead.padding));
-strcpy((char*)packetHead.magic, RS_ID);
-packetHead.protoVer[0] = '0';
-packetHead.protoVer[1] = '2';
-if (forceDisconnect)
- {
- packetHead.packetType = RS_DISCONNECT_PACKET;
- printfd(__FILE__, "RSCRIPT: force disconnect for '%s'\n", rsu.user->GetLogin().c_str());
- }
-else
- {
- if (rsu.shortPacketsCount % MAX_SHORT_PCKT == 0)
- {
- //SendLong
- packetHead.packetType = rsu.user->IsInetable() ? RS_CONNECT_PACKET : RS_DISCONNECT_PACKET;
- if (rsu.user->IsInetable())
- printfd(__FILE__, "RSCRIPT: connect for '%s'\n", rsu.user->GetLogin().c_str());
- else
- printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
- }
- else
- {
- //SendShort
- packetHead.packetType = rsu.user->IsInetable() ? RS_ALIVE_PACKET : RS_DISCONNECT_PACKET;
- if (rsu.user->IsInetable())
- printfd(__FILE__, "RSCRIPT: alive for '%s'\n", rsu.user->GetLogin().c_str());
- else
- printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
- }
- }
-rsu.shortPacketsCount++;
-rsu.lastSentTime = stgTime;
-
-packetHead.ip = htonl(rsu.ip);
-packetHead.id = htonl(rsu.user->GetID());
-strncpy((char*)packetHead.login, rsu.user->GetLogin().c_str(), RS_LOGIN_LEN);
-packetHead.login[RS_LOGIN_LEN - 1] = 0;
-
-memcpy(buf, &packetHead, sizeof(packetHead));
-
-if (packetHead.packetType == RS_ALIVE_PACKET)
- {
- return false;
- }
-
-RS::PACKET_TAIL packetTail;
-
-memset(packetTail.padding, 0, sizeof(packetTail.padding));
-strcpy((char*)packetTail.magic, RS_ID);
-std::vector<std::string>::const_iterator it;
-std::string params;
-for(it = rsSettings.GetUserParams().begin();
- it != rsSettings.GetUserParams().end();
- ++it)
- {
- std::string parameter(rsu.user->GetParamValue(it->c_str()));
- if (params.length() + parameter.length() > RS_PARAMS_LEN - 1)
- {
- logger("Script params string length %d exceeds the limit of %d symbols.", params.length() + parameter.length(), RS_PARAMS_LEN);
- break;
- }
- params += parameter + " ";
- }
-strncpy((char *)packetTail.params, params.c_str(), RS_PARAMS_LEN);
-packetTail.params[RS_PARAMS_LEN - 1] = 0;
-
-assert(sizeof(packetHead) + sizeof(packetTail) <= bufSize && "Insufficient buffer space");
-
-Encrypt(&ctx, buf + sizeof(packetHead), (char *)&packetTail, sizeof(packetTail) / 8);
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool REMOTE_SCRIPT::Send(RS::USER & rsu, bool forceDisconnect) const
-{
-char buffer[RS_MAX_PACKET_LEN];
-
-memset(buffer, 0, sizeof(buffer));
-
-if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
- {
- printfd(__FILE__, "REMOTE_SCRIPT::Send() - Invalid packet length!\n");
- return true;
- }
-
-std::for_each(
- rsu.routers.begin(),
- rsu.routers.end(),
- PacketSender(sock, buffer, sizeof(buffer), static_cast<uint16_t>(htons(rsSettings.GetPort())))
- );
-
-return false;
-}
-//-----------------------------------------------------------------------------
-bool REMOTE_SCRIPT::SendDirect(RS::USER & rsu, uint32_t routerIP, bool forceDisconnect) const
-{
-char buffer[RS_MAX_PACKET_LEN];
-
-if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
- {
- printfd(__FILE__, "REMOTE_SCRIPT::SendDirect() - Invalid packet length!\n");
- return true;
- }
-
-struct sockaddr_in sendAddr;
-
-sendAddr.sin_family = AF_INET;
-sendAddr.sin_port = static_cast<uint16_t>(htons(rsSettings.GetPort()));
-sendAddr.sin_addr.s_addr = routerIP;
-
-ssize_t res = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&sendAddr, sizeof(sendAddr));
-
-if (res < 0)
- logger("sendto error: %s", strerror(errno));
-
-return (res != sizeof(buffer));
-}
-//-----------------------------------------------------------------------------
-bool REMOTE_SCRIPT::GetUsers()
-{
-UserPtr u;
-
-int h = users->OpenSearch();
-assert(h && "USERS::OpenSearch is always correct");
-
-while (!users->SearchNext(h, &u))
- {
- SetUserNotifiers(u);
- }
-
-users->CloseSearch(h);
-return false;
-}
-//-----------------------------------------------------------------------------
-std::vector<uint32_t> REMOTE_SCRIPT::IP2Routers(uint32_t ip)
-{
-STG_LOCKER lock(&mutex);
-for (size_t i = 0; i < netRouters.size(); ++i)
- {
- if ((ip & netRouters[i].subnetMask) == (netRouters[i].subnetIP & netRouters[i].subnetMask))
- {
- return netRouters[i].routers;
- }
- }
-return std::vector<uint32_t>();
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::SetUserNotifiers(UserPtr u)
-{
-ipNotifierList.push_front(RS::IP_NOTIFIER(*this, u));
-connNotifierList.push_front(RS::CONNECTED_NOTIFIER(*this, u));
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::UnSetUserNotifiers(UserPtr u)
-{
-ipNotifierList.erase(std::remove_if(ipNotifierList.begin(),
- ipNotifierList.end(),
- USER_IS<IP_NOTIFIER>(u)),
- ipNotifierList.end());
-connNotifierList.erase(std::remove_if(connNotifierList.begin(),
- connNotifierList.end(),
- USER_IS<CONNECTED_NOTIFIER>(u)),
- connNotifierList.end());
-
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::AddRSU(UserPtr user)
-{
-RS::USER rsu(IP2Routers(user->GetCurrIP()), user);
-Send(rsu);
-
-STG_LOCKER lock(&mutex);
-authorizedUsers.insert(std::make_pair(user->GetCurrIP(), rsu));
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::DelRSU(UserPtr user)
-{
-STG_LOCKER lock(&mutex);
-std::map<uint32_t, RS::USER>::iterator it(authorizedUsers.begin());
-while (it != authorizedUsers.end())
- {
- if (it->second.user == user)
- {
- Send(it->second, true);
- authorizedUsers.erase(it);
- return;
- }
- ++it;
- }
-/*const std::map<uint32_t, RS::USER>::iterator it(
- authorizedUsers.find(user->GetCurrIP())
- );
-if (it != authorizedUsers.end())
- {
- Send(it->second, true);
- authorizedUsers.erase(it);
- }*/
-}
-//-----------------------------------------------------------------------------
-void RS::IP_NOTIFIER::Notify(const uint32_t & /*oldValue*/, const uint32_t & newValue)
-{
-if (newValue)
- rs.AddRSU(user);
-else
- rs.DelRSU(user);
-}
-//-----------------------------------------------------------------------------
-void RS::CONNECTED_NOTIFIER::Notify(const bool & /*oldValue*/, const bool & newValue)
-{
-if (newValue)
- rs.AddRSU(user);
-else
- rs.DelRSU(user);
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) const
-{
-unsigned char keyL[PASSWD_LEN]; // Пароль для шифровки
-memset(keyL, 0, PASSWD_LEN);
-strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
-Blowfish_Init(ctx, keyL, PASSWD_LEN);
-}
-//-----------------------------------------------------------------------------
-void REMOTE_SCRIPT::Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, size_t len8) const
-{
-if (dst != src)
- memcpy(dst, src, len8 * 8);
-for (size_t i = 0; i < len8; ++i)
- Blowfish_Encrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- * Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/notifer.h"
-#include "stg/user.h"
-#include "stg/blowfish.h"
-#include "stg/rs_packets.h"
-#include "stg/logger.h"
-
-#include "nrmap_parser.h"
-
-#include <string>
-#include <list>
-#include <map>
-#include <functional>
-#include <utility>
-#include <cstdint>
-
-#include <pthread.h>
-
-namespace STG
-{
-struct Settings;
-struct Settings;
-}
-
-namespace RS
-{
-
-class REMOTE_SCRIPT;
-class UpdateRouter;
-class DisconnectUser;
-
-using UserPtr = STG::User*;
-
-//-----------------------------------------------------------------------------
-class ADD_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
-public:
- explicit ADD_USER_NONIFIER(REMOTE_SCRIPT & r)
- : rs(r) {}
- void Notify(const UserPtr & user);
-
-private:
- ADD_USER_NONIFIER(const ADD_USER_NONIFIER & rhs);
- ADD_USER_NONIFIER & operator=(const ADD_USER_NONIFIER);
-
- REMOTE_SCRIPT & rs;
-};
-//-----------------------------------------------------------------------------
-class DEL_USER_NONIFIER: public STG::NotifierBase<UserPtr> {
-public:
- explicit DEL_USER_NONIFIER(REMOTE_SCRIPT & r)
- : rs(r) {}
- void Notify(const UserPtr & user);
-
-private:
- DEL_USER_NONIFIER(const DEL_USER_NONIFIER & rhs);
- DEL_USER_NONIFIER & operator=(const DEL_USER_NONIFIER);
-
- REMOTE_SCRIPT & rs;
-};
-//-----------------------------------------------------------------------------
-class IP_NOTIFIER: public STG::PropertyNotifierBase<uint32_t> {
-public:
- IP_NOTIFIER(REMOTE_SCRIPT & r, UserPtr u)
- : user(u), rs(r) { user->AddCurrIPAfterNotifier(this); }
- IP_NOTIFIER(const IP_NOTIFIER & rhs)
- : user(rhs.user), rs(rhs.rs) { user->AddCurrIPAfterNotifier(this); }
- ~IP_NOTIFIER() { user->DelCurrIPAfterNotifier(this); }
-
- IP_NOTIFIER & operator=(const IP_NOTIFIER & rhs)
- {
- user->DelCurrIPAfterNotifier(this);
- user = rhs.user;
- user->AddCurrIPAfterNotifier(this);
- return *this;
- }
-
- void Notify(const uint32_t & oldValue, const uint32_t & newValue);
- UserPtr GetUser() const { return user; }
-
-private:
-
- UserPtr user;
- REMOTE_SCRIPT & rs;
-};
-//-----------------------------------------------------------------------------
-class CONNECTED_NOTIFIER: public STG::PropertyNotifierBase<bool> {
-public:
- CONNECTED_NOTIFIER(REMOTE_SCRIPT & r, UserPtr u)
- : user(u), rs(r) { user->AddConnectedAfterNotifier(this); }
- CONNECTED_NOTIFIER(const CONNECTED_NOTIFIER & rhs)
- : user(rhs.user), rs(rhs.rs) { user->AddConnectedAfterNotifier(this); }
- ~CONNECTED_NOTIFIER() { user->DelConnectedAfterNotifier(this); }
-
- CONNECTED_NOTIFIER & operator=(const CONNECTED_NOTIFIER & rhs)
- {
- user->DelConnectedAfterNotifier(this);
- user = rhs.user;
- user->AddConnectedAfterNotifier(this);
- return *this;
- }
-
- void Notify(const bool & oldValue, const bool & newValue);
- UserPtr GetUser() const { return user; }
-
-private:
-
- UserPtr user;
- REMOTE_SCRIPT & rs;
-};
-//-----------------------------------------------------------------------------
-struct USER {
- USER(const std::vector<uint32_t> & r, UserPtr it)
- : lastSentTime(0),
- user(it),
- routers(r),
- shortPacketsCount(0),
- ip(user->GetCurrIP())
- {}
-
- time_t lastSentTime;
- UserPtr user;
- std::vector<uint32_t> routers;
- int shortPacketsCount;
- uint32_t ip;
-};
-//-----------------------------------------------------------------------------
-class SETTINGS {
-public:
- SETTINGS();
- virtual ~SETTINGS() {}
- const std::string & GetStrError() const { return errorStr; }
- int ParseSettings(const STG::ModuleSettings & s);
- int GetSendPeriod() const { return sendPeriod; }
- uint16_t GetPort() const { return port; }
- const std::vector<NET_ROUTER> & GetSubnetsMap() const { return netRouters; }
- const std::vector<std::string> & GetUserParams() const { return userParams; }
- const std::string & GetPassword() const { return password; }
- const std::string & GetMapFileName() const { return subnetFile; }
-
-private:
- int sendPeriod;
- uint16_t port;
- std::string errorStr;
- std::vector<NET_ROUTER> netRouters;
- std::vector<std::string> userParams;
- std::string password;
- std::string subnetFile;
-};
-//-----------------------------------------------------------------------------
-class REMOTE_SCRIPT : public STG::Plugin {
-public:
- REMOTE_SCRIPT();
- ~REMOTE_SCRIPT() override;
-
- void SetUsers(STG::Users * u) override { users = u; }
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- int Start() override;
- int Stop() override;
- int Reload(const STG::ModuleSettings & ms) override;
- bool IsRunning() override { return isRunning; }
-
- const std::string & GetStrError() const override { return errorStr; }
- std::string GetVersion() const override { return "Remote script v 0.3"; }
- uint16_t GetStartPosition() const override { return 10; }
- uint16_t GetStopPosition() const override { return 10; }
-
- void DelUser(UserPtr u) { UnSetUserNotifiers(u); }
- void AddUser(UserPtr u) { SetUserNotifiers(u); }
-
- void AddRSU(UserPtr user);
- void DelRSU(UserPtr user);
-
-private:
- REMOTE_SCRIPT(const REMOTE_SCRIPT & rhs);
- REMOTE_SCRIPT & operator=(const REMOTE_SCRIPT & rhs);
-
- static void * Run(void *);
- bool PrepareNet();
- bool FinalizeNet();
-
- bool Send(USER & rsu, bool forceDisconnect = false) const;
- bool SendDirect(USER & rsu, uint32_t routerIP, bool forceDisconnect = false) const;
- bool PreparePacket(char * buf, size_t bufSize, USER &rsu, bool forceDisconnect = false) const;
- void PeriodicSend();
-
- std::vector<uint32_t> IP2Routers(uint32_t ip);
- bool GetUsers();
-
- void SetUserNotifiers(UserPtr u);
- void UnSetUserNotifiers(UserPtr u);
-
- void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) const;
- void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, size_t len8) const;
-
- mutable BLOWFISH_CTX ctx;
-
- std::list<IP_NOTIFIER> ipNotifierList;
- std::list<CONNECTED_NOTIFIER> connNotifierList;
- std::map<uint32_t, USER> authorizedUsers;
-
- mutable std::string errorStr;
- SETTINGS rsSettings;
- STG::ModuleSettings settings;
- int sendPeriod;
- int halfPeriod;
-
- bool nonstop;
- bool isRunning;
-
- STG::Users * users;
-
- std::vector<NET_ROUTER> netRouters;
-
- pthread_t thread;
- pthread_mutex_t mutex;
-
- int sock;
-
- ADD_USER_NONIFIER onAddUserNotifier;
- DEL_USER_NONIFIER onDelUserNotifier;
-
- STG::PluginLogger logger;
-
- friend class RS::UpdateRouter;
- friend class RS::DisconnectUser;
- friend class RS::CONNECTED_NOTIFIER;
-};
-//-----------------------------------------------------------------------------
-class DisconnectUser : public std::unary_function<std::pair<const uint32_t, USER> &, void> {
- public:
- explicit DisconnectUser(REMOTE_SCRIPT & rs) : rscript(rs) {}
- void operator()(std::pair<const uint32_t, USER> & p)
- {
- rscript.Send(p.second, true);
- }
- private:
- REMOTE_SCRIPT & rscript;
-};
-//-----------------------------------------------------------------------------
-inline void ADD_USER_NONIFIER::Notify(const UserPtr & user)
-{
-rs.AddUser(user);
-}
-//-----------------------------------------------------------------------------
-inline void DEL_USER_NONIFIER::Notify(const UserPtr & user)
-{
-rs.DelUser(user);
-}
-//-----------------------------------------------------------------------------
-
-} // namespace RS
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- $Revision: 1.2 $
- $Date: 2010/03/04 12:11:09 $
- $Author: faust $
-*/
-
-#ifndef __SEND_FUNCTOR_H__
-#define __SEND_FUNCTOR_H__
-
-#include <functional>
-#include <cstdint>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-
-class PacketSender : public std::unary_function<uint32_t, ssize_t> {
- public:
- PacketSender(int s, char * b, size_t l, uint16_t p)
- : sock(s),
- buffer(b),
- length(l),
- port(p) {}
- ssize_t operator() (uint32_t ip)
- {
- struct sockaddr_in sendAddr;
-
- sendAddr.sin_family = AF_INET;
- sendAddr.sin_port = port;
- sendAddr.sin_addr.s_addr = ip;
-
- return sendto(sock, buffer, length, 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
- }
- private:
- int sock;
- char * buffer;
- size_t length;
- uint16_t port;
-};
-
-#endif
+++ /dev/null
-/*
- * 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>
- */
-
-#ifndef __UR_FUNCTOR_H__
-#define __UR_FUNCTOR_H__
-
-#include "rscript.h"
-
-#include "stg/common.h"
-
-#include <functional>
-#include <algorithm>
-#include <utility>
-#include <cstdint>
-
-namespace RS
-{
-
-class UpdateRouter : public std::unary_function<std::pair<const uint32_t, RS::USER>, void>
-{
-public:
- explicit UpdateRouter(REMOTE_SCRIPT & t)
- : obj(t) {}
-
- void operator() (std::pair<const uint32_t, USER> & val)
- {
- std::vector<uint32_t> newRouters = obj.IP2Routers(val.second.ip);
- std::vector<uint32_t>::const_iterator oldIt(val.second.routers.begin());
- std::vector<uint32_t>::const_iterator newIt(newRouters.begin());
- val.second.shortPacketsCount = 0;
- while (oldIt != val.second.routers.end() ||
- newIt != newRouters.end())
- {
- if (oldIt == val.second.routers.end())
- {
- if (newIt != newRouters.end())
- {
- obj.SendDirect(val.second, *newIt); // Connect on new router
- ++newIt;
- }
- }
- else if (newIt == newRouters.end())
- {
- obj.SendDirect(val.second, *oldIt, true); // Disconnect on old router
- ++oldIt;
- }
- else if (*oldIt < *newIt)
- {
- obj.SendDirect(val.second, *oldIt, true); // Disconnect on old router
- ++oldIt;
- }
- else if (*oldIt > *newIt)
- {
- obj.SendDirect(val.second, *newIt); // Connect on new router
- ++newIt;
- }
- else
- {
- ++oldIt;
- if (newIt != newRouters.end())
- ++newIt;
- }
- }
- val.second.routers = newRouters;
- }
-private:
- REMOTE_SCRIPT & obj;
-};
-
-} // namespace RS
-
-#endif
+++ /dev/null
-STG-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- enterprises,
- MODULE-IDENTITY, OBJECT-TYPE,
- Integer32 FROM SNMPv2-SMI
- DisplayString FROM SNMPv2-TC;
-
-stgMIB MODULE-IDENTITY
- LAST-UPDATED "201101060000Z"
- ORGANIZATION "STG"
- CONTACT-INFO
- "Primary Contact: Maxim Mamontov
- email: faust@stg.dp.ua"
- DESCRIPTION
- "This MIB module defines objects for Stargazer data."
- REVISION "201101060000Z"
- DESCRIPTION "Initial revision"
- ::= { enterprises 38313 }
-
-stg24 OBJECT IDENTIFIER ::= { stgMIB 1 }
-
-users OBJECT IDENTIFIER ::= { stg24 1 }
-tariffs OBJECT IDENTIFIER ::= { stg24 2 }
-admins OBJECT IDENTIFIER ::= { stg24 3 }
-services OBJECT IDENTIFIER ::= { stg24 4 }
-corporations OBJECT IDENTIFIER ::= { stg24 5 }
-traffcounter OBJECT IDENTIFIER ::= { stg24 6 }
-
-totalUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total users registered in the billing"
- DEFVAL { 0 }
- ::= { users 1 }
-
-onlineUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of currently online users"
- DEFVAL { 0 }
- ::= { users 2 }
-
-authorizedUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of currently authorized users"
- DEFVAL { 0 }
- ::= { users 3 }
-
-alwaysOnlineUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of users with 'always online' option"
- DEFVAL { 0 }
- ::= { users 4 }
-
-noCashUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of users with negative cash"
- DEFVAL { 0 }
- ::= { users 5 }
-
-disabledDetailStatsUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of users with disabled detail stats"
- DEFVAL { 0 }
- ::= { users 6 }
-
-disabledUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of disabled users"
- DEFVAL { 0 }
- ::= { users 7 }
-
-passiveUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of passive users"
- DEFVAL { 0 }
- ::= { users 8 }
-
-creditUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of users with positive credit"
- DEFVAL { 0 }
- ::= { users 9 }
-
-freeMbUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of users with positive freeMb"
- DEFVAL { 0 }
- ::= { users 10 }
-
-tariffChangeUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of users changing tariff next month"
- DEFVAL { 0 }
- ::= { users 11 }
-
-activeUsers OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of online users with traffic during session"
- DEFVAL {0}
- ::= { users 12 }
-
-totalTariffs OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total tariffs registered in the billing"
- DEFVAL { 0 }
- ::= { tariffs 1 }
-
-tariffUsageTable OBJECT-TYPE
- SYNTAX SEQUENCE OF TariffUsageTable
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "The number of users by each tariff"
- DEFVAL { 0 }
- ::= { tariffs 2 }
-
-tariffUsageTableEntry OBJECT-TYPE
- SYNTAX TariffUsageTable
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A row describing a given tariff"
- INDEX { tariffIndex }
- ::= {tariffUsageTable 1 }
-
-TariffUsageTable ::= SEQUENCE {
- tariffIndex Integer32,
- tariffName DisplayString,
- userCount Integer32
-}
-
-tariffIndex OBJECT-TYPE
- SYNTAX Integer32 (0..255)
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "The id of the tariff this table describes."
- ::= { tariffUsageTableEntry 1 }
-
-tariffName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The name of the tariff this table describes."
- ::= { tariffUsageTableEntry 2 }
-
-userCount OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The count fo users of the tariff this table describes."
- ::= { tariffUsageTableEntry 3 }
-
-totalAdmins OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total admins registered in the billing"
- DEFVAL { 0 }
- ::= { admins 1 }
-
-totalServices OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total services registered in the billing"
- DEFVAL { 0 }
- ::= { services 1 }
-
-totalCorporations OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total corporations registered in the billing"
- DEFVAL { 0 }
- ::= { corporations 1 }
-
-totalRules OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total traffic classification rules described by rules file"
- DEFVAL { 0 }
- ::= { traffcounter 1 }
-
-END
+++ /dev/null
-Количество пользователей всего в биллинге
-Количество пользователей онлайн
-Количество пользователей с отрицательный балансом
-Количество пользователей с всегда онлайн
-Количество пользователей по отношению к каждому из тарифов
-Количество пользователей по отношению к каждому UserData полю - ?
-Количество пользователей с отключенной детальной статистикой
-Количество отключенных пользователей
-Количество замороженных пользователей
-Количество пользователей, у которых есть кредит
-Количество пользователей, у которых есть предоплаченный трафик
-
-Количество тарифов
-Количество направлений
+++ /dev/null
-#include <cassert>
-
-#include "stg/GetRequest-PDU.h"
-#include "stg/GetResponse-PDU.h"
-#include "stg/VarBindList.h"
-#include "stg/VarBind.h"
-
-#include "stg/common.h"
-
-#include "utils.h"
-#include "smux.h"
-
-#ifdef SMUX_DEBUG
-bool SMUX::CloseHandler(const SMUX_PDUs_t * pdus)
-{
-printfd(__FILE__, "SMUX::CloseHandler()\n");
-asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
-return true;
-}
-#else
-bool SMUX::CloseHandler(const SMUX_PDUs_t *)
-{
-return true;
-}
-#endif
-
-#ifdef SMUX_DEBUG
-bool SMUX::RegisterResponseHandler(const SMUX_PDUs_t * pdus)
-{
-printfd(__FILE__, "SMUX::RegisterResponseHandler()\n");
-asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
-return true;
-}
-#else
-bool SMUX::RegisterResponseHandler(const SMUX_PDUs_t *)
-{
-return true;
-}
-#endif
-
-bool SMUX::PDUsRequestHandler(const SMUX_PDUs_t * pdus)
-{
-#ifdef SMUX_DEBUG
-printfd(__FILE__, "SMUX::PDUsRequestHandler()\n");
-asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
-#endif
-PDUsHandlers::iterator it(pdusHandlers.find(pdus->choice.pdus.present));
-if (it != pdusHandlers.end())
- {
- return (this->*(it->second))(&pdus->choice.pdus);
- }
-#ifdef SMUX_DEBUG
-else
- {
- switch (pdus->present)
- {
- case PDUs_PR_NOTHING:
- printfd(__FILE__, "SMUX::PDUsRequestHandler() - nothing\n");
- break;
- case PDUs_PR_get_response:
- printfd(__FILE__, "SMUX::PDUsRequestHandler() - get response\n");
- break;
- case PDUs_PR_trap:
- printfd(__FILE__, "SMUX::PDUsRequestHandler() - trap\n");
- break;
- default:
- printfd(__FILE__, "SMUX::PDUsRequestHandler() - undefined\n");
- }
- }
-#endif
-return true;
-}
-
-#ifdef SMUX_DEBUG
-bool SMUX::CommitOrRollbackHandler(const SMUX_PDUs_t * pdus)
-{
-printfd(__FILE__, "SMUX::CommitOrRollbackHandler()\n");
-asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
-return true;
-}
-#else
-bool SMUX::CommitOrRollbackHandler(const SMUX_PDUs_t *)
-{
-return true;
-}
-#endif
-
-bool SMUX::GetRequestHandler(const PDUs_t * pdus)
-{
-#ifdef SMUX_DEBUG
-printfd(__FILE__, "SMUX::GetRequestHandler()\n");
-asn_fprint(stderr, &asn_DEF_PDUs, pdus);
-#endif
-const GetRequest_PDU_t * getRequest = &pdus->choice.get_request;
-GetResponse_PDU_t * msg = static_cast<GetResponse_PDU_t *>(calloc(1, sizeof(GetResponse_PDU_t)));
-assert(msg && "Enought mempry to allocate GetResponse_PDU_t");
-VarBindList_t * varBindList = &msg->variable_bindings;
-
-long id = 0;
-asn_INTEGER2long(&getRequest->request_id, &id);
-asn_long2INTEGER(&msg->request_id, id);
-asn_long2INTEGER(&msg->error_status, 0);
-asn_long2INTEGER(&msg->error_index, 0);
-
-const VarBindList_t * vbl = &getRequest->variable_bindings;
-for (int i = 0; i < vbl->list.count; ++i)
- {
- VarBind_t * vb = getRequest->variable_bindings.list.array[i];
- Sensors::iterator it;
- it = sensors.find(OID(&vb->name));
- if (it == sensors.end())
- {
- return SendGetResponseErrorPDU(sock, getRequest,
- PDU__error_status_noSuchName, i);
- }
-
- VarBind_t * newVb = static_cast<VarBind_t *>(calloc(1, sizeof(VarBind_t)));
- assert(newVb && "Enought mempry to allocate VarBind_t");
-
- it->first.ToOID(&newVb->name);
- it->second->GetValue(&newVb->value);
-
- ASN_SEQUENCE_ADD(varBindList, newVb);
- }
-
-bool res = SendGetResponsePDU(sock, msg);
-#ifdef SMUX_DEBUG
-asn_fprint(stderr, &asn_DEF_GetResponse_PDU, msg);
-#endif
-ASN_STRUCT_FREE(asn_DEF_GetResponse_PDU, msg);
-return res;
-}
-
-bool SMUX::GetNextRequestHandler(const PDUs_t * pdus)
-{
-#ifdef SMUX_DEBUG
-printfd(__FILE__, "SMUX::GetNextRequestHandler()\n");
-asn_fprint(stderr, &asn_DEF_PDUs, pdus);
-#endif
-const GetRequest_PDU_t * getRequest = &pdus->choice.get_request;
-GetResponse_PDU_t * msg = static_cast<GetResponse_PDU_t *>(calloc(1, sizeof(GetResponse_PDU_t)));
-assert(msg && "Enought mempry to allocate GetResponse_PDU_t");
-VarBindList_t * varBindList = &msg->variable_bindings;
-
-long id = 0;
-asn_INTEGER2long(&getRequest->request_id, &id);
-asn_long2INTEGER(&msg->request_id, id);
-asn_long2INTEGER(&msg->error_status, 0);
-asn_long2INTEGER(&msg->error_index, 0);
-
-const VarBindList_t * vbl = &getRequest->variable_bindings;
-for (int i = 0; i < vbl->list.count; ++i)
- {
- VarBind_t * vb = getRequest->variable_bindings.list.array[i];
- Sensors::iterator it;
- it = sensors.upper_bound(OID(&vb->name));
- if (it == sensors.end())
- {
-#ifdef SMUX_DEBUG
- printfd(__FILE__, "SMUX::GetNextRequestHandler() - '%s' not found\n", OID(&vb->name).ToString().c_str());
-#endif
- return SendGetResponseErrorPDU(sock, getRequest,
- PDU__error_status_noSuchName, i);
- }
-
- VarBind_t * newVb = static_cast<VarBind_t *>(calloc(1, sizeof(VarBind_t)));
- assert(newVb && "Enought mempry to allocate VarBind_t");
-
- it->first.ToOID(&newVb->name);
- it->second->GetValue(&newVb->value);
-
- ASN_SEQUENCE_ADD(varBindList, newVb);
- }
-
-bool res = SendGetResponsePDU(sock, msg);
-#ifdef SMUX_DEBUG
-asn_fprint(stderr, &asn_DEF_PDU, msg);
-#endif
-ASN_STRUCT_FREE(asn_DEF_GetResponse_PDU, msg);
-return res;
-}
-
-bool SMUX::SetRequestHandler(const PDUs_t * pdus)
-{
-#ifdef SMUX_DEBUG
-printfd(__FILE__, "SMUX::SetRequestHandler()\n");
-asn_fprint(stderr, &asn_DEF_PDUs, pdus);
-#endif
-return SendGetResponseErrorPDU(sock, &pdus->choice.set_request,
- PDU__error_status_readOnly, 0);
-}
+++ /dev/null
-#ifndef __PEN_H__
-#define __PEN_H__
-
-#define PEN_PREFIX ".1.3.6.1.4.1.38313"
-
-#endif
+++ /dev/null
-#include <cassert>
-
-#include "stg/INTEGER.h"
-
-#include "stg/user.h"
-
-#include "sensors.h"
-
-bool UsersSensor::GetValue(ObjectSyntax_t * objectSyntax) const
-{
-int handle = users.OpenSearch();
-assert(handle && "USERS::OpenSearch is always correct");
-
-STG::User* user;
-size_t count = 0;
-while (!users.SearchNext(handle, &user))
- {
- if (UserPredicate(user))
- ++count;
- }
-
-users.CloseSearch(handle);
-
-ValueToOS(count, objectSyntax);
-return true;
-}
-
-#ifdef DEBUG
-std::string UsersSensor::ToString() const
-{
-int handle = users.OpenSearch();
-assert(handle && "USERS::OpenSearch is always correct");
-
-STG::User* user;
-size_t count = 0;
-while (!users.SearchNext(handle, &user))
- {
- if (UserPredicate(user))
- ++count;
- }
-
-users.CloseSearch(handle);
-
-return std::to_string(count);
-}
-#endif
-
-bool ActiveUsersSensor::UserPredicate(STG::User* userPtr) const
-{
-if (!userPtr->GetConnected())
- return false;
-for (size_t i = 0; i < DIR_NUM; ++i)
- {
- if (userPtr->GetSessionUpload()[i] > 0 ||
- userPtr->GetSessionDownload()[i] > 0)
- return true;
- }
-return false;
-}
+++ /dev/null
-#ifndef __SENSORS_H__
-#define __SENSORS_H__
-
-#include <map>
-
-#include "stg/users.h"
-#include "stg/user.h"
-#include "stg/tariffs.h"
-#include "stg/admins.h"
-#include "stg/services.h"
-#include "stg/corporations.h"
-#include "stg/traffcounter.h"
-#include "stg/user_property.h"
-
-#include "stg/ObjectSyntax.h"
-
-#include "value2os.h"
-#include "types.h"
-
-class Sensor {
- public:
- virtual ~Sensor() = default;
- virtual bool GetValue(ObjectSyntax_t * objectSyntax) const = 0;
-#ifdef DEBUG
- virtual std::string ToString() const = 0;
-#endif
-};
-
-typedef std::map<OID, Sensor *> Sensors;
-
-class TotalUsersSensor : public Sensor {
- public:
- explicit TotalUsersSensor(const STG::Users & u) : users(u) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override
- {
- ValueToOS(users.Count(), objectSyntax);
- return true;
- }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(users.Count(), res); return res; }
-#endif
-
- private:
- const STG::Users & users;
-};
-
-class UsersSensor : public Sensor {
- public:
- explicit UsersSensor(STG::Users & u) : users(u) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override;
-#ifdef DEBUG
- std::string ToString() const override;
-#endif
-
- private:
- STG::Users & users;
-
- virtual bool UserPredicate(STG::User* userPtr) const = 0;
-};
-
-class ConnectedUsersSensor : public UsersSensor {
- public:
- explicit ConnectedUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetConnected(); }
-};
-
-class AuthorizedUsersSensor : public UsersSensor {
- public:
- explicit AuthorizedUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetAuthorized(); }
-};
-
-class AlwaysOnlineUsersSensor : public UsersSensor {
- public:
- explicit AlwaysOnlineUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().alwaysOnline; }
-};
-
-class NoCashUsersSensor : public UsersSensor {
- public:
- explicit NoCashUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().cash < 0; }
-};
-
-class DisabledDetailStatsUsersSensor : public UsersSensor {
- public:
- explicit DisabledDetailStatsUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().disabledDetailStat; }
-};
-
-class DisabledUsersSensor : public UsersSensor {
- public:
- explicit DisabledUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().disabled; }
-};
-
-class PassiveUsersSensor : public UsersSensor {
- public:
- explicit PassiveUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().passive; }
-};
-
-class CreditUsersSensor : public UsersSensor {
- public:
- explicit CreditUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().credit > 0; }
-};
-
-class FreeMbUsersSensor : public UsersSensor {
- public:
- explicit FreeMbUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return userPtr->GetProperties().freeMb > 0; }
-};
-
-class TariffChangeUsersSensor : public UsersSensor {
- public:
- explicit TariffChangeUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override
- { return !userPtr->GetProperties().nextTariff.ConstData().empty(); }
-};
-
-class ActiveUsersSensor : public UsersSensor {
- public:
- explicit ActiveUsersSensor(STG::Users & u) : UsersSensor(u) {}
-
- private:
- bool UserPredicate(STG::User* userPtr) const override;
-};
-
-class TotalTariffsSensor : public Sensor {
- public:
- explicit TotalTariffsSensor(const STG::Tariffs & t) : tariffs(t) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override
- {
- ValueToOS(tariffs.Count(), objectSyntax);
- return true;
- }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(tariffs.Count(), res); return res; }
-#endif
-
- private:
- const STG::Tariffs & tariffs;
-};
-
-class TotalAdminsSensor : public Sensor {
- public:
- explicit TotalAdminsSensor(const STG::Admins & a) : admins(a) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override
- {
- ValueToOS(admins.count(), objectSyntax);
- return true;
- }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(admins.Count(), res); return res; }
-#endif
-
- private:
- const STG::Admins & admins;
-};
-
-class TotalServicesSensor : public Sensor {
- public:
- explicit TotalServicesSensor(const STG::Services & s) : services(s) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override
- {
- ValueToOS(services.Count(), objectSyntax);
- return true;
- }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(services.Count(), res); return res; }
-#endif
-
- private:
- const STG::Services & services;
-};
-
-class TotalCorporationsSensor : public Sensor {
- public:
- explicit TotalCorporationsSensor(const STG::Corporations & c) : corporations(c) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override
- {
- ValueToOS(corporations.Count(), objectSyntax);
- return true;
- }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(corporations.Count(), res); return res; }
-#endif
-
- private:
- const STG::Corporations & corporations;
-};
-
-class TotalRulesSensor : public Sensor {
- public:
- explicit TotalRulesSensor(const STG::TraffCounter & t) : traffcounter(t) {}
-
- bool GetValue(ObjectSyntax_t * objectSyntax) const override
- {
- ValueToOS(traffcounter.rulesCount(), objectSyntax);
- return true;
- }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(traffcounter.rulesCount(), res); return res; }
-#endif
-
- private:
- const STG::TraffCounter & traffcounter;
-};
-
-template <typename T>
-class ConstSensor : public Sensor {
- public:
- explicit ConstSensor(const T & v) : value(v) {}
-
- bool GetValue(ObjectSyntax * objectSyntax) const override
- { return ValueToOS(value, objectSyntax); }
-
-#ifdef DEBUG
- std::string ToString() const override
- { std::string res; std::to_string(value, res); return res; }
-#endif
-
- private:
- T value;
-};
-
-#ifdef DEBUG
-template <>
-inline
-std::string ConstSensor<std::string>::ToString() const
-{
-return value;
-}
-#endif
-
-#endif
+++ /dev/null
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include <cstring>
-#include <cerrno>
-#include <ctime>
-#include <csignal>
-#include <cassert>
-
-#include <vector>
-#include <algorithm>
-#include <iterator>
-#include <stdexcept>
-#include <utility>
-
-#include "stg/common.h"
-
-#include "smux.h"
-#include "utils.h"
-
-namespace
-{
-
-bool SPrefixLess(const Sensors::value_type & a,
- const Sensors::value_type & b)
-{
-return a.first.PrefixLess(b.first);
-}
-
-}
-
-extern "C" STG::Plugin* GetPlugin()
-{
- static SMUX plugin;
- return &plugin;
-}
-
-SMUX_SETTINGS::SMUX_SETTINGS()
- : errorStr(),
- ip(0),
- port(0),
- password()
-{}
-
-int SMUX_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-STG::ParamValue pv;
-std::vector<STG::ParamValue>::const_iterator pvi;
-int p;
-
-pv.param = "Port";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Port\' not found.";
- printfd(__FILE__, "Parameter 'Port' not found\n");
- return -1;
- }
-if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
- {
- errorStr = "Cannot parse parameter \'Port\': " + errorStr;
- printfd(__FILE__, "Cannot parse parameter 'Port'\n");
- return -1;
- }
-port = static_cast<uint16_t>(p);
-
-pv.param = "Password";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Password\' not found.";
- printfd(__FILE__, "Parameter 'Password' not found\n");
- password = "";
- }
-else
- {
- password = pvi->value[0];
- }
-
-pv.param = "Server";
-pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'Server\' not found.";
- printfd(__FILE__, "Parameter 'Server' not found\n");
- return -1;
- }
-ip = inet_strington(pvi->value[0]);
-
-return 0;
-}
-
-SMUX::SMUX()
- : users(NULL),
- tariffs(NULL),
- admins(NULL),
- services(NULL),
- corporations(NULL),
- traffcounter(NULL),
- running(false),
- stopped(true),
- needReconnect(false),
- lastReconnectTry(0),
- reconnectTimeout(1),
- sock(-1),
- addUserNotifier(*this),
- delUserNotifier(*this),
- addDelTariffNotifier(*this),
- logger(STG::PluginLogger::get("smux"))
-{
-pthread_mutex_init(&mutex, NULL);
-
-smuxHandlers[SMUX_PDUs_PR_close] = &SMUX::CloseHandler;
-smuxHandlers[SMUX_PDUs_PR_registerResponse] = &SMUX::RegisterResponseHandler;
-smuxHandlers[SMUX_PDUs_PR_pdus] = &SMUX::PDUsRequestHandler;
-smuxHandlers[SMUX_PDUs_PR_commitOrRollback] = &SMUX::CommitOrRollbackHandler;
-
-pdusHandlers[PDUs_PR_get_request] = &SMUX::GetRequestHandler;
-pdusHandlers[PDUs_PR_get_next_request] = &SMUX::GetNextRequestHandler;
-pdusHandlers[PDUs_PR_set_request] = &SMUX::SetRequestHandler;
-}
-
-SMUX::~SMUX()
-{
- {
- Sensors::iterator it;
- for (it = sensors.begin(); it != sensors.end(); ++it)
- delete it->second;
- }
- {
- Tables::iterator it;
- for (it = tables.begin(); it != tables.end(); ++it)
- delete it->second;
- }
-printfd(__FILE__, "SMUX::~SMUX()\n");
-pthread_mutex_destroy(&mutex);
-}
-
-int SMUX::ParseSettings()
-{
-return smuxSettings.ParseSettings(settings);
-}
-
-int SMUX::Start()
-{
-assert(users != NULL && "users must not be NULL");
-assert(tariffs != NULL && "tariffs must not be NULL");
-assert(admins != NULL && "admins must not be NULL");
-assert(services != NULL && "services must not be NULL");
-assert(corporations != NULL && "corporations must not be NULL");
-assert(traffcounter != NULL && "traffcounter must not be NULL");
-
-if (PrepareNet())
- needReconnect = true;
-
-// Users
-sensors[OID(".1.3.6.1.4.1.38313.1.1.1")] = new TotalUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.2")] = new ConnectedUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.3")] = new AuthorizedUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.4")] = new AlwaysOnlineUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.5")] = new NoCashUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.6")] = new DisabledDetailStatsUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.7")] = new DisabledUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.8")] = new PassiveUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.9")] = new CreditUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.10")] = new FreeMbUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.11")] = new TariffChangeUsersSensor(*users);
-sensors[OID(".1.3.6.1.4.1.38313.1.1.12")] = new ActiveUsersSensor(*users);
-// Tariffs
-sensors[OID(".1.3.6.1.4.1.38313.1.2.1")] = new TotalTariffsSensor(*tariffs);
-// Admins
-sensors[OID(".1.3.6.1.4.1.38313.1.3.1")] = new TotalAdminsSensor(*admins);
-// Services
-sensors[OID(".1.3.6.1.4.1.38313.1.4.1")] = new TotalServicesSensor(*services);
-// Corporations
-sensors[OID(".1.3.6.1.4.1.38313.1.5.1")] = new TotalCorporationsSensor(*corporations);
-// Traffcounter
-sensors[OID(".1.3.6.1.4.1.38313.1.6.1")] = new TotalRulesSensor(*traffcounter);
-
-// Table data
-tables[".1.3.6.1.4.1.38313.1.2.2"] = new TariffUsersTable(".1.3.6.1.4.1.38313.1.2.2", *tariffs, *users);
-
-UpdateTables();
-SetNotifiers();
-
-#ifdef SMUX_DEBUG
-Sensors::const_iterator it(sensors.begin());
-while (it != sensors.end())
- {
- printfd(__FILE__, "%s = %s\n",
- it->first.ToString().c_str(),
- it->second->ToString().c_str());
- ++it;
- }
-#endif
-
-if (!running)
- {
- if (pthread_create(&thread, NULL, Runner, this))
- {
- errorStr = "Cannot create thread.";
- logger("Cannot create thread.");
- printfd(__FILE__, "Cannot create thread\n");
- return -1;
- }
- }
-
-return 0;
-}
-
-int SMUX::Stop()
-{
-printfd(__FILE__, "SMUX::Stop() - Before\n");
-running = false;
-
-if (!stopped)
- {
- //5 seconds to thread stops itself
- for (int i = 0; i < 25 && !stopped; i++)
- {
- struct timespec ts = {0, 200000000};
- nanosleep(&ts, NULL);
- }
- }
-
-if (stopped)
- pthread_join(thread, NULL);
-
-ResetNotifiers();
-
- {
- Tables::iterator it;
- for (it = tables.begin(); it != tables.end(); ++it)
- delete it->second;
- }
- {
- Sensors::iterator it;
- for (it = sensors.begin(); it != sensors.end(); ++it)
- delete it->second;
- }
-
-tables.erase(tables.begin(), tables.end());
-sensors.erase(sensors.begin(), sensors.end());
-
-close(sock);
-
-if (!stopped)
- {
- running = true;
- return -1;
- }
-
-printfd(__FILE__, "SMUX::Stop() - After\n");
-return 0;
-}
-
-int SMUX::Reload(const STG::ModuleSettings & /*ms*/)
-{
-if (Stop())
- return -1;
-if (Start())
- return -1;
-if (!needReconnect)
- {
- printfd(__FILE__, "SMUX reconnected succesfully.\n");
- logger("Reconnected successfully.");
- }
-return 0;
-}
-
-void * SMUX::Runner(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-SMUX * smux = static_cast<SMUX *>(d);
-
-smux->Run();
-
-return NULL;
-}
-
-void SMUX::Run()
-{
-stopped = true;
-if (!SendOpenPDU(sock))
- needReconnect = true;
-if (!SendRReqPDU(sock))
- needReconnect = true;
-running = true;
-stopped = false;
-
-while(running)
- {
- if (WaitPackets(sock) && !needReconnect)
- {
- SMUX_PDUs_t * pdus = RecvSMUXPDUs(sock);
- if (pdus)
- {
- DispatchPDUs(pdus);
- ASN_STRUCT_FREE(asn_DEF_SMUX_PDUs, pdus);
- }
- else if (running)
- Reconnect();
- }
- else if (running && needReconnect)
- Reconnect();
- if (!running)
- break;
- }
-SendClosePDU(sock);
-stopped = true;
-}
-
-bool SMUX::PrepareNet()
-{
-sock = socket(AF_INET, SOCK_STREAM, 0);
-
-if (sock < 0)
- {
- errorStr = "Cannot create socket.";
- logger("Cannot create a socket: %s", strerror(errno));
- printfd(__FILE__, "Cannot create socket\n");
- return true;
- }
-
-struct sockaddr_in addr;
-
-addr.sin_family = AF_INET;
-addr.sin_port = htons(smuxSettings.GetPort());
-addr.sin_addr.s_addr = smuxSettings.GetIP();
-
-if (connect(sock, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)))
- {
- errorStr = "Cannot connect.";
- logger("Cannot connect the socket: %s", strerror(errno));
- printfd(__FILE__, "Cannot connect. Message: '%s'\n", strerror(errno));
- return true;
- }
-
-return false;
-}
-
-bool SMUX::Reconnect()
-{
-if (needReconnect && difftime(time(NULL), lastReconnectTry) < reconnectTimeout)
- return true;
-
-time(&lastReconnectTry);
-SendClosePDU(sock);
-close(sock);
-if (!PrepareNet())
- if (SendOpenPDU(sock))
- if (SendRReqPDU(sock))
- {
- reconnectTimeout = 1;
- needReconnect = false;
- logger("Connected successfully");
- printfd(__FILE__, "Connected successfully\n");
- return false;
- }
-
-if (needReconnect)
- if (reconnectTimeout < 60)
- reconnectTimeout *= 2;
-
-needReconnect = true;
-return true;
-}
-
-bool SMUX::DispatchPDUs(const SMUX_PDUs_t * pdus)
-{
-SMUXHandlers::iterator it(smuxHandlers.find(pdus->present));
-if (it != smuxHandlers.end())
- {
- return (this->*(it->second))(pdus);
- }
-#ifdef SMUX_DEBUG
-else
- {
- switch (pdus->present)
- {
- case SMUX_PDUs_PR_NOTHING:
- printfd(__FILE__, "PDUs: nothing\n");
- break;
- case SMUX_PDUs_PR_open:
- printfd(__FILE__, "PDUs: open\n");
- break;
- case SMUX_PDUs_PR_registerRequest:
- printfd(__FILE__, "PDUs: registerRequest\n");
- break;
- default:
- printfd(__FILE__, "PDUs: undefined\n");
- }
- asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
- }
-#endif
-return false;
-}
-
-bool SMUX::UpdateTables()
-{
-Sensors newSensors;
-bool done = true;
-Tables::iterator it(tables.begin());
-while (it != tables.end())
- {
- try
- {
- it->second->UpdateSensors(newSensors);
- }
- catch (const std::runtime_error & ex)
- {
- printfd(__FILE__,
- "SMUX::UpdateTables - failed to update table '%s': '%s'\n",
- it->first.c_str(), ex.what());
- done = false;
- break;
- }
- ++it;
- }
-if (!done)
- {
- Sensors::iterator it(newSensors.begin());
- while (it != newSensors.end())
- {
- delete it->second;
- ++it;
- }
- return false;
- }
-
-it = tables.begin();
-while (it != tables.end())
- {
- std::pair<Sensors::iterator, Sensors::iterator> res;
- res = std::equal_range(sensors.begin(),
- sensors.end(),
- std::pair<OID, Sensor *>(OID(it->first), NULL),
- SPrefixLess);
- Sensors::iterator sit(res.first);
- while (sit != res.second)
- {
- delete sit->second;
- ++sit;
- }
- sensors.erase(res.first, res.second);
- ++it;
- }
-
-sensors.insert(newSensors.begin(), newSensors.end());
-
-return true;
-}
-
-void SMUX::SetNotifier(UserPtr userPtr)
-{
-notifiers.push_back(CHG_AFTER_NOTIFIER(*this, userPtr));
-userPtr->GetProperties().tariffName.AddAfterNotifier(¬ifiers.back());
-}
-
-void SMUX::UnsetNotifier(UserPtr userPtr)
-{
-std::list<CHG_AFTER_NOTIFIER>::iterator it = notifiers.begin();
-while (it != notifiers.end())
- {
- if (it->GetUserPtr() == userPtr)
- {
- userPtr->GetProperties().tariffName.DelAfterNotifier(&(*it));
- notifiers.erase(it);
- break;
- }
- ++it;
- }
-}
-
-void SMUX::SetNotifiers()
-{
-int h = users->OpenSearch();
-assert(h && "USERS::OpenSearch is always correct");
-
-UserPtr u;
-while (!users->SearchNext(h, &u))
- SetNotifier(u);
-
-users->CloseSearch(h);
-
-users->AddNotifierUserAdd(&addUserNotifier);
-users->AddNotifierUserDel(&delUserNotifier);
-
-tariffs->AddNotifierAdd(&addDelTariffNotifier);
-tariffs->AddNotifierDel(&addDelTariffNotifier);
-}
-
-void SMUX::ResetNotifiers()
-{
-tariffs->DelNotifierDel(&addDelTariffNotifier);
-tariffs->DelNotifierAdd(&addDelTariffNotifier);
-
-users->DelNotifierUserDel(&delUserNotifier);
-users->DelNotifierUserAdd(&addUserNotifier);
-
-std::list<CHG_AFTER_NOTIFIER>::iterator it(notifiers.begin());
-while (it != notifiers.end())
- {
- it->GetUserPtr()->GetProperties().tariffName.DelAfterNotifier(&(*it));
- ++it;
- }
-notifiers.clear();
-}
+++ /dev/null
-#ifndef __SMUX_H__
-#define __SMUX_H__
-
-#include <pthread.h>
-
-#include <string>
-#include <map>
-#include <list>
-#include <cstdint>
-
-#include "stg/SMUX-PDUs.h"
-#include "stg/ObjectSyntax.h"
-
-#include "stg/plugin.h"
-#include "stg/module_settings.h"
-#include "stg/notifer.h"
-#include "stg/noncopyable.h"
-#include "stg/logger.h"
-
-#include "sensors.h"
-#include "tables.h"
-#include "types.h"
-
-namespace STG
-{
-struct User;
-struct Settings;
-struct Users;
-struct Tariffs;
-struct Services;
-struct Corporations;
-struct TraffCounter;
-}
-
-class SMUX;
-
-typedef bool (SMUX::*SMUXPacketHandler)(const SMUX_PDUs_t * pdus);
-typedef bool (SMUX::*PDUsHandler)(const PDUs_t * pdus);
-typedef std::map<SMUX_PDUs_PR, SMUXPacketHandler> SMUXHandlers;
-typedef std::map<PDUs_PR, PDUsHandler> PDUsHandlers;
-
-using UserPtr = STG::User*;
-//-----------------------------------------------------------------------------
-class SMUX_SETTINGS {
-public:
- SMUX_SETTINGS();
- virtual ~SMUX_SETTINGS() {}
- const std::string & GetStrError() const { return errorStr; }
- int ParseSettings(const STG::ModuleSettings & s);
-
- uint32_t GetIP() const { return ip; }
- uint16_t GetPort() const { return port; }
- const std::string GetPassword() const { return password; }
-
-private:
- mutable std::string errorStr;
-
- uint32_t ip;
- uint16_t port;
- std::string password;
-};
-//-----------------------------------------------------------------------------
-class CHG_AFTER_NOTIFIER : public STG::PropertyNotifierBase<std::string> {
-public:
- CHG_AFTER_NOTIFIER(SMUX & s, const UserPtr & u)
- : STG::PropertyNotifierBase<std::string>(),
- smux(s), userPtr(u) {}
- CHG_AFTER_NOTIFIER(const CHG_AFTER_NOTIFIER & rvalue)
- : STG::PropertyNotifierBase<std::string>(),
- smux(rvalue.smux), userPtr(rvalue.userPtr) {}
- void Notify(const std::string &, const std::string &);
-
- UserPtr GetUserPtr() const { return userPtr; }
-
-private:
- CHG_AFTER_NOTIFIER & operator=(const CHG_AFTER_NOTIFIER & rvalue);
- SMUX & smux;
- UserPtr userPtr;
-};
-//-----------------------------------------------------------------------------
-class ADD_DEL_TARIFF_NOTIFIER : public STG::NotifierBase<STG::TariffData> {
-public:
- explicit ADD_DEL_TARIFF_NOTIFIER(SMUX & s)
- : STG::NotifierBase<STG::TariffData>(), smux(s) {}
- void Notify(const STG::TariffData &);
-
-private:
- SMUX & smux;
-};
-//-----------------------------------------------------------------------------
-class ADD_USER_NOTIFIER : public STG::NotifierBase<UserPtr> {
-public:
- explicit ADD_USER_NOTIFIER(SMUX & s) : STG::NotifierBase<STG::User*>(), smux(s) {}
- void Notify(const UserPtr &);
-
-private:
- SMUX & smux;
-};
-//-----------------------------------------------------------------------------
-class DEL_USER_NOTIFIER : public STG::NotifierBase<UserPtr> {
-public:
- explicit DEL_USER_NOTIFIER(SMUX & s) : STG::NotifierBase<UserPtr>(), smux(s) {}
- void Notify(const UserPtr &);
-
-private:
- SMUX & smux;
-};
-//-----------------------------------------------------------------------------
-class SMUX : public STG::Plugin {
-public:
- SMUX();
- virtual ~SMUX();
-
- void SetUsers(STG::Users * u) { users = u; }
- void SetTariffs(STG::Tariffs * t) { tariffs = t; }
- void SetAdmins(STG::Admins * a) { admins = a; }
- void SetServices(STG::Services * s) { services = s; }
- void SetTraffcounter(STG::TraffCounter * tc) { traffcounter = tc; }
- void SetCorporations(STG::Corporations * c) { corporations = c; }
- void SetSettings(const STG::ModuleSettings & s) { settings = s; }
- int ParseSettings();
-
- int Start();
- int Stop();
- int Reload(const STG::ModuleSettings & ms);
- bool IsRunning() { return running && !stopped; }
-
- const std::string & GetStrError() const { return errorStr; }
- std::string GetVersion() const { return "Stg SMUX Plugin 1.1"; }
- uint16_t GetStartPosition() const { return 10; }
- uint16_t GetStopPosition() const { return 10; }
-
- bool UpdateTables();
-
- void SetNotifier(UserPtr userPtr);
- void UnsetNotifier(UserPtr userPtr);
-
-private:
- SMUX(const SMUX & rvalue);
- SMUX & operator=(const SMUX & rvalue);
-
- static void * Runner(void * d);
- void Run();
- bool PrepareNet();
- bool Reconnect();
-
- bool DispatchPDUs(const SMUX_PDUs_t * pdus);
-
- bool CloseHandler(const SMUX_PDUs_t * pdus);
- bool RegisterResponseHandler(const SMUX_PDUs_t * pdus);
- bool PDUsRequestHandler(const SMUX_PDUs_t * pdus);
- bool CommitOrRollbackHandler(const SMUX_PDUs_t * pdus);
-
- bool GetRequestHandler(const PDUs_t * pdus);
- bool GetNextRequestHandler(const PDUs_t * pdus);
- bool SetRequestHandler(const PDUs_t * pdus);
-
- void SetNotifiers();
- void ResetNotifiers();
-
- STG::Users * users;
- STG::Tariffs * tariffs;
- STG::Admins * admins;
- STG::Services * services;
- STG::Corporations * corporations;
- STG::TraffCounter * traffcounter;
-
- mutable std::string errorStr;
- SMUX_SETTINGS smuxSettings;
- STG::ModuleSettings settings;
-
- pthread_t thread;
- pthread_mutex_t mutex;
- bool running;
- bool stopped;
- bool needReconnect;
-
- time_t lastReconnectTry;
- unsigned reconnectTimeout;
-
- int sock;
-
- SMUXHandlers smuxHandlers;
- PDUsHandlers pdusHandlers;
- Sensors sensors;
- Tables tables;
-
- std::list<CHG_AFTER_NOTIFIER> notifiers;
- ADD_USER_NOTIFIER addUserNotifier;
- DEL_USER_NOTIFIER delUserNotifier;
- ADD_DEL_TARIFF_NOTIFIER addDelTariffNotifier;
-
- STG::PluginLogger logger;
-};
-//-----------------------------------------------------------------------------
-
-inline
-void CHG_AFTER_NOTIFIER::Notify(const std::string &, const std::string &)
-{
-smux.UpdateTables();
-}
-
-inline
-void ADD_DEL_TARIFF_NOTIFIER::Notify(const STG::TariffData &)
-{
-smux.UpdateTables();
-}
-
-inline
-void ADD_USER_NOTIFIER::Notify(const UserPtr & userPtr)
-{
-smux.SetNotifier(userPtr);
-smux.UpdateTables();
-}
-
-inline
-void DEL_USER_NOTIFIER::Notify(const UserPtr & userPtr)
-{
-smux.UnsetNotifier(userPtr);
-smux.UpdateTables();
-}
-
-#endif
+++ /dev/null
-#include <cassert>
-#include <utility>
-#include <iterator>
-#include <algorithm>
-
-#include "stg/user_property.h"
-#include "stg/tariffs.h"
-#include "stg/tariff_conf.h"
-#include "stg/users.h"
-
-#include "tables.h"
-
-std::pair<std::string, size_t> TD2Info(const STG::TariffData & td);
-
-void TariffUsersTable::UpdateSensors(Sensors & sensors) const
-{
-std::map<std::string, size_t> data;
-
-std::vector<STG::TariffData> tdl;
-tariffs.GetTariffsData(&tdl);
-std::transform(tdl.begin(),
- tdl.end(),
- std::inserter(data, data.begin()),
- TD2Info);
-
-int handle = users.OpenSearch();
-assert(handle && "USERS::OpenSearch is always correct");
-
-STG::User* user;
-while (!users.SearchNext(handle, &user))
- {
- if (user->GetDeleted())
- continue;
- std::string tariffName(user->GetProperties().tariffName.ConstData());
- std::map<std::string, size_t>::iterator it(data.lower_bound(tariffName));
- if (it == data.end() ||
- it->first != tariffName)
- {
- data.insert(it, std::make_pair(tariffName, 1));
- }
- else
- {
- ++it->second;
- }
- }
-
-users.CloseSearch(handle);
-
-size_t idx = 1;
-OID prefixOid(prefix);
-
-std::map<std::string, size_t>::const_iterator it(data.begin());
-while (it != data.end())
- {
- sensors[prefixOid.copyWithSuffix(2, static_cast<unsigned int>(idx))] = new ConstSensor<std::string>(it->first);
- sensors[prefixOid.copyWithSuffix(3, static_cast<unsigned int>(idx))] = new ConstSensor<unsigned long>(it->second);
- ++idx;
- ++it;
- }
-}
-
-std::pair<std::string, size_t> TD2Info(const STG::TariffData & td)
-{
-return std::make_pair(td.tariffConf.name, 0);
-}
+++ /dev/null
-#ifndef __TABLES_H__
-#define __TABLES_H__
-
-#include <string>
-#include <map>
-
-#include "sensors.h"
-
-namespace STG
-{
-struct Tariffs;
-struct Users;
-}
-
-class TableSensor {
- public:
- explicit TableSensor(const std::string & p) : prefix(p) {}
- virtual ~TableSensor() {}
-
- const std::string & GetPrefix() const { return prefix; }
- virtual void UpdateSensors(Sensors & sensors) const = 0;
-
- protected:
- std::string prefix;
-};
-
-class TariffUsersTable : public TableSensor {
- public:
- TariffUsersTable(const std::string & p,
- STG::Tariffs & t,
- STG::Users & u)
- : TableSensor(p),
- tariffs(t),
- users(u)
- {}
- virtual ~TariffUsersTable() {}
-
- void UpdateSensors(Sensors & sensors) const;
-
- private:
- STG::Tariffs & tariffs;
- STG::Users & users;
-};
-
-typedef std::map<std::string, TableSensor *> Tables;
-
-#endif
+++ /dev/null
-#include <stdexcept>
-#include <algorithm>
-#include <iterator>
-#include <sstream>
-
-#include "types.h"
-
-namespace
-{
-
-bool ParseArcs(const char * str, ptrdiff_t length, unsigned * a, size_t * pos);
-bool StringToArcs(const char * str, size_t length, std::vector<unsigned> & arcs);
-bool AppendToArcs(const char * str, size_t length, std::vector<unsigned> & arcs);
-
-bool ParseArcs(const char * str, ptrdiff_t length, unsigned * a, size_t * pos)
-{
-if (length == 0)
- return false;
-const char * left = str;
-if (*left == '.')
- ++left;
-size_t arcPos = 0;
-while ((left - str) < length)
- {
- char * pos = NULL;
- unsigned arc = static_cast<unsigned int>(strtoul(left, &pos, 10));
- if (pos == left)
- return false;
- a[arcPos++] = arc;
- if (arcPos >= 1024)
- return false;
- left = pos + 1;
- }
-*pos = arcPos;
-return true;
-}
-
-bool StringToArcs(const char * str, size_t length, std::vector<unsigned> & arcs)
-{
-unsigned a[1024];
-size_t pos = 0;
-
-if (!ParseArcs(str, length, a, &pos))
- return false;
-
-arcs.assign(a, a + pos);
-return true;
-}
-
-bool AppendToArcs(const char * str, size_t length, std::vector<unsigned> & arcs)
-{
-unsigned a[1024];
-size_t pos = 0;
-
-if (!ParseArcs(str, length, a, &pos))
- return false;
-
-std::copy(&a[0], &a[pos], std::back_inserter(arcs));
-return true;
-}
-
-}
-
-OID::OID(const std::string & str)
- : arcs()
-{
-if (!StringToArcs(str.c_str(), str.length(), arcs))
- throw std::runtime_error("Invalid oid");
-}
-
-OID::OID(const char * str, size_t length)
- : arcs()
-{
-if (!StringToArcs(str, length, arcs))
- throw std::runtime_error("Invalid oid");
-}
-
-OID::OID(const std::vector<unsigned> & a)
- : arcs(a)
-{
-}
-
-OID::OID(const unsigned * a, size_t length)
- : arcs()
-{
-std::vector<unsigned> newArcs(a, a + length);
-arcs.swap(newArcs);
-}
-
-OID::OID(OBJECT_IDENTIFIER_t * oid)
- : arcs()
-{
-unsigned a[1024];
-int count = OBJECT_IDENTIFIER_get_arcs(oid, a, sizeof(a[0]), 1024);
-
-if (count > 1024)
- throw std::runtime_error("OID is too long");
-
-std::vector<unsigned> newArcs(a, a + count);
-arcs.swap(newArcs);
-}
-
-OID::OID(const OID & rvalue)
- : arcs(rvalue.arcs)
-{
-}
-
-OID::~OID()
-{
-}
-
-bool OID::addSuffix(const char * suffix, size_t length)
-{
-if (!AppendToArcs(suffix, length, arcs))
- return false;
-return true;
-}
-
-bool OID::addSuffix(const std::string & suffix)
-{
-if (!AppendToArcs(suffix.c_str(), suffix.length(), arcs))
- return false;
-return true;
-}
-
-bool OID::addSuffix(const unsigned * suffix, size_t length)
-{
-std::copy(suffix, suffix + length, std::back_inserter(arcs));
-return true;
-}
-
-bool OID::addSuffix(const std::vector<unsigned> & suffix)
-{
-std::copy(suffix.begin(), suffix.end(), std::back_inserter(arcs));
-return true;
-}
-
-bool OID::addSuffix(unsigned a, unsigned b)
-{
-arcs.push_back(a);
-arcs.push_back(b);
-return true;
-}
-
-OID OID::copyWithSuffix(const char * suffix, size_t length) const
-{
-OID oid(*this);
-if (!oid.addSuffix(suffix, length))
- throw std::runtime_error("Invalid suffix");
-return oid;
-}
-
-OID OID::copyWithSuffix(const std::string & suffix) const
-{
-OID oid(*this);
-if (!oid.addSuffix(suffix))
- throw std::runtime_error("Invalid suffix");
-return oid;
-}
-
-OID OID::copyWithSuffix(const unsigned * suffix, size_t length) const
-{
-OID oid(*this);
-if (!oid.addSuffix(suffix, length))
- throw std::runtime_error("Invalid suffix");
-return oid;
-}
-
-OID OID::copyWithSuffix(const std::vector<unsigned> & suffix) const
-{
-OID oid(*this);
-if (!oid.addSuffix(suffix))
- throw std::runtime_error("Invalid suffix");
-return oid;
-}
-
-OID OID::copyWithSuffix(unsigned a, unsigned b) const
-{
-OID oid(*this);
-oid.addSuffix(a, b);
-return oid;
-}
-
-std::string OID::ToString() const
-{
-std::stringstream stream;
-for (size_t i = 0; i < arcs.size(); ++i)
- stream << "." << arcs[i];
-return stream.str();
-}
-
-void OID::ToOID(OBJECT_IDENTIFIER_t * oid) const
-{
-OBJECT_IDENTIFIER_set_arcs(oid, &arcs.front(), sizeof(unsigned), static_cast<unsigned int>(arcs.size()));
-}
-
-OID & OID::operator=(const OID & rvalue)
-{
-arcs = rvalue.arcs;
-return *this;
-}
-
-bool OID::operator==(const OID & rvalue) const
-{
-if (arcs.size() != rvalue.arcs.size())
- return false;
-for (size_t i = 0; i < arcs.size(); ++i)
- if (arcs[i] != rvalue.arcs[i])
- return false;
-return true;
-}
-
-bool OID::operator<(const OID & rvalue) const
-{
-size_t i = 0;
-size_t min = std::min(arcs.size(), rvalue.arcs.size());
-while (i < min &&
- arcs[i] == rvalue.arcs[i])
- ++i;
-if (i == min)
- {
- if (rvalue.arcs.size() > arcs.size())
- return true;
- return false;
- }
-
-if (arcs[i] < rvalue.arcs[i])
- return true;
-
-return false;
-}
-
-bool OID::PrefixLess(const OID & rvalue) const
-{
-size_t i = 0;
-size_t min = std::min(arcs.size(), rvalue.arcs.size());
-while (i < min &&
- arcs[i] == rvalue.arcs[i])
- ++i;
-if (i == min)
- return false;
-if (arcs[i] < rvalue.arcs[i])
- return true;
-return false;
-}
-
-std::ostream & operator<<(std::ostream & stream, const OID & oid)
-{
-for (size_t i = 0; i < oid.arcs.size(); ++i)
- stream << "." << oid.arcs[i];
-return stream;
-}
+++ /dev/null
-#ifndef __TYPES_H__
-#define __TYPES_H__
-
-#include <string>
-#include <vector>
-#include <iostream>
-
-#include "stg/OBJECT_IDENTIFIER.h"
-
-class OID {
- public:
- explicit OID(const std::string & str);
- OID(const char * str, size_t length);
- explicit OID(const std::vector<unsigned> & arcs);
- OID(const unsigned * arcs, size_t length);
- explicit OID(OBJECT_IDENTIFIER_t * oid);
- OID(const OID & rvalue);
- ~OID();
-
- bool addSuffix(const char * suffix, size_t length);
- bool addSuffix(const std::string & suffix);
- bool addSuffix(const unsigned * suffix, size_t length);
- bool addSuffix(const std::vector<unsigned> & suffix);
- bool addSuffix(unsigned a, unsigned b);
-
- OID copyWithSuffix(const char * suffix, size_t length) const;
- OID copyWithSuffix(const std::string & suffix) const;
- OID copyWithSuffix(const unsigned * suffix, size_t length) const;
- OID copyWithSuffix(const std::vector<unsigned> & suffix) const;
- OID copyWithSuffix(unsigned a, unsigned b) const;
-
- std::string ToString() const;
- const std::vector<unsigned> & ToVector() const { return arcs; }
- void ToOID(OBJECT_IDENTIFIER_t * oid) const;
-
- OID & operator=(const OID & rvalue);
- bool operator==(const OID & rvalue) const;
- bool operator!=(const OID & rvalue) const { return !operator==(rvalue); }
- bool operator<(const OID & rvalue) const;
- bool operator>(const OID & rvalue) const
- { return !operator==(rvalue) && !operator<(rvalue); }
-
- bool PrefixLess(const OID & rvalue) const;
-
- friend std::ostream & operator<<(std::ostream & stream, const OID & oid);
-
- private:
- std::vector<unsigned> arcs;
-};
-
-inline
-bool PrefixLess(const OID & a, const OID & b)
-{
-return a.PrefixLess(b);
-}
-
-#endif
+++ /dev/null
-#include <unistd.h> // write
-
-#include <cstring> // memset
-#include <cerrno>
-
-#include "stg/common.h"
-
-#include "stg/OpenPDU.h"
-#include "stg/ClosePDU.h"
-#include "stg/RReqPDU.h"
-#include "stg/ber_decoder.h"
-#include "stg/der_encoder.h"
-
-#include "pen.h"
-#include "utils.h"
-
-bool String2OI(const std::string & str, OBJECT_IDENTIFIER_t * oi)
-{
-size_t left = 0, pos = 0, arcPos = 0;
-int arcs[1024];
-pos = str.find_first_of('.', left);
-if (pos == 0)
- {
- left = 1;
- pos = str.find_first_of('.', left);
- }
-while (pos != std::string::npos)
- {
- int arc = 0;
- if (str2x(str.substr(left, left - pos), arc))
- {
- return false;
- }
- arcs[arcPos++] = arc;
- left = pos + 1;
- pos = str.find_first_of('.', left);
- }
-if (left < str.length())
- {
- int arc = 0;
- if (str2x(str.substr(left, left - pos), arc))
- {
- return false;
- }
- arcs[arcPos++] = arc;
- }
-OBJECT_IDENTIFIER_set_arcs(oi, arcs, sizeof(arcs[0]), static_cast<unsigned int>(arcPos));
-return true;
-}
-
-bool SendOpenPDU(int fd)
-{
-const char * description = "Stg SMUX Plugin";
-asn_enc_rval_t error;
-OpenPDU_t msg;
-
-memset(&msg, 0, sizeof(msg));
-
-msg.present = OpenPDU_PR_simple;
-asn_long2INTEGER(&msg.choice.simple.version, SimpleOpen__version_version_1);
-if (!String2OI(PEN_PREFIX, &msg.choice.simple.identity))
- {
- printfd(__FILE__,
- "SendOpenPDU() - failed to convert string to OBJECT_IDENTIFIER\n");
- return false;
- }
-OCTET_STRING_fromString(&msg.choice.simple.description, description);
-OCTET_STRING_fromString(&msg.choice.simple.password, "");
-
-char buffer[1024];
-error = der_encode_to_buffer(&asn_DEF_OpenPDU, &msg, buffer, sizeof(buffer));
-
-ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_OpenPDU, &msg);
-
-if (error.encoded == -1)
- {
- printfd(__FILE__, "Could not encode OpenPDU (at %s)\n",
- error.failed_type ? error.failed_type->name : "unknown");
- return false;
- }
-else
- {
- if (write(fd, buffer, error.encoded) < 0)
- {
- printfd(__FILE__, "Failed to send OpenPDU: %s\n", strerror(errno));
- return false;
- }
- }
-return true;
-}
-
-bool SendClosePDU(int fd)
-{
-ClosePDU_t msg;
-
-memset(&msg, 0, sizeof(msg));
-
-asn_long2INTEGER(&msg, ClosePDU_goingDown);
-
-char buffer[1024];
-asn_enc_rval_t error;
-error = der_encode_to_buffer(&asn_DEF_ClosePDU, &msg, buffer, sizeof(buffer));
-
-ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_ClosePDU, &msg);
-
-if (error.encoded == -1)
- {
- printfd(__FILE__, "Could not encode ClosePDU (at %s)\n",
- error.failed_type ? error.failed_type->name : "unknown");
- return false;
- }
-else
- {
- if (write(fd, buffer, error.encoded) < 0)
- {
- printfd(__FILE__, "Failed to send ClosePDU: %s\n", strerror(errno));
- return false;
- }
- }
-return true;
-}
-
-bool SendRReqPDU(int fd)
-{
-int oid[] = {1, 3, 6, 1, 4, 1, 38313, 1};
-asn_enc_rval_t error;
-RReqPDU_t msg;
-
-memset(&msg, 0, sizeof(msg));
-
-msg.priority = 0;
-asn_long2INTEGER(&msg.operation, RReqPDU__operation_readOnly);
-OBJECT_IDENTIFIER_set_arcs(&msg.subtree,
- oid,
- sizeof(oid[0]),
- 8);
-
-char buffer[1024];
-error = der_encode_to_buffer(&asn_DEF_RReqPDU, &msg, buffer, sizeof(buffer));
-
-ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RReqPDU, &msg);
-
-if (error.encoded == -1)
- {
- printfd(__FILE__, "Could not encode RReqPDU (at %s)\n",
- error.failed_type ? error.failed_type->name : "unknown");
- return false;
- }
-else
- {
- if (write(fd, buffer, error.encoded) < 0)
- {
- printfd(__FILE__, "Failed to send RReqPDU: %s\n", strerror(errno));
- return false;
- }
- }
-return true;
-}
-
-SMUX_PDUs_t * RecvSMUXPDUs(int fd)
-{
-char buffer[1024];
-SMUX_PDUs_t * pdus = NULL;
-
-memset(buffer, 0, sizeof(buffer));
-
-size_t length = read(fd, buffer, sizeof(buffer));
-if (length < 1)
- return NULL;
-asn_dec_rval_t error;
-error = ber_decode(0, &asn_DEF_SMUX_PDUs, (void **)&pdus, buffer, length);
-
-if(error.code != RC_OK)
- {
- printfd(__FILE__, "Failed to decode PDUs at byte %ld\n",
- (long)error.consumed);
- return NULL;
- }
-return pdus;
-}
-
-bool SendGetResponsePDU(int fd, GetResponse_PDU_t * getResponse)
-{
-asn_enc_rval_t error;
-
-char buffer[1024];
-error = der_encode_to_buffer(&asn_DEF_GetResponse_PDU, getResponse, buffer,
- sizeof(buffer));
-
-if (error.encoded == -1)
- {
- printfd(__FILE__, "Could not encode GetResponsePDU (at %s)\n",
- error.failed_type ? error.failed_type->name : "unknown");
- return false;
- }
-else
- {
- if (write(fd, buffer, error.encoded) < 0)
- {
- printfd(__FILE__, "Failed to send GetResponsePDU: %s\n", strerror(errno));
- return false;
- }
- }
-return true;
-}
-
-bool SendGetResponseErrorPDU(int fd,
- const PDU_t * getRequest,
- int errorStatus,
- int errorIndex)
-{
-asn_enc_rval_t error;
-GetResponse_PDU_t msg;
-
-memset(&msg, 0, sizeof(msg));
-
-long id = 0;
-asn_INTEGER2long(&getRequest->request_id, &id);
-asn_long2INTEGER(&msg.request_id, id);
-asn_long2INTEGER(&msg.error_status, errorStatus);
-asn_long2INTEGER(&msg.error_index, errorIndex);
-
-char buffer[1024];
-error = der_encode_to_buffer(&asn_DEF_GetResponse_PDU, &msg, buffer,
- sizeof(buffer));
-
-ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetResponse_PDU, &msg);
-
-if (error.encoded == -1)
- {
- printfd(__FILE__, "Could not encode GetResponsePDU for error (at %s)\n",
- error.failed_type ? error.failed_type->name : "unknown");
- return false;
- }
-else
- {
- if (write(fd, buffer, error.encoded) < 0)
- {
- printfd(__FILE__, "Failed to send GetResponseErrorPDU: %s\n", strerror(errno));
- return false;
- }
- }
-return true;
-}
+++ /dev/null
-#ifndef __UTILS_H__
-#define __UTILS_H__
-
-#include <string>
-
-#include "stg/OBJECT_IDENTIFIER.h"
-#include "stg/SMUX-PDUs.h"
-#include "stg/GetResponse-PDU.h"
-
-bool String2OI(const std::string & str, OBJECT_IDENTIFIER_t * oi);
-bool SendOpenPDU(int fd);
-bool SendClosePDU(int fd);
-bool SendRReqPDU(int fd);
-SMUX_PDUs_t * RecvSMUXPDUs(int fd);
-bool SendGetResponsePDU(int fd, GetResponse_PDU_t * getResponse);
-bool SendGetResponseErrorPDU(int fd,
- const PDU_t * getRequest,
- int errorStatus,
- int errorIndex);
-
-#endif
+++ /dev/null
-#ifndef __VALUE_2_OS_H__
-#define __VALUE_2_OS_H__
-
-#include "stg/ObjectSyntax.h"
-
-template <typename T>
-bool ValueToOS(const T & value, ObjectSyntax * objectSyntax);
-
-template <>
-inline
-bool ValueToOS<int>(const int & value, ObjectSyntax * objectSyntax)
-{
-objectSyntax->present = ObjectSyntax_PR_simple;
-SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
-simpleSyntax->present = SimpleSyntax_PR_number;
-asn_long2INTEGER(&simpleSyntax->choice.number, value);
-return true;
-}
-
-template <>
-inline
-bool ValueToOS<unsigned int>(const unsigned int & value, ObjectSyntax * objectSyntax)
-{
-objectSyntax->present = ObjectSyntax_PR_simple;
-SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
-simpleSyntax->present = SimpleSyntax_PR_number;
-asn_long2INTEGER(&simpleSyntax->choice.number, value);
-return true;
-}
-
-template <>
-inline
-bool ValueToOS<long>(const long & value, ObjectSyntax * objectSyntax)
-{
-objectSyntax->present = ObjectSyntax_PR_simple;
-SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
-simpleSyntax->present = SimpleSyntax_PR_number;
-asn_long2INTEGER(&simpleSyntax->choice.number, value);
-return true;
-}
-
-template <>
-inline
-bool ValueToOS<unsigned long>(const unsigned long & value, ObjectSyntax * objectSyntax)
-{
-objectSyntax->present = ObjectSyntax_PR_simple;
-SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
-simpleSyntax->present = SimpleSyntax_PR_number;
-asn_long2INTEGER(&simpleSyntax->choice.number, value);
-return true;
-}
-
-template <>
-inline
-bool ValueToOS<std::string>(const std::string & value, ObjectSyntax * objectSyntax)
-{
-objectSyntax->present = ObjectSyntax_PR_simple;
-SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
-simpleSyntax->present = SimpleSyntax_PR_string;
-OCTET_STRING_fromBuf(&simpleSyntax->choice.string, value.c_str(), static_cast<int>(value.length()));
-return true;
-}
-
-#endif
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-/*
- $Revision: 1.67 $
- $Date: 2010/10/07 19:53:11 $
- $Author: faust $
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include "file_store.h"
-
-#include "stg/common.h"
-#include "stg/user_ips.h"
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/const.h"
-#include "stg/blowfish.h"
-#include "stg/logger.h"
-#include "stg/locker.h"
-#include "stg/admin_conf.h"
-#include "stg/tariff.h"
-#include "stg/tariff_conf.h"
-#include "stg/service_conf.h"
-
-#include <sstream>
-#include <algorithm>
-#include <cstdio>
-#include <ctime>
-#include <cerrno>
-#include <cstring>
-
-#include <pwd.h>
-#include <grp.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#define DELETED_USERS_DIR "deleted_users"
-
-#define adm_enc_passwd "cjeifY8m3"
-
-int GetFileList(std::vector<std::string> * fileList, const std::string & directory, mode_t mode, const std::string & ext);
-
-const int pt_mega = 1024 * 1024;
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-namespace
-{
-
-bool CheckAndCreate(const std::string & dir, mode_t mode)
-{
-if (access(dir.c_str(), F_OK) == 0)
- return true;
-if (mkdir(dir.c_str(), mode) == 0)
- return true;
-return false;
-}
-
-}
-
-extern "C" STG::Store* GetStore()
-{
- static FILES_STORE plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-FILES_STORE_SETTINGS::FILES_STORE_SETTINGS()
- : settings(NULL),
- statMode(0),
- statUID(0),
- statGID(0),
- confMode(0),
- confUID(0),
- confGID(0),
- userLogMode(0),
- userLogUID(0),
- userLogGID(0),
- removeBak(true),
- readBak(true)
-{
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::ParseOwner(const std::vector<STG::ParamValue> & moduleParams, const std::string & owner, uid_t * uid)
-{
-STG::ParamValue pv;
-pv.param = owner;
-std::vector<STG::ParamValue>::const_iterator pvi;
-pvi = find(moduleParams.begin(), moduleParams.end(), pv);
-if (pvi == moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'" + owner + "\' not found.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-if (User2UID(pvi->value[0].c_str(), uid) < 0)
- {
- errorStr = "Parameter \'" + owner + "\': Unknown user \'" + pvi->value[0] + "\'";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::ParseGroup(const std::vector<STG::ParamValue> & moduleParams, const std::string & group, gid_t * gid)
-{
-STG::ParamValue pv;
-pv.param = group;
-std::vector<STG::ParamValue>::const_iterator pvi;
-pvi = find(moduleParams.begin(), moduleParams.end(), pv);
-if (pvi == moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'" + group + "\' not found.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-if (Group2GID(pvi->value[0].c_str(), gid) < 0)
- {
- errorStr = "Parameter \'" + group + "\': Unknown group \'" + pvi->value[0] + "\'";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::ParseYesNo(const std::string & value, bool * val)
-{
-if (0 == strcasecmp(value.c_str(), "yes"))
- {
- *val = true;
- return 0;
- }
-if (0 == strcasecmp(value.c_str(), "no"))
- {
- *val = false;
- return 0;
- }
-
-errorStr = "Incorrect value \'" + value + "\'.";
-return -1;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::ParseMode(const std::vector<STG::ParamValue> & moduleParams, const std::string & modeStr, mode_t * mode)
-{
-STG::ParamValue pv;
-pv.param = modeStr;
-std::vector<STG::ParamValue>::const_iterator pvi;
-pvi = find(moduleParams.begin(), moduleParams.end(), pv);
-if (pvi == moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'" + modeStr + "\' not found.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-if (Str2Mode(pvi->value[0].c_str(), mode) < 0)
- {
- errorStr = "Parameter \'" + modeStr + "\': Incorrect mode \'" + pvi->value[0] + "\'";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-if (ParseOwner(s.moduleParams, "StatOwner", &statUID) < 0)
- return -1;
-if (ParseGroup(s.moduleParams, "StatGroup", &statGID) < 0)
- return -1;
-if (ParseMode(s.moduleParams, "StatMode", &statMode) < 0)
- return -1;
-
-if (ParseOwner(s.moduleParams, "ConfOwner", &confUID) < 0)
- return -1;
-if (ParseGroup(s.moduleParams, "ConfGroup", &confGID) < 0)
- return -1;
-if (ParseMode(s.moduleParams, "ConfMode", &confMode) < 0)
- return -1;
-
-if (ParseOwner(s.moduleParams, "UserLogOwner", &userLogUID) < 0)
- return -1;
-if (ParseGroup(s.moduleParams, "UserLogGroup", &userLogGID) < 0)
- return -1;
-if (ParseMode(s.moduleParams, "UserLogMode", &userLogMode) < 0)
- return -1;
-
-std::vector<STG::ParamValue>::const_iterator pvi;
-STG::ParamValue pv;
-pv.param = "RemoveBak";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- removeBak = true;
- }
-else
- {
- if (ParseYesNo(pvi->value[0], &removeBak))
- {
- printfd(__FILE__, "Cannot parse parameter 'RemoveBak'\n");
- return -1;
- }
- }
-
-pv.param = "ReadBak";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- readBak = false;
- }
-else
- {
- if (ParseYesNo(pvi->value[0], &readBak))
- {
- printfd(__FILE__, "Cannot parse parameter 'ReadBak'\n");
- return -1;
- }
- }
-
-pv.param = "WorkDir";
-pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
-if (pvi == s.moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'WorkDir\' not found.";
- printfd(__FILE__, "Parameter 'WorkDir' not found\n");
- return -1;
- }
-
-workDir = pvi->value[0];
-if (workDir.size() && workDir[workDir.size() - 1] == '/')
- {
- workDir.resize(workDir.size() - 1);
- }
-usersDir = workDir + "/users/";
-if (!CheckAndCreate(usersDir, GetConfModeDir()))
- {
- errorStr = usersDir + " doesn't exist. Failed to create.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-tariffsDir = workDir + "/tariffs/";
-if (!CheckAndCreate(tariffsDir, GetConfModeDir()))
- {
- errorStr = tariffsDir + " doesn't exist. Failed to create.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-adminsDir = workDir + "/admins/";
-if (!CheckAndCreate(adminsDir, GetConfModeDir()))
- {
- errorStr = adminsDir + " doesn't exist. Failed to create.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-servicesDir = workDir + "/services/";
-if (!CheckAndCreate(servicesDir, GetConfModeDir()))
- {
- errorStr = servicesDir + " doesn't exist. Failed to create.";
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-const std::string & FILES_STORE_SETTINGS::GetStrError() const
-{
-return errorStr;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::User2UID(const char * user, uid_t * uid)
-{
-struct passwd * pw;
-pw = getpwnam(user);
-if (!pw)
- {
- errorStr = std::string("User \'") + std::string(user) + std::string("\' not found in system.");
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
-*uid = pw->pw_uid;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::Group2GID(const char * gr, gid_t * gid)
-{
-struct group * grp;
-grp = getgrnam(gr);
-if (!grp)
- {
- errorStr = std::string("Group \'") + std::string(gr) + std::string("\' not found in system.");
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
-*gid = grp->gr_gid;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE_SETTINGS::Str2Mode(const char * str, mode_t * mode)
-{
-char a;
-char b;
-char c;
-if (strlen(str) > 3)
- {
- errorStr = std::string("Error parsing mode \'") + str + std::string("\'");
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
-for (int i = 0; i < 3; i++)
- if (str[i] > '7' || str[i] < '0')
- {
- errorStr = std::string("Error parsing mode \'") + str + std::string("\'");
- printfd(__FILE__, "%s\n", errorStr.c_str());
- return -1;
- }
-
-a = str[0] - '0';
-b = str[1] - '0';
-c = str[2] - '0';
-
-*mode = ((mode_t)c) + ((mode_t)b << 3) + ((mode_t)a << 6);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-mode_t FILES_STORE_SETTINGS::GetStatModeDir() const
-{
-mode_t mode = statMode;
-if (statMode & S_IRUSR) mode |= S_IXUSR;
-if (statMode & S_IRGRP) mode |= S_IXGRP;
-if (statMode & S_IROTH) mode |= S_IXOTH;
-return mode;
-}
-//-----------------------------------------------------------------------------
-mode_t FILES_STORE_SETTINGS::GetConfModeDir() const
-{
-mode_t mode = confMode;
-if (confMode & S_IRUSR) mode |= S_IXUSR;
-if (confMode & S_IRGRP) mode |= S_IXGRP;
-if (confMode & S_IROTH) mode |= S_IXOTH;
-return mode;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-FILES_STORE::FILES_STORE()
- : version("file_store v.1.04"),
- logger(STG::PluginLogger::get("store_files"))
-{
-pthread_mutexattr_t attr;
-pthread_mutexattr_init(&attr);
-pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-pthread_mutex_init(&mutex, &attr);
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::ParseSettings()
-{
-int ret = storeSettings.ParseSettings(settings);
-if (ret)
- {
- STG_LOCKER lock(&mutex);
- errorStr = storeSettings.GetStrError();
- }
-return ret;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::GetUsersList(std::vector<std::string> * userList) const
-{
-std::vector<std::string> files;
-
-if (GetFileList(&files, storeSettings.GetUsersDir(), S_IFDIR, ""))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Failed to open '" + storeSettings.GetUsersDir() + "': " + std::string(strerror(errno));
- return -1;
- }
-
-STG_LOCKER lock(&mutex);
-
-userList->swap(files);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::GetAdminsList(std::vector<std::string> * adminList) const
-{
-std::vector<std::string> files;
-
-if (GetFileList(&files, storeSettings.GetAdminsDir(), S_IFREG, ".adm"))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Failed to open '" + storeSettings.GetAdminsDir() + "': " + std::string(strerror(errno));
- return -1;
- }
-
-STG_LOCKER lock(&mutex);
-
-adminList->swap(files);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::GetTariffsList(std::vector<std::string> * tariffList) const
-{
-std::vector<std::string> files;
-
-if (GetFileList(&files, storeSettings.GetTariffsDir(), S_IFREG, ".tf"))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Failed to open '" + storeSettings.GetTariffsDir() + "': " + std::string(strerror(errno));
- return -1;
- }
-
-STG_LOCKER lock(&mutex);
-
-tariffList->swap(files);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::GetServicesList(std::vector<std::string> * list) const
-{
-std::vector<std::string> files;
-
-if (GetFileList(&files, storeSettings.GetServicesDir(), S_IFREG, ".serv"))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Failed to open '" + storeSettings.GetServicesDir() + "': " + std::string(strerror(errno));
- return -1;
- }
-
-STG_LOCKER lock(&mutex);
-
-list->swap(files);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RemoveDir(const char * path) const
-{
-DIR * d = opendir(path);
-
-if (!d)
- {
- errorStr = "failed to open dir. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILE_STORE::RemoveDir() - Failed to open dir '%s': '%s'\n", path, strerror(errno));
- return -1;
- }
-
-dirent * entry;
-while ((entry = readdir(d)))
- {
- if (!(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")))
- continue;
-
- std::string str = path;
- str += "/" + std::string(entry->d_name);
-
- struct stat st;
- if (stat(str.c_str(), &st))
- continue;
-
- if ((st.st_mode & S_IFREG))
- {
- if (unlink(str.c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "unlink failed. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::RemoveDir() - unlink failed. Message: '%s'\n", strerror(errno));
- closedir(d);
- return -1;
- }
- }
-
- if (!(st.st_mode & S_IFDIR))
- {
- if (RemoveDir(str.c_str()))
- {
- closedir(d);
- return -1;
- }
-
- }
- }
-
-closedir(d);
-
-if (rmdir(path))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "rmdir failed. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::RemoveDir() - rmdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::AddUser(const std::string & login) const
-{
-std::string fileName;
-
-strprintf(&fileName, "%s%s", storeSettings.GetUsersDir().c_str(), login.c_str());
-
-if (mkdir(fileName.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("mkdir failed. Message: '") + strerror(errno) + "'";
- printfd(__FILE__, "FILES_STORE::AddUser - mkdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-strprintf(&fileName, "%s%s/conf", storeSettings.GetUsersDir().c_str(), login.c_str());
-if (Touch(fileName))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file \"" + fileName + "\'";
- printfd(__FILE__, "FILES_STORE::AddUser - fopen failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-strprintf(&fileName, "%s%s/stat", storeSettings.GetUsersDir().c_str(), login.c_str());
-if (Touch(fileName))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file \"" + fileName + "\'";
- printfd(__FILE__, "FILES_STORE::AddUser - fopen failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::DelUser(const std::string & login) const
-{
-std::string dirName;
-std::string dirName1;
-
-strprintf(&dirName, "%s/%s", storeSettings.GetWorkDir().c_str(), DELETED_USERS_DIR);
-if (access(dirName.c_str(), F_OK) != 0)
- {
- if (mkdir(dirName.c_str(), 0700) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Directory '" + dirName + "' cannot be created.";
- printfd(__FILE__, "FILES_STORE::DelUser - mkdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- }
-
-if (access(dirName.c_str(), F_OK) == 0)
- {
- strprintf(&dirName, "%s/%s/%s.%lu", storeSettings.GetWorkDir().c_str(), DELETED_USERS_DIR, login.c_str(), time(NULL));
- strprintf(&dirName1, "%s/%s", storeSettings.GetUsersDir().c_str(), login.c_str());
- if (rename(dirName1.c_str(), dirName.c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error moving dir from " + dirName1 + " to " + dirName;
- printfd(__FILE__, "FILES_STORE::DelUser - rename failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- }
-else
- {
- strprintf(&dirName, "%s/%s", storeSettings.GetUsersDir().c_str(), login.c_str());
- if (RemoveDir(dirName.c_str()))
- {
- return -1;
- }
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreUserConf(STG::UserConf * conf, const std::string & login) const
-{
-std::string fileName;
-fileName = storeSettings.GetUsersDir() + "/" + login + "/conf";
-if (RestoreUserConf(conf, login, fileName))
- {
- if (!storeSettings.GetReadBak())
- {
- return -1;
- }
- return RestoreUserConf(conf, login, fileName + ".bak");
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreUserConf(STG::UserConf * conf, const std::string & login, const std::string & fileName) const
-{
-CONFIGFILE cf(fileName);
-int e = cf.Error();
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - conf read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadString("Password", &conf->password, "") < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter Password.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - password read failed for user '%s'\n", login.c_str());
- return -1;
- }
-if (conf->password.empty())
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' password is blank.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - password is blank for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadString("tariff", &conf->tariffName, "") < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter Tariff.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - tariff read failed for user '%s'\n", login.c_str());
- return -1;
- }
-if (conf->tariffName.empty())
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' tariff is blank.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - tariff is blank for user '%s'\n", login.c_str());
- return -1;
- }
-
-std::string ipStr;
-cf.ReadString("IP", &ipStr, "?");
-try
- {
- conf->ips = STG::UserIPs::parse(ipStr);
- }
-catch (const std::string & s)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - ip read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadInt("alwaysOnline", &conf->alwaysOnline, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - alwaysonline read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadInt("down", &conf->disabled, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter Down.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - down read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadInt("passive", &conf->passive, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - passive read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-cf.ReadInt("DisabledDetailStat", &conf->disabledDetailStat, 0);
-cf.ReadTime("CreditExpire", &conf->creditExpire, 0);
-cf.ReadString("TariffChange", &conf->nextTariff, "");
-cf.ReadString("Group", &conf->group, "");
-cf.ReadString("RealName", &conf->realName, "");
-cf.ReadString("Address", &conf->address, "");
-cf.ReadString("Phone", &conf->phone, "");
-cf.ReadString("Note", &conf->note, "");
-cf.ReadString("email", &conf->email, "");
-
-char userdataName[12];
-for (int i = 0; i < USERDATA_NUM; i++)
- {
- snprintf(userdataName, 12, "Userdata%d", i);
- cf.ReadString(userdataName, &conf->userdata[i], "");
- }
-
-if (cf.ReadDouble("Credit", &conf->credit, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
- printfd(__FILE__, "FILES_STORE::RestoreUserConf - credit read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreUserStat(STG::UserStat * stat, const std::string & login) const
-{
-std::string fileName;
-fileName = storeSettings.GetUsersDir() + "/" + login + "/stat";
-
-if (RestoreUserStat(stat, login, fileName))
- {
- if (!storeSettings.GetReadBak())
- {
- return -1;
- }
- return RestoreUserStat(stat, login, fileName + ".bak");
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreUserStat(STG::UserStat * stat, const std::string & login, const std::string & fileName) const
-{
-CONFIGFILE cf(fileName);
-
-int e = cf.Error();
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Cannot open file " + fileName + ".";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - stat read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-char s[22];
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- uint64_t traff;
- snprintf(s, 22, "D%d", i);
- if (cf.ReadULongLongInt(s, &traff, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - download stat read failed for user '%s'\n", login.c_str());
- return -1;
- }
- stat->monthDown[i] = traff;
-
- snprintf(s, 22, "U%d", i);
- if (cf.ReadULongLongInt(s, &traff, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - upload stat read failed for user '%s'\n", login.c_str());
- return -1;
- }
- stat->monthUp[i] = traff;
- }
-
-if (cf.ReadDouble("Cash", &stat->cash, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter Cash";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - cash read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadDouble("FreeMb", &stat->freeMb, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter FreeMb";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - freemb read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadTime("LastCashAddTime", &stat->lastCashAddTime, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastcashaddtime read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadTime("PassiveTime", &stat->passiveTime, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter PassiveTime";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - passivetime read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadDouble("LastCashAdd", &stat->lastCashAdd, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAdd";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastcashadd read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-if (cf.ReadTime("LastActivityTime", &stat->lastActivityTime, 0) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "User \'" + login + "\' stat not read. Parameter LastActivityTime";
- printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastactivitytime read failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::SaveUserConf(const STG::UserConf & conf, const std::string & login) const
-{
-std::string fileName;
-fileName = storeSettings.GetUsersDir() + "/" + login + "/conf";
-
-CONFIGFILE cfstat(fileName, true);
-
-int e = cfstat.Error();
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("User \'") + login + "\' conf not written\n";
- printfd(__FILE__, "FILES_STORE::SaveUserConf - conf write failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-e = chmod(fileName.c_str(), storeSettings.GetConfMode());
-e += chown(fileName.c_str(), storeSettings.GetConfUID(), storeSettings.GetConfGID());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::SaveUserConf - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-cfstat.WriteString("Password", conf.password);
-cfstat.WriteInt ("Passive", conf.passive);
-cfstat.WriteInt ("Down", conf.disabled);
-cfstat.WriteInt("DisabledDetailStat", conf.disabledDetailStat);
-cfstat.WriteInt ("AlwaysOnline", conf.alwaysOnline);
-cfstat.WriteString("Tariff", conf.tariffName);
-cfstat.WriteString("Address", conf.address);
-cfstat.WriteString("Phone", conf.phone);
-cfstat.WriteString("Email", conf.email);
-cfstat.WriteString("Note", conf.note);
-cfstat.WriteString("RealName", conf.realName);
-cfstat.WriteString("Group", conf.group);
-cfstat.WriteDouble("Credit", conf.credit);
-cfstat.WriteString("TariffChange", conf.nextTariff);
-
-char userdataName[12];
-for (int i = 0; i < USERDATA_NUM; i++)
- {
- snprintf(userdataName, 12, "Userdata%d", i);
- cfstat.WriteString(userdataName, conf.userdata[i]);
- }
-cfstat.WriteInt("CreditExpire", conf.creditExpire);
-
-std::ostringstream ipStr;
-ipStr << conf.ips;
-cfstat.WriteString("IP", ipStr.str());
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::SaveUserStat(const STG::UserStat & stat, const std::string & login) const
-{
-std::string fileName;
-fileName = storeSettings.GetUsersDir() + "/" + login + "/stat";
-
- {
- CONFIGFILE cfstat(fileName, true);
- int e = cfstat.Error();
-
- if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("User \'") + login + "\' stat not written\n";
- printfd(__FILE__, "FILES_STORE::SaveUserStat - stat write failed for user '%s'\n", login.c_str());
- return -1;
- }
-
- for (int i = 0; i < DIR_NUM; i++)
- {
- char s[22];
- snprintf(s, 22, "D%d", i);
- cfstat.WriteInt(s, stat.monthDown[i]);
- snprintf(s, 22, "U%d", i);
- cfstat.WriteInt(s, stat.monthUp[i]);
- }
-
- cfstat.WriteDouble("Cash", stat.cash);
- cfstat.WriteDouble("FreeMb", stat.freeMb);
- cfstat.WriteDouble("LastCashAdd", stat.lastCashAdd);
- cfstat.WriteInt("LastCashAddTime", stat.lastCashAddTime);
- cfstat.WriteInt("PassiveTime", stat.passiveTime);
- cfstat.WriteInt("LastActivityTime", stat.lastActivityTime);
- }
-
-int e = chmod(fileName.c_str(), storeSettings.GetStatMode());
-e += chown(fileName.c_str(), storeSettings.GetStatUID(), storeSettings.GetStatGID());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::SaveUserStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::WriteLogString(const std::string & str, const std::string & login) const
-{
-FILE * f;
-time_t tm = time(NULL);
-std::string fileName;
-fileName = storeSettings.GetUsersDir() + "/" + login + "/log";
-f = fopen(fileName.c_str(), "at");
-
-if (f)
- {
- fprintf(f, "%s", LogDate(tm));
- fprintf(f, " -- ");
- fprintf(f, "%s", str.c_str());
- fprintf(f, "\n");
- fclose(f);
- }
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot open \'" + fileName + "\'";
- printfd(__FILE__, "FILES_STORE::WriteLogString - log write failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-int e = chmod(fileName.c_str(), storeSettings.GetLogMode());
-e += chown(fileName.c_str(), storeSettings.GetLogUID(), storeSettings.GetLogGID());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::WriteLogString - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::WriteLog2String(const std::string & str, const std::string & login) const
-{
-FILE * f;
-time_t tm = time(NULL);
-std::string fileName;
-fileName = storeSettings.GetUsersDir() + "/" + login + "/log2";
-f = fopen(fileName.c_str(), "at");
-
-if (f)
- {
- fprintf(f, "%s", LogDate(tm));
- fprintf(f, " -- ");
- fprintf(f, "%s", str.c_str());
- fprintf(f, "\n");
- fclose(f);
- }
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot open \'" + fileName + "\'";
- printfd(__FILE__, "FILES_STORE::WriteLogString - log write failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-int e = chmod(fileName.c_str(), storeSettings.GetLogMode());
-e += chown(fileName.c_str(), storeSettings.GetLogUID(), storeSettings.GetLogGID());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::WriteLogString - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message) const
-{
-std::string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
- + paramName + "\' parameter changed from \'" + oldValue +
- "\' to \'" + newValue + "\'. " + message;
-
-return WriteLogString(userLogMsg, login);
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
-{
-std::string logStr = "Connect, " + inet_ntostring(ip);
-if (WriteLogString(logStr, login))
- return -1;
-return WriteLog2String(logStr, login);
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & monthUp,
- const STG::DirTraff & monthDown,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double freeMb,
- const std::string & reason) const
-{
-std::ostringstream logStr;
-logStr << "Disconnect, "
- << " session upload: \'"
- << sessionUp
- << "\' session download: \'"
- << sessionDown
- << "\' month upload: \'"
- << monthUp
- << "\' month download: \'"
- << monthDown
- << "\' cash: \'"
- << cash
- << "\'";
-
-if (WriteLogString(logStr.str(), login))
- return -1;
-
-logStr << " freeMb: \'"
- << freeMb
- << "\'"
- << " reason: \'"
- << reason
- << "\'";
-
-return WriteLog2String(logStr.str(), login);
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
-{
-// Classic stats
-std::string stat1;
-strprintf(&stat1,"%s/%s/stat.%d.%02d",
- storeSettings.GetUsersDir().c_str(), login.c_str(), year + 1900, month + 1);
-
-CONFIGFILE s(stat1, true);
-
-if (s.Error())
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file '" + stat1 + "'";
- printfd(__FILE__, "FILES_STORE::SaveMonthStat - month stat write failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-// New stats
-std::string stat2;
-strprintf(&stat2,"%s/%s/stat2.%d.%02d",
- storeSettings.GetUsersDir().c_str(), login.c_str(), year + 1900, month + 1);
-
-CONFIGFILE s2(stat2, true);
-
-if (s2.Error())
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file '" + stat2 + "'";
- printfd(__FILE__, "FILES_STORE::SaveMonthStat - month stat write failed for user '%s'\n", login.c_str());
- return -1;
- }
-
-for (size_t i = 0; i < DIR_NUM; i++)
- {
- char dirName[3];
- snprintf(dirName, 3, "U%llu", (unsigned long long)i);
- s.WriteInt(dirName, stat.monthUp[i]); // Classic
- s2.WriteInt(dirName, stat.monthUp[i]); // New
- snprintf(dirName, 3, "D%llu", (unsigned long long)i);
- s.WriteInt(dirName, stat.monthDown[i]); // Classic
- s2.WriteInt(dirName, stat.monthDown[i]); // New
- }
-
-// Classic
-s.WriteDouble("cash", stat.cash);
-
-// New
-s2.WriteDouble("Cash", stat.cash);
-s2.WriteDouble("FreeMb", stat.freeMb);
-s2.WriteDouble("LastCashAdd", stat.lastCashAdd);
-s2.WriteInt("LastCashAddTime", stat.lastCashAddTime);
-s2.WriteInt("PassiveTime", stat.passiveTime);
-s2.WriteInt("LastActivityTime", stat.lastActivityTime);
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int FILES_STORE::AddAdmin(const std::string & login) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
-
-if (Touch(fileName))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file " + fileName;
- printfd(__FILE__, "FILES_STORE::AddAdmin - failed to add admin '%s'\n", login.c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int FILES_STORE::DelAdmin(const std::string & login) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
-if (unlink(fileName.c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "unlink failed. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
- }
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int FILES_STORE::SaveAdmin(const STG::AdminConf & ac) const
-{
-std::string fileName;
-
-strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), ac.login.c_str());
-
- {
- CONFIGFILE cf(fileName, true);
-
- int e = cf.Error();
-
- if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot write admin " + ac.login + ". " + fileName;
- printfd(__FILE__, "FILES_STORE::SaveAdmin - failed to save admin '%s'\n", ac.login.c_str());
- return -1;
- }
-
- char pass[ADM_PASSWD_LEN + 1];
- memset(pass, 0, sizeof(pass));
-
- char adminPass[ADM_PASSWD_LEN + 1];
- memset(adminPass, 0, sizeof(adminPass));
-
- BLOWFISH_CTX ctx;
- InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
-
- strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
- adminPass[ADM_PASSWD_LEN - 1] = 0;
-
- for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
- {
- EncryptBlock(pass + 8*i, adminPass + 8*i, &ctx);
- }
-
- pass[ADM_PASSWD_LEN - 1] = 0;
- char passwordE[2 * ADM_PASSWD_LEN + 2];
- Encode12(passwordE, pass, ADM_PASSWD_LEN);
-
- cf.WriteString("password", passwordE);
- cf.WriteInt("ChgConf", ac.priv.userConf);
- cf.WriteInt("ChgPassword", ac.priv.userPasswd);
- cf.WriteInt("ChgStat", ac.priv.userStat);
- cf.WriteInt("ChgCash", ac.priv.userCash);
- cf.WriteInt("UsrAddDel", ac.priv.userAddDel);
- cf.WriteInt("ChgTariff", ac.priv.tariffChg);
- cf.WriteInt("ChgAdmin", ac.priv.adminChg);
- cf.WriteInt("ChgService", ac.priv.serviceChg);
- cf.WriteInt("ChgCorp", ac.priv.corpChg);
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
-CONFIGFILE cf(fileName);
-char pass[ADM_PASSWD_LEN + 1];
-char password[ADM_PASSWD_LEN + 1];
-char passwordE[2 * ADM_PASSWD_LEN + 2];
-BLOWFISH_CTX ctx;
-
-std::string p;
-
-if (cf.Error())
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot open " + fileName;
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - failed to restore admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadString("password", &p, "*"))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter password";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - password read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-memset(passwordE, 0, sizeof(passwordE));
-strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
-
-memset(pass, 0, sizeof(pass));
-
-if (passwordE[0] != 0)
- {
- Decode21(pass, passwordE);
- InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
-
- for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
- {
- DecryptBlock(password + 8*i, pass + 8*i, &ctx);
- }
- }
-else
- {
- password[0] = 0;
- }
-
-ac->password = password;
-
-uint16_t a;
-
-if (cf.ReadUShortInt("ChgConf", &a, 0) == 0)
- ac->priv.userConf = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter ChgConf";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgconf read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("ChgPassword", &a, 0) == 0)
- ac->priv.userPasswd = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter ChgPassword";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgpassword read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("ChgStat", &a, 0) == 0)
- ac->priv.userStat = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter ChgStat";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgstat read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("ChgCash", &a, 0) == 0)
- ac->priv.userCash = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter ChgCash";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgcash read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("UsrAddDel", &a, 0) == 0)
- ac->priv.userAddDel = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter UsrAddDel";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - usradddel read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("ChgAdmin", &a, 0) == 0)
- ac->priv.adminChg = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter ChgAdmin";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgadmin read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("ChgTariff", &a, 0) == 0)
- ac->priv.tariffChg = a;
-else
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter ChgTariff";
- printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgtariff read failed for admin '%s'\n", ac->login.c_str());
- return -1;
- }
-
-if (cf.ReadUShortInt("ChgService", &a, 0) == 0)
- ac->priv.serviceChg = a;
-else
- ac->priv.serviceChg = 0;
-
-if (cf.ReadUShortInt("ChgCorp", &a, 0) == 0)
- ac->priv.corpChg = a;
-else
- ac->priv.corpChg = 0;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::AddTariff(const std::string & name) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.tf", storeSettings.GetTariffsDir().c_str(), name.c_str());
-if (Touch(fileName))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file " + fileName;
- printfd(__FILE__, "FILES_STORE::AddTariff - failed to add tariff '%s'\n", name.c_str());
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::DelTariff(const std::string & name) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.tf", storeSettings.GetTariffsDir().c_str(), name.c_str());
-if (unlink(fileName.c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "unlink failed. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::DelTariff - unlink failed. Message: '%s'\n", strerror(errno));
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreTariff(STG::TariffData * td, const std::string & tariffName) const
-{
-std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
-CONFIGFILE conf(fileName);
-std::string str;
-td->tariffConf.name = tariffName;
-
-if (conf.Error() != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read file " + fileName;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - failed to read tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
-std::string param;
-for (int i = 0; i<DIR_NUM; i++)
- {
- strprintf(¶m, "Time%d", i);
- if (conf.ReadString(param, &str, "00:00-00:00") < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - time%d read failed for tariff '%s'\n", i, tariffName.c_str());
- return -1;
- }
-
- ParseTariffTimeStr(str.c_str(),
- td->dirPrice[i].hDay,
- td->dirPrice[i].mDay,
- td->dirPrice[i].hNight,
- td->dirPrice[i].mNight);
-
- strprintf(¶m, "PriceDayA%d", i);
- if (conf.ReadDouble(param, &td->dirPrice[i].priceDayA, 0.0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - pricedaya read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
- td->dirPrice[i].priceDayA /= (1024*1024);
-
- strprintf(¶m, "PriceDayB%d", i);
- if (conf.ReadDouble(param, &td->dirPrice[i].priceDayB, 0.0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - pricedayb read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
- td->dirPrice[i].priceDayB /= (1024*1024);
-
- strprintf(¶m, "PriceNightA%d", i);
- if (conf.ReadDouble(param, &td->dirPrice[i].priceNightA, 0.0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - pricenighta read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
- td->dirPrice[i].priceNightA /= (1024*1024);
-
- strprintf(¶m, "PriceNightB%d", i);
- if (conf.ReadDouble(param, &td->dirPrice[i].priceNightB, 0.0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - pricenightb read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
- td->dirPrice[i].priceNightB /= (1024*1024);
-
- strprintf(¶m, "Threshold%d", i);
- if (conf.ReadInt(param, &td->dirPrice[i].threshold, 0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - threshold read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
- strprintf(¶m, "SinglePrice%d", i);
- if (conf.ReadInt(param, &td->dirPrice[i].singlePrice, 0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - singleprice read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
- strprintf(¶m, "NoDiscount%d", i);
- if (conf.ReadInt(param, &td->dirPrice[i].noDiscount, 0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - nodiscount read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
- }
-
-if (conf.ReadDouble("Fee", &td->tariffConf.fee, 0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
- printfd(__FILE__, "FILES_STORE::RestoreTariff - fee read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
-if (conf.ReadDouble("Free", &td->tariffConf.free, 0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
- printfd(__FILE__, "FILES_STORE::RestoreTariff - free read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
-if (conf.ReadDouble("PassiveCost", &td->tariffConf.passiveCost, 0) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
- printfd(__FILE__, "FILES_STORE::RestoreTariff - passivecost read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
-if (conf.ReadString("TraffType", &str, "") < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType";
- printfd(__FILE__, "FILES_STORE::RestoreTariff - trafftype read failed for tariff '%s'\n", tariffName.c_str());
- return -1;
- }
-
-td->tariffConf.traffType = STG::Tariff::parseTraffType(str);
-
-if (conf.ReadString("Period", &str, "month") < 0)
- td->tariffConf.period = STG::Tariff::MONTH;
-else
- td->tariffConf.period = STG::Tariff::parsePeriod(str);
-
-if (conf.ReadString("ChangePolicy", &str, "allow") < 0)
- td->tariffConf.changePolicy = STG::Tariff::ALLOW;
-else
- td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(str);
-
-conf.ReadTime("ChangePolicyTimeout", &td->tariffConf.changePolicyTimeout, 0);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::SaveTariff(const STG::TariffData & td, const std::string & tariffName) const
-{
-std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
-
- {
- CONFIGFILE cf(fileName, true);
-
- int e = cf.Error();
-
- if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error writing tariff " + tariffName;
- printfd(__FILE__, "FILES_STORE::RestoreTariff - failed to save tariff '%s'\n", tariffName.c_str());
- return e;
- }
-
- std::string param;
- for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, "PriceDayA%d", i);
- cf.WriteDouble(param, td.dirPrice[i].priceDayA * pt_mega);
-
- strprintf(¶m, "PriceDayB%d", i);
- cf.WriteDouble(param, td.dirPrice[i].priceDayB * pt_mega);
-
- strprintf(¶m, "PriceNightA%d", i);
- cf.WriteDouble(param, td.dirPrice[i].priceNightA * pt_mega);
-
- strprintf(¶m, "PriceNightB%d", i);
- cf.WriteDouble(param, td.dirPrice[i].priceNightB * pt_mega);
-
- strprintf(¶m, "Threshold%d", i);
- cf.WriteInt(param, td.dirPrice[i].threshold);
-
- std::string s;
- strprintf(¶m, "Time%d", i);
-
- strprintf(&s, "%0d:%0d-%0d:%0d",
- td.dirPrice[i].hDay,
- td.dirPrice[i].mDay,
- td.dirPrice[i].hNight,
- td.dirPrice[i].mNight);
-
- cf.WriteString(param, s);
-
- strprintf(¶m, "NoDiscount%d", i);
- cf.WriteInt(param, td.dirPrice[i].noDiscount);
-
- strprintf(¶m, "SinglePrice%d", i);
- cf.WriteInt(param, td.dirPrice[i].singlePrice);
- }
-
- cf.WriteDouble("PassiveCost", td.tariffConf.passiveCost);
- cf.WriteDouble("Fee", td.tariffConf.fee);
- cf.WriteDouble("Free", td.tariffConf.free);
- cf.WriteString("TraffType", STG::Tariff::toString(td.tariffConf.traffType));
- cf.WriteString("Period", STG::Tariff::toString(td.tariffConf.period));
- cf.WriteString("ChangePolicy", STG::Tariff::toString(td.tariffConf.changePolicy));
- cf.WriteTime("ChangePolicyTimeout", td.tariffConf.changePolicyTimeout);
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int FILES_STORE::AddService(const std::string & name) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
-
-if (Touch(fileName))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot create file " + fileName;
- printfd(__FILE__, "FILES_STORE::AddService - failed to add service '%s'\n", name.c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int FILES_STORE::DelService(const std::string & name) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
-if (unlink(fileName.c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "unlink failed. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
- }
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int FILES_STORE::SaveService(const STG::ServiceConf & conf) const
-{
-std::string fileName;
-
-strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), conf.name.c_str());
-
- {
- CONFIGFILE cf(fileName, true);
-
- int e = cf.Error();
-
- if (e)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot write service " + conf.name + ". " + fileName;
- printfd(__FILE__, "FILES_STORE::SaveService - failed to save service '%s'\n", conf.name.c_str());
- return -1;
- }
-
- cf.WriteString("name", conf.name);
- cf.WriteString("comment", conf.comment);
- cf.WriteDouble("cost", conf.cost);
- cf.WriteInt("pay_day", conf.payDay);
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::RestoreService(STG::ServiceConf * conf, const std::string & name) const
-{
-std::string fileName;
-strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
-CONFIGFILE cf(fileName);
-
-if (cf.Error())
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot open " + fileName;
- printfd(__FILE__, "FILES_STORE::RestoreService - failed to restore service '%s'\n", name.c_str());
- return -1;
- }
-
-if (cf.ReadString("name", &conf->name, name))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter 'name'";
- printfd(__FILE__, "FILES_STORE::RestoreService - name read failed for service '%s'\n", name.c_str());
- return -1;
- }
-
-if (cf.ReadString("comment", &conf->comment, ""))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter 'comment'";
- printfd(__FILE__, "FILES_STORE::RestoreService - comment read failed for service '%s'\n", name.c_str());
- return -1;
- }
-
-if (cf.ReadDouble("cost", &conf->cost, 0.0))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter 'cost'";
- printfd(__FILE__, "FILES_STORE::RestoreService - cost read failed for service '%s'\n", name.c_str());
- return -1;
- }
-
-unsigned short value = 0;
-if (cf.ReadUShortInt("pay_day", &value, 0))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error in parameter 'pay_day'";
- printfd(__FILE__, "FILES_STORE::RestoreService - pay day read failed for service '%s'\n", name.c_str());
- return -1;
- }
-conf->payDay = value;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const
-{
-char fn[FN_STR_LEN];
-char dn[FN_STR_LEN];
-FILE * statFile;
-time_t t;
-tm * lt;
-
-t = time(NULL);
-
-snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat", storeSettings.GetUsersDir().c_str(), login.c_str());
-if (access(dn, F_OK) != 0)
- {
- if (mkdir(dn, 0700) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Directory \'" + std::string(dn) + "\' cannot be created.";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- }
-
-int e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
-e += chmod(dn, storeSettings.GetStatModeDir());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-lt = localtime(&t);
-
-if (lt->tm_hour == 0 && lt->tm_min <= 5)
- {
- t -= 3600 * 24;
- lt = localtime(&t);
- }
-
-snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat/%d",
- storeSettings.GetUsersDir().c_str(),
- login.c_str(),
- lt->tm_year+1900);
-
-if (access(dn, F_OK) != 0)
- {
- if (mkdir(dn, 0700) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Directory \'" + std::string(dn) + "\' cannot be created.";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- }
-
-e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
-e += chmod(dn, storeSettings.GetStatModeDir());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat/%d/%s%d",
- storeSettings.GetUsersDir().c_str(),
- login.c_str(),
- lt->tm_year+1900,
- lt->tm_mon+1 < 10 ? "0" : "",
- lt->tm_mon+1);
-if (access(dn, F_OK) != 0)
- {
- if (mkdir(dn, 0700) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Directory \'" + std::string(dn) + "\' cannot be created.";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- }
-
-e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
-e += chmod(dn, storeSettings.GetStatModeDir());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-snprintf(fn, FN_STR_LEN, "%s/%s%d", dn, lt->tm_mday < 10 ? "0" : "", lt->tm_mday);
-
-statFile = fopen (fn, "at");
-
-if (!statFile)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "File \'" + std::string(fn) + "\' cannot be written.";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - fopen failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-struct tm * lt1;
-struct tm * lt2;
-
-lt1 = localtime(&lastStat);
-
-int h1, m1, s1;
-int h2, m2, s2;
-
-h1 = lt1->tm_hour;
-m1 = lt1->tm_min;
-s1 = lt1->tm_sec;
-
-lt2 = localtime(&t);
-
-h2 = lt2->tm_hour;
-m2 = lt2->tm_min;
-s2 = lt2->tm_sec;
-
-if (fprintf(statFile, "-> %02d.%02d.%02d - %02d.%02d.%02d\n",
- h1, m1, s1, h2, m2, s2) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("fprint failed. Message: '") + strerror(errno) + "'";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
- fclose(statFile);
- return -1;
- }
-
-auto stIter = statTree.begin();
-
-while (stIter != statTree.end())
- {
- const auto u = std::to_string(stIter->second.up);
- const auto d = std::to_string(stIter->second.down);
- #ifdef TRAFF_STAT_WITH_PORTS
- if (fprintf(statFile, "%17s:%hu\t%15d\t%15s\t%15s\t%f\n",
- inet_ntostring(stIter->first.ip).c_str(),
- stIter->first.port,
- stIter->first.dir,
- d.c_str(),
- u.c_str(),
- stIter->second.cash) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "fprint failed. Message: '";
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
- fclose(statFile);
- return -1;
- }
- #else
- if (fprintf(statFile, "%17s\t%15d\t%15s\t%15s\t%f\n",
- inet_ntostring(stIter->first.ip).c_str(),
- stIter->first.dir,
- d.c_str(),
- u.c_str(),
- stIter->second.cash) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("fprint failed. Message: '");
- errorStr += strerror(errno);
- errorStr += "'";
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
- fclose(statFile);
- return -1;
- }
- #endif
-
- ++stIter;
- }
-
-fclose(statFile);
-
-e = chown(fn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
-e += chmod(fn, storeSettings.GetStatMode());
-
-if (e)
- {
- STG_LOCKER lock(&mutex);
- printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::AddMessage(STG::Message * msg, const std::string & login) const
-{
-std::string fn;
-std::string dn;
-struct timeval tv;
-
-strprintf(&dn, "%s/%s/messages", storeSettings.GetUsersDir().c_str(), login.c_str());
-if (access(dn.c_str(), F_OK) != 0)
- {
- if (mkdir(dn.c_str(), 0700) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Directory \'";
- errorStr += dn;
- errorStr += "\' cannot be created.";
- printfd(__FILE__, "FILES_STORE::AddMessage - mkdir failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- }
-
-chmod(dn.c_str(), storeSettings.GetConfModeDir());
-
-gettimeofday(&tv, NULL);
-
-msg->header.id = ((long long)tv.tv_sec) * 1000000 + ((long long)tv.tv_usec);
-strprintf(&fn, "%s/%lld", dn.c_str(), msg->header.id);
-
-if (Touch(fn))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "File \'";
- errorStr += fn;
- errorStr += "\' cannot be writen.";
- printfd(__FILE__, "FILES_STORE::AddMessage - fopen failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-return EditMessage(*msg, login);
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::EditMessage(const STG::Message & msg, const std::string & login) const
-{
-std::string fileName;
-
-FILE * msgFile;
-strprintf(&fileName, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), msg.header.id);
-
-if (access(fileName.c_str(), F_OK) != 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Message for user \'";
- errorStr += login + "\' with ID \'";
- errorStr += std::to_string(msg.header.id) + "\' does not exist.";
- printfd(__FILE__, "FILES_STORE::EditMessage - %s\n", errorStr.c_str());
- return -1;
- }
-
-Touch(fileName + ".new");
-
-msgFile = fopen((fileName + ".new").c_str(), "wt");
-if (!msgFile)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "File \'" + fileName + "\' cannot be writen.";
- printfd(__FILE__, "FILES_STORE::EditMessage - fopen failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-bool res = true;
-res &= (fprintf(msgFile, "%u\n", msg.header.type) >= 0);
-res &= (fprintf(msgFile, "%u\n", msg.header.lastSendTime) >= 0);
-res &= (fprintf(msgFile, "%u\n", msg.header.creationTime) >= 0);
-res &= (fprintf(msgFile, "%u\n", msg.header.showTime) >= 0);
-res &= (fprintf(msgFile, "%d\n", msg.header.repeat) >= 0);
-res &= (fprintf(msgFile, "%u\n", msg.header.repeatPeriod) >= 0);
-res &= (fprintf(msgFile, "%s", msg.text.c_str()) >= 0);
-
-if (!res)
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("fprintf failed. Message: '") + strerror(errno) + "'";
- printfd(__FILE__, "FILES_STORE::EditMessage - fprintf failed. Message: '%s'\n", strerror(errno));
- fclose(msgFile);
- return -1;
- }
-
-fclose(msgFile);
-
-chmod((fileName + ".new").c_str(), storeSettings.GetConfMode());
-
-if (rename((fileName + ".new").c_str(), fileName.c_str()) < 0)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Error moving dir from " + fileName + ".new to " + fileName;
- printfd(__FILE__, "FILES_STORE::EditMessage - rename failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const
-{
-std::string fn;
-strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), id);
-msg->header.id = id;
-return ReadMessage(fn, &msg->header, &msg->text);
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::DelMessage(uint64_t id, const std::string & login) const
-{
-std::string fn;
-strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), id);
-
-return unlink(fn.c_str());
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const
-{
-std::string dn(storeSettings.GetUsersDir() + "/" + login + "/messages/");
-
-if (access(dn.c_str(), F_OK) != 0)
- {
- return 0;
- }
-
-std::vector<std::string> messages;
-GetFileList(&messages, dn, S_IFREG, "");
-
-for (unsigned i = 0; i < messages.size(); i++)
- {
- unsigned long long id = 0;
-
- if (str2x(messages[i].c_str(), id))
- {
- if (unlink((dn + messages[i]).c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("unlink failed. Message: '") + strerror(errno) + "'";
- printfd(__FILE__, "FILES_STORE::GetMessageHdrs - unlink failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- continue;
- }
-
- STG::Message::Header hdr;
- if (ReadMessage(dn + messages[i], &hdr, NULL))
- {
- return -1;
- }
-
- if (hdr.repeat < 0)
- {
- if (unlink((dn + messages[i]).c_str()))
- {
- STG_LOCKER lock(&mutex);
- errorStr = std::string("unlink failed. Message: '") + strerror(errno) + "'";
- printfd(__FILE__, "FILES_STORE::GetMessageHdrs - unlink failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
- continue;
- }
-
- hdr.id = id;
- hdrsList->push_back(hdr);
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::ReadMessage(const std::string & fileName,
- STG::Message::Header * hdr,
- std::string * text) const
-{
-FILE * msgFile;
-msgFile = fopen(fileName.c_str(), "rt");
-if (!msgFile)
- {
- STG_LOCKER lock(&mutex);
- errorStr = "File \'";
- errorStr += fileName;
- errorStr += "\' cannot be openned.";
- printfd(__FILE__, "FILES_STORE::ReadMessage - fopen failed. Message: '%s'\n", strerror(errno));
- return -1;
- }
-char p[20];
-unsigned * d[6];
-d[0] = &hdr->type;
-d[1] = &hdr->lastSendTime;
-d[2] = &hdr->creationTime;
-d[3] = &hdr->showTime;
-d[4] = (unsigned*)(&hdr->repeat);
-d[5] = &hdr->repeatPeriod;
-
-memset(p, 0, sizeof(p));
-
-for (int pos = 0; pos < 6; pos++)
- {
- if (fgets(p, sizeof(p) - 1, msgFile) == NULL) {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read file \'";
- errorStr += fileName;
- errorStr += "\'. Missing data.";
- printfd(__FILE__, "FILES_STORE::ReadMessage - cannot read file (missing data)\n");
- printfd(__FILE__, "FILES_STORE::ReadMessage - position: %d\n", pos);
- fclose(msgFile);
- return -1;
- }
-
- char * ep;
- ep = strrchr(p, '\r');
- if (ep) *ep = 0;
- ep = strrchr(p, '\n');
- if (ep) *ep = 0;
-
- if (feof(msgFile))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read file \'";
- errorStr += fileName;
- errorStr += "\'. Missing data.";
- printfd(__FILE__, "FILES_STORE::ReadMessage - cannot read file (feof)\n");
- printfd(__FILE__, "FILES_STORE::ReadMessage - position: %d\n", pos);
- fclose(msgFile);
- return -1;
- }
-
- if (str2x(p, *(d[pos])))
- {
- STG_LOCKER lock(&mutex);
- errorStr = "Cannot read file \'";
- errorStr += fileName;
- errorStr += "\'. Incorrect value. \'";
- errorStr += p;
- errorStr += "\'";
- printfd(__FILE__, "FILES_STORE::ReadMessage - incorrect value\n");
- fclose(msgFile);
- return -1;
- }
- }
-
-char txt[2048];
-memset(txt, 0, sizeof(txt));
-if (text)
- {
- text->erase(text->begin(), text->end());
- while (!feof(msgFile))
- {
- txt[0] = 0;
- if (fgets(txt, sizeof(txt) - 1, msgFile) == NULL) {
- break;
- }
-
- (*text) += txt;
- }
- }
-fclose(msgFile);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FILES_STORE::Touch(const std::string & path) const
-{
-FILE * f = fopen(path.c_str(), "wb");
-if (f)
- {
- fclose(f);
- return 0;
- }
-return -1;
-}
-//-----------------------------------------------------------------------------
-int GetFileList(std::vector<std::string> * fileList, const std::string & directory, mode_t mode, const std::string & ext)
-{
-DIR * d = opendir(directory.c_str());
-
-if (!d)
- {
- printfd(__FILE__, "GetFileList - Failed to open dir '%s': '%s'\n", directory.c_str(), strerror(errno));
- return -1;
- }
-
-dirent * entry;
-while ((entry = readdir(d)))
- {
- if (!(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")))
- continue;
-
- std::string str = directory + "/" + std::string(entry->d_name);
-
- struct stat st;
- if (stat(str.c_str(), &st))
- continue;
-
- if (!(st.st_mode & mode)) // Filter by mode
- continue;
-
- if (!ext.empty())
- {
- // Check extension
- size_t d_nameLen = strlen(entry->d_name);
- if (d_nameLen <= ext.size())
- continue;
-
- if (ext == entry->d_name + (d_nameLen - ext.size()))
- {
- entry->d_name[d_nameLen - ext.size()] = 0;
- fileList->push_back(entry->d_name);
- }
- }
- else
- {
- fileList->push_back(entry->d_name);
- }
- }
-
-closedir(d);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/module_settings.h"
-#include "stg/store.h"
-#include "stg/conffiles.h"
-#include "stg/user_traff.h"
-#include "stg/logger.h"
-
-#include <string>
-
-#include <sys/types.h>
-#include <pthread.h>
-
-//-----------------------------------------------------------------------------
-class FILES_STORE_SETTINGS {
-public:
- FILES_STORE_SETTINGS();
- int ParseSettings(const STG::ModuleSettings & s);
- const std::string & GetStrError() const;
-
- std::string GetWorkDir() const { return workDir; }
- std::string GetUsersDir() const { return usersDir; }
- std::string GetAdminsDir() const { return adminsDir; }
- std::string GetTariffsDir() const { return tariffsDir; }
- std::string GetServicesDir() const { return servicesDir; }
-
- mode_t GetStatMode() const { return statMode; }
- mode_t GetStatModeDir() const;
- uid_t GetStatUID() const { return statUID; }
- gid_t GetStatGID() const { return statGID; }
-
- mode_t GetConfMode() const { return confMode; }
- mode_t GetConfModeDir() const;
- uid_t GetConfUID() const { return confUID; }
- gid_t GetConfGID() const { return confGID; }
-
- mode_t GetLogMode() const { return userLogMode; }
- uid_t GetLogUID() const { return userLogUID; }
- gid_t GetLogGID() const { return userLogGID; }
-
- bool GetRemoveBak() const { return removeBak; }
- bool GetReadBak() const { return readBak; }
-
-private:
- FILES_STORE_SETTINGS(const FILES_STORE_SETTINGS & rvalue);
- FILES_STORE_SETTINGS & operator=(const FILES_STORE_SETTINGS & rvalue);
-
- const STG::ModuleSettings * settings;
-
- int User2UID(const char * user, uid_t * uid);
- int Group2GID(const char * gr, gid_t * gid);
- int Str2Mode(const char * str, mode_t * mode);
- int ParseOwner(const std::vector<STG::ParamValue> & moduleParams, const std::string & owner, uid_t * uid);
- int ParseGroup(const std::vector<STG::ParamValue> & moduleParams, const std::string & group, uid_t * uid);
- int ParseMode(const std::vector<STG::ParamValue> & moduleParams, const std::string & modeStr, mode_t * mode);
- int ParseYesNo(const std::string & value, bool * val);
-
- std::string errorStr;
-
- std::string workDir;
- std::string usersDir;
- std::string adminsDir;
- std::string tariffsDir;
- std::string servicesDir;
-
- mode_t statMode;
- uid_t statUID;
- gid_t statGID;
-
- mode_t confMode;
- uid_t confUID;
- gid_t confGID;
-
- mode_t userLogMode;
- uid_t userLogUID;
- gid_t userLogGID;
-
- bool removeBak;
- bool readBak;
-};
-//-----------------------------------------------------------------------------
-class FILES_STORE: public STG::Store {
-public:
- FILES_STORE();
- const std::string & GetStrError() const override { return errorStr; }
-
- //User
- int GetUsersList(std::vector<std::string> * usersList) const override;
- int AddUser(const std::string & login) const override;
- int DelUser(const std::string & login) const override;
- int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
- int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
-
- int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
- int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
-
- int WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message = "") const override;
- int WriteUserConnect(const std::string & login, uint32_t ip) const override;
- int WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & up,
- const STG::DirTraff & down,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double freeMb,
- const std::string & reason) const override;
-
- int WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const override;
-
- int AddMessage(STG::Message * msg, const std::string & login) const override;
- int EditMessage(const STG::Message & msg, const std::string & login) const override;
- int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
- int DelMessage(uint64_t id, const std::string & login) const override;
- int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
-
- int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
-
- //Admin
- int GetAdminsList(std::vector<std::string> * adminsList) const override;
- int AddAdmin(const std::string & login) const override;
- int DelAdmin(const std::string & login) const override;
- int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
- int SaveAdmin(const STG::AdminConf & ac) const override;
-
- //Tariff
- int GetTariffsList(std::vector<std::string> * tariffsList) const override;
- int AddTariff(const std::string & name) const override;
- int DelTariff(const std::string & name) const override;
- int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
- int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
-
- //Corparation
- int GetCorpsList(std::vector<std::string> *) const override { return 0; }
- int SaveCorp(const STG::CorpConf &) const override { return 0; }
- int RestoreCorp(STG::CorpConf *, const std::string &) const override { return 0; }
- int AddCorp(const std::string &) const override { return 0; }
- int DelCorp(const std::string &) const override { return 0; }
-
- // Services
- int GetServicesList(std::vector<std::string> *) const override;
- int SaveService(const STG::ServiceConf &) const override;
- int RestoreService(STG::ServiceConf *, const std::string &) const override;
- int AddService(const std::string &) const override;
- int DelService(const std::string &) const override;
-
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
- const std::string & GetVersion() const override { return version; }
-
-private:
- FILES_STORE(const FILES_STORE & rvalue);
- FILES_STORE & operator=(const FILES_STORE & rvalue);
-
- int ReadMessage(const std::string & fileName,
- STG::Message::Header * hdr,
- std::string * text) const;
-
- virtual int RestoreUserStat(STG::UserStat * stat, const std::string & login, const std::string & fileName) const;
- virtual int RestoreUserConf(STG::UserConf * conf, const std::string & login, const std::string & fileName) const;
-
- virtual int WriteLogString(const std::string & str, const std::string & login) const;
- virtual int WriteLog2String(const std::string & str, const std::string & login) const;
- int RemoveDir(const char * path) const;
- int Touch(const std::string & path) const;
-
- mutable std::string errorStr;
- std::string version;
- FILES_STORE_SETTINGS storeSettings;
- STG::ModuleSettings settings;
- mutable pthread_mutex_t mutex;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * This file contains a realization of a base firebird-storage plugin class
- *
- * $Revision: 1.18 $
- * $Date: 2010/01/08 16:00:45 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/common.h"
-
-#include <string>
-#include <vector>
-
-extern "C" STG::Store* GetStore()
-{
- static FIREBIRD_STORE plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-FIREBIRD_STORE::FIREBIRD_STORE()
- : version("firebird_store v.1.4"),
- db_server("localhost"),
- db_database("/var/stg/stargazer.fdb"),
- db_user("stg"),
- db_password("123456"),
- til(IBPP::ilConcurrency),
- tlr(IBPP::lrWait),
- schemaVersion(0),
- logger(STG::PluginLogger::get("store_firebird"))
-{
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-FIREBIRD_STORE::~FIREBIRD_STORE()
-{
-db->Disconnect();
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::ParseSettings()
-{
-std::vector<STG::ParamValue>::iterator i;
-std::string s;
-
-for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
- {
- if (i->value.empty())
- continue;
- s = ToLower(i->param);
-
- if (s == "server")
- db_server = i->value.front();
-
- if (s == "database")
- db_database = i->value.front();
-
- if (s == "user")
- db_user = i->value.front();
-
- if (s == "password")
- db_password = i->value.front();
-
- // Advanced settings block
-
- if (s == "isolationLevel")
- {
- if (i->value.front() == "Concurrency")
- til = IBPP::ilConcurrency;
- else if (i->value.front() == "DirtyRead")
- til = IBPP::ilReadDirty;
- else if (i->value.front() == "ReadCommitted")
- til = IBPP::ilReadCommitted;
- else if (i->value.front() == "Consistency")
- til = IBPP::ilConsistency;
- }
-
- if (s == "lockResolution")
- {
- if (i->value.front() == "Wait")
- tlr = IBPP::lrWait;
- else if (i->value.front() == "NoWait")
- tlr = IBPP::lrNoWait;
- }
- }
-
-try
- {
- db = IBPP::DatabaseFactory(db_server, db_database, db_user, db_password, "", "KOI8U", "");
- db->Connect();
- return CheckVersion();
- }
-catch (IBPP::Exception & ex)
- {
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::CheckVersion()
-{
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Execute("SELECT RDB$RELATION_NAME FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG=0 AND RDB$RELATION_NAME = 'TB_INFO'");
- if (!st->Fetch())
- {
- schemaVersion = 0;
- }
- else
- {
- st->Execute("SELECT version FROM tb_info");
- while (st->Fetch())
- st->Get(1, schemaVersion);
- }
- tr->Commit();
- logger("FIREBIRD_STORE: Current DB schema version: %d", schemaVersion);
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/store.h"
-#include "stg/locker.h"
-#include "stg/ibpp.h"
-#include "stg/logger.h"
-#include "stg/module_settings.h"
-
-#include <ctime>
-#include <string>
-#include <vector>
-
-struct ToLower {
- char operator() (char c) const { return static_cast<char>(std::tolower(c)); }
-};
-
-class FIREBIRD_STORE : public STG::Store {
-public:
- FIREBIRD_STORE();
- ~FIREBIRD_STORE() override;
-
- int GetUsersList(std::vector<std::string> * usersList) const override;
- int AddUser(const std::string & login) const override;
- int DelUser(const std::string & login) const override;
- int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
- int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
- int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
- int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
- int WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message) const override;
- int WriteUserConnect(const std::string & login, uint32_t ip) const override;
- int WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & up,
- const STG::DirTraff & down,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double freeMb,
- const std::string & reason) const override;
- int WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const override;
-
- int AddMessage(STG::Message * msg, const std::string & login) const override;
- int EditMessage(const STG::Message & msg, const std::string & login) const override;
- int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
- int DelMessage(uint64_t id, const std::string & login) const override;
- int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
-
- int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
-
- int GetAdminsList(std::vector<std::string> * adminsList) const override;
- int SaveAdmin(const STG::AdminConf & ac) const override;
- int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
- int AddAdmin(const std::string & login) const override;
- int DelAdmin(const std::string & login) const override;
-
- int GetTariffsList(std::vector<std::string> * tariffsList) const override;
- int AddTariff(const std::string & name) const override;
- int DelTariff(const std::string & name) const override;
- int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
- int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
-
- int GetCorpsList(std::vector<std::string> * corpsList) const override;
- int SaveCorp(const STG::CorpConf & cc) const override;
- int RestoreCorp(STG::CorpConf * cc, const std::string & name) const override;
- int AddCorp(const std::string & name) const override;
- int DelCorp(const std::string & name) const override;
-
- inline void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- inline const std::string & GetStrError() const override { return strError; }
-
- inline const std::string & GetVersion() const override { return version; }
-
- int GetServicesList(std::vector<std::string> * servicesList) const override;
- int SaveService(const STG::ServiceConf & sc) const override;
- int RestoreService(STG::ServiceConf * sc, const std::string & name) const override;
- int AddService(const std::string & name) const override;
- int DelService(const std::string & name) const override;
-
-private:
- FIREBIRD_STORE(const FIREBIRD_STORE & rvalue);
- FIREBIRD_STORE & operator=(const FIREBIRD_STORE & rvalue);
-
- std::string version;
- mutable std::string strError;
- std::string db_server, db_database, db_user, db_password;
- STG::ModuleSettings settings;
- mutable IBPP::Database db;
- mutable pthread_mutex_t mutex;
- IBPP::TIL til;
- IBPP::TLR tlr;
- int schemaVersion;
- STG::PluginLogger logger;
-
- int SaveStat(const STG::UserStat & stat, const std::string & login, int year = 0, int month = 0) const;
- int CheckVersion();
-};
-
-time_t ts2time_t(const IBPP::Timestamp & ts);
-void time_t2ts(time_t t, IBPP::Timestamp * ts);
-void ym2date(int year, int month, IBPP::Date * date);
-
-template <typename T>
-inline
-T Get(IBPP::Statement st, size_t pos)
-{
- T value;
- st->Get(pos, value);
- return value;
-}
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Administrators manipulation methods
- *
- * $Revision: 1.11 $
- * $Date: 2008/12/04 17:10:06 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/admin_conf.h"
-#include "stg/blowfish.h"
-#include "stg/common.h"
-
-#include <string>
-#include <vector>
-
-#define adm_enc_passwd "cjeifY8m3"
-
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-std::string login;
-
-try
- {
- tr->Start();
- st->Execute("select login from tb_admins");
- while (st->Fetch())
- {
- st->Get(1, login);
- adminsList->push_back(login);
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveAdmin(const STG::AdminConf & ac) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-char encodedPass[2 * ADM_PASSWD_LEN + 2];
-char cryptedPass[ADM_PASSWD_LEN + 1];
-char adminPass[ADM_PASSWD_LEN + 1];
-BLOWFISH_CTX ctx;
-
-memset(cryptedPass, 0, ADM_PASSWD_LEN + 1);
-strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
-InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
-
-for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
- EncryptBlock(cryptedPass + 8 * i, adminPass + 8 * i, &ctx);
-
-cryptedPass[ADM_PASSWD_LEN] = 0;
-Encode12(encodedPass, cryptedPass, ADM_PASSWD_LEN);
-
-try
- {
- tr->Start();
- st->Prepare("update tb_admins set passwd=?, \
- chg_conf=?, \
- chg_password=?, \
- chg_stat=?, \
- chg_cash=?, \
- usr_add_del=?, \
- chg_tariff=?, \
- chg_admin=? \
- where login=?");
- st->Set(1, encodedPass);
- st->Set(2, static_cast<int16_t>(ac.priv.userConf));
- st->Set(3, static_cast<int16_t>(ac.priv.userPasswd));
- st->Set(4, static_cast<int16_t>(ac.priv.userStat));
- st->Set(5, static_cast<int16_t>(ac.priv.userCash));
- st->Set(6, static_cast<int16_t>(ac.priv.userAddDel));
- st->Set(7, static_cast<int16_t>(ac.priv.tariffChg));
- st->Set(8, static_cast<int16_t>(ac.priv.adminChg));
- st->Set(9, ac.login);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-char cryptedPass[ADM_PASSWD_LEN + 1];
-char adminPass[ADM_PASSWD_LEN + 1];
-BLOWFISH_CTX ctx;
-
-try
- {
- tr->Start();
- st->Prepare("select * from tb_admins where login = ?");
- st->Set(1, login);
- st->Execute();
- if (st->Fetch())
- {
- st->Get(2, ac->login);
- st->Get(3, ac->password);
- st->Get(4, (int16_t &)ac->priv.userConf);
- st->Get(5, (int16_t &)ac->priv.userPasswd);
- st->Get(6, (int16_t &)ac->priv.userStat);
- st->Get(7, (int16_t &)ac->priv.userCash);
- st->Get(8, (int16_t &)ac->priv.userAddDel);
- st->Get(9, (int16_t &)ac->priv.tariffChg);
- st->Get(10, (int16_t &)ac->priv.adminChg);
- }
- else
- {
- strError = "Admin \"" + login + "\" not found in database";
- printfd(__FILE__, "Admin '%s' not found in database\n", login.c_str());
- tr->Rollback();
- return -1;
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-if (ac->password == "")
- {
- return 0;
- }
-
-Decode21(cryptedPass, ac->password.c_str());
-InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
-for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
- {
- DecryptBlock(adminPass + 8 * i, cryptedPass + 8 * i, &ctx);
- }
-ac->password = adminPass;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::AddAdmin(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("insert into tb_admins(login, \
- passwd, \
- chg_conf, \
- chg_password, \
- chg_stat, \
- chg_cash, \
- usr_add_del, \
- chg_tariff, \
- chg_admin, \
- chg_service, \
- chg_corporation) \
- values (?, '', 0, 0, 0, 0, 0, 0, 0, 0, 0)");
- st->Set(1, login);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::DelAdmin(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("delete from tb_admins where login = ?");
- st->Set(1, login);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Corporations manipulation methods
- *
- * $Revision: 1.5 $
- * $Date: 2007/12/23 13:39:59 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/corp_conf.h"
-#include "stg/common.h"
-
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetCorpsList(std::vector<std::string> * corpsList) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-std::string name;
-
-try
- {
- tr->Start();
- st->Execute("select name from tb_corporations");
- while (st->Fetch())
- {
- st->Get(1, name);
- corpsList->push_back(name);
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveCorp(const STG::CorpConf & cc) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Execute("update tb_corporations set cash = ? where name = ?");
- st->Set(1, cc.cash);
- st->Set(2, cc.name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::RestoreCorp(STG::CorpConf * cc, const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select cash from tb_corporations where name = ?");
- st->Set(1, name);
- st->Execute();
- if (st->Fetch())
- {
- st->Get(1, cc->cash);
- }
- else
- {
- strError = "Corporation \"" + name + "\" not found in database";
- tr->Rollback();
- printfd(__FILE__, "Corporation '%s' not found in database\n", name.c_str());
- return -1;
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::AddCorp(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("insert into tb_corporations (name, cash), values (?, 0)");
- st->Set(1, name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::DelCorp(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("delete from tb_corporations where name = ?");
- st->Set(1, name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-
-/*
- * Messages manipualtion methods
- *
- * $Revision: 1.10 $
- * $Date: 2009/03/03 16:16:23 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/message.h"
-#include "stg/common.h"
-
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::AddMessage(STG::Message * msg, const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_add_message(NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
- st->Set(1, login);
- st->Set(2, (int32_t)msg->header.ver);
- st->Set(3, (int32_t)msg->header.type);
- st->Set(4, (int32_t)msg->header.lastSendTime);
- st->Set(5, (int32_t)msg->header.creationTime);
- st->Set(6, (int32_t)msg->header.showTime);
- st->Set(7, msg->header.repeat);
- st->Set(8, (int32_t)msg->header.repeatPeriod);
- st->Set(9, msg->text);
- st->Execute();
- st->Get(1, (int64_t &)msg->header.id);
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::EditMessage(const STG::Message & msg,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_add_message(?, ?, ?, ?, ?, ?, ?, ?, ?)");
- st->Set(1, (int64_t)msg.header.id);
- st->Set(2, login);
- st->Set(3, (int32_t)msg.header.ver);
- st->Set(4, (int32_t)msg.header.type);
- st->Set(5, (int32_t)msg.header.lastSendTime);
- st->Set(6, (int32_t)msg.header.creationTime);
- st->Set(7, (int32_t)msg.header.showTime);
- st->Set(8, msg.header.repeat);
- st->Set(9, (int32_t)msg.header.repeatPeriod);
- st->Set(10, msg.text.c_str());
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetMessage(uint64_t id,
- STG::Message * msg,
- const std::string &) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select * from tb_messages where pk_message = ?");
- st->Set(1, (int64_t)id);
- st->Execute();
- if (st->Fetch())
- {
- st->Get(1, (int64_t &)msg->header.id);
- st->Get(3, (int32_t &)msg->header.ver);
- st->Get(4, (int32_t &)msg->header.type);
- st->Get(5, (int32_t &)msg->header.lastSendTime);
- st->Get(6, (int32_t &)msg->header.creationTime);
- st->Get(7, (int32_t &)msg->header.showTime);
- st->Get(8, msg->header.repeat);
- st->Get(9, (int32_t &)msg->header.repeatPeriod);
- st->Get(10, msg->text);
- }
- else
- {
- strprintf(&strError, "Message with id = %d not found in database", id);
- printfd(__FILE__, "Message with id - %d not found in database\n", id);
- tr->Rollback();
- return -1;
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::DelMessage(uint64_t id, const std::string &) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("delete from tb_messages where pk_message = ?");
- st->Set(1, (int64_t)id);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-STG::Message::Header header;
-
-try
- {
- tr->Start();
- st->Prepare("select pk_message, ver, msg_type, \
- last_send_time, creation_time, \
- show_time, repeat, repeat_period \
- from tb_messages where \
- fk_user = (select pk_user from tb_users where name = ?)");
- st->Set(1, login);
- st->Execute();
- while (st->Fetch())
- {
- st->Get(1, (int64_t &)header.id);
- st->Get(2, (int32_t &)header.ver);
- st->Get(3, (int32_t &)header.type);
- st->Get(4, (int32_t &)header.lastSendTime);
- st->Get(5, (int32_t &)header.creationTime);
- st->Get(6, (int32_t &)header.showTime);
- st->Get(7, header.repeat);
- st->Get(8, (int32_t &)header.repeatPeriod);
- hdrsList->push_back(header);
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-
-/*
- * Services manipulation methods
- *
- * $Revision: 1.6 $
- * $Date: 2009/05/13 13:19:33 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/service_conf.h"
-#include "stg/common.h"
-
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetServicesList(std::vector<std::string> * servicesList) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-std::string name;
-
-try
- {
- tr->Start();
- st->Execute("select name from tb_services");
- while (st->Fetch())
- {
- st->Get(1, name);
- servicesList->push_back(name);
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveService(const STG::ServiceConf & sc) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("update tb_services set \
- comments = ?, \
- cost = ?, \
- pay_day = ? \
- where name = ?");
- st->Set(1, sc.comment);
- st->Set(2, sc.cost);
- st->Set(3, static_cast<int16_t>(sc.payDay));
- st->Set(4, sc.name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::RestoreService(STG::ServiceConf * sc,
- const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select * from tb_services where name = ?");
- st->Set(1, name);
- st->Execute();
- if (st->Fetch())
- {
- st->Get(3, sc->comment);
- st->Get(4, sc->cost);
- int16_t pd;
- st->Get(5, pd);
- sc->payDay = static_cast<uint8_t>(pd);
- }
- else
- {
- strError = "Service \"" + name + "\" not found in database";
- printfd(__FILE__, "Service '%s' not found in database\n", name.c_str());
- tr->Rollback();
- return -1;
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::AddService(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("insert into tb_services (name, comment, cost, pay_day) \
- values (?, '', 0, 0)");
- st->Set(1, name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::DelService(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_delete_service(?)");
- st->Set(1, name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Tariffs manipulation methods
- *
- * $Revision: 1.5 $
- * $Date: 2007/12/23 13:39:59 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/tariff.h"
-#include "stg/tariff_conf.h"
-#include "stg/common.h"
-
-#include <cmath>
-
-namespace
-{
-
-const int pt_mega = 1024 * 1024;
-
-}
-
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-std::string name;
-
-try
- {
- tr->Start();
- st->Execute("select name from tb_tariffs");
- while (st->Fetch())
- {
- st->Get(1, name);
- tariffsList->push_back(name);
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::AddTariff(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_add_tariff(?, ?)");
- st->Set(1, name);
- st->Set(2, DIR_NUM);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::DelTariff(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_delete_tariff(?)");
- st->Set(1, name);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveTariff(const STG::TariffData & td,
- const std::string & tariffName) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select pk_tariff from tb_tariffs where name = ?");
- st->Set(1, tariffName);
- st->Execute();
- if (!st->Fetch())
- {
- tr->Rollback();
- strprintf(&strError, "Tariff \"%s\" not found in database", tariffName.c_str());
- printfd(__FILE__, "Tariff '%s' not found in database\n", tariffName.c_str());
- return -1;
- }
- int32_t id;
- st->Get(1, id);
- st->Close();
-
- std::string query = "update tb_tariffs set \
- fee = ?, \
- free = ?, \
- passive_cost = ?, \
- traff_type = ?";
-
- if (schemaVersion > 0)
- query += ", period = ?";
- if (schemaVersion > 1)
- query += ", change_policy = ?, \
- change_policy_timeout = ?";
-
- query += " where pk_tariff = ?";
-
- unsigned num = 5;
- st->Prepare(query);
- st->Set(1, td.tariffConf.fee);
- st->Set(2, td.tariffConf.free);
- st->Set(3, td.tariffConf.passiveCost);
- st->Set(4, td.tariffConf.traffType);
-
- if (schemaVersion > 0)
- {
- st->Set(5, STG::Tariff::toString(td.tariffConf.period));
- ++num;
- }
-
- if (schemaVersion > 1)
- {
- st->Set(6, STG::Tariff::toString(td.tariffConf.changePolicy));
- IBPP::Timestamp policyTimeout;
- time_t2ts(td.tariffConf.changePolicyTimeout, &policyTimeout);
- st->Set(7, policyTimeout);
- num += 2;
- }
-
- st->Set(num, id);
- st->Execute();
- st->Close();
-
- IBPP::Time tb;
- IBPP::Time te;
-
- for(int i = 0; i < DIR_NUM; i++)
- {
-
- tb.SetTime(td.dirPrice[i].hDay, td.dirPrice[i].mDay, 0);
- te.SetTime(td.dirPrice[i].hNight, td.dirPrice[i].mNight, 0);
-
- double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
- double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
- double pna = 0;
- double pnb = 0;
-
- if (td.dirPrice[i].singlePrice)
- {
- pna = pda;
- pnb = pdb;
- }
- else
- {
- pna = td.dirPrice[i].priceNightA;
- pnb = td.dirPrice[i].priceNightB;
- }
-
- int threshold = 0;
- if (td.dirPrice[i].noDiscount)
- {
- threshold = 0xffFFffFF;
- }
- else
- {
- threshold = td.dirPrice[i].threshold;
- }
-
- st->Prepare("update tb_tariffs_params set \
- price_day_a = ?, \
- price_day_b = ?, \
- price_night_a = ?, \
- price_night_b = ?, \
- threshold = ?, \
- time_day_begins = ?, \
- time_day_ends = ? \
- where fk_tariff = ? and dir_num = ?");
- st->Set(1, pda);
- st->Set(2, pdb);
- st->Set(3, pna);
- st->Set(4, pnb);
- st->Set(5, threshold);
- st->Set(6, tb);
- st->Set(7, te);
- st->Set(8, id);
- st->Set(9, i);
- st->Execute();
- st->Close();
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::RestoreTariff(STG::TariffData * td,
- const std::string & tariffName) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-
-td->tariffConf.name = tariffName;
-
-try
- {
- tr->Start();
- st->Prepare("select * from tb_tariffs where name = ?"); // TODO: explicit field order!
- st->Set(1, tariffName);
- st->Execute();
- if (!st->Fetch())
- {
- strError = "Tariff \"" + tariffName + "\" not found in database";
- printfd(__FILE__, "Tariff '%s' not found in database\n", tariffName.c_str());
- tr->Rollback();
- return -1;
- }
- int32_t id;
- st->Get(1, id);
- st->Get(3, td->tariffConf.fee);
- st->Get(4, td->tariffConf.free);
- st->Get(5, td->tariffConf.passiveCost);
- td->tariffConf.traffType = STG::Tariff::fromInt(Get<int>(st, 6));
- if (schemaVersion > 0)
- td->tariffConf.period = STG::Tariff::parsePeriod(Get<std::string>(st, 7));
- if (schemaVersion > 1)
- {
- td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(Get<std::string>(st, 8));
- td->tariffConf.changePolicyTimeout = ts2time_t(Get<IBPP::Timestamp>(st, 9));
- }
- st->Close();
- st->Prepare("select * from tb_tariffs_params where fk_tariff = ?");
- st->Set(1, id);
- st->Execute();
- int i = 0;
- while (st->Fetch())
- {
- i++;
- if (i > DIR_NUM)
- {
- strError = "Too mach params for tariff \"" + tariffName + "\"";
- printfd(__FILE__, "Too mach params for tariff '%s'\n", tariffName.c_str());
- tr->Rollback();
- return -1;
- }
- int16_t dir;
- st->Get(3, dir);
- st->Get(4, td->dirPrice[dir].priceDayA);
- td->dirPrice[dir].priceDayA /= 1024*1024;
- st->Get(5, td->dirPrice[dir].priceDayB);
- td->dirPrice[dir].priceDayB /= 1024*1024;
- st->Get(6, td->dirPrice[dir].priceNightA);
- td->dirPrice[dir].priceNightA /= 1024*1024;
- st->Get(7, td->dirPrice[dir].priceNightB);
- td->dirPrice[dir].priceNightB /= 1024*1024;
- st->Get(8, td->dirPrice[dir].threshold);
- if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
- std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
- {
- td->dirPrice[dir].singlePrice = true;
- }
- else
- {
- td->dirPrice[dir].singlePrice = false;
- }
- if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
- {
- td->dirPrice[dir].noDiscount = true;
- }
- else
- {
-
- td->dirPrice[dir].noDiscount = false;
- }
- IBPP::Time tb;
- st->Get(9, tb);
- IBPP::Time te;
- st->Get(10, te);
- int h, m, s;
- tb.GetTime(h, m, s);
- td->dirPrice[dir].hDay = h;
- td->dirPrice[dir].mDay = m;
- te.GetTime(h, m, s);
- td->dirPrice[dir].hNight = h;
- td->dirPrice[dir].mNight = m;
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * User manipulation methods
- *
- * $Revision: 1.19 $
- * $Date: 2010/01/19 11:07:25 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/user_traff.h"
-#include "stg/user_ips.h"
-#include "stg/const.h"
-#include "stg/common.h"
-
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::GetUsersList(std::vector<std::string> * usersList) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-std::string name;
-
-try
- {
- tr->Start();
- st->Execute("select name from tb_users");
- while (st->Fetch())
- {
- st->Get(1, name);
- usersList->push_back(name);
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::AddUser(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_add_user(?, ?)");
- st->Set(1, name);
- st->Set(2, DIR_NUM);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::DelUser(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_delete_user(?)");
- st->Set(1, login);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveUserStat(const STG::UserStat & stat,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-return SaveStat(stat, login);
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveStat(const STG::UserStat & stat,
- const std::string & login,
- int year,
- int month) const
-{
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select pk_user from tb_users where name = ?");
- st->Set(1, login);
- st->Execute();
- if (!st->Fetch())
- {
- strError = "User \"" + login + "\" not found in database";
- printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
- tr->Rollback();
- return -1;
- }
- int32_t uid = Get<int32_t>(st, 1);
- st->Close();
- st->Prepare("select first 1 pk_stat from tb_stats where fk_user = ? order by stats_date desc");
- st->Set(1, uid);
- st->Execute();
- if (!st->Fetch())
- {
- tr->Rollback();
- strError = "No stat info for user \"" + login + "\"";
- printfd(__FILE__, "No stat info for user '%s'\n", login.c_str());
- return -1;
- }
- int32_t sid;
- st->Get(1, sid);
- st->Close();
-
- IBPP::Timestamp actTime;
- time_t2ts(stat.lastActivityTime, &actTime);
- IBPP::Timestamp addTime;
- time_t2ts(stat.lastCashAddTime, &addTime);
- IBPP::Date dt;
- if (year != 0)
- ym2date(year, month, &dt);
- else
- dt.Today();
-
- st->Prepare("update tb_stats set \
- cash = ?, \
- free_mb = ?, \
- last_activity_time = ?, \
- last_cash_add = ?, \
- last_cash_add_time = ?, \
- passive_time = ?, \
- stats_date = ? \
- where pk_stat = ?");
-
- st->Set(1, stat.cash);
- st->Set(2, stat.freeMb);
- st->Set(3, actTime);
- st->Set(4, stat.lastCashAdd);
- st->Set(5, addTime);
- st->Set(6, (int32_t)stat.passiveTime);
- st->Set(7, dt);
- st->Set(8, sid);
-
- st->Execute();
- st->Close();
-
- for(int i = 0; i < DIR_NUM; i++)
- {
- st->Prepare("update tb_stats_traffic set \
- upload = ?, \
- download = ? \
- where fk_stat = ? and dir_num = ?");
- st->Set(1, (int64_t)stat.monthUp[i]);
- st->Set(2, (int64_t)stat.monthDown[i]);
- st->Set(3, sid);
- st->Set(4, i);
- st->Execute();
- st->Close();
- }
-
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveUserConf(const STG::UserConf & conf,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select pk_user from tb_users where name = ?");
- st->Set(1, login);
- st->Execute();
- if (!st->Fetch())
- {
- strError = "User \"" + login + "\" not found in database";
- printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
- tr->Rollback();
- return -1;
- }
- int32_t uid;
- st->Get(1, uid);
- st->Close();
-
- IBPP::Timestamp creditExpire;
- time_t2ts(conf.creditExpire, &creditExpire);
-
- st->Prepare("update tb_users set \
- address = ?, \
- always_online = ?, \
- credit = ?, \
- credit_expire = ?, \
- disabled = ?, \
- disabled_detail_stat = ?, \
- email = ?, \
- grp = ?, \
- note = ?, \
- passive = ?, \
- passwd = ?, \
- phone = ?, \
- fk_tariff = (select pk_tariff from tb_tariffs \
- where name = ?), \
- fk_tariff_change = (select pk_tariff from tb_tariffs \
- where name = ?), \
- fk_corporation = (select pk_corporation from tb_corporations \
- where name = ?), \
- real_name = ? \
- where pk_user = ?");
-
- st->Set(1, conf.address);
- st->Set(2, (bool)conf.alwaysOnline);
- st->Set(3, conf.credit);
- st->Set(4, creditExpire);
- st->Set(5, (bool)conf.disabled);
- st->Set(6, (bool)conf.disabledDetailStat);
- st->Set(7, conf.email);
- st->Set(8, conf.group);
- st->Set(9, conf.note);
- st->Set(10, (bool)conf.passive);
- st->Set(11, conf.password);
- st->Set(12, conf.phone);
- st->Set(13, conf.tariffName);
- st->Set(14, conf.nextTariff);
- st->Set(15, conf.corp);
- st->Set(16, conf.realName);
- st->Set(17, uid);
-
- st->Execute();
- st->Close();
-
- st->Prepare("delete from tb_users_services where fk_user = ?");
- st->Set(1, uid);
- st->Execute();
- st->Close();
-
- st->Prepare("insert into tb_users_services (fk_user, fk_service) \
- values (?, (select pk_service from tb_services \
- where name = ?))");
- for(std::vector<std::string>::const_iterator it = conf.services.begin(); it != conf.services.end(); ++it)
- {
- st->Set(1, uid);
- st->Set(2, *it);
- st->Execute();
- }
- st->Close();
-
- st->Prepare("delete from tb_users_data where fk_user = ?");
- st->Set(1, uid);
- st->Execute();
- st->Close();
-
- int i = 0;
- st->Prepare("insert into tb_users_data (fk_user, data, num) values (?, ?, ?)");
- for (std::vector<std::string>::const_iterator it = conf.userdata.begin(); it != conf.userdata.end(); ++it)
- {
- st->Set(1, uid);
- st->Set(2, *it);
- st->Set(3, i++);
- st->Execute();
- }
- st->Close();
-
- st->Prepare("delete from tb_allowed_ip where fk_user = ?");
- st->Set(1, uid);
- st->Execute();
-
- st->Prepare("insert into tb_allowed_ip (fk_user, ip, mask) values (?, ?, ?)");
- for(size_t i = 0; i < conf.ips.count(); i++)
- {
- st->Set(1, uid);
- st->Set(2, (int32_t)conf.ips[i].ip);
- st->Set(3, (int32_t)conf.ips[i].mask);
- st->Execute();
- }
- tr->Commit();
- }
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::RestoreUserStat(STG::UserStat * stat,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select pk_user from tb_users where name = ?");
- st->Set(1, login);
- st->Execute();
- if (!st->Fetch())
- {
- strError = "User \"" + login + "\" not found in database";
- printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
- return -1;
- }
- int32_t uid;
- st->Get(1, uid);
- st->Close();
-
- st->Prepare("select first 1 pk_stat, cash, free_mb, last_activity_time, \
- last_cash_add, last_cash_add_time, passive_time from tb_stats \
- where fk_user = ? order by stats_date desc");
- st->Set(1, uid);
- st->Execute();
- if (!st->Fetch())
- {
- strError = "No stat info for user \"" + login + "\"";
- printfd(__FILE__, "No stat info for user '%s'\n", login.c_str());
- tr->Rollback();
- return -1;
- }
-
- int32_t sid;
- st->Get(1, sid);
- st->Get(2, stat->cash);
- st->Get(3, stat->freeMb);
- IBPP::Timestamp actTime;
- st->Get(4, actTime);
- st->Get(5, stat->lastCashAdd);
- IBPP::Timestamp addTime;
- st->Get(6, addTime);
- int32_t passiveTime;
- st->Get(7, passiveTime);
-
- stat->passiveTime = passiveTime;
-
- stat->lastActivityTime = ts2time_t(actTime);
-
- stat->lastCashAddTime = ts2time_t(addTime);
-
- st->Close();
- st->Prepare("select * from tb_stats_traffic where fk_stat = ?");
- st->Set(1, sid);
- st->Execute();
- for(int i = 0; i < DIR_NUM; i++)
- {
- if (st->Fetch())
- {
- int dir;
- st->Get(3, dir);
- st->Get(5, (int64_t &)stat->monthUp[dir]);
- st->Get(4, (int64_t &)stat->monthDown[dir]);
- }
- else
- {
- break;
- }
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::RestoreUserConf(STG::UserConf * conf,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-try
- {
- tr->Start();
- st->Prepare("select tb_users.pk_user, tb_users.address, tb_users.always_online, \
- tb_users.credit, tb_users.credit_expire, tb_users.disabled, \
- tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, \
- tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, \
- tb_users.real_name, tf1.name, tf2.name, tb_corporations.name \
- from tb_users left join tb_tariffs tf1 \
- on tf1.pk_tariff = tb_users.fk_tariff \
- left join tb_tariffs tf2 \
- on tf2.pk_tariff = tb_users.fk_tariff_change \
- left join tb_corporations \
- on tb_corporations.pk_corporation = tb_users.fk_corporation \
- where tb_users.name = ?");
- st->Set(1, login);
- st->Execute();
- if (!st->Fetch())
- {
- strError = "User \"" + login + "\" not found in database";
- printfd(__FILE__, "User '%s' not found in database", login.c_str());
- tr->Rollback();
- return -1;
- }
- int32_t uid;
- st->Get(1, uid);
- // Getting base config
- st->Get(2, conf->address);
- bool test;
- st->Get(3, test);
- conf->alwaysOnline = test;
- st->Get(4, conf->credit);
- IBPP::Timestamp timestamp;
- st->Get(5, timestamp);
-
- conf->creditExpire = ts2time_t(timestamp);
-
- st->Get(6, test);
- conf->disabled = test;
- st->Get(7, test);
- conf->disabledDetailStat = test;
- st->Get(8, conf->email);
- st->Get(9, conf->group);
- st->Get(10, conf->note);
- st->Get(11, test);
- conf->passive = test;
- st->Get(12, conf->password);
- st->Get(13, conf->phone);
- st->Get(14, conf->realName);
- st->Get(15, conf->tariffName);
- st->Get(16, conf->nextTariff);
- st->Get(17, conf->corp);
-
- if (conf->tariffName == "")
- conf->tariffName = NO_TARIFF_NAME;
- if (conf->corp == "")
- conf->corp = NO_CORP_NAME;
-
- // Services
- st->Close();
- st->Prepare("select name from tb_services \
- where pk_service in \
- (select fk_service from tb_users_services \
- where fk_user = ?)");
- st->Set(1, uid);
- st->Execute();
- while (st->Fetch())
- {
- std::string name;
- st->Get(1, name);
- conf->services.push_back(name);
- }
-
- // User data
- st->Close();
- st->Prepare("select data, num from tb_users_data where fk_user = ? order by num");
- st->Set(1, uid);
- st->Execute();
- while (st->Fetch())
- {
- int i;
- st->Get(2, i);
- st->Get(1, conf->userdata[i]);
- }
-
- // User IPs
- st->Close();
- st->Prepare("select ip, mask from tb_allowed_ip \
- where fk_user = ?");
- st->Set(1, uid);
- st->Execute();
- STG::UserIPs ips;
- while (st->Fetch())
- {
- STG::IPMask im;
- st->Get(1, (int32_t &)im.ip);
- st->Get(2, (int32_t &)im.mask);
- ips.add(im);
- }
- conf->ips = ips;
-
- tr->Commit();
- }
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message = "") const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-IBPP::Timestamp now;
-now.Now();
-
-std::string temp = ""; // Composed message for log
-
-try
- {
- tr->Start();
- temp += "Admin \"" + admLogin + "\", ";
- temp += inet_ntostring(admIP);
- temp += ": ";
- temp = temp + message;
- //----------------------------------------------------------------------------------------
- // Checking and inserting parameters in params table
- st->Prepare("select pk_parameter from tb_parameters where name = ?");
- st->Set(1, paramName);
- st->Execute();
- if (!st->Fetch())
- {
- st->Close();
- st->Prepare("insert into tb_parameters (name) values (?)");
- st->Set(1, paramName);
- st->Execute();
- }
- st->Close();
- //----------------------------------------------------------------------------------------
- st->Prepare("insert into tb_params_log \
- (fk_user, fk_parameter, event_time, from_val, to_val, comment) \
- values ((select pk_user from tb_users \
- where name = ?), \
- (select pk_parameter from tb_parameters \
- where name = ?), \
- ?, ?, ?, ?)");
- st->Set(1, login);
- st->Set(2, paramName);
- st->Set(3, now);
- st->Set(4, oldValue);
- st->Set(5, newValue);
- st->Set(6, temp);
- st->Execute();
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-IBPP::Timestamp now;
-now.Now();
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_append_session_log(?, ?, 'c', ?)");
- st->Set(1, login);
- st->Set(2, now);
- st->Set(3, (int32_t)ip);
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & up,
- const STG::DirTraff & down,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double /*cash*/,
- double /*freeMb*/,
- const std::string & /*reason*/) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-IBPP::Timestamp now;
-now.Now();
-
-try
- {
- tr->Start();
- st->Prepare("execute procedure sp_append_session_log(?, ?, 'd', 0)");
- st->Set(1, login);
- st->Set(2, now);
- st->Execute();
- int32_t id;
- st->Get(1, id);
- st->Prepare("insert into tb_sessions_data \
- (fk_session_log, dir_num, session_upload, \
- session_download, month_upload, month_download) \
- values (?, ?, ?, ?, ?, ?)");
- for(int i = 0; i < DIR_NUM; i++)
- {
- st->Set(1, id);
- st->Set(2, i);
- st->Set(3, (int64_t)sessionUp[i]);
- st->Set(4, (int64_t)sessionDown[i]);
- st->Set(5, (int64_t)up[i]);
- st->Set(6, (int64_t)down[i]);
- st->Execute();
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-IBPP::Timestamp statTime, now;
-now.Now();
-
-time_t2ts(lastStat, &statTime);
-
-try
- {
- tr->Start();
- STG::TraffStat::const_iterator it;
- it = statTree.begin();
- st->Prepare("insert into tb_detail_stats \
- (till_time, from_time, fk_user, dir_num, \
- ip, download, upload, cost) \
- values (?, ?, (select pk_user from tb_users \
- where name = ?), \
- ?, ?, ?, ?, ?)");
- while (it != statTree.end())
- {
- st->Set(1, now);
- st->Set(2, statTime);
- st->Set(3, login);
- st->Set(4, it->first.dir);
- st->Set(5, (int32_t)it->first.ip);
- st->Set(6, (int64_t)it->second.down);
- st->Set(7, (int64_t)it->second.up);
- st->Set(8, it->second.cash);
- st->Execute();
- ++it;
- }
- tr->Commit();
- }
-
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int FIREBIRD_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
-IBPP::Statement st = IBPP::StatementFactory(db, tr);
-
-IBPP::Timestamp now;
-IBPP::Date nowDate;
-nowDate.Today();
-now.Now();
-
-if (SaveStat(stat, login, year, month))
- {
- return -1;
- }
-
-try
- {
- tr->Start();
-
- st->Prepare("execute procedure sp_add_stat(?, 0, 0, ?, 0, ?, 0, ?)");
- st->Set(1, login);
- st->Set(2, now);
- st->Set(3, now);
- st->Set(4, nowDate);
-
- st->Execute();
- int32_t id;
- st->Get(1, id);
- st->Close();
-
- st->Prepare("insert into tb_stats_traffic \
- (fk_stat, dir_num, upload, download) \
- values (?, ?, 0, 0)");
-
- for(int i = 0; i < DIR_NUM; i++)
- {
- st->Set(1, id);
- st->Set(2, i);
- st->Execute();
- }
-
- tr->Commit();
- }
-catch (IBPP::Exception & ex)
- {
- tr->Rollback();
- strError = "IBPP exception";
- printfd(__FILE__, ex.what());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Vairous utility methods
- *
- * $Revision: 1.8 $
- * $Date: 2010/03/04 12:20:32 $
- *
- */
-
-#include "firebird_store.h"
-
-#include "stg/ibpp.h"
-#include "stg/common.h"
-
-#include <cstdio>
-
-//-----------------------------------------------------------------------------
-time_t ts2time_t(const IBPP::Timestamp & ts)
-{
- char buf[32];
- int year, month, day, hour, min, sec;
- struct tm time_tm;
-
- memset(&time_tm, 0, sizeof(time_tm));
- ts.GetDate(year, month, day);
- ts.GetTime(hour, min, sec);
- if (year < 1990)
- return 0;
- sprintf(buf, "%d-%d-%d %d:%d:%d", year, month, day, hour, min, sec);
- stg_strptime(buf, "%Y-%m-%d %H:%M:%S", &time_tm);
-
- return mktime(&time_tm);
-}
-//-----------------------------------------------------------------------------
-void time_t2ts(time_t t, IBPP::Timestamp * ts)
-{
- struct tm res;
-
- localtime_r(&t, &res); // Reenterable
-
- *ts = IBPP::Timestamp(res.tm_year + 1900, res.tm_mon + 1, res.tm_mday, res.tm_hour, res.tm_min, res.tm_sec);
-}
-//-----------------------------------------------------------------------------
-void ym2date(int year, int month, IBPP::Date * date)
-{
- date->SetDate(year + 1900, month + 1, 1);
- date->EndOfMonth();
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-#include "mysql_store.h"
-
-#include "stg/common.h"
-#include "stg/user_ips.h"
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/admin_conf.h"
-#include "stg/tariff_conf.h"
-#include "stg/blowfish.h"
-#include "stg/logger.h"
-
-#include <algorithm>
-#include <sys/time.h>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-
-#include <mysql/errmsg.h>
-
-#define adm_enc_passwd "cjeifY8m3"
-
-namespace
-{
-char qbuf[4096];
-
-const int pt_mega = 1024 * 1024;
-const std::string badSyms = "'`";
-const char repSym = '\"';
-const int RepitTimes = 3;
-
-template <typename T>
-int GetInt(const std::string & str, T * val, T defaultVal = T())
-{
- char *res;
-
- *val = static_cast<T>(strtoll(str.c_str(), &res, 10));
-
- if (*res != 0)
- {
- *val = defaultVal; //Error!
- return EINVAL;
- }
-
- return 0;
-}
-
-int GetDouble(const std::string & str, double * val, double defaultVal)
-{
- char *res;
-
- *val = strtod(str.c_str(), &res);
-
- if (*res != 0)
- {
- *val = defaultVal; //Error!
- return EINVAL;
- }
-
- return 0;
-}
-
-int GetTime(const std::string & str, time_t * val, time_t defaultVal)
-{
- char *res;
-
- *val = strtol(str.c_str(), &res, 10);
-
- if (*res != 0)
- {
- *val = defaultVal; //Error!
- return EINVAL;
- }
-
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-std::string ReplaceStr(std::string source, const std::string & symlist, const char chgsym)
-{
- std::string::size_type pos=0;
-
- while( (pos = source.find_first_of(symlist,pos)) != std::string::npos)
- source.replace(pos, 1,1, chgsym);
-
- return source;
-}
-
-int GetULongLongInt(const std::string & str, uint64_t * val, uint64_t defaultVal)
-{
- char *res;
-
- *val = strtoull(str.c_str(), &res, 10);
-
- if (*res != 0)
- {
- *val = defaultVal; //Error!
- return EINVAL;
- }
-
- return 0;
-}
-
-}
-
-extern "C" STG::Store* GetStore()
-{
- static MYSQL_STORE plugin;
- return &plugin;
-}
-//-----------------------------------------------------------------------------
-MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
- : settings(NULL)
-{
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE_SETTINGS::ParseParam(const std::vector<STG::ParamValue> & moduleParams,
- const std::string & name, std::string & result)
-{
-STG::ParamValue pv;
-pv.param = name;
-std::vector<STG::ParamValue>::const_iterator pvi;
-pvi = find(moduleParams.begin(), moduleParams.end(), pv);
-if (pvi == moduleParams.end() || pvi->value.empty())
- {
- errorStr = "Parameter \'" + name + "\' not found.";
- return -1;
- }
-
-result = pvi->value[0];
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE_SETTINGS::ParseSettings(const STG::ModuleSettings & s)
-{
-if (ParseParam(s.moduleParams, "user", dbUser) < 0 &&
- ParseParam(s.moduleParams, "dbuser", dbUser) < 0)
- return -1;
-if (ParseParam(s.moduleParams, "password", dbPass) < 0 &&
- ParseParam(s.moduleParams, "rootdbpass", dbPass) < 0)
- return -1;
-if (ParseParam(s.moduleParams, "database", dbName) < 0 &&
- ParseParam(s.moduleParams, "dbname", dbName) < 0)
- return -1;
-if (ParseParam(s.moduleParams, "server", dbHost) < 0 &&
- ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
- return -1;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-MYSQL_STORE::MYSQL_STORE()
- : version("mysql_store v.0.67"),
- schemaVersion(0),
- logger(STG::PluginLogger::get("store_mysql"))
-{
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
-{
- int ret;
-
- if( (ret = mysql_query(sock,sQuery)) )
- {
- for(int i=0; i<RepitTimes; i++)
- {
- if( (ret = mysql_query(sock,sQuery)) )
- ;//need to send error result
- else
- return 0;
- }
- }
-
- return ret;
-}
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::ParseSettings()
-{
-int ret = storeSettings.ParseSettings(settings);
-MYSQL mysql;
-mysql_init(&mysql);
-if (ret)
- errorStr = storeSettings.GetStrError();
-else
-{
- if(storeSettings.GetDBPassword().length() == 0)
- {
- errorStr = "Database password must be not empty. Please read Manual.";
- return -1;
- }
- MYSQL * sock;
- if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
- storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
- 0,0,NULL,0)))
- {
- errorStr = "Couldn't connect to mysql engine! With error:\n";
- errorStr += mysql_error(&mysql);
- mysql_close(sock);
- ret = -1;
- }
- else
- {
- if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
- {
- std::string res = "CREATE DATABASE " + storeSettings.GetDBName();
-
- if(MysqlQuery(res.c_str(),sock))
- {
- errorStr = "Couldn't create database! With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- ret = -1;
- }
- else
- {
- if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
- {
- errorStr = "Couldn't select database! With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- ret = -1;
- }
- else
- ret = CheckAllTables(sock);
- }
- }
- else
- {
- ret = CheckAllTables(sock);
- }
- if (!ret)
- {
- logger("MYSQL_STORE: Current DB schema version: %d", schemaVersion);
- MakeUpdates(sock);
- }
- mysql_close(sock);
- }
-}
-return ret;
-}
-//-----------------------------------------------------------------------------
-bool MYSQL_STORE::IsTablePresent(const std::string & str,MYSQL * sock)
-{
-MYSQL_RES* result;
-
-if (!(result=mysql_list_tables(sock,str.c_str() )))
-{
- errorStr = "Couldn't get tables list With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-my_ulonglong num_rows = mysql_num_rows(result);
-
-if(result)
- mysql_free_result(result);
-
-return num_rows == 1;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::CheckAllTables(MYSQL * sock)
-{
-//info-------------------------------------------------------------------------
-if(!IsTablePresent("info",sock))
-{
- sprintf(qbuf,"CREATE TABLE info (version INTEGER NOT NULL)");
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't create info table With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-
- sprintf(qbuf,"INSERT INTO info SET version=0");
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't write default version. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
- schemaVersion = 0;
-}
-else
-{
- std::vector<std::string> info;
- if (GetAllParams(&info, "info", "version"))
- schemaVersion = 0;
- else
- {
- if (info.empty())
- schemaVersion = 0;
- else
- GetInt(info.front(), &schemaVersion, 0);
- }
-}
-//admins-----------------------------------------------------------------------
-if(!IsTablePresent("admins",sock))
-{
- sprintf(qbuf,"CREATE TABLE admins (login VARCHAR(40) DEFAULT '' PRIMARY KEY,"\
- "password VARCHAR(150) DEFAULT '*',ChgConf TINYINT DEFAULT 0,"\
- "ChgPassword TINYINT DEFAULT 0,ChgStat TINYINT DEFAULT 0,"\
- "ChgCash TINYINT DEFAULT 0,UsrAddDel TINYINT DEFAULT 0,"\
- "ChgTariff TINYINT DEFAULT 0,ChgAdmin TINYINT DEFAULT 0)");
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't create admin table list With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-
- sprintf(qbuf,"INSERT INTO admins SET login='admin',"\
- "password='geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa',"\
- "ChgConf=1,ChgPassword=1,ChgStat=1,ChgCash=1,UsrAddDel=1,ChgTariff=1,ChgAdmin=1");
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't create default admin. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-}
-
-//tariffs-----------------------------------------------------------------------
-std::string param, res;
-if(!IsTablePresent("tariffs",sock))
-{
- res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
-
- for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " PriceDayA%d DOUBLE DEFAULT 0.0,", i);
- res += param;
-
- strprintf(¶m, " PriceDayB%d DOUBLE DEFAULT 0.0,", i);
- res += param;
-
- strprintf(¶m, " PriceNightA%d DOUBLE DEFAULT 0.0,", i);
- res += param;
-
- strprintf(¶m, " PriceNightB%d DOUBLE DEFAULT 0.0,", i);
- res += param;
-
- strprintf(¶m, " Threshold%d INT DEFAULT 0,", i);
- res += param;
-
- strprintf(¶m, " Time%d VARCHAR(15) DEFAULT '0:0-0:0',", i);
- res += param;
-
- strprintf(¶m, " NoDiscount%d INT DEFAULT 0,", i);
- res += param;
-
- strprintf(¶m, " SinglePrice%d INT DEFAULT 0,", i);
- res += param;
- }
-
- res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"
- "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '',"
- "period VARCHAR(32) NOT NULL DEFAULT 'month',"
- "change_policy VARCHAR(32) NOT NULL DEFAULT 'allow',"
- "change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0)";
-
- if(MysqlQuery(res.c_str(),sock))
- {
- errorStr = "Couldn't create tariffs table list With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-
- res = "INSERT INTO tariffs SET name='tariff',";
-
- for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " NoDiscount%d=1,", i);
- res += param;
-
- strprintf(¶m, " Threshold%d=0,", i);
- res += param;
-
- strprintf(¶m, " Time%d='0:0-0:0',", i);
- res += param;
-
- if(i != 0 && i != 1)
- {
- strprintf(¶m, " SinglePrice%d=0,", i);
- res += param;
- }
-
- if(i != 1)
- {
- strprintf(¶m, " PriceDayA%d=0.0,", i);
- res += param;
- }
- if(i != 1)
- {
- strprintf(¶m, " PriceDayB%d=0.0,", i);
- res += param;
- }
-
- if(i != 0)
- {
- strprintf(¶m, " PriceNightA%d=0.0,", i);
- res += param;
- }
- if(i != 0)
- {
- strprintf(¶m, " PriceNightB%d=0.0,", i);
- res += param;
- }
- }
-
- res += "PassiveCost=0.0, Fee=10.0, Free=0,"\
- "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\
- "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month',"\
- "change_policy='allow', change_policy_timeout=0";
-
- if(MysqlQuery(res.c_str(),sock))
- {
- errorStr = "Couldn't create default tariff. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-
- sprintf(qbuf,"UPDATE info SET version=1");
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't write default version. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
- schemaVersion = 2;
-}
-
-//users-----------------------------------------------------------------------
-if(!IsTablePresent("users",sock))
-{
- res = "CREATE TABLE users (login VARCHAR(50) NOT NULL DEFAULT '' PRIMARY KEY, Password VARCHAR(150) NOT NULL DEFAULT '*',"\
- "Passive INT(3) DEFAULT 0,Down INT(3) DEFAULT 0,DisabledDetailStat INT(3) DEFAULT 0,AlwaysOnline INT(3) DEFAULT 0,Tariff VARCHAR(40) NOT NULL DEFAULT '',"\
- "Address VARCHAR(254) NOT NULL DEFAULT '',Phone VARCHAR(128) NOT NULL DEFAULT '',Email VARCHAR(50) NOT NULL DEFAULT '',"\
- "Note TEXT NOT NULL,RealName VARCHAR(254) NOT NULL DEFAULT '',StgGroup VARCHAR(40) NOT NULL DEFAULT '',"\
- "Credit DOUBLE DEFAULT 0, TariffChange VARCHAR(40) NOT NULL DEFAULT '',";
-
- for (int i = 0; i < USERDATA_NUM; i++)
- {
- strprintf(¶m, " Userdata%d VARCHAR(254) NOT NULL,", i);
- res += param;
- }
-
- param = " CreditExpire INT(11) DEFAULT 0,";
- res += param;
-
- strprintf(¶m, " IP VARCHAR(254) DEFAULT '*',");
- res += param;
-
- for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " D%d BIGINT(30) DEFAULT 0,", i);
- res += param;
-
- strprintf(¶m, " U%d BIGINT(30) DEFAULT 0,", i);
- res += param;
- }
-
- strprintf(¶m, "Cash DOUBLE DEFAULT 0,FreeMb DOUBLE DEFAULT 0,LastCashAdd DOUBLE DEFAULT 0,"\
- "LastCashAddTime INT(11) DEFAULT 0,PassiveTime INT(11) DEFAULT 0,LastActivityTime INT(11) DEFAULT 0,"\
- "NAS VARCHAR(17) NOT NULL, INDEX (AlwaysOnline), INDEX (IP), INDEX (Address),"\
- " INDEX (Tariff),INDEX (Phone),INDEX (Email),INDEX (RealName))");
- res += param;
-
- if(MysqlQuery(res.c_str(),sock))
- {
- errorStr = "Couldn't create users table list With error:\n";
- errorStr += mysql_error(sock);
- errorStr += "\n\n" + res;
- mysql_close(sock);
- return -1;
- }
-
- res = "INSERT INTO users SET login='test',Address='',AlwaysOnline=0,"\
- "Credit=0.0,CreditExpire=0,Down=0,Email='',DisabledDetailStat=0,"\
- "StgGroup='',IP='192.168.1.1',Note='',Passive=0,Password='123456',"\
- "Phone='', RealName='',Tariff='tariff',TariffChange='',NAS='',";
-
- for (int i = 0; i < USERDATA_NUM; i++)
- {
- strprintf(¶m, " Userdata%d='',", i);
- res += param;
- }
-
- for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " D%d=0,", i);
- res += param;
-
- strprintf(¶m, " U%d=0,", i);
- res += param;
- }
-
- res += "Cash=10.0,FreeMb=0.0,LastActivityTime=0,LastCashAdd=0,"\
- "LastCashAddTime=0, PassiveTime=0";
-
- if(MysqlQuery(res.c_str(),sock))
- {
- errorStr = "Couldn't create default user. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-}
-/*
-//logs-----------------------------------------------------------------------
-if(!IsTablePresent("logs"))
-{
- sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
-
- if(MysqlQuery(qbuf))
- {
- errorStr = "Couldn't create admin table list With error:\n";
- errorStr += mysql_error(sock);
- return -1;
- }
-}
-*/
-//messages---------------------------------------------------------------------
-if(!IsTablePresent("messages",sock))
-{
- sprintf(qbuf,"CREATE TABLE messages (login VARCHAR(40) DEFAULT '', id BIGINT, "\
- "type INT, lastSendTime INT, creationTime INT, showTime INT,"\
- "stgRepeat INT, repeatPeriod INT, text TEXT)");
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't create messages table. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-}
-
-//month_stat-------------------------------------------------------------------
-if(!IsTablePresent("stat",sock))
-{
- res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
-
- for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " U%d BIGINT,", i);
- res += param;
-
- strprintf(¶m, " D%d BIGINT,", i);
- res += param;
- }
-
- res += " cash DOUBLE, INDEX (login))";
-
- if(MysqlQuery(res.c_str(),sock))
- {
- errorStr = "Couldn't create stat table. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::MakeUpdates(MYSQL * sock)
-{
-if (schemaVersion < 1)
- {
- if (MysqlQuery("ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month'", sock))
- {
- errorStr = "Couldn't update tariffs table to version 1. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
- if (MysqlQuery("UPDATE info SET version = 1", sock))
- {
- errorStr = "Couldn't update DB schema version to 1. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
- schemaVersion = 1;
- logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
- }
-
-if (schemaVersion < 2)
- {
- if (MysqlQuery("ALTER TABLE tariffs ADD change_policy VARCHAR(32) NOT NULL DEFAULT 'allow'", sock) ||
- MysqlQuery("ALTER TABLE tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0", sock))
- {
- errorStr = "Couldn't update tariffs table to version 2. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
- if (MysqlQuery("UPDATE info SET version = 2", sock))
- {
- errorStr = "Couldn't update DB schema version to 2. With error:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
- schemaVersion = 2;
- logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-
-int MYSQL_STORE::GetAllParams(std::vector<std::string> * ParamList,
- const std::string & table, const std::string & name) const
-{
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock=NULL;
-my_ulonglong num, i;
-
-ParamList->clear();
-
-sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
-
-if(MysqlGetQuery(qbuf,sock))
-{
- errorStr = "Couldn't GetAllParams Query for: ";
- errorStr += name + " - " + table + "\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't GetAllParams Results for: ";
- errorStr += name + " - " + table + "\n";
- errorStr += mysql_error(sock);
- return -1;
-}
-
-num = mysql_num_rows(res);
-
-for(i = 0; i < num; i++)
-{
- row = mysql_fetch_row(res);
- ParamList->push_back(row[0]);
-}
-
-mysql_free_result(res);
-mysql_close(sock);
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
-{
-if(GetAllParams(usersList, "users", "login"))
- return -1;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
-{
-if(GetAllParams(adminsList, "admins", "login"))
- return -1;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
-{
-if(GetAllParams(tariffsList, "tariffs", "name"))
- return -1;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::AddUser(const std::string & login) const
-{
-std::string query = "INSERT INTO users SET login='" + login + "',Note='',NAS=''";
-
-for (int i = 0; i < USERDATA_NUM; i++)
- query += ",Userdata" + std::to_string(i) + "=''";
-
-if(MysqlSetQuery(query.c_str()))
-{
- errorStr = "Couldn't add user:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::DelUser(const std::string & login) const
-{
-sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't delete user:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::RestoreUserConf(STG::UserConf * conf, const std::string & login) const
-{
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock;
-std::string query;
-
-query = "SELECT login, Password, Passive, Down, DisabledDetailStat, \
- AlwaysOnline, Tariff, Address, Phone, Email, Note, \
- RealName, StgGroup, Credit, TariffChange, ";
-
-for (int i = 0; i < USERDATA_NUM; i++)
-{
- sprintf(qbuf, "Userdata%d, ", i);
- query += qbuf;
-}
-
-query += "CreditExpire, IP FROM users WHERE login='";
-query += login + "' LIMIT 1";
-
-//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
-
-if(MysqlGetQuery(query.c_str(),sock))
-{
- errorStr = "Couldn't restore Tariff(on query):\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't restore Tariff(on getting result):\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (mysql_num_rows(res) != 1)
-{
- errorStr = "User not found";
- mysql_close(sock);
- return -1;
-}
-
-row = mysql_fetch_row(res);
-
-conf->password = row[1];
-
-if (conf->password.empty())
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' password is blank.";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[2],&conf->passive) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[3], &conf->disabled) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' data not read. Parameter Down.";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[4], &conf->disabledDetailStat) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' data not read. Parameter DisabledDetailStat.";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[5], &conf->alwaysOnline) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
- mysql_close(sock);
- return -1;
- }
-
-conf->tariffName = row[6];
-
-if (conf->tariffName.empty())
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' tariff is blank.";
- mysql_close(sock);
- return -1;
- }
-
-conf->address = row[7];
-conf->phone = row[8];
-conf->email = row[9];
-conf->note = row[10];
-conf->realName = row[11];
-conf->group = row[12];
-
-if (GetDouble(row[13], &conf->credit, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
- mysql_close(sock);
- return -1;
- }
-
-conf->nextTariff = row[14];
-
-for (int i = 0; i < USERDATA_NUM; i++)
- {
- conf->userdata[i] = row[15+i];
- }
-
-GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
-
-std::string ipStr = row[16+USERDATA_NUM];
-STG::UserIPs i;
-try
- {
- i = STG::UserIPs::parse(ipStr);
- }
-catch (const std::string & s)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
- mysql_close(sock);
- return -1;
- }
-conf->ips = i;
-
-mysql_free_result(res);
-mysql_close(sock);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::RestoreUserStat(STG::UserStat * stat, const std::string & login) const
-{
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock;
-
-std::string query;
-
-query = "SELECT ";
-
-for (int i = 0; i < DIR_NUM; i++)
-{
- sprintf(qbuf, "D%d, U%d, ", i, i);
- query += qbuf;
-}
-
-query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityTime \
- FROM users WHERE login = '";
-query += login + "'";
-
-//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
-
-if(MysqlGetQuery(query.c_str() ,sock))
-{
- errorStr = "Couldn't restore UserStat(on query):\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't restore UserStat(on getting result):\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-row = mysql_fetch_row(res);
-
-unsigned int startPos=0;
-
-char s[22];
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- uint64_t traff;
- sprintf(s, "D%d", i);
- if (GetULongLongInt(row[startPos+i*2], &traff, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
- mysql_close(sock);
- return -1;
- }
- stat->monthDown[i] = traff;
-
- sprintf(s, "U%d", i);
- if (GetULongLongInt(row[startPos+i*2+1], &traff, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
- mysql_close(sock);
- return -1;
- }
- stat->monthUp[i] = traff;
- }//for
-
-startPos += (2*DIR_NUM);
-
-if (GetDouble(row[startPos], &stat->cash, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter Cash";
- mysql_close(sock);
- return -1;
- }
-
-if (GetDouble(row[startPos+1],&stat->freeMb, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter FreeMb";
- mysql_close(sock);
- return -1;
- }
-
-if (GetDouble(row[startPos+2], &stat->lastCashAdd, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAdd";
- mysql_close(sock);
- return -1;
- }
-
-if (GetTime(row[startPos+3], &stat->lastCashAddTime, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
- mysql_close(sock);
- return -1;
- }
-
-if (GetTime(row[startPos+4], &stat->passiveTime, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter PassiveTime";
- mysql_close(sock);
- return -1;
- }
-
-if (GetTime(row[startPos+5], &stat->lastActivityTime, 0) != 0)
- {
- mysql_free_result(res);
- errorStr = "User \'" + login + "\' stat not read. Parameter LastActivityTime";
- mysql_close(sock);
- return -1;
- }
-
-mysql_free_result(res);
-mysql_close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::SaveUserConf(const STG::UserConf & conf, const std::string & login) const
-{
-std::string param;
-std::string res;
-
-strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDetailStat = %d, "\
- "AlwaysOnline=%d, Tariff='%s', Address='%s', Phone='%s', Email='%s', "\
- "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ",
- conf.password.c_str(),
- conf.passive,
- conf.disabled,
- conf.disabledDetailStat,
- conf.alwaysOnline,
- conf.tariffName.c_str(),
- (ReplaceStr(conf.address,badSyms,repSym)).c_str(),
- (ReplaceStr(conf.phone,badSyms,repSym)).c_str(),
- (ReplaceStr(conf.email,badSyms,repSym)).c_str(),
- (ReplaceStr(conf.note,badSyms,repSym)).c_str(),
- (ReplaceStr(conf.realName,badSyms,repSym)).c_str(),
- (ReplaceStr(conf.group,badSyms,repSym)).c_str(),
- conf.credit,
- conf.nextTariff.c_str()
- );
-
-for (int i = 0; i < USERDATA_NUM; i++)
- {
- strprintf(¶m, " Userdata%d='%s',", i,
- (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
- res += param;
- }
-
-strprintf(¶m, " CreditExpire=%d,", conf.creditExpire);
-res += param;
-
-std::ostringstream ipStr;
-ipStr << conf.ips;
-
-strprintf(¶m, " IP='%s'", ipStr.str().c_str());
-res += param;
-
-strprintf(¶m, " WHERE login='%s' LIMIT 1", login.c_str());
-res += param;
-
-if(MysqlSetQuery(res.c_str()))
-{
- errorStr = "Couldn't save user conf:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::SaveUserStat(const STG::UserStat & stat, const std::string & login) const
-{
-std::string param;
-std::string res;
-
-res = "UPDATE users SET";
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " D%d=%lld,", i, stat.monthDown[i]);
- res += param;
-
- strprintf(¶m, " U%d=%lld,", i, stat.monthUp[i]);
- res += param;
- }
-
-strprintf(¶m, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
- " PassiveTime=%d, LastActivityTime=%d",
- stat.cash,
- stat.freeMb,
- stat.lastCashAdd,
- stat.lastCashAddTime,
- stat.passiveTime,
- stat.lastActivityTime
- );
-res += param;
-
-strprintf(¶m, " WHERE login='%s' LIMIT 1", login.c_str());
-res += param;
-
-if(MysqlSetQuery(res.c_str()))
-{
- errorStr = "Couldn't save user stat:\n";
-// errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::WriteLogString(const std::string & str, const std::string & login) const
-{
-std::string res, tempStr;
-time_t t;
-tm * lt;
-
-t = time(NULL);
-lt = localtime(&t);
-
-MYSQL_RES* result;
-MYSQL * sock;
-strprintf(&tempStr, "logs_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
-if (!(sock=MysqlConnect())){
- errorStr = "Couldn't connect to Server";
- return -1;
-}
-if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
-{
- errorStr = "Couldn't get table " + tempStr + ":\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-my_ulonglong num_rows = mysql_num_rows(result);
-
-mysql_free_result(result);
-
-if (num_rows < 1)
-{
- sprintf(qbuf,"CREATE TABLE logs_%02d_%4d (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)",
- lt->tm_mon+1, lt->tm_year+1900);
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't create WriteDetailedStat table:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-}
-
-strprintf(&res, "%s -- %s",LogDate(t), str.c_str());
-
-std::string send;
-
-strprintf(&send,"INSERT INTO logs_%02d_%4d SET login='%s', text='%s'",
- lt->tm_mon+1, lt->tm_year+1900,
- login.c_str(), (ReplaceStr(res,badSyms,repSym)).c_str());
-
-if(MysqlQuery(send.c_str(),sock))
-{
- errorStr = "Couldn't write log string:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-mysql_close(sock);
-return 0;
-
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message) const
-{
-std::string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
- + paramName + "\' parameter changed from \'" + oldValue +
- "\' to \'" + newValue + "\'. " + message;
-
-return WriteLogString(userLogMsg, login);
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
-{
-std::string logStr = "Connect, " + inet_ntostring(ip);
-return WriteLogString(logStr, login);
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & up,
- const STG::DirTraff & down,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double /*freeMb*/,
- const std::string & /*reason*/) const
-{
-std::string logStr = "Disconnect, ";
-std::ostringstream sssu;
-std::ostringstream sssd;
-std::ostringstream ssmu;
-std::ostringstream ssmd;
-std::ostringstream sscash;
-
-ssmu << up;
-ssmd << down;
-
-sssu << sessionUp;
-sssd << sessionDown;
-
-sscash << cash;
-
-logStr += " session upload: \'";
-logStr += sssu.str();
-logStr += "\' session download: \'";
-logStr += sssd.str();
-logStr += "\' month upload: \'";
-logStr += ssmu.str();
-logStr += "\' month download: \'";
-logStr += ssmd.str();
-logStr += "\' cash: \'";
-logStr += sscash.str();
-logStr += "\'";
-
-return WriteLogString(logStr, login);
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year,
- const std::string & login) const
-{
-std::string param, res;
-
-strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,",
- login.c_str(), month+1, year+1900);
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " U%d=%lld,", i, stat.monthUp[i]);
- res += param;
-
- strprintf(¶m, " D%d=%lld,", i, stat.monthDown[i]);
- res += param;
- }
-
-strprintf(¶m, " cash=%f", stat.cash);
-res += param;
-
-if(MysqlSetQuery(res.c_str()))
-{
- errorStr = "Couldn't SaveMonthStat:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int MYSQL_STORE::AddAdmin(const std::string & login) const
-{
-sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't add admin:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int MYSQL_STORE::DelAdmin(const std::string & login) const
-{
-sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't delete admin:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------*/
-int MYSQL_STORE::SaveAdmin(const STG::AdminConf & ac) const
-{
-char passwordE[2 * ADM_PASSWD_LEN + 2];
-char pass[ADM_PASSWD_LEN + 1];
-char adminPass[ADM_PASSWD_LEN + 1];
-
-memset(pass, 0, sizeof(pass));
-memset(adminPass, 0, sizeof(adminPass));
-
-BLOWFISH_CTX ctx;
-InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
-
-strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
-adminPass[ADM_PASSWD_LEN - 1] = 0;
-
-for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
- {
- EncryptBlock(pass + 8*i, adminPass + 8*i, &ctx);
- }
-
-pass[ADM_PASSWD_LEN - 1] = 0;
-Encode12(passwordE, pass, ADM_PASSWD_LEN);
-
-sprintf(qbuf,"UPDATE admins SET password='%s', ChgConf=%d, ChgPassword=%d, "\
- "ChgStat=%d, ChgCash=%d, UsrAddDel=%d, ChgTariff=%d, ChgAdmin=%d "\
- "WHERE login='%s' LIMIT 1",
- passwordE,
- ac.priv.userConf,
- ac.priv.userPasswd,
- ac.priv.userStat,
- ac.priv.userCash,
- ac.priv.userAddDel,
- ac.priv.tariffChg,
- ac.priv.adminChg,
- ac.login.c_str()
- );
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't save admin:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
-{
-char pass[ADM_PASSWD_LEN + 1];
-char password[ADM_PASSWD_LEN + 1];
-char passwordE[2*ADM_PASSWD_LEN + 2];
-BLOWFISH_CTX ctx;
-
-memset(password, 0, sizeof(password));
-
-std::string p;
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock;
-sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
-
-if(MysqlGetQuery(qbuf,sock))
-{
- errorStr = "Couldn't restore admin:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't restore admin:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if ( mysql_num_rows(res) == 0)
-{
- mysql_free_result(res);
- errorStr = "Couldn't restore admin as couldn't found him in table.\n";
- mysql_close(sock);
- return -1;
-}
-
-row = mysql_fetch_row(res);
-
-p = row[1];
-
-if(p.length() == 0)
-{
- mysql_free_result(res);
- errorStr = "Error in parameter password";
- mysql_close(sock);
- return -1;
-}
-
-memset(passwordE, 0, sizeof(passwordE));
-strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
-
-memset(pass, 0, sizeof(pass));
-
-if (passwordE[0] != 0)
- {
- Decode21(pass, passwordE);
- InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
-
- for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
- {
- DecryptBlock(password + 8*i, pass + 8*i, &ctx);
- }
- }
-else
- {
- password[0] = 0;
- }
-
-ac->password = password;
-
-uint16_t a;
-
-if (GetInt(row[2], &a) == 0)
- ac->priv.userConf = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter ChgConf";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[3], &a) == 0)
- ac->priv.userPasswd = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter ChgPassword";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[4], &a) == 0)
- ac->priv.userStat = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter ChgStat";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[5], &a) == 0)
- ac->priv.userCash = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter ChgCash";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[6], &a) == 0)
- ac->priv.userAddDel = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter UsrAddDel";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[7], &a) == 0)
- ac->priv.tariffChg = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter ChgTariff";
- mysql_close(sock);
- return -1;
- }
-
-if (GetInt(row[8], &a) == 0)
- ac->priv.adminChg = a;
-else
- {
- mysql_free_result(res);
- errorStr = "Error in parameter ChgAdmin";
- mysql_close(sock);
- return -1;
- }
-
-mysql_free_result(res);
-mysql_close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::AddTariff(const std::string & name) const
-{
-sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't add tariff:\n";
-// errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::DelTariff(const std::string & name) const
-{
-sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't delete tariff: ";
-// errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::RestoreTariff(STG::TariffData * td, const std::string & tariffName) const
-{
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock;
-sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
-
-if(MysqlGetQuery(qbuf,sock))
-{
- errorStr = "Couldn't restore Tariff:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't restore Tariff:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-std::string str;
-td->tariffConf.name = tariffName;
-
-row = mysql_fetch_row(res);
-
-std::string param;
-for (int i = 0; i<DIR_NUM; i++)
- {
- strprintf(¶m, "Time%d", i);
- str = row[6+i*8];
- if (str.length() == 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
- ParseTariffTimeStr(str.c_str(),
- td->dirPrice[i].hDay,
- td->dirPrice[i].mDay,
- td->dirPrice[i].hNight,
- td->dirPrice[i].mNight);
-
- strprintf(¶m, "PriceDayA%d", i);
- if (GetDouble(row[1+i*8], &td->dirPrice[i].priceDayA, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
- td->dirPrice[i].priceDayA /= (1024*1024);
-
- strprintf(¶m, "PriceDayB%d", i);
- if (GetDouble(row[2+i*8], &td->dirPrice[i].priceDayB, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
- td->dirPrice[i].priceDayB /= (1024*1024);
-
- strprintf(¶m, "PriceNightA%d", i);
- if (GetDouble(row[3+i*8], &td->dirPrice[i].priceNightA, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
- td->dirPrice[i].priceNightA /= (1024*1024);
-
- strprintf(¶m, "PriceNightB%d", i);
- if (GetDouble(row[4+i*8], &td->dirPrice[i].priceNightB, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
- td->dirPrice[i].priceNightB /= (1024*1024);
-
- strprintf(¶m, "Threshold%d", i);
- if (GetInt(row[5+i*8], &td->dirPrice[i].threshold) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
- strprintf(¶m, "SinglePrice%d", i);
- if (GetInt(row[8+i*8], &td->dirPrice[i].singlePrice) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
- strprintf(¶m, "NoDiscount%d", i);
- if (GetInt(row[7+i*8], &td->dirPrice[i].noDiscount) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
- }//main for
-
-if (GetDouble(row[2+8*DIR_NUM], &td->tariffConf.fee, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
- mysql_close(sock);
- return -1;
- }
-
-if (GetDouble(row[3+8*DIR_NUM], &td->tariffConf.free, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
- mysql_close(sock);
- return -1;
- }
-
-if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
- mysql_close(sock);
- return -1;
- }
-
- str = row[4+8*DIR_NUM];
- param = "TraffType";
-
- if (str.length() == 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
-td->tariffConf.traffType = STG::Tariff::parseTraffType(str);
-
-if (schemaVersion > 0)
-{
- str = row[5+8*DIR_NUM];
- param = "Period";
-
- if (str.length() == 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
- td->tariffConf.period = STG::Tariff::parsePeriod(str);
- }
-else
- {
- td->tariffConf.period = STG::Tariff::MONTH;
- }
-
-if (schemaVersion > 1)
- {
- str = row[6+8*DIR_NUM];
- param = "ChangePolicy";
-
- if (str.length() == 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
- td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(str);
-
- str = row[7+8*DIR_NUM];
- param = "ChangePolicyTimeout";
-
- if (str.length() == 0)
- {
- mysql_free_result(res);
- errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
- mysql_close(sock);
- return -1;
- }
-
- td->tariffConf.changePolicyTimeout = readTime(str);
- }
-else
- {
- td->tariffConf.changePolicy = STG::Tariff::ALLOW;
- td->tariffConf.changePolicyTimeout = 0;
- }
-
-mysql_free_result(res);
-mysql_close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::SaveTariff(const STG::TariffData & td, const std::string & tariffName) const
-{
-std::string param;
-
-std::string res="UPDATE tariffs SET";
-
-for (int i = 0; i < DIR_NUM; i++)
- {
- strprintf(¶m, " PriceDayA%d=%f,", i,
- td.dirPrice[i].priceDayA * pt_mega);
- res += param;
-
- strprintf(¶m, " PriceDayB%d=%f,", i,
- td.dirPrice[i].priceDayB * pt_mega);
- res += param;
-
- strprintf(¶m, " PriceNightA%d=%f,", i,
- td.dirPrice[i].priceNightA * pt_mega);
- res += param;
-
- strprintf(¶m, " PriceNightB%d=%f,", i,
- td.dirPrice[i].priceNightB * pt_mega);
- res += param;
-
- strprintf(¶m, " Threshold%d=%d,", i,
- td.dirPrice[i].threshold);
- res += param;
-
- std::string s;
- strprintf(¶m, " Time%d", i);
-
- strprintf(&s, "%0d:%0d-%0d:%0d",
- td.dirPrice[i].hDay,
- td.dirPrice[i].mDay,
- td.dirPrice[i].hNight,
- td.dirPrice[i].mNight);
-
- res += (param + "='" + s + "',");
-
- strprintf(¶m, " NoDiscount%d=%d,", i,
- td.dirPrice[i].noDiscount);
- res += param;
-
- strprintf(¶m, " SinglePrice%d=%d,", i,
- td.dirPrice[i].singlePrice);
- res += param;
- }
-
-strprintf(¶m, " PassiveCost=%f,", td.tariffConf.passiveCost);
-res += param;
-
-strprintf(¶m, " Fee=%f,", td.tariffConf.fee);
-res += param;
-
-strprintf(¶m, " Free=%f,", td.tariffConf.free);
-res += param;
-
-res += " TraffType='" + STG::Tariff::toString(td.tariffConf.traffType) + "'";
-
-if (schemaVersion > 0)
- res += ", Period='" + STG::Tariff::toString(td.tariffConf.period) + "'";
-
-if (schemaVersion > 1)
- res += ", change_policy='" + STG::Tariff::toString(td.tariffConf.changePolicy) + "'"\
- ", change_policy_timeout='" + formatTime(td.tariffConf.changePolicy) + "'";
-
-strprintf(¶m, " WHERE name='%s' LIMIT 1", tariffName.c_str());
-res += param;
-
-if(MysqlSetQuery(res.c_str()))
-{
- errorStr = "Couldn't save tariff:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const
-{
-std::string res, stTime, endTime, tempStr;
-time_t t;
-tm * lt;
-
-t = time(NULL);
-lt = localtime(&t);
-
-if (lt->tm_hour == 0 && lt->tm_min <= 5)
- {
- t -= 3600 * 24;
- lt = localtime(&t);
- }
-
-MYSQL_RES* result;
-MYSQL * sock;
-strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
-
-if (!(sock=MysqlConnect())){
- mysql_close(sock);
- return -1;
-}
-
-if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
-{
- errorStr = "Couldn't get table " + tempStr + ":\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-my_ulonglong num_rows = mysql_num_rows(result);
-
-mysql_free_result(result);
-
-if (num_rows < 1)
-{
- sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
- "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
- "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
- "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
- lt->tm_mon+1, lt->tm_year+1900);
-
- if(MysqlQuery(qbuf,sock))
- {
- errorStr = "Couldn't create WriteDetailedStat table:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-}
-
-struct tm * lt1;
-struct tm * lt2;
-
-lt1 = localtime(&lastStat);
-
-int h1, m1, s1;
-int h2, m2, s2;
-
-h1 = lt1->tm_hour;
-m1 = lt1->tm_min;
-s1 = lt1->tm_sec;
-
-lt2 = localtime(&t);
-
-h2 = lt2->tm_hour;
-m2 = lt2->tm_min;
-s2 = lt2->tm_sec;
-
-strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
-strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
-
-strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
- "day=%d,startTime='%s',endTime='%s',",
- lt->tm_mon+1, lt->tm_year+1900,
- login.c_str(),
- lt->tm_mday,
- stTime.c_str(),
- endTime.c_str()
- );
-
-STG::TraffStat::const_iterator stIter;
-stIter = statTree.begin();
-
-while (stIter != statTree.end())
- {
- strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f",
- inet_ntostring(stIter->first.ip).c_str(),
- stIter->first.dir,
- stIter->second.down,
- stIter->second.up,
- stIter->second.cash
- );
-
- if( MysqlQuery((res+tempStr).c_str(),sock) )
- {
- errorStr = "Couldn't insert data in WriteDetailedStat:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
- }
-
- result=mysql_store_result(sock);
- if(result)
- mysql_free_result(result);
-
- ++stIter;
- }
-mysql_close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::AddMessage(STG::Message * msg, const std::string & login) const
-{
-struct timeval tv;
-
-gettimeofday(&tv, NULL);
-
-msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
-
-sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld",
- login.c_str(),
- static_cast<long long>(msg->header.id)
- );
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't add message:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return EditMessage(*msg, login);
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::EditMessage(const STG::Message & msg, const std::string & login) const
-{
-std::string res;
-
-strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
- "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
- "WHERE login='%s' AND id=%lld LIMIT 1",
- msg.header.type,
- msg.header.lastSendTime,
- msg.header.creationTime,
- msg.header.showTime,
- msg.header.repeat,
- msg.header.repeatPeriod,
- (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
- login.c_str(),
- msg.header.id
- );
-
-if(MysqlSetQuery(res.c_str()))
-{
- errorStr = "Couldn't edit message:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const
-{
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock;
-
-sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
- login.c_str(), static_cast<unsigned long long>(id));
-
-if(MysqlGetQuery(qbuf,sock))
-{
- errorStr = "Couldn't GetMessage:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't GetMessage:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-row = mysql_fetch_row(res);
-
-if(row[2]&&str2x(row[2], msg->header.type))
-{
- mysql_free_result(res);
- errorStr = "Invalid value in message header for user: " + login;
- mysql_close(sock);
- return -1;
-}
-
-if(row[3] && str2x(row[3], msg->header.lastSendTime))
-{
- mysql_free_result(res);
- errorStr = "Invalid value in message header for user: " + login;
- mysql_close(sock);
- return -1;
-}
-
-if(row[4] && str2x(row[4], msg->header.creationTime))
-{
- mysql_free_result(res);
- errorStr = "Invalid value in message header for user: " + login;
- mysql_close(sock);
- return -1;
-}
-
-if(row[5] && str2x(row[5], msg->header.showTime))
-{
- mysql_free_result(res);
- errorStr = "Invalid value in message header for user: " + login;
- mysql_close(sock);
- return -1;
-}
-
-if(row[6] && str2x(row[6], msg->header.repeat))
-{
- mysql_free_result(res);
- errorStr = "Invalid value in message header for user: " + login;
- mysql_close(sock);
- return -1;
-}
-
-if(row[7] && str2x(row[7], msg->header.repeatPeriod))
-{
- mysql_free_result(res);
- errorStr = "Invalid value in message header for user: " + login;
- mysql_close(sock);
- return -1;
-}
-
-msg->header.id = id;
-msg->text = row[8];
-
-mysql_free_result(res);
-mysql_close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
-{
-sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1",
- login.c_str(), static_cast<long long>(id));
-
-if(MysqlSetQuery(qbuf))
-{
- errorStr = "Couldn't delete Message:\n";
- //errorStr += mysql_error(sock);
- return -1;
-}
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const
-{
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL * sock;
-sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
-
-if(MysqlGetQuery(qbuf,sock))
-{
- errorStr = "Couldn't GetMessageHdrs:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-if (!(res=mysql_store_result(sock)))
-{
- errorStr = "Couldn't GetMessageHdrs:\n";
- errorStr += mysql_error(sock);
- mysql_close(sock);
- return -1;
-}
-
-unsigned int i;
-my_ulonglong num_rows = mysql_num_rows(res);
-uint64_t id = 0;
-
-for (i = 0; i < num_rows; i++)
-{
- row = mysql_fetch_row(res);
- if (str2x(row[1], id))
- continue;
-
- STG::Message::Header hdr;
- if (row[2])
- if(str2x(row[2], hdr.type))
- continue;
-
- if (row[3])
- if(str2x(row[3], hdr.lastSendTime))
- continue;
-
- if (row[4])
- if(str2x(row[4], hdr.creationTime))
- continue;
-
- if (row[5])
- if(str2x(row[5], hdr.showTime))
- continue;
-
- if (row[6])
- if(str2x(row[6], hdr.repeat))
- continue;
-
- if (row[7])
- if(str2x(row[7], hdr.repeatPeriod))
- continue;
-
- hdr.id = id;
- hdrsList->push_back(hdr);
-}
-
-mysql_free_result(res);
-mysql_close(sock);
-return 0;
-}
-//-----------------------------------------------------------------------------
-
-int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
-
- MYSQL * sock;
- int ret=MysqlGetQuery(Query,sock);
- mysql_close(sock);
- return ret;
-}
-//-----------------------------------------------------------------------------
-int MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
- if (!(sock=MysqlConnect())) {
- return -1;
- }
- return MysqlQuery(Query,sock);
-}
-//-----------------------------------------------------------------------------
-MYSQL * MYSQL_STORE::MysqlConnect() const {
- MYSQL * sock;
- if ( !(sock=mysql_init(NULL)) ){
- errorStr= "mysql init susck\n";
- return NULL;
- }
- if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
- storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
- 0,0,NULL,0)))
- {
- errorStr = "Couldn't connect to mysql engine! With error:\n";
- errorStr += mysql_error(sock);
- return NULL;
- }
- else{
- if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
- errorStr = "Database lost !\n";
- return NULL;
- }
- }
- return sock;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-#pragma once
-
-#include "stg/store.h"
-#include "stg/module_settings.h"
-#include "stg/user_traff.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include <mysql/mysql.h>
-
-//-----------------------------------------------------------------------------
-class MYSQL_STORE_SETTINGS
-{
-public:
- MYSQL_STORE_SETTINGS();
- virtual ~MYSQL_STORE_SETTINGS() {}
- virtual int ParseSettings(const STG::ModuleSettings & s);
- virtual const std::string & GetStrError() const { return errorStr; }
-
- const std::string & GetDBUser() const { return dbUser; }
- const std::string & GetDBPassword() const { return dbPass; }
- const std::string & GetDBHost() const { return dbHost; }
- const std::string & GetDBName() const { return dbName; }
-
-private:
- MYSQL_STORE_SETTINGS(const MYSQL_STORE_SETTINGS & rvalue);
- MYSQL_STORE_SETTINGS & operator=(const MYSQL_STORE_SETTINGS & rvalue);
-
- const STG::ModuleSettings * settings;
-
- int ParseParam(const std::vector<STG::ParamValue> & moduleParams,
- const std::string & name, std::string & result);
-
- std::string errorStr;
-
- std::string dbUser;
- std::string dbPass;
- std::string dbName;
- std::string dbHost;
-};
-//-----------------------------------------------------------------------------
-class MYSQL_STORE: public STG::Store
-{
-public:
- MYSQL_STORE();
- const std::string & GetStrError() const override { return errorStr; }
-
- //User
- int GetUsersList(std::vector<std::string> * usersList) const override;
- int AddUser(const std::string & login) const override;
- int DelUser(const std::string & login) const override;
- int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
- int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
- int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
- int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
- int WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message = "") const override;
- int WriteUserConnect(const std::string & login, uint32_t ip) const override;
- int WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & up,
- const STG::DirTraff & down,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double freeMb,
- const std::string & reason) const override;
-
- int WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const override;
-
- int AddMessage(STG::Message * msg, const std::string & login) const override;
- int EditMessage(const STG::Message & msg, const std::string & login) const override;
- int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
- int DelMessage(uint64_t id, const std::string & login) const override;
- int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
-
- int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
-
- //Admin
- int GetAdminsList(std::vector<std::string> * adminsList) const override;
- int AddAdmin(const std::string & login) const override;
- int DelAdmin(const std::string & login) const override;
- int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
- int SaveAdmin(const STG::AdminConf & ac) const override;
-
- //Tariff
- int GetTariffsList(std::vector<std::string> * tariffsList) const override;
- int AddTariff(const std::string & name) const override;
- int DelTariff(const std::string & name) const override;
- int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
- int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
-
- //Corparation
- int GetCorpsList(std::vector<std::string> *) const override {return 0;}
- int SaveCorp(const STG::CorpConf &) const override {return 0;}
- int RestoreCorp(STG::CorpConf *, const std::string &) const override {return 0;}
- int AddCorp(const std::string &) const override {return 0;}
- int DelCorp(const std::string &) const override {return 0;}
-
- // Services
- int GetServicesList(std::vector<std::string> *) const override {return 0;}
- int SaveService(const STG::ServiceConf &) const override {return 0;}
- int RestoreService(STG::ServiceConf *, const std::string &) const override {return 0;}
- int AddService(const std::string &) const override {return 0;}
- int DelService(const std::string &) const override {return 0;}
-
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
- const std::string & GetVersion() const override { return version; }
-
-private:
- MYSQL_STORE(const MYSQL_STORE & rvalue);
- MYSQL_STORE & operator=(const MYSQL_STORE & rvalue);
-
- virtual int WriteLogString(const std::string & str, const std::string & login) const;
- int GetAllParams(std::vector<std::string> * ParamList, const std::string & table, const std::string & name) const;
- int CheckAllTables(MYSQL * sock);
- int MakeUpdates(MYSQL * sock);
- bool IsTablePresent(const std::string & str,MYSQL * sock);
- mutable std::string errorStr;
- int MysqlQuery(const char* sQuery,MYSQL * sock) const;
- int MysqlGetQuery(const char * Query,MYSQL * & sock) const;
- int MysqlSetQuery(const char * Query) const;
- MYSQL * MysqlConnect() const ;
- std::string version;
- MYSQL_STORE_SETTINGS storeSettings;
- STG::ModuleSettings settings;
- int schemaVersion;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * This file contains a realization of a base postgresql-storage plugin class
- *
- * v. 1.3
- * FreeMb logging on disconnects added
- *
- * v. 1.2
- * Reconnection on faults added
- *
- * v. 1.1
- * tb_stats removed
- *
- * v. 1.0
- * Initial implementation
- *
- * $Revision: 1.5 $
- * $Date: 2010/01/06 10:43:48 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "postgresql_store_utils.h"
-#include "postgresql_store.h"
-
-#include "stg/common.h" // str2x, printfd
-
-#include <string>
-#include <vector>
-
-#include <libpq-fe.h>
-
-extern "C" STG::Store* GetStore()
-{
- static POSTGRESQL_STORE plugin;
- return &plugin;
-}
-
-//-----------------------------------------------------------------------------
-POSTGRESQL_STORE::POSTGRESQL_STORE()
- : versionString("postgresql_store v.1.3"),
- server("localhost"),
- database("stargazer"),
- user("stg"),
- password("123456"),
- clientEncoding("KOI8"),
- version(0),
- retries(3),
- connection(NULL),
- logger(STG::PluginLogger::get("store_postgresql"))
-{
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-POSTGRESQL_STORE::~POSTGRESQL_STORE()
-{
-if (connection)
- {
- PQfinish(connection);
- }
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::ParseSettings()
-{
-std::vector<STG::ParamValue>::iterator i;
-
-for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
- {
- if (i->value.empty())
- continue;
- std::string s = ToLower(i->param);
- if (s == "server")
- {
- server = i->value.front();
- }
- if (s == "database")
- {
- database = i->value.front();
- }
- if (s == "user")
- {
- user = i->value.front();
- }
- if (s == "password")
- {
- password = i->value.front();
- }
- if (s == "retries")
- {
- if (str2x(i->value.front(), retries))
- {
- strError = "Invalid 'retries' value";
- printfd(__FILE__, "POSTGRESQL_STORE::ParseSettings(): '%s'\n", strError.c_str());
- return -1;
- }
- }
- }
-
-clientEncoding = "KOI8";
-
-return Connect();
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::Connect()
-{
-std::string params;
-params = "host=" + server + " "
- + "dbname=" + database + " "
- + "user=" + user + " "
- + "password=" + password;
-
-connection = PQconnectdb(params.c_str());
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- strError = PQerrorMessage(connection);
- printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
- // Will try to connect later
- return 0;
- }
-
-if (PQsetClientEncoding(connection, clientEncoding.c_str()))
- {
- strError = PQerrorMessage(connection);
- printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
- return 1;
- }
-
-return CheckVersion();
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::Reset() const
-{
-for (int i = 0; i < retries && PQstatus(connection) != CONNECTION_OK; ++i)
- {
- struct timespec ts = {1, 0};
- nanosleep(&ts, NULL);
- PQreset(connection);
- }
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- strError = PQerrorMessage(connection);
- printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
- return 1;
- }
-
-if (PQsetClientEncoding(connection, clientEncoding.c_str()))
- {
- strError = PQerrorMessage(connection);
- printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
- return -1;
- }
-
-return CheckVersion();
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::CheckVersion() const
-{
-
-if (StartTransaction())
- {
- strError = "Failed to start transaction";
- printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
- return -1;
- }
-
-PGresult * result = PQexec(connection, "SELECT MAX(version) FROM tb_info");
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n");
- RollbackTransaction();
- return -1;
- }
-
-if (str2x(PQgetvalue(result, 0, 0), version))
- {
- strError = "Invalid DB version";
- PQclear(result);
- RollbackTransaction();
- printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
- return -1;
- }
-
-PQclear(result);
-
-if (version < DB_MIN_VERSION)
- {
- strError = "DB version too old";
- RollbackTransaction();
- printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
- return -1;
- }
-
-if (version < 6)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): I recommend you to upgrade your DB to higher version to support FreeMb logging on disconnect. Current version is %d\n", version);
- }
-
-if (CommitTransaction())
- {
- strError = "Failed to commit transaction";
- printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
- return -1;
- }
-
-logger("POSTGRESQL_STORE: Current DB schema version: %d", version);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/store.h"
-#include "stg/module_settings.h"
-#include "stg/logger.h"
-
-#include <string>
-#include <vector>
-
-#include <libpq-fe.h>
-
-// Minimal DB version is 5
-// Recommended DB version is 6 (support FreeMb logging on disconnects)
-#define DB_MIN_VERSION 5
-
-namespace STG
-{
-
-class UserIPs;
-
-}
-
-class POSTGRESQL_STORE : public STG::Store {
-public:
- POSTGRESQL_STORE();
- ~POSTGRESQL_STORE() override;
-
- // Users
- int GetUsersList(std::vector<std::string> * usersList) const override;
- int AddUser(const std::string & login) const override;
- int DelUser(const std::string & login) const override;
- int SaveUserStat(const STG::UserStat & stat, const std::string & login) const override;
- int SaveUserConf(const STG::UserConf & conf, const std::string & login) const override;
- int RestoreUserStat(STG::UserStat * stat, const std::string & login) const override;
- int RestoreUserConf(STG::UserConf * conf, const std::string & login) const override;
- int WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message) const override;
- int WriteUserConnect(const std::string & login, uint32_t ip) const override;
- int WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & up,
- const STG::DirTraff & down,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double freeMb,
- const std::string & reason) const override;
- int WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const override;
-
- // Messages
- int AddMessage(STG::Message * msg, const std::string & login) const override;
- int EditMessage(const STG::Message & msg, const std::string & login) const override;
- int GetMessage(uint64_t id, STG::Message * msg, const std::string & login) const override;
- int DelMessage(uint64_t id, const std::string & login) const override;
- int GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList, const std::string & login) const override;
-
- // Stats
- int SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const override;
-
- // Admins
- int GetAdminsList(std::vector<std::string> * adminsList) const override;
- int SaveAdmin(const STG::AdminConf & ac) const override;
- int RestoreAdmin(STG::AdminConf * ac, const std::string & login) const override;
- int AddAdmin(const std::string & login) const override;
- int DelAdmin(const std::string & login) const override;
-
- // Tariffs
- int GetTariffsList(std::vector<std::string> * tariffsList) const override;
- int AddTariff(const std::string & name) const override;
- int DelTariff(const std::string & name) const override;
- int SaveTariff(const STG::TariffData & td, const std::string & tariffName) const override;
- int RestoreTariff(STG::TariffData * td, const std::string & tariffName) const override;
-
- // Corporations
- int GetCorpsList(std::vector<std::string> * corpsList) const override;
- int SaveCorp(const STG::CorpConf & cc) const override;
- int RestoreCorp(STG::CorpConf * cc, const std::string & name) const override;
- int AddCorp(const std::string & name) const override;
- int DelCorp(const std::string & name) const override;
-
- // Services
- int GetServicesList(std::vector<std::string> * servicesList) const override;
- int SaveService(const STG::ServiceConf & sc) const override;
- int RestoreService(STG::ServiceConf * sc, const std::string & name) const override;
- int AddService(const std::string & name) const override;
- int DelService(const std::string & name) const override;
-
- // Settings
- void SetSettings(const STG::ModuleSettings & s) override { settings = s; }
- int ParseSettings() override;
-
- const std::string & GetStrError() const override { return strError; }
- const std::string & GetVersion() const override { return versionString; }
-private:
- POSTGRESQL_STORE(const POSTGRESQL_STORE & rvalue);
- POSTGRESQL_STORE & operator=(const POSTGRESQL_STORE & rvalue);
-
- int StartTransaction() const;
- int CommitTransaction() const;
- int RollbackTransaction() const;
-
- int EscapeString(std::string & value) const;
-
- int SaveStat(const STG::UserStat & stat, const std::string & login, int year = 0, int month = 0) const;
-
- int SaveUserServices(uint32_t uid, const std::vector<std::string> & services) const;
- int SaveUserData(uint32_t uid, const std::vector<std::string> & data) const;
- int SaveUserIPs(uint32_t uid, const STG::UserIPs & ips) const;
-
- void MakeDate(std::string & date, int year = 0, int month = 0) const;
-
- int Connect();
- int Reset() const;
- int CheckVersion() const;
-
- std::string versionString;
- mutable std::string strError;
- std::string server;
- std::string database;
- std::string user;
- std::string password;
- std::string clientEncoding;
- STG::ModuleSettings settings;
- mutable pthread_mutex_t mutex;
- mutable int version;
- int retries;
-
- PGconn * connection;
-
- STG::PluginLogger logger;
-};
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Administrators manipulation methods
- *
- * $Revision: 1.3 $
- * $Date: 2010/11/08 10:10:24 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/locker.h"
-#include "stg/common.h"
-#include "stg/admin_conf.h"
-#include "stg/blowfish.h"
-
-#include <string>
-#include <vector>
-#include <sstream>
-
-#include <libpq-fe.h>
-
-#define adm_enc_passwd "cjeifY8m3"
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to start transaction'\n");
- return -1;
- }
-
-result = PQexec(connection, "SELECT login FROM tb_admins WHERE login <> '@stargazer'");
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- adminsList->push_back(PQgetvalue(result, i, 0));
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveAdmin(const STG::AdminConf & ac) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to start transaction'\n");
- return -1;
- }
-
-char encodedPass[2 * ADM_PASSWD_LEN + 2];
-char cryptedPass[ADM_PASSWD_LEN + 1];
-char adminPass[ADM_PASSWD_LEN + 1];
-BLOWFISH_CTX ctx;
-
-memset(cryptedPass, 0, ADM_PASSWD_LEN + 1);
-strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
-InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
-
-for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
- EncryptBlock(cryptedPass + 8 * i, adminPass + 8 * i, &ctx);
-
-cryptedPass[ADM_PASSWD_LEN] = 0;
-Encode12(encodedPass, cryptedPass, ADM_PASSWD_LEN);
-
-std::string pass = encodedPass;
-std::string login = ac.login;
-
-if (EscapeString(pass))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to escape password'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(login))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::stringstream query;
-query << "UPDATE tb_admins SET "
- << "passwd = '" << pass << "', "
- << "chg_conf = " << ac.priv.userConf << ", "
- << "chg_password = " << ac.priv.userPasswd << ", "
- << "chg_stat = " << ac.priv.userStat << ", "
- << "chg_cash = " << ac.priv.userCash << ", "
- << "usr_add_del = " << ac.priv.userAddDel << ", "
- << "chg_tariff = " << ac.priv.tariffChg << ", "
- << "chg_admin = " << ac.priv.adminChg << " "
- << "WHERE login = '" << login << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::RestoreAdmin(STG::AdminConf * ac, const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to start transaction'\n");
- return -1;
- }
-
-char cryptedPass[ADM_PASSWD_LEN + 1];
-char adminPass[ADM_PASSWD_LEN + 1];
-BLOWFISH_CTX ctx;
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT login, passwd, \
- chg_conf, chg_password, chg_stat, \
- chg_cash, usr_add_del, chg_tariff, \
- chg_admin, chg_service, chg_corporation \
- FROM tb_admins \
- WHERE login = '" << elogin << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch admin's data";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-ac->login = PQgetvalue(result, 0, 0);
-ac->password = PQgetvalue(result, 0, 1);
-
-std::stringstream tuple;
-tuple << PQgetvalue(result, 0, 2) << " "
- << PQgetvalue(result, 0, 3) << " "
- << PQgetvalue(result, 0, 4) << " "
- << PQgetvalue(result, 0, 5) << " "
- << PQgetvalue(result, 0, 6) << " "
- << PQgetvalue(result, 0, 7) << " "
- << PQgetvalue(result, 0, 8) << " "
- << PQgetvalue(result, 0, 9) << " "
- << PQgetvalue(result, 0, 10);
-
-PQclear(result);
-
-tuple >> ac->priv.userConf
- >> ac->priv.userPasswd
- >> ac->priv.userStat
- >> ac->priv.userCash
- >> ac->priv.userAddDel
- >> ac->priv.tariffChg
- >> ac->priv.adminChg;
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to commit transacion'\n");
- return -1;
- }
-
-if (ac->password == "")
- {
- return 0;
- }
-
-Decode21(cryptedPass, ac->password.c_str());
-InitContext(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
-for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
- {
- DecryptBlock(adminPass + 8 * i, cryptedPass + 8 * i, &ctx);
- }
-ac->password = adminPass;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::AddAdmin(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "INSERT INTO tb_admins \
- (login, passwd, \
- chg_conf, chg_password, chg_stat, \
- chg_cash, usr_add_del, chg_tariff, \
- chg_admin, chg_service, chg_corporation) \
- VALUES "
- << "('" << elogin << "', \
- '', 0, 0, 0, 0, 0, 0, 0, 0, 0)";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::DelAdmin(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "DELETE FROM tb_admins WHERE login = '" << elogin << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Corporations manipulation methods
- *
- * $Revision: 1.2 $
- * $Date: 2009/06/09 12:32:39 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/corp_conf.h"
-#include "stg/locker.h"
-#include "stg/common.h"
-
-#include <string>
-#include <vector>
-#include <sstream>
-
-#include <libpq-fe.h>
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetCorpsList(std::vector<std::string> * corpsList) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to start transaction'\n");
- return -1;
- }
-
-result = PQexec(connection, "SELECT name FROM tb_corporations");
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- corpsList->push_back(PQgetvalue(result, i, 0));
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveCorp(const STG::CorpConf & cc) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = cc.name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "UPDATE tb_corporations SET "
- << "cash = " << cc.cash
- << "WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::RestoreCorp(STG::CorpConf * cc, const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT cash FROM tb_corporations WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch corp's data";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::stringstream tuple;
-tuple << PQgetvalue(result, 0, 0);
-
-PQclear(result);
-
-tuple >> cc->cash;
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::AddCorp(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "INSERT INTO tb_corporations \
- (name, cash) \
- VALUES \
- ('" << ename << "', 0)";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::DelCorp(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "DELETE FROM tb_corporations WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-
-/*
- * Messages manipualtion methods
- *
- * $Revision: 1.6 $
- * $Date: 2009/07/15 11:19:42 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/common.h"
-#include "stg/locker.h"
-#include "stg/message.h"
-
-#include <string>
-#include <vector>
-#include <sstream>
-
-#include <libpq-fe.h>
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::AddMessage(STG::Message * msg, const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-std::string etext = msg->text;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(etext))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to escape message text'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT sp_add_message("
- << "'" << elogin << "', "
- << "CAST(1 AS SMALLINT), " // Here need to be a version, but, it's uninitiated actually
- << "CAST(" << msg->header.type << " AS SMALLINT), "
- << "CAST('" << formatTime(msg->header.lastSendTime) << "' AS TIMESTAMP), "
- << "CAST('" << formatTime(msg->header.creationTime) << "' AS TIMESTAMP), "
- << msg->header.showTime << ", "
- << "CAST(" << msg->header.repeat << " AS SMALLINT), "
- << msg->header.repeatPeriod << ", "
- << "'" << etext << "')";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch newlly added message ID";
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::stringstream tuple;
-tuple << PQgetvalue(result, 0, 0);
-
-PQclear(result);
-
-tuple >> msg->header.id;
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::EditMessage(const STG::Message & msg,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-std::string etext = msg.text;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(etext))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to escape message text'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "UPDATE tb_messages SET "
- << "fk_user = (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
- << "ver = " << msg.header.ver << ", "
- << "msg_type = " << msg.header.type << ", "
- << "last_send_time = CAST('" << formatTime(msg.header.lastSendTime) << "' AS TIMESTAMP), "
- << "creation_time = CAST('" << formatTime(msg.header.creationTime) << "' AS TIMESTAMP), "
- << "show_time = " << msg.header.showTime << ", "
- << "repeat = " << msg.header.repeat << ", "
- << "repeat_period = " << msg.header.repeatPeriod << ", "
- << "msg_text = '" << etext << "' "
- << "WHERE pk_message = " << msg.header.id;
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetMessage(uint64_t id,
- STG::Message * msg,
- const std::string &) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT ver, msg_type, last_send_time, \
- creation_time, show_time, repeat, \
- repeat_period, msg_text \
- FROM tb_messages \
- WHERE pk_message = " << id;
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch message data";
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-str2x(PQgetvalue(result, 0, 0), msg->header.ver);
-str2x(PQgetvalue(result, 0, 1), msg->header.type);
-msg->header.lastSendTime = static_cast<unsigned int>(readTime(PQgetvalue(result, 0, 2)));
-msg->header.creationTime = static_cast<unsigned int>(readTime(PQgetvalue(result, 0, 3)));
-str2x(PQgetvalue(result, 0, 4), msg->header.showTime);
-str2x(PQgetvalue(result, 0, 5), msg->header.repeat);
-str2x(PQgetvalue(result, 0, 6), msg->header.repeatPeriod);
-msg->text = PQgetvalue(result, 0, 7);
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::DelMessage(uint64_t id, const std::string &) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::ostringstream query;
-query << "DELETE FROM tb_messages WHERE pk_message = " << id;
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetMessageHdrs(std::vector<STG::Message::Header> * hdrsList,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT pk_message, ver, msg_type, \
- last_send_time, creation_time, show_time, \
- repeat, repeat_period \
- FROM tb_messages \
- WHERE fk_user IN \
- (SELECT pk_user FROM tb_users \
- WHERE name = '" << elogin << "')";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- std::stringstream tuple;
- STG::Message::Header header;
- tuple << PQgetvalue(result, i, 0) << " ";
- tuple << PQgetvalue(result, i, 1) << " ";
- tuple << PQgetvalue(result, i, 2) << " ";
- header.lastSendTime = static_cast<unsigned int>(readTime(PQgetvalue(result, i, 3)));
- header.creationTime = static_cast<unsigned int>(readTime(PQgetvalue(result, i, 4)));
- tuple << PQgetvalue(result, i, 5) << " ";
- tuple << PQgetvalue(result, i, 6) << " ";
- tuple << PQgetvalue(result, i, 7) << " ";
-
- tuple >> header.id;
- tuple >> header.ver;
- tuple >> header.type;
- tuple >> header.showTime;
- tuple >> header.repeat;
- tuple >> header.repeatPeriod;
- hdrsList->push_back(header);
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-
-/*
- * Services manipulation methods
- *
- * $Revision: 1.2 $
- * $Date: 2009/06/09 12:32:40 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/service_conf.h"
-#include "stg/common.h"
-#include "stg/locker.h"
-
-#include <string>
-#include <vector>
-#include <sstream>
-
-#include <libpq-fe.h>
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetServicesList(std::vector<std::string> * servicesList) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to start transaction'\n");
- return -1;
- }
-
-result = PQexec(connection, "SELECT name FROM tb_services");
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- servicesList->push_back(PQgetvalue(result, i, 0));
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveService(const STG::ServiceConf & sc) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = sc.name;
-std::string ecomment = sc.comment;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(ecomment))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to escape comment'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "UPDATE tb_services SET "
- << "comment = '" << ecomment << "', "
- << "cost = " << sc.cost << ", "
- << "pay_day = " << sc.payDay << " "
- << "WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::RestoreService(STG::ServiceConf * sc,
- const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT comment, cost, pay_day FROM tb_services WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch service's data";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::stringstream tuple;
-tuple << PQgetvalue(result, 0, 0) << " "
- << PQgetvalue(result, 0, 1) << " "
- << PQgetvalue(result, 0, 2);
-
-PQclear(result);
-
-tuple >> sc->comment
- >> sc->cost
- >> sc->payDay;
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::AddService(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "INSERT INTO tb_services \
- (name, comment, cost, pay_day) \
- VALUES \
- ('" << ename << "', '', 0, 0)";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::DelService(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "DELETE FROM tb_services WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Tariffs manipulation methods
- *
- * $Revision: 1.2 $
- * $Date: 2009/06/09 12:32:40 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/tariff_conf.h"
-#include "stg/common.h"
-#include "stg/locker.h"
-
-#include <string>
-#include <vector>
-#include <sstream>
-#include <cmath>
-
-#include <libpq-fe.h>
-
-namespace
-{
-
-const int pt_mega = 1024 * 1024;
-
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to start transaction'\n");
- return -1;
- }
-
-result = PQexec(connection, "SELECT name FROM tb_tariffs");
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- tariffsList->push_back(PQgetvalue(result, i, 0));
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::AddTariff(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT sp_add_tariff('" << ename << "', " << DIR_NUM << ")";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::DelTariff(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = name;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "DELETE FROM tb_tariffs WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveTariff(const STG::TariffData & td,
- const std::string & tariffName) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = tariffName;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- {
- std::ostringstream query;
- query << "SELECT pk_tariff FROM tb_tariffs WHERE name = '" << ename << "'";
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch tariff ID";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int32_t id;
-
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, 0, 0);
-
- PQclear(result);
-
- tuple >> id;
- }
-
- {
- std::ostringstream query;
- query << "UPDATE tb_tariffs SET \
- fee = " << td.tariffConf.fee << ", \
- free = " << td.tariffConf.free << ", \
- passive_cost = " << td.tariffConf.passiveCost << ", \
- traff_type = " << td.tariffConf.traffType;
-
- if (version > 6)
- query << ", period = '" << STG::Tariff::toString(td.tariffConf.period) << "'";
-
- if (version > 7)
- query << ", change_policy = '" << STG::Tariff::toString(td.tariffConf.changePolicy) << "', \
- change_policy_timeout = CAST('" << formatTime(td.tariffConf.changePolicyTimeout) << "' AS TIMESTAMP)";
-
- query << " WHERE pk_tariff = " << id;
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-for(int i = 0; i < DIR_NUM; i++)
- {
- double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
- double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
- double pna = 0;
- double pnb = 0;
-
- if (td.dirPrice[i].singlePrice)
- {
- pna = pda;
- pnb = pdb;
- }
- else
- {
- pna = td.dirPrice[i].priceNightA * 1024 * 1024;
- pnb = td.dirPrice[i].priceNightB * 1024 * 1024;
- }
-
- int threshold = 0;
- if (td.dirPrice[i].noDiscount)
- {
- threshold = 0xffFFffFF;
- }
- else
- {
- threshold = td.dirPrice[i].threshold;
- }
-
- {
- std::ostringstream query;
- query << "UPDATE tb_tariffs_params SET \
- price_day_a = " << pda << ", \
- price_day_b = " << pdb << ", \
- price_night_a = " << pna << ", \
- price_night_b = " << pnb << ", \
- threshold = " << threshold << ", \
- time_day_begins = CAST('" << td.dirPrice[i].hDay
- << ":"
- << td.dirPrice[i].mDay << "' AS TIME), \
- time_day_ends = CAST('" << td.dirPrice[i].hNight
- << ":"
- << td.dirPrice[i].mNight << "' AS TIME) \
- WHERE fk_tariff = " << id << " AND dir_num = " << i;
-
- result = PQexec(connection, query.str().c_str());
- }
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- PQclear(result);
- }
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::RestoreTariff(STG::TariffData * td,
- const std::string & tariffName) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string ename = tariffName;
-
-if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to escape name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-td->tariffConf.name = tariffName;
-
-std::ostringstream query;
-query << "SELECT pk_tariff, \
- fee, \
- free, \
- passive_cost, \
- traff_type";
-
-if (version > 6)
- query << ", period";
-
-if (version > 7)
- query << ", change_policy \
- , change_policy_timeout";
-
-query << " FROM tb_tariffs WHERE name = '" << ename << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch tariff data";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int id;
-
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, 0, 0) << " ";
- tuple << PQgetvalue(result, 0, 1) << " ";
- tuple << PQgetvalue(result, 0, 2) << " ";
- tuple << PQgetvalue(result, 0, 3) << " ";
- tuple << PQgetvalue(result, 0, 4) << " ";
-
- tuple >> id;
- tuple >> td->tariffConf.fee;
- tuple >> td->tariffConf.free;
- tuple >> td->tariffConf.passiveCost;
- unsigned traffType;
- tuple >> traffType;
- td->tariffConf.traffType = static_cast<STG::Tariff::TraffType>(traffType);
- }
-
-if (version > 6)
- td->tariffConf.period = STG::Tariff::parsePeriod(PQgetvalue(result, 0, 5));
-
-if (version > 7)
- {
- td->tariffConf.changePolicy = STG::Tariff::parseChangePolicy(PQgetvalue(result, 0, 6));
- td->tariffConf.changePolicyTimeout = readTime(PQgetvalue(result, 0, 7));
- }
-
-PQclear(result);
-
-query.str("");
-query << "SELECT dir_num, \
- price_day_a, \
- price_day_b, \
- price_night_a, \
- price_night_b, \
- threshold, \
- EXTRACT(hour FROM time_day_begins), \
- EXTRACT(minute FROM time_day_begins), \
- EXTRACT(hour FROM time_day_ends), \
- EXTRACT(minute FROM time_day_ends) \
- FROM tb_tariffs_params \
- WHERE fk_tariff = " << id;
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-tuples = PQntuples(result);
-
-if (tuples != DIR_NUM)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Tariff params count and DIR_NUM does not feet (wanted %d, actually %d)'\n", DIR_NUM, tuples);
- }
-
-for (int i = 0; i < std::min(tuples, DIR_NUM); ++i)
- {
- int dir;
-
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, i, 0) << " ";
- tuple << PQgetvalue(result, i, 1) << " ";
- tuple << PQgetvalue(result, i, 2) << " ";
- tuple << PQgetvalue(result, i, 3) << " ";
- tuple << PQgetvalue(result, i, 4) << " ";
- tuple << PQgetvalue(result, i, 5) << " ";
- tuple << PQgetvalue(result, i, 6) << " ";
- tuple << PQgetvalue(result, i, 7) << " ";
- tuple << PQgetvalue(result, i, 8) << " ";
- tuple << PQgetvalue(result, i, 9) << " ";
-
- tuple >> dir;
- tuple >> td->dirPrice[dir].priceDayA;
- td->dirPrice[dir].priceDayA /= 1024 * 1024;
- tuple >> td->dirPrice[dir].priceDayB;
- td->dirPrice[dir].priceDayB /= 1024 * 1024;
- tuple >> td->dirPrice[dir].priceNightA;
- td->dirPrice[dir].priceNightA /= 1024 * 1024;
- tuple >> td->dirPrice[dir].priceNightB;
- td->dirPrice[dir].priceNightB /= 1024 * 1024;
- tuple >> td->dirPrice[dir].threshold;
- tuple >> td->dirPrice[dir].hDay;
- tuple >> td->dirPrice[dir].mDay;
- tuple >> td->dirPrice[dir].hNight;
- tuple >> td->dirPrice[dir].mNight;
- }
-
- if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
- std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
- {
- td->dirPrice[dir].singlePrice = true;
- }
- else
- {
- td->dirPrice[dir].singlePrice = false;
- }
- if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
- {
- td->dirPrice[dir].noDiscount = true;
- }
- else
- {
-
- td->dirPrice[dir].noDiscount = false;
- }
-
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * User manipulation methods
- *
- * $Revision: 1.14 $
- * $Date: 2010/05/07 07:26:36 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/user_ips.h"
-#include "stg/user_traff.h"
-#include "stg/common.h"
-#include "stg/const.h"
-#include "stg/locker.h"
-#include "../../../stg_timer.h"
-
-#include <string>
-#include <vector>
-#include <sstream>
-#include <ctime>
-
-#include <libpq-fe.h>
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to start transaction'\n");
- return -1;
- }
-
-result = PQexec(connection, "SELECT name FROM tb_users");
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- usersList->push_back(PQgetvalue(result, i, 0));
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::AddUser(const std::string & name) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = name;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT sp_add_user('" << elogin << "')";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::DelUser(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "DELETE FROM tb_users WHERE name = '" << elogin << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveUserStat(const STG::UserStat & stat,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-return SaveStat(stat, login);
-}
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveStat(const STG::UserStat & stat,
- const std::string & login,
- int year,
- int month) const
-{
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "UPDATE tb_users SET "
- "cash = " << stat.cash << ", "
- "free_mb = " << stat.freeMb << ", "
- "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), "
- "last_cash_add = " << stat.lastCashAdd << ", "
- "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), "
- "passive_time = " << stat.passiveTime << " "
- "WHERE name = '" << elogin << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-std::string date;
-
-MakeDate(date, year, month);
-
-for (int dir = 0; dir < DIR_NUM; ++dir)
- {
- query.str("");
- query << "SELECT sp_add_stats_traffic ("
- "'" << elogin << "', "
- "CAST('" << date << "' AS DATE), "
- "CAST(" << dir << " AS SMALLINT), "
- "CAST(" << stat.monthUp[dir] << " AS BIGINT), "
- "CAST(" << stat.monthDown[dir] << " AS BIGINT))";
-
- result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- PQclear(result);
- }
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveUserConf(const STG::UserConf & conf,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch user's ID";
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-uint32_t uid;
-
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, 0, 0);
-
- PQclear(result);
-
- tuple >> uid;
- }
-
-std::string eaddress = conf.address;
-std::string eemail = conf.email;
-std::string egroup = conf.group;
-std::string enote = conf.note;
-std::string epassword = conf.password;
-std::string ephone = conf.phone;
-std::string erealname = conf.realName;
-std::string etariffname = conf.tariffName;
-std::string enexttariff = conf.nextTariff;
-std::string ecorporation = conf.corp;
-
-if (EscapeString(eaddress))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape address'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(eemail))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape email'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(egroup))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape group'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(enote))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape note'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(epassword))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape password'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(ephone))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape phone'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(erealname))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape real name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(etariffname))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape tariff name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(enexttariff))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape next tariff name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(ecorporation))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape corporation name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-query.str("");
-query << "UPDATE tb_users SET "
- "address = '" << eaddress << "', "
- "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
- "credit = " << conf.credit << ", "
- "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), "
- "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
- "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
- "email = '" << eemail << "', "
- "grp = '" << egroup << "', "
- "note = '" << enote << "', "
- "passive = " << (conf.passive ? "'t'" : "'f'") << ", "
- "passwd = '" << epassword << "', "
- "phone = '" << ephone << "', "
- "real_name = '" << erealname << "', "
- "fk_tariff = (SELECT pk_tariff "
- "FROM tb_tariffs "
- "WHERE name = '" << etariffname << "'), "
- "fk_tariff_change = (SELECT pk_tariff "
- "FROM tb_tariffs "
- "WHERE name = '" << enexttariff << "'), "
- "fk_corporation = (SELECT pk_corporation "
- "FROM tb_corporations "
- "WHERE name = '" << ecorporation << "') "
- "WHERE pk_user = " << uid;
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (SaveUserServices(uid, conf.services))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (SaveUserData(uid, conf.userdata))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's data'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (SaveUserIPs(uid, conf.ips))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's IPs'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::RestoreUserStat(STG::UserStat * stat,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- {
- std::ostringstream query;
- query << "SELECT cash, free_mb, "
- "last_activity_time, last_cash_add, "
- "last_cash_add_time, passive_time "
- "FROM tb_users "
- "WHERE name = '" << elogin << "'";
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch user's stat";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, 0, 0) << " ";
- tuple << PQgetvalue(result, 0, 1) << " ";
- stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2));
- tuple << PQgetvalue(result, 0, 3) << " ";
- stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4));
- tuple << PQgetvalue(result, 0, 5) << " ";
-
- PQclear(result);
-
- tuple >> stat->cash
- >> stat->freeMb
- >> stat->lastCashAdd
- >> stat->passiveTime;
- }
-
- {
- std::ostringstream query;
- query << "SELECT dir_num, upload, download "
- "FROM tb_stats_traffic "
- "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND "
- "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))";
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, i, 0) << " ";
- tuple << PQgetvalue(result, i, 1) << " ";
- tuple << PQgetvalue(result, i, 2) << " ";
-
- int dir;
-
- tuple >> dir;
- tuple >> stat->monthUp[dir];
- tuple >> stat->monthDown[dir];
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::RestoreUserConf(STG::UserConf * conf,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin = login;
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- {
- std::ostringstream query;
- query << "SELECT tb_users.pk_user, tb_users.address, tb_users.always_online, "
- "tb_users.credit, tb_users.credit_expire, tb_users.disabled, "
- "tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, "
- "tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, "
- "tb_users.real_name, tf1.name, tf2.name, tb_corporations.name "
- "FROM tb_users LEFT JOIN tb_tariffs AS tf1 "
- "ON tf1.pk_tariff = tb_users.fk_tariff "
- "LEFT JOIN tb_tariffs AS tf2 "
- "ON tf2.pk_tariff = tb_users.fk_tariff_change "
- "LEFT JOIN tb_corporations "
- "ON tb_corporations.pk_corporation = tb_users.fk_corporation "
- "WHERE tb_users.name = '" << elogin << "'";
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch user's stat";
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-uint32_t uid;
-
- {
- std::stringstream tuple;
- tuple << PQgetvalue(result, 0, 0) << " "; // uid
- conf->address = PQgetvalue(result, 0, 1); // address
- conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1);
- tuple << PQgetvalue(result, 0, 3) << " "; // credit
- conf->creditExpire = readTime(PQgetvalue(result, 0, 4)); // creditExpire
- conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1);
- conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1);
- conf->email = PQgetvalue(result, 0, 7); // email
- conf->group = PQgetvalue(result, 0, 8); // group
- conf->note = PQgetvalue(result, 0, 9); // note
- conf->passive = !strncmp(PQgetvalue(result, 0, 10), "t", 1);
- conf->password = PQgetvalue(result, 0, 11); // password
- conf->phone = PQgetvalue(result, 0, 12); // phone
- conf->realName = PQgetvalue(result, 0, 13); // realName
- conf->tariffName = PQgetvalue(result, 0, 14); // tariffName
- conf->nextTariff = PQgetvalue(result, 0, 15); // nextTariff
- conf->corp = PQgetvalue(result, 0, 16); // corp
-
- PQclear(result);
-
- if (conf->tariffName == "")
- conf->tariffName = NO_TARIFF_NAME;
- if (conf->corp == "")
- conf->corp = NO_CORP_NAME;
-
- tuple >> uid
- >> conf->credit;
- }
-
- {
- std::ostringstream query;
- query << "SELECT name FROM tb_services "
- "WHERE pk_service IN (SELECT fk_service "
- "FROM tb_users_services "
- "WHERE fk_user = " << uid << ")";
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- conf->services.push_back(PQgetvalue(result, i, 0));
- }
-
-PQclear(result);
-
- {
- std::ostringstream query;
- query << "SELECT num, data "
- "FROM tb_users_data "
- "WHERE fk_user = " << uid;
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-tuples = PQntuples(result);
-
-for (int i = 0; i < tuples; ++i)
- {
- int num;
- if (str2x(PQgetvalue(result, i, 0), num))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to convert string to int'\n");
- }
- else
- {
- if (num < USERDATA_NUM &&
- num >= 0)
- {
- conf->userdata[num] = PQgetvalue(result, i, 1);
- }
- }
- }
-
-PQclear(result);
-
- {
- std::ostringstream query;
- query << "SELECT host(ip), masklen(ip) "
- "FROM tb_allowed_ip "
- "WHERE fk_user = " << uid;
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-tuples = PQntuples(result);
-
-STG::UserIPs ips;
-for (int i = 0; i < tuples; ++i)
- {
- STG::IPMask im;
-
- im.ip = inet_strington(PQgetvalue(result, i, 0));
-
- if (str2x(PQgetvalue(result, i, 1), im.mask))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to fetch mask'\n");
- continue;
- }
-
- ips.add(im);
- }
-conf->ips = ips;
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::WriteUserChgLog(const std::string & login,
- const std::string & admLogin,
- uint32_t admIP,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & message = "") const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin(login);
-std::string eadminLogin(admLogin);
-std::string eparam(paramName);
-std::string eold(oldValue);
-std::string enew(newValue);
-std::string emessage(message);
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(eadminLogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape admin's login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(eparam))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape param's name'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(eold))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape old value'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-if (EscapeString(enew))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape new value'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-query << "SELECT sp_add_param_log_entry("
- "'" << elogin << "', "
- "'" << eadminLogin << "', CAST('"
- << inet_ntostring(admIP) << "/32' AS INET), "
- "'" << eparam << "', "
- "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
- "'" << eold << "', "
- "'" << enew << "', "
- "'" << emessage << "')";
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin(login);
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::ostringstream query;
-if (version < 6)
- {
- query << "SELECT sp_add_session_log_entry("
- "'" << elogin << "', "
- "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
- "'c', CAST('"
- << inet_ntostring(ip) << "/32' AS INET), 0)";
- }
-else
- {
- query << "SELECT sp_add_session_log_entry("
- "'" << elogin << "', "
- "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
- "'c', CAST('"
- << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
- }
-
-result = PQexec(connection, query.str().c_str());
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::WriteUserDisconnect(const std::string & login,
- const STG::DirTraff & monthUp,
- const STG::DirTraff & monthDown,
- const STG::DirTraff & sessionUp,
- const STG::DirTraff & sessionDown,
- double cash,
- double freeMb,
- const std::string & reason) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-PGresult * result;
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin(login);
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-std::string ereason(reason);
-
-if (EscapeString(ereason))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape reason'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- {
- std::ostringstream query;
- if (version < 6)
- {
- // Old database version - no freeMb logging support
- query << "SELECT sp_add_session_log_entry("
- "'" << elogin << "', "
- "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
- "'d', CAST('0.0.0.0/0' AS INET), "
- << cash << ")";
- }
- else
- {
- query << "SELECT sp_add_session_log_entry("
- "'" << elogin << "', "
- "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
- "'d', CAST('0.0.0.0/0' AS INET), "
- << cash << ", " << freeMb << ", '" << ereason << "')";
- }
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-int tuples = PQntuples(result);
-
-if (tuples != 1)
- {
- strError = "Failed to fetch session's log ID";
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-uint32_t lid;
-
-if (str2x(PQgetvalue(result, 0, 0), lid))
- {
- strError = "Failed to convert string to int";
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
- PQclear(result);
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-PQclear(result);
-
-for (int i = 0; i < DIR_NUM; ++i)
- {
- std::ostringstream query;
- query << "INSERT INTO tb_sessions_data "
- "(fk_session_log, "
- "dir_num, "
- "session_upload, "
- "session_download, "
- "month_upload, "
- "month_download)"
- "VALUES ("
- << lid << ", "
- << i << ", "
- << sessionUp[i] << ", "
- << sessionDown[i] << ", "
- << monthUp[i] << ", "
- << monthDown[i] << ")";
-
- result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- PQclear(result);
- }
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
- time_t lastStat,
- const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-if (PQstatus(connection) != CONNECTION_OK)
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
- if (Reset())
- {
- strError = "Connection lost";
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
- return -1;
- }
- }
-
-if (StartTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to start transaction'\n");
- return -1;
- }
-
-std::string elogin(login);
-
-if (EscapeString(elogin))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to escape login'\n");
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
-STG::TraffStat::const_iterator it;
-time_t currTime = time(NULL);
-
-for (it = statTree.begin(); it != statTree.end(); ++it)
- {
- std::ostringstream query;
- query << "INSERT INTO tb_detail_stats "
- "(till_time, from_time, fk_user, "
- "dir_num, ip, download, upload, cost) "
- "VALUES ("
- "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
- "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
- "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
- << it->first.dir << ", "
- << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
- << it->second.down << ", "
- << it->second.up << ", "
- << it->second.cash << ")";
-
- PGresult * result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
- if (RollbackTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
- }
- return -1;
- }
-
- PQclear(result);
- }
-
-if (CommitTransaction())
- {
- printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to commit transaction'\n");
- return -1;
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-
-return SaveStat(stat, login, year, month);
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveUserServices(uint32_t uid,
- const std::vector<std::string> & services) const
-{
-PGresult * result;
-
- {
- std::ostringstream query;
- query << "DELETE FROM tb_users_services WHERE fk_user = " << uid;
-
- result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
- return -1;
- }
-
- PQclear(result);
- }
-
-std::vector<std::string>::const_iterator it;
-
-for (it = services.begin(); it != services.end(); ++it)
- {
- std::string ename = *it;
-
- if (EscapeString(ename))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): 'Failed to escape service name'\n");
- return -1;
- }
-
- std::ostringstream query;
- query << "INSERT INTO tb_users_services "
- "(fk_user, fk_service) "
- "VALUES "
- "(" << uid << ", "
- "(SELECT pk_service "
- "FROM tb_services "
- "WHERE name = '" << ename << "'))";
-
- result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
- return -1;
- }
-
- PQclear(result);
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveUserIPs(uint32_t uid,
- const STG::UserIPs & ips) const
-{
-PGresult * result;
-
- {
- std::ostringstream query;
- query << "DELETE FROM tb_allowed_ip WHERE fk_user = " << uid;
-
- result = PQexec(connection, query.str().c_str());
- }
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
- return -1;
- }
-
-PQclear(result);
-
-for (size_t i = 0; i < ips.count(); ++i)
- {
- std::ostringstream query;
- query << "INSERT INTO tb_allowed_ip "
- "(fk_user, ip) "
- "VALUES "
- "(" << uid << ", CAST('"
- << inet_ntostring(ips[i].ip) << "/"
- << static_cast<int>(ips[i].mask) << "' AS INET))";
-
- result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
- return -1;
- }
-
- PQclear(result);
- }
-
-return 0;
-}
-
-//-----------------------------------------------------------------------------
-int POSTGRESQL_STORE::SaveUserData(uint32_t uid,
- const std::vector<std::string> & data) const
-{
-for (unsigned i = 0; i < data.size(); ++i)
- {
- std::string edata = data[i];
-
- if (EscapeString(edata))
- {
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): 'Failed to escape userdata field'\n");
- return -1;
- }
-
- PGresult * result;
-
- std::ostringstream query;
- query << "SELECT sp_set_user_data("
- << uid << ", "
- << "CAST(" << i << " AS SMALLINT), "
- << "'" << edata << "')";
-
- result = PQexec(connection, query.str().c_str());
-
- if (PQresultStatus(result) != PGRES_TUPLES_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): '%s'\n", strError.c_str());
- return -1;
- }
-
- PQclear(result);
- }
-
-return 0;
-}
-
+++ /dev/null
-/*
- * 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>
- */
-
-/*
- * Vairous utility methods
- *
- * $Revision: 1.3 $
- * $Date: 2009/10/22 10:01:08 $
- *
- */
-
-#include "postgresql_store.h"
-
-#include "stg/common.h"
-
-#include <string>
-#include <ctime>
-
-#include <libpq-fe.h>
-
-extern volatile time_t stgTime;
-
-int POSTGRESQL_STORE::StartTransaction() const
-{
-PGresult * result = PQexec(connection, "BEGIN");
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::StartTransaction(): '%s'\n", strError.c_str());
- return -1;
- }
-
-PQclear(result);
-
-return 0;
-}
-
-int POSTGRESQL_STORE::CommitTransaction() const
-{
-PGresult * result = PQexec(connection, "COMMIT");
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::CommitTransaction(): '%s'\n", strError.c_str());
- return -1;
- }
-
-PQclear(result);
-
-return 0;
-}
-
-int POSTGRESQL_STORE::RollbackTransaction() const
-{
-PGresult * result = PQexec(connection, "ROLLBACK");
-
-if (PQresultStatus(result) != PGRES_COMMAND_OK)
- {
- strError = PQresultErrorMessage(result);
- PQclear(result);
- printfd(__FILE__, "POSTGRESQL_STORE::RollbackTransaction(): '%s'\n", strError.c_str());
- return -1;
- }
-
-PQclear(result);
-
-return 0;
-}
-
-int POSTGRESQL_STORE::EscapeString(std::string & value) const
-{
-int error = 0;
-char * buf = new char[(value.length() << 1) + 1];
-
-PQescapeStringConn(connection,
- buf,
- value.c_str(),
- value.length(),
- &error);
-
-if (error)
- {
- strError = PQerrorMessage(connection);
- printfd(__FILE__, "POSTGRESQL_STORE::EscapeString(): '%s'\n", strError.c_str());
- delete[] buf;
- return -1;
- }
-
-value = buf;
-
-delete[] buf;
-return 0;
-}
-
-void POSTGRESQL_STORE::MakeDate(std::string & date, int year, int month) const
-{
-struct tm brokenTime;
-
-brokenTime.tm_wday = 0;
-brokenTime.tm_yday = 0;
-brokenTime.tm_isdst = 0;
-
-if (year)
- {
- brokenTime.tm_hour = 0;
- brokenTime.tm_min = 0;
- brokenTime.tm_sec = 0;
- brokenTime.tm_year = year;
- brokenTime.tm_mon = month;
- }
-else
- {
- time_t curTime = stgTime;
- localtime_r(&curTime, &brokenTime);
- }
-
-brokenTime.tm_mday = DaysInMonth(brokenTime.tm_year + 1900, brokenTime.tm_mon);
-
-char buf[32];
-
-strftime(buf, 32, "%Y-%m-%d", &brokenTime);
-
-date = buf;
-}
+++ /dev/null
-#ifndef POSTGRESQL_UTILS_STORE_H
-#define POSTGRESQL_UTILS_STORE_H
-
-#include <functional>
-
-struct ToLower : public std::unary_function<char, char>
-{
-char operator() (char c) const { return static_cast<char>(std::tolower(c)); }
-};
-
-#endif
+++ /dev/null
-#!/bin/bash
-
-# Этот скрипт производит очистку файловой БД stargazer-а.
-# Его можно вызывать вручную или покрону, к примеру раз в неделю или раз в месяц.
-
-
-# Эта переменная задает сколько месяцев детальной статистики оставить в БД
-SAVE_MONTHS=3
-
-# Эта переменная задает сколько строк оставить в логах юзеров
-MAX_LOG_LINES=5000
-
-# Тут определяется путь к БД
-DB=/var/stargazer/
-
-
-
-
-declare -i NOW=`date +%s`
-declare -i DT=SAVE_MONTHS*31*24*3600
-declare -i stat_time=0
-
-for usr in $DB/users/*
-do
- echo cleaning `basename $usr`
- for ys in $usr/detail_stat/*
- do
- year=`basename $ys`
-
- for ms in $ys/*
- do
- month=`basename $ms`
- stat_time=`date --date="$year/$month/01" +%s`
-
- if (( $NOW - $stat_time > $DT ))
- then
- rm -fr $ms
- fi
- done
- done
- tail -n $MAX_LOG_LINES $usr/log > /tmp/stg_usr_log.`basename $usr`
- mv -f /tmp/stg_usr_log.`basename $usr` $usr/log
-done
-
+++ /dev/null
-#!/bin/bash
-
-# Данный скрипт производит мониторинг СТГ-сервера на зависание и в
-# случае его зависания перезапускает.
-# Для работы скрипта в настройках СТГ должен быть указан параметер
-# MonitorDir
-# Скрипт отрабатывает один раз и выходит. Т.е. он не работает постоянно
-# и следит за СТГ. Его нужно вызывать по крону или как-то еще с нужной
-# периодичностью!!!
-
-
-# Путь к файлам монитора. Должен совпадать со значением MonitorDir
-# в настройках сервера
-MONITOR_DIR=/var/stargazer/monitor/
-
-
-# Максимальная задержка обновления файлов монитора в секундах.
-# При привышении этого значения сервер считается зависшим и будет
-# перезапущен
-DT=300
-
-
-
-
-declare -i now=`date +%s`
-declare -i DT=300
-declare -i file_time=0
-
-stg_running=`ps ax | grep stargazer`
-if [ -z "$stg_running" ]
-then
- echo "Stargazer is not running"
- exit 0
-fi
-
-#wakeuper for traffcounter
-ping -c 1 127.0.0.1 > /dev/null
-sleep 1
-
-for mon in $MONITOR_DIR/*
-do
- if [ ! -r $mon ]
- then
- echo "no monitor files"
- exit 0
- fi
- file_time=`stat -c%Y $mon`
-
- if (( $now - $file_time > $DT ))
- then
- echo "Stargazer is deadlocked!"
-
- # Команда остаовки СТГ
- killall -KILL stargazer
-
- rm -f $MONITOR_DIR/*
- sleep 15
-
- # Команда запуска СТГ
- /etc/init.d/stargazer start
-
- fi
-
-done
-
-
+++ /dev/null
-#!/bin/bash
-
-int_iface=eth1
-
-# Login
-LOGIN=$1
-
-#user IP
-IP=$2
-
-#cash
-CASH=$3
-
-#user ID
-ID=$4
-
-#Selected dirs to connect
-DIRS=$5
-
-default_speed=32kbit
-
-# =========== shaping by tariff ===========
-#tariff=$(grep -i "^tariff=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
-#echo "tariff=$tariff" > /var/stargazer/users/$LOGIN/connect.log
-#case $tariff in
-# minimum) speedkb=128kbit;; # 128 kbit
-# middle) speedkb=256kbit;; # 256 kbi
-# maximum) speedkb=512kbit;; # 512 kbit
-# *) speedkb=$default_speed;; # default speed
-#esac
-# ========= shaping by tariff end =========
-
-# ========= shaping by userdata0 ==========
-speedR=$(grep -i "^Userdata0=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
-speed=$(echo $speedR | grep "^[0-9]*[0-9]$")
-
-if [ -z "$speed" ]
-then
- speedkb=$default_speed
-else
- speedkb="$speed"kbit
-fi
-# ======= shaping by userdata0 end ========
-
-declare -i mark=$ID+10
-
-echo "$mark" > /var/stargazer/users/$LOGIN/shaper_mark
-echo "$speedkb" > /var/stargazer/users/$LOGIN/shaper_rate
-
-iptables -t mangle -A FORWARD -d $IP -j MARK --set-mark $mark
-
-tc class add dev $int_iface parent 1:1 classid 1:$mark htb rate $speedkb burst 40k
-tc filter add dev $int_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:$mark
-
+++ /dev/null
-#!/bin/bash
-
-int_iface=eth1
-
-# Login
-LOGIN=$1
-
-#user IP
-IP=$2
-
-#cash
-CASH=$3
-
-#user ID
-ID=$4
-
-#Selected dirs to disconnect
-DIRS=$4
-
-mark=$(cat /var/stargazer/users/$LOGIN/shaper_mark)
-rate=$(cat /var/stargazer/users/$LOGIN/shaper_rate)
-
-if [ -n "$mark" ]
-then
- iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
- while [ $? == 0 ]
- do
- iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
- done
-fi
-
-tc filter del dev $int_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:$mark
-tc class del dev $int_iface parent 1:1 classid 1:$mark htb rate $rate burst 40k
-
-#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
-
-
+++ /dev/null
-Настройка шейпера для STG в Linux.
-
-По мотивам форума:
-http://local.com.ua/forum/index.php?showtopic=7920
-
-Настройка сводится к указанию сетевого интерфейса, обращенного к пользователю
-в скриптах shaper.sh, shaper.stop.sh, OnConnect и OnDisconnect, и уточнению
-скоростоей и тарифов в скрипте OnConnect (если нужно).
-
-Скрипты сделаны для БД на файлах, однако, сделать их для БД на Firebird или
-MySQL не составит большого труда.
-
-В OnConnect есть два типа шейпинга.
-1. На основании тарифа. Т.е. для каждого тарифа у задана скорость и задано
-дефолтное значение, на случай отсутсвия тарифа в списке скоростей или
-забывчивости админа.
-2. На основании Userdata0. В этом поле просто прописывается число равное
-скорости в kbit/sec. Также есть дефолтное значение скорости в 32 kbit/sec
-на случай отсутсвия в Userdata0 корректного значения.
-
-В скрипте первый способ закомментирован. Для того чтобы выбрать один из них нужно
-либо удалить, либо закомментировать строчики между
-
-# ========= shaping by tariff ==========
-.........
-# ======= shaping by tariff end ========
-
-и
-
-# ========= shaping by userdata0 ==========
-.........
-# ======= shaping by userdata0 end ========
-
-
-и нужную часть расскоментировать, если она закомментрована.
-
-Скрипт shaper.sh должен быть выполнен один раз при загрузке системы.
-
-Интерфейс обращенный к пользователю определяется в переменной
-int_iface=
-(присутствует во всех 4-х файлах shaper.sh, shaper.stop.sh, OnConnect и
-OnDisconnect !!!)
-
-Скорость по умолчанию в OnConnect в переменной default_speed
-
-Зависимость скорости от тарифа задается в следующем фрагменте кода:
-case $tariff in
- minimum) speedkb=128kbit;;
- middle) speedkb=256kbit;;
- maximum) speedkb=512kbit;;
- *) speedkb=$default_speed;;
-esac
-
-Т.е. тут нужно вместо minimum, ... maximum подставить имена ваших тарифов
-и соотв. скорость. Пользователи с тарифами не указанными в списке будут иметь
-дефолтную скорость.
-
-Скорость ограничевается только для входящего тарафика, однако расширить
-эти скрипты для исходящего не составит труда.
+++ /dev/null
-#!/bin/bash
-
-int_iface=eth1
-
-iptables -t mangle --flush
-
-tc qdisc add dev $int_iface root handle 1: htb
-tc class add dev $int_iface parent 1: classid 1:1 htb rate 100mbit ceil 100mbit burst 200k
-
+++ /dev/null
-#!/bin/bash
-
-int_iface=eth1
-
-#iptables -t mangle --flush
-
-tc qdisc del dev $int_iface root handle 1: htb
-
+++ /dev/null
-Настройка такой конфигурации происходит в 3 этапа:
-1. Настройка VPN с использованием pptpd;
-2. Настройка авторизации VPN через FreeRADIUS;
-3. Настройка шейпера;
-
-1. Настройка VPN
-
-Необходимо установить пакеты ppp и pptpd. Также необходима поддержка PPP в ядре:
- Device Drivers --->
- Network device support --->
- <M> PPP (point-to-point protocol) support
- <M> PPP support for sync tty ports
- <M> PPP Deflate compression
- <M> PPP BSD-Compress compression
- <M> PPP MPPE compression (encryption) (EXPERIMENTAL)
- <M> PPP over Ethernet (EXPERIMENTAL)
-В файле /etc/pptpd.conf прописываем файл настроек PPP (параметр option). Также
-указываем адреса сервера внутри сети VPN (параметр localip) и диапазон адресов
-клиентов (параметр remoteip). См. пример файла конфигурации.
-В настройках PPP указываем имя сервера (параметр name), параметры шифрования.
-Для использования шифрования MPPE необходима его поддержка в ядре. Кроме того,
-в процессе аутентификации MPPE использует MS-CHAPv2. По этому при
-использовании шифрования MPPE также необходимо указать необходимость
-поддержки MS-CHAPv2 клиентом. По желанию указываем proxyarp (для того чтобы
-клиенты в сети VPN "видели" друг друга) и defaultroute. Прописываем в файле
-/etc/ppp/chap-secrets тестового пользователя и проверяем работоспособность
-VPN.
-
-2. Настройка авторизации VPN через FreeRADIUS
-
-Необходимо установить пакет freeradius.
-Настройку сервера (файл radiusd.conf) проводим в соответствии с документацией
-на модуль rlm_stg.so (см. документацию на систему Stargazer).
-Настройку Stargazer с плагином для FreeRADIUS проводим в соответствиии с
-документацией на модуль mod_radius.so (см. документацию на систему Stargazer).
-В файле clients.conf, расположенном в дирректории с конфигурационными файлами
-FreeRADIUS, описываем, какие клиенты могут использовать FreeRADIUS.
-Рекомендуется заменить стандартный пароль, которым шифруется обмен информации
-с клиентом, "testing123" на что-то более приемлимое с точки зрения безопасности.
-После этого запускаем FreeRADIUS и удостоверяемся, что он работает строчкой
-"Mon Mar 31 16:06:17 2008 : Info: Ready to process requests." в журнале
-(обычно, /var/log/radius/radius.log). Если журнал FreeRADIUS не позволяет
-определить проблему - можно запустить сервер в отладочном режме с ключем -X.
-В этом режиме более детальное журналирование проводится в консоль.
-Если на данном этапе все работает - в файл насттроек PPP прописываем строчку
-plugin radius.so. После этого VPN должен нормально авторизоваться
-пользователями системы Stargazer.
-
-3. Настройка шейпера
-
-Собственно настройки шейпер не требует. Всё, что нужно прописано в скриптах
-OnConnect и OnDisconnect. Шейпер предназначен для работы с хранилищем на
-файлах, однако, переделать скипт под MySQL или Firebird не составит труда.
-Скорость для пользоватлея задается в поле Userdata0 в kbit/sec. В этом поле
-должно быть прописано просто число без всяких kbit/sec и т.п. Если в этом поле
-у пользователя нет данных или стоит некорректное значение, пользователь будет
-ограничен скоростью определенной в переменной default_speed в скрипте
-OnConnect.
+++ /dev/null
-#!/bin/bash
-
-#adsl-start
-
-modprobe ip_queue
-
-int_addr=10.0.0.2
-ext_addr=192.168.1.34
-
-int_net=10.0.0.0/16
-ext_net=192.168.1.0/24
-
-echo 1 > /proc/sys/net/ipv4/ip_forward
-
-iptables -P INPUT DROP
-iptables -P OUTPUT ACCEPT
-iptables -P FORWARD ACCEPT
-
-iptables -t nat -F
-iptables -t filter -F
-
-#
-#iptables -A INPUT -d $ip1 -j ACCEPT
-#iptables -A OUTPUT -s $ip1 -j ACCEPT
-
-# Разрешам говорить самому с собой
-iptables -A INPUT -d 127.0.0.1 -j ACCEPT
-iptables -A OUTPUT -s 127.0.0.1 -j ACCEPT
-
-#iptables -A INPUT -d $ip4 -j ACCEPT
-#iptables -A INPUT -s $ip4 -j ACCEPT
-#iptables -A OUTPUT -s $ip4 -j ACCEPT
-#iptables -A OUTPUT -d $ip4 -j ACCEPT
-
-iptables -A INPUT -p icmp -j ACCEPT
-iptables -A OUTPUT -p icmp -j ACCEPT
-
-iptables -A INPUT -p 47 -j ACCEPT
-iptables -A FORWARD -p 47 -j ACCEPT
-iptables -A OUTPUT -p 47 -j ACCEPT
-
-#SSH On this machine
-iptables -A INPUT -p tcp -d $int_addr --dport 22 -j ACCEPT
-iptables -A OUTPUT -p tcp -s $int_addr --sport 22 -j ACCEPT
-iptables -A INPUT -p tcp -d $ext_addr --dport 22 -j ACCEPT
-iptables -A OUTPUT -p tcp -s $ext_addr --sport 22 -j ACCEPT
-
-#WEB On this machine
-#iptables -A INPUT -p tcp -d $ip2 --dport 80 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip2 --sport 80 -j ACCEPT
-#iptables -A INPUT -p tcp -d $ip3 --dport 80 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip3 --sport 80 -j ACCEPT
-
-#PPTP
-iptables -A INPUT -p tcp --dport 1723 -j ACCEPT
-iptables -A OUTPUT -p tcp --sport 1723 -j ACCEPT
-iptables -A INPUT -p udp --dport 1723 -j ACCEPT
-iptables -A OUTPUT -p udp --sport 1723 -j ACCEPT
-
-#FTP
-#iptables -A INPUT -p tcp -d $ip2 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip2 -j ACCEPT
-#iptables -A INPUT -p tcp -d $ip3 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip3 -j ACCEPT
-
-#iptables -A INPUT -p tcp -d $ip2 --dport 20:21 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip2 --sport 20:21 -j ACCEPT
-#iptables -A INPUT -p tcp -d $ip3 --dport 20:21 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip3 --sport 20:21 -j ACCEPT
-
-#iptables -A INPUT -p tcp -d $ip2 --dport 1024:65535 --sport 1024:65535 -j ACCEPT
-#iptables -A INPUT -p tcp -d $ip3 --dport 1024:65535 --sport 1024:65535 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip2 --sport 1024:65535 --dport 1024:65535 -j ACCEPT
-#iptables -A OUTPUT -p tcp -s $ip3 --sport 1024:65535 --dport 1024:65535 -j ACCEPT
-
-#DNS
-iptables -A INPUT -p tcp --sport 53 -j ACCEPT
-iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
-iptables -A INPUT -p udp --sport 53 -j ACCEPT
-iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
-
-#iptables -t nat -A PREROUTING -p tcp -d $ip1 --dport 80 -j ACCEPT
-#iptables -t nat -A PREROUTING -p tcp -d $ip2 --dport 80 -j ACCEPT
-#iptables -t nat -A PREROUTING -p tcp -d $ip3 --dport 80 -j ACCEPT
-#iptables -t nat -A PREROUTING -p tcp -d $ip4 --dport 80 -j ACCEPT
-
-#iptables -t nat -A PREROUTING -p tcp -s 192.168.1.7 -j ACCEPT
-#iptables -t nat -A PREROUTING -p tcp -s 192.168.1.16 -j ACCEPT
-#iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3128
-
-iptables -t nat -A POSTROUTING -d 0.0.0.0/0 -s 192.168.2.0/24 -j MASQUERADE
-
-
-
+++ /dev/null
-#
-# clients.conf - client configuration directives
-#
-#######################################################################
-
-#######################################################################
-#
-# Definition of a RADIUS client (usually a NAS).
-#
-# The information given here over rides anything given in the
-# 'clients' file, or in the 'naslist' file. The configuration here
-# contains all of the information from those two files, and allows
-# for more configuration items.
-#
-# The "shortname" is be used for logging. The "nastype", "login" and
-# "password" fields are mainly used for checkrad and are optional.
-#
-
-#
-# Defines a RADIUS client. The format is 'client [hostname|ip-address]'
-#
-# '127.0.0.1' is another name for 'localhost'. It is enabled by default,
-# to allow testing of the server after an initial installation. If you
-# are not going to be permitting RADIUS queries from localhost, we suggest
-# that you delete, or comment out, this entry.
-#
-client 127.0.0.1 {
- #
- # The shared secret use to "encrypt" and "sign" packets between
- # the NAS and FreeRADIUS. You MUST change this secret from the
- # default, otherwise it's not a secret any more!
- #
- # The secret can be any string, up to 31 characters in length.
- #
- secret = testing123
-
- #
- # The short name is used as an alias for the fully qualified
- # domain name, or the IP address.
- #
- shortname = localhost
-
- #
- # the following three fields are optional, but may be used by
- # checkrad.pl for simultaneous use checks
- #
-
- #
- # The nastype tells 'checkrad.pl' which NAS-specific method to
- # use to query the NAS for simultaneous use.
- #
- # Permitted NAS types are:
- #
- # cisco
- # computone
- # livingston
- # max40xx
- # multitech
- # netserver
- # pathras
- # patton
- # portslave
- # tc
- # usrhiper
- # other # for all other types
-
- #
- nastype = other # localhost isn't usually a NAS...
-
- #
- # The following two configurations are for future use.
- # The 'naspasswd' file is currently used to store the NAS
- # login name and password, which is used by checkrad.pl
- # when querying the NAS for simultaneous use.
- #
-# login = !root
-# password = someadminpas
-}
+++ /dev/null
-##
-## radiusd.conf -- FreeRADIUS server configuration file.
-##
-## http://www.freeradius.org/
-## $Id: radiusd.conf,v 1.1 2008/03/31 13:54:59 faust Exp $
-##
-
-# The location of other config files and
-# logfiles are declared in this file
-#
-# Also general configuration for modules can be done
-# in this file, it is exported through the API to
-# modules that ask for it.
-#
-# The configuration variables defined here are of the form ${foo}
-# They are local to this file, and do not change from request to
-# request.
-#
-# The per-request variables are of the form %{Attribute-Name}, and
-# are taken from the values of the attribute in the incoming
-# request. See 'doc/variables.txt' for more information.
-
-prefix = /usr
-exec_prefix = /usr
-sysconfdir = /etc
-localstatedir = /var
-sbindir = ${exec_prefix}/sbin
-logdir = /var/log/freeradius
-raddbdir = /etc/freeradius
-radacctdir = ${logdir}/radacct
-
-# Location of config and logfiles.
-confdir = ${raddbdir}
-run_dir = ${localstatedir}/run/freeradius
-
-#
-# The logging messages for the server are appended to the
-# tail of this file.
-#
-log_file = ${logdir}/radius.log
-
-#
-# libdir: Where to find the rlm_* modules.
-#
-# This should be automatically set at configuration time.
-#
-# If the server builds and installs, but fails at execution time
-# with an 'undefined symbol' error, then you can use the libdir
-# directive to work around the problem.
-#
-# The cause is usually that a library has been installed on your
-# system in a place where the dynamic linker CANNOT find it. When
-# executing as root (or another user), your personal environment MAY
-# be set up to allow the dynamic linker to find the library. When
-# executing as a daemon, FreeRADIUS MAY NOT have the same
-# personalized configuration.
-#
-# To work around the problem, find out which library contains that symbol,
-# and add the directory containing that library to the end of 'libdir',
-# with a colon separating the directory names. NO spaces are allowed.
-#
-# e.g. libdir = /usr/local/lib:/opt/package/lib
-#
-# You can also try setting the LD_LIBRARY_PATH environment variable
-# in a script which starts the server.
-#
-# If that does not work, then you can re-configure and re-build the
-# server to NOT use shared libraries, via:
-#
-# ./configure --disable-shared
-# make
-# make install
-#
-libdir = /usr/lib/freeradius
-
-# pidfile: Where to place the PID of the RADIUS server.
-#
-# The server may be signalled while it's running by using this
-# file.
-#
-# This file is written when ONLY running in daemon mode.
-#
-# e.g.: kill -HUP `cat /var/run/freeradius/freeradius.pid`
-#
-pidfile = ${run_dir}/freeradius.pid
-
-
-# user/group: The name (or #number) of the user/group to run radiusd as.
-#
-# If these are commented out, the server will run as the user/group
-# that started it. In order to change to a different user/group, you
-# MUST be root ( or have root privleges ) to start the server.
-#
-# We STRONGLY recommend that you run the server with as few permissions
-# as possible. That is, if you're not using shadow passwords, the
-# user and group items below should be set to 'nobody'.
-#
-# On SCO (ODT 3) use "user = nouser" and "group = nogroup".
-#
-# NOTE that some kernels refuse to setgid(group) when the value of
-# (unsigned)group is above 60000; don't use group nobody on these systems!
-#
-# On systems with shadow passwords, you might have to set 'group = shadow'
-# for the server to be able to read the shadow password file. If you can
-# authenticate users while in debug mode, but not in daemon mode, it may be
-# that the debugging mode server is running as a user that can read the
-# shadow info, and the user listed below can not.
-#
-user = freerad
-group = freerad
-
-# max_request_time: The maximum time (in seconds) to handle a request.
-#
-# Requests which take more time than this to process may be killed, and
-# a REJECT message is returned.
-#
-# WARNING: If you notice that requests take a long time to be handled,
-# then this MAY INDICATE a bug in the server, in one of the modules
-# used to handle a request, OR in your local configuration.
-#
-# This problem is most often seen when using an SQL database. If it takes
-# more than a second or two to receive an answer from the SQL database,
-# then it probably means that you haven't indexed the database. See your
-# SQL server documentation for more information.
-#
-# Useful range of values: 5 to 120
-#
-max_request_time = 30
-
-# delete_blocked_requests: If the request takes MORE THAN 'max_request_time'
-# to be handled, then maybe the server should delete it.
-#
-# If you're running in threaded, or thread pool mode, this setting
-# should probably be 'no'. Setting it to 'yes' when using a threaded
-# server MAY cause the server to crash!
-#
-delete_blocked_requests = no
-
-# cleanup_delay: The time to wait (in seconds) before cleaning up
-# a reply which was sent to the NAS.
-#
-# The RADIUS request is normally cached internally for a short period
-# of time, after the reply is sent to the NAS. The reply packet may be
-# lost in the network, and the NAS will not see it. The NAS will then
-# re-send the request, and the server will respond quickly with the
-# cached reply.
-#
-# If this value is set too low, then duplicate requests from the NAS
-# MAY NOT be detected, and will instead be handled as seperate requests.
-#
-# If this value is set too high, then the server will cache too many
-# requests, and some new requests may get blocked. (See 'max_requests'.)
-#
-# Useful range of values: 2 to 10
-#
-cleanup_delay = 5
-
-# max_requests: The maximum number of requests which the server keeps
-# track of. This should be 256 multiplied by the number of clients.
-# e.g. With 4 clients, this number should be 1024.
-#
-# If this number is too low, then when the server becomes busy,
-# it will not respond to any new requests, until the 'cleanup_delay'
-# time has passed, and it has removed the old requests.
-#
-# If this number is set too high, then the server will use a bit more
-# memory for no real benefit.
-#
-# If you aren't sure what it should be set to, it's better to set it
-# too high than too low. Setting it to 1000 per client is probably
-# the highest it should be.
-#
-# Useful range of values: 256 to infinity
-#
-max_requests = 1024
-
-# bind_address: Make the server listen on a particular IP address, and
-# send replies out from that address. This directive is most useful
-# for machines with multiple IP addresses on one interface.
-#
-# It can either contain "*", or an IP address, or a fully qualified
-# Internet domain name. The default is "*"
-#
-# As of 1.0, you can also use the "listen" directive. See below for
-# more information.
-#
-bind_address = *
-
-# port: Allows you to bind FreeRADIUS to a specific port.
-#
-# The default port that most NAS boxes use is 1645, which is historical.
-# RFC 2138 defines 1812 to be the new port. Many new servers and
-# NAS boxes use 1812, which can create interoperability problems.
-#
-# The port is defined here to be 0 so that the server will pick up
-# the machine's local configuration for the radius port, as defined
-# in /etc/services.
-#
-# If you want to use the default RADIUS port as defined on your server,
-# (usually through 'grep radius /etc/services') set this to 0 (zero).
-#
-# A port given on the command-line via '-p' over-rides this one.
-#
-# As of 1.0, you can also use the "listen" directive. See below for
-# more information.
-#
-port = 0
-
-#
-# By default, the server uses "bind_address" to listen to all IP's
-# on a machine, or just one IP. The "port" configuration is used
-# to select the authentication port used when listening on those
-# addresses.
-#
-# If you want the server to listen on additional addresses, you can
-# use the "listen" section. A sample section (commented out) is included
-# below. This "listen" section duplicates the functionality of the
-# "bind_address" and "port" configuration entries, but it only listens
-# for authentication packets.
-#
-# If you comment out the "bind_address" and "port" configuration entries,
-# then it becomes possible to make the server accept only accounting,
-# or authentication packets. Previously, it always listened for both
-# types of packets, and it was impossible to make it listen for only
-# one type of packet.
-#
-#listen {
- # IP address on which to listen.
- # Allowed values are:
- # dotted quad (1.2.3.4)
- # hostname (radius.example.com)
- # wildcard (*)
-# ipaddr = *
-
- # Port on which to listen.
- # Allowed values are:
- # integer port number (1812)
- # 0 means "use /etc/services for the proper port"
-# port = 0
-
- # Type of packets to listen for.
- # Allowed values are:
- # auth listen for authentication packets
- # acct listen for accounting packets
- #
-# type = auth
-#}
-
-
-# hostname_lookups: Log the names of clients or just their IP addresses
-# e.g., www.freeradius.org (on) or 206.47.27.232 (off).
-#
-# The default is 'off' because it would be overall better for the net
-# if people had to knowingly turn this feature on, since enabling it
-# means that each client request will result in AT LEAST one lookup
-# request to the nameserver. Enabling hostname_lookups will also
-# mean that your server may stop randomly for 30 seconds from time
-# to time, if the DNS requests take too long.
-#
-# Turning hostname lookups off also means that the server won't block
-# for 30 seconds, if it sees an IP address which has no name associated
-# with it.
-#
-# allowed values: {no, yes}
-#
-hostname_lookups = no
-
-# Core dumps are a bad thing. This should only be set to 'yes'
-# if you're debugging a problem with the server.
-#
-# allowed values: {no, yes}
-#
-allow_core_dumps = no
-
-# Regular expressions
-#
-# These items are set at configure time. If they're set to "yes",
-# then setting them to "no" turns off regular expression support.
-#
-# If they're set to "no" at configure time, then setting them to "yes"
-# WILL NOT WORK. It will give you an error.
-#
-regular_expressions = yes
-extended_expressions = yes
-
-# Log the full User-Name attribute, as it was found in the request.
-#
-# allowed values: {no, yes}
-#
-log_stripped_names = no
-
-# Log authentication requests to the log file.
-#
-# allowed values: {no, yes}
-#
-log_auth = no
-
-# Log passwords with the authentication requests.
-# log_auth_badpass - logs password if it's rejected
-# log_auth_goodpass - logs password if it's correct
-#
-# allowed values: {no, yes}
-#
-log_auth_badpass = no
-log_auth_goodpass = no
-
-# usercollide: Turn "username collision" code on and off. See the
-# "doc/duplicate-users" file
-#
-# WARNING
-# !!!!!!! Setting this to "yes" may result in the server behaving
-# !!!!!!! strangely. The "username collision" code will ONLY work
-# !!!!!!! with clear-text passwords. Even then, it may not do what
-# !!!!!!! you want, or what you expect.
-# !!!!!!!
-# !!!!!!! We STRONGLY RECOMMEND that you do not use this feature,
-# !!!!!!! and that you find another way of acheiving the same goal.
-# !!!!!!!
-# !!!!!!! e,g. module fail-over. See 'doc/configurable_failover'
-# WARNING
-#
-usercollide = no
-
-# lower_user / lower_pass:
-# Lower case the username/password "before" or "after"
-# attempting to authenticate.
-#
-# If "before", the server will first modify the request and then try
-# to auth the user. If "after", the server will first auth using the
-# values provided by the user. If that fails it will reprocess the
-# request after modifying it as you specify below.
-#
-# This is as close as we can get to case insensitivity. It is the
-# admin's job to ensure that the username on the auth db side is
-# *also* lowercase to make this work
-#
-# Default is 'no' (don't lowercase values)
-# Valid values = "before" / "after" / "no"
-#
-lower_user = no
-lower_pass = no
-
-# nospace_user / nospace_pass:
-#
-# Some users like to enter spaces in their username or password
-# incorrectly. To save yourself the tech support call, you can
-# eliminate those spaces here:
-#
-# Default is 'no' (don't remove spaces)
-# Valid values = "before" / "after" / "no" (explanation above)
-#
-nospace_user = no
-nospace_pass = no
-
-# The program to execute to do concurrency checks.
-checkrad = ${sbindir}/checkrad
-
-# SECURITY CONFIGURATION
-#
-# There may be multiple methods of attacking on the server. This
-# section holds the configuration items which minimize the impact
-# of those attacks
-#
-security {
- #
- # max_attributes: The maximum number of attributes
- # permitted in a RADIUS packet. Packets which have MORE
- # than this number of attributes in them will be dropped.
- #
- # If this number is set too low, then no RADIUS packets
- # will be accepted.
- #
- # If this number is set too high, then an attacker may be
- # able to send a small number of packets which will cause
- # the server to use all available memory on the machine.
- #
- # Setting this number to 0 means "allow any number of attributes"
- max_attributes = 200
-
- #
- # reject_delay: When sending an Access-Reject, it can be
- # delayed for a few seconds. This may help slow down a DoS
- # attack. It also helps to slow down people trying to brute-force
- # crack a users password.
- #
- # Setting this number to 0 means "send rejects immediately"
- #
- # If this number is set higher than 'cleanup_delay', then the
- # rejects will be sent at 'cleanup_delay' time, when the request
- # is deleted from the internal cache of requests.
- #
- # Useful ranges: 1 to 5
- reject_delay = 1
-
- #
- # status_server: Whether or not the server will respond
- # to Status-Server requests.
- #
- # Normally this should be set to "no", because they're useless.
- # See: http://www.freeradius.org/rfc/rfc2865.html#Keep-Alives
- #
- # However, certain NAS boxes may require them.
- #
- # When sent a Status-Server message, the server responds with
- # an Access-Accept packet, containing a Reply-Message attribute,
- # which is a string describing how long the server has been
- # running.
- #
- status_server = no
-}
-
-# PROXY CONFIGURATION
-#
-# proxy_requests: Turns proxying of RADIUS requests on or off.
-#
-# The server has proxying turned on by default. If your system is NOT
-# set up to proxy requests to another server, then you can turn proxying
-# off here. This will save a small amount of resources on the server.
-#
-# If you have proxying turned off, and your configuration files say
-# to proxy a request, then an error message will be logged.
-#
-# To disable proxying, change the "yes" to "no", and comment the
-# $INCLUDE line.
-#
-# allowed values: {no, yes}
-#
-proxy_requests = yes
-$INCLUDE ${confdir}/proxy.conf
-
-
-# CLIENTS CONFIGURATION
-#
-# Client configuration is defined in "clients.conf".
-#
-
-# The 'clients.conf' file contains all of the information from the old
-# 'clients' and 'naslist' configuration files. We recommend that you
-# do NOT use 'client's or 'naslist', although they are still
-# supported.
-#
-# Anything listed in 'clients.conf' will take precedence over the
-# information from the old-style configuration files.
-#
-$INCLUDE ${confdir}/clients.conf
-
-
-# SNMP CONFIGURATION
-#
-# Snmp configuration is only valid if SNMP support was enabled
-# at compile time.
-#
-# To enable SNMP querying of the server, set the value of the
-# 'snmp' attribute to 'yes'
-#
-snmp = no
-$INCLUDE ${confdir}/snmp.conf
-
-
-# THREAD POOL CONFIGURATION
-#
-# The thread pool is a long-lived group of threads which
-# take turns (round-robin) handling any incoming requests.
-#
-# You probably want to have a few spare threads around,
-# so that high-load situations can be handled immediately. If you
-# don't have any spare threads, then the request handling will
-# be delayed while a new thread is created, and added to the pool.
-#
-# You probably don't want too many spare threads around,
-# otherwise they'll be sitting there taking up resources, and
-# not doing anything productive.
-#
-# The numbers given below should be adequate for most situations.
-#
-thread pool {
- # Number of servers to start initially --- should be a reasonable
- # ballpark figure.
- start_servers = 5
-
- # Limit on the total number of servers running.
- #
- # If this limit is ever reached, clients will be LOCKED OUT, so it
- # should NOT BE SET TOO LOW. It is intended mainly as a brake to
- # keep a runaway server from taking the system with it as it spirals
- # down...
- #
- # You may find that the server is regularly reaching the
- # 'max_servers' number of threads, and that increasing
- # 'max_servers' doesn't seem to make much difference.
- #
- # If this is the case, then the problem is MOST LIKELY that
- # your back-end databases are taking too long to respond, and
- # are preventing the server from responding in a timely manner.
- #
- # The solution is NOT do keep increasing the 'max_servers'
- # value, but instead to fix the underlying cause of the
- # problem: slow database, or 'hostname_lookups=yes'.
- #
- # For more information, see 'max_request_time', above.
- #
- max_servers = 32
-
- # Server-pool size regulation. Rather than making you guess
- # how many servers you need, FreeRADIUS dynamically adapts to
- # the load it sees, that is, it tries to maintain enough
- # servers to handle the current load, plus a few spare
- # servers to handle transient load spikes.
- #
- # It does this by periodically checking how many servers are
- # waiting for a request. If there are fewer than
- # min_spare_servers, it creates a new spare. If there are
- # more than max_spare_servers, some of the spares die off.
- # The default values are probably OK for most sites.
- #
- min_spare_servers = 3
- max_spare_servers = 10
-
- # There may be memory leaks or resource allocation problems with
- # the server. If so, set this value to 300 or so, so that the
- # resources will be cleaned up periodically.
- #
- # This should only be necessary if there are serious bugs in the
- # server which have not yet been fixed.
- #
- # '0' is a special value meaning 'infinity', or 'the servers never
- # exit'
- max_requests_per_server = 0
-}
-
-# MODULE CONFIGURATION
-#
-# The names and configuration of each module is located in this section.
-#
-# After the modules are defined here, they may be referred to by name,
-# in other sections of this configuration file.
-#
-modules {
- #
- # Each module has a configuration as follows:
- #
- # name [ instance ] {
- # config_item = value
- # ...
- # }
- #
- # The 'name' is used to load the 'rlm_name' library
- # which implements the functionality of the module.
- #
- # The 'instance' is optional. To have two different instances
- # of a module, it first must be referred to by 'name'.
- # The different copies of the module are then created by
- # inventing two 'instance' names, e.g. 'instance1' and 'instance2'
- #
- # The instance names can then be used in later configuration
- # INSTEAD of the original 'name'. See the 'radutmp' configuration
- # below for an example.
- #
-
- # PAP module to authenticate users based on their stored password
- #
- # Supports multiple encryption schemes
- # clear: Clear text
- # crypt: Unix crypt
- # md5: MD5 ecnryption
- # sha1: SHA1 encryption.
- # DEFAULT: crypt
- pap {
- encryption_scheme = crypt
- }
-
- # CHAP module
- #
- # To authenticate requests containing a CHAP-Password attribute.
- #
- chap {
- authtype = CHAP
- }
-
- # Extensible Authentication Protocol
- #
- # For all EAP related authentications.
- # Now in another file, because it is very large.
- #
-$INCLUDE ${confdir}/eap.conf
-
- # Microsoft CHAP authentication
- #
- # This module supports MS-CHAP and MS-CHAPv2 authentication.
- # It also enforces the SMB-Account-Ctrl attribute.
- #
- mschap {
- #
- # As of 0.9, the mschap module does NOT support
- # reading from /etc/smbpasswd.
- #
- # If you are using /etc/smbpasswd, see the 'passwd'
- # module for an example of how to use /etc/smbpasswd
-
- # if use_mppe is not set to no mschap will
- # add MS-CHAP-MPPE-Keys for MS-CHAPv1 and
- # MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2
- #
- use_mppe = yes
- authtype = MS-CHAP
-
- # if mppe is enabled require_encryption makes
- # encryption moderate
- #
- #require_encryption = yes
-
- # require_strong always requires 128 bit key
- # encryption
- #
- #require_strong = yes
-
- # Windows sends us a username in the form of
- # DOMAIN\user, but sends the challenge response
- # based on only the user portion. This hack
- # corrects for that incorrect behavior.
- #
- #with_ntdomain_hack = no
-
- # The module can perform authentication itself, OR
- # use a Windows Domain Controller. This configuration
- # directive tells the module to call the ntlm_auth
- # program, which will do the authentication, and return
- # the NT-Key. Note that you MUST have "winbindd" and
- # "nmbd" running on the local machine for ntlm_auth
- # to work. See the ntlm_auth program documentation
- # for details.
- #
- # Be VERY careful when editing the following line!
- #
- #ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{Stripped-User-Name:-%{User-Name:-None}} --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00}"
- }
-
- # Preprocess the incoming RADIUS request, before handing it off
- # to other modules.
- #
- # This module processes the 'huntgroups' and 'hints' files.
- # In addition, it re-writes some weird attributes created
- # by some NASes, and converts the attributes into a form which
- # is a little more standard.
- #
- preprocess {
- huntgroups = ${confdir}/huntgroups
- hints = ${confdir}/hints
-
- # This hack changes Ascend's wierd port numberings
- # to standard 0-??? port numbers so that the "+" works
- # for IP address assignments.
- with_ascend_hack = no
- ascend_channels_per_line = 23
-
- # Windows NT machines often authenticate themselves as
- # NT_DOMAIN\username
- #
- # If this is set to 'yes', then the NT_DOMAIN portion
- # of the user-name is silently discarded.
- #
- # This configuration entry SHOULD NOT be used.
- # See the "realms" module for a better way to handle
- # NT domains.
- with_ntdomain_hack = no
-
- # Specialix Jetstream 8500 24 port access server.
- #
- # If the user name is 10 characters or longer, a "/"
- # and the excess characters after the 10th are
- # appended to the user name.
- #
- # If you're not running that NAS, you don't need
- # this hack.
- with_specialix_jetstream_hack = no
-
- # Cisco (and Quintum in Cisco mode) sends it's VSA attributes
- # with the attribute name *again* in the string, like:
- #
- # H323-Attribute = "h323-attribute=value".
- #
- # If this configuration item is set to 'yes', then
- # the redundant data in the the attribute text is stripped
- # out. The result is:
- #
- # H323-Attribute = "value"
- #
- # If you're not running a Cisco or Quintum NAS, you don't
- # need this hack.
- with_cisco_vsa_hack = no
- }
-
- # Write a detailed log of all accounting records received.
- #
- detail {
- # Note that we do NOT use NAS-IP-Address here, as
- # that attribute MAY BE from the originating NAS, and
- # NOT from the proxy which actually sent us the
- # request. The Client-IP-Address attribute is ALWAYS
- # the address of the client which sent us the
- # request.
- #
- # The following line creates a new detail file for
- # every radius client (by IP address or hostname).
- # In addition, a new detail file is created every
- # day, so that the detail file doesn't have to go
- # through a 'log rotation'
- #
- # If your detail files are large, you may also want
- # to add a ':%H' (see doc/variables.txt) to the end
- # of it, to create a new detail file every hour, e.g.:
- #
- # ..../detail-%Y%m%d:%H
- #
- # This will create a new detail file for every hour.
- #
- detailfile = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
-
- #
- # The Unix-style permissions on the 'detail' file.
- #
- # The detail file often contains secret or private
- # information about users. So by keeping the file
- # permissions restrictive, we can prevent unwanted
- # people from seeing that information.
- detailperm = 0600
-
- #
- # Certain attributes such as User-Password may be
- # "sensitive", so they should not be printed in the
- # detail file. This section lists the attributes
- # that should be suppressed.
- #
- # The attributes should be listed one to a line.
- #
- #suppress {
- # User-Password
- #}
- }
-
- #
- # Create a unique accounting session Id. Many NASes re-use
- # or repeat values for Acct-Session-Id, causing no end of
- # confusion.
- #
- # This module will add a (probably) unique session id
- # to an accounting packet based on the attributes listed
- # below found in the packet. See doc/rlm_acct_unique for
- # more information.
- #
- acct_unique {
- key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port"
- }
-
- # Write a 'utmp' style file, of which users are currently
- # logged in, and where they've logged in from.
- #
- # This file is used mainly for Simultaneous-Use checking,
- # and also 'radwho', to see who's currently logged in.
- #
- radutmp {
- # Where the file is stored. It's not a log file,
- # so it doesn't need rotating.
- #
- filename = ${logdir}/radutmp
-
- # The field in the packet to key on for the
- # 'user' name, If you have other fields which you want
- # to use to key on to control Simultaneous-Use,
- # then you can use them here.
- #
- # Note, however, that the size of the field in the
- # 'utmp' data structure is small, around 32
- # characters, so that will limit the possible choices
- # of keys.
- #
- # You may want instead: %{Stripped-User-Name:-%{User-Name}}
- username = %{User-Name}
-
-
- # Whether or not we want to treat "user" the same
- # as "USER", or "User". Some systems have problems
- # with case sensitivity, so this should be set to
- # 'no' to enable the comparisons of the key attribute
- # to be case insensitive.
- #
- case_sensitive = yes
-
- # Accounting information may be lost, so the user MAY
- # have logged off of the NAS, but we haven't noticed.
- # If so, we can verify this information with the NAS,
- #
- # If we want to believe the 'utmp' file, then this
- # configuration entry can be set to 'no'.
- #
- check_with_nas = yes
-
- # Set the file permissions, as the contents of this file
- # are usually private.
- perm = 0600
-
- callerid = "yes"
- }
-
- # "Safe" radutmp - does not contain caller ID, so it can be
- # world-readable, and radwho can work for normal users, without
- # exposing any information that isn't already exposed by who(1).
- #
- # This is another 'instance' of the radutmp module, but it is given
- # then name "sradutmp" to identify it later in the "accounting"
- # section.
- radutmp sradutmp {
- filename = ${logdir}/sradutmp
- perm = 0644
- callerid = "no"
- }
-
- # attr_filter - filters the attributes received in replies from
- # proxied servers, to make sure we send back to our RADIUS client
- # only allowed attributes.
- attr_filter {
- attrsfile = ${confdir}/attrs
- }
-
- # counter module:
- # This module takes an attribute (count-attribute).
- # It also takes a key, and creates a counter for each unique
- # key. The count is incremented when accounting packets are
- # received by the server. The value of the increment depends
- # on the attribute type.
- # If the attribute is Acct-Session-Time or of an integer type we add the
- # value of the attribute. If it is anything else we increase the
- # counter by one.
- #
- # The 'reset' parameter defines when the counters are all reset to
- # zero. It can be hourly, daily, weekly, monthly or never.
- #
- # hourly: Reset on 00:00 of every hour
- # daily: Reset on 00:00:00 every day
- # weekly: Reset on 00:00:00 on sunday
- # monthly: Reset on 00:00:00 of the first day of each month
- #
- # It can also be user defined. It should be of the form:
- # num[hdwm] where:
- # h: hours, d: days, w: weeks, m: months
- # If the letter is ommited days will be assumed. In example:
- # reset = 10h (reset every 10 hours)
- # reset = 12 (reset every 12 days)
- #
- #
- # The check-name attribute defines an attribute which will be
- # registered by the counter module and can be used to set the
- # maximum allowed value for the counter after which the user
- # is rejected.
- # Something like:
- #
- # DEFAULT Max-Daily-Session := 36000
- # Fall-Through = 1
- #
- # You should add the counter module in the instantiate
- # section so that it registers check-name before the files
- # module reads the users file.
- #
- # If check-name is set and the user is to be rejected then we
- # send back a Reply-Message and we log a Failure-Message in
- # the radius.log
- # If the count attribute is Acct-Session-Time then on each login
- # we send back the remaining online time as a Session-Timeout attribute
- #
- # The counter-name can also be used instead of using the check-name
- # like below:
- #
- # DEFAULT Daily-Session-Time > 3600, Auth-Type = Reject
- # Reply-Message = "You've used up more than one hour today"
- #
- # The allowed-servicetype attribute can be used to only take
- # into account specific sessions. For example if a user first
- # logs in through a login menu and then selects ppp there will
- # be two sessions. One for Login-User and one for Framed-User
- # service type. We only need to take into account the second one.
- #
- # The module should be added in the instantiate, authorize and
- # accounting sections. Make sure that in the authorize
- # section it comes after any module which sets the
- # 'check-name' attribute.
- #
- counter daily {
- filename = ${raddbdir}/db.daily
- key = User-Name
- count-attribute = Acct-Session-Time
- reset = daily
- counter-name = Daily-Session-Time
- check-name = Max-Daily-Session
- allowed-servicetype = Framed-User
- cache-size = 5000
- }
-
- #
- # The "always" module is here for debugging purposes. Each
- # instance simply returns the same result, always, without
- # doing anything.
- always fail {
- rcode = fail
- }
- always reject {
- rcode = reject
- }
- always ok {
- rcode = ok
- simulcount = 0
- mpp = no
- }
-
- stg {
- local_port = 6667
- server = localhost
- port = 6666
- password = 123456
- }
-
-}
-
-# Instantiation
-#
-# This section orders the loading of the modules. Modules
-# listed here will get loaded BEFORE the later sections like
-# authorize, authenticate, etc. get examined.
-#
-# This section is not strictly needed. When a section like
-# authorize refers to a module, it's automatically loaded and
-# initialized. However, some modules may not be listed in any
-# of the following sections, so they can be listed here.
-#
-# Also, listing modules here ensures that you have control over
-# the order in which they are initalized. If one module needs
-# something defined by another module, you can list them in order
-# here, and ensure that the configuration will be OK.
-#
-instantiate {
- stg
-}
-
-# Authorization. First preprocess (hints and huntgroups files),
-# then realms, and finally look in the "users" file.
-#
-# The order of the realm modules will determine the order that
-# we try to find a matching realm.
-#
-# Make *sure* that 'preprocess' comes before any realm if you
-# need to setup hints for the remote radius server
-authorize {
- #
- # The preprocess module takes care of sanitizing some bizarre
- # attributes in the request, and turning them into attributes
- # which are more standard.
- #
- # It takes care of processing the 'raddb/hints' and the
- # 'raddb/huntgroups' files.
- #
- # It also adds the %{Client-IP-Address} attribute to the request.
- preprocess
-
- #
- # The chap module will set 'Auth-Type := CHAP' if we are
- # handling a CHAP request and Auth-Type has not already been set
- chap
-
- #
- # If the users are logging in with an MS-CHAP-Challenge
- # attribute for authentication, the mschap module will find
- # the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP'
- # to the request, which will cause the server to then use
- # the mschap module for authentication.
- mschap
-
- #
- # This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP
- # authentication.
- #
- # It also sets the EAP-Type attribute in the request
- # attribute list to the EAP type from the packet.
- eap
-
- stg
-}
-
-
-# Authentication.
-#
-#
-# This section lists which modules are available for authentication.
-# Note that it does NOT mean 'try each module in order'. It means
-# that a module from the 'authorize' section adds a configuration
-# attribute 'Auth-Type := FOO'. That authentication type is then
-# used to pick the apropriate module from the list below.
-#
-
-# In general, you SHOULD NOT set the Auth-Type attribute. The server
-# will figure it out on its own, and will do the right thing. The
-# most common side effect of erroneously setting the Auth-Type
-# attribute is that one authentication method will work, but the
-# others will not.
-#
-# The common reasons to set the Auth-Type attribute by hand
-# is to either forcibly reject the user, or forcibly accept him.
-#
-authenticate {
- #
- # PAP authentication, when a back-end database listed
- # in the 'authorize' section supplies a password. The
- # password can be clear-text, or encrypted.
- Auth-Type PAP {
- stg
- pap
- }
-
- #
- # Most people want CHAP authentication
- # A back-end database listed in the 'authorize' section
- # MUST supply a CLEAR TEXT password. Encrypted passwords
- # won't work.
- Auth-Type CHAP {
- stg
- chap
- }
-
- #
- # MSCHAP authentication.
- Auth-Type MS-CHAP {
- stg
- mschap
- }
-
- #
- # Allow EAP authentication.
- eap
-}
-
-
-#
-# Pre-accounting. Decide which accounting type to use.
-#
-preacct {
- preprocess
-
- #
- # Ensure that we have a semi-unique identifier for every
- # request, and many NAS boxes are broken.
- acct_unique
-}
-
-#
-# Accounting. Log the accounting data.
-#
-accounting {
- #
- # Create a 'detail'ed log of the packets.
- # Note that accounting requests which are proxied
- # are also logged in the detail file.
- detail
-# daily
-
- #
- # For Simultaneous-Use tracking.
- #
- # Due to packet losses in the network, the data here
- # may be incorrect. There is little we can do about it.
- radutmp
-
- stg
-
-}
-
-
-# Session database, used for checking Simultaneous-Use. Either the radutmp
-# or rlm_sql module can handle this.
-# The rlm_sql module is *much* faster
-session {
- radutmp
-}
-
-
-# Post-Authentication
-# Once we KNOW that the user has been authenticated, there are
-# additional steps we can take.
-post-auth {
- stg
-}
-
-#
-# When the server decides to proxy a request to a home server,
-# the proxied request is first passed through the pre-proxy
-# stage. This stage can re-write the request, or decide to
-# cancel the proxy.
-#
-# Only a few modules currently have this method.
-#
-pre-proxy {
-}
-
-#
-# When the server receives a reply to a request it proxied
-# to a home server, the request may be massaged here, in the
-# post-proxy stage.
-#
-post-proxy {
- #
- # If you are proxying LEAP, you MUST configure the EAP
- # module, and you MUST list it here, in the post-proxy
- # stage.
- #
- # You MUST also use the 'nostrip' option in the 'realm'
- # configuration. Otherwise, the User-Name attribute
- # in the proxied request will not match the user name
- # hidden inside of the EAP packet, and the end server will
- # reject the EAP request.
- #
- eap
-}
+++ /dev/null
-#!/bin/sh
-
-rm -f /var/stargazer/ifaces/$PPP_REMOTE
\ No newline at end of file
+++ /dev/null
-#!/bin/sh
-
-echo $PPP_IFACE > /var/stargazer/ifaces/$PPP_REMOTE
\ No newline at end of file
+++ /dev/null
-###############################################################################
-# $Id: pptpd-options,v 1.1 2008/03/31 13:55:20 faust Exp $
-#
-# Sample Poptop PPP options file /etc/ppp/pptpd-options
-# Options used by PPP when a connection arrives from a client.
-# This file is pointed to by /etc/pptpd.conf option keyword.
-# Changes are effective on the next connection. See "man pppd".
-#
-# You are expected to change this file to suit your system. As
-# packaged, it requires PPP 2.4.2 and the kernel MPPE module.
-###############################################################################
-
-
-# Authentication
-
-# Name of the local system for authentication purposes
-# (must match the second field in /etc/ppp/chap-secrets entries)
-name pptpd
-
-# Optional: domain name to use for authentication
-# domain mydomain.net
-
-# Strip the domain prefix from the username before authentication.
-# (applies if you use pppd with chapms-strip-domain patch)
-#chapms-strip-domain
-
-
-# Encryption
-# Debian: on systems with a kernel built with the package
-# kernel-patch-mppe >= 2.4.2 and using ppp >= 2.4.2, ...
-# {{{
-refuse-pap
-refuse-chap
-refuse-mschap
-# Require the peer to authenticate itself using MS-CHAPv2 [Microsoft
-# Challenge Handshake Authentication Protocol, Version 2] authentication.
-require-mschap-v2
-# Require MPPE 128-bit encryption
-# (note that MPPE requires the use of MSCHAP-V2 during authentication)
-require-mppe-128
-# }}}
-
-
-
-
-# Network and Routing
-
-# If pppd is acting as a server for Microsoft Windows clients, this
-# option allows pppd to supply one or two DNS (Domain Name Server)
-# addresses to the clients. The first instance of this option
-# specifies the primary DNS address; the second instance (if given)
-# specifies the secondary DNS address.
-# Attention! This information may not be taken into account by a Windows
-# client. See KB311218 in Microsoft's knowledge base for more information.
-#ms-dns 10.0.0.1
-#ms-dns 10.0.0.2
-
-# If pppd is acting as a server for Microsoft Windows or "Samba"
-# clients, this option allows pppd to supply one or two WINS (Windows
-# Internet Name Services) server addresses to the clients. The first
-# instance of this option specifies the primary WINS address; the
-# second instance (if given) specifies the secondary WINS address.
-#ms-wins 10.0.0.3
-#ms-wins 10.0.0.4
-
-# Add an entry to this system's ARP [Address Resolution Protocol]
-# table with the IP address of the peer and the Ethernet address of this
-# system. This will have the effect of making the peer appear to other
-# systems to be on the local ethernet.
-# (you do not need this if your PPTP server is responsible for routing
-# packets to the clients -- James Cameron)
-proxyarp
-
-# Debian: do not replace the default route
-defaultroute
-
-
-# Logging
-
-# Enable connection debugging facilities.
-# (see your syslog configuration for where pppd sends to)
-#debug
-
-# Print out all the option values which have been set.
-# (often requested by mailing list to verify options)
-#dump
-
-
-# Miscellaneous
-
-# Create a UUCP-style lock file for the pseudo-tty to ensure exclusive
-# access.
-lock
-
-# Disable BSD-Compress compression
-nobsdcomp
-plugin radius.so
\ No newline at end of file
+++ /dev/null
-###############################################################################
-# $Id: pptpd.conf,v 1.1 2008/03/31 13:54:13 faust Exp $
-#
-# Sample Poptop configuration file /etc/pptpd.conf
-#
-# Changes are effective when pptpd is restarted.
-###############################################################################
-
-# TAG: ppp
-# Path to the pppd program, default '/usr/sbin/pppd' on Linux
-#
-#ppp /usr/sbin/pppd
-
-# TAG: option
-# Specifies the location of the PPP options file.
-# By default PPP looks in '/etc/ppp/options'
-#
-option /etc/ppp/pptpd-options
-
-# TAG: debug
-# Turns on (more) debugging to syslog
-#
-#debug
-
-# TAG: stimeout
-# Specifies timeout (in seconds) on starting ctrl connection
-#
-# stimeout 10
-
-# TAG: noipparam
-# Suppress the passing of the client's IP address to PPP, which is
-# done by default otherwise.
-#
-#noipparam
-
-# TAG: logwtmp
-# Use wtmp(5) to record client connections and disconnections.
-#
-logwtmp
-
-# TAG: bcrelay <if>
-# Turns on broadcast relay to clients from interface <if>
-#
-#bcrelay eth1
-
-# TAG: localip
-# TAG: remoteip
-# Specifies the local and remote IP address ranges.
-#
-# Any addresses work as long as the local machine takes care of the
-# routing. But if you want to use MS-Windows networking, you should
-# use IP addresses out of the LAN address space and use the proxyarp
-# option in the pppd options file, or run bcrelay.
-#
-# You can specify single IP addresses seperated by commas or you can
-# specify ranges, or both. For example:
-#
-# 192.168.0.234,192.168.0.245-249,192.168.0.254
-#
-# IMPORTANT RESTRICTIONS:
-#
-# 1. No spaces are permitted between commas or within addresses.
-#
-# 2. If you give more IP addresses than MAX_CONNECTIONS, it will
-# start at the beginning of the list and go until it gets
-# MAX_CONNECTIONS IPs. Others will be ignored.
-#
-# 3. No shortcuts in ranges! ie. 234-8 does not mean 234 to 238,
-# you must type 234-238 if you mean this.
-#
-# 4. If you give a single localIP, that's ok - all local IPs will
-# be set to the given one. You MUST still give at least one remote
-# IP for each simultaneous client.
-#
-# (Recommended)
-#localip 192.168.0.1
-#remoteip 192.168.0.234-238,192.168.0.245
-# or
-#localip 192.168.0.234-238,192.168.0.245
-#remoteip 192.168.1.234-238,192.168.1.245
-localip 192.168.2.1
-remoteip 192.168.2.2-254
+++ /dev/null
-localhost testing123
+++ /dev/null
-#! /bin/sh
-
-login=$1
-param=$2
-oldValue=$3
-newValue=$4
-
-#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
+++ /dev/null
-#!/bin/bash
-
-#Этот скрипт вызывается в момент, когда пользователь
-#успешно прошел авторизацию на сервере. Задача скрипта - перестроить
-#файрвол так, что бы пользователь получил доступ в интернет
-
-# Login
-LOGIN=$1
-
-#user IP
-IP=$2
-
-#cash
-CASH=$3
-
-#user ID
-ID=$4
-
-#Selected dirs to connect
-DIRS=$5
-
-iptables -A INPUT -s $IP -j QUEUE
-iptables -A OUTPUT -d $IP -j QUEUE
-iptables -A FORWARD -s $IP -j QUEUE
-iptables -A FORWARD -d $IP -j QUEUE
-
-# shaper
-
-default_speed=32
-
-speedR=$(grep -i "^Userdata0=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
-#echo "speedR=$speedR" >> /var/stargazer/users/$LOGIN/connect.log
-speed=$(echo $speedR | grep "^[0-9]*[0-9]$")
-
-if [ -z "$speed" ]
-then
- speed=$default_speed
-fi
-
-speedkbit=$speed"kbit"
-
-#echo "speed=$speedkbit" >> /var/stargazer/users/$LOGIN/connect.log
-declare -i mark=$ID+1
-
-iptables -t mangle -A FORWARD -d $IP -j MARK --set-mark $mark
-
-sleep 1
-
-if [ -f "/var/stargazer/ifaces/$IP" ]
-then
- #echo "1" >> /var/stargazer/users/$LOGIN/connect.log
- ppp_iface=$(cat /var/stargazer/ifaces/$IP)
-else
- #echo "2" >> /var/stargazer/users/$LOGIN/connect.log
- exit 0
-fi
-
-tc qdisc add dev $ppp_iface root handle 1: htb
-tc class add dev $ppp_iface parent 1: classid 1:1 htb rate 100mbit ceil 100mbit burst 200k
-tc class add dev $ppp_iface parent 1:1 classid 1:10 htb rate $speedkbit burst 20k
-tc filter add dev $ppp_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:10
-
-#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH $ID $mark $speed $ppp_iface" >> /var/stargazer/users/$LOGIN/connect.log
-
+++ /dev/null
-#!/bin/bash
-
-# Этот скрипт вызывается в момент, когда пользователь
-# желает отключится от интернета или вышел таймаут у пользователя
-# и сервер сам отключает пользователя
-# Задача скрипта подобна задаче скрипта OnConnect - перестроить
-# файрвол так, что бы пользователю закрыть доступ в интернет
-
-# Login
-LOGIN=$1
-
-#user IP
-IP=$2
-
-#cash
-CASH=$3
-
-#user ID
-ID=$4
-
-#Selected dirs to disconnect
-DIRS=$4
-
-#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
-
-iptables -D INPUT -s $IP -j QUEUE
-while [ $? == 0 ]
-do
- iptables -D INPUT -s $IP -j QUEUE
-done
-
-iptables -D OUTPUT -d $IP -j QUEUE
-while [ $? == 0 ]
-do
- iptables -D OUTPUT -d $IP -j QUEUE
-done
-
-iptables -D FORWARD -s $IP -j QUEUE
-while [ $? == 0 ]
-do
- iptables -D FORWARD -s $IP -j QUEUE
-done
-
-iptables -D FORWARD -d $IP -j QUEUE
-while [ $? == 0 ]
-do
- iptables -D FORWARD -d $IP -j QUEUE
-done
-
-
-
-declare -i mark=$ID+1
-
-iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
-while [ $? == 0 ]
-do
- iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
-done
-
-
-if [ -f /var/stargazer/ifaces/$IP ]
-then
- ppp_iface=$(cat /var/stargazer/ifaces/$IP)
-else
- exit 0
-fi
-
-tc qdisc del dev $ppp_iface root
-
-
+++ /dev/null
-#! /bin/sh
-
-# Использование (неиспользование) этого скрипта дело вкуса.
-# Он не выполняет критических функций. Его задача автматизировать
-# действия характерные при добавлении пользователя сети, например добавлекние
-# пользователю почты
-
-# Login
-login=$1
-
-#echo "added user $login" >> /var/stargazer/add_del.log
-
-
-
+++ /dev/null
-#! /bin/sh
-
-# Login
-login=$1
-
-#echo "deleted user $login" >> /var/stargazer/add_del.log
-
+++ /dev/null
-ALL 192.168.0.0/16 DIR1
-ALL 10.0.0.0/8 DIR2
-ALL 0.0.0.0/0 DIR0
\ No newline at end of file
+++ /dev/null
-
-# Имя лог-файла куда пишутся события
-LogFile = /var/log/stargazer.log
-
-
-
-# Имя файла в котором определяются правила подсчета трафика
-Rules = /etc/stargazer/rules
-
-
-
-# Время через которое пишется d БД детальная статистика пользователя
-# Значения: 1, 1/2, 1/4, 1/6.
-# 1 - раз в чаc, 1/2 - раз в пол часа, 1/4 - раз в 15 мин, 1/6 - раз в 10 мин
-DetailStatWritePeriod=1/6
-
-
-
-# Периодичность записи записи в БД информации о статистике пользователя (минуты)
-# При большом кол-ве пользователей эту величину стоит увеличить, т.к.
-# запись в БД может занимать длительное время.
-# Значения: 1...1440 (минуты)
-StatWritePeriod = 10
-
-
-
-# День снятия абонплаты
-# Значения: 0...31. 0 - Последний день месяца
-DayFee = 1
-
-
-
-# Абонплата снимается в последний (yes) или первый (no) день учетного периода.
-# Это влияет на то, как будет снята абонплата (АП) при переходе на новый тариф.
-# Если у пользователя был тариф A с АП=100 и он хочет перейти на тариф B с АП=200,
-# то при переходе на новый тариф со счета пользователя снимется 100, если
-# DayFeeIsLastDay = yes и 200, если DayFeeIsLastDay = no
-DayFeeIsLastDay = yes
-
-
-
-# День сброса данных о трафике за месяц и день перехода пользователей на новые тарифы
-# Значения: 0...31. 0 - Последний день месяца
-DayResetTraff = 1
-
-
-
-# "Размазанное" снятие абонплаты. Снятие АП не раз в месяц, а каждый
-# день 1/30 или 1/31 части АП
-# Значения: yes, no
-SpreadFee = no
-
-
-
-# Данная опция определяет может ли пользователь получить доступ в интерент
-# если у него на счету нет денег, но остался предоплаченный трафик
-# Значения: yes, no
-FreeMbAllowInet = no
-
-
-
-# Эта опция определяет что будет писаться в стоимость трафика в detail_stat.
-# Если у пользователя еще есть предоплаченный трафик и WriteFreeMbTraffCost = no,
-# то в detail_stat стоимость будет 0. Если у пользователя уже нет
-# предоплаченного трафика и WriteFreeMbTraffCost = no, то в detail_stat
-# будет записана стоиость трафика. При WriteFreeMbTraffCost = yes стоимость
-# трафика будет записана в любом случае.
-WriteFreeMbTraffCost = no
-
-
-
-# Необязательный параметр. Указывает снимать полную абонплату у пользователя даже
-# если он быз заморожен только часть учетного периода.
-# По умолчанию установлен в no
-# FullFee=no
-
-# Необязательный параметр указывающий показывать на счету и позволять
-# использовать пользователю абонплату. По умолчанию установлен в yes
-# ShowFeeInCash=yes
-
-
-
-# Названия направлений. Направления без названий не будут отображаться в
-# авторизаторе и конфигураторе. Названия состоящие из нескольких слов должны
-# быть взяты в кавычки
-<DirNames>
- DirName0 = Local
- DirName1 = City
- DirName2 = World
- DirName3 =
- DirName4 =
- DirName5 =
- DirName6 =
- DirName7 =
- DirName8 =
- DirName9 =
-</DirNames>
-
-
-
-# Кол-во запускаемых процессов stg-exec.
-# Эти процессы отвечают за выполнение скриптов OnConnect, OnDisconnect, ...
-# Кол-во процессов означает сколько скриптов могут выполнятся одновременно.
-# Значения: 1...1024
-ExecutersNum = 2
-
-
-
-# Message Key для stg-exec.
-# Идентификатор очереди сообщений для выполнятеля скриптов.
-# Его изменение может понадобится если есть необходимость запустить несколько
-# экземпляров stg. Если вы не понимаете, что это, не трогайте этот параметр!
-# Значения: 0...2^32
-# Значение по умолчанию: 5555
-# ExecMsgKey = 5555
-
-
-
-# Путь к директории, в которой находятся модули сервера
-ModulesPath = /usr/lib/stg
-
-# Определяет директорию, в которой будут находится файлы "монитора"
-# работы сервера. В этой директории будут созданы пустые файлы, время
-# модификации которых будет меняться примерно раз в минуту. Если какой-то
-# компонент сервера зависнет, файл(ы) перестанет обновлятся, и по этому
-# признаку можно определить сбой в работе сервера и при надобности
-# перезапустить. Если параметр не указан или пустой, мониторинг производится
-# не будет. Параметр не является обязательным, по умолчанию пустой.
-# MonitorDir=/var/stargazer/monitor
-
-
-################################################################################
-# Store module
-# Настройки плагина работающего с БД сервера
-
-# Второй параметр - это имя модуля без mod_ в начале и .so в конце
-# Т.е. полное имя модуля mod_store_files.so
-<StoreModule store_files>
-
- # Рабочая директория сервера, тут содержатся данные о тарифах, пользователях,
- # администраторах и т.д.
- WorkDir = /var/stargazer
-
-
- # Владелец, группа и права доступа на файлы статистики (stat) пользователя
- ConfOwner = root
- ConfGroup = root
- ConfMode = 600
-
-
- # Владелец, группа и права доступа на файлы конфигурации (conf) пользователя
- StatOwner = root
- StatGroup = root
- StatMode = 640
-
- # Владелец, группа и права доступа на лог-файлы (log) пользователя
- UserLogOwner = root
- UserLogGroup = root
- UserLogMode = 640
-
-</StoreModule>
-
-#<StoreModule store_firebird>
-# # Адрес сервера БД
-# server=localhost
-#
-# # Путь к БД на сервере или ее алиас
-# path=/var/stg/stargazer.fdb
-#
-# # Имя пользователя БД
-# user=stg
-#
-# # Пароль пользователя БД
-# password=123456
-#</StoreModule>
-
-#<StoreModule store_mysql>
-# # Имя пользователя БД
-# dbuser = stg
-#
-# # Пароль пользователя БД
-# rootdbpass = 123456
-#
-# # Имя БД на сервере
-# dbname = stg
-#
-# # Адрес сервера БД
-# dbhost = localhost
-#</StoreModule>
-
-
-
-################################################################################
-# Прочие модули
-
-<Modules>
-
- # Настройки плагина авторизации Always Online "mod_auth_ao.so"
- # Второй параметр - это имя модуля без mod_ в начале и .so в конце
- # Т.е. полное имя модуля mod_auth_ao.so
- #<Module auth_ao>
- #</Module>
-
-
-
- # Настройки плагина авторизации InetAccess "mod_auth_ia.so"
- # Второй параметр - это имя модуля без mod_ в начале и .so в конце
- # Т.е. полное имя модуля mod_auth_ia.so
- #<Module auth_ia>
- # Port = 5555
- # UserDelay = 15
- # UserTimeout = 65
- # FreeMb = 0
- #</Module>
-
-
-
- # Настройки модуля конфигурации SgConfig "mod_conf_sg.so"
- # Второй параметр - это имя модуля без mod_ в начале и .so в конце
- <Module conf_sg>
-
- # Порт по которому сервер взаимодействует с конфигуратором
- # Значения: 1...65535
- Port = 5555
-
- </Module>
-
-
-
- # Модуль захвата трафика "mod_cap_ether.so"
- # Второй параметер - это имя модуля без mod_ в начале и .so в конце
- # Без параметров. Только имя модуля.
- <Module cap_ipq>
- # Модуль без параметров
- </Module>
-
-
-
- # Настройки модуля пингующего пользователей "mod_ping.so"
- # Второй параметр - это имя модуля без mod_ в начале и .so в конце
- <Module ping>
-
- # Время, в секундах, между пингами одного и того же пользователя
- # Значения: 10...3600
- PingDelay = 15
-
- </Module>
-
- <Module radius>
- Password = 123456
- ServerIP = 127.0.0.1
- Port = 6666
- AuthServices = Login-User
- AcctServices = Framed-User
- </Module>
-
-# # Настройки модуля для удаленного выполнения скриптов OnConnect и
-# # OnDisconnect "mod_remote_script.so"
-# # Второй параметр - это имя модуля без mod_ в начале и .so в конце
-# <Module remote_script>
-#
-# # Время, в секундах, между посылками подтверждений, того, что пользователь
-# # всё еще онлайн
-# # Значения: 10...600
-# SendPeriod = 15
-#
-# # Соответствие подсетей, в которой находится пользователь и
-# # соответствующего роутера. Первая часть строки - подсеть, заданная
-# # как IP-адрес и маска, через пробел - IP-адрес роутера на котором
-# # должны выполняться скрипты
-# # Например эта запись "192.168.1.0/24 192.168.1.1" означает, что для
-# # всех пользователей из подсети 192.168.1.0/24, скрипты будут
-# # выполняться на роутере с адресом 192.168.1.1
-# # Subnet0...Subnet100
-# Subnet0 = 192.168.1.0/24 192.168.1.7
-# Subnet1 = 192.168.2.0/24 192.168.2.5
-# Subnet2 = 192.168.3.0/24 192.168.2.5
-# Subnet3 = 192.168.4.0/24 192.168.2.5
-#
-# # Пароль для шифрования пакетов между stg-сервером и сервером,
-# # выполняющим скрипты
-# Password = 123456
-#
-# # Этот параметр определяет какие параметры пользователя передаются
-# # на удаленный сервер
-# # Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName, NextTariff, Address,
-# # Note, Group, Email, RealName, Credit, EnabledDirs, Userdata0...Userdata9
-# UserParams=Cash Tariff EnabledDirs
-#
-# # Порт по которому сервер отсылает сообщения на роутер
-# # Значения: 1...65535
-# Port = 9999
-#
-# </Module>
-
-</Modules>
-################################################################################
-
+++ /dev/null
-/*
- * 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 "services_impl.h"
-
-#include "stg/admin.h"
-#include "stg/admin_conf.h"
-#include "stg/store.h"
-#include "stg/common.h"
-
-#include <algorithm>
-#include <cassert>
-
-using STG::ServicesImpl;
-
-//-----------------------------------------------------------------------------
-ServicesImpl::ServicesImpl(Store * st)
- : store(st),
- WriteServLog(Logger::get()),
- searchDescriptors(),
- handle(0)
-{
-Read();
-}
-//-----------------------------------------------------------------------------
-int ServicesImpl::Add(const ServiceConf & service, const Admin * admin)
-{
-std::lock_guard<std::mutex> lock(mutex);
-const auto& priv = admin->priv();
-
-if (!priv.serviceChg)
- {
- std::string s = admin->logStr() + " Add service \'" + service.name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-iterator si(std::find(data.begin(), data.end(), service));
-
-if (si != data.end())
- {
- strError = "Service \'" + service.name + "\' cannot not be added. Service already exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
-
- return -1;
- }
-
-data.push_back(service);
-
-if (store->AddService(service.name) == 0)
- {
- WriteServLog("%s Service \'%s\' added.",
- admin->logStr().c_str(), service.name.c_str());
- return 0;
- }
-
-strError = "Service \'" + service.name + "\' was not added. Error: " + store->GetStrError();
-WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
-
-return -1;
-}
-//-----------------------------------------------------------------------------
-int ServicesImpl::Del(const std::string & name, const Admin * admin)
-{
-std::lock_guard<std::mutex> lock(mutex);
-const auto& priv = admin->priv();
-
-if (!priv.serviceChg)
- {
- std::string s = admin->logStr() + " Delete service \'" + name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
-
-if (si == data.end())
- {
- strError = "Service \'" + name + "\' cannot be deleted. Service does not exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
-std::map<int, const_iterator>::iterator csi;
-csi = searchDescriptors.begin();
-while (csi != searchDescriptors.end())
- {
- if (csi->second == si)
- (csi->second)++;
- ++csi;
- }
-
-data.erase(si);
-if (store->DelService(name) < 0)
- {
- strError = "Service \'" + name + "\' was not deleted. Error: " + store->GetStrError();
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
-
- return -1;
- }
-
-WriteServLog("%s Service \'%s\' deleted.", admin->logStr().c_str(), name.c_str());
-return 0;
-}
-//-----------------------------------------------------------------------------
-int ServicesImpl::Change(const ServiceConf & service, const Admin * admin)
-{
-std::lock_guard<std::mutex> lock(mutex);
-const auto& priv = admin->priv();
-
-if (!priv.serviceChg)
- {
- std::string s = admin->logStr() + " Change service \'" + service.name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-iterator si(std::find(data.begin(), data.end(), service));
-
-if (si == data.end())
- {
- strError = "Service \'" + service.name + "\' cannot be changed " + ". Service does not exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
-printfd(__FILE__, "Old cost = %f, old pay day = %u\n", si->cost, static_cast<unsigned>(si->payDay));
-*si = service;
-printfd(__FILE__, "New cost = %f, New pay day = %u\n", si->cost, static_cast<unsigned>(si->payDay));
-if (store->SaveService(service))
- {
- WriteServLog("Cannot write service %s.", service.name.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- return -1;
- }
-
-WriteServLog("%s Service \'%s\' changed.",
- admin->logStr().c_str(), service.name.c_str());
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-bool ServicesImpl::Read()
-{
-std::lock_guard<std::mutex> lock(mutex);
-std::vector<std::string> servicesList;
-if (store->GetServicesList(&servicesList) < 0)
- {
- WriteServLog(store->GetStrError().c_str());
- return true;
- }
-
-for (size_t i = 0; i < servicesList.size(); i++)
- {
- ServiceConf service;
-
- if (store->RestoreService(&service, servicesList[i]))
- {
- WriteServLog(store->GetStrError().c_str());
- return true;
- }
-
- data.push_back(service);
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-bool ServicesImpl::Find(const std::string & name, ServiceConf * service) const
-{
-assert(service != NULL && "Pointer to service is not null");
-
-std::lock_guard<std::mutex> lock(mutex);
-if (data.empty())
- return true;
-
-const_iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
-
-if (si != data.end())
- {
- *service = *si;
- return false;
- }
-
-return true;
-}
-//-----------------------------------------------------------------------------
-bool ServicesImpl::Find(const std::string & name, ServiceConfOpt * service) const
-{
-assert(service != NULL && "Pointer to service is not null");
-
-std::lock_guard<std::mutex> lock(mutex);
-if (data.empty())
- return true;
-
-const_iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
-
-if (si != data.end())
- {
- *service = *si;
- return false;
- }
-
-return true;
-}
-//-----------------------------------------------------------------------------
-bool ServicesImpl::Exists(const std::string & name) const
-{
-std::lock_guard<std::mutex> lock(mutex);
-if (data.empty())
- {
- printfd(__FILE__, "No services in the system!\n");
- return true;
- }
-
-const_iterator si(std::find(data.begin(), data.end(), ServiceConf(name)));
-
-if (si != data.end())
- return true;
-
-return false;
-}
-//-----------------------------------------------------------------------------
-int ServicesImpl::OpenSearch() const
-{
-std::lock_guard<std::mutex> lock(mutex);
-handle++;
-searchDescriptors[handle] = data.begin();
-return handle;
-}
-//-----------------------------------------------------------------------------
-int ServicesImpl::SearchNext(int h, ServiceConf * service) const
-{
-std::lock_guard<std::mutex> lock(mutex);
-if (searchDescriptors.find(h) == searchDescriptors.end())
- {
- WriteServLog("SERVICES. Incorrect search handle.");
- return -1;
- }
-
-if (searchDescriptors[h] == data.end())
- return -1;
-
-*service = *searchDescriptors[h]++;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int ServicesImpl::CloseSearch(int h) const
-{
-std::lock_guard<std::mutex> lock(mutex);
-if (searchDescriptors.find(h) != searchDescriptors.end())
- {
- searchDescriptors.erase(searchDescriptors.find(h));
- return 0;
- }
-
-WriteServLog("SERVICES. Incorrect search handle.");
-return -1;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/services.h"
-#include "stg/service_conf.h"
-#include "stg/locker.h"
-#include "stg/noncopyable.h"
-#include "stg/logger.h"
-
-#include <vector>
-#include <map>
-#include <string>
-#include <mutex>
-
-namespace STG
-{
-
-struct Admin;
-struct Store;
-
-class ServicesImpl : public Services {
- public:
- explicit ServicesImpl(Store* st);
-
- int Add(const ServiceConf& service, const Admin* admin) override;
- int Del(const std::string& name, const Admin* admin) override;
- int Change(const ServiceConf& service, const Admin* admin) override;
- bool Find(const std::string& name, ServiceConf* service) const override;
- bool Find(const std::string& name, ServiceConfOpt* service) const override;
- bool Exists(const std::string& name) const override;
- const std::string& GetStrError() const override { return strError; }
-
- size_t Count() const override { return data.size(); }
-
- int OpenSearch() const override;
- int SearchNext(int, ServiceConf* service) const override;
- int CloseSearch(int) const override;
-
- private:
- typedef std::vector<ServiceConf>::iterator iterator;
- typedef std::vector<ServiceConf>::const_iterator const_iterator;
-
- bool Read();
-
- std::vector<ServiceConf> data;
- Store* store;
- Logger& WriteServLog;
- mutable std::map<int, const_iterator> searchDescriptors;
- mutable unsigned int handle;
- mutable std::mutex mutex;
- std::string strError;
-};
-
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include "settings_impl.h"
-
-#include "stg/logger.h"
-#include "stg/dotconfpp.h"
-#include "stg/common.h"
-#include "stg/const.h"
-
-#include <stdexcept>
-#include <cstring>
-#include <cerrno>
-
-using STG::SettingsImpl;
-using STG::ParamValue;
-
-namespace
-{
-
-struct Error : public std::runtime_error
-{
- Error(const std::string& message) : runtime_error(message) {}
-};
-
-std::vector<std::string> toValues(const DOTCONFDocumentNode& node)
-{
- std::vector<std::string> values;
-
- size_t i = 0;
- const char* value = NULL;
- while ((value = node.getValue(i++)) != NULL)
- values.push_back(value);
-
- return values;
-}
-
-std::vector<ParamValue> toPVS(const DOTCONFDocumentNode& node)
-{
- std::vector<ParamValue> pvs;
-
- const DOTCONFDocumentNode* child = node.getChildNode();
- while (child != NULL)
- {
- if (child->getName() == NULL)
- continue;
-
- if (child->getChildNode() == NULL)
- pvs.push_back(ParamValue(child->getName(), toValues(*child)));
- else
- pvs.push_back(ParamValue(child->getName(), toValues(*child), toPVS(*child)));
-
- child = child->getNextNode();
- }
-
- return pvs;
-}
-
-unsigned toPeriod(const char* value)
-{
- if (value == NULL)
- throw Error("No detail stat period value.");
-
- std::string period(value);
- if (period == "1")
- return STG::dsPeriod_1;
- else if (period == "1/2")
- return STG::dsPeriod_1_2;
- else if (period == "1/4")
- return STG::dsPeriod_1_4;
- else if (period == "1/6")
- return STG::dsPeriod_1_6;
-
- throw Error("Invalid detail stat period value: '" + period + "'. Should be one of '1', '1/2', '1/4' or '1/6'.");
-}
-
-void errorCallback(void* /*data*/, const char* buf)
-{
- printfd(__FILE__, "SettingsImpl::errorCallback() - %s\n", buf);
- STG::Logger::get()("%s", buf);
-}
-
-}
-
-//-----------------------------------------------------------------------------
-SettingsImpl::SettingsImpl(const std::string & cd)
- : modulesPath("/usr/lib/stg"),
- dirName(DIR_NUM),
- confDir(cd.empty() ? "/etc/stargazer" : cd),
- scriptsDir(confDir),
- rules(confDir + "/rules"),
- logFile("/var/log/stargazer.log"),
- pidFile("/var/run/stargazer.pid"),
- monitorDir("/var/stargazer/monitoring"),
- monitoring(false),
- detailStatWritePeriod(dsPeriod_1_6),
- statWritePeriod(10),
- stgExecMsgKey(5555),
- executersNum(1),
- fullFee(false),
- dayFee(0),
- dayResetTraff(0),
- spreadFee(false),
- freeMbAllowInet(false),
- dayFeeIsLastDay(false),
- stopOnError(true),
- writeFreeMbTraffCost(false),
- showFeeInCash(true),
- messageTimeout(0),
- feeChargeType(0),
- reconnectOnTariffChange(false),
- disableSessionLog(false)
-{
- filterParamsLog.push_back("*");
-}
-//-----------------------------------------------------------------------------
-int SettingsImpl::ReadSettings()
-{
-const char * requiredOptions[] = {
- "ModulesPath",
- "Modules",
- "StoreModule",
- "Rules",
- "LogFile",
- "DetailStatWritePeriod",
- "DayFee",
- "DayResetTraff",
- "SpreadFee",
- "FreeMbAllowInet",
- "DayFeeIsLastDay",
- "WriteFreeMbTraffCost",
- NULL
- };
-int storeModulesCount = 0;
-modulesSettings.clear();
-
-DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
-conf.setErrorCallback(errorCallback, nullptr);
-conf.setRequiredOptionNames(requiredOptions);
-std::string confFile = confDir + "/stargazer.conf";
-
-if(conf.setContent(confFile.c_str()) != 0)
- {
- strError = "Cannot read file " + confFile;
- return -1;
- }
-
-auto node = conf.getFirstNode();
-
-while (node)
- {
- if (strcasecmp(node->getName(), "ScriptDir") == 0)
- {
- scriptsDir = node->getValue(0);
- }
-
- if (strcasecmp(node->getName(), "LogFile") == 0)
- {
- logFile = node->getValue(0);
- }
-
- if (strcasecmp(node->getName(), "PIDFile") == 0)
- {
- pidFile = node->getValue(0);
- }
-
- if (strcasecmp(node->getName(), "ModulesPath") == 0)
- {
- modulesPath = node->getValue(0);
- }
-
- if (strcasecmp(node->getName(), "Rules") == 0)
- {
- rules = node->getValue(0);
- }
-
- if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
- {
- try
- {
- detailStatWritePeriod = toPeriod(node->getValue(0));
- }
- catch (const Error& error)
- {
- strError = error.what();
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
- {
- if (ParseUnsignedInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
- {
- strError = "Incorrect StatWritePeriod value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
- {
- if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
- {
- strError = "Incorrect ExecMsgKey value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "ExecutersNum") == 0)
- {
- if (ParseUnsignedInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
- {
- strError = "Incorrect ExecutersNum value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "DayFee") == 0)
- {
- if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayFee) != 0)
- {
- strError = "Incorrect DayFee value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "FullFee") == 0)
- {
- if (ParseYesNo(node->getValue(0), &fullFee) != 0)
- {
- strError = "Incorrect FullFee value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "DayResetTraff") == 0)
- {
- if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
- {
- strError = "Incorrect DayResetTraff value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "SpreadFee") == 0)
- {
- if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
- {
- strError = "Incorrect SpreadFee value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
- {
- if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
- {
- strError = "Incorrect FreeMbAllowInet value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
- {
- if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
- {
- strError = "Incorrect DayFeeIsLastDay value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "StopOnError") == 0)
- {
- if (ParseYesNo(node->getValue(0), &stopOnError) != 0)
- {
- strError = "Incorrect StopOnError value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
- {
- if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
- {
- strError = "Incorrect WriteFreeMbTraffCost value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
- {
- if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
- {
- strError = "Incorrect ShowFeeInCash value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "MonitorDir") == 0)
- {
- monitorDir = node->getValue(0);
- struct stat stat;
- monitoring = false;
-
- if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
- {
- monitoring = true;
- }
- }
-
- if (strcasecmp(node->getName(), "MessageTimeout") == 0)
- {
- if (ParseUnsigned(node->getValue(0), &messageTimeout) != 0)
- {
- strError = "Incorrect MessageTimeout value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "FeeChargeType") == 0)
- {
- if (ParseUnsignedInRange(node->getValue(0), 0, 3, &feeChargeType) != 0)
- {
- strError = "Incorrect FeeChargeType value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "ReconnectOnTariffChange") == 0)
- {
- if (ParseYesNo(node->getValue(0), &reconnectOnTariffChange) != 0)
- {
- strError = "Incorrect ReconnectOnTariffChange value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "DisableSessionLog") == 0)
- {
- if (ParseYesNo(node->getValue(0), &disableSessionLog) != 0)
- {
- strError = "Incorrect DisableSessionLog value: \'" + std::string(node->getValue(0)) + "\'";
- return -1;
- }
- }
-
- if (strcasecmp(node->getName(), "FilterParamsLog") == 0)
- {
- filterParamsLog.clear();
- for (int i = 0; node->getValue(i) != NULL; ++i)
- filterParamsLog.push_back(node->getValue(i));
- }
-
- if (strcasecmp(node->getName(), "DirNames") == 0)
- {
- const DOTCONFDocumentNode * child = node->getChildNode();
- if (child)
- {
- const DOTCONFDocumentNode * dirNameNode;
- dirName.reserve(DIR_NUM);
- for (int i = 0; i < DIR_NUM; i++)
- {
- char strDirName[12];
- sprintf(strDirName, "DirName%d", i);
- dirNameNode = conf.findNode(strDirName, node);
- if (dirNameNode && dirNameNode->getValue(0))
- {
- dirName[i] = dirNameNode->getValue(0);
- }
- }
- }
- }
-
- if (strcasecmp(node->getName(), "StoreModule") == 0)
- {
- if (node->getValue(1))
- {
- strError = "Unexpected \'" + std::string(node->getValue(1)) + "\'.";
- return -1;
- }
-
- if (storeModulesCount)
- {
- strError = "Should be only one StoreModule.";
- return -1;
- }
- storeModulesCount++;
-
- if (node->getValue(0) == NULL)
- {
- strError = "No module name in the StoreModule section.";
- return -1;
- }
- storeModuleSettings.moduleName = node->getValue(0);
- storeModuleSettings.moduleParams = toPVS(*node);
- }
-
- if (strcasecmp(node->getName(), "Modules") == 0)
- {
- if (node->getValue(0))
- {
- strError = "Unexpected \'" + std::string(node->getValue(0)) + "\'.";
- return -1;
- }
- const DOTCONFDocumentNode * child = node->getChildNode();
- while (child)
- {
- if (strcasecmp(child->getName(), "Module") != 0)
- {
- child = child->getNextNode();
- continue;
- }
-
- if (child->getValue(0) == NULL)
- {
- strError = "No module name in the Module section.";
- return -1;
- }
-
- modulesSettings.push_back(ModuleSettings(child->getValue(0), toPVS(*child)));
-
- child = child->getNextNode();
- }
- }
-
- if (strcasecmp(node->getName(), "ScriptParams") == 0)
- {
- for (int i = 0; node->getValue(i) != NULL; ++i)
- scriptParams.push_back(node->getValue(i));
- }
- node = node->getNextNode();
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/settings.h"
-#include "stg/common.h"
-#include "stg/module_settings.h"
-
-#include <string>
-#include <vector>
-
-class DOTCONFDocumentNode;
-
-namespace STG
-{
-
-//-----------------------------------------------------------------------------
-enum DETAIL_STAT_PERIOD {
- dsPeriod_1,
- dsPeriod_1_2,
- dsPeriod_1_4,
- dsPeriod_1_6
-};
-//-----------------------------------------------------------------------------
-class SettingsImpl : public Settings {
- public:
- explicit SettingsImpl(const std::string &);
-
- SettingsImpl(const SettingsImpl&) = default;
- SettingsImpl& operator=(const SettingsImpl&) = default;
- SettingsImpl(SettingsImpl&&) = default;
- SettingsImpl& operator=(SettingsImpl&&) = default;
-
- int Reload() { return ReadSettings(); }
- int ReadSettings();
-
- std::string GetStrError() const { return strError; }
-
- int GetExecMsgKey() const { return stgExecMsgKey; }
- unsigned GetExecutersNum() const { return executersNum; }
- const std::string & GetDirName(size_t num) const { return dirName[num]; }
- const std::string & GetConfDir() const { return confDir; }
- const std::string & GetScriptsDir() const { return scriptsDir; }
- const std::string & GetRulesFileName() const { return rules; }
- const std::string & GetLogFileName() const { return logFile; }
- const std::string & GetPIDFileName() const { return pidFile; }
- unsigned GetDetailStatWritePeriod() const
- { return detailStatWritePeriod; }
- unsigned GetStatWritePeriod() const { return statWritePeriod * 60; }
- unsigned GetDayFee() const { return dayFee; }
- bool GetFullFee() const { return fullFee; }
- unsigned GetDayResetTraff() const { return dayResetTraff; }
- bool GetSpreadFee() const { return spreadFee; }
- bool GetFreeMbAllowInet() const { return freeMbAllowInet; }
- bool GetDayFeeIsLastDay() const { return dayFeeIsLastDay; }
- bool GetStopOnError() const { return stopOnError; }
- bool GetWriteFreeMbTraffCost() const
- { return writeFreeMbTraffCost; }
- bool GetShowFeeInCash() const { return showFeeInCash; }
- const std::string & GetMonitorDir() const { return monitorDir; }
- bool GetMonitoring() const { return monitoring; }
- unsigned GetMessageTimeout() const { return messageTimeout * 3600 * 24; }
- unsigned GetFeeChargeType() const { return feeChargeType; }
- bool GetReconnectOnTariffChange() const { return reconnectOnTariffChange; }
- bool GetDisableSessionLog() const { return disableSessionLog; }
- const std::vector<std::string> & GetFilterParamsLog() const { return filterParamsLog; }
-
- const std::string & GetModulesPath() const { return modulesPath; }
- const ModuleSettings & GetStoreModuleSettings() const
- { return storeModuleSettings; }
- const std::vector<ModuleSettings> & GetModulesSettings() const
- { return modulesSettings; }
- const std::vector<std::string> & GetScriptParams() const { return scriptParams; }
-
- private:
- std::string strError;
-
- //////////settings
- std::string modulesPath;
- std::vector<std::string> dirName;
- std::string confDir;
- std::string scriptsDir;
- std::string rules;
- std::string logFile;
- std::string pidFile;
- std::string monitorDir;
- std::vector<std::string> scriptParams;
- bool monitoring;
- unsigned detailStatWritePeriod;
- unsigned statWritePeriod;
- int stgExecMsgKey;
- unsigned executersNum;
- bool fullFee;
- unsigned dayFee;
- unsigned dayResetTraff;
- bool spreadFee;
- bool freeMbAllowInet;
- bool dayFeeIsLastDay;
- bool stopOnError;
- bool writeFreeMbTraffCost;
- bool showFeeInCash;
- unsigned messageTimeout;
- unsigned feeChargeType;
- bool reconnectOnTariffChange;
- bool disableSessionLog;
- std::vector<std::string> filterParamsLog;
-
- std::vector<ModuleSettings> modulesSettings;
- ModuleSettings storeModuleSettings;
-};
-//-----------------------------------------------------------------------------
-
-}
+++ /dev/null
-#include "stg_timer.h"
-
-#include "stg/common.h"
-
-#include <ctime>
-#include <cstring>
-#include <csignal>
-
-#include <pthread.h>
-
-void * StgTimer(void *);
-
-static int nonstop;
-static pthread_t thrStgTimer;
-static bool isTimerRunning = false;
-volatile time_t stgTime;
-
-#ifdef STG_TIMER_DEBUG
-const int TIME_SPEED = 1;
-/*
- 1 - 1x speed
- 2 - 2x speed
- 5 - 5x speed
- 10 - 10x speed
- */
-
-const int START_TIME = 2;
-/*
- 0 - as is
- 1 - start before new day (3 min before) 29.11.2005 23:57:00
- 2 - start before new month (3 min before) 30.11.2005 23:57:00
- */
-#endif
-
-//-----------------------------------------------------------------------------
-void * StgTimer(void *)
-{
-#ifdef STG_TIMER_DEBUG
-struct tm lt;
-memset(<, 0, sizeof(lt));
-
-lt.tm_year = 2016 - 1900; // 2005
-lt.tm_mon = 7 - 1; // Nov
-lt.tm_hour = 23; // 23 h
-lt.tm_min = 57; // 50 min
-lt.tm_sec = 0; // 00 sec
-lt.tm_isdst = -1;
-
-switch (START_TIME)
- {
- case 0:
- stgTime = time(NULL);
- break;
-
- case 1:
- lt.tm_mday = 29;
- stgTime = mktime(<);
- break;
-
- case 2:
- lt.tm_mday = 31;
- stgTime = mktime(<);
- break;
- }
-#else
-stgTime = time(NULL);
-#endif
-
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-nonstop = 1;
-isTimerRunning = true;
-while (nonstop)
- {
- #ifdef STG_TIMER_DEBUG
- struct timespec ts;
- if (TIME_SPEED == 1)
- {
- ts.tv_sec = 1;
- ts.tv_nsec = 0;
- }
- else
- {
- ts.tv_sec = 0;
- ts.tv_nsec = 1000000000 / TIME_SPEED;
- }
- nanosleep(&ts, NULL);
- stgTime++;
- #else
- struct timespec ts = {0, 500000000};
- nanosleep(&ts, NULL);
- stgTime = time(NULL);
- #endif
- }
-isTimerRunning = false;
-
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int RunStgTimer()
-{
-static int a = 0;
-isTimerRunning = false;
-
-if (a == 0)
- if (pthread_create(&thrStgTimer, NULL, &StgTimer, NULL))
- {
- isTimerRunning = false;
- return -1;
- }
-
-a = 1;
-return 0;
-}
-//-----------------------------------------------------------------------------
-void StopStgTimer()
-{
-nonstop = 0;
-pthread_join(thrStgTimer, NULL); // Cleanup thread resources
-printfd(__FILE__, "STG_TIMER stopped\n");
-}
-//-----------------------------------------------------------------------------
-bool IsStgTimerRunning()
-{
-return isTimerRunning;
-}
-//-----------------------------------------------------------------------------
-int stgUsleep(unsigned long t)
-{
-#ifdef STG_TIMER_DEBUG
-struct timespec ts = {static_cast<time_t>((t / TIME_SPEED) / 1000000), static_cast<long>(((t / TIME_SPEED) % 1000000) * 1000)};
-return nanosleep(&ts, NULL);
-#else
-struct timespec ts = {static_cast<time_t>(t / 1000000), static_cast<long>((t % 1000000) * 1000)};
-return nanosleep(&ts, NULL);
-#endif
-}
-//-----------------------------------------------------------------------------
-void WaitTimer()
-{
- for (int i = 0; i < 5 && !isTimerRunning; i++)
- stgUsleep(200000);
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
- /*
- $Revision: 1.9 $
- $Date: 2010/11/03 10:37:52 $
- $Author: faust $
- */
-
-#ifndef STG_TIMER_H
-#define STG_TIMER_H
-
-#include <ctime>
-
-extern volatile time_t stgTime;
-int RunStgTimer();
-void StopStgTimer();
-void WaitTimer();
-bool IsStgTimerRunning();
-int stgUsleep(unsigned long t);
-
-#endif //STG_TIMER_H
-
-
+++ /dev/null
-/*
- * 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 <dlfcn.h>
-
-#include "stg/common.h"
-#include "stg/store.h"
-#include "store_loader.h"
-#include "settings_impl.h"
-
-using STG::StoreLoader;
-
-StoreLoader::StoreLoader(const SettingsImpl& settings) noexcept
- : isLoaded(false),
- handle(NULL),
- plugin(NULL),
- storeSettings(settings.GetStoreModuleSettings()),
- pluginFileName(settings.GetModulesPath() + "/mod_" + storeSettings.moduleName + ".so")
-{
-}
-
-StoreLoader::~StoreLoader()
-{
- unload();
-}
-
-bool StoreLoader::load() noexcept
-{
- if (isLoaded)
- {
- errorStr = "Store plugin '" + pluginFileName + "' was already loaded!";
- printfd(__FILE__, "StoreLoader::load() - %s\n", errorStr.c_str());
- return false;
- }
-
- if (pluginFileName.empty())
- {
- errorStr = "Empty store plugin filename";
- printfd(__FILE__, "StoreLoader::load() - %s\n", errorStr.c_str());
- return true;
- }
-
- handle = dlopen(pluginFileName.c_str(), RTLD_NOW);
-
- if (!handle)
- {
- errorStr = "Error loading plugin '"
- + pluginFileName + "': '" + dlerror() + "'";
- printfd(__FILE__, "StoreLoader::Load() - %s\n", errorStr.c_str());
- return true;
- }
-
- isLoaded = true;
-
- using Getter = Store* (*)();
- auto GetStore = reinterpret_cast<Getter>(dlsym(handle, "GetStore"));
- if (!GetStore)
- {
- errorStr = std::string("GetStore() not found! ") + dlerror();
- printfd(__FILE__, "StoreLoader::load() - %s\n", errorStr.c_str());
- return true;
- }
-
- plugin = GetStore();
-
- if (!plugin)
- {
- errorStr = "Plugin was not created!";
- printfd(__FILE__, "StoreLoader::Load() - %s\n");
- return true;
- }
-
- plugin->SetSettings(storeSettings);
- if (plugin->ParseSettings())
- {
- errorStr = plugin->GetStrError();
- printfd(__FILE__, "StoreLoader::Load() - Failed to parse settings. Plugin reports: '%s'\n", errorStr.c_str());
- return true;
- }
-
- return false;
-}
-
-bool StoreLoader::unload() noexcept
-{
- if (!isLoaded)
- return true;
-
- delete plugin;
-
- if (dlclose(handle))
- {
- errorStr = "Failed to unload plugin '";
- errorStr += pluginFileName + "': ";
- errorStr += dlerror();
- printfd(__FILE__, "StoreLoader::Unload() - %s\n", errorStr.c_str());
- return true;
- }
-
- isLoaded = false;
-
- return false;
-}
+++ /dev/null
-/*
- * 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>
- */
-
-#pragma once
-
-#include "stg/module_settings.h"
-
-#include <string>
-
-namespace STG
-{
-
-struct Store;
-class SettingsImpl;
-
-class StoreLoader {
- public:
- explicit StoreLoader(const SettingsImpl& settings) noexcept;
- ~StoreLoader();
-
- StoreLoader(const StoreLoader&) = delete;
- StoreLoader& operator=(const StoreLoader&) = delete;
-
- bool load() noexcept;
- bool unload() noexcept;
-
- Store& get() noexcept { return *plugin; }
-
- const std::string& GetStrError() const noexcept { return errorStr; }
-
- private:
- bool isLoaded;
- void* handle;
- Store* plugin;
- std::string errorStr;
- ModuleSettings storeSettings;
- std::string pluginFileName;
-};
-
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 07.11.2007
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-/*
- $Revision: 1.11 $
- $Date: 2010/10/07 16:57:21 $
- $Author: faust $
- */
-
-#include "tariff_impl.h"
-
-#include "stg_timer.h"
-#include "stg/common.h"
-
-#include <ctime>
-#include <algorithm> // std::max
-
-using STG::TariffImpl;
-
-//-----------------------------------------------------------------------------
-TariffImpl & TariffImpl::operator=(const TariffData & td)
-{
-tariffData = td;
-return *this;
-}
-//-----------------------------------------------------------------------------
-double TariffImpl::GetPriceWithTraffType(uint64_t up,
- uint64_t down,
- int dir,
- time_t t) const
-{
-return GetPriceWithoutFreeMb(dir, GetTraffByType(up, down) / (1024 * 1024), t);
-}
-//-----------------------------------------------------------------------------
-int64_t TariffImpl::GetTraffByType(uint64_t up, uint64_t down) const
-{
-switch (tariffData.tariffConf.traffType)
- {
- case TRAFF_UP:
- return up;
-
- case TRAFF_DOWN:
- return down;
-
- case TRAFF_MAX:
- return std::max(up, down);
-
- default: //TRAFF_UP_DOWN:
- return up + down;
- }
-}
-//-----------------------------------------------------------------------------
-int TariffImpl::GetThreshold(int dir) const
-{
- return tariffData.dirPrice[dir].threshold;
-}
-//-----------------------------------------------------------------------------
-void TariffImpl::Print() const
-{
-printfd(__FILE__, "Traiff name: %s\n", tariffData.tariffConf.name.c_str());
-}
-//-----------------------------------------------------------------------------
-int TariffImpl::Interval(int dir, time_t t) const
-{
-// Start of the day (and end of the night) in sec from 00:00:00
-int s1 = tariffData.dirPrice[dir].hDay * 3600 +
- tariffData.dirPrice[dir].mDay * 60;
-// Start of the night (and end of the day) in sec from 00:00:00
-int s2 = tariffData.dirPrice[dir].hNight * 3600 +
- tariffData.dirPrice[dir].mNight * 60;
-
-struct tm * lt;
-
-lt = localtime(&t);
-
-// Position of time t in sec from 00:00:00
-// Ignoring seconds due to minute precision
-int lts = lt->tm_hour * 3600 + lt->tm_min * 60;
-
-if (s1 < s2)
- {
- // Normal situation (00:00:00 is a night)
- if (lts > s1 && lts < s2)
- return TARIFF_DAY;
- else
- return TARIFF_NIGHT;
- }
-else
- {
- // Not so common but possible situation (00:00:00 is a day)
- if (lts < s1 && lts > s2)
- return TARIFF_NIGHT;
- else
- return TARIFF_DAY;
- }
-}
-//-----------------------------------------------------------------------------
-double TariffImpl::GetPriceWithoutFreeMb(int dir, int64_t mb, time_t t) const
-{
-int interval = Interval(dir, t);
-
-/*
- * 0011 - NB
- * *01* - NA
- * 0**1 - DB
- * **** - DA
- */
-
-bool nd = tariffData.dirPrice[dir].noDiscount;
-bool sp = tariffData.dirPrice[dir].singlePrice;
-bool th = (interval == TARIFF_NIGHT);
-bool tr = (mb > tariffData.dirPrice[dir].threshold);
-
-if (!nd && !sp && th && tr)
- return tariffData.dirPrice[dir].priceNightB;
-else if (!nd && tr)
- return tariffData.dirPrice[dir].priceDayB;
-else if (!sp && th)
- return tariffData.dirPrice[dir].priceNightA;
-else
- return tariffData.dirPrice[dir].priceDayA;
-}
-//-----------------------------------------------------------------------------
-std::string TariffImpl::TariffChangeIsAllowed(const Tariff & to, time_t currentTime) const
-{
-time_t timeout = GetChangePolicyTimeout();
-if (currentTime > timeout && timeout != 0)
- return "";
-switch (GetChangePolicy())
- {
- case Tariff::ALLOW:
- return "";
- case Tariff::TO_CHEAP:
- if (to.GetFee() < GetFee())
- return "";
- else
- return "New tariff '" + to.GetName() + "' is more expensive than current tariff '" + GetName() + "'. The policy is '" + Tariff::toString(GetChangePolicy()) + "'.";
- case Tariff::TO_EXPENSIVE:
- if (to.GetFee() >= GetFee())
- return "";
- else
- return "New tariff '" + to.GetName() + "' is more cheap than current tariff '" + GetName() + "'. The policy is '" + Tariff::toString(GetChangePolicy()) + "'.";
- case Tariff::DENY:
- return "Current tariff '" + GetName() + "', new tariff '" + to.GetName() + "'. The policy is '" + Tariff::toString(GetChangePolicy()) + "'.";
- }
-return "";
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 07.11.2007
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/tariff.h"
-#include "stg/tariff_conf.h"
-
-#include <string>
-
-#include <ctime>
-#include <cstdint>
-
-#define TARIFF_DAY 0
-#define TARIFF_NIGHT 1
-
-namespace STG
-{
-
-class TariffImpl : public Tariff {
- public:
- explicit TariffImpl(const std::string & name)
- : tariffData(name)
- {}
- explicit TariffImpl(const TariffData & td)
- : tariffData(td)
- {}
-
- TariffImpl(const TariffImpl&) = default;
- TariffImpl& operator=(const TariffImpl&) = default;
- TariffImpl(TariffImpl&&) = default;
- TariffImpl& operator=(TariffImpl&&) = default;
-
- double GetPriceWithTraffType(uint64_t up,
- uint64_t down,
- int dir,
- time_t t) const;
- double GetFreeMb() const { return tariffData.tariffConf.free; }
- double GetPassiveCost() const { return tariffData.tariffConf.passiveCost; }
- double GetFee() const { return tariffData.tariffConf.fee; }
- double GetFree() const { return tariffData.tariffConf.free; }
- Period GetPeriod() const { return tariffData.tariffConf.period; }
- ChangePolicy GetChangePolicy() const { return tariffData.tariffConf.changePolicy; }
- time_t GetChangePolicyTimeout() const { return tariffData.tariffConf.changePolicyTimeout; }
-
- void Print() const;
-
- const std::string & GetName() const { return tariffData.tariffConf.name; }
- void SetName(const std::string & name) { tariffData.tariffConf.name = name; }
-
- int GetTraffType() const { return tariffData.tariffConf.traffType; }
- int64_t GetTraffByType(uint64_t up, uint64_t down) const;
- int GetThreshold(int dir) const;
- const TariffData & GetTariffData() const { return tariffData; }
-
- TariffImpl & operator=(const TariffData & td);
- bool operator==(const TariffImpl & rhs) const { return GetName() == rhs.GetName(); }
- bool operator!=(const TariffImpl & rhs) const { return GetName() != rhs.GetName(); }
- std::string TariffChangeIsAllowed(const Tariff & to, time_t currentTime) const;
-
- private:
- TariffData tariffData;
-
- double GetPriceWithoutFreeMb(int dir, int64_t mb, time_t t) const;
- int Interval(int dir, time_t t) const;
-};
-
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 07.11.2007
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-/*
- $Revision: 1.9 $
- $Date: 2010/10/07 18:43:21 $
- $Author: faust $
- */
-
-#include <cassert>
-#include <algorithm>
-#include <vector>
-
-#include "stg/locker.h"
-#include "stg/logger.h"
-#include "stg/store.h"
-#include "stg/admin.h"
-#include "stg/admin_conf.h"
-#include "tariffs_impl.h"
-
-using STG::TariffsImpl;
-
-//-----------------------------------------------------------------------------
-TariffsImpl::TariffsImpl(Store * st)
- : store(st),
- WriteServLog(Logger::get()),
- noTariff(NO_TARIFF_NAME)
-{
-ReadTariffs();
-}
-//-----------------------------------------------------------------------------
-int TariffsImpl::ReadTariffs()
-{
-std::lock_guard<std::mutex> lock(m_mutex);
-
-std::vector<std::string> tariffsList;
-if (store->GetTariffsList(&tariffsList))
- {
- WriteServLog("Cannot get tariffs list.");
- WriteServLog("%s", store->GetStrError().c_str());
- }
-
-Data::size_type tariffsNum = tariffsList.size();
-
-for (Data::size_type i = 0; i < tariffsNum; i++)
- {
- TariffData td;
- if (store->RestoreTariff(&td, tariffsList[i]))
- {
- WriteServLog("Cannot read tariff %s.", tariffsList[i].c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- return -1;
- }
- tariffs.push_back(TariffImpl(td));
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-size_t TariffsImpl::Count() const
-{
-std::lock_guard<std::mutex> lock(m_mutex);
-return tariffs.size();
-}
-//-----------------------------------------------------------------------------
-const STG::Tariff* TariffsImpl::FindByName(const std::string & name) const
-{
-if (name == NO_TARIFF_NAME)
- return &noTariff;
-
-std::lock_guard<std::mutex> lock(m_mutex);
-const auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(name));
-
-if (ti != tariffs.end())
- return &(*ti);
-
-return NULL;
-}
-//-----------------------------------------------------------------------------
-int TariffsImpl::Chg(const TariffData & td, const Admin * admin)
-{
-const auto& priv = admin->priv();
-
-if (!priv.tariffChg)
- {
- std::string s = admin->logStr() + " Change tariff \'"
- + td.tariffConf.name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-std::lock_guard<std::mutex> lock(m_mutex);
-
-auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(td.tariffConf.name));
-
-if (ti == tariffs.end())
- {
- strError = "Tariff \'" + td.tariffConf.name + "\' cannot be changed. Tariff does not exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
-*ti = td;
-
-if (store->SaveTariff(td, td.tariffConf.name))
- {
- std::string error = "Tariff " + td.tariffConf.name + " writing error. " + store->GetStrError();
- WriteServLog(error.c_str());
- return -1;
- }
-
-WriteServLog("%s Tariff \'%s\' changed.",
- admin->logStr().c_str(), td.tariffConf.name.c_str());
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int TariffsImpl::Del(const std::string & name, const Admin * admin)
-{
-const auto& priv = admin->priv();
-
-if (!priv.tariffChg)
- {
- std::string s = admin->logStr() + " Delete tariff \'"
- + name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
-TariffData td;
-
- {
- std::lock_guard<std::mutex> lock(m_mutex);
-
- const auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(name));
-
- if (ti == tariffs.end())
- {
- strError = "Tariff \'" + name + "\' cannot be deleted. Tariff does not exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
- if (store->DelTariff(name))
- {
- WriteServLog("Cannot delete tariff %s.", name.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- return -1;
- }
-
- td = ti->GetTariffData();
-
- tariffs.erase(ti);
- }
-
-auto ni = onDelNotifiers.begin();
-while (ni != onDelNotifiers.end())
- {
- (*ni)->Notify(td);
- ++ni;
- }
-
-WriteServLog("%s Tariff \'%s\' deleted.",
- admin->logStr().c_str(),
- name.c_str());
-return 0;
-}
-//-----------------------------------------------------------------------------
-int TariffsImpl::Add(const std::string & name, const Admin * admin)
-{
-const auto& priv = admin->priv();
-
-if (!priv.tariffChg)
- {
- std::string s = admin->logStr() + " Add tariff \'"
- + name + "\'. Access denied.";
- strError = "Access denied.";
- WriteServLog(s.c_str());
- return -1;
- }
-
- {
- std::lock_guard<std::mutex> lock(m_mutex);
-
- const auto ti = find(tariffs.begin(), tariffs.end(), TariffImpl(name));
-
- if (ti != tariffs.end())
- {
- strError = "Tariff \'" + name + "\' cannot be added. Tariff already exist.";
- WriteServLog("%s %s", admin->logStr().c_str(), strError.c_str());
- return -1;
- }
-
- tariffs.push_back(TariffImpl(name));
- }
-
-if (store->AddTariff(name) < 0)
- {
- strError = "Tariff " + name + " adding error. " + store->GetStrError();
- WriteServLog(strError.c_str());
- return -1;
- }
-
-// Fire all "on add" notifiers
-auto ni = onAddNotifiers.begin();
-while (ni != onAddNotifiers.end())
- {
- (*ni)->Notify(tariffs.back().GetTariffData());
- ++ni;
- }
-
-WriteServLog("%s Tariff \'%s\' added.",
- admin->logStr().c_str(), name.c_str());
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void TariffsImpl::GetTariffsData(std::vector<TariffData> * tdl) const
-{
-assert(tdl != NULL && "Tariffs data list is not null");
-std::lock_guard<std::mutex> lock(m_mutex);
-
-auto it = tariffs.begin();
-for (; it != tariffs.end(); ++it)
- {
- tdl->push_back(it->GetTariffData());
- }
-}
-//-----------------------------------------------------------------------------
-void TariffsImpl::AddNotifierAdd(NotifierBase<TariffData> * n)
-{
-std::lock_guard<std::mutex> lock(m_mutex);
-onAddNotifiers.insert(n);
-}
-//-----------------------------------------------------------------------------
-void TariffsImpl::DelNotifierAdd(NotifierBase<TariffData> * n)
-{
-std::lock_guard<std::mutex> lock(m_mutex);
-onAddNotifiers.erase(n);
-}
-//-----------------------------------------------------------------------------
-void TariffsImpl::AddNotifierDel(NotifierBase<TariffData> * n)
-{
-std::lock_guard<std::mutex> lock(m_mutex);
-onDelNotifiers.insert(n);
-}
-//-----------------------------------------------------------------------------
-void TariffsImpl::DelNotifierDel(NotifierBase<TariffData> * n)
-{
-std::lock_guard<std::mutex> lock(m_mutex);
-onDelNotifiers.erase(n);
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 07.11.2007
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/tariff.h"
-#include "stg/tariffs.h"
-#include "stg/tariff_conf.h"
-#include "tariff_impl.h"
-
-#include <string>
-#include <vector>
-#include <set>
-#include <mutex>
-
-namespace STG
-{
-
-struct Store;
-class Logger;
-struct Admin;
-
-class TariffsImpl : public Tariffs {
- public:
- using Data = std::vector<TariffImpl>;
-
- explicit TariffsImpl(Store * store);
-
- int ReadTariffs () override;
- const Tariff * FindByName(const std::string & name) const override;
- const Tariff * GetNoTariff() const override { return &noTariff; }
- size_t Count() const override;
- int Del(const std::string & name, const Admin * admin) override;
- int Add(const std::string & name, const Admin * admin) override;
- int Chg(const TariffData & td, const Admin * admin) override;
-
- void AddNotifierAdd(NotifierBase<TariffData> * notifier) override;
- void DelNotifierAdd(NotifierBase<TariffData> * notifier) override;
-
- void AddNotifierDel(NotifierBase<TariffData> * notifier) override;
- void DelNotifierDel(NotifierBase<TariffData> * notifier) override;
-
- void GetTariffsData(std::vector<TariffData> * tdl) const override;
-
- const std::string & GetStrError() const override { return strError; }
-
- private:
- Data tariffs;
- Store* store;
- Logger& WriteServLog;
- mutable std::mutex m_mutex;
- std::string strError;
- TariffImpl noTariff;
-
- std::set<NotifierBase<TariffData>*> onAddNotifiers;
- std::set<NotifierBase<TariffData>*> onDelNotifiers;
-};
-
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 27.10.2002
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-/*
- $Revision: 1.58 $
- $Date: 2010/11/03 11:28:07 $
- $Author: faust $
- */
-
-/* inet_aton */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <csignal>
-#include <cassert>
-#include <cstdio> // fopen and similar
-#include <cstdlib> // strtol
-
-#include "stg/common.h"
-#include "stg/locker.h"
-#include "stg/const.h" // MONITOR_TIME_DELAY_SEC
-#include "traffcounter_impl.h"
-#include "stg_timer.h"
-#include "users_impl.h"
-
-#define FLUSH_TIME (10)
-#define REMOVE_TIME (31)
-
-using STG::TraffCounterImpl;
-
-const char protoName[PROTOMAX][8] =
-{"TCP", "UDP", "ICMP", "TCP_UDP", "ALL"};
-
-enum protoNum
-{
-tcp = 0, udp, icmp, tcp_udp, all
-};
-
-//-----------------------------------------------------------------------------
-TraffCounterImpl::TraffCounterImpl(UsersImpl * u, const std::string & fn)
- : WriteServLog(Logger::get()),
- rulesFileName(fn),
- monitoring(false),
- touchTimeP(stgTime - MONITOR_TIME_DELAY_SEC),
- users(u),
- running(false),
- stopped(true),
- addUserNotifier(*this),
- delUserNotifier(*this)
-{
-for (int i = 0; i < DIR_NUM; i++)
- strprintf(&dirName[i], "DIR%d", i);
-
-dirName[DIR_NUM] = "NULL";
-
-users->AddNotifierUserAdd(&addUserNotifier);
-users->AddNotifierUserDel(&delUserNotifier);
-
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-TraffCounterImpl::~TraffCounterImpl()
-{
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-int TraffCounterImpl::Start()
-{
-STG_LOCKER lock(&mutex);
-
-if (!stopped)
- return 0;
-
-if (ReadRules())
- {
- printfd(__FILE__, "TraffCounterImpl::Start() - Cannot read rules\n");
- WriteServLog("TraffCounter: Cannot read rules.");
- return -1;
- }
-
-printfd(__FILE__, "TraffCounter::Start()\n");
-int h = users->OpenSearch();
-assert(h && "USERS::OpenSearch is always correct");
-UserImpl * u;
-
-while (users->SearchNext(h, &u) == 0)
- SetUserNotifiers(u);
-users->CloseSearch(h);
-
-running = true;
-if (pthread_create(&thread, NULL, Run, this))
- {
- printfd(__FILE__, "TraffCounterImpl::Start() - Cannot start thread\n");
- WriteServLog("TraffCounter: Error: Cannot start thread.");
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int TraffCounterImpl::Stop()
-{
-if (stopped)
- return 0;
-
-running = false;
-
-int h = users->OpenSearch();
-assert(h && "USERS::OpenSearch is always correct");
-
-UserImpl * u;
-while (users->SearchNext(h, &u) == 0)
- UnSetUserNotifiers(u);
-users->CloseSearch(h);
-
-//5 seconds to thread stops itself
-struct timespec ts = {0, 200000000};
-for (int i = 0; i < 25 && !stopped; i++)
- {
- nanosleep(&ts, NULL);
- }
-
-if (!stopped)
- return -1;
-
-printfd(__FILE__, "TraffCounter::Stop()\n");
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * TraffCounterImpl::Run(void * data)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-TraffCounterImpl * tc = static_cast<TraffCounterImpl *>(data);
-tc->stopped = false;
-int c = 0;
-
-time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
-struct timespec ts = {0, 500000000};
-while (tc->running)
- {
- nanosleep(&ts, 0);
- if (!tc->running)
- {
- tc->FlushAndRemove();
- break;
- }
-
- if (tc->monitoring && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
- {
- std::string monFile(tc->monitorDir + "/traffcounter_r");
- printfd(__FILE__, "Monitor=%d file TraffCounter %s\n", tc->monitoring, monFile.c_str());
- touchTime = stgTime;
- TouchFile(monFile);
- }
-
- if (++c % FLUSH_TIME == 0)
- tc->FlushAndRemove();
- }
-
-tc->stopped = true;
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::process(const RawPacket & rawPacket)
-{
-if (!running)
- return;
-
-if (monitoring && (touchTimeP + MONITOR_TIME_DELAY_SEC <= stgTime))
- {
- std::string monFile = monitorDir + "/traffcounter_p";
- printfd(__FILE__, "Monitor=%d file TraffCounter %s\n", monitoring, monFile.c_str());
- touchTimeP = stgTime;
- TouchFile(monFile);
- }
-
-STG_LOCKER lock(&mutex);
-
-//printfd(__FILE__, "TraffCounter::Process()\n");
-//TODO replace find with lower_bound.
-
-// Searching a new packet in a tree.
-pp_iter pi = packets.find(rawPacket);
-
-// Packet found - update length and time
-if (pi != packets.end())
- {
- pi->second.lenU += rawPacket.GetLen();
- pi->second.lenD += rawPacket.GetLen();
- pi->second.updateTime = stgTime;
- /*printfd(__FILE__, "=============================\n");
- printfd(__FILE__, "Packet found!\n");
- printfd(__FILE__, "Version=%d\n", rawPacket.GetIPVersion());
- printfd(__FILE__, "HeaderLen=%d\n", rawPacket.GetHeaderLen());
- printfd(__FILE__, "PacketLen=%d\n", rawPacket.GetLen());
- printfd(__FILE__, "SIP=%s\n", inet_ntostring(rawPacket.GetSrcIP()).c_str());
- printfd(__FILE__, "DIP=%s\n", inet_ntostring(rawPacket.GetDstIP()).c_str());
- printfd(__FILE__, "src port=%d\n", rawPacket.GetSrcPort());
- printfd(__FILE__, "pst port=%d\n", rawPacket.GetDstPort());
- printfd(__FILE__, "len=%d\n", rawPacket.GetLen());
- printfd(__FILE__, "proto=%d\n", rawPacket.GetProto());
- printfd(__FILE__, "PacketDirU=%d\n", pi->second.dirU);
- printfd(__FILE__, "PacketDirD=%d\n", pi->second.dirD);
- printfd(__FILE__, "=============================\n");*/
- return;
- }
-
-PacketExtraData ed;
-
-// Packet not found - add new packet
-
-ed.updateTime = stgTime;
-ed.flushTime = stgTime;
-
-/*
- userU is that whose user_ip == packet_ip_src
- userD is that whose user_ip == packet_ip_dst
- */
-
-uint32_t ipU = rawPacket.GetSrcIP();
-uint32_t ipD = rawPacket.GetDstIP();
-
-// Searching users with such IP
-if (users->FindByIPIdx(ipU, &ed.userU) == 0)
- {
- ed.userUPresent = true;
- }
-
-if (users->FindByIPIdx(ipD, &ed.userD) == 0)
- {
- ed.userDPresent = true;
- }
-
-if (ed.userUPresent ||
- ed.userDPresent)
- {
- DeterminateDir(rawPacket, &ed.dirU, &ed.dirD);
-
- ed.lenD = ed.lenU = rawPacket.GetLen();
-
- //TODO use result of lower_bound to inserting new record
-
- // Adding packet to a tree.
- std::pair<pp_iter, bool> insertResult = packets.insert(std::make_pair(rawPacket, ed));
- pp_iter newPacket = insertResult.first;
-
- // Adding packet reference to an IP index.
- ip2packets.insert(std::make_pair(ipU, newPacket));
- ip2packets.insert(std::make_pair(ipD, newPacket));
- }
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::FlushAndRemove()
-{
-STG_LOCKER lock(&mutex);
-
-Packets::size_type oldPacketsSize = packets.size();
-Index::size_type oldIp2packetsSize = ip2packets.size();
-
-pp_iter pi;
-pi = packets.begin();
-Packets newPackets;
-ip2packets.erase(ip2packets.begin(), ip2packets.end());
-while (pi != packets.end())
- {
- //Flushing
- if (stgTime - pi->second.flushTime > FLUSH_TIME)
- {
- if (pi->second.userUPresent)
- {
- //printfd(__FILE__, "+++ Flushing U user %s (%s:%d) of length %d\n", pi->second.userU->GetLogin().c_str(), inet_ntostring(pi->first.GetSrcIP()).c_str(), pi->first.GetSrcPort(), pi->second.lenU);
-
- // Add stat
- if (pi->second.dirU < DIR_NUM)
- {
- #ifdef TRAFF_STAT_WITH_PORTS
- pi->second.userU->AddTraffStatU(pi->second.dirU,
- pi->first.GetDstIP(),
- pi->first.GetDstPort(),
- pi->second.lenU);
- #else
- pi->second.userU->AddTraffStatU(pi->second.dirU,
- pi->first.GetDstIP(),
- pi->second.lenU);
- #endif
- }
-
- pi->second.lenU = 0;
- pi->second.flushTime = stgTime;
- }
-
- if (pi->second.userDPresent)
- {
- //printfd(__FILE__, "+++ Flushing D user %s (%s:%d) of length %d\n", pi->second.userD->GetLogin().c_str(), inet_ntostring(pi->first.GetDstIP()).c_str(), pi->first.GetDstPort(), pi->second.lenD);
-
- // Add stat
- if (pi->second.dirD < DIR_NUM)
- {
- #ifdef TRAFF_STAT_WITH_PORTS
- pi->second.userD->AddTraffStatD(pi->second.dirD,
- pi->first.GetSrcIP(),
- pi->first.GetSrcPort(),
- pi->second.lenD);
- #else
- pi->second.userD->AddTraffStatD(pi->second.dirD,
- pi->first.GetSrcIP(),
- pi->second.lenD);
- #endif
- }
-
- pi->second.lenD = 0;
- pi->second.flushTime = stgTime;
- }
- }
-
- if (stgTime - pi->second.updateTime < REMOVE_TIME)
- {
- std::pair<pp_iter, bool> res = newPackets.insert(*pi);
- if (res.second)
- {
- ip2packets.insert(std::make_pair(pi->first.GetSrcIP(), res.first));
- ip2packets.insert(std::make_pair(pi->first.GetDstIP(), res.first));
- }
- }
- ++pi;
- }
-swap(packets, newPackets);
-printfd(__FILE__, "FlushAndRemove() packets: %d(rem %d) ip2packets: %d(rem %d)\n",
- packets.size(),
- oldPacketsSize - packets.size(),
- ip2packets.size(),
- oldIp2packetsSize - ip2packets.size());
-
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::AddUser(UserImpl * user)
-{
-printfd(__FILE__, "AddUser: %s\n", user->GetLogin().c_str());
-uint32_t uip = user->GetCurrIP();
-std::pair<ip2p_iter, ip2p_iter> pi;
-
-STG_LOCKER lock(&mutex);
-// Find all packets with IP belongs to this user
-pi = ip2packets.equal_range(uip);
-
-while (pi.first != pi.second)
- {
- if (pi.first->second->first.GetSrcIP() == uip)
- {
- assert((!pi.first->second->second.userUPresent ||
- pi.first->second->second.userU == user) &&
- "U user present but it's not current user");
-
- pi.first->second->second.lenU = 0;
- pi.first->second->second.userU = user;
- pi.first->second->second.userUPresent = true;
- }
-
- if (pi.first->second->first.GetDstIP() == uip)
- {
- assert((!pi.first->second->second.userDPresent ||
- pi.first->second->second.userD == user) &&
- "D user present but it's not current user");
-
- pi.first->second->second.lenD = 0;
- pi.first->second->second.userD = user;
- pi.first->second->second.userDPresent = true;
- }
-
- ++pi.first;
- }
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::DelUser(uint32_t uip)
-{
-printfd(__FILE__, "DelUser: %s \n", inet_ntostring(uip).c_str());
-std::pair<ip2p_iter, ip2p_iter> pi;
-
-STG_LOCKER lock(&mutex);
-pi = ip2packets.equal_range(uip);
-
-while (pi.first != pi.second)
- {
- if (pi.first->second->first.GetSrcIP() == uip)
- {
- if (pi.first->second->second.dirU < DIR_NUM && pi.first->second->second.userUPresent)
- {
- #ifdef TRAFF_STAT_WITH_PORTS
- pi.first->second->second.userU->AddTraffStatU(pi.first->second->second.dirU,
- pi.first->second->first.GetDstIP(),
- pi.first->second->first.GetDstPort(),
- pi.first->second->second.lenU);
- #else
- pi.first->second->second.userU->AddTraffStatU(pi.first->second->second.dirU,
- pi.first->second->first.GetDstIP(),
- pi.first->second->second.lenU);
- #endif
- }
- pi.first->second->second.userUPresent = false;
- }
-
- if (pi.first->second->first.GetDstIP() == uip)
- {
- if (pi.first->second->second.dirD < DIR_NUM && pi.first->second->second.userDPresent)
- {
- #ifdef TRAFF_STAT_WITH_PORTS
- pi.first->second->second.userD->AddTraffStatD(pi.first->second->second.dirD,
- pi.first->second->first.GetSrcIP(),
- pi.first->second->first.GetSrcPort(),
- pi.first->second->second.lenD);
- #else
- pi.first->second->second.userD->AddTraffStatD(pi.first->second->second.dirD,
- pi.first->second->first.GetSrcIP(),
- pi.first->second->second.lenD);
- #endif
- }
-
- pi.first->second->second.userDPresent = false;
- }
-
- ++pi.first;
- }
-
-ip2packets.erase(pi.first, pi.second);
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::SetUserNotifiers(UserImpl * user)
-{
-// Adding user. Adding notifiers to user.
-TRF_IP_BEFORE ipBNotifier(*this, user);
-ipBeforeNotifiers.push_front(ipBNotifier);
-user->AddCurrIPBeforeNotifier(&(*ipBeforeNotifiers.begin()));
-
-TRF_IP_AFTER ipANotifier(*this, user);
-ipAfterNotifiers.push_front(ipANotifier);
-user->AddCurrIPAfterNotifier(&(*ipAfterNotifiers.begin()));
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::UnSetUserNotifiers(UserImpl * user)
-{
-// Removing user. Removing notifiers from user.
-std::list<TRF_IP_BEFORE>::iterator bi;
-std::list<TRF_IP_AFTER>::iterator ai;
-
-bi = ipBeforeNotifiers.begin();
-while (bi != ipBeforeNotifiers.end())
- {
- if (user->GetLogin() == bi->GetUser()->GetLogin())
- {
- user->DelCurrIPBeforeNotifier(&(*bi));
- ipBeforeNotifiers.erase(bi);
- break;
- }
- ++bi;
- }
-
-ai = ipAfterNotifiers.begin();
-while (ai != ipAfterNotifiers.end())
- {
- if (user->GetLogin() == ai->GetUser()->GetLogin())
- {
- user->DelCurrIPAfterNotifier(&(*ai));
- ipAfterNotifiers.erase(ai);
- break;
- }
- ++ai;
- }
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::DeterminateDir(const RawPacket & packet,
- int * dirU, // Direction for incoming packet
- int * dirD) const // Direction for outgoing packet
-{
-bool addrMatchU = false;
-bool portMatchU = false;
-bool addrMatchD = false;
-bool portMatchD = false;
-bool foundU = false; // Was rule for U found ?
-bool foundD = false; // Was rule for D found ?
-//printfd(__FILE__, "foundU=%d, foundD=%d\n", foundU, foundD);
-
-enum { ICMP_RPOTO = 1, TCP_PROTO = 6, UDP_PROTO = 17 };
-
-std::list<Rule>::const_iterator ln;
-ln = rules.begin();
-
-while (ln != rules.end())
- {
- if (!foundU)
- {
- portMatchU = false;
-
- switch (ln->proto)
- {
- case all:
- portMatchU = true;
- break;
-
- case icmp:
- portMatchU = (packet.GetProto() == ICMP_RPOTO);
- break;
-
- case tcp_udp:
- if (packet.GetProto() == TCP_PROTO || packet.GetProto() == UDP_PROTO)
- portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
- break;
-
- case tcp:
- if (packet.GetProto() == TCP_PROTO)
- portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
- break;
-
- case udp:
- if (packet.GetProto() == UDP_PROTO)
- portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
- break;
-
- default:
- printfd(__FILE__, "Error! Incorrect rule!\n");
- break;
- }
-
- addrMatchU = (packet.GetDstIP() & ln->mask) == ln->ip;
-
- if (!foundU && addrMatchU && portMatchU)
- {
- foundU = true;
- *dirU = ln->dir;
- //printfd(__FILE__, "Up rule ok! %d\n", ln->dir);
- }
-
- } //if (!foundU)
-
- if (!foundD)
- {
- portMatchD = false;
-
- switch (ln->proto)
- {
- case all:
- portMatchD = true;
- break;
-
- case icmp:
- portMatchD = (packet.GetProto() == ICMP_RPOTO);
- break;
-
- case tcp_udp:
- if (packet.GetProto() == TCP_PROTO || packet.GetProto() == UDP_PROTO)
- portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
- break;
-
- case tcp:
- if (packet.GetProto() == TCP_PROTO)
- portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
- break;
-
- case udp:
- if (packet.GetProto() == UDP_PROTO)
- portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
- break;
-
- default:
- printfd(__FILE__, "Error! Incorrect rule!\n");
- break;
- }
-
- addrMatchD = (packet.GetSrcIP() & ln->mask) == ln->ip;
-
- if (!foundD && addrMatchD && portMatchD)
- {
- foundD = true;
- *dirD = ln->dir;
- //printfd(__FILE__, "Down rule ok! %d\n", ln->dir);
- }
- } //if (!foundD)
-
- ++ln;
- } //while (ln != rules.end())
-
-if (!foundU)
- *dirU = DIR_NUM;
-
-if (!foundD)
- *dirD = DIR_NUM;
-}
-//-----------------------------------------------------------------------------
-bool TraffCounterImpl::ReadRules(bool test)
-{
-//printfd(__FILE__, "TraffCounter::ReadRules()\n");
-
-Rule rul;
-FILE * f;
-char str[1024];
-char tp[100]; // protocol
-char ta[100]; // address
-char td[100]; // target direction
-int r;
-int lineNumber = 0;
-f = fopen(rulesFileName.c_str(), "rt");
-
-if (!f)
- {
- printfd(__FILE__, "TraffCounterImpl::ReadRules() - File '%s' cannot be opened.\n", rulesFileName.c_str());
- WriteServLog("File '%s' cannot be oppened.", rulesFileName.c_str());
- return true;
- }
-
-while (fgets(str, 1023, f))
- {
- lineNumber++;
- if (str[strspn(str," \t")] == '#' || str[strspn(str," \t")] == '\n')
- {
- continue;
- }
-
- r = sscanf(str,"%99s %99s %99s", tp, ta, td);
- if (r != 3)
- {
- printfd(__FILE__, "TraffCounterImpl::ReadRules() - Error in file '%s' at line %d. There must be 3 parameters.\n", rulesFileName.c_str(), lineNumber);
- WriteServLog("Error in file '%s' at line %d. There must be 3 parameters.", rulesFileName.c_str(), lineNumber);
- fclose(f);
- return true;
- }
-
- rul.proto = 0xff;
- rul.dir = 0xff;
-
- for (uint8_t i = 0; i < PROTOMAX; i++)
- {
- if (strcasecmp(tp, protoName[i]) == 0)
- rul.proto = i;
- }
-
- for (uint32_t i = 0; i < DIR_NUM + 1; i++)
- {
- if (td == dirName[i])
- rul.dir = i;
- }
-
- if (rul.dir == 0xff || rul.proto == 0xff)
- {
- printfd(__FILE__, "TraffCounterImpl::ReadRules() - Error in file '%s' at line %d.\n", rulesFileName.c_str(), lineNumber);
- WriteServLog("Error in file %s. Line %d.",
- rulesFileName.c_str(), lineNumber);
- fclose(f);
- return true;
- }
-
- if (ParseAddress(ta, &rul) != 0)
- {
- printfd(__FILE__, "TraffCounterImpl::ReadRules() - Error in file '%s' at line %d. Error in adress.\n", rulesFileName.c_str(), lineNumber);
- WriteServLog("Error in file %s. Error in adress. Line %d.",
- rulesFileName.c_str(), lineNumber);
- fclose(f);
- return true;
- }
- if (!test)
- rules.push_back(rul);
- }
-
-fclose(f);
-
-// Adding lastest rule: ALL 0.0.0.0/0 NULL
-rul.dir = DIR_NUM; //NULL
-rul.ip = 0; //0.0.0.0
-rul.mask = 0;
-rul.port1 = 0;
-rul.port2 = 65535;
-rul.proto = all;
-
-if (!test)
- rules.push_back(rul);
-
-return false;
-}
-//-----------------------------------------------------------------------------
-int TraffCounterImpl::Reload()
-{
-STG_LOCKER lock(&mutex);
-
-if (ReadRules(true))
- {
- printfd(__FILE__, "TraffCounterImpl::Reload() - Failed to reload rules.\n");
- WriteServLog("TraffCounter: Cannot reload rules. Errors found.");
- return -1;
- }
-
-FreeRules();
-ReadRules();
-printfd(__FILE__, "TraffCounterImpl::Reload() - Reloaded rules successfully.\n");
-WriteServLog("TraffCounter: Reloaded rules successfully.");
-return 0;
-}
-//-----------------------------------------------------------------------------
-bool TraffCounterImpl::ParseAddress(const char * ta, Rule * rule) const
-{
-char addr[50], mask[20], port1[20], port2[20], ports[40];
-
-size_t len = strlen(ta);
-char n = 0;
-size_t i, p;
-memset(addr, 0, sizeof(addr));
-for (i = 0; i < len; i++)
- {
- if (ta[i] == '/' || ta[i] == ':')
- {
- addr[i] = 0;
- n = ta[i];
- break;
- }
- addr[i] = ta[i];
- n = 0;
- }
-addr[i + 1] = 0;
-p = i + 1;
-
-if (n == '/')
- {
- // mask
- for (; i < len; i++)
- {
- if (ta[i] == ':')
- {
- mask[i - p] = 0;
- n = ':';
- break;
- }
- mask[i - p] = ta[i];
- }
- mask[i - p] = 0;
- }
-else
- {
- strcpy(mask, "32");
- }
-
-p = i + 1;
-i++;
-
-if (n == ':')
- {
- // port
- if (!(rule->proto == tcp || rule->proto == udp || rule->proto == tcp_udp))
- {
- printfd(__FILE__, "TraffCounterImpl::ParseAddress() - No ports specified for this protocol.\n");
- WriteServLog("No ports specified for this protocol.");
- return true;
- }
-
- for (; i < len; i++)
- ports[i - p] = ta[i];
-
- ports[i - p] = 0;
- }
-else
- {
- strcpy(ports, "0-65535");
- }
-
-char *sss;
-char pts[100];
-strcpy(pts, ports);
-
-if ((sss = strchr(ports, '-')) != NULL)
- {
- strncpy(port1, ports, int(sss-ports));
- port1[int(sss - ports)] = 0;
- strcpy(port2, sss + 1);
- }
-else
- {
- strcpy(port1, ports);
- strcpy(port2, ports);
- }
-
-// Convert strings to mask, ports and IP
-uint16_t prt1, prt2, msk;
-struct in_addr ipaddr;
-char *res;
-
-msk = static_cast<uint16_t>(strtol(mask, &res, 10));
-if (*res != 0)
- return true;
-
-prt1 = static_cast<uint16_t>(strtol(port1, &res, 10));
-if (*res != 0)
- return true;
-
-prt2 = static_cast<uint16_t>(strtol(port2, &res, 10));
-if (*res != 0)
- return true;
-
-int r = inet_aton(addr, &ipaddr);
-if (r == 0)
- return true;
-
-rule->ip = ipaddr.s_addr;
-rule->mask = CalcMask(msk);
-
-if ((ipaddr.s_addr & rule->mask) != ipaddr.s_addr)
- {
- printfd(__FILE__, "TraffCounterImpl::ParseAddress() - Address does'n match mask.\n");
- WriteServLog("Address does'n match mask.");
- return true;
- }
-
-rule->port1 = prt1;
-rule->port2 = prt2;
-
-return false;
-}
-//-----------------------------------------------------------------------------
-uint32_t TraffCounterImpl::CalcMask(uint32_t msk) const
-{
-if (msk >= 32) return 0xFFffFFff;
-if (msk == 0) return 0;
-return htonl(0xFFffFFff << (32 - msk));
-}
-//---------------------------------------------------------------------------
-void TraffCounterImpl::FreeRules()
-{
-rules.clear();
-}
-//-----------------------------------------------------------------------------
-void TraffCounterImpl::SetMonitorDir(const std::string & dir)
-{
-monitorDir = dir;
-monitoring = !monitorDir.empty();
-}
-//-----------------------------------------------------------------------------
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/traffcounter.h"
-#include "stg/logger.h"
-#include "stg/raw_ip_packet.h"
-#include "stg/noncopyable.h"
-#include "stg/notifer.h"
-#include "actions.h"
-#include "eventloop.h"
-#include "user_impl.h"
-
-#include <ctime>
-#include <list>
-#include <map>
-#include <string>
-#include <cstdint>
-
-#include <pthread.h>
-
-#define PROTOMAX (5)
-
-namespace STG
-{
-
-class UsersImpl;
-
-//-----------------------------------------------------------------------------
-struct Rule {
-uint32_t ip; // IP
-uint32_t mask; // Network mask
-uint16_t port1; // Min port
-uint16_t port2; // Max port
-uint8_t proto; // Protocol
-uint32_t dir; // Direction
-};
-//-----------------------------------------------------------------------------
-struct PacketExtraData {
- PacketExtraData()
- : flushTime(0),
- updateTime(0),
- userU(NULL),
- userUPresent(false),
- userD(NULL),
- userDPresent(false),
- dirU(DIR_NUM),
- dirD(DIR_NUM),
- lenU(0),
- lenD(0)
- {}
-
- time_t flushTime; // Last flush time
- time_t updateTime; // Last update time
- UserImpl * userU; // Uploader
- bool userUPresent; // Uploader is registered user
- UserImpl * userD; // Downloader
- bool userDPresent; // Downloader is registered user
- int dirU; // Upload direction
- int dirD; // Download direction
- uint32_t lenU; // Upload length
- uint32_t lenD; // Download length
-};
-//-----------------------------------------------------------------------------
-class TraffCounterImpl;
-//-----------------------------------------------------------------------------
-class TRF_IP_BEFORE: public PropertyNotifierBase<uint32_t> {
-public:
- TRF_IP_BEFORE(TraffCounterImpl & t, UserImpl * u)
- : PropertyNotifierBase<uint32_t>(),
- traffCnt(t),
- user(u)
- {}
- TRF_IP_BEFORE(const TRF_IP_BEFORE & rvalue)
- : PropertyNotifierBase<uint32_t>(),
- traffCnt(rvalue.traffCnt),
- user(rvalue.user)
- {}
- void Notify(const uint32_t & oldValue, const uint32_t & newValue);
- void SetUser(UserImpl * u) { user = u; }
- UserImpl * GetUser() const { return user; }
-
-private:
- TRF_IP_BEFORE & operator=(const TRF_IP_BEFORE & rvalue);
-
- TraffCounterImpl & traffCnt;
- UserImpl * user;
-};
-//-----------------------------------------------------------------------------
-class TRF_IP_AFTER: public PropertyNotifierBase<uint32_t> {
-public:
- TRF_IP_AFTER(TraffCounterImpl & t, UserImpl * u)
- : PropertyNotifierBase<uint32_t>(),
- traffCnt(t),
- user(u)
- {}
- TRF_IP_AFTER(const TRF_IP_AFTER & rvalue)
- : PropertyNotifierBase<uint32_t>(),
- traffCnt(rvalue.traffCnt),
- user(rvalue.user)
- {}
- void Notify(const uint32_t & oldValue, const uint32_t & newValue);
- void SetUser(UserImpl * u) { user = u; }
- UserImpl * GetUser() const { return user; }
-private:
- TRF_IP_AFTER & operator=(const TRF_IP_AFTER & rvalue);
-
- TraffCounterImpl & traffCnt;
- UserImpl * user;
-};
-
-using UserImplPtr = UserImpl*;
-//-----------------------------------------------------------------------------
-class ADD_USER_NONIFIER: public NotifierBase<UserImplPtr> {
-public:
- explicit ADD_USER_NONIFIER(TraffCounterImpl & t) :
- NotifierBase<UserImplPtr>(),
- traffCnt(t)
- {}
- virtual ~ADD_USER_NONIFIER() {}
- void Notify(const UserImplPtr & user);
-
-private:
- ADD_USER_NONIFIER(const ADD_USER_NONIFIER & rvalue);
- ADD_USER_NONIFIER & operator=(const ADD_USER_NONIFIER & rvalue);
-
- TraffCounterImpl & traffCnt;
-};
-//-----------------------------------------------------------------------------
-class DEL_USER_NONIFIER: public NotifierBase<UserImplPtr> {
-public:
- explicit DEL_USER_NONIFIER(TraffCounterImpl & t) :
- NotifierBase<UserImplPtr>(),
- traffCnt(t)
- {}
- virtual ~DEL_USER_NONIFIER() {}
- void Notify(const UserImplPtr & user);
-
-private:
- DEL_USER_NONIFIER(const DEL_USER_NONIFIER & rvalue);
- DEL_USER_NONIFIER & operator=(const DEL_USER_NONIFIER & rvalue);
-
- TraffCounterImpl & traffCnt;
-};
-//-----------------------------------------------------------------------------
-class TraffCounterImpl : public TraffCounter {
- friend class ADD_USER_NONIFIER;
- friend class DEL_USER_NONIFIER;
- friend class TRF_IP_BEFORE;
- friend class TRF_IP_AFTER;
- public:
- TraffCounterImpl(UsersImpl * users, const std::string & rulesFileName);
- ~TraffCounterImpl();
-
- int Reload();
- int Start();
- int Stop();
-
- void process(const RawPacket & rawPacket) override;
- void SetMonitorDir(const std::string & monitorDir);
-
- size_t rulesCount() const override { return rules.size(); }
-
- private:
- bool ParseAddress(const char * ta, Rule * rule) const;
- uint32_t CalcMask(uint32_t msk) const;
- void FreeRules();
- bool ReadRules(bool test = false);
-
- static void * Run(void * data);
-
- void DeterminateDir(const RawPacket & packet,
- int * dirU, // Direction for upload
- int * dirD) const; // Direction for download
-
- void FlushAndRemove();
-
- void AddUser(UserImpl * user);
- void DelUser(uint32_t uip);
- void SetUserNotifiers(UserImpl * user);
- void UnSetUserNotifiers(UserImpl * user);
-
- typedef std::list<Rule>::iterator rule_iter;
-
- std::list<Rule> rules;
-
- typedef std::map<RawPacket, PacketExtraData> Packets;
- typedef Packets::iterator pp_iter;
- typedef std::multimap<uint32_t, pp_iter> Index;
- typedef Index::iterator ip2p_iter;
- typedef Index::const_iterator ip2p_citer;
-
- Packets packets; // Packets tree
-
- Index ip2packets; // IP-to-Packet index
-
- std::string dirName[DIR_NUM + 1];
-
- Logger & WriteServLog;
- std::string rulesFileName;
-
- std::string monitorDir;
- bool monitoring;
- time_t touchTimeP;
-
- UsersImpl * users;
-
- bool running;
- bool stopped;
- pthread_mutex_t mutex;
- pthread_t thread;
-
- std::list<TRF_IP_BEFORE> ipBeforeNotifiers;
- std::list<TRF_IP_AFTER> ipAfterNotifiers;
-
- ADD_USER_NONIFIER addUserNotifier;
- DEL_USER_NONIFIER delUserNotifier;
-};
-//-----------------------------------------------------------------------------
-inline
-void TRF_IP_BEFORE::Notify(const uint32_t & oldValue, const uint32_t &)
-{
-// User changes his address. Remove old IP
-if (!oldValue)
- return;
-
-EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::DelUser, oldValue);
-}
-//-----------------------------------------------------------------------------
-inline
-void TRF_IP_AFTER::Notify(const uint32_t &, const uint32_t & newValue)
-{
-// User changes his address. Add new IP
-if (!newValue)
- return;
-
-EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::AddUser, user);
-}
-//-----------------------------------------------------------------------------
-inline
-void ADD_USER_NONIFIER::Notify(const UserImplPtr & user)
-{
-EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::SetUserNotifiers, user);
-}
-//-----------------------------------------------------------------------------
-inline
-void DEL_USER_NONIFIER::Notify(const UserImplPtr & user)
-{
-EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::UnSetUserNotifiers, user);
-EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TraffCounterImpl::DelUser, user->GetCurrIP());
-}
-//-----------------------------------------------------------------------------
-}
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 27.10.2002
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-/*
- $Revision: 1.101 $
- $Date: 2010/11/03 10:50:03 $
- $Author: faust $
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include "user_impl.h"
-#include "settings_impl.h"
-#include "stg_timer.h"
-
-#include "stg/users.h"
-#include "stg/common.h"
-#include "stg/scriptexecuter.h"
-#include "stg/tariff.h"
-#include "stg/tariffs.h"
-#include "stg/services.h"
-#include "stg/service_conf.h"
-#include "stg/admin.h"
-
-#include <algorithm>
-#include <functional>
-
-#include <cassert>
-#include <cstdlib>
-#include <cmath>
-
-#include <pthread.h>
-#include <unistd.h> // access
-
-using STG::UserImpl;
-
-namespace
-{
-
-std::string dirsToString(const bool * dirs)
-{
-std::string res;
-for (size_t i = 0; i < DIR_NUM; i++)
- res += dirs[i] ? '1' : '0';
-return res;
-}
-
-void dirsFromBits(bool * dirs, uint32_t bits)
-{
-for (size_t i = 0; i < DIR_NUM; i++)
- dirs[i] = bits & (1 << i);
-}
-
-}
-
-UserImpl::UserImpl(const Settings * s,
- const Store * st,
- const Tariffs * t,
- const Admin * a,
- const Users * u,
- const Services & svcs)
- : users(u),
- properties(*s),
- WriteServLog(Logger::get()),
- lastScanMessages(0),
- id(0),
- __connected(0),
- connected(__connected),
- __currIP(0),
- currIP(__currIP),
- lastIPForDisconnect(0),
- pingTime(0),
- sysAdmin(a),
- store(st),
- tariffs(t),
- tariff(NULL),
- m_services(svcs),
- settings(s),
- authorizedModificationTime(0),
- deleted(false),
- lastWriteStat(0),
- lastWriteDetailedStat(0),
- cash(properties.cash),
- up(properties.up),
- down(properties.down),
- lastCashAdd(properties.lastCashAdd),
- passiveTime(properties.passiveTime),
- lastCashAddTime(properties.lastCashAddTime),
- freeMb(properties.freeMb),
- lastActivityTime(properties.lastActivityTime),
- password(properties.password),
- passive(properties.passive),
- disabled(properties.disabled),
- disabledDetailStat(properties.disabledDetailStat),
- alwaysOnline(properties.alwaysOnline),
- tariffName(properties.tariffName),
- nextTariff(properties.nextTariff),
- address(properties.address),
- note(properties.note),
- group(properties.group),
- email(properties.email),
- phone(properties.phone),
- realName(properties.realName),
- credit(properties.credit),
- creditExpire(properties.creditExpire),
- ips(properties.ips),
- userdata0(properties.userdata0),
- userdata1(properties.userdata1),
- userdata2(properties.userdata2),
- userdata3(properties.userdata3),
- userdata4(properties.userdata4),
- userdata5(properties.userdata5),
- userdata6(properties.userdata6),
- userdata7(properties.userdata7),
- userdata8(properties.userdata8),
- userdata9(properties.userdata9),
- sessionUploadModTime(stgTime),
- sessionDownloadModTime(stgTime),
- passiveNotifier(this),
- disabledNotifier(this),
- tariffNotifier(this),
- cashNotifier(this),
- ipNotifier(this)
-{
-Init();
-}
-//-----------------------------------------------------------------------------
-void UserImpl::Init()
-{
-password = "*_EMPTY_PASSWORD_*";
-tariffName = NO_TARIFF_NAME;
-tariff = tariffs->FindByName(tariffName);
-ips = UserIPs::parse("*");
-lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
-lastWriteDetailedStat = stgTime;
-
-properties.tariffName.AddBeforeNotifier(&tariffNotifier);
-properties.passive.AddBeforeNotifier(&passiveNotifier);
-properties.disabled.AddAfterNotifier(&disabledNotifier);
-properties.cash.AddBeforeNotifier(&cashNotifier);
-ips.AddAfterNotifier(&ipNotifier);
-
-pthread_mutexattr_t attr;
-pthread_mutexattr_init(&attr);
-pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-pthread_mutex_init(&mutex, &attr);
-}
-//-----------------------------------------------------------------------------
-UserImpl::UserImpl(const UserImpl & u)
- : users(u.users),
- properties(*u.settings),
- WriteServLog(Logger::get()),
- lastScanMessages(0),
- login(u.login),
- id(u.id),
- __connected(0),
- connected(__connected),
- __currIP(u.__currIP),
- currIP(__currIP),
- lastIPForDisconnect(0),
- pingTime(u.pingTime),
- sysAdmin(u.sysAdmin),
- store(u.store),
- tariffs(u.tariffs),
- tariff(u.tariff),
- m_services(u.m_services),
- traffStat(u.traffStat),
- traffStatSaved(u.traffStatSaved),
- settings(u.settings),
- authorizedModificationTime(u.authorizedModificationTime),
- messages(u.messages),
- deleted(u.deleted),
- lastWriteStat(u.lastWriteStat),
- lastWriteDetailedStat(u.lastWriteDetailedStat),
- cash(properties.cash),
- up(properties.up),
- down(properties.down),
- lastCashAdd(properties.lastCashAdd),
- passiveTime(properties.passiveTime),
- lastCashAddTime(properties.lastCashAddTime),
- freeMb(properties.freeMb),
- lastActivityTime(properties.lastActivityTime),
- password(properties.password),
- passive(properties.passive),
- disabled(properties.disabled),
- disabledDetailStat(properties.disabledDetailStat),
- alwaysOnline(properties.alwaysOnline),
- tariffName(properties.tariffName),
- nextTariff(properties.nextTariff),
- address(properties.address),
- note(properties.note),
- group(properties.group),
- email(properties.email),
- phone(properties.phone),
- realName(properties.realName),
- credit(properties.credit),
- creditExpire(properties.creditExpire),
- ips(properties.ips),
- userdata0(properties.userdata0),
- userdata1(properties.userdata1),
- userdata2(properties.userdata2),
- userdata3(properties.userdata3),
- userdata4(properties.userdata4),
- userdata5(properties.userdata5),
- userdata6(properties.userdata6),
- userdata7(properties.userdata7),
- userdata8(properties.userdata8),
- userdata9(properties.userdata9),
- sessionUpload(),
- sessionDownload(),
- sessionUploadModTime(stgTime),
- sessionDownloadModTime(stgTime),
- passiveNotifier(this),
- disabledNotifier(this),
- tariffNotifier(this),
- cashNotifier(this),
- ipNotifier(this)
-{
-if (&u == this)
- return;
-
-properties.tariffName.AddBeforeNotifier(&tariffNotifier);
-properties.passive.AddBeforeNotifier(&passiveNotifier);
-properties.disabled.AddAfterNotifier(&disabledNotifier);
-properties.cash.AddBeforeNotifier(&cashNotifier);
-ips.AddAfterNotifier(&ipNotifier);
-
-properties.SetProperties(u.properties);
-
-pthread_mutexattr_t attr;
-pthread_mutexattr_init(&attr);
-pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-pthread_mutex_init(&mutex, &attr);
-}
-//-----------------------------------------------------------------------------
-UserImpl::~UserImpl()
-{
-properties.tariffName.DelBeforeNotifier(&tariffNotifier);
-properties.passive.DelBeforeNotifier(&passiveNotifier);
-properties.disabled.DelAfterNotifier(&disabledNotifier);
-properties.cash.DelBeforeNotifier(&cashNotifier);
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::SetLogin(const std::string & l)
-{
-STG_LOCKER lock(&mutex);
-static int idGen = 0;
-assert(login.empty() && "Login is already set");
-login = l;
-id = idGen++;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::ReadConf()
-{
-STG_LOCKER lock(&mutex);
-UserConf conf;
-
-if (store->RestoreUserConf(&conf, login))
- {
- WriteServLog("Cannot read conf for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
- printfd(__FILE__, "%s\n", store->GetStrError().c_str());
- return -1;
- }
-
-properties.SetConf(conf);
-
-tariff = tariffs->FindByName(tariffName);
-if (tariff == NULL)
- {
- WriteServLog("Cannot read user %s. Tariff %s not exist.",
- login.c_str(), properties.tariffName.Get().c_str());
- return -1;
- }
-
-std::vector<Message::Header> hdrsList;
-
-if (store->GetMessageHdrs(&hdrsList, login))
- {
- printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
- WriteServLog("Cannot read user %s. Error reading message headers: %s.",
- login.c_str(),
- store->GetStrError().c_str());
- return -1;
- }
-
-std::vector<Message::Header>::const_iterator it;
-for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
- {
- Message msg;
- if (store->GetMessage(it->id, &msg, login) == 0)
- {
- messages.push_back(msg);
- }
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::ReadStat()
-{
-STG_LOCKER lock(&mutex);
-UserStat stat;
-
-if (store->RestoreUserStat(&stat, login))
- {
- WriteServLog("Cannot read stat for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
- printfd(__FILE__, "%s\n", store->GetStrError().c_str());
- return -1;
- }
-
-properties.SetStat(stat);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::WriteConf()
-{
-STG_LOCKER lock(&mutex);
-UserConf conf(properties.GetConf());
-
-printfd(__FILE__, "UserImpl::WriteConf()\n");
-
-if (store->SaveUserConf(conf, login))
- {
- WriteServLog("Cannot write conf for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
- printfd(__FILE__, "%s\n", store->GetStrError().c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::WriteStat()
-{
-STG_LOCKER lock(&mutex);
-UserStat stat(properties.GetStat());
-
-if (store->SaveUserStat(stat, login))
- {
- WriteServLog("Cannot write stat for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
- printfd(__FILE__, "%s\n", store->GetStrError().c_str());
- return -1;
- }
-
-lastWriteStat = stgTime;
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::WriteMonthStat()
-{
-STG_LOCKER lock(&mutex);
-time_t tt = stgTime - 3600;
-struct tm t1;
-localtime_r(&tt, &t1);
-
-UserStat stat(properties.GetStat());
-if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
- {
- WriteServLog("Cannot write month stat for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
- printfd(__FILE__, "%s\n", store->GetStrError().c_str());
- return -1;
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth)
-{
-STG_LOCKER lock(&mutex);
-/*
- * Authorize user. It only means that user will be authorized. Nothing more.
- * User can be connected or disconnected while authorized.
- * Example: user is authorized but disconnected due to 0 money or blocking
- */
-
-/*
- * TODO: in fact "authorization" means allowing access to a service. What we
- * call "authorization" here, int STG, is "authentication". So this should be
- * fixed in future.
- */
-
-/*
- * Prevent double authorization by identical authorizers
- */
-if (authorizedBy.find(auth) != authorizedBy.end())
- return 0;
-
-if (!ip)
- return -1;
-
-dirsFromBits(enabledDirs, dirs);
-
-if (!authorizedBy.empty())
- {
- if (currIP != ip)
- {
- // We are already authorized, but with different IP address
- errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
- return -1;
- }
-
- User * u = NULL;
- if (!users->FindByIPIdx(ip, &u))
- {
- // Address presents in IP-index.
- // If it's not our IP - report it.
- if (u != this)
- {
- errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
- return -1;
- }
- }
- }
-else
- {
- if (users->IsIPInIndex(ip))
- {
- // Address is already present in IP-index.
- errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
- return -1;
- }
-
- if (ips.ConstData().find(ip))
- {
- currIP = ip;
- lastIPForDisconnect = currIP;
- }
- else
- {
- printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().toString().c_str());
- errorStr = "IP address " + inet_ntostring(ip) + " does not belong to user " + login;
- return -1;
- }
- }
-
-if (authorizedBy.empty())
- authorizedModificationTime = stgTime;
-authorizedBy.insert(auth);
-
-ScanMessage();
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void UserImpl::Unauthorize(const Auth * auth, const std::string & reason)
-{
-STG_LOCKER lock(&mutex);
-/*
- * Authorizer tries to unauthorize user, that was not authorized by it
- */
-if (!authorizedBy.erase(auth))
- return;
-
-authorizedModificationTime = stgTime;
-
-if (authorizedBy.empty())
- {
- lastDisconnectReason = reason;
- lastIPForDisconnect = currIP;
- currIP = 0; // DelUser in traffcounter
- if (connected)
- Disconnect(false, "not authorized");
- return;
- }
-}
-//-----------------------------------------------------------------------------
-bool UserImpl::IsAuthorizedBy(const Auth * auth) const
-{
-STG_LOCKER lock(&mutex);
-// Is this user authorized by specified authorizer?
-return authorizedBy.find(auth) != authorizedBy.end();
-}
-//-----------------------------------------------------------------------------
-std::vector<std::string> UserImpl::GetAuthorizers() const
-{
- STG_LOCKER lock(&mutex);
- std::vector<std::string> list;
- std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), [](const auto auth){ return auth->GetVersion(); });
- return list;
-}
-//-----------------------------------------------------------------------------
-void UserImpl::Connect(bool fakeConnect)
-{
-/*
- * Connect user to Internet. This function is differ from Authorize() !!!
- */
-
-STG_LOCKER lock(&mutex);
-
-if (!fakeConnect)
- {
- std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
-
- if (access(scriptOnConnect.c_str(), X_OK) == 0)
- {
- std::string dirs = dirsToString(enabledDirs);
-
- std::string scriptOnConnectParams;
- strprintf(&scriptOnConnectParams,
- "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
- scriptOnConnect.c_str(),
- login.c_str(),
- inet_ntostring(currIP).c_str(),
- cash.ConstData(),
- id,
- dirs.c_str());
-
- std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
- while (it != settings->GetScriptParams().end())
- {
- scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
- ++it;
- }
-
- ScriptExec(scriptOnConnectParams.c_str());
- }
- else
- {
- WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
- }
-
- connected = true;
- }
-
-if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, currIP))
- {
- WriteServLog("Cannot write connect for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- }
-
-if (!fakeConnect)
- lastIPForDisconnect = currIP;
-}
-//-----------------------------------------------------------------------------
-void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason)
-{
-/*
- * Disconnect user from Internet. This function is differ from UnAuthorize() !!!
- */
-
-STG_LOCKER lock(&mutex);
-
-if (!lastIPForDisconnect)
- {
- printfd(__FILE__, "lastIPForDisconnect\n");
- return;
- }
-
-if (!fakeDisconnect)
- {
- lastDisconnectReason = reason;
- std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
-
- if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
- {
- std::string dirs = dirsToString(enabledDirs);
-
- std::string scriptOnDisonnectParams;
- strprintf(&scriptOnDisonnectParams,
- "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
- scriptOnDisonnect.c_str(),
- login.c_str(),
- inet_ntostring(lastIPForDisconnect).c_str(),
- cash.ConstData(),
- id,
- dirs.c_str());
-
- std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
- while (it != settings->GetScriptParams().end())
- {
- scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
- ++it;
- }
-
- ScriptExec(scriptOnDisonnectParams.c_str());
- }
- else
- {
- WriteServLog("Script OnDisconnect cannot be executed. File not found.");
- }
-
- connected = false;
- }
-
-std::string reasonMessage(reason);
-if (!lastDisconnectReason.empty())
- reasonMessage += ": " + lastDisconnectReason;
-
-if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
- cash, freeMb, reasonMessage))
- {
- WriteServLog("Cannot write disconnect for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- }
-
-if (!fakeDisconnect)
- lastIPForDisconnect = 0;
-
-sessionUpload.reset();
-sessionDownload.reset();
-sessionUploadModTime = stgTime;
-sessionDownloadModTime = stgTime;
-}
-//-----------------------------------------------------------------------------
-void UserImpl::Run()
-{
-STG_LOCKER lock(&mutex);
-
-if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
- {
- printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str());
- WriteStat();
- }
-if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
- {
- WriteServLog("User: %s. Credit expired.", login.c_str());
- credit = 0;
- creditExpire = 0;
- WriteConf();
- }
-
-if (passive.ConstData()
- && (stgTime % 30 == 0)
- && (passiveTime.ModificationTime() != stgTime))
- {
- passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
- printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
- }
-
-if (!authorizedBy.empty())
- {
- if (connected)
- properties.Stat().lastActivityTime = stgTime;
-
- if (!connected && IsInetable())
- Connect();
-
- if (connected && !IsInetable())
- {
- if (disabled)
- Disconnect(false, "disabled");
- else if (passive)
- Disconnect(false, "passive");
- else
- Disconnect(false, "no cash");
- }
-
- if (stgTime - lastScanMessages > 10)
- {
- ScanMessage();
- lastScanMessages = stgTime;
- }
- }
-else
- {
- if (connected)
- Disconnect(false, "not authorized");
- }
-
-}
-//-----------------------------------------------------------------------------
-void UserImpl::UpdatePingTime(time_t t)
-{
-STG_LOCKER lock(&mutex);
-if (t)
- pingTime = t;
-else
- pingTime = stgTime;
-}
-//-----------------------------------------------------------------------------
-bool UserImpl::IsInetable()
-{
-if (disabled || passive)
- return false;
-
-if (settings->GetFreeMbAllowInet())
- {
- if (freeMb >= 0)
- return true;
- }
-
-if (settings->GetShowFeeInCash() || tariff == NULL)
- return (cash >= -credit);
-
-return (cash - tariff->GetFee() >= -credit);
-}
-//-----------------------------------------------------------------------------
-std::string UserImpl::GetEnabledDirs() const
-{
-return dirsToString(enabledDirs);
-}
-//-----------------------------------------------------------------------------
-#ifdef TRAFF_STAT_WITH_PORTS
-void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
-#else
-void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
-#endif
-{
-STG_LOCKER lock(&mutex);
-
-if (!connected || tariff == NULL)
- return;
-
-double cost = 0;
-DirTraff dt(up);
-
-int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
-int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
-
-dt[dir] += len;
-
-int tt = tariff->GetTraffType();
-if (tt == Tariff::TRAFF_UP ||
- tt == Tariff::TRAFF_UP_DOWN ||
- // Check NEW traff data
- (tt == Tariff::TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
- {
- double dc = 0;
- if (traff < threshold &&
- traff + len >= threshold)
- {
- // cash = partBeforeThreshold * priceBeforeThreshold +
- // partAfterThreshold * priceAfterThreshold
- int64_t before = threshold - traff; // Chunk part before threshold
- int64_t after = len - before; // Chunk part after threshold
- dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
- down.ConstData()[dir],
- dir,
- stgTime) * before +
- tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
- down.ConstData()[dir],
- dir,
- stgTime) * after;
- }
- else
- {
- dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
- down.ConstData()[dir],
- dir,
- stgTime) * len;
- }
-
- if (freeMb.ConstData() <= 0) // FreeMb is exhausted
- cost = dc;
- else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
- cost = dc - freeMb.ConstData();
-
- // Direct access to internal data structures via friend-specifier
- properties.Stat().freeMb -= dc;
- properties.Stat().cash -= cost;
- cash.ModifyTime();
- freeMb.ModifyTime();
- }
-
-up = dt;
-sessionUpload[dir] += len;
-sessionUploadModTime = stgTime;
-
-//Add detailed stat
-
-if (!settings->GetWriteFreeMbTraffCost() &&
- freeMb.ConstData() >= 0)
- cost = 0;
-
-#ifdef TRAFF_STAT_WITH_PORTS
-IPDirPair idp(ip, dir, port);
-#else
-IPDirPair idp(ip, dir);
-#endif
-
-std::map<IPDirPair, StatNode>::iterator lb;
-lb = traffStat.lower_bound(idp);
-if (lb == traffStat.end() || lb->first != idp)
- {
- traffStat.insert(lb,
- std::make_pair(idp,
- StatNode(len, 0, cost)));
- }
-else
- {
- lb->second.cash += cost;
- lb->second.up += len;
- }
-}
-//-----------------------------------------------------------------------------
-#ifdef TRAFF_STAT_WITH_PORTS
-void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
-#else
-void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
-#endif
-{
-STG_LOCKER lock(&mutex);
-
-if (!connected || tariff == NULL)
- return;
-
-double cost = 0;
-DirTraff dt(down);
-
-int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
-int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
-
-dt[dir] += len;
-
-int tt = tariff->GetTraffType();
-if (tt == Tariff::TRAFF_DOWN ||
- tt == Tariff::TRAFF_UP_DOWN ||
- // Check NEW traff data
- (tt == Tariff::TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
- {
- double dc = 0;
- if (traff < threshold &&
- traff + len >= threshold)
- {
- // cash = partBeforeThreshold * priceBeforeThreshold +
- // partAfterThreshold * priceAfterThreshold
- int64_t before = threshold - traff; // Chunk part before threshold
- int64_t after = len - before; // Chunk part after threshold
- dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
- down.ConstData()[dir], // Traff before chunk
- dir,
- stgTime) * before +
- tariff->GetPriceWithTraffType(up.ConstData()[dir],
- dt[dir], // Traff after chunk
- dir,
- stgTime) * after;
- }
- else
- {
- dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
- down.ConstData()[dir],
- dir,
- stgTime) * len;
- }
-
- if (freeMb.ConstData() <= 0) // FreeMb is exhausted
- cost = dc;
- else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
- cost = dc - freeMb.ConstData();
-
- properties.Stat().freeMb -= dc;
- properties.Stat().cash -= cost;
- cash.ModifyTime();
- freeMb.ModifyTime();
- }
-
-down = dt;
-sessionDownload[dir] += len;
-sessionDownloadModTime = stgTime;
-
-//Add detailed stat
-
-if (!settings->GetWriteFreeMbTraffCost() &&
- freeMb.ConstData() >= 0)
- cost = 0;
-
-#ifdef TRAFF_STAT_WITH_PORTS
-IPDirPair idp(ip, dir, port);
-#else
-IPDirPair idp(ip, dir);
-#endif
-
-std::map<IPDirPair, StatNode>::iterator lb;
-lb = traffStat.lower_bound(idp);
-if (lb == traffStat.end() || lb->first != idp)
- {
- traffStat.insert(lb,
- std::make_pair(idp,
- StatNode(0, len, cost)));
- }
-else
- {
- lb->second.cash += cost;
- lb->second.down += len;
- }
-}
-//-----------------------------------------------------------------------------
-void UserImpl::AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-currIP.AddBeforeNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-currIP.DelBeforeNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-currIP.AddAfterNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-currIP.DelAfterNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-connected.AddBeforeNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-connected.DelBeforeNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-connected.AddAfterNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier)
-{
-STG_LOCKER lock(&mutex);
-connected.DelAfterNotifier(notifier);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::OnAdd()
-{
-STG_LOCKER lock(&mutex);
-
-std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
-
-if (access(scriptOnAdd.c_str(), X_OK) == 0)
- {
- std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
-
- ScriptExec(scriptOnAddParams.c_str());
- }
-else
- {
- WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
- }
-}
-//-----------------------------------------------------------------------------
-void UserImpl::OnDelete()
-{
-STG_LOCKER lock(&mutex);
-
-std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
-
-if (access(scriptOnDel.c_str(), X_OK) == 0)
- {
- std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
-
- ScriptExec(scriptOnDelParams.c_str());
- }
-else
- {
- WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
- }
-
-Run();
-}
-//-----------------------------------------------------------------------------
-int UserImpl::WriteDetailStat(bool hard)
-{
-printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
-
-if (!traffStatSaved.second.empty())
- {
- if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
- {
- printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write detail stat from queue\n");
- WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- return -1;
- }
- traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
- }
-
-TraffStat ts;
-
- {
- STG_LOCKER lock(&mutex);
- ts.swap(traffStat);
- }
-
-printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size());
-
-if (ts.size() && !disabledDetailStat)
- {
- if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
- {
- printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write current detail stat\n");
- WriteServLog("Cannot write detail stat for user %s.", login.c_str());
- WriteServLog("%s", store->GetStrError().c_str());
- if (!hard)
- {
- printfd(__FILE__, "UserImpl::WriteDetailStat() - pushing detail stat to queue\n");
- STG_LOCKER lock(&mutex);
- traffStatSaved.second.swap(ts);
- traffStatSaved.first = lastWriteDetailedStat;
- }
- return -1;
- }
- }
-lastWriteDetailedStat = stgTime;
-return 0;
-}
-//-----------------------------------------------------------------------------
-double UserImpl::GetPassiveTimePart() const
-{
-STG_LOCKER lock(&mutex);
-
-static int daysInMonth[12] =
-{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-struct tm tms;
-time_t t = stgTime;
-localtime_r(&t, &tms);
-
-time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
-
-if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
- {
- // Leap year
- secMonth += 24 * 3600;
- }
-
-time_t dt = secMonth - passiveTime;
-
-if (dt < 0)
- dt = 0;
-
-return static_cast<double>(dt) / secMonth;
-}
-//-----------------------------------------------------------------------------
-void UserImpl::SetPassiveTimeAsNewUser()
-{
-STG_LOCKER lock(&mutex);
-
-time_t t = stgTime;
-struct tm tm;
-localtime_r(&t, &tm);
-int daysCurrMon = DaysInCurrentMonth();
-double pt = tm.tm_mday - 1;
-pt /= daysCurrMon;
-
-passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
-}
-//-----------------------------------------------------------------------------
-void UserImpl::MidnightResetSessionStat()
-{
-STG_LOCKER lock(&mutex);
-
-if (connected)
- {
- Disconnect(true, "fake");
- Connect(true);
- }
-}
-//-----------------------------------------------------------------------------
-void UserImpl::ProcessNewMonth()
-{
-STG_LOCKER lock(&mutex);
-// Reset traff
-if (connected)
- Disconnect(true, "fake");
-
-WriteMonthStat();
-
-properties.Stat().monthUp.reset();
-properties.Stat().monthDown.reset();
-
-if (connected)
- Connect(true);
-
-// Set new tariff
-if (nextTariff.ConstData() != "")
- {
- const Tariff * nt = tariffs->FindByName(nextTariff);
- if (nt == NULL)
- {
- WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
- login.c_str(), properties.tariffName.Get().c_str());
- }
- else
- {
- std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime);
- if (message.empty())
- {
- properties.tariffName.Set(nextTariff, *sysAdmin, login, *store);
- }
- else
- {
- WriteServLog("Tariff change is prohibited for user %s. %s",
- login.c_str(),
- message.c_str());
- }
- }
- ResetNextTariff();
- WriteConf();
- }
-}
-//-----------------------------------------------------------------------------
-void UserImpl::ProcessDayFeeSpread()
-{
-STG_LOCKER lock(&mutex);
-
-if (passive.ConstData() || tariff == NULL)
- return;
-
-if (tariff->GetPeriod() != Tariff::MONTH)
- return;
-
-double fee = tariff->GetFee() / DaysInCurrentMonth();
-
-if (std::fabs(fee) < 1.0e-3)
- return;
-
-double c = cash;
-switch (settings->GetFeeChargeType())
- {
- case 0:
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- case 1:
- if (c + credit >= 0)
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- case 2:
- if (c + credit >= fee)
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- case 3:
- if (c >= 0)
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- }
-ResetPassiveTime();
-}
-//-----------------------------------------------------------------------------
-void UserImpl::ProcessDayFee()
-{
-STG_LOCKER lock(&mutex);
-
-if (tariff == NULL)
- return;
-
-if (tariff->GetPeriod() != Tariff::MONTH)
- return;
-
-double passiveTimePart = 1.0;
-if (!settings->GetFullFee())
- {
- passiveTimePart = GetPassiveTimePart();
- }
-else
- {
- if (passive.ConstData())
- {
- printfd(__FILE__, "Don't charge fee `cause we are passive\n");
- return;
- }
- }
-double fee = tariff->GetFee() * passiveTimePart;
-
-ResetPassiveTime();
-
-if (std::fabs(fee) < 1.0e-3)
- {
- SetPrepaidTraff();
- return;
- }
-
-double c = cash;
-printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
- login.c_str(),
- cash.ConstData(),
- credit.ConstData(),
- tariff->GetFee(),
- passiveTimePart,
- fee);
-switch (settings->GetFeeChargeType())
- {
- case 0:
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- break;
- case 1:
- if (c + credit >= 0)
- {
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- }
- break;
- case 2:
- if (c + credit >= fee)
- {
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- }
- break;
- case 3:
- if (c >= 0)
- {
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- }
- break;
- }
-}
-//-----------------------------------------------------------------------------
-void UserImpl::ProcessDailyFee()
-{
-STG_LOCKER lock(&mutex);
-
-if (passive.ConstData() || tariff == NULL)
- return;
-
-if (tariff->GetPeriod() != Tariff::DAY)
- return;
-
-double fee = tariff->GetFee();
-
-if (fee == 0.0)
- return;
-
-double c = cash;
-switch (settings->GetFeeChargeType())
- {
- case 0:
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- case 1:
- if (c + credit >= 0)
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- case 2:
- if (c + credit >= fee)
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- break;
- }
-ResetPassiveTime();
-}
-//-----------------------------------------------------------------------------
-void UserImpl::ProcessServices()
-{
-struct tm tms;
-time_t t = stgTime;
-localtime_r(&t, &tms);
-
-double passiveTimePart = 1.0;
-if (!settings->GetFullFee())
- {
- passiveTimePart = GetPassiveTimePart();
- }
-else
- {
- if (passive.ConstData())
- {
- printfd(__FILE__, "Don't charge fee `cause we are passive\n");
- return;
- }
- }
-
-for (size_t i = 0; i < properties.Conf().services.size(); ++i)
- {
- ServiceConf conf;
- if (m_services.Find(properties.Conf().services[i], &conf))
- continue;
- if (conf.payDay == tms.tm_mday ||
- (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
- {
- double c = cash;
- double fee = conf.cost * passiveTimePart;
- printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
- login.c_str(),
- cash.ConstData(),
- credit.ConstData(),
- tariff->GetFee(),
- passiveTimePart,
- fee);
- switch (settings->GetFeeChargeType())
- {
- case 0:
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- break;
- case 1:
- if (c + credit >= 0)
- {
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- }
- break;
- case 2:
- if (c + credit >= fee)
- {
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- }
- break;
- case 3:
- if (c >= 0)
- {
- properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
- SetPrepaidTraff();
- }
- break;
- }
- }
- }
-}
-//-----------------------------------------------------------------------------
-void UserImpl::SetPrepaidTraff()
-{
-if (tariff != NULL)
- properties.freeMb.Set(tariff->GetFree(), *sysAdmin, login, *store, "Prepaid traffic");
-}
-//-----------------------------------------------------------------------------
-int UserImpl::AddMessage(Message * msg)
-{
-STG_LOCKER lock(&mutex);
-
-if (SendMessage(*msg))
- {
- if (store->AddMessage(msg, login))
- {
- errorStr = store->GetStrError();
- WriteServLog("Error adding message: '%s'", errorStr.c_str());
- printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
- return -1;
- }
- messages.push_back(*msg);
- }
-else
- {
- if (msg->header.repeat > 0)
- {
- msg->header.repeat--;
- #ifndef DEBUG
- //TODO: gcc v. 4.x generate ICE on x86_64
- msg->header.lastSendTime = static_cast<int>(time(NULL));
- #else
- msg->header.lastSendTime = static_cast<int>(stgTime);
- #endif
- if (store->AddMessage(msg, login))
- {
- errorStr = store->GetStrError();
- WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
- printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
- return -1;
- }
- messages.push_back(*msg);
- }
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UserImpl::SendMessage(Message & msg) const
-{
-// No lock `cause we are already locked from caller
-int ret = -1;
-std::set<const Auth*>::iterator it(authorizedBy.begin());
-while (it != authorizedBy.end())
- {
- if (!(*it++)->SendMessage(msg, currIP))
- ret = 0;
- }
-if (!ret)
- {
-#ifndef DEBUG
- //TODO: gcc v. 4.x generate ICE on x86_64
- msg.header.lastSendTime = static_cast<int>(time(NULL));
-#else
- msg.header.lastSendTime = static_cast<int>(stgTime);
-#endif
- msg.header.repeat--;
- }
-return ret;
-}
-//-----------------------------------------------------------------------------
-void UserImpl::ScanMessage()
-{
-// No lock `cause we are already locked from caller
-// We need not check for the authorizedBy `cause it has already checked by caller
-
-auto it = messages.begin();
-while (it != messages.end())
- {
- if (settings->GetMessageTimeout() > 0 &&
- difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
- {
- // Timeout exceeded
- if (store->DelMessage(it->header.id, login))
- {
- WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
- printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
- }
- messages.erase(it++);
- continue;
- }
- if (it->GetNextSendTime() <= stgTime)
- {
- if (SendMessage(*it))
- {
- // We need to check all messages in queue for timeout
- ++it;
- continue;
- }
- if (it->header.repeat < 0)
- {
- if (store->DelMessage(it->header.id, login))
- {
- WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
- printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
- }
- messages.erase(it++);
- }
- else
- {
- if (store->EditMessage(*it, login))
- {
- WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
- printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
- }
- ++it;
- }
- }
- else
- {
- ++it;
- }
- }
-}
-//-----------------------------------------------------------------------------
-std::string UserImpl::GetParamValue(const std::string & name) const
-{
- std::string lowerName = ToLower(name);
- if (lowerName == "id")
- {
- std::ostringstream stream;
- stream << id;
- return stream.str();
- }
- if (lowerName == "login") return login;
- if (lowerName == "currip") return currIP.ToString();
- if (lowerName == "enableddirs") return GetEnabledDirs();
- if (lowerName == "tariff") return properties.tariffName;
- if (properties.Exists(lowerName))
- return properties.GetPropertyValue(lowerName);
- else
- {
- WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
- return "";
- }
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void STG::CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
-{
-if (newPassive && !oldPassive && user->tariff != NULL)
- user->properties.cash.Set(user->cash - user->tariff->GetPassiveCost(),
- *user->sysAdmin,
- user->login,
- *user->store,
- "Freeze");
-}
-//-----------------------------------------------------------------------------
-void STG::CHG_DISABLED_NOTIFIER::Notify(const int & oldValue, const int & newValue)
-{
-if (oldValue && !newValue && user->GetConnected())
- user->Disconnect(false, "disabled");
-else if (!oldValue && newValue && user->IsInetable())
- user->Connect(false);
-}
-//-----------------------------------------------------------------------------
-void STG::CHG_TARIFF_NOTIFIER::Notify(const std::string &, const std::string & newTariff)
-{
-STG_LOCKER lock(&user->mutex);
-if (user->settings->GetReconnectOnTariffChange() && user->connected)
- user->Disconnect(false, "Change tariff");
-user->tariff = user->tariffs->FindByName(newTariff);
-if (user->settings->GetReconnectOnTariffChange() &&
- !user->authorizedBy.empty() &&
- user->IsInetable())
- {
- // This notifier gets called *before* changing the tariff, and in Connect we want to see new tariff name.
- user->properties.Conf().tariffName = newTariff;
- user->Connect(false);
- }
-}
-//-----------------------------------------------------------------------------
-void STG::CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
-{
-user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
-user->lastCashAdd = newCash - oldCash;
-}
-//-----------------------------------------------------------------------------
-void STG::CHG_IPS_NOTIFIER::Notify(const UserIPs & from, const UserIPs & to)
-{
-printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.toString().c_str(), to.toString().c_str());
-if (user->connected)
- user->Disconnect(false, "Change IP");
-if (!user->authorizedBy.empty() && user->IsInetable())
- user->Connect(false);
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include "stg/user.h"
-#include "stg/user_stat.h"
-#include "stg/user_conf.h"
-#include "stg/user_ips.h"
-#include "stg/user_property.h"
-#include "stg/auth.h"
-#include "stg/message.h"
-#include "stg/noncopyable.h"
-#include "stg/const.h"
-
-#include <vector>
-#include <string>
-#include <set>
-
-#include <ctime>
-#include <cstdint>
-
-namespace STG
-{
-
-//-----------------------------------------------------------------------------
-struct Tariff;
-struct Tariffs;
-struct Admin;
-class UserImpl;
-#ifdef USE_ABSTRACT_SETTINGS
-struct Settings;
-#else
-class SettingsImpl;
-#endif
-//-----------------------------------------------------------------------------
-class CHG_PASSIVE_NOTIFIER : public PropertyNotifierBase<int> {
- public:
- explicit CHG_PASSIVE_NOTIFIER(UserImpl * u) : user(u) {}
- void Notify(const int & oldPassive, const int & newPassive);
-
- private:
- UserImpl * user;
-};
-//-----------------------------------------------------------------------------
-class CHG_DISABLED_NOTIFIER : public PropertyNotifierBase<int> {
-public:
- explicit CHG_DISABLED_NOTIFIER(UserImpl * u) : user(u) {}
- void Notify(const int & oldValue, const int & newValue);
-
-private:
- UserImpl * user;
-};
-//-----------------------------------------------------------------------------
-class CHG_TARIFF_NOTIFIER : public PropertyNotifierBase<std::string> {
-public:
- explicit CHG_TARIFF_NOTIFIER(UserImpl * u) : user(u) {}
- void Notify(const std::string & oldTariff, const std::string & newTariff);
-
-private:
- UserImpl * user;
-};
-//-----------------------------------------------------------------------------
-class CHG_CASH_NOTIFIER : public PropertyNotifierBase<double> {
-public:
- explicit CHG_CASH_NOTIFIER(UserImpl * u) : user(u) {}
- void Notify(const double & oldCash, const double & newCash);
-
-private:
- UserImpl * user;
-};
-//-----------------------------------------------------------------------------
-class CHG_IPS_NOTIFIER : public PropertyNotifierBase<UserIPs> {
-public:
- explicit CHG_IPS_NOTIFIER(UserImpl * u) : user(u) {}
- void Notify(const UserIPs & oldIPs, const UserIPs & newIPs);
-
-private:
- UserImpl * user;
-};
-//-----------------------------------------------------------------------------
-class UserImpl : public User {
- friend class CHG_PASSIVE_NOTIFIER;
- friend class CHG_DISABLED_NOTIFIER;
- friend class CHG_TARIFF_NOTIFIER;
- friend class CHG_CASH_NOTIFIER;
- friend class CHG_IPS_NOTIFIER;
- public:
-#ifdef USE_ABSTRACT_SETTINGS
- using Settings = STG::Settings;
-#else
- using Settings = STG::SettingsImpl;
-#endif
- UserImpl(const Settings * settings,
- const Store * store,
- const Tariffs * tariffs,
- const Admin * sysAdmin,
- const Users * u,
- const Services & svcs);
- UserImpl(const UserImpl & u);
- virtual ~UserImpl();
-
- int ReadConf();
- int ReadStat();
- int WriteConf() override;
- int WriteStat() override;
- int WriteMonthStat();
-
- const std::string & GetLogin() const override { return login; }
- void SetLogin(std::string const & l);
-
- uint32_t GetCurrIP() const override{ return currIP; }
- time_t GetCurrIPModificationTime() const override { return currIP.ModificationTime(); }
-
- void AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier) override;
- void DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier) override;
-
- void AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier) override;
- void DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier) override;
-
- void AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier) override;
- void DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier) override;
-
- void AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier) override;
- void DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier) override;
-
- int GetID() const override { return id; }
-
- double GetPassiveTimePart() const override;
- void ResetPassiveTime() { passiveTime = 0; }
- void SetPassiveTimeAsNewUser();
-
- int WriteDetailStat(bool hard = false);
-
- const Tariff * GetTariff() const override { return tariff; }
- void ResetNextTariff() override { nextTariff = ""; }
-
- #ifdef TRAFF_STAT_WITH_PORTS
- void AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len);
- void AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len);
- #else
- void AddTraffStatU(int dir, uint32_t ip, uint32_t len);
- void AddTraffStatD(int dir, uint32_t ip, uint32_t len);
- #endif
-
- const DirTraff & GetSessionUpload() const override { return sessionUpload; }
- const DirTraff & GetSessionDownload() const override { return sessionDownload; }
- time_t GetSessionUploadModificationTime() const override { return sessionUploadModTime; }
- time_t GetSessionDownloadModificationTime() const override { return sessionDownloadModTime; }
-
- bool GetConnected() const override { return connected; }
- time_t GetConnectedModificationTime() const override { return connected.ModificationTime(); }
- const std::string & GetLastDisconnectReason() const override { return lastDisconnectReason; }
- int GetAuthorized() const override { return static_cast<int>(authorizedBy.size()); }
- time_t GetAuthorizedModificationTime() const override { return authorizedModificationTime; }
- int Authorize(uint32_t ip, uint32_t enabledDirs, const Auth * auth);
- void Unauthorize(const Auth * auth,
- const std::string & reason = std::string());
- bool IsAuthorizedBy(const Auth * auth) const override;
- std::vector<std::string> GetAuthorizers() const override;
-
- int AddMessage(Message * msg) override;
-
- void UpdatePingTime(time_t t = 0) override;
- time_t GetPingTime() const override { return pingTime; }
-
- void Run() override;
-
- const std::string & GetStrError() const override { return errorStr; }
-
- UserProperties & GetProperties() override { return properties; }
- const UserProperties & GetProperties() const override { return properties; }
-
- void SetDeleted() override { deleted = true; }
- bool GetDeleted() const override { return deleted; }
-
- time_t GetLastWriteStatTime() const override { return lastWriteStat; }
-
- void MidnightResetSessionStat();
- void ProcessDayFee();
- void ProcessDayFeeSpread();
- void ProcessNewMonth();
- void ProcessDailyFee();
- void ProcessServices();
-
- bool IsInetable() override;
- std::string GetEnabledDirs() const override;
-
- void OnAdd() override;
- void OnDelete() override;
-
- virtual std::string GetParamValue(const std::string & name) const override;
-
- private:
- UserImpl & operator=(const UserImpl & rvalue);
-
- void Init();
-
- const Users* users;
- UserProperties properties;
- STG::Logger& WriteServLog;
-
- void Connect(bool fakeConnect = false);
- void Disconnect(bool fakeDisconnect, const std::string & reason);
- int SaveMonthStat(int month, int year);
-
- void SetPrepaidTraff();
-
- int SendMessage(Message & msg) const;
- void ScanMessage();
-
- time_t lastScanMessages;
-
- std::string login;
- int id;
- bool __connected;
- UserProperty<bool> connected;
-
- bool enabledDirs[DIR_NUM];
-
- uint32_t __currIP; // Current user's ip
- UserProperty<uint32_t> currIP;
-
- uint32_t lastIPForDisconnect; // User's ip after unauth but before disconnect
- std::string lastDisconnectReason;
-
- time_t pingTime;
-
- const Admin * sysAdmin;
- const Store * store;
-
- const Tariffs * tariffs;
- const Tariff * tariff;
-
- const Services & m_services;
-
- TraffStat traffStat;
- std::pair<time_t, TraffStat> traffStatSaved;
-
- const Settings * settings;
-
- std::set<const Auth *> authorizedBy;
- time_t authorizedModificationTime;
-
- std::vector<Message> messages;
-
- bool deleted;
-
- time_t lastWriteStat;
- time_t lastWriteDetailedStat;
-
- // Properties
- UserProperty<double> & cash;
- UserProperty<DirTraff> & up;
- UserProperty<DirTraff> & down;
- UserProperty<double> & lastCashAdd;
- UserProperty<time_t> & passiveTime;
- UserProperty<time_t> & lastCashAddTime;
- UserProperty<double> & freeMb;
- UserProperty<time_t> & lastActivityTime;
- UserProperty<std::string> & password;
- UserProperty<int> & passive;
- UserProperty<int> & disabled;
- UserProperty<int> & disabledDetailStat;
- UserProperty<int> & alwaysOnline;
- UserProperty<std::string> & tariffName;
- UserProperty<std::string> & nextTariff;
- UserProperty<std::string> & address;
- UserProperty<std::string> & note;
- UserProperty<std::string> & group;
- UserProperty<std::string> & email;
- UserProperty<std::string> & phone;
- UserProperty<std::string> & realName;
- UserProperty<double> & credit;
- UserProperty<time_t> & creditExpire;
- UserProperty<UserIPs> & ips;
- UserProperty<std::string> & userdata0;
- UserProperty<std::string> & userdata1;
- UserProperty<std::string> & userdata2;
- UserProperty<std::string> & userdata3;
- UserProperty<std::string> & userdata4;
- UserProperty<std::string> & userdata5;
- UserProperty<std::string> & userdata6;
- UserProperty<std::string> & userdata7;
- UserProperty<std::string> & userdata8;
- UserProperty<std::string> & userdata9;
-
- // End properties
-
- DirTraff sessionUpload;
- DirTraff sessionDownload;
- time_t sessionUploadModTime;
- time_t sessionDownloadModTime;
-
- CHG_PASSIVE_NOTIFIER passiveNotifier;
- CHG_DISABLED_NOTIFIER disabledNotifier;
- CHG_TARIFF_NOTIFIER tariffNotifier;
- CHG_CASH_NOTIFIER cashNotifier;
- CHG_IPS_NOTIFIER ipNotifier;
-
- mutable pthread_mutex_t mutex;
-
- std::string errorStr;
-};
-//-----------------------------------------------------------------------------
-
-}
+++ /dev/null
-#include "stg/user_property.h"
-
-STG::UserProperties::UserProperties(const Settings& s)
- : cash (stat.cash, "cash", false, true, s, properties),
- up (stat.monthUp, "upload", false, true, s, properties),
- down (stat.monthDown, "download", false, true, s, properties),
- lastCashAdd (stat.lastCashAdd, "lastCashAdd", false, true, s, properties),
- passiveTime (stat.passiveTime, "passiveTime", false, true, s, properties),
- lastCashAddTime (stat.lastCashAddTime, "lastCashAddTime", false, true, s, properties),
- freeMb (stat.freeMb, "freeMb", false, true, s, properties),
- lastActivityTime(stat.lastActivityTime, "lastActivityTime", false, true, s, properties),
-
- password (conf.password, "password", true, false, s, properties),
- passive (conf.passive, "passive", false, false, s, properties),
- disabled (conf.disabled, "disabled", false, false, s, properties),
- disabledDetailStat(conf.disabledDetailStat, "DisabledDetailStat", false, false, s, properties),
- alwaysOnline(conf.alwaysOnline, "alwaysOnline", false, false, s, properties),
- tariffName (conf.tariffName, "tariffName", false, false, s, properties),
- nextTariff (conf.nextTariff, "nextTariff", false, false, s, properties),
- address (conf.address, "address", false, false, s, properties),
- note (conf.note, "note", false, false, s, properties),
- group (conf.group, "group", false, false, s, properties),
- email (conf.email, "email", false, false, s, properties),
- phone (conf.phone, "phone", false, false, s, properties),
- realName (conf.realName, "realName", false, false, s, properties),
- credit (conf.credit, "credit", false, false, s, properties),
- creditExpire(conf.creditExpire, "creditExpire", false, false, s, properties),
- ips (conf.ips, "ips", false, false, s, properties),
- userdata0 (conf.userdata[0], "userdata0", false, false, s, properties),
- userdata1 (conf.userdata[1], "userdata1", false, false, s, properties),
- userdata2 (conf.userdata[2], "userdata2", false, false, s, properties),
- userdata3 (conf.userdata[3], "userdata3", false, false, s, properties),
- userdata4 (conf.userdata[4], "userdata4", false, false, s, properties),
- userdata5 (conf.userdata[5], "userdata5", false, false, s, properties),
- userdata6 (conf.userdata[6], "userdata6", false, false, s, properties),
- userdata7 (conf.userdata[7], "userdata7", false, false, s, properties),
- userdata8 (conf.userdata[8], "userdata8", false, false, s, properties),
- userdata9 (conf.userdata[9], "userdata9", false, false, s, properties)
-{}
+++ /dev/null
-/*
- * 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
- */
-
-/*
- * Date: 27.10.2002
- */
-
-/*
- * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#include <pthread.h>
-
-#include <csignal>
-#include <cassert>
-#include <algorithm>
-#include <utility>
-#include <string>
-#include <vector>
-
-#include "stg/settings.h"
-#include "stg/common.h"
-
-#include "users_impl.h"
-#include "stg_timer.h"
-
-extern volatile time_t stgTime;
-
-using STG::UsersImpl;
-
-//-----------------------------------------------------------------------------
-UsersImpl::UsersImpl(SettingsImpl * s, Store * st,
- Tariffs * t, Services & svcs,
- const Admin& sa)
- : settings(s),
- tariffs(t),
- m_services(svcs),
- store(st),
- sysAdmin(sa),
- WriteServLog(Logger::get()),
- nonstop(false),
- isRunning(false),
- handle(0)
-{
-pthread_mutexattr_t attr;
-pthread_mutexattr_init(&attr);
-pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-pthread_mutex_init(&mutex, &attr);
-}
-//-----------------------------------------------------------------------------
-UsersImpl::~UsersImpl()
-{
-pthread_mutex_destroy(&mutex);
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::FindByNameNonLock(const std::string & login, user_iter * user)
-{
-const std::map<std::string, user_iter>::const_iterator iter(loginIndex.find(login));
-if (iter == loginIndex.end())
- return -1;
-if (user)
- *user = iter->second;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::FindByNameNonLock(const std::string & login, const_user_iter * user) const
-{
-const std::map<std::string, user_iter>::const_iterator iter(loginIndex.find(login));
-if (iter == loginIndex.end())
- return -1;
-if (user)
- *user = iter->second;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::FindByName(const std::string & login, UserPtr * user)
-{
-STG_LOCKER lock(&mutex);
-user_iter u;
-if (FindByNameNonLock(login, &u))
- return -1;
-*user = &(*u);
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::FindByName(const std::string & login, ConstUserPtr * user) const
-{
-STG_LOCKER lock(&mutex);
-const_user_iter u;
-if (FindByNameNonLock(login, &u))
- return -1;
-*user = &(*u);
-return 0;
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::Exists(const std::string & login) const
-{
-STG_LOCKER lock(&mutex);
-const std::map<std::string, user_iter>::const_iterator iter(loginIndex.find(login));
-return iter != loginIndex.end();
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::TariffInUse(const std::string & tariffName) const
-{
-STG_LOCKER lock(&mutex);
-std::list<UserImpl>::const_iterator iter;
-iter = users.begin();
-while (iter != users.end())
- {
- if (iter->GetProperties().tariffName.Get() == tariffName)
- return true;
- ++iter;
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::Add(const std::string & login, const Admin * admin)
-{
-STG_LOCKER lock(&mutex);
-const auto& priv = admin->priv();
-
-if (!priv.userAddDel)
- {
- WriteServLog("%s tried to add user \'%s\'. Access denied.",
- admin->logStr().c_str(), login.c_str());
- return -1;
- }
-
-if (store->AddUser(login))
- return -1;
-
-UserImpl u(settings, store, tariffs, &sysAdmin, this, m_services);
-
-u.SetLogin(login);
-
-u.SetPassiveTimeAsNewUser();
-
-u.WriteConf();
-u.WriteStat();
-
-WriteServLog("%s User \'%s\' added.",
- admin->logStr().c_str(), login.c_str());
-
-u.OnAdd();
-
-users.push_front(u);
-
-AddUserIntoIndexes(users.begin());
-
- {
- // Fire all "on add" notifiers
- std::set<NotifierBase<UserPtr> *>::iterator ni = onAddNotifiers.begin();
- while (ni != onAddNotifiers.end())
- {
- (*ni)->Notify(&users.front());
- ++ni;
- }
- }
-
- {
- // Fire all "on add" implementation notifiers
- std::set<NotifierBase<UserImplPtr> *>::iterator ni = onAddNotifiersImpl.begin();
- while (ni != onAddNotifiersImpl.end())
- {
- (*ni)->Notify(&users.front());
- ++ni;
- }
- }
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::Del(const std::string & login, const Admin * admin)
-{
-const auto& priv = admin->priv();
-user_iter u;
-
-if (!priv.userAddDel)
- {
- WriteServLog("%s tried to remove user \'%s\'. Access denied.",
- admin->logStr().c_str(), login.c_str());
- return;
- }
-
-
- {
- STG_LOCKER lock(&mutex);
-
- if (FindByNameNonLock(login, &u))
- {
- WriteServLog("%s tried to delete user \'%s\': not found.",
- admin->logStr().c_str(),
- login.c_str());
- return;
- }
-
- u->SetDeleted();
- }
-
- {
- std::set<NotifierBase<UserPtr> *>::iterator ni = onDelNotifiers.begin();
- while (ni != onDelNotifiers.end())
- {
- (*ni)->Notify(&(*u));
- ++ni;
- }
- }
-
- {
- std::set<NotifierBase<UserImplPtr> *>::iterator ni = onDelNotifiersImpl.begin();
- while (ni != onDelNotifiersImpl.end())
- {
- (*ni)->Notify(&(*u));
- ++ni;
- }
- }
-
- {
- STG_LOCKER lock(&mutex);
-
- u->OnDelete();
-
- USER_TO_DEL utd;
- utd.iter = u;
- utd.delTime = stgTime;
- usersToDelete.push_back(utd);
-
- DelUserFromIndexes(u);
-
- WriteServLog("%s User \'%s\' deleted.",
- admin->logStr().c_str(), login.c_str());
-
- }
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::Authorize(const std::string & login, uint32_t ip,
- uint32_t enabledDirs, const Auth * auth)
-{
-user_iter iter;
-STG_LOCKER lock(&mutex);
-if (FindByNameNonLock(login, &iter))
- {
- WriteServLog("Attempt to authorize non-existant user '%s'", login.c_str());
- return false;
- }
-
-if (FindByIPIdx(ip, iter))
- {
- if (iter->GetLogin() != login)
- {
- WriteServLog("Attempt to authorize user '%s' from ip %s which already occupied by '%s'",
- login.c_str(), inet_ntostring(ip).c_str(),
- iter->GetLogin().c_str());
- return false;
- }
- if (iter->Authorize(ip, enabledDirs, auth))
- return false;
- return true;
- }
-
-if (iter->Authorize(ip, enabledDirs, auth))
- return false;
-
-AddToIPIdx(iter);
-return true;
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::Unauthorize(const std::string & login,
- const Auth * auth,
- const std::string & reason)
-{
-user_iter iter;
-STG_LOCKER lock(&mutex);
-if (FindByNameNonLock(login, &iter))
- {
- WriteServLog("Attempt to unauthorize non-existant user '%s'", login.c_str());
- printfd(__FILE__, "Attempt to unauthorize non-existant user '%s'", login.c_str());
- return false;
- }
-
-uint32_t ip = iter->GetCurrIP();
-
-iter->Unauthorize(auth, reason);
-
-if (!iter->GetAuthorized())
- DelFromIPIdx(ip);
-
-return true;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::ReadUsers()
-{
-std::vector<std::string> usersList;
-usersList.clear();
-if (store->GetUsersList(&usersList) < 0)
- {
- WriteServLog(store->GetStrError().c_str());
- return -1;
- }
-
-user_iter ui;
-
-unsigned errors = 0;
-for (unsigned int i = 0; i < usersList.size(); i++)
- {
- UserImpl u(settings, store, tariffs, &sysAdmin, this, m_services);
-
- u.SetLogin(usersList[i]);
- users.push_front(u);
- ui = users.begin();
-
- AddUserIntoIndexes(ui);
-
- if (settings->GetStopOnError())
- {
- if (ui->ReadConf() < 0)
- return -1;
-
- if (ui->ReadStat() < 0)
- return -1;
- }
- else
- {
- if (ui->ReadConf() < 0)
- errors++;
-
- if (ui->ReadStat() < 0)
- errors++;
- }
- }
-
-if (errors > 0)
- return -1;
-return 0;
-}
-//-----------------------------------------------------------------------------
-void * UsersImpl::Run(void * d)
-{
-sigset_t signalSet;
-sigfillset(&signalSet);
-pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
-
-printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
-UsersImpl * us = static_cast<UsersImpl *>(d);
-
-struct tm t;
-time_t tt = stgTime;
-localtime_r(&tt, &t);
-
-int min = t.tm_min;
-int day = t.tm_mday;
-
-printfd(__FILE__,"Day = %d Min = %d\n", day, min);
-
-time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
-std::string monFile = us->settings->GetMonitorDir() + "/users_r";
-printfd(__FILE__, "Monitor=%d file USERS %s\n", us->settings->GetMonitoring(), monFile.c_str());
-
-us->isRunning = true;
-while (us->nonstop)
- {
- //printfd(__FILE__,"New Minute. old = %02d current = %02d\n", min, t->tm_min);
- //printfd(__FILE__,"New Day. old = %2d current = %2d\n", day, t->tm_mday);
-
- for_each(us->users.begin(), us->users.end(), [](auto& user){ user.Run(); });
-
- tt = stgTime;
- localtime_r(&tt, &t);
-
- if (min != t.tm_min)
- {
- printfd(__FILE__,"Sec = %d\n", stgTime);
- printfd(__FILE__,"New Minute. old = %d current = %d\n", min, t.tm_min);
- min = t.tm_min;
-
- us->NewMinute(t);
- }
-
- if (day != t.tm_mday)
- {
- printfd(__FILE__,"Sec = %d\n", stgTime);
- printfd(__FILE__,"New Day. old = %d current = %d\n", day, t.tm_mday);
- day = t.tm_mday;
- us->NewDay(t);
- }
-
- if (us->settings->GetMonitoring() && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
- {
- //printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", tc->monitoring, monFile.c_str());
- touchTime = stgTime;
- TouchFile(monFile);
- }
-
- stgUsleep(100000);
- } //while (us->nonstop)
-
-std::list<USER_TO_DEL>::iterator iter(us->usersToDelete.begin());
-while (iter != us->usersToDelete.end())
- {
- iter->delTime -= 2 * userDeleteDelayTime;
- ++iter;
- }
-us->RealDelUser();
-
-us->isRunning = false;
-
-return NULL;
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::NewMinute(const struct tm & t)
-{
-//Write traff, reset session traff. Fake disconnect-connect
-if (t.tm_hour == 23 && t.tm_min == 59)
- {
- printfd(__FILE__,"MidnightResetSessionStat\n");
- for_each(users.begin(), users.end(), [](auto& user){ user.MidnightResetSessionStat(); });
- }
-
-if (TimeToWriteDetailStat(t))
- {
- //printfd(__FILE__, "USER::WriteInetStat\n");
- int usersCnt = 0;
-
- // ðÉÛÅÍ ÀÚÅÒÏ× ÞÁÓÔÑÍÉ. ÷ ÐÅÒÅÒÙ×ÁÈ ×ÙÚÙ×ÁÅÍ USER::Run
- std::list<UserImpl>::iterator usr = users.begin();
- while (usr != users.end())
- {
- usersCnt++;
- usr->WriteDetailStat();
- ++usr;
- if (usersCnt % 10 == 0)
- for_each(users.begin(), users.end(), [](auto& user){ user.Run(); });
- }
- }
-
-RealDelUser();
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::NewDay(const struct tm & t)
-{
-struct tm t1;
-time_t tt = stgTime;
-localtime_r(&tt, &t1);
-int dayFee = settings->GetDayFee();
-
-if (dayFee == 0)
- dayFee = DaysInCurrentMonth();
-
-printfd(__FILE__, "DayFee = %d\n", dayFee);
-printfd(__FILE__, "Today = %d DayResetTraff = %d\n", t1.tm_mday, settings->GetDayResetTraff());
-printfd(__FILE__, "DayFeeIsLastDay = %d\n", settings->GetDayFeeIsLastDay());
-
-if (!settings->GetDayFeeIsLastDay())
- {
- printfd(__FILE__, "DayResetTraff - 1 -\n");
- DayResetTraff(t1);
- //printfd(__FILE__, "DayResetTraff - 1 - 1 -\n");
- }
-
-if (settings->GetSpreadFee())
- {
- printfd(__FILE__, "Spread DayFee\n");
- for_each(users.begin(), users.end(), [](auto& user){ user.ProcessDayFeeSpread(); });
- }
-else
- {
- if (t.tm_mday == dayFee)
- {
- printfd(__FILE__, "DayFee\n");
- for_each(users.begin(), users.end(), [](auto& user){ user.ProcessDayFee(); });
- }
- }
-
-std::for_each(users.begin(), users.end(), [](auto& user){ user.ProcessDailyFee(); });
-std::for_each(users.begin(), users.end(), [](auto& user){ user.ProcessServices(); });
-
-if (settings->GetDayFeeIsLastDay())
- {
- printfd(__FILE__, "DayResetTraff - 2 -\n");
- DayResetTraff(t1);
- }
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DayResetTraff(const struct tm & t1)
-{
-int dayResetTraff = settings->GetDayResetTraff();
-if (dayResetTraff == 0)
- dayResetTraff = DaysInCurrentMonth();
-if (t1.tm_mday == dayResetTraff)
- {
- printfd(__FILE__, "ResetTraff\n");
- for_each(users.begin(), users.end(), [](auto& user){ user.ProcessNewMonth(); });
- //for_each(users.begin(), users.end(), mem_fun_ref(&UserImpl::SetPrepaidTraff));
- }
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::Start()
-{
-if (ReadUsers())
- {
- WriteServLog("USERS: Error: Cannot read users!");
- return -1;
- }
-
-nonstop = true;
-if (pthread_create(&thread, NULL, Run, this))
- {
- WriteServLog("USERS: Error: Cannot start thread!");
- return -1;
- }
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::Stop()
-{
-printfd(__FILE__, "USERS::Stop()\n");
-
-if (!isRunning)
- {
- //printfd(__FILE__, "Alredy stopped\n");
- return 0;
- }
-
-nonstop = false;
-
-//5 seconds to thread stops itself
-struct timespec ts = {0, 200000000};
-for (size_t i = 0; i < 25 * (users.size() / 50 + 1); i++)
- {
- if (!isRunning)
- break;
-
- nanosleep(&ts, NULL);
- }
-
-//after 5 seconds waiting thread still running. now kill it
-if (isRunning)
- {
- printfd(__FILE__, "kill USERS thread.\n");
- //TODO pthread_cancel()
- if (pthread_kill(thread, SIGINT))
- {
- //errorStr = "Cannot kill USERS thread.";
- //printfd(__FILE__, "Cannot kill USERS thread.\n");
- //return 0;
- }
- printfd(__FILE__, "USERS killed\n");
- }
-
-printfd(__FILE__, "Before USERS::Run()\n");
-for_each(users.begin(), users.end(), [](auto& user){ user.Run(); });
-
-// 'cause bind2st accepts only constant first param
-for (std::list<UserImpl>::iterator it = users.begin();
- it != users.end();
- ++it)
- it->WriteDetailStat(true);
-
-for_each(users.begin(), users.end(), [](auto& user){ user.WriteStat(); });
-//for_each(users.begin(), users.end(), mem_fun_ref(&UserImpl::WriteConf));
-
-printfd(__FILE__, "USERS::Stop()\n");
-return 0;
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::RealDelUser()
-{
-STG_LOCKER lock(&mutex);
-
-printfd(__FILE__, "RealDelUser() users to del: %d\n", usersToDelete.size());
-
-std::list<USER_TO_DEL>::iterator iter;
-iter = usersToDelete.begin();
-while (iter != usersToDelete.end())
- {
- printfd(__FILE__, "RealDelUser() user=%s\n", iter->iter->GetLogin().c_str());
- if (iter->delTime + userDeleteDelayTime < stgTime)
- {
- printfd(__FILE__, "RealDelUser() user=%s removed from DB\n", iter->iter->GetLogin().c_str());
- if (store->DelUser(iter->iter->GetLogin()))
- {
- WriteServLog("Error removing user \'%s\' from database.", iter->iter->GetLogin().c_str());
- }
- users.erase(iter->iter);
- usersToDelete.erase(iter++);
- }
- else
- {
- ++iter;
- }
- }
-return;
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::AddToIPIdx(user_iter user)
-{
-printfd(__FILE__, "USERS: Add IP Idx\n");
-uint32_t ip = user->GetCurrIP();
-//assert(ip && "User has non-null ip");
-if (!ip)
- return; // User has disconnected
-
-STG_LOCKER lock(&mutex);
-
-const std::map<uint32_t, user_iter>::iterator it(
- ipIndex.lower_bound(ip)
-);
-
-assert((it == ipIndex.end() || it->first != ip) && "User is not in index");
-
-ipIndex.insert(it, std::make_pair(ip, user));
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DelFromIPIdx(uint32_t ip)
-{
-printfd(__FILE__, "USERS: Del IP Idx\n");
-assert(ip && "User has non-null ip");
-
-STG_LOCKER lock(&mutex);
-
-const std::map<uint32_t, user_iter>::iterator it(
- ipIndex.find(ip)
-);
-
-if (it == ipIndex.end())
- return;
-
-ipIndex.erase(it);
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::FindByIPIdx(uint32_t ip, user_iter & iter) const
-{
-std::map<uint32_t, user_iter>::const_iterator it(ipIndex.find(ip));
-if (it == ipIndex.end())
- return false;
-iter = it->second;
-return true;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::FindByIPIdx(uint32_t ip, UserPtr * usr) const
-{
-STG_LOCKER lock(&mutex);
-
-user_iter iter;
-if (FindByIPIdx(ip, iter))
- {
- *usr = &(*iter);
- return 0;
- }
-
-return -1;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::FindByIPIdx(uint32_t ip, UserImpl ** usr) const
-{
-STG_LOCKER lock(&mutex);
-
-user_iter iter;
-if (FindByIPIdx(ip, iter))
- {
- *usr = &(*iter);
- return 0;
- }
-
-return -1;
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::IsIPInIndex(uint32_t ip) const
-{
-STG_LOCKER lock(&mutex);
-
-std::map<uint32_t, user_iter>::const_iterator it(ipIndex.find(ip));
-
-return it != ipIndex.end();
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::IsIPInUse(uint32_t ip, const std::string & login, ConstUserPtr * user) const
-{
-STG_LOCKER lock(&mutex);
-std::list<UserImpl>::const_iterator iter;
-iter = users.begin();
-while (iter != users.end())
- {
- if (iter->GetLogin() != login &&
- !iter->GetProperties().ips.Get().isAnyIP() &&
- iter->GetProperties().ips.Get().find(ip))
- {
- if (user != NULL)
- *user = &(*iter);
- return true;
- }
- ++iter;
- }
-return false;
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::AddNotifierUserAdd(NotifierBase<UserPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onAddNotifiers.insert(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DelNotifierUserAdd(NotifierBase<UserPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onAddNotifiers.erase(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::AddNotifierUserDel(NotifierBase<UserPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onDelNotifiers.insert(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DelNotifierUserDel(NotifierBase<UserPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onDelNotifiers.erase(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::AddNotifierUserAdd(NotifierBase<UserImplPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onAddNotifiersImpl.insert(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DelNotifierUserAdd(NotifierBase<UserImplPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onAddNotifiersImpl.erase(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::AddNotifierUserDel(NotifierBase<UserImplPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onDelNotifiersImpl.insert(n);
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DelNotifierUserDel(NotifierBase<UserImplPtr> * n)
-{
-STG_LOCKER lock(&mutex);
-onDelNotifiersImpl.erase(n);
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::OpenSearch()
-{
-STG_LOCKER lock(&mutex);
-handle++;
-searchDescriptors[handle] = users.begin();
-return handle;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::SearchNext(int h, UserPtr * user)
-{
- UserImpl * ptr = NULL;
- if (SearchNext(h, &ptr))
- return -1;
- *user = ptr;
- return 0;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::SearchNext(int h, UserImpl ** user)
-{
-STG_LOCKER lock(&mutex);
-
-if (searchDescriptors.find(h) == searchDescriptors.end())
- {
- WriteServLog("USERS. Incorrect search handle.");
- return -1;
- }
-
-if (searchDescriptors[h] == users.end())
- return -1;
-
-while (searchDescriptors[h]->GetDeleted())
- {
- ++searchDescriptors[h];
- if (searchDescriptors[h] == users.end())
- {
- return -1;
- }
- }
-
-*user = &(*searchDescriptors[h]);
-
-++searchDescriptors[h];
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int UsersImpl::CloseSearch(int h)
-{
-STG_LOCKER lock(&mutex);
-if (searchDescriptors.find(h) != searchDescriptors.end())
- {
- searchDescriptors.erase(searchDescriptors.find(h));
- return 0;
- }
-
-WriteServLog("USERS. Incorrect search handle.");
-return -1;
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::AddUserIntoIndexes(user_iter user)
-{
-STG_LOCKER lock(&mutex);
-loginIndex.insert(make_pair(user->GetLogin(), user));
-}
-//-----------------------------------------------------------------------------
-void UsersImpl::DelUserFromIndexes(user_iter user)
-{
-STG_LOCKER lock(&mutex);
-loginIndex.erase(user->GetLogin());
-}
-//-----------------------------------------------------------------------------
-bool UsersImpl::TimeToWriteDetailStat(const struct tm & t)
-{
-int statTime = settings->GetDetailStatWritePeriod();
-
-switch (statTime)
- {
- case dsPeriod_1:
- if (t.tm_min == 0)
- return true;
- break;
- case dsPeriod_1_2:
- if (t.tm_min % 30 == 0)
- return true;
- break;
- case dsPeriod_1_4:
- if (t.tm_min % 15 == 0)
- return true;
- break;
- case dsPeriod_1_6:
- if (t.tm_min % 10 == 0)
- return true;
- break;
- }
-return false;
-}
+++ /dev/null
-/*
- * 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 : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
-#pragma once
-
-#include <pthread.h>
-
-#include <string>
-#include <map>
-#include <list>
-#include <set>
-#include <ctime>
-#include <cstdint>
-
-#include "stg/store.h"
-#include "stg/users.h"
-#include "stg/user.h"
-#include "stg/tariffs.h"
-#include "stg/logger.h"
-#include "stg/notifer.h"
-#include "stg/noncopyable.h"
-#include "actions.h"
-#include "eventloop.h"
-#include "settings_impl.h"
-#include "user_impl.h"
-
-namespace STG
-{
-
-const int userDeleteDelayTime = 120;
-
-typedef std::list<UserImpl>::iterator user_iter;
-typedef std::list<UserImpl>::const_iterator const_user_iter;
-
-class UsersImpl;
-//-----------------------------------------------------------------------------
-struct USER_TO_DEL {
-USER_TO_DEL()
- : iter(),
- delTime(0)
-{}
-
-std::list<UserImpl>::iterator iter;
-time_t delTime;
-};
-//-----------------------------------------------------------------------------
-class UsersImpl : public Users {
- friend class PROPERTY_NOTIFER_IP_BEFORE;
- friend class PROPERTY_NOTIFER_IP_AFTER;
-
-public:
- using UserImplPtr = UserImpl*;
-
- UsersImpl(SettingsImpl * s, Store * store,
- Tariffs * tariffs, Services & svcs,
- const Admin& sysAdmin);
- virtual ~UsersImpl();
-
- int FindByName(const std::string & login, UserPtr * user) override;
- int FindByName(const std::string & login, ConstUserPtr * user) const override;
- bool Exists(const std::string & login) const override;
-
- bool TariffInUse(const std::string & tariffName) const override;
-
- void AddNotifierUserAdd(NotifierBase<UserPtr> *) override;
- void DelNotifierUserAdd(NotifierBase<UserPtr> *) override;
-
- void AddNotifierUserDel(NotifierBase<UserPtr> *) override;
- void DelNotifierUserDel(NotifierBase<UserPtr> *) override;
-
- void AddNotifierUserAdd(NotifierBase<UserImplPtr> *);
- void DelNotifierUserAdd(NotifierBase<UserImplPtr> *);
-
- void AddNotifierUserDel(NotifierBase<UserImplPtr> *);
- void DelNotifierUserDel(NotifierBase<UserImplPtr> *);
-
- int Add(const std::string & login, const Admin * admin) override;
- void Del(const std::string & login, const Admin * admin) override;
-
- bool Authorize(const std::string & login, uint32_t ip,
- uint32_t enabledDirs, const Auth * auth) override;
- bool Unauthorize(const std::string & login,
- const Auth * auth,
- const std::string & reason) override;
-
- int ReadUsers() override;
- size_t Count() const override { return users.size(); }
-
- int FindByIPIdx(uint32_t ip, UserPtr * user) const override;
- int FindByIPIdx(uint32_t ip, UserImpl ** user) const;
- bool IsIPInIndex(uint32_t ip) const override;
- bool IsIPInUse(uint32_t ip, const std::string & login, ConstUserPtr * user) const override;
-
- int OpenSearch() override;
- int SearchNext(int handler, UserPtr * user) override;
- int SearchNext(int handler, UserImpl ** user);
- int CloseSearch(int handler) override;
-
- int Start() override;
- int Stop() override;
-
-private:
- UsersImpl(const UsersImpl & rvalue);
- UsersImpl & operator=(const UsersImpl & rvalue);
-
- void AddToIPIdx(user_iter user);
- void DelFromIPIdx(uint32_t ip);
- bool FindByIPIdx(uint32_t ip, user_iter & iter) const;
-
- int FindByNameNonLock(const std::string & login, user_iter * user);
- int FindByNameNonLock(const std::string & login, const_user_iter * user) const;
-
- void RealDelUser();
- void ProcessActions();
-
- void AddUserIntoIndexes(user_iter user);
- void DelUserFromIndexes(user_iter user);
-
- static void * Run(void *);
- void NewMinute(const struct tm & t);
- void NewDay(const struct tm & t);
- void DayResetTraff(const struct tm & t);
-
- bool TimeToWriteDetailStat(const struct tm & t);
-
- std::list<UserImpl> users;
- std::list<USER_TO_DEL> usersToDelete;
-
- std::map<uint32_t, user_iter> ipIndex;
- std::map<std::string, user_iter> loginIndex;
-
- SettingsImpl * settings;
- Tariffs * tariffs;
- Services & m_services;
- Store * store;
- const Admin& sysAdmin;
- Logger & WriteServLog;
-
- bool nonstop;
- bool isRunning;
-
- mutable pthread_mutex_t mutex;
- pthread_t thread;
- mutable unsigned int handle;
-
- mutable std::map<int, user_iter> searchDescriptors;
-
- std::set<NotifierBase<UserPtr>*> onAddNotifiers;
- std::set<NotifierBase<UserPtr>*> onDelNotifiers;
- std::set<NotifierBase<UserImplPtr>*> onAddNotifiersImpl;
- std::set<NotifierBase<UserImplPtr>*> onDelNotifiersImpl;
-};
-
-}
test_filter_params_log.cpp
test_crypto.cpp
test_bfstream.cpp
- ../stargazer/tariff_impl.cpp
- ../stargazer/user_impl.cpp
- ../stargazer/user_property.cpp )
+ ../projects/stargazer/tariff_impl.cpp
+ ../projects/stargazer/user_impl.cpp
+ ../projects/stargazer/user_property.cpp )
set ( THREADS_PREFER_PTHREAD_FLAG ON )
find_package ( Threads REQUIRED )
target_link_libraries ( tests conffiles crypto logger scriptexecuter common Threads::Threads )
-target_include_directories ( tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ../stargazer )
+target_include_directories ( tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ../projects/stargazer )