source: MondoRescue/branches/2.2.5/monitas/server.c@ 1854

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

monitas latest version

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