Question: 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

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 

//--- ---// //--- Header file inclusions: ---// //--- ---// #include #include #include #include // For alarm() #include #include // For creat() #include // For creat(), wait() #include // For creat() #include // For creat() #include #include //--- ---// //--- 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 == ' ') { // II.A.1.a. Treat carriage return like newline: c = ' '; } 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 == ' ') { // 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] = ' '; index++; saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); index = 0; waddch(typingWindow,' '); 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); }

  1. 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:
    SIGALRM sigAlarmHandler()
    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)
  2. 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.
  3. Add whatever variables you want (within reason).
  4. 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? ") | +--------------------------------------->|read() | | | | |<---------------------------------------+ write("(stdin)= 2bf96f28acc7c224180c36f241abb9f36a1ab95fe8f3737d312abcd4") | stops | | | | | fork() | /execl() openssl +--------------------------------------->| | | | | | | | | | write("Greetings, how are you? ") | +--------------------------------------->|read() | | | | |<---------------------------------------+ write("(stdin)= 77a710abf0b87330026b1530fd062049fd923f0170fdc2dd786004601659218e") | | | stops |

Step by Step Solution

There are 3 Steps involved in it

1 Expert Approved Answer
Step: 1 Unlock blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Databases Questions!