]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/radius/radius.cpp
Introduced SGCP library.
[stg.git] / projects / stargazer / plugins / other / radius / radius.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 #include "radius.h"
22
23 #include "stg/store.h"
24 #include "stg/users.h"
25 #include "stg/plugin_creator.h"
26
27 #include <csignal>
28 #include <cerror>
29 #include <cstring>
30
31 namespace
32 {
33
34 PLUGIN_CREATOR<RADIUS> creator;
35
36 }
37
38 extern "C" PLUGIN * GetPlugin()
39 {
40     return creator.GetPlugin();
41 }
42
43 RADIUS::RADIUS()
44     : m_running(false),
45       m_stopped(true),
46       m_users(NULL),
47       m_store(NULL),
48       m_logger(GetPluginLogger(GetStgLogger(), "radius"))
49 {
50 }
51
52 int RADIUS::ParseSettings()
53 {
54     try {
55         m_config = STG::Config(m_settings);
56         return 0;
57     } catch (const std::runtime_error& ex) {
58         m_logger("Failed to parse settings. %s", ex.what());
59         return -1;
60     }
61 }
62
63 int RADIUS::Start()
64 {
65     if (m_running)
66         return 0;
67
68     int res = pthread_create(&m_thread, NULL, run, this);
69     if (res == 0)
70         return 0;
71
72     m_error = strerror(res);
73     m_logger("Failed to create thread: '" + m_error + "'.");
74     return -1;
75 }
76
77 int RADIUS::Stop()
78 {
79     if (m_stopped)
80         return 0;
81
82     m_running = false;
83
84     for (size_t i = 0; i < 25 && !m_stopped; i++) {
85         struct timespec ts = {0, 200000000};
86         nanosleep(&ts, NULL);
87     }
88
89     if (m_stopped) {
90         pthread_join(m_thread, NULL);
91         return 0;
92     }
93
94     m_error = "Failed to stop thread.";
95     m_logger(m_error);
96     return -1;
97 }
98 //-----------------------------------------------------------------------------
99 void* RADIUS::run(void* d)
100 {
101     sigset_t signalSet;
102     sigfillset(&signalSet);
103     pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
104
105     static_cast<RADIUS *>(d)->runImpl();
106
107     return NULL;
108 }
109
110 void RADIUS::runImpl()
111 {
112     m_running = true;
113
114     while (m_running) {
115         fd_set fds;
116
117         buildFDSet(fds);
118
119         struct timeval tv;
120         tv.tv_sec = 0;
121         tv.tv_usec = 500000;
122
123         int res = select(maxFD() + 1, &fds, NULL, NULL, &tv);
124         if (res < 0)
125         {
126             m_error = std::string("'select' is failed: '") + strerror(errno) + "'.";
127             m_logger(m_error);
128             break;
129         }
130
131         if (!m_running)
132             break;
133
134         if (res > 0)
135             handleEvents(fds);
136
137         cleanupConns();
138     }
139
140     m_stopped = true;
141 }
142
143 int RADIUS::maxFD() const
144 {
145     int maxFD = m_listenSocket;
146     std::deque<STG::Conn *>::const_iterator it;
147     for (it = m_conns.begin(); it != m_conns.end(); ++it)
148         if (maxFD < (*it)->sock())
149             maxFD = (*it)->sock();
150     return maxFD;
151 }
152
153 void RADIUS::buildFDSet(fd_set & fds) const
154 {
155     FD_ZERO(&fds);
156     FD_SET(m_listenSocket, &fds);
157     std::deque<STG::Conn *>::const_iterator it;
158     for (it = m_conns.begin(); it != m_conns.end(); ++it)
159         FD_SET((*it)->sock(), &fds);
160 }
161
162 void RADIUS::cleanupConns()
163 {
164     std::deque<STG::Conn *>::iterator pos;
165     for (pos = m_conns.begin(); pos != m_conns.end(); ++pos)
166         if (((*pos)->isDone() && !(*pos)->isKeepAlive()) || !(*pos)->isOk()) {
167             delete *pos;
168             *pos = NULL;
169         }
170
171     pos = std::remove(m_conns.begin(), m_conns.end(), static_cast<STG::Conn *>(NULL));
172     m_conns.erase(pos, m_conns.end());
173 }
174
175 void RADIUS::handleEvents(const fd_set & fds)
176 {
177     if (FD_ISSET(m_listenSocket, &fds))
178         acceptConnection();
179     else
180     {
181         std::deque<STG::Conn *>::iterator it;
182         for (it = m_conns.begin(); it != m_conns.end(); ++it)
183             if (FD_ISSET((*it)->sock(), &fds))
184                 (*it)->read();
185     }
186 }