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