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