230 likes | 384 Views
CS244A Review Session #3. Assignment #2 (STCP) Friday, January 24 , 200 3 Matthew Holliman. Assignment overview. Write your own reliable transport layer Three parts: Basic STCP functionality Delivery over reliable network Connection setup/teardown, windows, ACKs…
E N D
CS244A Review Session #3 Assignment #2 (STCP) Friday, January 24, 2003 Matthew Holliman
Assignment overview • Write your own reliable transport layer • Three parts: • Basic STCP functionality • Delivery over reliable network • Connection setup/teardown, windows, ACKs… • No dropped packets, reordering, retransmissions • Due one week from today • Support missequenced/lost packets • Reliable delivery over unreliable network • Retransmissions (timeouts, Go-back N), buffering… • Due in a fortnight (Fri, Feb 7th) • FTP client from HW#1 running over STCP • Modify your HW#1 or use our object files • Due Wed, Feb 12th • Get started early!
Assignment overview • Client/server (client.c, server.c) • File download application • “Mysocket” layer (mysock.c) • Replacement for socket API (myopen, myread, etc.) • STCP (transport.c) • Transport layer: You fill this in! • Network layer (network.c) • Simulates random packet loss, delay, duplication • network_send(), network_recv()—datagram service used by STCP client server mysocket mysocket transport transport network network
What is STCP? • TCP Lite • Simplified connection setup • Two-way handshake • No piggybacking of data with acknowledgement packets • No congestion control • No slow-start, fast retransmissions, delayed ACKs, etc. • Still provides reliable, connection-based, byte-oriented transport between two endpoints • Flow control (sliding sender/receiver window) • Go-back N • Retransmissions
STCP packets • Simplified version of TCP segments • SYN packet: start a connection • ACK packet: acknowledge reception of data (next seq) • No data payload permitted in STCP • SYN-ACK: passive side completes connection • FIN packet: end a connection • FIN-ACK: passive side closed connection • Data packet: Any packet without these flags set • SYN/data packets: sequence numbers • No advertised window
STCP model • Each side of connection: two processes • Parent (application/mysocket layer) • Child (your STCP implementation/network layer) • Why this model? • Simulates real O/S implementation • User-level socket library interfaces to kernel functionality • Network data arrival is asynchronous • Protocol stack is idle until packet arrives • H/W interruptO/S context switch, kernel packet processing, data passed up stack to app • STCP implementation can sleep until an “interesting” event happens • Timeout, packet arrival, etc.
STCP model Parent client server mysocket mysocket transport interface transport interface Child transport implementation transport implementation network network
STCP transport layer initiation myconnect(), myaccept() • transport_init() creates two socket pairs, forks; parent blocks until connected • In STCP, a SYN received from peer by child • Parent/child communicate via local sockets (a la pipe) • syn_sd[]—notify parent of connection completion • data_sd[]—pass data between app/transport layer • Application end of data pipe returned by transport_init() Parent (app) fork syn_sd[0] (syn pipe) data_sd[0] (data pipe) syn_sd[1] data_sd[1] transport_init() Data pipe Syn pipe IPC Child (transport) syn_sd[0] data_sd[0] syn_sd[1] (syn pipe) data_sd[1] (data pipe) comm_sd (peer socket)
STCP IPC details • Forking, IPC is provided already in transport.c • You shouldn’t need to touch much of transport_init(), except to • Add your SYN/SYN-ACK handling • Change/add the transport layer state setup as needed • Sockets created in transport_init() (using localsocketpair()) before forking • Descriptors valid in both parent/child processes • Syn_sd[] used only for connection setup • Data_sd[] used for all data sent between application and transport layer • Only one of each socket is used in parent/child to communicate, a la pipe/FIFO • transport_init() closes unneeded sockets in parent and child
STCP/application interaction • Connection establishment (myconnect, myaccept) • Application blocks until SYN received • STCP wakes up blocked parent process using “syn pipe” • Use network_peer_name(&peeraddr…), write to its syn_sd socket • syn_sd is finished with at this point • See select(3c), poll(2) • Data read/write (myread, mywrite) • Application reads from/writes to its end of the “data pipe” (the socket returned by transport_init() in the parent process) • STCP writes to/reads from its end of the “data pipe” • Whenever data is available (from app or peer) and you have space in your window • Just assume data written to application has been read
STCP/application interaction • Connection teardown (myclose) • Application closes stream socket returned by transport_init() • Pay attention to delivery semantics in assignment handout • Parent blocks in transport_close(), waiting for child to exit • Child waits for all outstanding data to be ACKed before sending FIN • Child process exits on FIN-ACK, unblocking parent • Passive end closes connection immediately on receiving FIN • Multiple connections • A unique child process is forked by transport_init(), so you don’t have to worry about session demultiplexing
STCP main control loop • Stub transport.c talks about “callbacks” • You can ignore this if it’s confusing (I did) • You will probably want to split out functionality for handling data from the app (e.g., transport_appl_io) and functionality for handling data from the peer (e.g., transport_sock_io) • This is all handled in the child process by your transport layer • Main loop repeatedly waits for event on application socket (local_data_sd), peer socket (comm_sd), timeout (in part B onwards) • Select/poll to see which event happened • Be sure not to wake up on application socket unless your sender window is open!
Be careful! These are common problem areas… Select • Online information • man –s 3c select • Looks in section 3c of manual (C library) • Also useful: section 2 (system calls), 3socket (socket calls) • Select semantics • Wait for file descriptor(s) to become readable/writable/error state • select(fd_range, &readfds, &writefds, &errfds, &timeout) • fd_range—range of file descriptors to test (0..fd_range-1) • readfs (writefds/errfds)—description of file descriptors of interest • timeout—time interval for which select() blocks if no socket becomes readable/writable/error state (NULLinfinite) fd_set readfds; FD_ZERO(&readfds); FD_SET(my_sock_fd, &readfds); … switch (select(my_sock_fd+1, &readfs, NULL, NULL, &timeout)) {…
Poll • “Newer” system call • More efficient kernel implementation than select • No need to scan through all open file descriptors • You explicitly specify the descriptors of interest • Poll semantics • poll(struct pollfd fds[], int nfds, int timeout); • pollfd structure contains file descriptor, events of interest struct pollfd fds[] = { { my_socket, POLLIN, 0 } }; switch (poll(fds, sizeof(fds)/sizeof(fds[0]), timeout_interval) { …
Part 2.a—STCP in reliable mode • Network layer refrains from any mischief • All packets delivered in sequence, no losses • You implement connection setup/teardown, acknowledgements, send/receive windows • Client/server pair should be able to download files after you’ve finished this • For testing and submitting code, we need (and accept) only transport.c • No auxiliary files
Client: mywrite(…, 2048) 1000 2000 STCP ACK packet th_ack=2000 Part 2.a—STCP in reliable mode • Window example • Other side received through seq #999, responded with ACK for seq #1000 • We’ve sent through seq #2999 • Sender window is 3072-2000 = 1072 bytes Last seq # acked Seq # 3000 Seq # 4072 …
Part 2.b—STCP in unreliable mode • Network layer becomes obnoxious • Packets reordered, dropped, duplicated • See network_send() in network.c • You must handle retransmissions, timeouts, Go-back N, buffering of data, … • No exponential back-off • Minimum RTT estimate is 20 ms • Five retransmissions of any segment • Careful about packets crossing ends of receive window • Client, server pair should now work with –U flags • Your modified transport.c is the only file needed (and accepted) for testing and the final submission
Part 2.c—STCP-based ftpcopy • You can either modify your HW#1 to use STCP, or you can use the provided object files (libftpcopy.a etc.) • Should just be a few minutes of work • Change the provided Makefile as needed • If linking your transport layer against the STCP-talking libftpd.a, there is a caveat… • Don’t write anything to stdout! • Disable debugging messages, or write to stderr • Another caveat… • libftpcopy.a works only against localhost
General comments • See Peterson & Davie for TCP FSM diagram • Keep track of SYN_SENT, SYN_WAITING, etc. • STCP state machine is simpler • Network layer uses UDP datagrams • Treat it like an IP implementation • Packet-oriented rather than byte-oriented service • Be sure to read the maximum length datagram! • Unread bytes in a datagram are discarded by recv() • Portability • Don’t forget to use htonX()/ntohX() as appropriate in STCP header fields
General comments • Efficiency • Required: Be sure not to wake up unnecessarily/sit in tight loops waiting for things to happen • Use select(), poll() appropriately • Don’t select() on app socket unless you can really send data • Pedantic (optional, but encouraged): If you can avoid unnecessary memcpy()s, you’ll get a lot more out of the assignment—but you’ll probably spend more time on it, too • See the book’s description of mbufs if interested • Don’t worry about this if you don’t care too much—correctness is more important
General comments • Yes, for part (a), the lazy STCP implementer could just send data directly to/from the app, no need to buffer • You still need to pay attention to the windows • But you can’t get away with this for part (b) • It’s worth the extra time to plan ahead rather than wasting effort • Be aware of design changes/additions you’ll need to make to handle unreliable mode
Debugging • Don’t forget to Purify! • It can save you a lot of time on this assignment • Bad select() calls, invalid pointers in network_recv(), can cause some mysterious behaviour in your code • gdb • Normal approach is to place ‘set follow-fork-mode child’ in your .gdbinit • This doesn’t work for me now (?!) • Ugly hack: add sleep(N) in your child after the fork(), run the client/server pair outside of gdb, do ‘ps’ and attach to the child process (larger PID) of interest with ‘gdb {server|client} PID’ • If you have better ideas, please post them to the newsgroup!
General nagging • Start early and test often • This assignment is trickier than it looks! • The earlier you can get to part (b), the better… • This will probably be the toughest two week stretch of the quarter (for everyone…) • Please remember to submit to the right TA! • Steve received only five submissions for HW#1; 26 people incorrectly submitted to Guido or me, despite having been reassigned!