pipes/socket pairs

Anonymous
timer Asked: Feb 2nd, 2021

Question Description

  • Purpose:

    To go over multiprocessing on a single machine:
    • pipes/socket pairs
    • fork()/execl()

    Overview:

    Cryptographic hash functions are hash functions that are designed to be relatively easy to compute but hard to figure out which sequences of bytes yields a given hash value. (Computation in reverse.)On Linux systems the command-line tool openssl does several things, including computing some common hash functions. For example, if we make a little file:
    $ cat > print.txt
    Greetings, how are you? (press Enter)
    (press Ctrl-D)
    $ cat print.txt
    Greetings, how are you?
    $  
    We can use openssl to compute the SHA-224 hash of it:
    $ openssl sha224 -hex < print.txt
    (stdin)= 2bf96f28acc7c224180c36f241abb9f36a1ab95fe8f3737d312abcd4
    $     
    We will finish a program that acts like a simple word-processor and that sends its text to openssl to compute the hashes SHA-224 and SHA-256. It then prints them for the user.
    'Esc' to quit. Ctrl-P to compute hashes.
     Greetings, how	are you?
     
    
    
    
    Hashes:
     sha224= 2bf96f28acc7c224180c36f241abb9f36a1ab95fe8f3737d312abcd4
     sha256= 77a710abf0b87330026b1530fd062049fd923f0170fdc2dd786004601659218e
        

    Computing

    Please ssh into one of the following:
    • cdmcscjpprd01.dpu.depaul.edu
    • your own Unix machine with openssl and ncurses installed
    Please submit your finished program
    1. Please copy-and-paste the following file (0 Points):

      wordProc_hash.c
      /*-------------------------------------------------------------------------*
       *---									---*
       *---		wordProc_hash.c						---*
       *---									---*
       *---	  A rudimentary word processor that prints the hash values of	---*
       *---	saved files.							---*
       *---									---*
       *---	----	----	----	----	----	----	----	----	---*
       *---									---*
       *---	Version 1a		2020 January 1		Joseph Phillips	---*
       *---									---*
       *-------------------------------------------------------------------------*/
      
      //
      //	Compile with:
      //	$ g++ wordProc_hash.c -o wordProc_hash -lncurses -g
      //
      //	NOTE:
      //	If this program crashes then you may not see what you type.
      //	If that happens, just type:
      //
      //		stty sane
      //
      //	to your terminal, even though you cannot even see it.
      
      //---									---//
      //---			Header file inclusions:				---//
      //---									---//
      #include	<stdlib.h>
      #include	<stdio.h>
      #include	<string.h>
      #include	<unistd.h>	// For alarm()
      #include	<sys/socket.h>
      #include	<sys/types.h>	// For creat()
      #include	<sys/wait.h>	// For creat(), wait()
      #include	<sys/stat.h>	// For creat()
      #include	<fcntl.h>	// For creat()
      #include	<signal.h>
      #include	<ncurses.h>
      
      
      //---									---//
      //---			Definitions of constants:			---//
      //---									---//
      #define		HASH_PROGRAM		"/usr/bin/openssl"
      #define		HASH_ARG		"-hex"
      #define		STOP_CHARS		"*+-#&"
      const char*	HASH_TYPE_ARRAY[]	= {"sha224","sha256"};
      const int	NUM_HASH_TYPES		= sizeof(HASH_TYPE_ARRAY)/sizeof(char*);
      
      const int	HEIGHT			= 5;
      const int	WIDTH			= 72;
      const int	INIT_TEXT_LEN		= 1024;
      const int	MAX_TEXT_LEN		= 65536;
      const char	STOP_CHAR		= (char)27;
      const char	PRINT_CHAR		= (char)0x10;
      const int	BUFFER_LEN		= 64 * 16;
      const int	TYPING_WINDOW_BAR_Y	= 0;
      const int	CHECKING_WINDOW_BAR_Y	= TYPING_WINDOW_BAR_Y   + HEIGHT + 1;
      const int	MESSAGE_WINDOW_BAR_Y	= CHECKING_WINDOW_BAR_Y + 1;
      const int	NUM_MESSAGE_SECS	= 6;
      
      
      //---									---//
      //---			Definitions of global vars:			---//
      //---									---//
      WINDOW*		typingWindow;
      WINDOW*		checkingWindow;
      WINDOW*		messageWindow;
      pid_t		childPid;
      int		shouldRun	= 1;
      
      
      //---									---//
      //---			Definitions of global fncs:			---//
      //---									---//
      
      //  PURPOSE:  To turn 'ncurses' on.  No parameters.  No return value.
      void		onNCurses	()
      {
        //  I.  Application validity check:
      
        //  II.  Turn 'ncurses' on:
        initscr();
        cbreak();
        noecho();
        nonl();
      //intrflush(stdscr, FALSE);
      //keypad(stdscr, TRUE);
        typingWindow		= newwin(HEIGHT,WIDTH,TYPING_WINDOW_BAR_Y+1,1);
        checkingWindow	= newwin(HEIGHT,WIDTH,CHECKING_WINDOW_BAR_Y+1,1);
        messageWindow		= newwin(     2,WIDTH,MESSAGE_WINDOW_BAR_Y,1);
        scrollok(typingWindow,TRUE);
        scrollok(checkingWindow,TRUE);
      
        mvaddstr(TYPING_WINDOW_BAR_Y,0,"'Esc' to quit. Ctrl-P to compute hashes.");
        mvaddstr(CHECKING_WINDOW_BAR_Y,0,"Hashes:");
        refresh();
        wrefresh(typingWindow);	// moves cursor back to 'typingWindow':
      
        //  III.  Finished:
      }
      
      
      //  PURPOSE:  To handle 'SIGALRM' signals.  Ignores 'sig' (which will be
      //	'SIGALRM').  No return value.
      void		sigAlarmHandler	(int		sig
      				)
      {
        mvwaddstr (messageWindow,0,0,
        	     "                                        "
        	     "                                       "
      	    );
        mvwaddstr (messageWindow,1,0,
        	     "                                        "
        	     "                                       "
      	    );
        wrefresh(messageWindow);
        wrefresh(typingWindow);	// moves cursor back to 'typingWindow':
      }
      
      
      //  PURPOSE:  To save the 'lineIndex' chars at the beginning of 'line' to
      //	to position '*endTextPtrPtr' in buffer '*bufferPtrPtr' of length
      //	'*bufferLenPtr' and with end '*endBufferPtrPtr'.  If there is not
      //	enough space in '*bufferPtrPtr' then '*bufferLenPtr' will be doubled,
      //	and '*bufferPtrPtr' will be 'realloc()'-ed to this new length.
      //	No return value.
      void		saveLine	(size_t*	bufferLenPtr,
      				 char**		bufferPtrPtr,
      				 char**		endTextPtrPtr,
      				 char**		endBufferPtrPtr,
      				 const char*	line,
      				 int   		lineIndex
      				)
      {
        //  I.  Application validity check:
      
        //  II.  Save 'line' to '*bufferPtrPtr':
        //  II.A.  Allocate more space if needed:
        if  (lineIndex >= (*endBufferPtrPtr - *endTextPtrPtr + 1) )
        {
          size_t	textLen	 = *endTextPtrPtr - *bufferPtrPtr;
      
          (*bufferLenPtr)	*= 2;
          (*bufferPtrPtr)	 = (char*)realloc(*bufferPtrPtr,*bufferLenPtr);
          (*endTextPtrPtr)	 = *bufferPtrPtr + textLen;
          (*endBufferPtrPtr)	 = *bufferPtrPtr + *bufferLenPtr;
        }
      
        //  II.B.  Save 'line' to '*bufferPtrPtr':
        memcpy(*endTextPtrPtr,line,lineIndex);
        (*endTextPtrPtr)	+= lineIndex;
      
        //  III.  Finished:
      }
      
      
      
      //  PURPOSE:  To attempt to compute the hashes of the text pointed to by
      //	'bufferPtr' using the hash functions in 'HASH_TYPE_ARRAY[]'.
      //	'endTextPtr' points to one char beyond the end of the text to print
      //	in 'bufferPtr'.  No return value.
      //
      //	SIDE EFFECT: Prints to 'messageWindow' and sets process to receive
      //		     'SIGALRM' 'NUM_MESSAGE_SECS' seconds in the future.
      //		     This will invoke 'sigAlarmHandler()', which erases the
      //		     text in 'messageWindow'.
      void		computeHashes	(const char*	bufferPtr,
      				 const char*	endTextPtr
      				)
      {
        //  I.  Application validity check:
      
        //  II.  Compute hashes:
        //  II.A.  Each iteration computes one hash:
        int hashIndex;
      
        for  (hashIndex = 0;  hashIndex < NUM_HASH_TYPES;  hashIndex++)
        {
          //  II.A.1.  Create pipes:
          int	toChild[2];
          int	fromChild[2];
      
          //  YOUR CODE HERE to make 2 pipes
      
          //  II.A.2.  Do 'openssl' process work:
          if  (/*  YOUR CODE HERE to make a child */ == 0)
          {
            //  YOUR CODE HERE to handle child case
      
      
            exit(EXIT_FAILURE);
          }
      
          //  II.A.3.  Do parent work:
          int		numBytes;
          int		status;
          char	text[INIT_TEXT_LEN];
          const char*	msgCPtr;
      
          //  YOUR CODE HERE to handle parent case
      
          mvwaddstr(messageWindow,hashIndex,0,HASH_TYPE_ARRAY[hashIndex]);
          waddstr(messageWindow,msgCPtr);
          wrefresh(messageWindow);
        }
      
        wrefresh(typingWindow);	// moves cursor back to 'typingWindow':
        //  YOUR CODE HERE to do one last thing
      
        //  III.  Finished:
      }
      
      
      //  PURPOSE:  To allow the user to type, display what they type in
      //	&apos'typingWindow', and to compute the hash upon pressing 'PRINT_CHAR'.
      //	'vPtr' comes in, perhaps pointing to something.  Returns 'NULL'.
      void*		type		(void*	vPtr
      				)
      {
        //  I.  Application validity check:
      
        //  II.  Handle user typing:
        unsigned int	c;
        char		line[WIDTH+1];
        int		index		= 0;
        size_t	bufferLen	= INIT_TEXT_LEN;
        char*		bufferPtr	= (char*)malloc(bufferLen);
        char*		endTextPtr	= bufferPtr;
        char*		endBufferPtr	= bufferPtr + bufferLen;
      
        //  II.A.  Each iteration handles another typed char:
        while  ( (c = getch()) != STOP_CHAR )
        {
      
          //  II.A.1.  Handle special chars:
          if  (c == '\r')
          {
            //  II.A.1.a.  Treat carriage return like newline:
            c = '\n';
          }
          else
          if  ( (c == 0x7) || (c == 127) )
          {
            //  II.A.1.b.  Handle backspace:
            int	col	= getcurx(typingWindow);
      
            if  (col > 0)
            {
              index--;
              wmove(typingWindow,getcury(typingWindow),col-1);
      	wrefresh(typingWindow);
            }
      
            continue;
          }
          else
          if  (c == PRINT_CHAR)
          {
            size_t	textLen	= endTextPtr - bufferPtr;
      
            saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index);
            computeHashes(bufferPtr,endTextPtr);
            endTextPtr	= bufferPtr + textLen;
            continue;
          }
          else
          if  (c == ERR)
          {
            continue;
          }
      
          //  II.A.2.  Print and record the char:
          waddch(typingWindow,c);
          wrefresh(typingWindow);
          line[index++]	= c;
      
          //  II.A.3.  Handle when save 'line':
          if  (c == '\n')
          {
            //  II.A.3.a.  Save 'line' when user types newline:
            saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index);
            index = 0;
          }
          else
          if  (index == WIDTH-1)
          {
            //  II.A.3.b.  Save 'line' when at last column:
            line[index] = '\n';
            index++;
            saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index);
            index = 0;
            waddch(typingWindow,'\n');
            wrefresh(typingWindow);
          }
        }
      
        //  III.  Finished:
        saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index);
      //int inFd = creat(TEXT_FILENAME,0640);
      //write(inFd,bufferPtr,endTextPtr-bufferPtr);
      //close(inFd);
        free(bufferPtr);
        return(NULL);
      }
      
      
      //  PURPOSE:  To turn off 'ncurses'.  No parameters.  No return value.
      void		offNCurses	()
      {
        sleep(1);
        nl();
        echo();
        refresh();
        delwin(messageWindow);
        delwin(typingWindow);
        delwin(checkingWindow);
        endwin();
      }
      
      
      
      //  PURPOSE:  To do the spell-checking word-processor.  Ignores command line
      //	arguments.  Return 'EXIT_SUCCESS' to OS.
      int		main		()
      {
        struct sigaction	act;
      
        // (2) YOUR CODE HERE to install sigAlarmHandler as the handler for SIGALRM
      
        onNCurses();
      
        type(NULL);
        offNCurses();
        return(EXIT_SUCCESS);
      }
      	  
    2. The action starts, of course, in main(). The first thing that main() should do is to install a simple signal handler:
      Signal:Handler to run:
      SIGALRMsigAlarmHandler()
      After that, mainy-main:
      • turns the windowing on (onNCurses(), already done)
      • lets the user type expressions (type() is done, but it calls computeHashes() which you must finish)
      • turns the windowing off (offNCurses(), already done)
    3. You must finish computeHashes(). It has a loop because it calls openssl twice, once for SHA-224 and once for SHA-256. Both iterations use pipes to send the endTextPtr-outputBufferPtr bytes pointed to by outputBufferPtr to a child process running openssl.
      1. (Section II.A.1.) First create two pipes. We will use one for the parent to talk to the child and the other for the child to talk to the parent.
      2. (Section II.A.2.) Now make a child process. If we are the child process then be sure to:
        • close() unnecessary pipe file descriptors
        • Redirect STDIN_FILENO to the input end of the appropriate pipe, and redirect STDOUT_FILENO to the output end of the appropriate pipe.
        • Run the hash program. The execl() program must specify the string constants
          • HASH_PROGRAM: The path of openssl
          • HASH_TYPE_ARRAY[hashIndex]: Tells which hash to compute (SHA-224 or SHA-256)
          • HASH_ARG: tells to give output in hexadecimal
          Remember:
          • How many times do we specify the program name?
          • What should the last argument to execl() be?
        • Have exit(EXIT_FAILURE) after the execl() line. Why?
      3. (Section II.A.3.) Now handle the parent. If we are the parent process then be sure to:
        • close() unnecessary pipe file descriptors
        • Send the endTextPtr-bufferPtr bytes of text pointed to by bufferPtr to the child. Then close() that file descriptor.
        • Get the response from the child into text and wait() for the child to end (getting its return status).
        • If the child successfully finished and read()ing its response was successful then
          • Add a null-char just after the last byte
          • Set msgCPtr to the occurence of "= " in the text you read() (HINT Use strstr().)
            IF YOU HAVE A MAC: then just say this instead:
            msgCPtr = text;
          If the child did not successfully finish or read()ing the response was not successful then set msgCPtr = "Compute hash failed"
      4. The very last thing the function should do is alarm(NUM_MESSAGE_SECS) This tells it run sigAlarmHandler() NUM_MESSAGE_SECS seconds in the future. That function erases the hash-values.
    4. Add whatever variables you want (within reason).
    5. Now run the bad boy! Type something and press Ctrl-P to compute the hash. Press Esc to quit.

    Sample output:

     'Esc' to quit. Ctrl-P to compute hashes.
     Greetings, how	are you?
     
    
    
    
    Hashes:
     sha224= 2bf96f28acc7c224180c36f241abb9f36a1ab95fe8f3737d312abcd4
     sha256= 77a710abf0b87330026b1530fd062049fd923f0170fdc2dd786004601659218e
        

    Sequence diagram:

     parent
    process
      |
      |
      |  fork()
      | /execl()			 openssl
      +--------------------------------------->|
      |					   |
      |					   |
      |					   |
      |					   |
      |write("Greetings, how are you?\n")	   |
      +--------------------------------------->|read()
      |					   |	
      |					   |
      |<---------------------------------------+ write("(stdin)= 2bf96f28acc7c224180c36f241abb9f36a1ab95fe8f3737d312abcd4")
      |					 stops
      |
      |
      |
      |
      |  fork()
      | /execl()			 openssl
      +--------------------------------------->|
      |					   |
      |					   |
      |					   |
      |					   |
      | write("Greetings, how are you?\n")	   |
      +--------------------------------------->|read()
      |					   |	
      |					   |
      |<---------------------------------------+ write("(stdin)= 77a710abf0b87330026b1530fd062049fd923f0170fdc2dd786004601659218e")
      |					   |	
      |					 stops
      |
          

Student has agreed that all tutoring, explanations, and answers provided by the tutor will be used to help in the learning process and in accordance with Studypool's honor code & terms of service.

This question has not been answered.

Create a free account to get help with this and any other question!

Brown University





1271 Tutors

California Institute of Technology




2131 Tutors

Carnegie Mellon University




982 Tutors

Columbia University





1256 Tutors

Dartmouth University





2113 Tutors

Emory University





2279 Tutors

Harvard University





599 Tutors

Massachusetts Institute of Technology



2319 Tutors

New York University





1645 Tutors

Notre Dam University





1911 Tutors

Oklahoma University





2122 Tutors

Pennsylvania State University





932 Tutors

Princeton University





1211 Tutors

Stanford University





983 Tutors

University of California





1282 Tutors

Oxford University





123 Tutors

Yale University





2325 Tutors