TCP/IP | Assignment 1 | Due acc. to syllabus ------------------------------------------------ The first assignment is to implement a reliable protocol on top of the TCP/IP UDP (User Datagram Protocol). The reliable protocol will be called "RUP" for Reliable UDP Protocol. RUP must implement a packet oriented protocol that is totally reliable on top of UDP. The problem with UDP is that packet arrival can suffer from the following flaws: 1. lost; never delivered 2. partially destroyed (data corruption) 3. delivered out of order 4. duplicated. RUP must prevent an application from suffering any of the above flaws. A complete assignment must consist of three parts: 1. a sample client/server application as two UNIX processes. 2. a RUP "driver" library. 3. a low-level packet testbed that can simulate possible layer2-layer4 errors; e.g., 1. random loss of packets, 2. random duplication of packets, 3. random damage to the packet's integrity (bit rot). The application level ---------------------------------------------------------- The client and server must be coded to use the RUP library. The client should have the following parameters: % rupclient hostname serverport nopackets packetsize hostname - remote name of host (/etc/hosts) serverport - remote UDP port number for server nopackets - number of packets of packetsize to send packetsize - the size of the packets to send. The max. packet size should be 8k. The server should have the following parameters: %rupserver portnumber The server will simply read every packet written to it and write it back (echo it) to the client it received it from. Each client that runs should do the following 1. checksum a packet 2. write it to the server 3. read it back 4. checksum the results and make sure they match. Report an error if an error occurs. This is APPLICATION level error checking. ---------------------------------------- The rup layer must also have a checksum, and the checksum in the rup layer should be the ip checksum as used in the IPv4 header, UDP and TCP headers. The server should only terminate upon receiving a SIGHUP or SIGINT signal. The RUP library --------------- A "driver" or library module should be coded that has the following application entry-points: 1. int rfd = rup_open() This call should return a RUP descriptor object that will be used by all other RUP i/f calls. A return value of -1, will mean that a fatal error has been found. 2. int rc = rup_bind(int rfd, int portno) An integer port number is passed to the RUP protocol. It is only used by a server that desires to establish a "well-known" port. If rc < 0, an error has occured. 3. char *rup_error(int rfd) If any RUP call returns -1, this routine should be called to return an error string. 4. void rup_close(int rfd) close a RUP handle. 5. int rc = rup_write(int rfd, char *buf, int cc, sockaddr_in *to) rfd - a rfd returned by rup_open() buf - a buffer of data cc - the byte count / size of buf to - a socket address structure that contains the remote ip/port number of the machine, UDP port to write the data. write data to remote ip, port. rc - returns the amount of data written, -1 if error. 6. int rc = rup_read(int rfd, char *buf, int cc, sockaddr_in *from) rfd - a rfd returned by rup_open buf - a buffer of data cc - the byte count / size of buf from - a socket address structure that contains the remote ip/port number of the machine, UDP port that wrote the data. read data from remote ip, port. 7. int rc = rup_layer2_simulation(int lose_packets, int dup_packets, int reorder_packets, int damage_packets); This is only a suggestion as to how to proceed with this function. The goal of the function is to pass command-line arguments that create a particular test case to the underlying test layer that should logically lie under the rup layer. This should be callable by either the client or server. You should add runtime client/server "main" arguments to turn these functions on/off. lose_packets: boolean, randomly lose a few packets. dup_packets: boolean, randomly duplicate a few packets. reorder_packets: boolean, randomly reorder packets. damage_packets: boolean, randomly damage packets. random UNIX hints: see srand(3), rand(3) functions, although these are "deprecated" in the security community. E.g., traditionally: rand() % 2, returns a value with the range 0..1, in a psuedo-random fashion, and can be used as a rough "coin-flipping" mechanism. The RUP library must in turn somehow encapsulate the UNIX socket calls that it makes. In particular it should encapsulate sendto and recvfrom calls. This is one suggestion as to how to do that: in rup_write and rup_read functions when you call sendto and/or recvfrom, you could encapsulate those calls as follows: #ifdef TESTSIMULATION test_sendto(... normal sendto params and/or test params too); #else sendto(normal sendto params) #endif Then have a module called simulation.c that has test_sendto and test_recvfrom in it as well as an higher level function that might pass "HOWTO TEST" information from the command-line to the test module. Architecturally we have: application | RUP | test layer | UDP sockets Requirements: 1. all data should be received reliably in order, without being destroyed, or lost. 2. a RUP server must be able to receive data from more than one client simultaneously. client data must not be mixed up. 3. Any client or server must be able to open at least 4 protocol handles simultaneously. 4. RUP must interoperate across machines with different byte-orders e.g., Sun SPARC to Intel 486. 5. the RUP library *MUST* hide the details of reliability entirely from the client/server. The coding for the client/server should only use the RUP calls and there shouldn't be any sequence number/timeout mechanics apparent there. You will want to use a mechanism that combines methods of retransmission with positive acknowledgement. Use a checksum algorithm to make sure that data is transmitted correctly. Use a timer (select or alarm; select is better) and use a sequence number mechanism. Note: you must implement a test bed mechanism underneath the socket mechanism that can inject "errors"; i.e., lose packets, corrupt packets, re-order packets, duplicate packets. Be sure and include a section in your architecture description that discusses how your "testbed" loss simulation mechanism works. Turn in at class: 1. src listings 2. makefile 3. script output turn in 4. architecture description describe in English the overall implementation of your protocol. This should be a detailed description of at least two pages. Be sure and describe in psuedo-code/English how your RUP primitives work. 5. test plan describe how you tested RUP. This should consist of a set of test cases where you list each test, describe what it does, and describe what results you expect. Your script output should reflect a run of your test plan. ALSO turn in all of the above via e-mail to the instructor as a shar listing. Again (following the syllabus), note that the shar listing AND the paper version must be given to the instructor at the same time. BOTH forms (email/paper) must be turned in (mailed off) before class on the due date. broad hints: 1. study TCP the protocol 2. study tftp 3. look in the Stevens Network Programming Book