]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig2/stgconfig.cpp
Merge branch 'master' into full-month-stats
[stg.git] / projects / stargazer / plugins / configuration / sgconfig2 / stgconfig.cpp
1 #include <cstdio>
2 #include <cunistd>
3 #include <csignal>
4 #include <functional>
5 #include <algorithm>
6
7 #include "stg/plugin_creator.h"
8 #include "stgconfig.h"
9 #include "../../../tariffs.h"
10 #include "../../../admins.h"
11 #include "../../../users.h"
12
13 PLUGIN_CREATOR<STG_CONFIG> stgc;
14
15 BASE_PLUGIN * GetPlugin()
16 {
17 return stgc.GetPlugin();
18 }
19
20 STG_CONFIG_SETTINGS::STG_CONFIG_SETTINGS()
21     : port(0)
22 {
23 }
24
25 const string& STG_CONFIG_SETTINGS::GetStrError() const
26 {
27 return errorStr;
28 }
29
30 int STG_CONFIG_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
31 {
32 int p;
33 PARAM_VALUE pv;
34 vector<PARAM_VALUE>::const_iterator pvi;
35 ///////////////////////////
36 pv.param = "Port";
37 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
38 if (pvi == s.moduleParams.end())
39     {
40     errorStr = "Parameter \'Port\' not found.";
41     printfd(__FILE__, "Parameter 'Port' not found\n");
42     return -1;
43     }
44 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
45     {
46     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
47     printfd(__FILE__, "%s\n", errorStr.c_str());
48     return -1;
49     }
50 port = p;
51
52 return 0;
53 }
54
55 uint16_t STG_CONFIG_SETTINGS::GetPort()
56 {
57 return port;
58 }
59
60 STG_CONFIG::STG_CONFIG()
61     : running(false),
62       stopped(true)
63 {
64 }
65
66 string STG_CONFIG::GetVersion() const
67 {
68 return "Stg configurator v.2.00";
69 }
70
71 int STG_CONFIG::ParseSettings()
72 {
73 int ret = stgConfigSettings.ParseSettings(settings);
74 if (ret)
75     errorStr = stgConfigSettings.GetStrError();
76 return ret;
77 }
78
79 int STG_CONFIG::Start()
80 {
81 if (running)
82     return false;
83
84 if (PrepareNetwork())
85     return true;
86
87 stopped = false;
88
89 config.SetPort(stgConfigSettings.GetPort());
90 config.SetAdmins(admins);
91 config.SetUsers(users);
92 config.SetTariffs(tariffs);
93 config.SetStgSettings(stgSettings);
94 config.SetStore(store);
95
96 if (config.Prepare())
97     {
98     errorStr = config.GetStrError();
99     return true;
100     }
101
102 if (pthread_create(&thread, NULL, Run, this))
103     {
104     errorStr = "Cannot create thread.";
105     printfd(__FILE__, "Cannot create thread\n");
106     return true;
107     }
108
109 errorStr = "";
110 return false;
111 }
112
113 int STG_CONFIG::Stop()
114 {
115 if (!running)
116     return false;
117
118 running = false;
119
120 config.Stop();
121
122 //5 seconds to thread stops itself
123 int i;
124 for (i = 0; i < 25 && !stopped; i++)
125     {
126     usleep(200000);
127     }
128
129 //after 5 seconds waiting thread still running. now killing it
130 if (!stopped)
131     {
132     //TODO pthread_cancel()
133     if (pthread_kill(thread, SIGINT))
134         {
135         errorStr = "Cannot kill thread.";
136         printfd(__FILE__, "Cannot kill thread\n");
137         return FinalizeNetwork();
138         }
139     printfd(__FILE__, "STG_CONFIG killed\n");
140     }
141
142 return FinalizeNetwork();
143 }
144
145 void * STG_CONFIG::Run(void * d)
146 {
147 STG_CONFIG * stgConf = static_cast<STG_CONFIG *>(d);
148 stgConf->running = true;
149
150 stgConf->RealRun();
151
152 stgConf->stopped = true;
153 return NULL;
154 }
155
156 uint16_t STG_CONFIG::GetStartPosition() const
157 {
158 return 20;
159 }
160
161 uint16_t STG_CONFIG::GetStopPosition() const
162 {
163 return 20;
164 }
165
166 bool PrepareNetwork()
167 {
168 struct sockaddr_in local;
169
170 local.sin_family = AF_INET;
171 local.sin_port = htons(port);
172 local.sin_addr.s_addr = INADDR_ANY;
173
174 sd = socket(AF_INET, SOCK_STREAM, 0);
175 if (sd < 0)
176     {
177     errorStr = "Error creating socket: '";
178     errorStr += strerror(errno);
179     errorStr += "'";
180     return true;
181     }
182
183 if (bind(sd, static_cast<struct sockaddr *>(&local), sizeof(local)) < 0)
184     {
185     errorStr = "Error binding socket: '";
186     errorStr += strerror(errno);
187     errorStr += "'";
188     return true;
189     }
190
191 return false;
192 }
193
194 bool FinalizeNetwork()
195 {
196 if (close(sd) < 0)
197     {
198     errorStr = "Error closing socket: '";
199     errorStr += strerror(errno);
200     errorStr += "'";
201     return true;
202     }
203 return false;
204 }
205
206 void STG_CONFIG::RealRun()
207 {
208 if (listen(sd, 64) < 0)
209     {
210     errorStr = "Error listening socket: '";
211     errorStr += strerror(errno);
212     errorStr += "'";
213     return;
214     }
215
216 fd_set rfds;
217
218 FD_ZERO(&rfds);
219 FD_SET(sd, &rfds);
220
221 running = true;
222 while (running)
223     {
224     struct timeval tv;
225     tv.tv_sec = 0;
226     tv.tv_usec = 500000;
227
228     int res = select(sd + 1, &rfds, NULL, NULL, &tv);
229
230     if (res < 0)
231         {
232         // Error logging
233         }
234     else if (res == 0)
235         {
236         // Timeout
237         }
238     else
239         {
240         if (FD_ISSET(sd, &rfds))
241             {
242             AcceptConnection();
243             }
244         }
245
246     // Reorder: right part is done
247     std::list<ConnectionThread *>::iterator done(
248             std::remove_if(
249                 connections.begin(),
250                 connections.end(),
251                 std::not1(std::mem_fun(&ConnectionThread::isDone))
252             )
253     );
254     // Destruct done
255     std::for_each(
256             done,
257             connections.end(),
258             DeleteConnection());
259     // Erase done
260     std::erase(done, connections.end());
261
262     }
263 stopped = true;
264 }
265
266 void STG_CONFIG::AcceptConnection()
267 {
268 struct sockaddr_in remoteAddr;
269 socklen_t len = sizeof(struct sockaddr_in);
270 int rsd = accept(sd, &remoteAddr, &len);
271
272 if (rsd < 0)
273     {
274     // Error logging
275     }
276
277 connections.push_back(new ConnectionThread(this, rsd, remoteAddr, users, admins, tariffs, store, stgSettings));
278 }