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