Changeset 352 in MondoRescue for branches/stable/monitas/server.c


Ignore:
Timestamp:
Jan 28, 2006, 6:41:40 PM (18 years ago)
Author:
bcornec
Message:

monitas v0.1a

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/monitas/server.c

    r351 r352  
    33
    44
    5 SERVER
    6 
    7 
    8 FIXME
    9 - when sysadm requests it:-
    10   - connect to relevant port of client
    11   - send trigger_backup msg
    12   - receive file(s)
    13   - close client's port
    14 
    15 05/20
    16 - changed 'clientname' to 'clientIP'
     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
    1750 
    185105/11
     
    3770
    3871
     72/*-----------------------------------------------------------*/
     73
     74
     75
    3976#include "structs.h"
    40 
    41 #define LOG_THESE_AND_HIGHER debug   /* debug, info, warn, error, fatal */
     77//#define LOG_THESE_AND_HIGHER debug
     78
     79
     80
    4281#define NOOF_THREADS 10
    43 
     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);
    44102
    45103
     
    48106
    49107struct s_clientlist g_clientlist; /* FIXME - lock during login/logout, using mutexes */
    50 
     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];
    51112
    52113
     
    54115/* prototypes */
    55116
    56 int backup_client(int,char*);
     117int backup_client(char*, int, char*);
     118int compare_client(char*, int, char*);
    57119int find_client_in_clientlist(char *);
     120int forcibly_logout_all_clients(void);
     121int forcibly_logout_client(int);
     122void* generate_server_status_file_regularly(void*);
    58123int handle_incoming_message(int, struct sockaddr_in *, struct s_client2server_msg_record *);
    59124int handle_login_request(int, struct s_client2server_msg_record *, char *);
    60125int handle_logout_request(int, struct s_client2server_msg_record *, char *);
    61126int handle_ping_request(int, struct s_client2server_msg_record *, char *);
    62 void log_it(t_loglevel, char *);
    63 int restore_client(int,char*);
    64 int send_msg_to_client(struct s_server2client_msg_record *, char *, int);
     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*);
    65133void start_threads_to_watch_ports_for_requests(void);
    66 void interact_with_sysadm(void);
     134void terminate_daemon(int);
    67135char *tmsg_to_string(t_msg);
    68136void* watch_port_for_requests_from_clients(void*);
     
    70138
    71139
    72 /* subroutines */
    73 
    74 int backup_client(int clientno, char*path)
     140/*-----------------------------------------------------------*/
     141
     142
     143
     144int backup_client(char*ipaddr, int port, char*clientpath)
    75145/*
    76146Purpose:Backup the path of a specific client. Receive
    77     the archives. Store them locally (on me, the server).
     147the archives. Store them locally (on me, the server).
    78148Params: clientno - client# in g_clientlist[]
    79     path - client's path to be backed up
     149        clientpath - client's path to be backed up
    80150Return: result (0=success, nonzero=failure)
    81151*/
    82152{
    83153  struct s_server2client_msg_record rec_to_client;
    84   int i, res=0;
    85   char tmp[MAX_STR_LEN];
    86 
    87   sprintf(tmp, "Client# = %d", clientno);
     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);
    88249  log_it(debug, tmp);
    89   if (clientno >= g_clientlist.items)
    90     { log_it(fatal, "backup_client: clientno>=g_clientlist.items"); }
    91   sprintf(tmp, "Backing up %s - path=%s", g_clientlist.el[clientno].ipaddr, path);
    92   log_it(info, tmp);
    93   rec_to_client.msg_type = trigger_backup;
    94   strncpy(rec_to_client.body, path, sizeof(rec_to_client.body));
    95   if (send_msg_to_client(&rec_to_client, g_clientlist.el[clientno].ipaddr, g_clientlist.el[clientno].port))
    96     { log_it(error, "backup_client - failed to send msg to client"); return(1); }
    97 
    98   if (res)
    99     {
    100       sprintf(tmp, "Error(s) occurred while backing up %s", g_clientlist.el[clientno].ipaddr);
    101       log_it(error, tmp);
    102       return(1);
     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);
    103274    }
    104275  else
    105276    {
    106       sprintf(tmp, "Backed up %s OK", g_clientlist.el[clientno].ipaddr);
    107       log_it(error, tmp);
    108       return(0);
    109     }
    110 }
     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
    111297
    112298
     
    121307{
    122308  int i;
    123   char tmp[MAX_STR_LEN];
     309  char tmp[MAX_STR_LEN+1];
    124310
    125311  for(i = 0; i < g_clientlist.items; i++)
     
    132318  return(-1);
    133319}
     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/*-----------------------------------------------------------*/
    134408
    135409
     
    145419*/
    146420{
    147   char clientIP[MAX_STR_LEN], *ptr, tmp[MAX_STR_LEN];
     421  char clientIP[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
     422  unsigned char *ptr;
    148423  int res=0;
    149424
     
    152427  sprintf(clientIP, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);
    153428  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);
    154431  log_it(debug, tmp);
    155432  switch(rec->msg_type)
     
    161438      res=handle_ping_request(skt, rec, clientIP);
    162439      break;
     440    case progress_rpt:
     441      res=handle_progress_rpt(skt, rec, clientIP);
     442      break;
    163443    case logout:
    164444      res=handle_logout_request(skt, rec, clientIP);
    165445      break;
     446    case user_req:
     447      res=handle_user_request(skt, rec, clientIP);
     448      break;
    166449    default:
    167       sprintf(tmp, "%s request from %s [%s] (port %d) - how do I handle it?", tmsg_to_string(rec->msg_type), clientIP, rec->body, rec->port);
    168       log_it(error, tmp);
     450      log_it(error, "...How do I handle it?");
    169451    }
    170452  return(res);
    171453}
     454
     455
     456
     457/*-----------------------------------------------------------*/
    172458
    173459
     
    185471  struct s_server2client_msg_record rec_to_client;
    186472  int clientno;
    187   char tmp[MAX_STR_LEN];
    188 
    189   sprintf(tmp, "Login request from %s [%s] (port %d)", clientIP, rec_from_client->body, rec_from_client->port);
    190   log_it(info, tmp);
     473  char tmp[MAX_STR_LEN+1];
     474
     475//FIXME - lock g_clientlist[]
    191476  clientno = find_client_in_clientlist(clientIP);
    192477  if (clientno>=0)
    193478    {
    194       rec_to_client.msg_type = fail;
     479      rec_to_client.msg_type = login_fail;
    195480      sprintf(rec_to_client.body, "Sorry, you're already logged in!");
    196481      sprintf(tmp, "Ignoring login rq from %s: he's already logged in.", clientIP);
     
    210495      strncpy(g_clientlist.el[clientno].ipaddr, clientIP, sizeof(g_clientlist.el[clientno].ipaddr));
    211496      g_clientlist.el[clientno].port = rec_from_client->port;
     497      g_clientlist.el[clientno].busy = false;
    212498      g_clientlist.items ++;
    213499      sprintf(tmp, "Login request from %s ACCEPTED", clientIP);
    214500      log_it(info, tmp);
    215     }
    216   send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port);
     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);
    217504  return(0);
    218505}
     506
     507
     508
     509/*-----------------------------------------------------------*/
    219510
    220511
     
    225516    from client.
    226517Params: skt - client's port to talk to
    227     rec_from_client - login rq record received from client
     518    rec_from_client - logout rq record received from client
    228519    clientIP - client's IP address, in string
    229520Return: result (0=success, nonzero=failure)
     
    232523  struct s_server2client_msg_record rec_to_client;
    233524  int i, res=0;
    234   char tmp[MAX_STR_LEN];
    235 
    236   sprintf(tmp, "Logout request from %s [%s] (port %d)", clientIP, rec_from_client->body, rec_from_client->port);
    237   log_it(info, tmp);
     525  char tmp[MAX_STR_LEN+1];
     526
    238527  i = find_client_in_clientlist(clientIP);
    239528  if (i<0)
     
    241530      sprintf(rec_to_client.body, "Client is not logged in yet. How can I log him out?");
    242531      log_it(error, rec_to_client.body);
    243       rec_to_client.msg_type = fail;
     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;
    244540      res=1;
    245541    }
     
    257553      log_it(info, tmp);
    258554    }
    259   send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port);
     555  send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
    260556  return(res);
    261557}
     558
     559
     560
     561/*-----------------------------------------------------------*/
    262562
    263563
     
    268568    from client.
    269569Params: skt - client's port to talk to
    270     rec_from_client - login rq record received from client
     570    rec_from_client - ping record received from client
    271571    clientIP - client's IP address, in string
    272572Return: result (0=success, nonzero=failure)
     
    275575  struct s_server2client_msg_record rec_to_client;
    276576  int i;
    277   char tmp[MAX_STR_LEN];
    278 
    279   sprintf(tmp, "ping request from port %d --- %s", rec_from_client->port, rec_from_client->body);
    280   log_it(info, tmp);
     577  char tmp[MAX_STR_LEN+1];
     578
    281579  i = find_client_in_clientlist(clientIP);
    282580  if (i < 0)
     
    289587      rec_to_client.msg_type = pong; /* reply to ping */
    290588      sprintf(rec_to_client.body, "Hey, I'm replying to client#%d's ping. Pong! (re: %s", i, rec_from_client->body);
    291       send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port);
     589      send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
    292590      log_it(debug, rec_to_client.body);
    293591    }
     
    297595
    298596
    299 void interact_with_sysadm()
    300 /*
    301 Purpose:Tell sysadm about users logged in, etc. in
    302     response to keypresses (1=users, ENTER=exit)
    303 Params: none
    304 Return: none
    305 NB: Called by main()
    306 */
    307 {
    308   char tmp[MAX_STR_LEN];
    309   int i;
    310   bool done;
    311 
    312   for(done=false; !done; )
    313     {
    314       printf("Type 1 to list clients\n");
    315       printf("Type 2 to backup a client\n");
    316       printf("Type 3 to restore a client\n");
    317       printf("Type ENTER to quit.\n");
    318       fgets(tmp, sizeof(tmp), stdin);
    319       if (!strcmp(tmp, "1\n"))
    320     {
    321       printf("g_clientlist.items is %d\n", g_clientlist.items);
    322       printf("List of %d clients:-\n", g_clientlist.items);
    323       printf("\tClient# Port#  IP address       Client name\n");
    324       for(i=0; i<g_clientlist.items; i++)
    325         {
    326           printf("\t%d\t%4d   %-16s %-20s \n", i, g_clientlist.el[i].port, g_clientlist.el[i].ipaddr, g_clientlist.el[i].hostname_pretty);
    327         }
    328           printf("<End of list>\n\n");
    329         }
    330       else if (!strcmp(tmp, "2\n"))
    331         {
    332       if (g_clientlist.items!=1) { printf("Forget it\n"); }
    333       else
    334         {
    335           backup_client(0, "/usr/local");
    336         }
    337     }
    338       else if (!strcmp(tmp, "3\n"))
    339         {
    340       if (g_clientlist.items!=1) { printf("Forget it\n"); }
    341       else
    342         {
    343           restore_client(0, "/usr/local");
    344         }
    345     }
    346       else if (!strcmp(tmp, "\n"))
    347         {
    348           if (g_clientlist.items > 0)
     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)
    349705            {
    350               printf("There are %d users logged in. Are you sure you want to quit? ", g_clientlist.items);
    351               fgets(tmp, sizeof(tmp), stdin);
    352               if (tmp[0]=='Y' || tmp[0]=='y')
    353                 { done=true; }
     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);
    354713            }
    355714          else
    356             { done=true; }
    357           if (done)
    358             { log_it(info, "OK, you've chosen to shutdown server."); }
    359           else
    360             { log_it(info, "Shutdown canceled."); }
    361         }
    362     }
    363 }
    364 
    365 
    366 
    367 void log_it(t_loglevel level, char *sz_message)
    368 {
    369   char sz_outstr[MAX_STR_LEN], sz_level[MAX_STR_LEN], sz_time[MAX_STR_LEN];
    370   time_t time_rec;
    371 
    372   time(&time_rec);
    373   switch(level)
    374     {
    375       case debug: strcpy(sz_level, "DEBUG"); break;
    376       case info:  strcpy(sz_level, "INFO "); break;
    377       case warn:  strcpy(sz_level, "WARN "); break;
    378       case error: strcpy(sz_level, "ERROR"); break;
    379       case fatal: strcpy(sz_level, "FATAL"); break;
    380       default:    strcpy(sz_level, "UNKWN"); break;
    381     }
    382   sprintf(sz_time, ctime(&time_rec));
    383   sz_time[strlen(sz_time)-6] = '\0';
    384   sprintf(sz_outstr, "%s %s: %s", sz_time+11, sz_level, sz_message);
    385   if ((int)level >= LOG_THESE_AND_HIGHER)
    386     {
    387       fprintf(stderr, "%s\n",sz_outstr);
    388     }
    389   if (level==fatal) { fprintf(stderr,"Aborting now."); exit(1); }
    390 }
    391 
    392 
    393 
    394 
    395 int restore_client(int clientno, char*path)
    396 {
    397 }
    398 
    399 
    400 int send_msg_to_client(struct s_server2client_msg_record *rec, char *clientIP, int port)
     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)
    401814/*
    402815Purpose:Send a message from server to client.
    403     A 'message' could be a response to a login/logout/ping
    404     request or perhaps a 'trigger'. (A trigger is a message
    405     from server to client intended to initiate a backup
    406     or similar activity.)
     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.)
    407820Params: rec - record containing the data to be sent to client
    408     clientIP - the xxx.yyy.zzz.aaa IP address of client
    409     port - the client's port to send data to
    410 Return: result (0=success, nonzero=failure)
    411 */
    412 {
    413   struct hostent *hp;
    414   struct sockaddr_in sin;
    415   int  s;
    416   char tmp[MAX_STR_LEN];
    417 
    418   if ((hp = gethostbyname(clientIP)) == NULL)
    419     {
    420       sprintf(tmp, "send_msg_to_client: %s: unknown host\n", clientIP);
    421       log_it(error, tmp);
    422       return(1);
    423     }
    424   memset((void*)&sin, 0, sizeof(sin));
    425   memcpy((void*)&sin.sin_addr, hp->h_addr, hp->h_length);
    426   sin.sin_family = AF_INET;
    427   sin.sin_addr.s_addr = INADDR_ANY;
    428   sin.sin_port = htons(port);
    429   if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    430     { perror("socket"); log_it(error, "send_msg_to_client: SOCKET error"); return(1); }
    431   if (connect(s, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)) < 0)
    432     { sprintf(tmp, "Failed to connect to client %s on port %d", clientIP, port); log_it(error, tmp); return(1); }
    433   send(s, (char*)rec, sizeof(struct s_server2client_msg_record), 0);
    434   close(s);
    435   sprintf(tmp, "Sent %s msg to %s (port %d)", tmsg_to_string(rec->msg_type), clientIP, port);
    436   log_it(debug, tmp);
    437   return(0);
    438 }
     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/*-----------------------------------------------------------*/
    439858
    440859
     
    450869{
    451870  int i, port, res;
    452   pthread_t threadinfo[NOOF_THREADS];
    453   char tmp[MAX_STR_LEN];
     871  char tmp[MAX_STR_LEN+1];
    454872
    455873  g_clientlist.items = 0;
     
    458876      port = 8700+i;
    459877      sprintf(tmp,"%d", port);
    460       res = pthread_create(&(threadinfo[i]), NULL, watch_port_for_requests_from_clients, (void*)tmp);
     878      res = pthread_create(&(g_threadinfo[i]), NULL, watch_port_for_requests_from_clients, (void*)tmp);
    461879      if (res != 0)
    462880        {
    463         perror("Thread creation failed");
     881      perror("Thread creation failed");
    464882        }
    465       usleep(80000);
    466     }
    467   sprintf(tmp, "Threads are now running.");
     883      usleep(50000);
     884    }
     885  sprintf(tmp, "Now monitoring ports %d thru %d for requests from clients.", 8700, 8700+NOOF_THREADS-1);
    468886  log_it(info, tmp);
    469887}
     
    471889
    472890
    473 char *tmsg_to_string(t_msg msg_type)
    474 /*
    475 Purpose:Return a string/name of the msg of type msg_type
    476 Params: msg_type - type of message (enum typedef)
    477 Return: pointer to static string {name of msg)
    478 */
    479 {
    480   static char sz_msg[MAX_STR_LEN];
    481   switch(msg_type)
    482     {
    483       case unused : strcpy(sz_msg, "unused"); break;
    484       case login  : strcpy(sz_msg, "login"); break;
    485       case logout : strcpy(sz_msg, "logout"); break;
    486       case login_ok:strcpy(sz_msg, "login_ok"); break;
    487       case logout_ok:strcpy(sz_msg, "logout_ok"); break;
    488       case ping   : strcpy(sz_msg, "ping"); break;
    489       case pong   : strcpy(sz_msg, "pong"); break;
    490       case fail   : strcpy(sz_msg, "fail"); break;
    491       case trigger_backup: strcpy(sz_msg, "trigger_backup"); break;
    492       case trigger_restore: strcpy(sz_msg, "trigger_restore"); break;
    493       case begin_stream: strcpy(sz_msg, "begin_stream"); break;
    494       case end_stream: strcpy(sz_msg, "end_stream"); break;
    495       default: strcpy(sz_msg, "(Fix tmsg_to_string please)"); break;
    496     }
    497   return(sz_msg);
    498 }
     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/*-----------------------------------------------------------*/
    499935
    500936
     
    514950  int watch_port;
    515951  struct sockaddr_in sin;
    516   char buf[MAX_STR_LEN+1], tmp[MAX_STR_LEN];
     952  char buf[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
    517953  int len, s, new_s;
    518954  struct s_client2server_msg_record rec;
    519955
    520956  watch_port = atoi((char*)sz_watchport);
    521   sprintf(tmp, "watch_port_for_requests_from_clients(%d) - starting", watch_port);
    522   log_it(debug, tmp);
     957//  sprintf(tmp, "watch_port_for_requests_from_clients(%d) - starting", watch_port); log_it(debug, tmp);
    523958  memset((void*)&sin, 0, sizeof(sin));
    524959  sin.sin_family = AF_INET;
     
    544979    }
    545980  /* service incoming connections */
    546   sprintf(tmp, "Opened socket on port #%d OK", watch_port);
    547   log_it(info, tmp);
     981  sprintf(tmp, "Bound port #%d OK", watch_port);
     982  log_it(debug, tmp);
    548983  while(true)
    549984    {
     
    5681003
    5691004
     1005/*-----------------------------------------------------------*/
     1006
     1007
     1008
    5701009int main(int argc, char*argv[])
    5711010/*
     
    5751014*/
    5761015{
    577   char tmp[MAX_STR_LEN];
    578 
    579 /* FIXME - add Ctrl-C / sigterm trapping */
    580 
     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);
    5811021  start_threads_to_watch_ports_for_requests();
    582   interact_with_sysadm(); /* report on users logged in, etc.; return after a while... */
    583   if (g_clientlist.items != 0)
    584     { fprintf(stderr, "Ruh-roh! Some users are still logged in. Oh well...\n"); }
    585 /* FIXME - force clients to log off */
    586 /* FIXME - send signal to threads, telling them to terminate */
    587   sprintf(tmp, "Done. Server is exiting now.");
    588   log_it(info, tmp);
    589   return(0);
     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);
    5901026}
    5911027/* end main() */
Note: See TracChangeset for help on using the changeset viewer.