Preliminaries
Set up a bare repository on stu.cs.jmu.edu based on the instructions
in the CS 361 Submission Procedures,
using the name lab6-www.git
.
Implementation requirements: Set up a minimal HTTP server
Please consult the extended example at the end of
Chapter 4
in the textbook. It documents a lot of the steps for setting up a
web server.
Most of the work will involve modifying utils.c
to implement a
number of helper functions:
- Complete the code in
build_address()
to set up an IPv4
address within a struct sockaddr_in
.
- Using the textbook examples as a reference, set
up a server socket in
setup_server()
. This function
should go from making the call to socket()
until
the call to listen()
. Return the socket file descriptor
(or -1 if an error occurs).
- Complete
get_connection()
so that it accepts incoming
requests and prints the IP address of a connection. Use
"Received incoming request from %s\n"
for the format string
for printing the address. Return the file descriptor for the connection.
- Complete
build_response()
so that it opens the file,
uses buile_response_header()
to build the header, then
concatenates the contents. If the file doesn't exist, return
NULL
.
Next, complete the implementation of serve_web()
in
server.c
. The provided code uses the functions in
utils.c
to set up the server socket and get the connection.
You will need to complete the code to read the request, call
build_response()
to get the HTTP response, then write the
response back to the client. If build_response()
returns
NULL
, then write the 404 message indicated. Finally,
close both the server and connection sockets and shut them down.
There are two
very important things to keep in mind
when completing the server code:
- You are dealing with TWO socket file descriptors, not one. Once
you pass a file descriptor to
listen()
(i.e., the one
that you got from socket()
), it becomes a
server socket and can only be used for
accepting incoming requests (i.e., calls to accept()
).
You cannot pass this file descriptor to read()
or write()
. Those functions require the
connection file descriptor, which you get as a return value from
the call to accept()
.
- After writing the response, you must close and shutdown both
file descriptors. If you don't, you'll fail the integration tests.
What happens is the first test opens and binds the server socket to
the port number. Then, when the next test tries to bind again, it
fails because Linux thinks the port number is still in use.