----------------------- Lab #05 for CST8165 due March 5, 2007 (Week 9) ----------------------- -Ian! D. Allen - idallen@idallen.ca - www.idallen.com Remember - knowing how to find out an answer is more important than memorizing the answer. Learn to fish! RTFM! (Read The Fine Manual) Global weight: 6% of your total mark this term. Due date: before 10h00 AM Monday March 5 (Week 9) The deliverables for this exercise are to be submitted on-line in the Linux Lab T127 using the "cstsubmit" method described in the exercise description, below. No paper; no email; no FTP. Late-submission date: I will accept without penalty exercises that are submitted late but before 12h00 (noon) on Tuesday, March 6. After that late-submission date, the exercise is worth zero marks. Exercises submitted by the *due date* will be marked on-line and your marks will be sent to you by email after the late-submission date. Exercise Synopsis: Modify an existing multi-client server to include private messages. Test it. For full marks, this submission depends on a working selectserver.c submission from the previous lab that passes all its tests, though part marks can be given for starting with an unmodified or partially modified selectserver.c. Where to work: Submissions must make, compile, and run cleanly in the T127 Linux Lab, though you are free to work on them anywhere you like. Recall that most any program or C function has a Unix/Linux manual page: RTFM Code submitted without your added useful comments will not be marked. Code Quality and Portability ---------------------------- See previous labs. Adding private messages ----------------------- For full marks, this lab starts with the completed and tested chat server from last lab. For part marks, you may start with the partially modified or unmodified chat server from the previous lab. 1) Modify your chat server to detect "command" words that start with a forward slash at the start of a line, e.g. "/msg". Any line received from a client that starts with a forward slash is a command line that will *not* be sent to all clients. Any unrecognized commands should be sent back to the originating client as distinctive error messages about "unknown command". 2) Modify the chat server to detect an incoming client line that starts with the four characters "/msg" followed by blanks or tabs, a dotted-quad address, more blanks or tabs, and message ending in a newline, e.g.: /msg 1.2.3.4 this is a message to 1.2.3.4 only\n Have the server send the text part of the message only to matching client IPs (more than one may match), together with some text indicating that this is a private message from the client. (RTFM "man inet_aton" to convert an ascii dotted quad to binary) If the incoming line from the client has no newline on the end (the line doesn't fit in your internal buffer, or not all data was read), process it anyway. The client message text starts *after* the *first* blank or tab after the dotted-quad - do not strip off any other leading blanks on the client message line when you pass it on. Leave the other leading blanks on the text message untouched. Only remove one. The keyword "/msg" may be written as upper-case, lower-case, or mixed-case and must start at the beginning of the line. Any non-zero number of blanks or tabs may separate the arguments: "Be liberal in what you accept." You will have to have room to add a trailing NUL ('\0') byte to the end of the message if you use many of the functions listed in the Hints below. (I do recommend using strspn() and strcspn() to locate your arguments in the /msg line.) Hints: RTFM "man strncasecmp" "man tolower", "man strspn", "man strcspn", "man strpbrk", "man memchr", "man strtok", "man strsep" but read the BUGS sections, and make sure your buffer is NUL ('\0') terminated if you use some of these string functions! 3) If the server detects that the /msg keyword is not followed by a recognized dotted-quad for any known client, send a good error message back to the client indicating that no message was delivered. The error message should look somewhat distinctive, so as not to confuse it with regular chat lines. 4) Do you allow a /msg to be sent to yourself? Why or why not? In a plain text file "README.txt", document the syntax and rules for using your version of the /msg command. Document what is allowed and what errors are possible in the README.txt file. 5) Do "/msg 1.2.3.4 hi" and "/msg 01.002.0003.00004 hi" both work? Why or why not? (See the man page for inet_aton to see how it converts dotted quads to binary!) Document your choices in the "README.txt" documentation file. 6) Does a syntactically invalid IP address give the same error message as a valid but unrecognized address? Document your choice in the README.txt file. Documentation ------------- 7) Review the "Code Quality and Portability" items at the start of this assignment. 8) Add file headers, function headers and block comments to the code (all of it, even the parts you did not write!). Remove useless comments, e.g. "// listen", "// bind", etc. Document the purpose of all variables when they are declared. Include a small "how to use this program" at the top of any file containing a main(). 9) Document the code. Did you bring all source files up to programming and comment standards, even the code you did not write yourself? Are comments relevant? Is indentation consistent ("indent -kr -i8")? Code submitted without your added useful comments will not be marked. Reference: Notes file programming_style.txt 10) Note: I haven't asked for any separate User Manual for using the chat server program. Include brief syntax/usage information (how to run this program) in the comments at the top of the source file. Official Testing ---------------- These are the official tests for handing in. Make sure your script sessions contain *only* the required commands below and their output - do not flood the script session with VIM sessions or other unneccessary interactions. Remember that you can throw away unwanted DEBUG output by shell redirection of standard output and/or standard error to /dev/null. The "script" command has an option to append to a script file, if you want to run the testing below in separate sections. When you are done, you will have four script sessions to hand in (see below): A. testing.txt: for the Makefile and server status and DEBUG messages B. localhost.txt: for a connection from the local host (first machine) C. test1.txt: for a connection from a second different machine D. test2.txt: for a connection from a third different machine NOTE: You cannot cut and paste more than one line at a time into a standard netcat client, since netcat will bundle up multiple lines and send them all in one packet to your chat server. Your chat server will read() data that contains more than one line, and it isn't yet designed to handle that properly, so the multiple lines will all incorrectly appear to be part of the first message line. We will fix that later. You can tell netcat to separate sending individual lines by one second by adding the "-i 1" option to the netcat command line. This seems to allow your chat server to see each line as a separate read() statement. 11) (A) Start a "script" session with output file "testing.txt". $ script testing.txt 12) (A) "testing.txt": Test the Makefile. Run a full clean and recompile test: $ make clean $ make clean # second time should not produce any errors $ make selectserver $ make selectserver # second time should say everything is up to date Use the exact four tests above, in the above order. Make sure you rebuild with all these required CFLAGS: CFLAGS = -g -O -Wall -Wextra -Wshadow -Wstrict-prototypes \ -Wmissing-prototypes -Wmissing-declarations \ -Wdeclaration-after-statement \ -Wmissing-field-initializers -Wredundant-decls -Wunreachable-code 13) (A) "testing.txt": Start your server in the foreground (not background): $ ./selectserver 55555 Note: If your server produces many hundreds of lines of debugging output, you must turn that off (or redirect server output to /dev/null) before running this test, so that you don't flood the script session with hundreds of lines of unnecessary DEBUG output. A few lines of DEBUG output are expected as clients connect and disconnect. 14) (B) "localhost.txt": Open a new shell window and start a new "script" session with output file "localhost.txt". Run netcat to your server: $ script localhost.txt $ nc -i 1 -v localhost 55555 This is your (B) first client connection. Use it to check the parsing of your /msg string by trying (at least) these few invalid tests: / /m /ms /msg /msgx /msg foo /msg 127.0.0.foo /msg 127.0.0.1foo /msg 127.0.0.1 /msgx 127.0.0.1 None of the above are valid commands - all should generate error messages on the server that get sent back to the screen of this client. 15) (C) "test1.txt": Open a new shell window and start a new "script" session with output file "test1.txt". Login to a (second) different machine in the Linux lab. Run netcat to your server (replace XX and YY by the right numbers): $ script test1.txt $ ssh wt127-YY $ nc -i 1 -v wt127-XX 55555 This is your (C) second client connection. 16) (D) "test2.txt": Open a new shell window and start a new "script" session with output file "test2.txt". Login to a (third) different machine in the Linux lab. Run netcat to your server (replace XX and ZZ by the right number): $ script test2.txt $ ssh wt127-ZZ $ nc -i 1 -v wt127-XX 55555 This is your (D) third client connection. 17) At this point verify that you have four script sessions going. (A) is the server, the rest B, C, D, are clients. A. testing.txt: for the server status and DEBUG messages B. localhost.txt: for a connection from the local host (first machine) C. test1.txt: for a connection from a second different machine D. test2.txt: for a connection from a third different machine 18) Into netcat on the (B) localhost.txt machine, type these three lines: this line comes from the (B) localhost test client /msg X.X.X.X private from the (B) localhost test client to (C) /msg Y.Y.Y.Y private from the (B) localhost test client to (D) - where X.X.X.X is the IP address of your (C) client. - where Y.Y.Y.Y is the IP address of your (D) client. Spelling counts - I will be looking for these exact three lines. 19) Into netcat on the (C) test1.txt machine, type these three lines: this line comes from the (C) test1 test client /msg Z.Z.Z.Z private from the (C) test1 test client to (B) /msg Y.Y.Y.Y private from the (C) test1 test client to (D) - where Z.Z.Z.Z is the IP address of your (B) client. - where Y.Y.Y.Y is the IP address of your (D) client. Spelling counts - I will be looking for these exact three lines. 20) Into netcat on the (D) test1.txt machine, type these three lines: this line comes from the (D) test2 test client /msg X.X.X.X private from the (D) test2 test client to (C) /msg Z.Z.Z.Z private from the (D) test2 test client to (B) - where X.X.X.X is the IP address of your (C) client. - where Z.Z.Z.Z is the IP address of your (B) client. Spelling counts - I will be looking for these exact three lines. 21) Now interrupt (ctrl-C) the netcat processes on (B) localhost.txt and (C) test1.txt, in that order. Restart them in the reverse order. (Start the netcat on (C) test1.txt first, then do the one on (B) localhost.txt second.) 22) Repeat the typing in steps 18, 19, 20. Spelling counts - I will be looking for the exact 3x3 lines. 23) Interrupt (ctrl-C) the netcat process on (D) test2.txt and (C) test1.txt, in that order. Restart them: Start the netcat on (D) test2.txt first, then do the one on (C) test1.txt. 24) Repeat the typing in steps 18, 19, 20. Spelling counts - I will be looking for the exact 3x3 lines. 25) Interrupt (ctrl-C) all the netcat processess in the order (B), (C), (D). Restart them in the order (D), (C), (B). 26) Repeat the typing in steps 18, 19, 20. Spelling counts - I will be looking for the exact 3x3 lines. 27) Interrupt (ctrl-C) your chat server in session (A). All your netcat processes (B), (C), (D) should exit. Exit from your two remote login sessions. Exit all four script sessions, creating four non-empty script files: A. testing.txt: for the server status and DEBUG messages B. localhost.txt: for a connection from the local host (first machine) C. test1.txt: for a connection from a second different machine D. test2.txt: for a connection from a third different machine 28) In a file named "README.txt", summarize briefly the results of doing each of the points in this assignment. For each of the 28 points in this assignment, state whether you succeeded or failed that step. Follow the README.txt format of the previous labs. 29) In the README.txt file, under a heading: Feedback to instructor: Tell me how easy/difficult this assignment was. How long did it take to complete? 30) Add assignment headers to the top of all your files and submit the files (see below). Add a header to *every* file you submit. Verify that your script files contain *only* the above commands. No VIM sessions. Not hundreds of lines of DEBUG output. Submission ---------- Note: The Assignment Label is not a substitute for a proper program file header giving the purpose of this program code. Add a proper file header to all program source code submitted. A. At the top of each and every submitted file, as comments, create an Exterior Assignment Submission label following the directions from last week's lab. Add this header to *every* file you submit. B. For material you copy from other sources, credit the author and source, following the directions from last week's lab. C. Submit these text files for marking as Exercise 05 using the following exact and *single* cstsubmit command line: $ ~alleni/bin/cstsubmit 05 Makefile README.txt \ testing.txt localhost.txt test1.txt test2.txt \ selectserver.c myerror.c myerror.h sendall.c sendall.h See last week's lab for details on using cstsubmit. All file names must be spelled *exactly* as given above. Incorrect submissions are worth zero marks. If you use any automated test scripts, you may submit those on the same command line. (You can safely submit extra files, as long as you always submit the required files at the same time.) P.S. Did you spell all the assignment label fields and file names correctly?