]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp
Optimized sending answers in sgconfig.
[stg.git] / projects / stargazer / plugins / configuration / sgconfig / rsconf.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 *
19 *    DESCRIPTION: æÁÊÌ Ó ÏÓÎÏ×ÎÙÍÉ ÆÕÎËÃÉÑÍÉ ÄÌÑ ÓÅÔÅ×ÏÇÏ ÏÂÍÅÎÁ ÄÁÎÎÙÍÉ
20 *    Ó ÍÅÎÅÄÖÅÒÏÍ ËÌÉÅÎÔÏ×. ðÒÉÅÍ, ÐÅÒÅÄÁÞÁ É ÛÉÆÒÏ×ÁÎÉÅ ÓÏÏÂÝÅÎÉÊ.
21 *
22 *    AUTHOR: Boris Mikhailenko <stg34@stargazer.dp.ua>
23 *
24 *    $Revision: 1.24 $
25 *    $Date: 2010/10/04 20:24:54 $
26 *
27 *******************************************************************/
28
29 #include "configproto.h"
30
31 #include "parser.h"
32
33 #include "stg/logger.h"
34 #include "stg/common.h"
35 #include "stg/blowfish.h"
36
37 #include <cerrno>
38 #include <csignal>
39 #include <cstdio> // snprintf
40 #include <cstring> // strerror
41
42 #include <unistd.h> // close
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47
48 #ifndef ENODATA
49 // FreeBSD 4.* - suxx
50 #define ENODATA -1
51 #endif
52
53 enum CONF_STATE
54     {
55     confHdr,
56     confLogin,
57     confLoginCipher,
58     confData
59     };
60
61 enum
62     {
63     ans_ok = 0,
64     ans_err
65     };
66
67 //-----------------------------------------------------------------------------
68 int CONFIGPROTO::Prepare()
69 {
70 int res;
71 struct sockaddr_in listenAddr;
72
73 sigset_t sigmask, oldmask;
74 sigemptyset(&sigmask);
75 sigaddset(&sigmask, SIGINT);
76 sigaddset(&sigmask, SIGTERM);
77 sigaddset(&sigmask, SIGUSR1);
78 sigaddset(&sigmask, SIGHUP);
79 pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
80
81 listenSocket = socket(PF_INET, SOCK_STREAM, 0);
82
83 if (listenSocket < 0)
84     {
85     errorStr = "Create NET_CONFIGURATOR socket failed.";
86     logger("Cannot create a socket: %s", strerror(errno));
87     return -1;
88     }
89
90 listenAddr.sin_family = PF_INET;
91 listenAddr.sin_port = htons(port);
92 listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
93
94 int lng = 1;
95
96 if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
97     {
98     errorStr = "Setsockopt failed. " + std::string(strerror(errno));
99     logger("setsockopt error: %s", strerror(errno));
100     return -1;
101     }
102
103 res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
104
105 if (res == -1)
106     {
107     errorStr = "Bind admin socket failed";
108     logger("Cannot bind the socket: %s", strerror(errno));
109     return -1;
110     }
111
112 res = listen(listenSocket, 0);
113 if (res == -1)
114     {
115     errorStr = "Listen admin socket failed";
116     logger("Cannot listen the socket: %s", strerror(errno));
117     return -1;
118     }
119
120 errorStr = "";
121 nonstop = true;
122 return 0;
123 }
124 //-----------------------------------------------------------------------------
125 int CONFIGPROTO::Stop()
126 {
127 nonstop = false;
128 close(listenSocket);
129 //TODO: Idiotism
130 int                 sock;
131 struct sockaddr_in  addr;
132 socklen_t           addrLen;
133 addr.sin_family = PF_INET;
134 addr.sin_port = htons(port);
135 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
136
137 addrLen = sizeof(addr);
138 sock = socket(PF_INET, SOCK_STREAM, 0);
139 connect(sock, (sockaddr*)&addr, addrLen);
140 close(sock);
141 //Idiotism end
142 return 0;
143 }
144 //-----------------------------------------------------------------------------
145 void CONFIGPROTO::Run()
146 {
147 state = confHdr;
148
149 while (nonstop)
150     {
151     state = confHdr;
152     struct sockaddr_in outerAddr;
153     socklen_t outerAddrLen(sizeof(outerAddr));
154     int outerSocket = accept(listenSocket,
155                              (struct sockaddr*)(&outerAddr),
156                              &outerAddrLen);
157
158     if (!nonstop)
159         break;
160
161     if (outerSocket < 0)
162         {
163         logger("accept error: %s", strerror(errno));
164         printfd(__FILE__, "accept failed\n");
165         continue;
166         }
167
168     adminIP = *(unsigned int*)&(outerAddr.sin_addr);
169
170     if (state == confHdr)
171         {
172         if (RecvHdr(outerSocket) < 0)
173             {
174             close(outerSocket);
175             continue;
176             }
177         if (state == confLogin)
178             {
179             if (SendHdrAnswer(outerSocket, ans_ok) < 0)
180                 {
181                 close(outerSocket);
182                 continue;
183                 }
184             if (RecvLogin(outerSocket) < 0)
185                 {
186                 close(outerSocket);
187                 continue;
188                 }
189             if (state == confLoginCipher)
190                 {
191                 if (SendLoginAnswer(outerSocket) < 0)
192                     {
193                     close(outerSocket);
194                     continue;
195                     }
196                 if (RecvLoginS(outerSocket) < 0)
197                     {
198                     close(outerSocket);
199                     continue;
200                     }
201                 if (state == confData)
202                     {
203                     if (SendLoginSAnswer(outerSocket, ans_ok) < 0)
204                         {
205                         close(outerSocket);
206                         continue;
207                         }
208                     if (RecvData(outerSocket) < 0)
209                         {
210                         close(outerSocket);
211                         continue;
212                         }
213                     state = confHdr;
214                     }
215                 else
216                     {
217                     if (SendLoginSAnswer(outerSocket, ans_err) < 0)
218                         {
219                         close(outerSocket);
220                         continue;
221                         }
222                     WriteLogAccessFailed(adminIP);
223                     }
224                 }
225             else
226                 {
227                 WriteLogAccessFailed(adminIP);
228                 }
229             }
230         else
231             {
232             WriteLogAccessFailed(adminIP);
233             if (SendHdrAnswer(outerSocket, ans_err) < 0)
234                 {
235                 close(outerSocket);
236                 continue;
237                 }
238             }
239         }
240     else
241         {
242         WriteLogAccessFailed(adminIP);
243         }
244     printfd(__FILE__, "Successfull connection from %s\n", inet_ntostring(outerAddr.sin_addr.s_addr).c_str());
245     close(outerSocket);
246     }
247 }
248 //-----------------------------------------------------------------------------
249 int CONFIGPROTO::RecvHdr(int sock)
250 {
251 char buf[sizeof(STG_HEADER)];
252 memset(buf, 0, sizeof(STG_HEADER));
253 size_t stgHdrLen = sizeof(STG_HEADER) - 1; // Without 0-char
254 size_t pos = 0;
255 while (pos < stgHdrLen)
256     {
257     if (!WaitPackets(sock))
258         {
259         state = confHdr;
260         SendError(sock, "Bad request");
261         return -1;
262         }
263     ssize_t ret = recv(sock, &buf[pos], static_cast<int>(stgHdrLen) - static_cast<int>(pos), 0);
264     if (ret <= 0)
265         {
266         if (ret < 0)
267             logger("recv error: %s", strerror(errno));
268         state = confHdr;
269         return -1;
270         }
271     pos += ret;
272     }
273
274 if (0 == strncmp(buf, STG_HEADER, strlen(STG_HEADER)))
275     {
276     state = confLogin;
277     return 0;
278     }
279 else
280     {
281     SendError(sock, "Bad request");
282     }
283
284 state = confHdr;
285 return -1;
286 }
287 //-----------------------------------------------------------------------------
288 int CONFIGPROTO::SendHdrAnswer(int sock, int err)
289 {
290 if (err)
291     {
292     if (send(sock, ERR_HEADER, sizeof(ERR_HEADER) - 1, 0) < 0)
293         {
294         logger("send error: %s", strerror(errno));
295         return -1;
296         }
297     }
298 else
299     {
300     if (send(sock, OK_HEADER, sizeof(OK_HEADER) - 1, 0) < 0)
301         {
302         logger("send error: %s", strerror(errno));
303         return -1;
304         }
305     }
306
307 return 0;
308 }
309 //-----------------------------------------------------------------------------
310 int CONFIGPROTO::RecvLogin(int sock)
311 {
312 char login[ADM_LOGIN_LEN + 1];
313
314 memset(login, 0, ADM_LOGIN_LEN + 1);
315
316 size_t pos = 0;
317 while (pos < ADM_LOGIN_LEN) {
318     if (!WaitPackets(sock))
319         {
320         state = confHdr;
321         return ENODATA;
322         }
323
324     ssize_t ret = recv(sock, &login[pos], ADM_LOGIN_LEN - static_cast<int>(pos), 0);
325
326     if (ret <= 0)
327         {
328         // Error in network
329         logger("recv error: %s", strerror(errno));
330         state = confHdr;
331         return ENODATA;
332         }
333
334     pos += ret;
335 }
336
337 if (admins->Find(login, &currAdmin))
338     {
339     // Admin not found
340     state = confHdr;
341     return ENODATA;
342     }
343
344 currAdmin->SetIP(adminIP);
345 adminLogin = login;
346 state = confLoginCipher;
347 return 0;
348 }
349 //-----------------------------------------------------------------------------
350 int CONFIGPROTO::SendLoginAnswer(int sock)
351 {
352 if (send(sock, OK_LOGIN, sizeof(OK_LOGIN) - 1, 0) < 0)
353     {
354     logger("Send OK_LOGIN error in SendLoginAnswer.");
355     return -1;
356     }
357 return 0;
358 }
359 //-----------------------------------------------------------------------------
360 int CONFIGPROTO::RecvLoginS(int sock)
361 {
362 char loginS[ADM_LOGIN_LEN + 1];
363 memset(loginS, 0, ADM_LOGIN_LEN + 1);
364
365 size_t pos = 0;
366 while (pos < ADM_LOGIN_LEN)
367     {
368     if (!WaitPackets(sock))
369         {
370         state = confHdr;
371         return ENODATA;
372         }
373
374     ssize_t ret = recv(sock, &loginS[pos], ADM_LOGIN_LEN - static_cast<int>(pos), 0);
375
376     if (ret <= 0)
377         {
378         // Network error
379         printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
380         logger("recv error: %s", strerror(errno));
381         state = confHdr;
382         return ENODATA;
383         }
384
385     pos += ret;
386     }
387
388 if (currAdmin->GetLogin().empty())
389     {
390     state = confHdr;
391     return ENODATA;
392     }
393
394 BLOWFISH_CTX ctx;
395 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
396
397 char login[ADM_LOGIN_LEN + 1];
398 for (size_t i = 0; i < ADM_LOGIN_LEN / 8; i++)
399     DecodeString(login + i * 8, loginS + i * 8, &ctx);
400
401 if (currAdmin == admins->GetNoAdmin())
402     {
403     // If there are no admins registered in the system - give access with any password
404     state = confData;
405     return 0;
406     }
407
408 if (strncmp(currAdmin->GetLogin().c_str(), login, ADM_LOGIN_LEN) != 0)
409     {
410     state = confHdr;
411     return ENODATA;
412     }
413
414 state = confData;
415 adminPassword = currAdmin->GetPassword();
416 return 0;
417 }
418 //-----------------------------------------------------------------------------
419 int CONFIGPROTO::SendLoginSAnswer(int sock, int err)
420 {
421 if (err)
422     {
423     if (send(sock, ERR_LOGINS, sizeof(ERR_LOGINS) - 1, 0) < 0)
424         {
425         logger("send error: %s", strerror(errno));
426         return -1;
427         }
428     }
429 else
430     {
431     if (send(sock, OK_LOGINS, sizeof(OK_LOGINS) - 1, 0) < 0)
432         {
433         logger("send error: %s", strerror(errno));
434         return -1;
435         }
436     }
437 return 0;
438 }
439 //-----------------------------------------------------------------------------
440 int CONFIGPROTO::RecvData(int sock)
441 {
442 requestList.clear();
443 BLOWFISH_CTX ctx;
444
445 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
446
447 while (1)
448     {
449     bool done = false;
450     char bufferS[8];
451     size_t pos = 0;
452     while (pos < sizeof(bufferS))
453         {
454         if (!WaitPackets(sock))
455             {
456             done = true;
457             break;
458             }
459
460         ssize_t ret = recv(sock, &bufferS[pos], sizeof(bufferS) - static_cast<int>(pos), 0);
461         if (ret < 0)
462             {
463             // Network error
464             logger("recv error: %s", strerror(errno));
465             printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
466             return -1;
467             }
468
469         if (ret == 0)
470             {
471             done = true;
472             break;
473             }
474
475         pos += ret;
476         }
477
478     char buffer[8];
479     buffer[7] = 0;
480
481     DecodeString(buffer, bufferS, &ctx);
482     requestList.push_back(std::string(buffer, pos));
483
484     if (done || memchr(buffer, 0, pos) != NULL)
485         {
486         // End of data
487         if (ParseCommand())
488             return SendError(sock, "Bad command");
489         else
490             return SendDataAnswer(sock, currParser->GetAnswer());
491         }
492     }
493 //return 0;
494 }
495 //-----------------------------------------------------------------------------
496 int CONFIGPROTO::SendDataAnswer(int sock, const std::string & answer)
497 {
498 if (answer.empty())
499     return 0;
500
501 BLOWFISH_CTX ctx;
502 EnDecodeInit(adminPassword.c_str(), ADM_PASSWD_LEN, &ctx);
503
504 std::string::size_type pos = 0;
505 std::string::size_type length = answer.length();
506 while (pos < length)
507     {
508     char buffer[1024];
509     std::string::size_type chunkLength = std::min(length - pos, sizeof(buffer));
510     EncodeFullString(buffer, answer.c_str() + pos, chunkLength, ctx);
511     if (send(sock, buffer, chunkLength, 0) < 0)
512         return -1;
513     pos += chunkLength;
514     }
515
516 return 1;
517 }
518 //-----------------------------------------------------------------------------
519 int CONFIGPROTO::SendError(int sock, const std::string & text)
520 {
521 return SendDataAnswer(sock, "<Error value=\"" + text + "\"/>");
522 }
523 //-----------------------------------------------------------------------------
524 void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
525 {
526 logger("Admin's connection failed. IP %s", inet_ntostring(ip).c_str());
527 }
528 //-----------------------------------------------------------------------------