source: branches/stable/monitas/server.c

Last change on this file was 353, checked in by bcornec, 13 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.