The objective of this lab is to practice basic network programming using TCP sockets that provide reliable data transmission and UDP sockets that implement unreliable transport. The two network interfaces complement each other, the former incurring higher overhead to export reliability and the latter being lightweight that may be suited in environments where reliable transport is not an essential requirement.
Read chapter 2 from Peterson & Davie (textbook).
An extension of Problem 2, lab1, modify the client/server
app so that client and server processes run on different machines in
HAAS G050; instead of FIFOs clients submit requests to a server
using TCP sockets. Create a subdirectory v1/ under lab2 where the
source code of server, tcpcmds, and client, tcpcmdc are deposited
along with a README and Makefile.
When tcpcmds is executed at a server machine, it accepts two command-line
arguments:
% tcpcmds <portnum> <secret>
where portnum is a port number on which the server listens for client
requests and secret is a 6-character string comprised of lower and upper
case alphabet letters that serves as a rudimentary authentication
token.
A client is executed by running
% tcpcmdc <servip> <portnum> <secret>
where servip is the IPv4 address of the server machine (in dotted decimal
format), portnum
specifies the port number on which the server is expecting client requests,
and secret is the same 6-character string entered on
command-line at server side.
The request message format is modified so that a request starts with a 6-character string entered as the third command-line argument of tcpcmds. If the secret string supplied by a client does not match the server's secret string, a message is output to stdout specifying the client's IP address and port number; the request is ignored. As before, messages are delineated by newline character '\n'. All other client/server behavioral specification and interaction remain unchanged.
Code the server, tcpcmds, using system calls socket(), bind(), listen(), accept(), and read(), along with ancillary calls to implement the specified server behavior. Code the client using socket(), connect(), and write() system calls along with any other needed ancillary calls(). They include inet_addr() (or inet_pton()) to translate dotted decimal IPv4 address (a string) into 4-byte IPv4 address (in big endian byte order), htons() to translate a 2-byte port number of type short into network byte order. Use PF_INET (or AF_INET) as first argument of socket() to specify the protocol family and AF_INET as value of the address family field for struct sockaddr_in. Use bzero() or memset() to clear the bits of sockaddr_in (or sockaddr). Test and verify that the remote command client/server app works correctly.
A continuation of Problem 2, modify tcpcmds/tcpcmdc so that the output of the requested command is not displayed on stdout at the server but sent to the client who, then, displays its on its stdout. Use the dup2() system call make file descriptor 1 (i.e., stdout) point to the client's socket before calling execvp(). This ensures that when the legacy app (e.g., ls or ps) outputs to stdout the characters are written to the client's socket instead. After submitting a sequest, a client blocks on its socket by calling read() to await the server's response. After reading the server's response, the client writes it to stdout which will output to the window associated with the client process.
Before calling read() to wait on the server's response, the client should set an alarm (i.e., SIGALRM) for 3 seconds. The client registers a SIGALRM handler, void myalrmhandler(int), upon startup. When SIGALRM is raised before a response arrives from the server, a suitable message is outout to stdout and blocking on read() is ended. If a response arrives from the server before a SIGALRM is raised, the alarm is cancelled.
Place your source code, along with README and Makefile, in subdirectory v2/. Test and verify that your modified app works correctly.
Code a UDP-based ping app in v3/ where the ping server is called udppings, the
client udppingc, along with README and Makefile. The ping server is executed through
% udppings <portnum> <secret>
where portnum specifies the port number on which the server waits for client
requests and secret is a 6-character secret string as in Problem 1.
The client is executed using
% udppingc <servip> <portnum> <secret> <portnum2>
<pcount>
where servip and portnum are the coordinates of a ping server and
secret its authentication token. portnum2 is a specific port number that
the client should bind to and pcount denotes
the number of ping packets to be transmitted. If binding fails, the client terminates
by calling exit(1) after printing a suitable error message to stdout.
The client's request message (i.e., payload of UDP packet or datagram)
consists of a 6-byte secret key followed by 4 bytes that encode a
32-bit integer of type unsigned int. When transmitting multibyte data,
keep in mind that communication networks follow the Big Endian byte
ordering convention. Consider, and determine, if byte ordering matters
for the ping application.
The 32-bit integer is used to represent a sequence number that is used to estimate the RTT (round-trip time) of a ping request. Use a random number generator so that a sequence is selected uniformly randomly from the range 0, 1, ..., 999 for the first ping probe packet. The sequence number of a subsequent ping packet is set by incrementing the previous packet's sequence number. The ping server, udppings, upon receiving a ping request checks that the secret key is valid, and if so, sends a response packet to the client where the payload is a copy of the request packet's payload. Unlike in Problem 1 and 2, the ping server is an iterative server (i.e., not a concurrent server) that performs the requested task without spawing a child process. When requested tasks are simple and incur small constant overhead iterative server design is preferrable to concurrent server design due to improved efficiency.
Both client and server use socket() and bind() to set up sockets, and utilize sendto() and recvfrom() system calls to transmit/receive UDP datagrams (i.e., packets). Before the client transmits a ping request packet it calls ualarm() to set a timer to expire after 1.234567 seconds. If a response packet with the expected secret key and matching sequence number arrives the timer is cancelled and a new UDP ping request is transmitted with an incremented sequence number. As before, prior to calling sendto() a new timer is set to expire after 1.234567 seconds. If SIGALRM is raised, the client assumes that the request packet or its reponse has been lost, and proceeds to transmit a new ping requested with an increased sequence number. If a response packet arrives with an outdated sequence number -- i.e., does not match the most recent request packet's sequence number -- the response packet is ignored.
To estimate RTT, the client calls gettimeofday() to record the time when a ping request packet is transmitted. Both gettimeofday() and ualarm() provide microsecond resolution or granularity. When the response packet arrives before a timer expires, RTT can be calculated in two ways. One, call gettimeofday() and subtract the timestamp from the first gettimeofday() call to estimate RTT at microsecond resolution. Two, when canceling SIGALRM by calling ualarm() with suitable arguments, ualarm() returns the time remaining on the previously set timer. Since its value 1.234567 is fixed, we can use the value returned by ualarm() to estimate RTT. Select the method of your choice. Store the RTT estimates in a 1-D array in main memory of size pcount. Mark a value as 0 if a request was transmitted but a response not received. At the end of the pcount ping probes, the client calculates the average, mininum, maximum, and standard deviation of the estimated RTT values and outputs them to stdout.
Test and verify that your UDP ping app works correctly on the lab machines in HAAS G050. In your tests upper bound pcount at 100. After establishing correctness, benchmark the app at two different time of day periods (e.g., morning and afternoon) and check if there is a noticeable difference. For the same periods, run the legacy ping app in /bin/ping and compare their estimates. Discuss your results in lab2.pdf.
Use the legacy ping app to estimate RTT to www.upenn.edu. Do not transmit more than 30 probes to avoid potential false alarms being triggered at server side. Based on the observed RTT values, perform rough calculations on the physical distance between Purdue and the assumed location of the server. Note that effective distance may be greater than a line (i.e., shortest path) from source to destination since communication lines go through PoPs (points of presence), or GigaPoPs, typically located at larger cities. For example, in Indiana, Indianapolis serves as a central communication exchange for multiple nationwide networks. Using the app traceroute you may be able to partially glean which geographic route a packet is taking. Using SOL (speed of light) as an upper on communication latency, compute an approximate lower bound on how long a ping packet may take to reach www.upenn.edu. Assuming routes are symmetry, estimate RTT and compare it to the values reported by the ping app.
Find a site significantly more distant than www.upenn.edu and repeat the measurements, estimate and comparison. When selecting a server (e.g., web server) note that many institutions subcontract their web services (wholly or partly) to ISPs including CDNs (content distribution networks) that use proxy servers located in geographic proximity to clients in order to provide speedy response times. Hence picking an institution on the west coast does not imply that a ping packet sent to its web server is routed to the west coast; a proxy much closer by may be the respondent. You may use nslookup or dig to check the results reported by DNS (Domain Name System), a massive distributed database that resolves Internet related names including translating domain names (e.g., www.upenn.edu) to IP addresses (IPv4 and IPv6 where available). By inspecting the results from nslookup/dig you can discern if an institution is running their own servers (hence likely located in close proximity to the physical location of the institution) or subcontracted to ISPs that provide services through a network of proxy servers distributed nationally/internationally. Report your findings in lab2.pdf.
The Bonus Problem is completely optional. It serves to provide additional exercises to understand material. Bonus problems help more readily reach the 40% contributed by lab component to the course grade.
Electronic turn-in instructions:
i) For problems that require answering/explaining questions, submit a write-up as a pdf file called lab2.pdf. Place lab2.pdf in your directory lab2/. You can use your favorite editor subject to that it is able to export pdf files which several freeware editors do. Files submitted in any other format will not be graded.
ii) We will use turnin to manage lab assignment submissions. Please check that the relevance source code including Makefile are included in the v1, v2, and v3 subdirectories of lab2. In the parent directory of lab2, run the command
turnin -c cs536 -p lab2 lab2
You can check/list the submitted files using
turnin -c cs536 -p lab2 -v