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