BmnRoot
Loading...
Searching...
No Matches
MpdWebScreenshots.cxx
Go to the documentation of this file.
1// -------------------------------------------------------------------------
2// ----- MpdWebScreenshots source file -----
3// -------------------------------------------------------------------------
4#include "MpdWebScreenshots.h"
5
6#include "TEveManager.h"
7#include "TGLViewer.h"
8#include <TThread.h>
9
10#include <sys/stat.h>
11#include <sys/socket.h>
12#include <sys/wait.h>
13#include <netinet/in.h>
14
15#include <iostream>
16using namespace std;
17
18// ----- Default constructor (private) ----------------------------------
20 : FairTask("MpdWebScreenshots", 0)
21{}
22
23// ----- Destructor ----------------------------------------------------
26
27// ----- Standard constructor ------------------------------------------
28MpdWebScreenshots::MpdWebScreenshots(const char* name, char* output_dir, bool isWebServer, Int_t iVerbose)
29 : FairTask(name, iVerbose)
30{
31 outputDir = output_dir;
32 outputDir += "/";
33
34 isWebStarted = false;
35 isWeb = isWebServer;
36 if (isWebServer)
37 return;
38
39 if (strlen(outputDir) > 0)
40 {
41 struct stat st = {0};
42 if (stat(outputDir, &st) == -1) mkdir(outputDir, 0700);
43
44 cout<<"Images of the event display will be saved in directory: "<<outputDir<<endl;
45 }
46}
47
48// -------------------------------------------------------------------------
50{
51 if (fVerbose > 1) cout<<"MpdWebScreenshots::Init()"<<endl;
52
53 if (!IsActive())
54 return kERROR;
55
57
58 // start web server if required
59 if (isWeb && (!isWebStarted))
60 {
61 // Set daemon to FALSE
62 daemon = 0;
63
64 www_thread_par* pPar = new www_thread_par();
65 pPar->web_port = web_port;
66 pPar->outputDir = outputDir;
67 pPar->daemon = daemon;
68
69 TThread* threadWebServ = new TThread((TThread::VoidFunc_t)&start_server, (void*)pPar, TThread::kNormalPriority);
70 threadWebServ->Run();
71 isWebStarted = true;
72 }
73
74 return kSUCCESS;
75}
76
77// -------------------------------------------------------------------------
78void MpdWebScreenshots::Exec(Option_t* option)
79{
80 // redraw event display to capture current event
81 gEve->Redraw3D();
82 gSystem->ProcessEvents();
83
84 TString fileName = outputDir;
85 if (isMultiFiles == 1)
86 fileName += "event_" + TString::Format("%d", fMan->GetCurrentEvent());
87 else
88 fileName += "event";
89
90 if ((iFormatFiles == 0) || (iFormatFiles == 2))
91 {
92 fileName += ".png";
93 gEve->GetDefaultGLViewer()->SavePicture(fileName.Data());
94 }
95
96 if (iFormatFiles > 0)
97 {
98 fileName += ".jpg";
99 gEve->GetDefaultGLViewer()->SavePicture(fileName.Data());
100 }
101
102 return;
103}
104
105// -------------------------------------------------------------------------
108
109// -------------------------------------------------------------------------
112
113// -------------------------------------------------------------------------
114int MpdWebScreenshots::daemonize()
115{
116 pid_t pid;
117 // already a daemon
118 if (getppid() == 1)
119 return -1;
120
121 // Fork off the parent process
122 pid = fork();
123 if (pid < 0)
124 return -2;
125
126 // If we got a good PID, then we can exit the parent process.
127 if (pid > 0)
128 return 0;
129
130 // At this point we are executing as the child process
131
132 // Change the file mode mask
133 umask(0);
134
135 // Create a new SID for the child process
136 if (setsid() < 0)
137 return -3;
138
139 // Change the current working directory. This prevents the current directory from being locked; hence not being able to remove it.
140 if ((chdir("/")) < 0)
141 return -4;
142
143 return 0;
144}
145
146int MpdWebScreenshots::sendString(const char *message, int socket)
147{
148 return send(socket, message, strlen(message), 0);
149}
150
151void MpdWebScreenshots::sendHeader(const char* Status_code, char* Content_Type, int TotalSize, int socket)
152{
153 char* head = (char*)"\r\nHTTP/1.1 ";
154 char* content_head = (char*)"\r\nContent-Type: ";
155 char* server_head = (char*)"\r\nServer: PT06";
156 char* length_head = (char*)"\r\nContent-Length: ";
157 char* date_head = (char*)"\r\nDate: ";
158 char* newline = (char*)"\r\n";
159
160 time_t rawtime;
161 time(&rawtime);
162
163 char contentLength[100];
164 sprintf(contentLength, "%i", TotalSize);
165
166 char* message = (char*)malloc(
167 (strlen(head) +
168 strlen(content_head) +
169 strlen(server_head) +
170 strlen(length_head) +
171 strlen(date_head) +
172 strlen(newline) +
173 strlen(Status_code) +
174 strlen(Content_Type) +
175 strlen(contentLength) +
176 28 +
177 sizeof(char)
178 )
179 * 2
180 );
181
182 if (message != NULL)
183 {
184 strcpy(message, head);
185 strcat(message, Status_code);
186 strcat(message, content_head);
187 strcat(message, Content_Type);
188 strcat(message, server_head);
189 strcat(message, length_head);
190 strcat(message, contentLength);
191 strcat(message, date_head);
192 strcat(message, (char*)ctime(&rawtime));
193 strcat(message, newline);
194
195 sendString(message, socket);
196
197 free(message);
198 }
199}
200
201// send file
202void MpdWebScreenshots::sendFile(FILE* fp, int connecting_socket)
203{
204 int current_char = 0;
205 do
206 {
207 current_char = fgetc(fp);
208 // send binary data
209 /*int bytes_sent = */send(connecting_socket, &current_char, sizeof(char), 0);
210 }
211 while (current_char != EOF);
212}
213
214int MpdWebScreenshots::scan(char* input, char* output, size_t start, size_t max)
215{
216 if (start >= strlen(input))
217 return -1;
218
219 int appending_char_count = 0;
220 size_t count = 0;
221
222 size_t i = start;
223 for (; i < strlen(input); i++)
224 {
225 if (*(input + i) != '\t' && *(input + i) != ' ' && *(input + i) != '\n' && *(input + i) != '\r')
226 {
227 if(count < (max-1))
228 {
229 *(output + appending_char_count) = *(input + i ) ;
230 appending_char_count += 1;
231 count++;
232 }
233 }
234 else
235 break;
236 }
237 *(output + appending_char_count) = '\0';
238
239 // Find next word start
240 i += 1;
241
242 for (; i < strlen(input); i++)
243 {
244 if (*(input + i ) != '\t' && *(input + i) != ' ' && *(input + i) != '\n' && *(input + i) != '\r')
245 break;
246 }
247
248 return i;
249}
250
251int MpdWebScreenshots::checkMime(char* extension, char* mime_type)
252{
253 char* current_word = (char*) malloc(600);
254 char* word_holder = (char*) malloc(600);
255 char* line = (char*) malloc(200);
256 int startline = 0;
257
258 TString mime_file = "mime.types";
259 FILE* mimeFile = fopen(mime_file.Data(), "r");
260
261 free(mime_type);
262 mime_type = (char*)malloc(200);
263
264 memset(mime_type,'\0',200);
265
266 while (fgets(line, 200, mimeFile) != NULL)
267 {
268 if (line[0] != '#')
269 {
270 startline = scan(line, current_word, 0, 600);
271 while (1)
272 {
273 startline = scan(line, word_holder, startline, 600);
274 if (startline != -1)
275 {
276 if (strcmp(word_holder, extension) == 0)
277 {
278 memcpy(mime_type, current_word, strlen(current_word));
279 free(current_word);
280 free(word_holder);
281 free(line);
282 return 1;
283 }
284 }
285 else
286 break;
287 }
288 }
289
290 memset(line, '\0', 200);
291 }
292
293 free(current_word);
294 free(word_holder);
295 free(line);
296
297 return 0;
298}
299
300int MpdWebScreenshots::getHttpVersion(char* input, char* output)
301{
302 char* filename = (char*) malloc(100);
303 int start = scan(input, filename, 4, 100);
304 if (start > 0)
305 {
306 if (scan(input, output, start, 20))
307 {
308 output[strlen(output)+1] = '\0';
309
310 if (strcmp("HTTP/1.1" , output) == 0)
311 return 1;
312 else
313 {
314 if (strcmp("HTTP/1.0", output) == 0)
315 return 0;
316 else
317 return -1;
318 }
319 }
320 else
321 return -1;
322 }
323
324 return -1;
325}
326
327int MpdWebScreenshots::GetExtension(char* input, char* output, size_t max)
328{
329 int in_position = 0;
330 int appended_position = 0;
331
332 size_t i = 0, count = 0;
333 for (; i < strlen(input); i++)
334 {
335 if (in_position == 1)
336 {
337 if (count < max)
338 {
339 output[appended_position] = input[i];
340 appended_position += 1;
341 count++;
342 }
343 }
344
345 if (input[i] == '.')
346 in_position = 1;
347 }
348 output[appended_position+1] = '\0';
349
350 if (strlen(output) > 0)
351 return 1;
352
353 return -1;
354}
355
356// IF NOT EXISTS - RETURN -1. IF EXISTS - RETURN 1
357int MpdWebScreenshots::handleHttpGET(char* input, TString output_dir, int connecting_socket)
358{
359 char* filename = (char*) malloc(200 * sizeof(char));
360 char* path = (char*) malloc(1000 * sizeof(char));
361 char* extension = (char*) malloc(10 * sizeof(char));
362 char* mime = (char*) malloc(200 * sizeof(char));
363 char* httpVersion = (char*) malloc(20 * sizeof(char));
364
365 int contentLength = 0, mimeSupported = 0;
366
367 memset(path, '\0', 1000);
368 memset(filename, '\0', 200);
369 memset(extension, '\0', 10);
370 memset(mime, '\0', 200);
371 memset(httpVersion, '\0', 20);
372
373 int fileNameLength = scan(input, filename, 5, 200);
374
375 int i = 0;
376 while (filename[i]!='\0' && filename[i]!='?')
377 i++;
378
379 if (filename[i] == '?')
380 filename[i] = '\0';
381
382 if (fileNameLength <= 0)
383 return -1;
384
385 if (getHttpVersion(input, httpVersion) == -1)
386 {
387 sendString("501 Not Implemented\n", connecting_socket);
388 return -1;
389 }
390
391 if (GetExtension(filename, extension, 10) == -1)
392 {
393 printf("File extension not existing");
394 sendString("400 Bad Request\n", connecting_socket);
395
396 free(filename);
397 free(mime);
398 free(path);
399 free(extension);
400 return -1;
401 }
402
403 mimeSupported = checkMime(extension, mime);
404 if (mimeSupported != 1)
405 {
406 printf("Mime not supported");
407 sendString("400 Bad Request\n", connecting_socket);
408
409 free(filename);
410 free(mime);
411 free(path);
412 free(extension);
413 return -1;
414 }
415
416 // Open the requesting file as binary
417 strcpy(path, output_dir.Data());
418 strcat(path, filename);
419
420 FILE* fp = fopen(path, "rb");
421 if (fp == NULL)
422 {
423 printf("\nUnable to open file %s\n",path);
424
425 sendString("404 Not Found\n", connecting_socket);
426
427 free(filename);
428 free(mime);
429 free(extension);
430 free(path);
431 return -1;
432 }
433
434 // Calculate Content Length
435 fseek(fp, 0, SEEK_END);
436 contentLength = ftell(fp);
437 rewind(fp);
438 if (contentLength < 0)
439 {
440 printf("File size is zero");
441
442 free(filename);
443 free(mime);
444 free(extension);
445 free(path);
446 fclose(fp);
447 return -1;
448 }
449
450 // Send File Content
451 sendHeader("200 OK", mime, contentLength, connecting_socket);
452
453 sendFile(fp, connecting_socket);
454
455 free(filename);
456 free(mime);
457 free(extension);
458 free(path);
459 fclose(fp);
460
461 return 1;
462}
463
464// IF NOT VALID REQUEST - RETURN -1. IF VALID REQUEST - RETURN 1. IF GET - RETURN 2. IF HEAD - RETURN 0.
465int MpdWebScreenshots::getRequestType(char* input)
466{
467 int type = -1;
468 if (strlen(input) > 0)
469 type = 1;
470
471 char* requestType = (char*) malloc(5);
472 scan(input, requestType, 0, 5);
473
474 if (type == 1 && strcmp("GET", requestType) == 0) type = 1;
475 else if (type == 1 && strcmp("HEAD", requestType) == 0) type = 2;
476 else if (strlen(input) > 4 && strcmp("POST", requestType) == 0) type = 0;
477 else type = -1;
478
479 return type;
480}
481
482int MpdWebScreenshots::receive(int connecting_socket, TString output_dir)
483{
484 char buffer[BUFFER_SIZE];
485 memset(buffer, '\0', BUFFER_SIZE);
486
487 if ((recv(connecting_socket, buffer, BUFFER_SIZE, 0)) == -1)
488 {
489 printf("Error handling incoming request");
490 return -1;
491 }
492
493 int request = getRequestType(buffer);
494 if (request == 1) // GET
495 handleHttpGET(buffer, output_dir, connecting_socket);
496 else
497 if (request != 2) // NOT HEAD
498 {
499 if (request == 0) // POST
500 sendString("501 Not Implemented\n", connecting_socket);
501 else // GARBAGE
502 sendString("400 Bad Request\n", connecting_socket);
503 }
504 //else // HEAD
505 // 1; //SendHeader();
506
507 return 1;
508}
509
510int MpdWebScreenshots::acceptConnection(int currentSocket, TString output_dir)
511{
512 sockaddr_storage connectorSocket;
513 socklen_t addressSize = sizeof(connectorSocket);
514
515 int connecting_socket = accept(currentSocket, (struct sockaddr *)&(connectorSocket), &addressSize);
516 if (connecting_socket < 0)
517 {
518 perror("Accepting sockets");
519 return -1;
520 }
521
522 // --- Workflow --- //
523 // 1. Receive ( recv() ) the GET / HEAD
524 // 2. Process the request and see if the file exists
525 // 3. Read the file content
526 // 4. Send out with correct mine and http 1.1
527 if (receive(connecting_socket, output_dir) < 0)
528 {
529 perror("Receive");
530 return -1;
531 }
532
533 close(connecting_socket);
534
535 while (-1 != waitpid(-1, NULL, WNOHANG));
536
537 return 0;
538}
539
540int MpdWebScreenshots::start(int webPort, TString output_dir)
541{
542 // Create a socket and assign currentSocket to the descriptor
543 int currentSocket = socket(AF_INET, SOCK_STREAM, 0);
544 if (currentSocket == -1)
545 {
546 perror("Create socket");
547 return -1;
548 }
549
550 // Bind to the currentSocket descriptor and listen to the port in PORT
551 struct sockaddr_in address;
552 address.sin_family = AF_INET;
553 address.sin_addr.s_addr = INADDR_ANY;
554 address.sin_port = htons(webPort);
555
556 if (bind(currentSocket, (struct sockaddr *)&address, sizeof(address)) < 0)
557 {
558 perror("Bind to port");
559 return -2;
560 }
561
562 // Start listening for connections and accept no more than MAX_CONNECTIONS in the Quee
563 if (listen(currentSocket, MAX_CONNECTIONS) < 0)
564 {
565 perror("Listen on port");
566 return -3;
567 }
568
569 while (1)
570 acceptConnection(currentSocket, output_dir);
571}
572
573int MpdWebScreenshots::start_server(void* ptr)
574{
575 www_thread_par* pPar = (www_thread_par*)ptr;
576 int webPort = pPar->web_port;
577 TString output_dir = pPar->outputDir;
578 int daemon = pPar->daemon;
579
580 int argc = 0;
581 char** argv = NULL;
582
583 TString log_file;
584 for (int parameterCount = 1; parameterCount < argc; parameterCount++)
585 {
586 // If flag -p is used, set port
587 if (strcmp(argv[parameterCount], "-p") == 0)
588 {
589 // Indicate that we want to jump over the next parameter
590 parameterCount++;
591 printf("Setting port to %i\n", atoi(argv[parameterCount]));
592 webPort = atoi(argv[parameterCount]);
593 }
594 // If flag -d is used, set daemon to TRUE;
595 else
596 {
597 if (strcmp(argv[parameterCount], "-d") == 0)
598 {
599 printf("Setting daemon = TRUE");
600 daemon = 1;
601 }
602 else
603 {
604 if (strcmp(argv[parameterCount], "-l") == 0)
605 {
606 // Indicate that we want to jump over the next parameter
607 parameterCount++;
608 printf("Setting logfile = %s\n", argv[parameterCount]);
609 log_file = (TString) (char*) argv[parameterCount];
610 }
611 else
612 {
613 printf("Usage: %s [-p port] [-d] [-l logfile]\n", argv[0]);
614 printf("\t\t-p port\t\tWhich port to listen to.\n");
615 printf("\t\t-d\t\tEnables daemon mode.\n");
616 printf("\t\t-l logfile\tWhich file to store the log to.\n");
617 return -1;
618 }
619 }
620 }
621 }
622
623 printf("Settings:\n");
624 printf("Port:\t\t\t%i\n", webPort);
625 printf("Server root:\t\t%s\n", output_dir.Data());
626 printf("Logfile:\t\t%s\n", log_file.Data());
627 printf("daemon:\t\t\t%i\n", daemon);
628
629 if (daemon == 1)
630 daemonize();
631
632 start(webPort, output_dir);
633
634 return 0;
635}
void memset(T *dest, T i, size_t num)
uses binary expansion of copied volume for speed up
Definition L1Grid.h:25
int i
Definition P4_F32vec4.h:22
friend F32vec4 max(const F32vec4 &a, const F32vec4 &b)
Definition P4_F32vec4.h:31
static MpdEventManager * Instance()
virtual Int_t GetCurrentEvent()
virtual InitStatus Init()
MpdWebScreenshots(const char *name, char *output_dir, bool isWebServer=false, Int_t iVerbose=0)
virtual void Exec(Option_t *option)
virtual void SetParContainers()
#define MAX_CONNECTIONS
#define BUFFER_SIZE
void scan()
STL namespace.