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