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 */