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