/*
 * pmb_s.c
 *
 * Retrieve megabytes per second, in real time.  
 * Built from pinfo.c
 *
 * Author: David Rochberg, Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1996,1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_pdrive_client.h>
#include <nasd/nasd_control.h>
#include <nasd/nasd_general.h>
#include <nasd/nasd_security.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <netdb.h>

#define CHECKRC(_rc_,a) {if (_rc_ < 0) {perror(a);exit(1);}}
char *progname;

nasd_error_string_t error_text;
nasd_sec_keyring_t keys;
nasd_drive_handle_t   h;
char                  *drive_name;
char                  *server_name;
int                     server_port;
nasd_cookie_t          cookie;

int exclude_part_info = 0;
int include_cache_stats = 0;
int include_op_stats = 0;
int zero_drive_stats = 0;



void
usage()
 {
  fprintf(stderr, "USAGE: %s [options] drive_name master_password server_name server_port\n", progname);
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  -p print out stats as they are collected\n");
  fflush(stderr);
  exit(1);
}


int
make_connection(char *hostname,int port)
{
  struct sockaddr_in	addr;
  struct hostent	*hp;
  int			s;
  int			rc;
  int			opt;
  struct hostent	hostent;
  nasd_status_t         nasd_status;

  bzero((char *)&addr,sizeof(addr));
  hp = &hostent;
  nasd_status = nasd_gethostbyname_r(hostname, hp);
  if (nasd_status) {
    fprintf(stderr, "ERROR: failed nasd_gethostbyname_r() with 0x%x (%s)\n",
      nasd_status, nasd_error_string(nasd_status));
    exit(1);
  }

  bcopy((char *)hp->h_addr, (char *)&addr.sin_addr, hp->h_length);
  addr.sin_family=AF_INET;
  addr.sin_port = htons (port);
  s = socket(AF_INET,SOCK_DGRAM,PF_UNSPEC);
  CHECKRC(s,"socket");
  opt = 1;
  rc = connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
  if (rc < 0) {
    close(s);
    perror("Could not connect");
    exit(1);
  }
  return s;
}


typedef struct stats_s {
  nasd_int64           timestamp;   /* Nanoseconds since epoch */
  nasd_int64           idlestamp;   /* Idle nanoseconds since epoch */
  nasd_int64           bytes_read;
  nasd_int64           bytes_written;
} stats_t;             


void 
alphaton64(nasd_int64 * dest, nasd_uint64 source) {
  nasd_int32  *d = (nasd_int32 *)dest;
  d[1]= htonl ((nasd_int32) (source & 0xFFFFFFFFl));
  d[0]= htonl ((nasd_int32) (source >> 32) );
}
  

int doprint = 0;

int
main(
  int     argc,
  char  **argv)
{
  nasd_ctrl_cache_stat_t *cache_stats;
  nasd_security_param_t sp;
  nasd_status_t rc;
  char c;
  int binding_type = NASD_BIND_DEFAULT;
  char buffer[8192];
  stats_t     stats;
  int s;

  progname = argv[0];

  while (nasd_getopt(argc, argv, "p", &c)) {
    switch(c) {
    case 'p' :
      doprint = 1;
      break;
    default:
      fprintf(stderr, "Unknown option '%c'\n", nasd_optopt);
      usage();
    }
  }

  if (nasd_optind +4 != argc)
    usage();

  drive_name = argv[nasd_optind+0];
  nasd_sec_password_to_keys(argv[nasd_optind+1], 0, &keys);
  server_name = argv[nasd_optind+2];
  if (sscanf(argv[nasd_optind+3],"%d",&server_port)!=1) {
    usage();
  }
  s = make_connection(server_name,server_port);

  bzero((char *)&cookie, sizeof(cookie));
  rc = nasd_cl_p_init();
  if (rc) {
    printf("ERROR (%s:%d): cannot init client library, rc=0x%x (%s)\n",
      __FILE__, __LINE__, rc, nasd_error_string(rc));
    return(rc);
  }
  rc = nasd_bind_to_drive(drive_name, NASD_PDRIVE_PORT,
    binding_type, NULL, 0, &h);
  if (rc) {
    fprintf(stderr, "ERROR: cannot bind to server %s\n", drive_name);
    fflush(stderr);
    exit(1);
  }

  printf("Drive: %s, server: %s port %d\n", drive_name,server_name,server_port);
  sp.type = NASD_BLACK_KEY;
  sp.partnum = 0;
  sp.actual_protection = NASD_NO_PROTECTION;

  cache_stats = (nasd_ctrl_cache_stat_t *)buffer;

  while (1) {
    rc = nasd_cl_p_ctrl_get_drive_cache_stats (h, keys.black_key, &sp,
                                               NULL, cache_stats);
    if (rc) {
      fprintf(stderr, "ERROR: got 0x%x (%s) from nasd_cl_p_get_drive_op_stats\n",
              rc, nasd_error_string(rc));
      fflush(stderr);
      exit(1);
    }

    if (doprint) {
      printf ("Timestamp %ds:%dns\n",
        cache_stats->timestamp.ts_sec , cache_stats->timestamp.ts_nsec);
      printf ("Idle %ds:%dns\n",
        cache_stats->idle.ts_sec , cache_stats->idle.ts_nsec);
      printf ("Bytes read %"NASD_64u_FMT"\n", cache_stats->read_bytes + cache_stats->read2_bytes);/*DB*/
      printf ("Bytes written %"NASD_64u_FMT"\n", cache_stats->write_bytes);
    }
    alphaton64 (&stats.timestamp, 1000000000L * (nasd_uint64 )cache_stats->timestamp.ts_sec + (nasd_uint64) cache_stats->timestamp.ts_nsec);
    alphaton64 (&stats.idlestamp, 1000000000L * (nasd_uint64 )cache_stats->idle.ts_sec + (nasd_uint64) cache_stats->idle.ts_nsec);
    alphaton64 (&stats.bytes_read, cache_stats->read_bytes + cache_stats->read2_bytes);
    alphaton64 (&stats.bytes_written, cache_stats->write_bytes);
    rc = write (s,&stats,sizeof(stats));
    if (rc != sizeof(stats)) {
      perror("Write on socket");
    }
    {
      struct timeval tv;
      tv.tv_sec=0;tv.tv_usec=500000;
      select(0,NULL,NULL,NULL,&tv);
    }
  }
  /* NOTREACHED */
  exit(0);
}

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
