]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/userstat/userstat.cpp
eca424e89fe739e69e34524b8ab31289b96ed736
[stg.git] / projects / stargazer / plugins / other / userstat / userstat.cpp
1 #include <algorithm>
2 #include <cstring>
3 #include <cerrno>
4 #include <arpa/inet.h>
5 #include <csignal>
6
7 #include "common.h"
8 #include "../../../users.h"
9
10 #include "userstat.h"
11
12 BASE_PLUGIN * GetPlugin()
13 {
14 return new USERSTAT();
15 }
16
17 USERSTAT::USERSTAT()
18     : maxThreads(16),
19       port(5555)
20 {
21 xmlParser = XML_ParserCreate(NULL);
22 pthread_mutex_init(&mutex, NULL);
23 }
24
25 USERSTAT::~USERSTAT()
26 {
27 XML_ParserFree(xmlParser);
28 }
29
30 int USERSTAT::ParseSettings()
31 {
32 vector<PARAM_VALUE>::iterator i;
33 string s;
34
35 for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
36     {
37     s = i->param;
38     transform(s.begin(), s.end(), s.begin(), USERSTAT::ToLower());
39     if (s == "port")
40         {
41         if (str2x<uint16_t>(*(i->value.begin()), port)) 
42             {
43             errorStr = "'Port' parameter must be a numeric value";
44             return -1;
45             }
46         }
47     if (s == "maxthreads")
48         {
49         if (str2x<unsigned>(*(i->value.begin()), maxThreads)) 
50             {
51             errorStr = "'MaxThreads' parameter must be a numeric value";
52             return -1;
53             }
54         }
55     }
56
57 return 0;
58 }
59
60 int USERSTAT::Prepare()
61 {
62 listenSocket = socket(PF_INET, SOCK_STREAM, 0);
63
64 if (listenSocket < 0)
65     {
66     errorStr = "Create USERSTAT socket failed.";
67     return -1;
68     }
69
70 printfd(__FILE__, "USERSTAT::Prepare() socket - ok\n");
71
72 listenAddr.sin_family = PF_INET;
73 listenAddr.sin_port = htons(port);
74 listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
75
76 int lng = 1;
77
78 if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
79     {
80     errorStr = "Setsockopt failed. " + string(strerror(errno));
81     return -1;
82     }
83
84 printfd(__FILE__, "USERSTAT::Prepare() setsockopt - ok\n");
85
86 int res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
87
88 if (res == -1)
89     {
90     errorStr = "Bind USERSTAT socket failed";
91     return -1;
92     }
93
94 printfd(__FILE__, "USERSTAT::Prepare() bind - ok port: %d\n", port);
95
96 res = listen(listenSocket, 0);
97 if (res == -1)
98     {
99     errorStr = "Listen USERSTAT socket failed";
100     return -1;
101     }
102 printfd(__FILE__, "USERSTAT::Prepare() listen - ok\n");
103
104 errorStr = "";
105 return 0;
106 }
107
108 int USERSTAT::Finalize()
109 {
110 return close(listenSocket);
111 }
112
113 int USERSTAT::Start()
114 {
115 if (Prepare())
116     {
117     return -1;
118     }
119 nonstop = true;
120 if (pthread_create(&thread, NULL, Run, this))
121     {
122     errorStr = "Cannot create thread";
123     return -1;
124     }
125
126 return 0;
127 }
128
129 int USERSTAT::Stop()
130 {
131 nonstop = false;
132 if (pthread_kill(thread, SIGTERM))
133     {
134     errorStr = "Cannot send signal to thread";
135     return -1;
136     }
137 for (int i = 0; i < 25; i++)
138     {
139     if (!isRunning)
140         break;
141
142     usleep(200000);
143     }
144 if (isRunning)
145     {
146     errorStr = "Cannot stop thread";
147     return -1;
148     }
149 return 0;
150 }
151
152 void * USERSTAT::Run(void * t)
153 {
154 USERSTAT * us = reinterpret_cast<USERSTAT *>(t);
155 pthread_t thread;
156 int outerSocket;
157 struct sockaddr_in outerAddr;
158 socklen_t outerAddrLen;
159 THREAD_INFO info;
160
161 us->isRunning = true;
162 while (us->nonstop)
163     {
164     outerSocket = accept(us->listenSocket, (struct sockaddr *)&outerAddr, &outerAddrLen); 
165     if (outerSocket > 0)
166         {
167         std::vector<THREAD_INFO>::iterator it;
168         us->pool.erase(remove_if(us->pool.begin(), us->pool.end(), USERSTAT::IsDone()), us->pool.end());
169
170         while (us->pool.size() >= us->maxThreads)
171             usleep(200000);
172         
173         info.users = us->users;
174         info.store = us->store;
175         info.outerSocket = outerSocket;
176         info.done = false;
177         us->pool.push_back(info);
178         it = us->pool.end();
179         --it;
180
181         if (pthread_create(&thread, NULL, Operate, &(*it)))
182             {
183             us->errorStr = "Cannot create thread";
184             printfd(__FILE__, "Cannot create thread\n");
185             }
186         it->thread = thread;
187         }
188     }
189 us->isRunning = false;
190 return NULL;
191 }
192
193 void * USERSTAT::Operate(void * i)
194 {
195     THREAD_INFO * info = reinterpret_cast<THREAD_INFO *>(i);
196     unsigned char * buf;
197     int32_t size;
198     char * login;
199
200     int res = read(info->outerSocket, &size, sizeof(size));
201     if (res != sizeof(size))
202     {
203         printfd(__FILE__, "Reading stream size failed! Wanted %d bytes, got %d bytes.\n", sizeof(size), res);
204         info->done = true;
205         return NULL;
206     }
207
208     printfd(__FILE__, "USERSTAT::Operate() size = %d\n", size);
209
210     if (size < 0) {
211         printfd(__FILE__, "USERSTAT::Operate() Invalid data size.\n");
212         info->done = true;
213         return NULL;
214     }
215
216     login = new char[size];
217
218     res = read(info->outerSocket, login, size);
219     if (res != size)
220     {
221         printfd(__FILE__, "Reading login failed! Wanted %d bytes, got %d bytes.\n", 32, res);
222         info->done = true;
223         return NULL;
224     }
225
226     std::string l;
227     l.assign(login, size);
228
229     res = read(info->outerSocket, &size, sizeof(size));
230     if (res != sizeof(size))
231     {
232         printfd(__FILE__, "Reading stream size failed! Wanted %d bytes, got %d bytes.\n", sizeof(size), res);
233         info->done = true;
234         return NULL;
235     }
236
237     printfd(__FILE__, "USERSTAT::Operate() size = %d\n", size);
238
239     if (size < 0) {
240         printfd(__FILE__, "USERSTAT::Operate() Invalid data size.\n");
241         info->done = true;
242         return NULL;
243     }
244
245     buf = new unsigned char[size];
246     res = read(info->outerSocket, buf, size);
247     if (res != size)
248     {
249         printfd(__FILE__, "Reading stream failed! Wanted %d bytes, got %d bytes.\n", size, res);
250         info->done = true;
251         return NULL;
252     }
253
254     printfd(__FILE__, "Received data: %s\n", buf);
255
256     user_iter it;
257     if (info->users->FindByName(l, &it))
258     {
259         printfd(__FILE__, "User '%s' not found.\n", login);
260         info->done = true;
261         return NULL;
262     }
263
264     std::string password = it->property.password;
265     
266     printfd(__FILE__, "USERSTAT::Operate() Requested user: '%s'\n", login);
267     printfd(__FILE__, "USERSTAT::Operate() Encription init using password: '%s'\n", password.c_str());
268
269     BLOWFISH_CTX ctx;
270     char * key = new char[password.length()];
271     strncpy(key, password.c_str(), password.length());
272
273     Blowfish_Init(&ctx,
274                   reinterpret_cast<unsigned char *>(key),
275                   password.length());
276
277     for (int i = 0; i < size / 8; ++i) {
278         uint32_t a;
279         uint32_t b;
280         a = n2l(buf + i * 8);
281         b = n2l(buf + i * 8 + 4);
282         Blowfish_Decrypt(&ctx,
283                          &a,
284                          &b);
285         l2n(a, buf + i * 8);
286         l2n(b, buf + i * 8 + 4);
287     }
288
289     delete[] key;
290
291     printfd(__FILE__, "Received XML: %s\n", buf);
292
293     info->done = true;
294     delete[] buf;
295     return NULL;
296 }