]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.cpp
Use external socket to correctly stop XML-RPC server
[stg.git] / projects / stargazer / plugins / configuration / rpcconfig / rpcconfig.cpp
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <arpa/inet.h>
5
6 #include <cstdlib>
7 #include <csignal>
8 #include <cerrno>
9 #include <cstring>
10 #include <vector>
11 #include <algorithm>
12
13 #include "stg/common.h"
14 #include "stg/admin.h"
15 #include "stg/module_settings.h"
16 #include "stg/settings.h"
17 #include "stg/plugin_creator.h"
18
19 #include "rpcconfig.h"
20 #include "info_methods.h"
21 #include "users_methods.h"
22 #include "tariffs_methods.h"
23 #include "admins_methods.h"
24 #include "messages_methods.h"
25
26 PLUGIN_CREATOR<RPC_CONFIG> rpcc;
27
28 RPC_CONFIG_SETTINGS::RPC_CONFIG_SETTINGS()
29     : errorStr(),
30       port(0),
31       cookieTimeout(0)
32 {
33 }
34
35 int RPC_CONFIG_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
36 {
37 int p;
38 PARAM_VALUE pv;
39 std::vector<PARAM_VALUE>::const_iterator pvi;
40
41 pv.param = "Port";
42 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
43 if (pvi == s.moduleParams.end())
44     {
45     errorStr = "Parameter \'Port\' not found.";
46     printfd(__FILE__, "Parameter 'Port' not found\n");
47     return -1;
48     }
49 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
50     {
51     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
52     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
53     return -1;
54     }
55 port = p;
56
57 pv.param = "CookieTimeout";
58 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
59 if (pvi == s.moduleParams.end())
60     {
61     cookieTimeout = 1800; // 30 * 60
62     }
63 else
64     {
65     if (str2x(pvi->value[0], cookieTimeout))
66         {
67         errorStr = "Incorrect value of CookieTimeout: \'" + pvi->value[0] + "\'";
68         printfd(__FILE__, "Incorrect value of 'CookieTimeout'\n");
69         return -1;
70         }
71     }
72
73 return 0;
74 }
75
76 PLUGIN * GetPlugin()
77 {
78 return rpcc.GetPlugin();
79 }
80
81 RPC_CONFIG::RPC_CONFIG()
82     : errorStr(),
83       rpcConfigSettings(),
84       users(NULL),
85       admins(NULL),
86       tariffs(NULL),
87       store(NULL),
88       settings(),
89       fd(-1),
90       rpcRegistry(),
91       rpcServer(NULL),
92       running(false),
93       stopped(true),
94       tid(),
95       cookies(),
96       dayFee(0),
97       dirNames()
98 {
99 }
100
101 RPC_CONFIG::~RPC_CONFIG()
102 {
103 // delete server
104 delete rpcServer;
105 }
106
107 int RPC_CONFIG::ParseSettings()
108 {
109 int ret = rpcConfigSettings.ParseSettings(settings);
110
111 if (ret)
112     errorStr = rpcConfigSettings.GetStrError();
113
114 return ret;
115 }
116
117 void RPC_CONFIG::SetStgSettings(const SETTINGS * settings)
118 {
119     dayFee = settings->GetDayFee();
120     dirNames.erase(dirNames.begin(), dirNames.end());
121     for (size_t i = 0; i < DIR_NUM; ++i) {
122         dirNames.push_back(settings->GetDirName(i));
123     }
124 }
125
126 int RPC_CONFIG::Start()
127 {
128 InitiateRegistry();
129 running = true;
130
131 fd = socket(AF_INET, SOCK_STREAM, 0);
132 if (fd < 0)
133     {
134     errorStr = "Failed to create socket";
135     printfd(__FILE__, "Failed to create listening socket: %s\n", strerror(errno));
136     return -1;
137     }
138
139 int flag = 1;
140
141 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
142     {
143     errorStr = "Setsockopt failed.";
144     printfd(__FILE__, "Setsockopt failed: %s\n", strerror(errno));
145     return -1;
146     }
147
148 struct sockaddr_in addr;
149 addr.sin_family = AF_INET;
150 addr.sin_port = htons(rpcConfigSettings.GetPort());
151 addr.sin_addr.s_addr = inet_addr("0.0.0.0");
152
153 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
154     {
155     errorStr = "Failed to bind socket";
156     printfd(__FILE__, "Failed to bind listening socket: %s\n", strerror(errno));
157     return -1;
158     }
159
160 if (listen(fd, 10))
161     {
162     errorStr = "Failed to listen socket";
163     printfd(__FILE__, "Failed to listen listening socket: %s\n", strerror(errno));
164     return -1;
165     }
166
167 rpcServer = new xmlrpc_c::serverAbyss(
168         xmlrpc_c::serverAbyss::constrOpt()
169         .registryP(&rpcRegistry)
170         .logFileName("/var/log/stargazer_rpc.log")
171         .socketFd(fd)
172         );
173
174 if (pthread_create(&tid, NULL, Run, this))
175     {
176     errorStr = "Failed to create RPC thread";
177     printfd(__FILE__, "Failed to crate RPC thread\n");
178     return -1;
179     }
180
181 return 0;
182 }
183
184 int RPC_CONFIG::Stop()
185 {
186 running = false;
187 for (int i = 0; i < 5 && !stopped; ++i)
188     {
189     struct timespec ts = {0, 200000000};
190     nanosleep(&ts, NULL);
191     }
192
193 if (!stopped)
194     {
195     running = true;
196     printfd(__FILE__, "Failed to stop RPC thread\n");
197     errorStr = "Failed to stop RPC thread";
198     return -1;
199     }
200 else
201     {
202     pthread_join(tid, NULL);
203     }
204
205 close(fd);
206
207 return 0;
208 }
209
210 void * RPC_CONFIG::Run(void * rc)
211 {
212 sigset_t signalSet;
213 sigfillset(&signalSet);
214 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
215
216 RPC_CONFIG * config = static_cast<RPC_CONFIG *>(rc);
217
218 config->stopped = false;
219 while (config->running)
220     {
221     if (WaitPackets(config->fd))
222         config->rpcServer->runOnce();
223     }
224 config->stopped = true;
225
226 return NULL;
227 }
228
229 bool RPC_CONFIG::GetAdminInfo(const std::string & cookie,
230                               ADMIN_INFO * info)
231 {
232 std::map<std::string,
233          ADMIN_INFO>::iterator it;
234
235 it = cookies.find(cookie);
236
237 if (it == cookies.end())
238     {
239     return true;
240     }
241
242 if (difftime(it->second.accessTime, time(NULL)) >
243     rpcConfigSettings.GetCookieTimeout())
244     {
245     cookies.erase(it);
246     return true;
247     }
248
249 // Update access time
250 time(&it->second.accessTime);
251 *info = it->second;
252 return false;
253 }
254
255 bool RPC_CONFIG::CheckAdmin(const std::string & login,
256                             const std::string & password,
257                             std::string * cookie)
258 {
259 ADMIN * admin = NULL;
260
261 if (!admins->Correct(login, password, &admin))
262     {
263     return true;
264     }
265
266 ADMIN_INFO info;
267 time(&info.accessTime);
268 info.admin = login;
269 info.priviledges = *admin->GetPriv();
270 *cookie = GetCookie();
271 cookies[*cookie] = info;
272
273 return false;
274 }
275
276 bool RPC_CONFIG::LogoutAdmin(const std::string & cookie)
277 {
278 std::map<std::string,
279          ADMIN_INFO>::iterator it;
280
281 it = cookies.find(cookie);
282
283 if (it == cookies.end())
284     {
285     return true;
286     }
287
288 cookies.erase(it);
289
290 return false;
291 }
292
293 std::string RPC_CONFIG::GetCookie() const
294 {
295 std::string charset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
296 std::string cookie;
297
298 for (int i = 0; i < 64; ++i)
299     {
300     cookie += charset[rand() % charset.length()];
301     };
302
303 return cookie;
304 }
305
306 void RPC_CONFIG::InitiateRegistry()
307 {
308 // manage registry
309 xmlrpc_c::methodPtr const methodInfoPtr(new METHOD_INFO(
310             tariffs,
311             users,
312             dayFee,
313             dirNames
314             ));
315 rpcRegistry.addMethod("stargazer.info", methodInfoPtr);
316
317 xmlrpc_c::methodPtr const methodLoginPtr(new METHOD_LOGIN(
318             this
319             ));
320 rpcRegistry.addMethod("stargazer.login", methodLoginPtr);
321
322 xmlrpc_c::methodPtr const methodLogoutPtr(new METHOD_LOGOUT(
323             this
324             ));
325 rpcRegistry.addMethod("stargazer.logout", methodLogoutPtr);
326
327 xmlrpc_c::methodPtr const methodGetUserPtr(new METHOD_USER_GET(
328             this,
329             users
330             ));
331 rpcRegistry.addMethod("stargazer.get_user", methodGetUserPtr);
332
333 xmlrpc_c::methodPtr const methodAddUserPtr(new METHOD_USER_ADD(
334             this,
335             admins,
336             users
337             ));
338 rpcRegistry.addMethod("stargazer.add_user", methodAddUserPtr);
339
340 xmlrpc_c::methodPtr const methodDelUserPtr(new METHOD_USER_DEL(
341             this,
342             admins,
343             users
344             ));
345 rpcRegistry.addMethod("stargazer.del_user", methodDelUserPtr);
346
347 xmlrpc_c::methodPtr const methodGetUsersPtr(new METHOD_USERS_GET(
348             this,
349             users
350             ));
351 rpcRegistry.addMethod("stargazer.get_users", methodGetUsersPtr);
352
353 xmlrpc_c::methodPtr const methodChgUserPtr(new METHOD_USER_CHG(
354             this,
355             admins,
356             tariffs,
357             store,
358             users
359             ));
360 rpcRegistry.addMethod("stargazer.chg_user", methodChgUserPtr);
361
362 xmlrpc_c::methodPtr const methodAddCashPtr(new METHOD_USER_CASH_ADD(
363             this,
364             admins,
365             store,
366             users
367             ));
368 rpcRegistry.addMethod("stargazer.add_user_cash", methodAddCashPtr);
369
370 xmlrpc_c::methodPtr const methodSetCashPtr(new METHOD_USER_CASH_SET(
371             this,
372             admins,
373             store,
374             users
375             ));
376 rpcRegistry.addMethod("stargazer.set_user_cash", methodSetCashPtr);
377
378 xmlrpc_c::methodPtr const methodTariffChangePtr(new METHOD_USER_TARIFF_CHANGE(
379             this,
380             admins,
381             tariffs,
382             store,
383             users
384             ));
385 rpcRegistry.addMethod("stargazer.chg_user_tariff", methodTariffChangePtr);
386
387 xmlrpc_c::methodPtr const methodGetTariffPtr(new METHOD_TARIFF_GET(
388             this,
389             tariffs
390             ));
391 rpcRegistry.addMethod("stargazer.get_tariff", methodGetTariffPtr);
392
393 xmlrpc_c::methodPtr const methodChgTariffPtr(new METHOD_TARIFF_CHG(
394             this,
395             admins,
396             tariffs
397             ));
398 rpcRegistry.addMethod("stargazer.chg_tariff", methodChgTariffPtr);
399
400 xmlrpc_c::methodPtr const methodGetTariffsPtr(new METHOD_TARIFFS_GET(
401             this,
402             tariffs
403             ));
404 rpcRegistry.addMethod("stargazer.get_tariffs", methodGetTariffsPtr);
405
406 xmlrpc_c::methodPtr const methodAddTariffPtr(new METHOD_TARIFF_ADD(
407             this,
408             admins,
409             tariffs
410             ));
411 rpcRegistry.addMethod("stargazer.add_tariff", methodAddTariffPtr);
412
413 xmlrpc_c::methodPtr const methodDelTariffPtr(new METHOD_TARIFF_DEL(
414             this,
415             admins,
416             tariffs,
417             users
418             ));
419 rpcRegistry.addMethod("stargazer.del_tariff", methodDelTariffPtr);
420
421 xmlrpc_c::methodPtr const methodGetAdminPtr(new METHOD_ADMIN_GET(
422             this,
423             admins
424             ));
425 rpcRegistry.addMethod("stargazer.get_admin", methodGetAdminPtr);
426
427 xmlrpc_c::methodPtr const methodAddAdminPtr(new METHOD_ADMIN_ADD(
428             this,
429             admins
430             ));
431 rpcRegistry.addMethod("stargazer.add_admin", methodAddAdminPtr);
432
433 xmlrpc_c::methodPtr const methodDelAdminPtr(new METHOD_ADMIN_DEL(
434             this,
435             admins
436             ));
437 rpcRegistry.addMethod("stargazer.del_admin", methodDelAdminPtr);
438
439 xmlrpc_c::methodPtr const methodChgAdminPtr(new METHOD_ADMIN_CHG(
440             this,
441             admins
442             ));
443 rpcRegistry.addMethod("stargazer.chg_admin", methodChgAdminPtr);
444
445 xmlrpc_c::methodPtr const methodGetAdminsPtr(new METHOD_ADMINS_GET(
446             this,
447             admins
448             ));
449 rpcRegistry.addMethod("stargazer.get_admins", methodGetAdminsPtr);
450
451 xmlrpc_c::methodPtr const methodSendMessagePtr(new METHOD_MESSAGE_SEND(
452             this,
453             users
454             ));
455 rpcRegistry.addMethod("stargazer.send_user_message", methodSendMessagePtr);
456
457 xmlrpc_c::methodPtr const methodGetOnlinIPsPtr(new METHOD_GET_ONLINE_IPS(
458             this,
459             users
460             ));
461 rpcRegistry.addMethod("stargazer.get_online_ips", methodGetOnlinIPsPtr);
462 }
463