source: MondoRescue/branches/stable/monitas/server.c@ 352

Last change on this file since 352 was 352, checked in by bcornec, 18 years ago

monitas v0.1a

  • Property svn:executable set to *
File size: 32.4 KB
Line 
1/* server.c
2
3
4
506/19
6- fixed bugs in mondoarchive compare code
7
806/16
9- every 15 seconds, update /var/spool/monitas/server-status.txt file
10- added handle_progress_rpt()
11- modify restore_path() to allow user to restore to another path
12
1306/14
14- added "2> /dev/null" to call to find /var/spool/monitas
15- improved backup_client(), compare_client(), restore_client()
16- pipe logs to logfile, not stdout
17
1806/11
19- moved register_pid(), set_signals(), termination_in_progress() to common.c
20- commented code a bit
21- improved backup_client(), compare_client(), restore_client()
22
2306/10
24- improved backup_client()
25- discover whether mondoarchive returned error (ask client)
26 and act accordingly (i.e. drop archive)
27
2806/09
29- added /var/spool/monitas/input.dev FIFO to
30 let external programs instruct me to backup
31 or restore a given computer
32- added signal trapping
33
3406/07
35- rename transmit_file... and move
36 to common.c, as transmit_file_to_socket()
37- rename receive_file... and move to
38 common.c, as receive_file_from_socket()
39
4005/27
41- save bkps to /var/spool/monitas/123.456.789.012/[time]
42
4305/23
44- added elementary saving/storing of incoming data
45 from client backing itself up
46
4705/21
48- added backup_client, compare_client, restore_client
49 templates for triggers
50
5105/11
52- clarified structures & their names
53- improved login/logout OK/fail feedback
54
5505/10
56- made main loop multithreaded (replaced multiple forks)
57- thanks to the move from forks to threads, clientlist
58 is now shared between processes automatically
59- replaced printf()'s and fprintf()'s with log_it() function
60 and levels debug/info/warn/error/fatal
61
6205/08
63- got down to some housecleaning
64- added comments; removed strcpy()'s
65- replaced silly exit()'s with return()'s
66
67*/
68
69
70
71
72/*-----------------------------------------------------------*/
73
74
75
76#include "structs.h"
77//#define LOG_THESE_AND_HIGHER debug
78
79
80
81#define NOOF_THREADS 10
82#define LOGFILE "/var/log/monitas-server.log"
83#define log_it(x,y) { log_it_SUB(g_logfile,x,y); }
84
85
86/* externs */
87
88extern bool does_file_exist(char*);
89extern char *call_program_and_get_last_line_of_output(char*);
90extern int call_program_and_log_output(char*);
91extern int create_and_watch_fifo_for_commands(char*);
92extern bool does_file_exist(char*);
93extern void log_it_SUB(char*, t_loglevel, char *);
94extern int make_hole_for_file (char *);
95extern int read_block_from_fd(int socket_fd, char*buf, int len_to_read);
96extern int receive_file_from_socket(FILE*, int);
97extern void register_pid(pid_t, char*);
98extern void set_signals(bool);
99extern void termination_in_progress(int);
100extern char *tmsg_to_string(t_msg);
101extern int transmit_file_to_socket(FILE*,int);
102
103
104
105/* global vars */
106
107struct s_clientlist g_clientlist; /* FIXME - lock during login/logout, using mutexes */
108char g_command_fifo[MAX_STR_LEN+1]; // Device which server will monitor for incoming commands
109pthread_t g_threadinfo[NOOF_THREADS]; // One thread per port, to watch for requests from clients
110char g_logfile[MAX_STR_LEN+1] = "/var/log/monitas-server.log";
111char g_server_status_file[MAX_STR_LEN+1];
112
113
114
115/* prototypes */
116
117int backup_client(char*, int, char*);
118int compare_client(char*, int, char*);
119int find_client_in_clientlist(char *);
120int forcibly_logout_all_clients(void);
121int forcibly_logout_client(int);
122void* generate_server_status_file_regularly(void*);
123int handle_incoming_message(int, struct sockaddr_in *, struct s_client2server_msg_record *);
124int handle_login_request(int, struct s_client2server_msg_record *, char *);
125int handle_logout_request(int, struct s_client2server_msg_record *, char *);
126int handle_ping_request(int, struct s_client2server_msg_record *, char *);
127int handle_progress_rpt(int, struct s_client2server_msg_record *, char *);
128int handle_user_request(int, struct s_client2server_msg_record *, char *);
129int process_incoming_command(char*);
130int read_block_from_fd(int, char*, int);
131int restore_client(char*, int, char*, char*);
132int send_msg_to_client(struct s_server2client_msg_record *, char *, int, int*);
133void start_threads_to_watch_ports_for_requests(void);
134void terminate_daemon(int);
135char *tmsg_to_string(t_msg);
136void* watch_port_for_requests_from_clients(void*);
137
138
139
140/*-----------------------------------------------------------*/
141
142
143
144int backup_client(char*ipaddr, int port, char*clientpath)
145/*
146Purpose:Backup the path of a specific client. Receive
147the archives. Store them locally (on me, the server).
148Params: clientno - client# in g_clientlist[]
149 clientpath - client's path to be backed up
150Return: result (0=success, nonzero=failure)
151*/
152{
153 struct s_server2client_msg_record rec_to_client;
154 int res=0, socket_fd, noof_archives, i, len;
155 char tmp[MAX_STR_LEN+1], outfile[MAX_STR_LEN+1];
156 FILE*fout;
157
158 sprintf(tmp, "%s - backup of %s commencing", ipaddr, clientpath);
159 log_it(info, tmp);
160 sprintf(outfile, "/var/spool/monitas/%s/%s.dat", ipaddr, call_program_and_get_last_line_of_output("date +%s"));
161 if (does_file_exist(outfile)) { log_it(error, "Backup storage location exists already. That should be impossible."); return(1); }
162 if (make_hole_for_file(outfile))
163 { res++; log_it(error, "Cannot write archive to spool dir"); }
164 else if (!(fout=fopen(outfile, "w")))
165 { res++; log_it(fatal, "Failed to openout temp data file"); }
166 else
167 {
168 sprintf(tmp, "Backing up %s - archive=%s", ipaddr, outfile);
169 log_it(debug, tmp);
170 rec_to_client.msg_type = trigger_backup;
171 strncpy(rec_to_client.body, clientpath, sizeof(rec_to_client.body));
172 if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
173 { log_it(error, "backup_client - failed to send msg to client"); return(1); }
174 res += receive_file_from_socket(fout, socket_fd);
175 len=read(socket_fd, (char*)&i, sizeof(i));
176 if (!len) { res++; log_it(error, "Client hasn't told me the result of its call to mondoarchive"); }
177 else if (len!=sizeof(i)) { res++; log_it(error, "Client didn't sent _entire_ result of its call to mondoarchive"); }
178 else if (i) { res++; log_it(error, "Client said, mondoarchive returned an error."); }
179 else { log_it(debug, "Client said, mondoarchive returned OK"); }
180 fclose(fout);
181 close(socket_fd);
182 }
183/* Shuffle older backups off the mortal coil. Leave maximum of 4 backup files in /var/spool/monitas/[ipaddr] */
184 sprintf(tmp, "find /var/spool/monitas/%s -type f 2> /dev/null | grep -n \"\" | tail -n1 | cut -d':' -f1", ipaddr);
185 noof_archives = atoi(call_program_and_get_last_line_of_output(tmp));
186 i = noof_archives - 3;
187 if (i>0)
188 {
189 sprintf(tmp, "rm -f `find /var/spool/monitas/%s -type f | sort | head -n%d`", ipaddr, i);
190 call_program_and_log_output(tmp);
191 }
192/* Return success/failure value */
193 if (res>0)
194 {
195 sprintf(tmp, "%s - error(s) occurred while backing up %s", ipaddr, clientpath);
196 log_it(error, tmp);
197 rec_to_client.msg_type = backup_fail;
198 sprintf(rec_to_client.body, "Failed to backup %s", clientpath);
199 log_it(debug, rec_to_client.body);
200 unlink(outfile);
201 }
202 else
203 {
204 sprintf(tmp, "%s - backed up %s ok", ipaddr, clientpath);
205 log_it(info, tmp);
206 rec_to_client.msg_type = backup_ok;
207 sprintf(rec_to_client.body, "%s - backed up ok", clientpath);
208 log_it(debug, rec_to_client.body);
209 }
210 if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
211 {
212 res++;
213 sprintf(tmp, "Unable to notify %s of backup success/failure", ipaddr);
214 log_it(error, tmp);
215 i = find_client_in_clientlist(ipaddr);
216 if (i>=0) { forcibly_logout_client(i); }
217 log_it(info, "I'm assuming the backup was bad because the client cannot be reached.");
218 unlink(outfile);
219 }
220 return(res);
221}
222
223
224
225/*-----------------------------------------------------------*/
226
227
228
229int compare_client(char*ipaddr, int port, char*clientpath)
230/*
231Purpose:Compare the path of a specific client. Transmit
232the archives from my (the server's) local storage loc.
233Params: clientno - client# in g_clientlist[]
234 clientpath - client's path to be compared
235Return: result (0=success, nonzero=failure)
236*/
237{
238 struct s_server2client_msg_record rec_to_client;
239 int res=0, socket_fd, len, i;
240 char tmp[MAX_STR_LEN+1], infile[MAX_STR_LEN+1];
241 FILE*fin;
242
243 sprintf(tmp, "%s - comparison of %s commencing", ipaddr, clientpath);
244 log_it(info, tmp);
245// FIXME - don't assume the latest backup contains the files we want ;)
246 sprintf(tmp, "find /var/spool/monitas/%s -type f | sort | tail -n1", ipaddr);
247 strcpy(infile, call_program_and_get_last_line_of_output(tmp));
248 sprintf(tmp, "Comparing to data file '%s'", infile);
249 log_it(debug, tmp);
250 if (!does_file_exist(infile)) { log_it(error, "Backup not found. That should be impossible."); return(1); }
251 sprintf(tmp, "Comparing %s - archive=%s", ipaddr, infile);
252 log_it(debug, tmp);
253 rec_to_client.msg_type = trigger_compare;
254 strncpy(rec_to_client.body, clientpath, sizeof(rec_to_client.body));
255 if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
256 { log_it(error, "compare_client - failed to send msg to client"); return(1); }
257 if (!(fin=fopen(infile, "r")))
258 { log_it(fatal, "Failed to openin temp data file"); }
259 res += transmit_file_to_socket(fin, socket_fd);
260 len=read(socket_fd, (char*)&i, sizeof(i));
261 if (!len) { res++; log_it(error, "Client hasn't told me the result of its call to mondoarchive"); }
262 else if (len!=sizeof(i)) { res++; log_it(error, "Client didn't sent _entire_ result of its call to mondoarchive"); }
263 else if (i) { res++; log_it(error, "Client said, mondoarchive returned an error."); }
264 else { log_it(debug, "Client said, mondoarchive returned OK"); }
265 fclose(fin);
266 close(socket_fd);
267 if (res>0)
268 {
269 sprintf(tmp, "%s - error(s) occurred while comparing %s", ipaddr, clientpath);
270 log_it(error, tmp);
271 rec_to_client.msg_type = compare_fail;
272 sprintf(rec_to_client.body, "Failed to compare %s", clientpath);
273 log_it(debug, rec_to_client.body);
274 }
275 else
276 {
277 sprintf(tmp, "%s - compared %s ok", ipaddr, clientpath);
278 log_it(info, tmp);
279 rec_to_client.msg_type = compare_ok;
280 sprintf(rec_to_client.body, "%s - compared ok", clientpath);
281 log_it(debug, rec_to_client.body);
282 }
283 if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
284 {
285 sprintf(tmp, "Unable to notify %s of compare success/failure", ipaddr);
286 log_it(error, tmp);
287 i = find_client_in_clientlist(ipaddr);
288 if (i>=0) { forcibly_logout_client(i); }
289 }
290 return(res);
291}
292
293
294
295/*-----------------------------------------------------------*/
296
297
298
299
300int find_client_in_clientlist(char *clientIP)
301/*
302Purpose:Find a client in the clientlist (list of logged-in
303 clients).
304Params: clientIP - IP address of client
305Return: result (<0=not found, 0+=found in element N)
306*/
307{
308 int i;
309 char tmp[MAX_STR_LEN+1];
310
311 for(i = 0; i < g_clientlist.items; i++)
312 {
313 if (!strcmp(clientIP, g_clientlist.el[i].ipaddr))
314 { return(i); }
315 sprintf(tmp, "find_client_in_clientlist: Compared %s to clientlist[%d]=%s; failed\n", clientIP, i, g_clientlist.el[i].ipaddr);
316 log_it(debug, tmp);
317 }
318 return(-1);
319}
320
321
322
323/*-----------------------------------------------------------*/
324
325
326
327int forcibly_logout_all_clients()
328/*
329Purpose: Tell all clients to disconnect, right now.
330Params: None
331Returns: 0=success
332*/
333{
334// FIXME - lock g_clientlist for duration of this function
335 while(g_clientlist.items>0)
336 {
337 forcibly_logout_client(0);
338 }
339 return(0);
340}
341
342
343
344/*-----------------------------------------------------------*/
345
346
347
348int forcibly_logout_client(int clientno)
349/*
350Purpose: Logout specific client(#) by force.
351Params: Client# in g_clientlist[] array.
352Returns: 0=success, nonzero=failure to get other end to hear me;)
353NB: The client was definitely removed from our login table.
354 If the client got the message, return 0; else, nonzero.
355*/
356{
357 struct s_server2client_msg_record rec_to_client;
358 char tmp[MAX_STR_LEN+1];
359 int res=0;
360
361 sprintf(tmp, "Forcibly logging %s out", g_clientlist.el[clientno].ipaddr);
362 log_it(info, tmp);
363 rec_to_client.msg_type = logout_ok; /* to confirm logout */
364 strcpy(rec_to_client.body, "Server is shutting down. You are forced to logout");
365 res=send_msg_to_client(&rec_to_client, g_clientlist.el[clientno].ipaddr, g_clientlist.el[clientno].port, NULL);
366 if (--g_clientlist.items > 0)
367 {
368 sprintf(tmp, "Moving clientlist[%d] to clientlist[%d]", clientno, g_clientlist.items);
369 log_it(debug, tmp);
370 sprintf(tmp, "Was ipaddr=%s; now is ipaddr=", g_clientlist.el[clientno].ipaddr);
371 memcpy((void*)&g_clientlist.el[clientno], (void*)&g_clientlist.el[g_clientlist.items], sizeof(struct s_registered_client_record));
372 strcat(tmp, g_clientlist.el[clientno].ipaddr);
373 log_it(debug, tmp);
374 }
375 return(res);
376}
377
378
379
380/*-----------------------------------------------------------*/
381
382
383void* generate_server_status_file_regularly(void*inp)
384{
385 int i;
386 FILE*fout;
387
388 strncpy(g_server_status_file, (char*)inp, MAX_STR_LEN);
389 for(;;)
390 {
391 if ((fout = fopen(g_server_status_file, "w")))
392 {
393// FIXME - lock g_clientlist
394 for(i=0; i<g_clientlist.items; i++)
395 {
396 fprintf(fout, "%s [%s] : %s\n", g_clientlist.el[i].ipaddr, g_clientlist.el[i].hostname_pretty, g_clientlist.el[i].last_progress_rpt);
397 }
398 fclose(fout);
399 }
400 sleep(1);
401 }
402 exit(0);
403}
404
405
406
407/*-----------------------------------------------------------*/
408
409
410
411int handle_incoming_message(int skt, struct sockaddr_in *sin, struct s_client2server_msg_record *rec)
412/*
413Purpose:Process message which has just arrived from client.
414 A 'message' could be a login/logout request or a ping.
415Params: skt - client's port to respond to
416 sin - client's IP address, in sockaddr_in structure
417 rec - data received from client
418Return: result (0=success, nonzero=failure)
419*/
420{
421 char clientIP[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
422 unsigned char *ptr;
423 int res=0;
424
425 // echo_ipaddr_to_screen(&sin->sin_addr);
426 ptr = (unsigned char*)(&sin->sin_addr);
427 sprintf(clientIP, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);
428 sprintf(tmp, "clientIP = %s", clientIP);
429 log_it(debug, tmp);
430 sprintf(tmp, "%s message from %s [%s] (port %d)", tmsg_to_string(rec->msg_type), clientIP, rec->body, rec->port);
431 log_it(debug, tmp);
432 switch(rec->msg_type)
433 {
434 case login:
435 res=handle_login_request(skt, rec, clientIP);
436 break;
437 case ping:
438 res=handle_ping_request(skt, rec, clientIP);
439 break;
440 case progress_rpt:
441 res=handle_progress_rpt(skt, rec, clientIP);
442 break;
443 case logout:
444 res=handle_logout_request(skt, rec, clientIP);
445 break;
446 case user_req:
447 res=handle_user_request(skt, rec, clientIP);
448 break;
449 default:
450 log_it(error, "...How do I handle it?");
451 }
452 return(res);
453}
454
455
456
457/*-----------------------------------------------------------*/
458
459
460
461int handle_login_request(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
462/*
463Purpose:Handle a login request which has just been received
464 from client.
465Params: skt - client's port to talk to
466 rec_from_client - login rq record received from client
467 clientIP - client's IP address, in string
468Return: result (0=success, nonzero=failure)
469*/
470{
471 struct s_server2client_msg_record rec_to_client;
472 int clientno;
473 char tmp[MAX_STR_LEN+1];
474
475//FIXME - lock g_clientlist[]
476 clientno = find_client_in_clientlist(clientIP);
477 if (clientno>=0)
478 {
479 rec_to_client.msg_type = login_fail;
480 sprintf(rec_to_client.body, "Sorry, you're already logged in!");
481 sprintf(tmp, "Ignoring login rq from %s: he's already logged in.", clientIP);
482 log_it(error, tmp);
483/* FIXME - ping client (which will have a child watching for incoming
484packets by now - you didn't forget to do that, did you? :)) - to find out
485if client is still running. If it's not then say OK, forget it, I'll kill
486that old connection and log you in anew. If it _is_ then say hey, you're
487already logged in; either you're an idiot or you're a hacker. */
488 }
489 else
490 {
491 rec_to_client.msg_type = login_ok; /* to confirm login */
492 sprintf(rec_to_client.body, "Thanks for logging in.");
493 clientno = g_clientlist.items;
494 strncpy(g_clientlist.el[clientno].hostname_pretty, rec_from_client->body, sizeof(g_clientlist.el[clientno].hostname_pretty));
495 strncpy(g_clientlist.el[clientno].ipaddr, clientIP, sizeof(g_clientlist.el[clientno].ipaddr));
496 g_clientlist.el[clientno].port = rec_from_client->port;
497 g_clientlist.el[clientno].busy = false;
498 g_clientlist.items ++;
499 sprintf(tmp, "Login request from %s ACCEPTED", clientIP);
500 log_it(info, tmp);
501 strcpy(g_clientlist.el[clientno].last_progress_rpt, "Logged in");
502 }
503 send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
504 return(0);
505}
506
507
508
509/*-----------------------------------------------------------*/
510
511
512
513int handle_logout_request(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
514/*
515Purpose:Handle a logout request which has just been received
516 from client.
517Params: skt - client's port to talk to
518 rec_from_client - logout rq record received from client
519 clientIP - client's IP address, in string
520Return: result (0=success, nonzero=failure)
521*/
522{
523 struct s_server2client_msg_record rec_to_client;
524 int i, res=0;
525 char tmp[MAX_STR_LEN+1];
526
527 i = find_client_in_clientlist(clientIP);
528 if (i<0)
529 {
530 sprintf(rec_to_client.body, "Client is not logged in yet. How can I log him out?");
531 log_it(error, rec_to_client.body);
532 rec_to_client.msg_type = logout_fail;
533 res=1;
534 }
535 else if (g_clientlist.el[i].busy)
536 {
537 sprintf(rec_to_client.body, "Client is working. I shouldn't log him out.");
538 log_it(error, rec_to_client.body);
539 rec_to_client.msg_type = logout_fail;
540 res=1;
541 }
542 else
543 {
544 sprintf(rec_to_client.body, "Removed client#%d from login table. Thanks for logging out.", i);
545 for(; i<g_clientlist.items; i++)
546 {
547 memcpy((char*)(&g_clientlist.el[i]), (char*)(&g_clientlist.el[i+1]), sizeof(struct s_registered_client_record));
548 }
549 strncpy(g_clientlist.el[i].hostname_pretty, "WTF? Someone teach Hugo to handle pointers properly, please!", sizeof(g_clientlist.el[i].hostname_pretty));
550 g_clientlist.items--;
551 rec_to_client.msg_type = logout_ok; /* to confirm logout */
552 sprintf(tmp, "Logout request from %s ACCEPTED", clientIP);
553 log_it(info, tmp);
554 }
555 send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
556 return(res);
557}
558
559
560
561/*-----------------------------------------------------------*/
562
563
564
565int handle_ping_request(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
566/*
567Purpose:Handle a ping request which has just been received
568 from client.
569Params: skt - client's port to talk to
570 rec_from_client - ping record received from client
571 clientIP - client's IP address, in string
572Return: result (0=success, nonzero=failure)
573*/
574{
575 struct s_server2client_msg_record rec_to_client;
576 int i;
577 char tmp[MAX_STR_LEN+1];
578
579 i = find_client_in_clientlist(clientIP);
580 if (i < 0)
581 {
582 sprintf(tmp, "Hey, %s isn't logged in. I'm not going to pong him.", clientIP);
583 log_it(error, tmp);
584 }
585 else
586 {
587 rec_to_client.msg_type = pong; /* reply to ping */
588 sprintf(rec_to_client.body, "Hey, I'm replying to client#%d's ping. Pong! (re: %s", i, rec_from_client->body);
589 send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
590 log_it(debug, rec_to_client.body);
591 }
592 return(0);
593}
594
595
596
597/*-----------------------------------------------------------*/
598
599
600
601int handle_progress_rpt(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
602/*
603Purpose:Handle a progress_rpt which has just been received
604 from client.
605Params: skt - client's port to talk to
606 rec_from_client - user record received from client
607 clientIP - client's IP address, in string
608Return: result (0=success, nonzero=failure)
609*/
610{
611// struct s_server2client_msg_record rec_to_client;
612 int i, res=0;
613 char tmp[MAX_STR_LEN+1];
614
615 i = find_client_in_clientlist(clientIP);
616 if (i < 0)
617 {
618 sprintf(tmp, "Hey, %s isn't logged in. I'm not going to deal with his progress_rpt.", clientIP);
619 log_it(error, tmp);
620 res++;
621 }
622 else
623 {
624 strcpy(g_clientlist.el[i].last_progress_rpt, rec_from_client->body);
625 }
626 return(res);
627}
628
629
630
631/*-----------------------------------------------------------*/
632
633
634
635int handle_user_request(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
636/*
637Purpose:Handle a user request which has just been received
638 from client.
639Params: skt - client's port to talk to
640 rec_from_client - user record received from client
641 clientIP - client's IP address, in string
642Return: result (0=success, nonzero=failure)
643*/
644{
645// struct s_server2client_msg_record rec_to_client;
646 int i, res=0;
647 char tmp[MAX_STR_LEN+1], command[MAX_STR_LEN+1], first_half[MAX_STR_LEN+1], second_half[MAX_STR_LEN+1], *p;
648
649 i = find_client_in_clientlist(clientIP);
650 if (i < 0)
651 {
652 sprintf(tmp, "Hey, %s isn't logged in. I'm not going to deal with his request.", clientIP);
653 log_it(error, tmp);
654 res++;
655 }
656 else
657 {
658 strcpy(first_half, rec_from_client->body);
659 p = strchr(first_half, ' ');
660 if (!p) { second_half[0]='\0'; } else { strcpy(second_half, p); *p='\0'; }
661 sprintf(command, "echo \"%s %s%s\" > %s", first_half, clientIP, second_half, SERVER_COMDEV);
662 log_it(debug, command);
663 i = system(command);
664 if (i) { res++; log_it(error, "Failed to echo command to FIFO"); }
665 }
666 return(res);
667}
668
669
670
671/*-----------------------------------------------------------*/
672
673
674
675int process_incoming_command(char*incoming)
676/*
677Purpose:Process incoming command, presumably
678 read from FIFO and sent there by sysadm/user.
679Params: incoming - raw command string itself
680Return: result (0=success; nonzero=failure)
681*/
682{
683int res=0, port;
684int clientno;
685char tmp[MAX_STR_LEN+1];
686int pos;
687char command[MAX_STR_LEN+1], ipaddr[MAX_STR_LEN+1],
688 path[MAX_STR_LEN+1], aux[MAX_STR_LEN+1];
689
690// sprintf(tmp, "incoming = '%s'", incoming);
691// log_it(debug, tmp);
692 pos=0;
693 sscanf(incoming, "%s %s %s", command, ipaddr, path);
694 if (!strcmp(command, "restore"))
695 { sscanf(incoming, "%s %s %s %s", command, ipaddr, path, aux); }
696 else
697 { aux[0] = '\0'; }
698
699// for(i=0; i<strlen(command); i++) { command[i]=command[i]|0x60; }
700 sprintf(tmp, "cmd=%s ipaddr=%s path=%s", command, ipaddr, path);
701 log_it(debug, tmp);
702 sprintf(tmp, "%s of %s on %s <-- command received", command, path, ipaddr);
703 log_it(info, tmp);
704 if ((clientno = find_client_in_clientlist(ipaddr)) < 0)
705 {
706 sprintf(tmp, "%s not found in clientlist; so, %s failed.", ipaddr, command);
707 log_it(error, tmp);
708 }
709 else if (g_clientlist.el[clientno].busy == true)
710 {
711 sprintf(tmp, "%s is busy; so, %s failed.", ipaddr, command);
712 log_it(error, tmp);
713 }
714 else
715 {
716 g_clientlist.el[clientno].busy = true;
717 port = g_clientlist.el[clientno].port;
718 if (!strcmp(command, "backup"))
719 { res = backup_client(ipaddr, port, path); }
720 else if (!strcmp(command, "compare"))
721 { res = compare_client(ipaddr, port, path); }
722 else if (!strcmp(command, "restore"))
723 { res = restore_client(ipaddr, port, path, aux); }
724 else
725 {
726 sprintf(tmp, "%s - cannot '%s'. Command unknown.", ipaddr, command);
727 log_it(error, tmp);
728 res=1;
729 }
730 g_clientlist.el[clientno].busy = false;
731 }
732 return(res);
733}
734
735
736
737/*-----------------------------------------------------------*/
738
739
740
741int restore_client(char*ipaddr, int port, char*clientpath, char*auxpath)
742/*
743Purpose:Restore the path of a specific client. Transmit
744the archives from my (the server's) local storage loc.
745Params: clientno - client# in g_clientlist[]
746 clientpath - client's path to be restored
747Return: result (0=success, nonzero=failure)
748*/
749{
750 struct s_server2client_msg_record rec_to_client;
751 int res=0, socket_fd, len, i;
752 char tmp[MAX_STR_LEN+1], infile[MAX_STR_LEN+1];
753 FILE*fin;
754
755 sprintf(tmp, "%s - restoration of %s commencing", ipaddr, clientpath);
756 log_it(info, tmp);
757// FIXME - don't assume the latest backup contains the files we want ;)
758 sprintf(tmp, "find /var/spool/monitas/%s -type f | sort | tail -n1", ipaddr);
759 strcpy(infile, call_program_and_get_last_line_of_output(tmp));
760 sprintf(tmp, "Restoring from data file '%s'", infile);
761 log_it(debug, tmp);
762 if (!does_file_exist(infile)) { log_it(error, "Backup not found. That should be impossible."); return(1); }
763 sprintf(tmp, "Restoring %s - archive=%s", ipaddr, infile);
764 log_it(debug, tmp);
765 rec_to_client.msg_type = trigger_restore;
766 strncpy(rec_to_client.body, clientpath, sizeof(rec_to_client.body));
767 strncpy(rec_to_client.bodyAux, auxpath, sizeof(rec_to_client.bodyAux));
768 if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
769 { log_it(error, "restore_client - failed to send msg to client"); return(1); }
770 if (!(fin=fopen(infile, "r")))
771 { log_it(fatal, "Failed to openin temp data file"); }
772 res += transmit_file_to_socket(fin, socket_fd);
773
774 len=read(socket_fd, (char*)&i, sizeof(i));
775 if (!len) { res++; log_it(error, "Client hasn't told me the result of its call to mondorestore"); }
776 else if (len!=sizeof(i)) { res++; log_it(error, "Client didn't sent _entire_ result of its call to mondorestore"); }
777 else if (i) { res++; log_it(error, "Client said, mondorestore returned an error."); }
778 else { log_it(debug, "Client said, mondorestore returned OK"); }
779
780 fclose(fin);
781 close(socket_fd);
782 if (res>0)
783 {
784 sprintf(tmp, "%s - error(s) occurred while restoring %s", ipaddr, clientpath);
785 log_it(error, tmp);
786 rec_to_client.msg_type = restore_fail;
787 sprintf(rec_to_client.body, "Failed to restore %s", clientpath);
788 log_it(debug, rec_to_client.body);
789 }
790 else
791 {
792 sprintf(tmp, "%s - restored %s ok", ipaddr, clientpath);
793 log_it(info, tmp);
794 rec_to_client.msg_type = restore_ok;
795 sprintf(rec_to_client.body, "%s - restored ok", clientpath);
796 log_it(debug, rec_to_client.body);
797 }
798 if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
799 {
800 sprintf(tmp, "Unable to notify %s of restore success/failure", ipaddr);
801 log_it(error, tmp);
802 i = find_client_in_clientlist(ipaddr);
803 if (i>=0) { forcibly_logout_client(i); }
804 }
805 return(res);
806}
807
808
809/*-----------------------------------------------------------*/
810
811
812
813int send_msg_to_client(struct s_server2client_msg_record *rec, char *clientIP, int port, int *psocket)
814/*
815Purpose:Send a message from server to client.
816A 'message' could be a response to a login/logout/ping
817request or perhaps a 'trigger'. (A trigger is a message
818from server to client intended to initiate a backup
819or similar activity.)
820Params: rec - record containing the data to be sent to client
821clientIP - the xxx.yyy.zzz.aaa IP address of client
822port - the client's port to send data to
823psocket - returns the socket's file descriptor, left
824open by me; or, if psocket==NULL, then socket is closed
825by me before I return.
826Return: result (0=success, nonzero=failure)
827*/
828{
829struct hostent *hp;
830struct sockaddr_in sin;
831int s;
832char tmp[MAX_STR_LEN+1];
833if ((hp = gethostbyname(clientIP)) == NULL)
834{
835sprintf(tmp, "send_msg_to_client: %s: unknown host", clientIP);
836log_it(error, tmp);
837return(1);
838}
839memset((void*)&sin, 0, sizeof(sin));
840memcpy((void*)&sin.sin_addr, hp->h_addr, hp->h_length);
841sin.sin_family = AF_INET;
842sin.sin_addr.s_addr = INADDR_ANY;
843sin.sin_port = htons(port);
844if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
845{ perror("socket"); log_it(error, "send_msg_to_client: SOCKET error"); return(1); }
846if (connect(s, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)) < 0)
847{ sprintf(tmp, "Failed to connect to client %s on port %d", clientIP, port); log_it(error, tmp); return(1); }
848send(s, (char*)rec, sizeof(struct s_server2client_msg_record), 0);
849if (psocket) { *psocket=s; } else { close(s); }
850sprintf(tmp, "Sent %s msg [%s] to %s (port %d)", tmsg_to_string(rec->msg_type), rec->body, clientIP, port);
851log_it(debug, tmp);
852return(0);
853}
854
855
856
857/*-----------------------------------------------------------*/
858
859
860
861void start_threads_to_watch_ports_for_requests()
862/*
863Purpose:Start the threads that watch the 'incoming' ports
864 for messages from clients.
865Params: none
866Return: none
867NB: Called by main()
868*/
869{
870 int i, port, res;
871 char tmp[MAX_STR_LEN+1];
872
873 g_clientlist.items = 0;
874 for(i=0; i<NOOF_THREADS; i++)
875 {
876 port = 8700+i;
877 sprintf(tmp,"%d", port);
878 res = pthread_create(&(g_threadinfo[i]), NULL, watch_port_for_requests_from_clients, (void*)tmp);
879 if (res != 0)
880 {
881 perror("Thread creation failed");
882 }
883 usleep(50000);
884 }
885 sprintf(tmp, "Now monitoring ports %d thru %d for requests from clients.", 8700, 8700+NOOF_THREADS-1);
886 log_it(info, tmp);
887}
888
889
890
891/*-----------------------------------------------------------*/
892
893
894
895void terminate_daemon(int sig)
896/*
897Purpose: Shut down the server in response to interrupt.
898Params: Signal received.
899Returns: None
900*/
901{
902 char command[MAX_STR_LEN+1];
903 static bool logged_out_everyone=false;
904
905 set_signals(false); // termination in progress
906 log_it(info, "Abort signal caught by interrupt handler");
907 if (!logged_out_everyone)
908 {
909// FIXME - lock the var w/mutex
910 logged_out_everyone=true;
911 forcibly_logout_all_clients();
912 }
913/*
914 for(i=0; i<NOOF_THREADS; i--)
915 {
916 sprintf(tmp, "Terminating thread #%d", i);
917 log_it(debug, tmp);
918 pthread_join(g_threadinfo[i], NULL);
919 }
920*/
921 forcibly_logout_all_clients();
922 sprintf(command, "rm -f %s", g_command_fifo);
923 call_program_and_log_output(command);
924// chmod(g_command_fifo, 0);
925 unlink(g_command_fifo);
926 unlink(g_server_status_file);
927 register_pid(0, "server");
928 log_it(info, "---------- Monitas (server) has terminated ----------");
929 exit(0);
930}
931
932
933
934/*-----------------------------------------------------------*/
935
936
937
938void* watch_port_for_requests_from_clients(void*sz_watchport)
939/*
940Purpose:Watch a port for incoming messages from clients.
941 A 'message' could be a request to login/logout or
942 a ping, or perhaps a request to backup/restore data.
943Params: sz_watchport - the port to watch for incoming messages
944 from clients
945Return: result (0=success, nonzero=failure)
946NB: Function will return nonzero if error occurs during
947 setup but will otherwise run forever, or until killed.
948*/
949{
950 int watch_port;
951 struct sockaddr_in sin;
952 char buf[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
953 int len, s, new_s;
954 struct s_client2server_msg_record rec;
955
956 watch_port = atoi((char*)sz_watchport);
957// sprintf(tmp, "watch_port_for_requests_from_clients(%d) - starting", watch_port); log_it(debug, tmp);
958 memset((void*)&sin, 0, sizeof(sin));
959 sin.sin_family = AF_INET;
960 sin.sin_addr.s_addr = INADDR_ANY;
961 sin.sin_port = htons(watch_port);
962 if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
963 {
964 sprintf(tmp, "Unable to open socket on port #%d", watch_port);
965 log_it(error, tmp);
966 return((void*)-1);
967 }
968 if (bind(s, (struct sockaddr*)&sin, sizeof(sin)) < 0)
969 {
970 sprintf(tmp, "Cannot bind %d - %s\n", watch_port, strerror(errno));
971 log_it(error, tmp);
972 return((void*)-1);
973 }
974 if (listen(s, MAX_PENDING) < 0)
975 {
976 sprintf(tmp, "Cannot setup listen (%d) - %s\n", watch_port, strerror(errno));
977 log_it(error, tmp);
978 return((void*)-1);
979 }
980 /* service incoming connections */
981 sprintf(tmp, "Bound port #%d OK", watch_port);
982 log_it(debug, tmp);
983 while(true)
984 {
985 len = sizeof(sin);
986 if ((new_s = accept(s, (struct sockaddr *)&sin, (unsigned int*)&len)) < 0)
987 {
988 sleep(1);
989 continue;
990 }
991 while ((len = recv(new_s, buf, sizeof(buf), 0)) > 0)
992 {
993 if (len > MAX_STR_LEN) { len = MAX_STR_LEN; }
994 buf[len] = '\0';
995 memcpy((char*)&rec, buf, sizeof(rec));
996 handle_incoming_message(new_s, &sin, &rec);
997 }
998 close(new_s);
999 }
1000 return(NULL);
1001}
1002
1003
1004
1005/*-----------------------------------------------------------*/
1006
1007
1008
1009int main(int argc, char*argv[])
1010/*
1011Purpose: main subroutine
1012Parameters: none
1013Return: result (0=success, nonzero=failure)
1014*/
1015{
1016 pthread_t server_status_thread;
1017
1018 log_it(info, "---------- Monitas (server) by Hugo Rabson ----------");
1019 register_pid(getpid(), "server");
1020 set_signals(true);
1021 start_threads_to_watch_ports_for_requests();
1022 pthread_create(&server_status_thread, NULL, generate_server_status_file_regularly, (void*)SERVER_STATUS_FILE);
1023 create_and_watch_fifo_for_commands(SERVER_COMDEV);
1024 log_it(warn, "Execution should never reach this point");
1025 exit(0);
1026}
1027/* end main() */
1028
1029
Note: See TracBrowser for help on using the repository browser.