/* 
 * Real-Time and Multimedia Systems Laboratory
 * Copyright (c) 2000 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Real-Time and Multimedia Systems Laboratory
 *  Attn: Prof. Raj Rajkumar
 *  Electrical and Computer Engineering, and Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 *  or via email to raj@ece.cmu.edu
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */

/* Simple networking test for RKs....					*/
/*			By Luca Abeni	(luca@sssup.it)			*/

/*
 * This program creates a resource set RS, and attaches a cpu
 * reserve to it. Then, a child task is attached to the resource set.
 * The child task creates a network reservation, attach it to RS, and
 * starts sending UDP packets using the network reserve.
 * Remember to modify the destination IP address at line 114, and
 * to start the receiving process on the destination host.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <wait.h>
#include <rk/rk.h>
#include <rk/rk_error.h>
#include <signal.h>
#include <rk/posix_timers.h>
#include <rk/timespec.h>

#define C1 200
#define T1 400
#define C2 500
#define T2 1000

#define ITER 100

char SENDLINE[1000] =  {'a','b','c','d','e',0};

unsigned long int timevect[10000];
unsigned long int firstime;
struct timespec fnow;

/* DIRTY!!!! HAVE TO FIX IT!!! */
pid_t child1, child2;
rk_resource_set_t rs1, rs2;



/* Destroy the resource sets... end exits!!! */
void myshutdown(rk_resource_set_t rs)
{
  int res;

  res = rk_resource_set_destroy(rs);
  if (res != 0) {
    printf("rk_resource_set_destroy failed destroying RS %p; res = %d",
			 rs, res);
  }

  printf("Everithing is finished...\n");
  exit(0);
}

void sendertask(int childnum)
{
//  net_reserve_t net1;
  int                     sockfd;
  struct sockaddr_in      cli_addr, serv_addr;
  int port, myport;
  int rate;
  rk_reserve_t netrsv;
  net_reserve_attr_data_t attr;
  int count;

  port = 2030;
  myport = 10004;
  rate = 20000;
  
  srand48(1234);
  
  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family      = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr("128.2.194.182");
  serv_addr.sin_addr.s_addr = inet_addr("128.2.185.83"); //Abel
  serv_addr.sin_port        = htons(port);
  
  /*
   * Open a UDP socket (an Internet datagram socket).
   */
  
  if ( (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    perror("client: can't open datagram socket");
  
  /*
   * Bind any local address for us.
   */
  bzero((char *) &cli_addr, sizeof(cli_addr));    /* zero out */
  cli_addr.sin_family      = AF_INET;
  cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  cli_addr.sin_port        = htons(myport);
  if (bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
    perror("client: can't bind local address");
    exit(-1);
  }

	
  /*
   * Create the network reserve
   */
	/* 1000 bytes per second */
  attr.amount = 2000;
  attr.period.tv_sec = 1;
  attr.period.tv_nsec = 0;
  attr.deadline.tv_sec = 1;
  attr.deadline.tv_nsec = 0;

  attr.start_time.tv_sec = 0;
  attr.start_time.tv_nsec = 0;
  attr.blocking_time.tv_sec = 0;
  attr.blocking_time.tv_nsec = 0;

  attr.reserve_type.enf_mode = RSV_HARD;
  attr.reserve_type.sch_mode = attr.reserve_type.rep_mode = RSV_HARD;
 
  attr.socket_fd = sockfd;
  netrsv = rk_net_reserve_create(rs1, &attr);
  if (netrsv == NULL_RESERVE) {
	  printf("Net reserve creation failed!!!\n");
	  close(sockfd);
	  exit(-1);
  }
  printf("Net reserve create: %p\n", netrsv);

 
  /*
   * Start sending packets...
   */
  count=0;
  while(count < 100) {
    if (sendto(sockfd, SENDLINE, sizeof(SENDLINE), 0,(struct sockaddr *)  &serv_addr, sizeof(serv_addr)) == -1) {
      perror("sendto error on socket");
	printf("%d packets sent\n", count);
	  close(sockfd);
      exit(1);
    }
    printf(".\n");

    count++;
  }
  
  printf("OK, I sent %d packets...\n", count);

  close(sockfd);
  exit(1);
}

void print_usage(char *cmdname)
{
  printf("usage: %s n (ms/sec) \n", cmdname);
}

int main(int argc, char *argv[])
{
  rk_reserve_t	cpu_rsv1;
  rk_reserve_param_data_t p;
  struct timespec c, t;
  cpu_reserve_attr_data_t attr;
  char name[256];
  int res;

  /* create resource sets */
  sprintf(name, "RS 1");
  rs1 = rk_resource_set_create(name);
  printf("Resource Set created: %p\n", rs1);
  
  /* And now, the reserves... */
  clock_gettime(CLOCK_REALTIME, &fnow);
  firstime= fnow.tv_nsec / 1000000 + fnow.tv_sec * 1000;
  
  c.tv_sec = C1 / 1000, c.tv_nsec = (C1 % 1000) * 1000 * 1000;
  t.tv_sec = T1 / 1000, t.tv_nsec = (T1 % 1000) * 1000 * 1000;
  
  p.enf_mode = RSV_HARD;
  p.enf_mode = RSV_FIRM;
  p.sch_mode = p.rep_mode = RSV_HARD; 
  attr.compute_time = c;
  attr.period = t;
  attr.deadline = t;
  attr.blocking_time.tv_sec = 0 ; attr.blocking_time.tv_nsec = 0;
  memcpy(&attr.start_time, &fnow, sizeof(struct timespec));
  attr.start_time.tv_sec += 1;
  attr.reserve_type = p;

  cpu_rsv1 = rk_cpu_reserve_create(rs1, &attr);
  if (cpu_rsv1 == 0) {
    printf("Cannot create CPU reserve # 1\n");
    myshutdown(rs1);
  }
  
  while (rk_resource_set_get_cpu_rsv(rs1) == 0);

    /* Create child 1 & attach it to RS 1 */
  child1 = fork();
  if (child1 < 0) {
    perror("Error in fork()");
    myshutdown(rs1);
  }
  if (child1 == 0) {
    sendertask(1);
    printf("ARRRG!!!! Why am I here?\n");
  }
 /* Attach the sender process to the created RS... */
  res = rk_resource_set_attach_process(rs1, child1);
  if (res != 0) {
    printf("rk_resource_set_attach_proces failed for Resource Set 1...\n");
    myshutdown(rs1);
  }

 
printf("Done...\n");

  /* And now, as a good father, wait for the children to die... */
  wait(&res);

  /* ...and destroy the resource sets!!! */
  myshutdown(rs1);
  
  return 0;
}
