/*
 * drive_stats.c
 *
 *  Program to measure idle time on drives.
 *   Borrows heavily from tiic
 *
 * Author: David Rochberg, Dan Stodolsky, Jim Zelenka, Tammo Spalink
 */
/*
 * Copyright (c) of Carnegie Mellon University, 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_common.h>
#include <nasd/nasd_sys.h>
#include <stdio.h>
#include <stdlib.h>
#include <nasd/nasd_timer.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <string.h>
#include <sys/time.h>

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

int
accept_connection() 
{
  int			s,syncfd;
  struct sockaddr_in	addr;
  int			addrlen;
  int			opt;
  int			rc;

  s = socket (AF_INET,SOCK_STREAM,0);
  CHECKRC(s,"Could not create socket");
  bzero((char *)&addr,sizeof (struct sockaddr_in));
  opt = 1;
  rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,(char *)&opt,sizeof(int));
  CHECKRC(rc,"Could not setsockopt to SO_REUSEADDR");
  opt = 1;
  rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY,(char *)&opt,sizeof(int));
  CHECKRC(rc,"Turning off delay");
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(3840);
  rc = bind(s,(struct sockaddr *)&addr,sizeof(addr));
  CHECKRC(rc,"Could not bind socket");
  rc = listen (s,1);
  CHECKRC(rc,"Listen");
  syncfd = accept(s,(struct sockaddr *)&addr,&addrlen); 
  return syncfd;
}

int
main()
{
  int syncfd;
  FILE    *syncfi;
  int		step;
  double   elapsed;
  nasd_timespec_t diff;
  nasd_timer_t    timer;
#if NASD_IDLE_SUPPORT > 0
  nasd_timespec_t idle_ts1, idle_ts2;
  nasd_status_t        nasd_status;
  double id1,id2;
  double   idle;
#endif /* NASD_IDLE_SUPPORT > 0 */
  char	   buf[128];
  
  
  syncfd = accept_connection();
  
  /* Tell the coordinator that we are ready */
  write (syncfd,&step,4);
  /* Wait for the coordinator to tell us that we should go */
  read(syncfd,&step,4);

  
#if NASD_IDLE_SUPPORT > 0
  nasd_status = nasd_get_total_idle_time(&idle_ts1);
  if (nasd_status) {
    fprintf(stderr, "ERROR: got 0x%x (%s) from nasd_get_total_idle_time\n",
            nasd_status, nasd_error_string(nasd_status));
    exit(1);
  }
#endif /* NASD_IDLE_SUPPORT > 0 */
  NASD_TM_START(&timer); 
  
  /* Wait for the coordinator to stop us */
  read(syncfd,&step,4);
  
  NASD_TM_STOP(&timer);
#if NASD_IDLE_SUPPORT > 0
  nasd_status = nasd_get_total_idle_time(&idle_ts2);
  if (nasd_status) {
    fprintf(stderr, "ERROR: got 0x%x (%s) from nasd_get_total_idle_time\n",
	    nasd_status, nasd_error_string(nasd_status));
    exit(1);
  }
#endif /* NASD_IDLE_SUPPORT > 0 */
  
  NASD_TM_ELAPSED_TS(&timer, &diff);
  elapsed = (double)diff.ts_nsec;
  elapsed /= (double)1000000000.0;
  elapsed += (double)diff.ts_sec;
  
  /*calculate idle time*/
  
  
#if NASD_IDLE_SUPPORT > 0
  id1 = (double)idle_ts1.ts_nsec;
  id1 /= (double)1000000000.0;
  id1 += (double)idle_ts1.ts_sec;
  id2 = (double)idle_ts2.ts_nsec;
  id2 /= (double)1000000000.0;
  id2 += (double)idle_ts2.ts_sec;
  idle = id2 - id1;
#endif /* NASD_IDLE_SUPPORT > 0 */
  
  syncfi = fdopen(syncfd,"w+");
  gethostname(buf,sizeof(buf));
  fprintf (syncfi,"name: %s\n",buf);
  fprintf (syncfi,"type: drive\n");
#if NASD_IDLE_SUPPORT > 0
  fprintf (syncfi,"elapsed: %g\nidle: %g  Idle fraction %0.2g\n",elapsed,idle,idle/elapsed);/*DB*/
#else /* NASD_IDLE_SUPPORT > 0 */
  fprintf (syncfi,"elapsed: %g\n",elapsed);/*DB*/
#endif /* NASD_IDLE_SUPPORT > 0 */
  fflush (syncfi);
  exit(0);
}  
