]> git.stg.codes - stg.git/blob - projects/sgauth/web.cpp
Add an option to opt-out Firebird store.
[stg.git] / projects / sgauth / web.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  */
20
21  /*
22  $Revision: 1.7 $
23  $Date: 2010/03/15 12:58:17 $
24  */
25
26 #include <libintl.h>
27
28 #include <csignal>
29 #include <cstdio>
30 #include <cstring>
31 #include <ctime>
32
33 #include "stg/common.h"
34 #include "stg/ia.h"
35 #include "web.h"
36
37 extern WEB * web;
38 extern IA_CLIENT_PROT * clnp;
39
40 #define LISTEN_PORT (5580)
41
42 #include "css.h"
43 //---------------------------------------------------------------------------
44 WEB::WEB()
45     : m_res(0),
46       m_listenSocket(0),
47       m_outerSocket(0),
48       m_refreshPeriod(0),
49       m_listenWebAddr(0)
50 {
51 #ifdef WIN32
52 m_res = WSAStartup(MAKEWORD(2,0), &m_wsaData);
53 #endif
54
55 for (int i = 0; i < DIR_NUM; i++)
56     m_dirName[i] = "-";
57
58 m_refreshPeriod = 5;
59
60 memset(&m_ls, 0, sizeof(m_ls));
61 }
62 //---------------------------------------------------------------------------
63 void WEB::Start()
64 {
65 m_thread = std::jthread([this](auto token){ Run(std::move(token)); });
66 }
67 //---------------------------------------------------------------------------
68 void WEB::PrepareNet()
69 {
70 m_listenSocket = socket(PF_INET, SOCK_STREAM, 0);
71
72 struct sockaddr_in listenAddr;
73 listenAddr.sin_family = AF_INET;
74 listenAddr.sin_port = htons(LISTEN_PORT);
75 listenAddr.sin_addr.s_addr = m_listenWebAddr;
76
77 #ifndef WIN32
78 int lng = 1;
79 if (0 != setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
80     {
81     printf("Setsockopt Fail\n");
82     printf(">>> Error %s\n", strerror(errno));
83     }
84 #else
85 //??? TODO
86 #endif
87
88
89 m_res = bind(m_listenSocket, reinterpret_cast<sockaddr*>(&listenAddr), sizeof(listenAddr));
90
91 if (m_res == -1)
92     {
93     printf("Bind failed.\n");
94     exit(0);
95     }
96
97 m_res = listen(m_listenSocket, 0);
98 if (m_res == -1)
99     {
100     printf("Listen failed.\n");
101     exit(0);
102     }
103 }
104 //---------------------------------------------------------------------------
105 void WEB::SetRefreshPagePeriod(int p)
106 {
107 m_refreshPeriod = p;
108 if (m_refreshPeriod <= 0 || m_refreshPeriod > 24*3600)
109     m_refreshPeriod = 5;
110 }
111 //---------------------------------------------------------------------------
112 void WEB::SetListenAddr(uint32_t ip)
113 {
114 m_listenWebAddr = ip;
115 }
116 //---------------------------------------------------------------------------
117 void WEB::Run(std::stop_token token) noexcept
118 {
119 sigset_t signalSet;
120 sigfillset(&signalSet);
121 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
122
123 PrepareNet();
124 char recvBuffer[4096];
125 while (!token.stop_requested())
126     {
127     struct sockaddr_in outerAddr;
128
129     #ifndef WIN32
130     socklen_t outerAddrLen = sizeof(outerAddr);
131     #else
132     int outerAddrLen = sizeof(outerAddr);
133     #endif
134
135     m_outerSocket = accept(m_listenSocket, reinterpret_cast<sockaddr*>(&outerAddr), &outerAddrLen);
136     if (m_outerSocket == -1)
137         {
138         printf(">>> Error %s\n", strerror(errno));
139         continue;
140         }
141     recv(m_outerSocket, recvBuffer, sizeof(recvBuffer), 0);
142
143     if (strncmp(recvBuffer, "GET /sgauth.css", strlen("GET /sgauth.css")) == 0)
144         {
145         SendCSS();
146         //printf("(1) recvBuffer=%s\n", recvBuffer);
147         }
148     else if (strncmp(recvBuffer, "GET /disconnect", strlen("GET /disconnect")) == 0)
149         {
150         clnp->Disconnect();
151         Redirect("/");
152         //printf("(2) recvBuffer=%s\n", recvBuffer);
153         }
154     else if (strncmp(recvBuffer, "GET /connect", strlen("GET /connect")) == 0)
155         {
156         clnp->Connect();
157         Redirect("/");
158         //printf("(3) recvBuffer=%s\n", recvBuffer);
159         }
160     else if (strncmp(recvBuffer, "GET /exit", strlen("GET /exit")) == 0)
161         {
162         Redirect("/");
163         clnp->Disconnect();
164         #ifdef WIN32
165         Sleep(1000);
166         #else
167         struct timespec ts = {1, 0};
168         nanosleep(&ts, NULL);
169         #endif
170         exit(0);
171         }
172     else
173        {
174        SendReply();
175        //printf("(4) recvBuffer=%s\n", recvBuffer);
176        }
177
178     #ifdef WIN32
179     closesocket(m_outerSocket);
180     #else
181     close(m_outerSocket);
182     #endif
183     }
184 }
185 //---------------------------------------------------------------------------
186 int WEB::Redirect(const char * url)
187 {
188 const char * redirect =
189     "HTTP/1.0 200 OK\n"
190     "Content-Type: text/html\n"
191     "Connection: close"
192     "\n\n"
193     "<html>\n"
194     "<head>\n"
195     "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;%s\">\n"
196     "</head>\n"
197     "<body>\n"
198     "</body></html>\n\n";
199
200 char buff[2000];
201 sprintf(buff, redirect, url);
202 send(m_outerSocket, buff, strlen(buff), 0);
203
204 return 0;
205 }
206 //---------------------------------------------------------------------------
207 int WEB::SendReply()
208 {
209 int j, rowNum;
210
211 const char * replyHeader =
212     "HTTP/1.0 200 OK\n"
213     "Content-Type: text/html\n"
214     "Connection: close"
215     "\n\n"
216     "<html>\n"
217     "<head>\n"
218     "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">\n"
219     "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">\n"
220     "<title>sgauth</title>\n"
221     "<link rel=\"Stylesheet\" href=\"sgauth.css\">"
222     "</head>\n"
223     "<body>\n"
224     "<H3>Stargazer</H3><p>\n";
225
226 const char * replyFooter = "</body></html>\n\n";
227
228 char replyHeaderBuffer[2000];
229 sprintf(replyHeaderBuffer, replyHeader, m_refreshPeriod);
230
231 send(m_outerSocket, replyHeaderBuffer, strlen(replyHeaderBuffer), 0);
232
233 char str[512];
234
235 int st = clnp->GetAuthorized();
236
237 sprintf(str, "<a href=\"connect\">%s</a><p>\n", gettext("Connect"));
238 m_res = send(m_outerSocket, str, strlen(str), 0);
239
240 sprintf(str, "<a href=\"disconnect\">%s</a><p>\n", gettext("Disconnect"));
241 m_res = send(m_outerSocket, str, strlen(str), 0);
242
243 sprintf(str, "<a href=\"/\">%s</a><p>\n", gettext("Refresh"));
244 m_res = send(m_outerSocket, str, strlen(str), 0);
245
246 sprintf(str, "<a href=\"exit\">%s</a><p>\n", gettext("Exit"));
247 m_res = send(m_outerSocket, str, strlen(str), 0);
248
249 sprintf(str, "<div id=\"%s\">%s</div><p>\n" , st ? "ConnectionStateOnline":"ConnectionStateOffline", st ? "Online":"Offline");
250 m_res = send(m_outerSocket, str, strlen(str), 0);
251
252 sprintf(str, "<div id=\"Cash\">%s: %.3f</div><p>\n" , gettext("Cash"), m_ls.cash / 1000.0);
253 m_res = send(m_outerSocket, str, strlen(str), 0);
254
255 sprintf(str, "<div id=\"Prepaid Traffic\">%s: %s</div><p>\n" ,
256         gettext("PrepaidTraffic"),
257         m_ls.freeMb[0] == 'C' ? m_ls.freeMb + 1 : m_ls.freeMb);
258 m_res = send(m_outerSocket, str, strlen(str), 0);
259
260 sprintf(str, "<TABLE id=\"TraffTable\">\n");
261 m_res = send(m_outerSocket, str, strlen(str), 0);
262 sprintf(str, "    <TR id=\"TraffTableCaptionRow\">\n");
263 m_res = send(m_outerSocket, str, strlen(str), 0);
264 sprintf(str, "       <TD id=\"TraffTableCaptionCellC\">&nbsp;</TD>\n");
265 m_res = send(m_outerSocket, str, strlen(str), 0);
266
267 rowNum = 0;
268 for (j = 0; j < DIR_NUM; j++)
269     {
270     if (m_dirName[j][0] == 0)
271         continue;
272     std::string s;
273     KOIToWin(m_dirName[j], &s);// +++++++++ sigsegv ==========   TODO too long dir name crashes sgauth
274     sprintf(str, "       <TD id=\"TraffTableCaptionCell%d\">%s</TD>\n", rowNum++, s.c_str());
275     send(m_outerSocket, str, strlen(str), 0);
276     }
277
278 sprintf(str,"    </TR>\n");
279 send(m_outerSocket, str, strlen(str), 0);
280
281 sprintf(str,"    <TR id=\"TraffTableUMRow\">\n");
282 send(m_outerSocket, str, strlen(str), 0);
283
284 sprintf(str,"        <TD id=\"TraffTableUMCellC\">%s</TD>\n", gettext("Month Upload"));
285 send(m_outerSocket, str, strlen(str), 0);
286
287 rowNum = 0;
288 for (j = 0; j < DIR_NUM; j++)
289     {
290     if (m_dirName[j][0] == 0)
291         continue;
292     sprintf(str,"        <TD id=\"TraffTableUMCell%d\">%s</TD>\n", rowNum++, IntToKMG(m_ls.mu[j], ST_F));
293     m_res = send(m_outerSocket, str, strlen(str), 0);
294     }
295
296 sprintf(str,"    </TR>\n");
297 m_res = send(m_outerSocket, str, strlen(str), 0);
298 sprintf(str,"    <TR id=\"TraffTableDMRow\">\n");
299 m_res = send(m_outerSocket, str, strlen(str), 0);
300 sprintf(str,"        <TD id=\"TraffTableDMCellC\">%s</TD>\n", gettext("Month Download"));
301 m_res = send(m_outerSocket, str, strlen(str), 0);
302
303 rowNum = 0;
304 for (j = 0; j < DIR_NUM; j++)
305     {
306     if (m_dirName[j][0] == 0)
307         continue;
308     sprintf(str,"        <TD id=\"TraffTableDMCell%d\">%s</TD>\n", rowNum++, IntToKMG(m_ls.md[j], ST_F));
309     m_res = send(m_outerSocket, str, strlen(str), 0);
310     }
311 sprintf(str,"    </TR>\n");
312 m_res = send(m_outerSocket, str, strlen(str), 0);
313
314
315 sprintf(str,"    <TR id=\"TraffTableUSRow\">\n");
316 m_res = send(m_outerSocket, str, strlen(str), 0);
317 sprintf(str,"        <TD id=\"TraffTableUSCellC\">%s</TD>\n", gettext("Session Upload"));
318 m_res = send(m_outerSocket, str, strlen(str), 0);
319
320 rowNum = 0;
321 for (j = 0; j < DIR_NUM; j++)
322     {
323     if (m_dirName[j][0] == 0)
324         continue;
325     sprintf(str,"        <TD id=\"TraffTableUSCell%d\">%s</TD>\n", rowNum++, IntToKMG(m_ls.su[j], ST_F));
326     m_res = send(m_outerSocket, str, strlen(str), 0);
327     }
328
329 sprintf(str,"    </TR>\n");
330 m_res = send(m_outerSocket, str, strlen(str), 0);
331 sprintf(str,"    <TR id=\"TraffTableDSRow\">\n");
332 m_res = send(m_outerSocket, str, strlen(str), 0);
333 sprintf(str,"        <TD id=\"TraffTableDSCellC\">%s</TD>\n", gettext("Session Download"));
334 m_res = send(m_outerSocket, str, strlen(str), 0);
335
336 for (j = 0; j < DIR_NUM; j++)
337     {
338     if (m_dirName[j][0] == 0)
339         continue;
340     sprintf(str,"        <TD id=\"TraffTableDSCell%d\">%s</TD>\n", j, IntToKMG(m_ls.sd[j], ST_F));
341     m_res = send(m_outerSocket, str, strlen(str), 0);
342     }
343
344 sprintf(str,"    </TR>\n");
345 m_res = send(m_outerSocket, str, strlen(str), 0);
346
347 sprintf(str,"</TABLE>\n");
348 m_res = send(m_outerSocket, str, strlen(str), 0);
349
350 rowNum = 0;
351 if (!m_messages.empty())
352     {
353     sprintf(str,"    <TABLE id=\"MessagesTable\">\n");
354     m_res = send(m_outerSocket, str, strlen(str), 0);
355
356     sprintf(str,"        <TR id=\"MessagesTableRowC\">\n");
357     send(m_outerSocket, str, strlen(str), 0);
358     sprintf(str,"            <TD>Date</TD>\n");
359     send(m_outerSocket, str, strlen(str), 0);
360     sprintf(str,"            <TD>Text</TD>\n");
361     send(m_outerSocket, str, strlen(str), 0);
362     sprintf(str,"        </TR>\n");
363     send(m_outerSocket, str, strlen(str), 0);
364
365     std::list<STG_MESSAGE>::reverse_iterator it;
366     it = m_messages.rbegin();
367     while (it != m_messages.rend())
368         {
369         sprintf(str,"        <TR id=\"MessagesTableRow%d\">\n", rowNum);
370         send(m_outerSocket, str, strlen(str), 0);
371         sprintf(str,"            <TD>%s</TD>\n", it->recvTime.c_str());
372         send(m_outerSocket, str, strlen(str), 0);
373         sprintf(str,"            <TD>%s</TD>\n", it->msg.c_str());
374         send(m_outerSocket, str, strlen(str), 0);
375         sprintf(str,"        </TR>\n");
376         send(m_outerSocket, str, strlen(str), 0);
377         ++it;
378         ++rowNum;
379         }
380
381     sprintf(str,"   </TABLE>\n");
382     m_res = send(m_outerSocket, str, strlen(str), 0);
383     }
384
385 time_t t = time(NULL);
386 sprintf(str,"Îáíîâëåíî: %s</b>" , ctime(&t));
387 m_res = send(m_outerSocket, str, strlen(str), 0);
388
389 send(m_outerSocket, replyFooter, strlen(replyFooter), 0);
390
391 return 0;
392 }
393 //---------------------------------------------------------------------------
394 int WEB::SendCSS()
395 {
396 const char * replyHeader =
397     "HTTP/1.0 200 OK\n"
398     "Content-Type: text/css\n"
399     "Connection: close\n\n";
400
401 const char * replyFooter= "\n\n";
402
403 send(m_outerSocket, replyHeader, strlen(replyHeader), 0);
404 send(m_outerSocket, SGAuth::css, strlen(SGAuth::css), 0);
405 send(m_outerSocket, replyFooter, strlen(replyFooter), 0);
406
407 return 0;
408 }
409 //---------------------------------------------------------------------------
410 void WEB::SetDirName(const std::string & dn, int n)
411 {
412 web->m_dirName[n] =  dn;
413 }
414 //---------------------------------------------------------------------------
415 void WEB::AddMessage(const std::string & message, int type)
416 {
417 time_t t = time(NULL);
418 STG_MESSAGE m;
419
420 m.msg = message;
421 m.type = type;
422 m.recvTime = ctime(&t);
423
424 m_messages.push_back(m);
425
426 if (m_messages.size() > MAX_MESSAGES)
427     m_messages.pop_front();
428
429 }
430 //---------------------------------------------------------------------------
431 void WEB::UpdateStat(const LOADSTAT & ls)
432 {
433 memcpy(&m_ls, &ls, sizeof(LOADSTAT));
434 }
435 //---------------------------------------------------------------------------
436