// CS-401 Networks and Beyond // Project 2 Test Program // // Created 1/28/03, Thomas C. Bressoud // Revised 9/12/06 for Networks and Beyond course // // This code can be used to test your layer 4 implementation // (which in turn can/should be used to test your layer 3, etc.) // // Also included is a simple implementation of layer 1 that can get // you going. #include #include #define MAXNAME 100 #define MAXVALUE 100 #define MAXNAMEP1 (MAXNAME + 1) #define MAXVALUEP1 (MAXNAME + 1) //------------------------------------------------------------------------- // Layer 4 Function prototypes //------------------------------------------------------------------------- extern int l4_write(char *, int, char *, int); extern int l4_read(char *, int *, char *, int *); //------------------------------------------------------------------------- //------------------------------------------------------------------------- // Layer 1: Sample inplementation. 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. //------------------------------------------------------------------------- // Function: l1_read // Simply reads a single character on stdin int l1_read(char * b) { return(read(STDIN_FILENO, b, 1)); } //------------------------------------------------------------------------- // Function: l1_write // Write the given character to stdout int l1_write(char b) { return(write(STDOUT_FILENO, &b, 1)); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // Main program. This program can be either a sender or a receiver. The // command line arguments are used to determine which, with the sender // processing arguments for the values of a username and password. // With the given layer 1 fucntions operating over stdin/stdout, we can // connect a sender and receiver by having the shell set up a pipe between // them, as follows (assuming the generated executable is named proj2: // // ./proj2 | ./proj2 //------------------------------------------------------------------------- int main(int argc, char ** argv) { char namebuf[MAXNAMEP1]; // Receiver's buffer for name of name/value pair char valuebuf[MAXVALUEP1]; // Recevier's buffer for value of name/value pair int namelen; // Storage for length of name int valuelen; // Storage for lenght of value // If there are 2 command line arguments, then this program will send the // first (argv[1]) as the username, and the second (argv[2]) as the // password, using l4_write to send the name/value pair. // If there are not 2 command line arguments, the program assumes it should // be the receiver, and so it will call l4_read to receive the name/value // pair. // We begin with the sender: if (argc == 3) { // I am the sender, so I need to use the command line arguments as the // values for the username and the password. // Check argument length and send username if (strlen(argv[1]) > 100) { // Check validity of first argument fprintf(stderr, "Error -- username is too long\n"); exit(1); } // Argument length is ok, so send it. if (l4_write("username", strlen("username") + 1, argv[1], strlen(argv[1]) + 1) == -1) { fprintf(stderr, "l4_write error sending username\n"); exit(1); } // Check argument length and send password if (strlen(argv[2]) > 100) { // Check validity of second argument fprintf(stderr, "Error -- password is too long\n"); exit(1); } // Argument length is ok, so send it. if (l4_write("password", strlen("password") + 1, argv[2], strlen(argv[2]) + 1) == -1) { fprintf(stderr, "l4_write error sending password\n"); exit(1); } } else if (argc == 1) { // No arguments indicates the receiver // Set up to read the two name/value pairs // start by setting up our in/out length parameters to the maximum size // we are willing to tolerate. namelen = MAXNAME; valuelen = MAXVALUE; // Use our layer 4 interface to read the first name/value pair if (l4_read(namebuf, &namelen, valuebuf, &valuelen) == -1) { fprintf(stderr, "l4_read error on first name/value pair read\n"); exit(1); } // we expect C strings, with appropriate null termination, but we make // sure that each is null terminated. (A malicious peer could be trying // to mess us up.) namebuf[namelen] = '\0'; valuebuf[valuelen] = '\0'; // verify that the application-level protocol expectation of the first // name/value pair to be the username is well-founded. if (strcmp(namebuf, "username") != 0) { fprintf(stderr,"Error -- first name/value pair was not \"username\"\n"); exit(1); } // We got something named "username", so print it out printf("Received username: %s\n", valuebuf); // Use our layer 4 interface to read the second name/value pair namelen = MAXNAME; // reinitialize our in/out parameters valuelen = MAXVALUE; if (l4_read(namebuf, &namelen, valuebuf, &valuelen) == -1) { fprintf(stderr, "l4_read error on second name/value pair read\n"); exit(1); } // Ensure null termination namebuf[namelen] = '\0'; valuebuf[valuelen] = '\0'; // verify that the application-level protocol expectation of the second // name/value pair to be the password is well-founded. if (strcmp(namebuf, "password") != 0) { fprintf(stderr,"Error -- first name/value pair was not \"password\"\n"); exit(1); } // We got something named "password", so print it out printf("Received password: %s\n", valuebuf); } else { // Usage error when argc is neither 1 nor 3 fprintf(stderr, "Receiver usage: %s\n", argv[0]); fprintf(stderr, "Sender usage: %s \n",argv[0]); exit(1); } return 0; } // end of main