/*
 * debitub.c
 * - recoit en arg bufsize et nbtubes
 * - alloue un tableau de char de lg bufsize
 * - cree nbtubes tubes et un fils
 *  - le pere scrute en ecriture les tubes
 *    si un descripteur est pres ecrit les
 *    bufsize premier caracteres de s dans
 *    le tube
 *  - le fils fait de meme en lecture et
 *    affiche chaque seconde le nombre de
 *    caracteres lus en ko pdt la seconde
 *******************************************
 * Davy Dequidt
 * L3 Info Luminy
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>

#define MAX_TUBES 1000

int sigaction(int sig,const struct sigaction *p_action,struct sigaction *p_action_ancien);

int mysignal (int sig, void (*h)(int))
{
        struct sigaction s;
        s.sa_handler=h;
        sigemptyset (&s.sa_mask);
        s.sa_flags=SA_RESTART;
        return sigaction(sig,&s,NULL);
}

unsigned long n = 0;

void capte( int sig ){
  switch( sig ){
    case SIGPIPE :
      printf("Fin de tube\n");
      exit(1);
    case SIGALRM :
      printf("fils a lu : %ld ko\n", n/1024);
      n = 0;
      alarm(1);
      break;
    default : 
      printf("Signal recu : %d\n", sig);
  }
}

int main(int argc, char *argv[])
{  
  char *s;
  int p[MAX_TUBES][2], pid, bufsize, nbtubes, i;
  if(argc!=3){
    printf("Usage : %s <bufsize> <nbtubes>\n\t nbtubes<%d\n",argv[0], MAX_TUBES);
    exit(0);
  }
  mysignal( SIGPIPE, capte);
  bufsize = atoi(argv[1]);
  nbtubes = atoi(argv[2]);
  if( nbtubes > MAX_TUBES ){
    printf("Usage : %s <bufsize> <nbtubes>\n\t nbtubes<%d\n",argv[0],MAX_TUBES);
    exit(0);
  }
  s = malloc( bufsize * sizeof *s ); /* alloc chaine de caracteres */
  if( !s ){ perror("malloc()"); exit(1); }

  for( i=0; i<nbtubes; i++ ) /* creation des tubes */
    if( pipe(p[i])<0 ){ perror("pipe()"); exit(1); }
  
  pid = fork();
  if( pid<0 ){
    perror("fork");
    exit(1);
  }
  if( pid==0 ){ /* fils */
    fd_set set;
    int res, k;
    mysignal( SIGALRM, capte);
    alarm(1);
    for( i=0; i<nbtubes; i++)
      close( p[i][1] );
    while(1){
      FD_ZERO(&set);
      for( i=0; i<nbtubes; i++) /* ajout des desc ds la liste */
	FD_SET( p[i][0],&set );
      res = select( p[nbtubes-1][0]+1, &set, NULL, NULL, NULL );
      if( res>0 ){ /* desc pret */
	for( i=0; i<nbtubes; i++){
	  if( FD_ISSET(p[i][0], &set) ){
	    k = read(p[i][0],s,bufsize);
	    if(k<0){
	      perror("read");
	      exit(1);
	    }
	    n += k;
	  }
	}
      }else{
	/* erreur */
	switch(errno){
	  case EBADF:fprintf(stderr, "1 desc (tube) fermé\n");break;
	  case EINTR:continue;
	  default:perror("fils select()");
	}
      }
    }
    for( i=0; i<nbtubes; i++)
      close( p[i][0] );
    exit(0);
  }
  if( pid>0 ){ /* pere */
    fd_set set;
    int res;
    printf("pere %d, fils %d\n", getpid(), pid);
    for( i=0; i<nbtubes; i++)
      close( p[i][0] );
    while(1){
      FD_ZERO(&set);
      for( i=0; i<nbtubes; i++) /* ajout des desc ds la liste */
          FD_SET( p[i][1],&set );
      res = select( p[nbtubes-1][1]+1, NULL, &set, NULL, NULL );
      if( res>0 ){
        for( i=0; i<nbtubes; i++)
	  if( FD_ISSET(p[i][1], &set) )
	    if( write(p[i][1],s,bufsize)<0 ){
	      perror("write()");
	      exit(1);
	    }
      }else{
	/* erreur */
	if(errno==EBADF) fprintf(stderr, "1 desc (tube) ferme\n");
	else perror("pere select()");
      }
    }
    for( i=0; i<nbtubes; i++)
      close( p[i][1] );
  }
  printf("bye\n");
  return EXIT_SUCCESS;
}


