/******************************************************************/
/* pcomm is a program which demonstrates three ways which         */
/* processes can communicate with each other.                     */
/* Physics 673: Real Time Computing                               */
/* Norm Buchanan           96/11/18                               */
/******************************************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUFFSIZE 1024

void pipe_comm(void);
void fifo_comm(void);
void smem_comm(void);
void menu(void);

main () {

    menu();
}

/******************************************************************/
/* pipe_comm is a simple routine which demonstrates communication */
/* between a parent and child process. The child first talks to   */
/* the parent, which echos the message to STDOUT.  The same then  */
/* takes place from the parent to child.                          */
/******************************************************************/

void pipe_comm(void){

    int ret_val, filedes[2], length;
    char input[BUFFSIZE];

    if (pipe(filedes) < 0){
	printf("\aError opening pipe\n");
	exit(1);
    }
    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child process */
        /* Child sends message to parent */
	write(filedes[1], "Message sent from child\n", 24);
        /* Child receives message from parent */
	sleep(2);
	length = read(filedes[0], input, BUFFSIZE);
	write(STDOUT_FILENO, input, length);
    }
    else { /* parent process */
	/* Parent receives message from child */
	length = read(filedes[0], input, BUFFSIZE);
	write(STDOUT_FILENO, input, length);
	/* Parent sends message to child */
	sleep(1);
	write(filedes[1], "Message sent from parent\n", 25);
	sleep(2);
    }
}

/******************************************************************/
/* fifo_comm is a simple routine which demonstrates communication */
/* between a parent and child process. The child first talks to   */
/* the parent, which echos the message to STDOUT.  The same then  */
/* takes place from the parent to child.                          */
/******************************************************************/

void fifo_comm(void){

    int ret_val, id, length;
    char input[BUFFSIZE];
    unlink("clink");
    if (mkfifo("clink",0666) < 0){
	printf("\aError making fifo\n");
	exit(1);
    }

    if ( (id = open("clink", O_RDWR)) < 0){
	printf("\a Error in opening pipe\n");
	exit(2);
    }
    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child sends message to parent */
	/* Child sends message to parent */
	write(id, "Message sent from child\n", 24);
        /* Child receives message from parent */
	sleep(2);
	length = read(id, input, BUFFSIZE);
	write(STDOUT_FILENO, input, length);
    }
    else { /* parent */
	length = read(id, input, 100);
	write(STDOUT_FILENO, input, length);
	sleep(1);
	write(id, "Message sent from parent\n", 25);
	sleep(2);	
    }

}

/************************************************************************/
/* This routine is an attempt at achieving shared memory communication  */
/* between processes.  Unfortunately I couldn't get it to work as there */
/* was a problem accessing memory between parent and child.             */
/************************************************************************/ 

void smem_comm(void){

    int ret_val, id, val;
    char *input1;
    char *shmaddr; 
    key_t key;
    char *mesgptr;
    
    key = IPC_PRIVATE;
    id = shmget(key,4096, 0600);              /* default size   */
    if (id < 0){
	printf("\aError getting memory block\n");
	exit(3);
    }
    /* attach segment for reading */
    if ((mesgptr = (void *) shmat (id, 0, 0)) == (void *) -1){
      printf("\aError attaching segment\n");
      exit(3);
    }
    
    fflush(stdout);
    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child sends message to parent */
      
      *input1 = 99;
      mesgptr=input1;
    }
    else { /* parent sleeps for 100 seconds */
      printf("%d\n", *mesgptr);

      if (shmdt(mesgptr) < 0){ /* detach segment */
	printf("\aError detaching message\n");
	printf("%d\n", val);
	printf("%d\n", errno);
	exit(4);
      }
    }

}


/***********************************************************/
/* Function which allows user to pick a particular forking */
/* routine                                                 */
/***********************************************************/

void menu(void){

    int choice;

    system("clear");  /* Send clear command to shell */
    printf("\nChoose comm routine:  1)pipe 2)fifo 3)shmem > ");
    scanf("%d", &choice);
    if (choice == 1) {
	printf("\n\nRunning pipe communication\n\n");
	pipe_comm();
    }
    else if (choice == 2) {
	printf("\n\nRunning fifo communication\n\n");
	fifo_comm();
    }
    else if (choice == 3) {
	printf("\n\nRunning shared memory communication\n\n");
	smem_comm();
    }
}