]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/rscript/rscript.cpp
Added specialization of str2x for doubles.
[stg.git] / projects / stargazer / plugins / other / rscript / rscript.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
20  */
21
22 #include <sys/time.h>
23
24 #include <csignal>
25 #include <cassert>
26 #include <cstdlib>
27 #include <cerrno>
28 #include <cstring>
29 #include <algorithm>
30
31 #include "stg/common.h"
32 #include "stg/locker.h"
33 #include "stg/users.h"
34 #include "stg/user_property.h"
35 #include "stg/plugin_creator.h"
36 #include "stg/logger.h"
37 #include "rscript.h"
38 #include "ur_functor.h"
39 #include "send_functor.h"
40
41 extern volatile time_t stgTime;
42
43 using RS::REMOTE_SCRIPT;
44
45 namespace {
46
47 template<typename T>
48 struct USER_IS
49 {
50     USER_IS(USER_PTR u) : user(u) {}
51     bool operator()(const T & notifier) { return notifier.GetUser() == user; }
52
53     USER_PTR user;
54 };
55
56 PLUGIN_CREATOR<REMOTE_SCRIPT> rsc;
57
58 } // namespace anonymous
59
60 extern "C" PLUGIN * GetPlugin();
61 //-----------------------------------------------------------------------------
62 //-----------------------------------------------------------------------------
63 //-----------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
67 PLUGIN * GetPlugin()
68 {
69 return rsc.GetPlugin();
70 }
71 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
73 //-----------------------------------------------------------------------------
74 RS::SETTINGS::SETTINGS()
75     : sendPeriod(0),
76       port(0)
77 {
78 }
79 //-----------------------------------------------------------------------------
80 int RS::SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
81 {
82 int p;
83 PARAM_VALUE pv;
84 std::vector<PARAM_VALUE>::const_iterator pvi;
85 netRouters.clear();
86 ///////////////////////////
87 pv.param = "Port";
88 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
89 if (pvi == s.moduleParams.end() || pvi->value.empty())
90     {
91     errorStr = "Parameter \'Port\' not found.";
92     printfd(__FILE__, "Parameter 'Port' not found\n");
93     return -1;
94     }
95 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
96     {
97     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
98     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
99     return -1;
100     }
101 port = static_cast<uint16_t>(p);
102 ///////////////////////////
103 pv.param = "SendPeriod";
104 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
105 if (pvi == s.moduleParams.end() || pvi->value.empty())
106     {
107     errorStr = "Parameter \'SendPeriod\' not found.";
108     printfd(__FILE__, "Parameter 'SendPeriod' not found\n");
109     return -1;
110     }
111
112 if (ParseIntInRange(pvi->value[0], 5, 600, &sendPeriod))
113     {
114     errorStr = "Cannot parse parameter \'SendPeriod\': " + errorStr;
115     printfd(__FILE__, "Cannot parse parameter 'SendPeriod'\n");
116     return -1;
117     }
118 ///////////////////////////
119 pv.param = "UserParams";
120 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
121 if (pvi == s.moduleParams.end() || pvi->value.empty())
122     {
123     errorStr = "Parameter \'UserParams\' not found.";
124     printfd(__FILE__, "Parameter 'UserParams' not found\n");
125     return -1;
126     }
127 userParams = pvi->value;
128 ///////////////////////////
129 pv.param = "Password";
130 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
131 if (pvi == s.moduleParams.end() || pvi->value.empty())
132     {
133     errorStr = "Parameter \'Password\' not found.";
134     printfd(__FILE__, "Parameter 'Password' not found\n");
135     return -1;
136     }
137 password = pvi->value[0];
138 ///////////////////////////
139 pv.param = "SubnetFile";
140 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
141 if (pvi == s.moduleParams.end() || pvi->value.empty())
142     {
143     errorStr = "Parameter \'SubnetFile\' not found.";
144     printfd(__FILE__, "Parameter 'SubnetFile' not found\n");
145     return -1;
146     }
147 subnetFile = pvi->value[0];
148
149 NRMapParser nrMapParser;
150
151 if (!nrMapParser.ReadFile(subnetFile))
152     {
153     netRouters = nrMapParser.GetMap();
154     }
155 else
156     {
157     GetStgLogger()("mod_rscript: error opening subnets file '%s'", subnetFile.c_str());
158     }
159
160 return 0;
161 }
162 //-----------------------------------------------------------------------------
163 //-----------------------------------------------------------------------------
164 //-----------------------------------------------------------------------------
165 REMOTE_SCRIPT::REMOTE_SCRIPT()
166     : ctx(),
167       ipNotifierList(),
168       connNotifierList(),
169       authorizedUsers(),
170       errorStr(),
171       rsSettings(),
172       settings(),
173       sendPeriod(15),
174       halfPeriod(8),
175       nonstop(false),
176       isRunning(false),
177       users(NULL),
178       netRouters(),
179       thread(),
180       mutex(),
181       sock(0),
182       onAddUserNotifier(*this),
183       onDelUserNotifier(*this),
184       logger(GetPluginLogger(GetStgLogger(), "rscript"))
185 {
186 pthread_mutex_init(&mutex, NULL);
187 }
188 //-----------------------------------------------------------------------------
189 REMOTE_SCRIPT::~REMOTE_SCRIPT()
190 {
191 pthread_mutex_destroy(&mutex);
192 }
193 //-----------------------------------------------------------------------------
194 void * REMOTE_SCRIPT::Run(void * d)
195 {
196 sigset_t signalSet;
197 sigfillset(&signalSet);
198 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
199
200 REMOTE_SCRIPT * rs = static_cast<REMOTE_SCRIPT *>(d);
201
202 rs->isRunning = true;
203
204 while (rs->nonstop)
205     {
206     rs->PeriodicSend();
207     sleep(2);
208     }
209
210 rs->isRunning = false;
211 return NULL;
212 }
213 //-----------------------------------------------------------------------------
214 int REMOTE_SCRIPT::ParseSettings()
215 {
216 int ret = rsSettings.ParseSettings(settings);
217 if (ret)
218     errorStr = rsSettings.GetStrError();
219
220 sendPeriod = rsSettings.GetSendPeriod();
221 halfPeriod = sendPeriod / 2;
222
223 return ret;
224 }
225 //-----------------------------------------------------------------------------
226 int REMOTE_SCRIPT::Start()
227 {
228 netRouters = rsSettings.GetSubnetsMap();
229
230 InitEncrypt(&ctx, rsSettings.GetPassword());
231
232 users->AddNotifierUserAdd(&onAddUserNotifier);
233 users->AddNotifierUserDel(&onDelUserNotifier);
234
235 nonstop = true;
236
237 if (GetUsers())
238     {
239     return -1;
240     }
241
242 if (PrepareNet())
243     {
244     return -1;
245     }
246
247 if (!isRunning)
248     {
249     if (pthread_create(&thread, NULL, Run, this))
250         {
251         errorStr = "Cannot create thread.";
252         logger("Cannot create thread.");
253         printfd(__FILE__, "Cannot create thread\n");
254         return -1;
255         }
256     }
257
258 errorStr = "";
259 return 0;
260 }
261 //-----------------------------------------------------------------------------
262 int REMOTE_SCRIPT::Stop()
263 {
264 if (!IsRunning())
265     return 0;
266
267 nonstop = false;
268
269 std::for_each(
270         authorizedUsers.begin(),
271         authorizedUsers.end(),
272         DisconnectUser(*this)
273         );
274
275 FinalizeNet();
276
277 if (isRunning)
278     {
279     //5 seconds to thread stops itself
280     for (int i = 0; i < 25 && isRunning; i++)
281         {
282         struct timespec ts = {0, 200000000};
283         nanosleep(&ts, NULL);
284         }
285     }
286
287 users->DelNotifierUserDel(&onDelUserNotifier);
288 users->DelNotifierUserAdd(&onAddUserNotifier);
289
290 if (isRunning)
291     {
292     logger("Cannot stop thread.");
293     return -1;
294     }
295
296 return 0;
297 }
298 //-----------------------------------------------------------------------------
299 int REMOTE_SCRIPT::Reload()
300 {
301 NRMapParser nrMapParser;
302
303 if (nrMapParser.ReadFile(rsSettings.GetMapFileName()))
304     {
305     errorStr = nrMapParser.GetErrorStr();
306     logger("Map file reading error: %s", errorStr.c_str());
307     return -1;
308     }
309
310     {
311     STG_LOCKER lock(&mutex);
312
313     printfd(__FILE__, "REMOTE_SCRIPT::Reload()\n");
314
315     netRouters = nrMapParser.GetMap();
316     }
317
318 std::for_each(authorizedUsers.begin(),
319               authorizedUsers.end(),
320               UpdateRouter(*this));
321
322 logger("%s reloaded successfully.", rsSettings.GetMapFileName().c_str());
323 printfd(__FILE__, "REMOTE_SCRIPT::Reload() %s reloaded successfully.\n");
324
325 return 0;
326 }
327 //-----------------------------------------------------------------------------
328 bool REMOTE_SCRIPT::PrepareNet()
329 {
330 sock = socket(AF_INET, SOCK_DGRAM, 0);
331
332 if (sock < 0)
333     {
334     errorStr = "Cannot create socket.";
335     logger("Canot create a socket: %s", strerror(errno));
336     printfd(__FILE__, "Cannot create socket\n");
337     return true;
338     }
339
340 return false;
341 }
342 //-----------------------------------------------------------------------------
343 bool REMOTE_SCRIPT::FinalizeNet()
344 {
345 close(sock);
346 return false;
347 }
348 //-----------------------------------------------------------------------------
349 void REMOTE_SCRIPT::PeriodicSend()
350 {
351 STG_LOCKER lock(&mutex);
352
353 std::map<uint32_t, RS::USER>::iterator it(authorizedUsers.begin());
354 while (it != authorizedUsers.end())
355     {
356     if (difftime(stgTime, it->second.lastSentTime) - (rand() % halfPeriod) > sendPeriod)
357         {
358         Send(it->second);
359         }
360     ++it;
361     }
362 }
363 //-----------------------------------------------------------------------------
364 #ifdef NDEBUG
365 bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t, RS::USER & rsu, bool forceDisconnect) const
366 #else
367 bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t bufSize, RS::USER & rsu, bool forceDisconnect) const
368 #endif
369 {
370 RS::PACKET_HEADER packetHead;
371
372 memset(packetHead.padding, 0, sizeof(packetHead.padding));
373 strcpy((char*)packetHead.magic, RS_ID);
374 packetHead.protoVer[0] = '0';
375 packetHead.protoVer[1] = '2';
376 if (forceDisconnect)
377     {
378     packetHead.packetType = RS_DISCONNECT_PACKET;
379     printfd(__FILE__, "RSCRIPT: force disconnect for '%s'\n", rsu.user->GetLogin().c_str());
380     }
381 else
382     {
383     if (rsu.shortPacketsCount % MAX_SHORT_PCKT == 0)
384         {
385         //SendLong
386         packetHead.packetType = rsu.user->IsInetable() ? RS_CONNECT_PACKET : RS_DISCONNECT_PACKET;
387         if (rsu.user->IsInetable())
388             printfd(__FILE__, "RSCRIPT: connect for '%s'\n", rsu.user->GetLogin().c_str());
389         else
390             printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
391         }
392     else
393         {
394         //SendShort
395         packetHead.packetType = rsu.user->IsInetable() ? RS_ALIVE_PACKET : RS_DISCONNECT_PACKET;
396         if (rsu.user->IsInetable())
397             printfd(__FILE__, "RSCRIPT: alive for '%s'\n", rsu.user->GetLogin().c_str());
398         else
399             printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
400         }
401     }
402 rsu.shortPacketsCount++;
403 rsu.lastSentTime = stgTime;
404
405 packetHead.ip = htonl(rsu.ip);
406 packetHead.id = htonl(rsu.user->GetID());
407 strncpy((char*)packetHead.login, rsu.user->GetLogin().c_str(), RS_LOGIN_LEN);
408 packetHead.login[RS_LOGIN_LEN - 1] = 0;
409
410 memcpy(buf, &packetHead, sizeof(packetHead));
411
412 if (packetHead.packetType == RS_ALIVE_PACKET)
413     {
414     return false;
415     }
416
417 RS::PACKET_TAIL packetTail;
418
419 memset(packetTail.padding, 0, sizeof(packetTail.padding));
420 strcpy((char*)packetTail.magic, RS_ID);
421 std::vector<std::string>::const_iterator it;
422 std::string params;
423 for(it = rsSettings.GetUserParams().begin();
424     it != rsSettings.GetUserParams().end();
425     ++it)
426     {
427     std::string parameter(rsu.user->GetParamValue(it->c_str()));
428     if (params.length() + parameter.length() > RS_PARAMS_LEN - 1)
429     {
430         logger("Script params string length %d exceeds the limit of %d symbols.", params.length() + parameter.length(), RS_PARAMS_LEN);
431         break;
432     }
433     params += parameter + " ";
434     }
435 strncpy((char *)packetTail.params, params.c_str(), RS_PARAMS_LEN);
436 packetTail.params[RS_PARAMS_LEN - 1] = 0;
437
438 assert(sizeof(packetHead) + sizeof(packetTail) <= bufSize && "Insufficient buffer space");
439
440 Encrypt(&ctx, buf + sizeof(packetHead), (char *)&packetTail, sizeof(packetTail) / 8);
441
442 return false;
443 }
444 //-----------------------------------------------------------------------------
445 bool REMOTE_SCRIPT::Send(RS::USER & rsu, bool forceDisconnect) const
446 {
447 char buffer[RS_MAX_PACKET_LEN];
448
449 memset(buffer, 0, sizeof(buffer));
450
451 if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
452     {
453     printfd(__FILE__, "REMOTE_SCRIPT::Send() - Invalid packet length!\n");
454     return true;
455     }
456
457 std::for_each(
458         rsu.routers.begin(),
459         rsu.routers.end(),
460         PacketSender(sock, buffer, sizeof(buffer), static_cast<uint16_t>(htons(rsSettings.GetPort())))
461         );
462
463 return false;
464 }
465 //-----------------------------------------------------------------------------
466 bool REMOTE_SCRIPT::SendDirect(RS::USER & rsu, uint32_t routerIP, bool forceDisconnect) const
467 {
468 char buffer[RS_MAX_PACKET_LEN];
469
470 if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
471     {
472     printfd(__FILE__, "REMOTE_SCRIPT::SendDirect() - Invalid packet length!\n");
473     return true;
474     }
475
476 struct sockaddr_in sendAddr;
477
478 sendAddr.sin_family = AF_INET;
479 sendAddr.sin_port = static_cast<uint16_t>(htons(rsSettings.GetPort()));
480 sendAddr.sin_addr.s_addr = routerIP;
481
482 ssize_t res = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&sendAddr, sizeof(sendAddr));
483
484 if (res < 0)
485     logger("sendto error: %s", strerror(errno));
486
487 return (res != sizeof(buffer));
488 }
489 //-----------------------------------------------------------------------------
490 bool REMOTE_SCRIPT::GetUsers()
491 {
492 USER_PTR u;
493
494 int h = users->OpenSearch();
495 assert(h && "USERS::OpenSearch is always correct");
496
497 while (!users->SearchNext(h, &u))
498     {
499     SetUserNotifiers(u);
500     }
501
502 users->CloseSearch(h);
503 return false;
504 }
505 //-----------------------------------------------------------------------------
506 std::vector<uint32_t> REMOTE_SCRIPT::IP2Routers(uint32_t ip)
507 {
508 STG_LOCKER lock(&mutex);
509 for (size_t i = 0; i < netRouters.size(); ++i)
510     {
511     if ((ip & netRouters[i].subnetMask) == (netRouters[i].subnetIP & netRouters[i].subnetMask))
512         {
513         return netRouters[i].routers;
514         }
515     }
516 return std::vector<uint32_t>();
517 }
518 //-----------------------------------------------------------------------------
519 void REMOTE_SCRIPT::SetUserNotifiers(USER_PTR u)
520 {
521 ipNotifierList.push_front(RS::IP_NOTIFIER(*this, u));
522 connNotifierList.push_front(RS::CONNECTED_NOTIFIER(*this, u));
523 }
524 //-----------------------------------------------------------------------------
525 void REMOTE_SCRIPT::UnSetUserNotifiers(USER_PTR u)
526 {
527 ipNotifierList.erase(std::remove_if(ipNotifierList.begin(),
528                                     ipNotifierList.end(),
529                                     USER_IS<IP_NOTIFIER>(u)),
530                      ipNotifierList.end());
531 connNotifierList.erase(std::remove_if(connNotifierList.begin(),
532                                       connNotifierList.end(),
533                                       USER_IS<CONNECTED_NOTIFIER>(u)),
534                        connNotifierList.end());
535
536 }
537 //-----------------------------------------------------------------------------
538 void REMOTE_SCRIPT::AddRSU(USER_PTR user)
539 {
540 RS::USER rsu(IP2Routers(user->GetCurrIP()), user);
541 Send(rsu);
542
543 STG_LOCKER lock(&mutex);
544 authorizedUsers.insert(std::make_pair(user->GetCurrIP(), rsu));
545 }
546 //-----------------------------------------------------------------------------
547 void REMOTE_SCRIPT::DelRSU(USER_PTR user)
548 {
549 STG_LOCKER lock(&mutex);
550 std::map<uint32_t, RS::USER>::iterator it(authorizedUsers.begin());
551 while (it != authorizedUsers.end())
552     {
553     if (it->second.user == user)
554         {
555         Send(it->second, true);
556         authorizedUsers.erase(it);
557         return;
558         }
559     ++it;
560     }
561 /*const std::map<uint32_t, RS::USER>::iterator it(
562         authorizedUsers.find(user->GetCurrIP())
563         );
564 if (it != authorizedUsers.end())
565     {
566     Send(it->second, true);
567     authorizedUsers.erase(it);
568     }*/
569 }
570 //-----------------------------------------------------------------------------
571 void RS::IP_NOTIFIER::Notify(const uint32_t & /*oldValue*/, const uint32_t & newValue)
572 {
573 if (newValue)
574     rs.AddRSU(user);
575 else
576     rs.DelRSU(user);
577 }
578 //-----------------------------------------------------------------------------
579 void RS::CONNECTED_NOTIFIER::Notify(const bool & /*oldValue*/, const bool & newValue)
580 {
581 if (newValue)
582     rs.AddRSU(user);
583 else
584     rs.DelRSU(user);
585 }
586 //-----------------------------------------------------------------------------
587 void REMOTE_SCRIPT::InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) const
588 {
589 unsigned char keyL[PASSWD_LEN];  // Пароль для шифровки
590 memset(keyL, 0, PASSWD_LEN);
591 strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
592 Blowfish_Init(ctx, keyL, PASSWD_LEN);
593 }
594 //-----------------------------------------------------------------------------
595 void REMOTE_SCRIPT::Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, size_t len8) const
596 {
597 if (dst != src)
598     memcpy(dst, src, len8 * 8);
599 for (size_t i = 0; i < len8; ++i)
600     Blowfish_Encrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
601 }
602 //-----------------------------------------------------------------------------