Insight into something.
/* #ifndef __UTILITY_H__ */ /* #define __UTILITY_H__ */ #include <stdio.h> #include <string.h> //------------------------------------------------------------------ :Functions: // ___ _ _ // | __| _ _ _ __| |_(_)___ _ _ ___ // | _| || | ' \/ _| _| / _ \ ' \(_-< // |_| \_,_|_||_\__|\__|_\___/_||_/__/ // // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /** * @brief Used for testing, prints a pretty formatted title a specified file. * @param[in] num 0 for first header, 1 for any other header * @param[in] mode The file to write to * @param[in] title The string to print in the title * @return void */ //////////////////////////////////////////////////////////////////////////////// extern void print_title( int num, FILE * mode, char* title ) { fprintf(mode, "\n----------------------------------------\n"); fprintf(mode, " "); if(num == 0) { fprintf(mode, "START"); } else { fprintf(mode, " END "); } fprintf(mode, " %s\n", title); fprintf(mode, "----------------------------------------\n"); } //////////////////////////////////////////////////////////////////////////////// /** * @brief Used fast exponentiation to calculate powers. * @param[in] x The base. * @param[in] y The power. * @return x^y. */ //////////////////////////////////////////////////////////////////////////////// int my_pow(int x, int n) { if(n < 0 ) return my_pow(1/x, -n); else if ( n == 0 ) return 1; else if ( n == 1 ) return x; else if ( n%2 == 0 ) return my_pow(x*x, n/2); else if ( n%2 != 0 ) return x * my_pow(x*x, (n-1)/2); else return -1; } //////////////////////////////////////////////////////////////////////////////// /** * @brief Lazy Binary number calculation * @param[in] num The number to calculate binary of, i.e. 4 = 2^3 = 8 * @return 2^num */ //////////////////////////////////////////////////////////////////////////////// int bin_exp(int num) { return my_pow(2, num); } //////////////////////////////////////////////////////////////////////////////// /** * @brief Converts a integer to a string * @param[out] o_buff The correctly sized buffer to store the string in. * @param[in] num The number to convert to a string. * @param[in] len The size of the zero padded string to produce. * @return */ //////////////////////////////////////////////////////////////////////////////// void itozstring( char * o_buff, int num, int len ) { //////////////////// // Variables //////////////////// int pnum; /* the power number */ int fnum; /* the fake number */ int rnum; /* the real number */ int i=0; /* for loop navigation variable */ int pos = 0; /* o_buff navigation variable */ // i represents 10^i for ( i = len-1; i >= 0; i-- ) { pnum = my_pow(10, i); /* calculate 10^i (i.e. 10^4 = 1000) */ fnum = num/pnum; /* calculate magnitude of digit (i.e. 4) */ rnum = pnum * fnum; /* get specific digit (i.e. 1000 * 4) */ num -= rnum; /* subtract that digit from the full number */ o_buff[pos++] = fnum + '0'; /* convert the single digit int to a char */ } } //////////////////////////////////////////////////////////////////////////////// /** * @brief Converts 0 padded strings to an integer. * @param[in] i_buff The input buffer containing the string to decode. * @param[in] size The size of the input stirng. * @return The number as an integer. */ //////////////////////////////////////////////////////////////////////////////// int stonum( char * i_buff, int len ) { //////////////////// // Variables //////////////////// int i; /* navigation variable */ int sum = 0; /* sum to return */ int num; /* the single digit of the place */ int pnum = len - 1; /* the power number */ int multiplier; // convert to char at buff[i] and multiply by 10^(other end) for ( i = 0; i < len; i++ ) { multiplier = my_pow(10, pnum); pnum--; num = i_buff[i] - '0'; if ( num > 0 ) num = num * multiplier; sum += num; } return sum; } //////////////////////////////////////////////////////////////////////////////// /** * @brief Converts a string formatted as a double to an actual double. * @param[in] i_buff The string to convert. * @return The string result as a double. */ //////////////////////////////////////////////////////////////////////////////// double stodoub( char * i_buff ) { //////////////////// // Variable //////////////////// int size = strlen( i_buff ); /* determine the size of the string */ int ptr = 0; /* i_buff navigation variable */ double result = 0; /* the resulting double */ int i; /* power calculation variable */ // Read in the Integer while( ptr < size && i_buff[ptr] != '.' ) { ptr++; } result += stonum( i_buff, ptr ); ptr++; /* consume '.' */ i = 1; while( ptr < size ) { double pnum = (double) my_pow(10, i++); /* determine power */ double x = i_buff[ptr++] - '0'; /* char # to int (inc ptr) */ result += x / pnum; /* decimal digit (inc i) */ } return result; } //////////////////////////////////////////////////////////////////////////////// /** * @brief Converts a double to a zero padded string. * @param[out] o_buff The already allocated string to print the double into. * @param[in] num The double to print into the string. * @param[in] size The size of o_buff. * @return void */ //////////////////////////////////////////////////////////////////////////////// /* int dtos( char * o_buff, double num ) */ /* { */ /* //////////////////// */ /* // Variables */ /* //////////////////// */ /* int size; /\* the size of the double to be stored *\/ */ /* char t_buff[200]; /\* temp storage to determine sizeof double *\/ */ /* // determine size of conversion from double to string */ /* //size = sprintf( t_buff, "%099.99lf", num ); */ /* // malloc enough memory for the double as a string */ /* /\* o_buff = (char *) malloc (sizeof(char) * size) ; *\/ */ /* /\* if ( o_buff == NULL ) *\/ */ /* /\* fprintf (stderr, "layer.h: : Failed to malloc() o_buff ") ; *\/ */ /* return sprintf( o_buff, "%.99lf", num); */ /* } */ /* #endif /\* __UTILITY_H__ *\/ */ [/c] <h2>layer.h</h2> [c] #ifndef LAYER_H #define LAYER_H //////////////////////////////////////////////////////////////////////////////// /** * @file layer.h * @brief Global header file for all layers, containging all necessary * libraries and defining global preprocessor directives such as the chunk * size. * * Additionally preprocessor directives are used to limit the scope of testing * various layers. Set layer from 1-5 for testing and 0 for normal use. * * @title Peer-to-peer and Interface Protocols Using C * @author Nicholas Guthrie * @email guthrn@rpi.edu * @web http//nickguthrie.com * @created January 30, 2014 * */ /////////////////////////////////////////////////////////////////////////////// /** * * A chunk :: a sequence of bytes whose length is no greater than 16 bytes * - Each of the bytes in a chunk can have any value, including binary data and * the '\0' character; only restriction is there are no more than 16 bytes. * - Note that it is also valid to send/receive a chunk of size 0. * */ //////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------- :Global: // ___ _ _ _ // / __| |___| |__ __ _| | // | (_ | / _ \ '_ \/ _` | | // \___|_\___/_.__/\__,_|_| // // ----------------------------------------------------------------------------- #define MAX_CHUNK_SIZE 16 /* sets chunk for all layers as 16 bytes */ #define LAYER 0 /* 1-5 for testing. 0 for normal use */ //------------------------------------------------------------------ :Libraries: // _ _ _ _ // | | (_) |__ _ _ __ _ _ _(_)___ ___ // | |__| | '_ \ '_/ _` | '_| / -_|_-< // |____|_|_.__/_| \__,_|_| |_\___/__/ // // ----------------------------------------------------------------------------- #include <stdio.h> /* printf, fprintf, etc */ #include <unistd.h> /* need this for read(), write() */ #include <stdlib.h> /* needed for exit() */ #include <string.h> /* strlen, etc */ /* ------------------------------------------------------------------- :Student: * ___ _ _ _ * / __| |_ _ _ __| |___ _ _| |_ * \__ \ _| || / _` / -_) ' \ _| * |___/\__|\_,_\__,_\___|_||_\__| * * -------------------------------------------------------------------------- */ typedef struct { char * firstname; char * lastname; int rin; double gpa; } student; extern void print_title( int num, FILE * mode, char* title ); extern int my_pow(int x, int n); extern int bin_exp(int num); extern void itozstring( char * o_buff, int num, int len ); extern int stonum( char * i_buff, int len ); extern double stodoub( char * i_buff ); //////////////////////////////////////////////////////////////////////////////// extern int layer1_read( char * b ); extern int layer1_write( char b ); extern int layer2_write( char * chunk, int len ); extern int layer2_read( char * chunk, int max ); extern int layer3_write( char * msg, int len ); extern int layer3_read( char * msg, int max ); extern int layer4_write( char * msg, int len ); extern int layer4_read( char * msg, int max ); extern int layer5_write( student * stu ); extern int layer5_read( student * stu ); //--------------------------------------------------------------------- :Layers: // _ // | | __ _ _ _ ___ _ _ ___ // | |__/ _` | || / -_) '_(_-< // |____\__,_|\_, \___|_| /__/ // |__/ // ----------------------------------------------------------------------------- //////////////////// // Layer 1 //////////////////// #if ( LAYER >= 1 ) #include "layer1.c" #endif /* LAYER1 */ //////////////////// // Layer 2 //////////////////// #if ( LAYER >= 2 ) #include "layer2.c" #endif /* LAYER2 */ //////////////////// // Layer 3 //////////////////// #if ( LAYER >= 3 ) #include "layer3.c" #endif /* LAYER3 */ //////////////////// // Layer 4 //////////////////// #if ( LAYER >= 4 ) #include "layer4.c" #endif /* LAYER4 */ //////////////////// // Layer 5 //////////////////// #if ( LAYER >= 5 ) #include "layer5.c" #endif /* LAYER5 */ #endif /* LAYER_H */
#ifndef LAYER_1 #define LAYER_1 //////////////////////////////////////////////////////////////////////////////// /** * @file layer1.c * @brief Layer 1 maintains byte ordering such that the receiver receives the * first byte sent before receiving the second byte, etc. * * * Sample layer 1 implementation - this can be used to provide half-duplex * communication by using the shell to create a pipe between a sender process * and a receiver process. * * @title Peer-to-peer and Interface Protocols Using C * @author Nicholas Guthrie * @email guthrn@rpi.edu * @web http//nickguthrie.com * @created January 30, 2014 * * Compile with: gcc -c layer1.c -o ../build/layer1.o */ //////////////////////////////////////////////////////////////////////////////// /** * * A chunk :: a sequence of bytes whose length is no greater than 16 bytes * - Each of the bytes in a chunk can have any value, including binary data and * the '\0' character; only restriction is there are no more than 16 bytes. * - Note that it is also valid to send/receive a chunk of size 0. * */ //////////////////////////////////////////////////////////////////////////////// /** * TODO List * - Add check function that checks max length vs actual length (const) */ //////////////////////////////////////////////////////////////////////////////// /* ----------------------------------------------------------------- :Libraries: * _ _ _ _ * | | (_) |__ _ _ __ _ _ _(_)___ ___ * | |__| | '_ \ '_/ _` | '_| / -_|_-< * |____|_|_.__/_| \__,_|_| |_\___/__/ * * -------------------------------------------------------------------------- */ #include "layer.h" //----------------------------------------------------------------- :Prototypes: // ___ _ _ // | _ \_ _ ___| |_ ___| |_ _ _ _ __ ___ ___ // | _/ '_/ _ \ _/ _ \ _| || | '_ \/ -_|_-< // |_| |_| \___/\__\___/\__|\_, | .__/\___/__/ // |__/|_| // //----------------------------------------------------------------------------- int layer1_write(char b); int layer1_read( char * b ); /* -------------------------------------------------------------------- :Layer 1: * _ _ * | | __ _ _ _ ___ _ _ / | * | |__/ _` | || / -_) '_| | | * |____\__,_|\_, \___|_| |_| * |__/ * -------------------------------------------------------------------------- */ //////////////////////////////////////////////////////////////////////////////// /** * @brief Sample layer1_write just calls write to stdout. * @param[in] b * @return The number of bytes written: 1 if everything goes well. -1 if there * was an error. */ //////////////////////////////////////////////////////////////////////////////// int layer1_write( char b ) { if ( write( 1, &b, 1 ) != 1 ) { return -1; } else { return 1; } } //////////////////////////////////////////////////////////////////////////////// /** * @brief Sample layer1_read just calls read on stdin. * @param[in] b * @return The number of bytes read: 1 if everything goes well. -1 if there was * an error. */ //////////////////////////////////////////////////////////////////////////////// int layer1_read( char * b ) { if ( read( 0, b, 1 ) != 1 ) { return -1; } else { return 1; } } #endif /* LAYER_1 */ [/c] <h2>layer2.c</h2> [c] #ifndef LAYER2_H #define LAYER2_H //////////////////////////////////////////////////////////////////////////////// /** * @file layer2.c * @brief Layer 2 provides the transmission and receipt of a chunk of data. * * DETAILED DESCRIPTION * * @title Peer-to-peer and Interface Protocols Using C * @author Nicholas Guthrie * @email guthrn@rpi.edu * @web http//nickguthrie.com * @created January 30, 2014 * * Compile with: gcc -c layer4.c -o ../build/layer4.o * */ //////////////////////////////////////////////////////////////////////////////// /* ----------------------------------------------------------------- :Libraries: * _ _ _ _ * | | (_) |__ _ _ __ _ _ _(_)___ ___ * | |__| | '_ \ '_/ _` | '_| / -_|_-< * |____|_|_.__/_| \__,_|_| |_\___/__/ * * -------------------------------------------------------------------------- */ #include "layer.h" /*--------------------------------------------------------------------- :Global: * ___ _ _ _ * / __| |___| |__ __ _| | * | (_ | / _ \ '_ \/ _` | | * \___|_\___/_.__/\__,_|_| * * -------------------------------------------------------------------------- */ #define SCHKSZE 2 /* small check size */ // -------------------------------------------------------------------- :Layer 2: // _ ___ // | | __ _ _ _ ___ _ _ |_ ) // | |__/ _` | || / -_) '_| / / // |____\__,_|\_, \___|_| /___| // |__/ // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /** * @brief Sends a chunk that consists of the sequence of bytes starting at the * address specified by the first parameter (chunk) with length len. * @warning all errors that can be detected here must be handled here including * valid values of len and the return value of layer1_write() * @param[in] chunk The data to write using layer 1 protocols. * @param[in] len The size of the chunk to write. * @return len on success, -1 on error */ //////////////////////////////////////////////////////////////////////////////// int layer2_write( char * chunk, int len ) { //////////////////// // Variables //////////////////// int i; /* navigation variable */ char size_buffer[SCHKSZE]; /* used to send chunk size to layer2_read */ // return error if length is greater than max chunk size if ( len > MAX_CHUNK_SIZE ) { return -1; } // send size of chunk to be sent itozstring( size_buffer, len, SCHKSZE ); //unable to use globals with sprintf for ( i = 0; i < SCHKSZE; i++ ) { layer1_write( size_buffer[i] ); } // write chunk using layer 1 for each char while checking errors for ( i = 0; i < len; i++ ) { if( layer1_write( chunk[i] ) == -1 ) { return -1; } } return len; } //////////////////////////////////////////////////////////////////////////////// /** * @brief Reads a chunk and stores the incoming bytes in the buffer starting at * the address specified by the first parameter (chunk). * * @warning Make sure that your layer2_read() does not allow the sender to * overflow the buffer! And it's not enough to recognize when this has * happened and return an error; you must not store anything beyond * the max location of chunk. * @param[in] chunk A sequence of bytes whose length is no greater than 16 * bytes as defined by MAX_CHUNK_SIZE which can contain any type of * data. * @param[in] max No more than max bytes will be put into chunk, so max limits * the size of the chunk read. * @return Upon successfully receiving a chunk, the size of the chunk in bytes * is returned. */ //////////////////////////////////////////////////////////////////////////////// int layer2_read( char * chunk, int max ) { //////////////////// // Variables //////////////////// int msg_size = 0; /* stores the size of the message */ int i; /* counter variable for for loops */ char c; /* used for reading characters from layer 1 */ char size_buffer[SCHKSZE]; /* used for storing size of string */ // receive the size of msg and convert to int for (i = 0; i < SCHKSZE; i++) { if ( layer1_read( &c ) == -1 ) { return -1; } size_buffer[i] = c; } msg_size = stonum( size_buffer, SCHKSZE ); /* * Error Checking - confirm chunk !> than allocated memory or MAX_CHUNK_SIZE * - IF a chunk is received by layer2_read() that would require more than * max bytes, layer2_read() returns -1 (error). */ if ( msg_size > max ) { fprintf(stderr, "LAYER 2 ERROR - Message Size of %d is too big\n", msg_size); return -1; } // read in data using layer 1 for ( i = 0; i < msg_size; i++ ) { if( layer1_read( &c ) == -1 ) { return -1; } chunk[i] = c; } return msg_size; } #endif /* LAYER2_H */ [/c] <h2>layer3.c</h2> [c] #ifndef LAYER3_H #define LAYER3_H //////////////////////////////////////////////////////////////////////////////// /** * @file layer3.c * @brief Layer 3 provides the capability to send and receive messages, where a * message is defined as any sequence of bytes. * * More specifically, there is no length limitation at layer 3, so a sender can * ask layer 3 to send any size message. * * @title Peer-to-peer and Interface Protocols Using C * @author Nicholas Guthrie * @email guthrn@rpi.edu * @web http//nickguthrie.com * @created January 30, 2014 * * Compile with: gcc -c layer3.c -o ../build/layer3.o */ //////////////////////////////////////////////////////////////////////////////// /* ----------------------------------------------------------------- :Libraries: * _ _ _ _ * | | (_) |__ _ _ __ _ _ _(_)___ ___ * | |__| | '_ \ '_/ _` | '_| / -_|_-< * |____|_|_.__/_| \__,_|_| |_\___/__/ * * -------------------------------------------------------------------------- */ #include "layer.h" /* -------------------------------------------------------------------- :Layer 3: * _ ____ * | | __ _ _ _ ___ _ _ |__ / * | |__/ _` | || / -_) '_| |_ \ * |____\__,_|\_, \___|_| |___/ * |__/ * -------------------------------------------------------------------------- */ //////////////////////////////////////////////////////////////////////////////// /** * @brief Sends a message. * @param[in] msg A message of any length to send. * @param[in] len The size of the message to send. * @return The number of bytes (of the message) sent on success (should be len) * or -1 on error. */ //////////////////////////////////////////////////////////////////////////////// int layer3_write( char * msg, int len ) { //////////////////// // Variables //////////////////// int counter = 0; /* keeps track of bytes sent */ // write message to layer 2 // should never write an empty message in this loop, since len would be 0 while( len > 0 ) { // when remaing msg is greater than chunk, just send whats left if( len < MAX_CHUNK_SIZE ) { if( layer2_write( &msg[counter], len) == -1 ) { return -1; } counter += len; len = 0; } else { // when the remaing msg is less than chunk, send a full chunk if( layer2_write( &msg[counter], MAX_CHUNK_SIZE ) == -1 ) { return -1; } counter += MAX_CHUNK_SIZE; len -= MAX_CHUNK_SIZE; } } // always write an empty message to signify end char foo; layer2_write(&foo, 0); return counter; } //////////////////////////////////////////////////////////////////////////////// /** * @brief reads a message and stores it in memory starting at the address * specified by msg * @param[in] msg Where the message that is read is stored. * @param[in] max No more than max bytes will be put into memory, so max must * limit the size of the message read. * @return The size of the message received or -1 on error. * * If a message is received by layer3_read() that would require more than max * bytes, layer3_read() must return -1 (indicating an error). */ //////////////////////////////////////////////////////////////////////////////// int layer3_read( char * msg, int max ) { //////////////////// // Variables //////////////////// int counter = 0; /* keeps track of position in msg */ char t_buff[MAX_CHUNK_SIZE]; /* a temporary buffer to prevent mem overlow */ int chars_read = 0; /* chars read from a single layer 2 read */ int total_chars_read = 0; /* total characters read using layer 2 */ int i; /* for loop navigation variable */ do { chars_read = 0; /* reset counter */ // read the next chunk of characters into temporary chunk chars_read = layer2_read( t_buff, MAX_CHUNK_SIZE ); if( chars_read == -1 ) { fprintf(stderr, "LAYER 3 ERROR: layer2_read Failed.\n"); return -1; } total_chars_read += chars_read; // check to make sure there is no character overflow if( total_chars_read > max ) { fprintf( stderr, "LAYER 3 ERROR: memory allocation exceded\n" ); return -1; } // store the temp buffer characters in the real buffer for ( i = 0; i < chars_read; i++ ) { msg[counter++] = t_buff[i]; } } while( chars_read > 0 ); return total_chars_read; } #endif /* LAYER3_H */
#ifndef LAYER4_H #define LAYER4_H //////////////////////////////////////////////////////////////////////////////// /** * @file layer4.c * @brief Layer 4 adds simple error detection to layer 4 services * * The errors to look for here involve transmission errors; we want to somehow * make sure that the message received is the same as the message that was * sent. The simplest approach to error detection is to use a checksum. The * checksum is the sum % 65536. The resulting two-byte checksum should be * sent along with the message data; the receiving end goes through the same * steps to compute the checksum, then compares the received checksum to the * computed checksum. * * @title Peer-to-peer and Interface Protocols Using C * @author Nicholas Guthrie * @email guthrn@rpi.edu * @web http//nickguthrie.com * @created January 30, 2014 * * Compile with: gcc -c layer4.c -o ../build/layer4.o */ //////////////////////////////////////////////////////////////////////////////// #include "layer.h" //////////////////////////////////////////////////////////////////////////////// /* -------------------------------------------------------------------- :Global: * ___ _ _ _ * / __| |___| |__ __ _| | * | (_ | / _ \ '_ \/ _` | | * \___|_\___/_.__/\__,_|_| * * -------------------------------------------------------------------------- */ #define CHKFRSZ 4 /* -------------------------------------------------------------------- :Layer 4: * _ _ _ * | | __ _ _ _ ___ _ _ | | | * | |__/ _` | || / -_) '_| |_ _| * |____\__,_|\_, \___|_| |_| * |__/ * -------------------------------------------------------------------------- */ //////////////////////////////////////////////////////////////////////////////// /** * @brief Computes a checksum of the message and sends it to layer4_read. * @param[in] msg The message to send. * @param[in] len The length of the message. * @return The number of Bytes sent. */ //////////////////////////////////////////////////////////////////////////////// int layer4_write( char * msg, int len ) { //////////////////// // Variables //////////////////// int checksum = 0; /* checksum to calculate and send */ char chksum_buff[CHKFRSZ]; /* store checksum as string */ int i = 0; /* navigator variable */ // Compute Checksum for (i = 0; i < len; i++) { checksum += msg[i]; } checksum = checksum % 65536; itozstring( chksum_buff, checksum, CHKFRSZ ); /* convert int to string */ /* sprintf(size_buffer, "%04d", checksum); */ // Write checksum to layer 3 and check for errors if( layer3_write( chksum_buff, CHKFRSZ ) == -1 ) { return -1; } // Send Message if( layer3_write( msg, len ) == -1 ) { return -1; } // Return the number of bytes sent on success return len; } //////////////////////////////////////////////////////////////////////////////// /** * @brief Reads a message into memory starting at the address specified by msg. * @param[in] msg No more than max bytes will be put into memory, so max must * limit the size of the message read. * @param[in] max The maximum size of the message. * @return -1 if max size is incorrect or if there is a transmission error. * The size of the message in bytes is returned otherwise. */ //////////////////////////////////////////////////////////////////////////////// int layer4_read( char * msg, int max ) { //////////////////// // Variables //////////////////// int sent_chksum = 0; /* checksum recieved */ int calc_chksum = 0; /* checksum calculated */ char chksum_buff[CHKFRSZ]; /* store checksum as string */ int msg_size = 0; /* the size of the message recieved */ int i = 0; /* for loop navigation variable */ // Read in the Checksum if( layer3_read( chksum_buff, CHKFRSZ ) == -1 ) { fprintf( stderr, "LAYER 4 ERROR: layer3_read Failed.\n" ); return -1; } sent_chksum = stonum( chksum_buff, CHKFRSZ ); // Read in Input and Check for Errors /* If a message is received by layer4_read() that would require more than * bytes, layer4_read() must return -1 (error). */ if( (msg_size = layer3_read( msg, max )) == -1 ) { fprintf( stderr, "LAYER 4 ERROR: layer3_read Failed.\n" ); return -1; } // Check Checksum /* If your error-detection mechanism detects transmission error(s), * layer4_read() must return a -1. */ calc_chksum = 0; for ( i = 0; i < msg_size; i++ ) { calc_chksum += (int) msg[i]; } // Compare Calcualted Checksum to Sent Checksum if( (calc_chksum % 65536) != sent_chksum ) { fprintf( stderr, "LAYER 4 ERROR: checksum match failed .\n" ); return -1; } return msg_size; } #endif /* LAYER4_H */ [/c] <h2>layer5.c</h2> [c] #ifndef LAYER5_H #define LAYER5_H //////////////////////////////////////////////////////////////////////////////// /** * @file layer5.c * @brief Layer 5 provides higher application layers with a mechanism for * sending and receiving a simple C struct. * * The sending function (i.e. layer5_write()) is given the address of the * struct to be sent, and the corresponding call to layer5_read() in the peer * will dynamically create an identical struct. Both peer processes have the * definition of the struct ahead of time (compiled in), and the functions are * written with this knowledge. Note that some languages (e.g. Java) have a * mechanism to ensure the structures on each side match up (i.e. are the same * "version" of code); we'll explore this in the future. * * @title Peer-to-peer and Interface Protocols Using C - Layer 5 * @author Nicholas Guthrie * @email guthrn@rpi.edu * @web http//nickguthrie.com * @created January 30, 2014 * * Compile with: gcc -c layer5.c -o ../build/layer5.o */ //////////////////////////////////////////////////////////////////////////////// /* ----------------------------------------------------------------- :Libraries: * _ _ _ _ * | | (_) |__ _ _ __ _ _ _(_)___ ___ * | |__| | '_ \ '_/ _` | '_| / -_|_-< * |____|_|_.__/_| \__,_|_| |_\___/__/ * * -------------------------------------------------------------------------- */ #include "layer.h" /* -------------------------------------------------------------------- :Global: * ___ _ _ _ * / __| |___| |__ __ _| | * | (_ | / _ \ '_ \/ _` | | * \___|_\___/_.__/\__,_|_| * * -------------------------------------------------------------------------- */ #define TSIZE 2 #define RINSIZE 15 /* Bytes stored in RIN */ /* -------------------------------------------------------------------- :Layer 5: * _ ___ * | | __ _ _ _ ___ _ _ | __| * | |__/ _` | || / -_) '_| |__ \ * |____\__,_|\_, \___|_| |___/ * |__/ * -------------------------------------------------------------------------- */ //////////////////////////////////////////////////////////////////////////////// /* * @brief The layer5_read() function must use layer4_read() to read a student * and put the received field values (firstname, lastname, rin, and gpa) * into the student pointed to by stu. * @warning You may assume that stu points to memory that has been allocated * and is large enough to store the two pointers, the int, and the * double. * @param[in] stu The student struct to write. * @return The return value is 1 on success, or -1 on error. */ //////////////////////////////////////////////////////////////////////////////// int layer5_write( student * stu ) { //////////////////// // Variables //////////////////// //@TODO Sloppy to use 200 as size char output[200]; /* huge buffer to store struct stream inpu */ int name_size; /* size of first or last name */ int o_ptr = 0; /* write location in output buff */ // First Name name_size = (int)strlen( stu->firstname ); // first name size error handling if( name_size > 81 ) { fprintf( stderr, "LAYER 5 ERROR: First Name exceeds 80 characters.\n"); return -1; } itozstring( output, name_size, TSIZE ); o_ptr += 2; o_ptr += sprintf( &output[o_ptr], "%s", stu->firstname ); // Last Name name_size = (int)strlen( stu->lastname ); // last name size error handling if( name_size > 81 ) { fprintf( stderr, "LAYER 5 ERROR: Last Name exceeds 80 characters.\n" ); return -1; } itozstring( &output[o_ptr], name_size, TSIZE ); o_ptr += 2; o_ptr += sprintf( &output[o_ptr], "%s", stu->lastname ); // RIN itozstring( &output[o_ptr], stu->rin, RINSIZE ); o_ptr += RINSIZE; // GPA o_ptr += sprintf( &output[o_ptr], "%016lf", stu->gpa ); // Send Output through layer 4 layer4_write( output, o_ptr ); return 1; } //////////////////////////////////////////////////////////////////////////////// /** * @brief Dynamically allocate memory of the appropriate size for the firstname * and lastname fields. * @warning It is the responsibility of the caller to free this memory. * @param[out] stu The student struct to read onto. * @return The return value is 1 on success, or -1 on error. */ //////////////////////////////////////////////////////////////////////////////// int layer5_read( student * stu ) { //////////////////// // Variables //////////////////// int name_size; char input[1000]; int i_ptr = 0; int i; // Read in layer 4 if( layer4_read(input, 1000 ) == -1 ) { return -1; } //////////////////////////////////////// // Store Data in Student //////////////////////////////////////// // First Name name_size = stonum( input, 2 ); stu->firstname = (char *) malloc ( sizeof(char) * name_size ) ; // allocate memory for first name if ( stu->firstname == NULL ) fprintf ( stderr, "layer5.c: : Failed to malloc() stu->firstname " ) ; i_ptr += 2; /* incrament to consume size string */ // store the first name from input into actual structure for ( i = 0; i < name_size; i++ ) { stu->firstname[i] = input[i_ptr++]; } stu->firstname[i] = '\0'; /* make sure the string is null terminated */ // Last Name name_size = stonum( &input[i_ptr], 2 ); stu->lastname = (char *) malloc ( sizeof(char) * name_size ) ; if ( stu->lastname == NULL ) fprintf ( stderr, "layer5.c: : Failed to malloc() stu->lastname " ) ; i_ptr += 2; /* incrament to consume size string */ // store the last name from input into actual structure for ( i = 0; i < name_size; i++ ) { stu->lastname[i] = input[i_ptr++]; } stu->lastname[i] = '\0'; /* make sure the string is null terminated */ // RIN stu->rin = stonum( &input[i_ptr], RINSIZE ); i_ptr += RINSIZE; // GPA stu->gpa = stodoub( &input[i_ptr] ); return 1; } #endif /* LAYER5_H */