Exercises

1   Exercise - execl

Write a program that uses the execl(3) system call to execute the command ls -l. Only once you have finished this, pass to the next stage.

Modify your program in such a way that it will take between 1 and 4 arguments. The fist argument will be the absolute path of a program to execute. The remaining arguments, up to the 4th, will be the arguments to invoke that command. For instance:

$ myexec /bin/ls              # ls executed with 0 arguments
$ myexec /bin/ls a            # ls executed with 1 arguments
$ myexec /bin/ls a b          # ls executed with 2 arguments
$ myexec /bin/ls a b c        # ls executed with 3 arguments

Your program will use execl to execute the provided command with the provided arguments.

NOTE. Be aware that the (internal) command exec(1) already exist, so don't use the same name for your command!

2   Exercise - fork

Write a program that forks one child process. The parent process should print its own PID and the exit value of the child. The child process should print its own PID and its PPID.

3   Exercise - stdout redirection

Write a program that forks one child process. Make the appropriate operations in the child process so that the standard output is redirected to the file /tmp/output. The child process will then use execl to execute the command ls -l. In the parent process, wait for the child and print its exit code.

Make sure you can see the output of ls in the output file.

4   Exercise - simple pipe

We will implement a program that runs forks two processes and creates one pipe, in order to execute the following shell command:

ps axu | grep bash
  1. Create pipe using pipe(2).
  2. Fork 2 processes using fork(2).
  3. In the first process, close the standard output file descriptor (1) and duplicate using dup(2) the second file descriptor of the pipe (the writing end)
  4. In the second process, close the standard input and duplicate the first file descriptor (the reading end) of the pipe.
  5. Now, write some testing code for checking that your pipe works well. You will printf some strings in the first process, and read from the standard input in the second process making sure that the data from the first process is getting to the second one.
  6. Modify the first process and use execl to execute ps axu, instead of the printf that you used in the previous step.
  7. In the second process, use now execl to execute grep bash.

5   Exercise - mykill

In this exercise you will implement a simplified version of the tool kill(1). It will accept the following syntax:

mykill PID [SIGNAL]

The second argument is optional, and if missing the signal SIGTERM (15) will be sent.

6   Exercise - Ctrl-c

In this program we will use sigaction(2) to reprogram various default signal handlers. The main function of the program will enter an infinite loop that displays the program's PID every 2 seconds.

6.1   SIGUSR1

Write a function handler1 that prints some message on the screen. Register this function as the handler for signal SIGUSER1, using sigaction(2).

Test that your program executes this handler when you send the SIGUSER1 signal to it. Try both the kill(1) command and the mykill program (which you wrote in the previous exercise) to send the signal.

6.2   SIGINT

As you known, typing Ctrl+c whenever you execute a program sends the signal SIGINT (2) to the program. The default action of this signal stops the program.

We want to reprogram the default action and instead execute function handler2, which will

  1. The first time you type Ctrl+c it will just display a message acknowledging the reception of the SIGINT. The handler will now restore back the original signal handler for the SIGINT signal.
  2. Second time you receive the signal, your program will execute the default handler, which terminates the program.

Test your program typing Ctrl+c and also using the mykill program that you wrote earlier.

7   Exercise - tcpcat

The goal of this exercise is writing a simplified version of the netcat(1) command. The output should be called tcpcat, and it will be able to both open TCP connexions as a client and act as a TCP server, with the following syntax and functionality:

NOTE: you do not have the right to use threads or processes to implement this program, use either poll(2) or select(2).

8   Exercise - mini-httpd, a Simple Concurrent Web Server

The Hypertext Transfer Protocol (HTTP) is the protocol that lies at the foundations of data communication in the Internet. It is a request-response protocol. It enables a client to manipulate a resource (usually a file) in the server. Request and reply messages are formatted using plain text.

In this exercise we will implement a very simple HTTP server capable of serving the files present in the file system. It will have the following features:

8.1   HTTP Protocol: Simplified Technical Presentation

Every HTTP request message contains a method and a resource. A method is an action to perform on the resource. The most common method is the GET method, which tells the server to send the resource to the client. Other methods (such as HEAD, POST) are out of the scope of this exercise. Our server will only implement the GET method.

Here is an example of a request message using the GET method and the resource path/to/file.html:

GET path/to/file.html HTTP/1.1
Host: localhost:1234
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:40.0)
Connection: keep-alive

The GET word identifies the method being used. It is followed by a space and then the path to the resource, then another space, the keyword HTTP/ and the version of the protocol being used. Our server will implement (a subset of) the messages included in version 1.0 of the protocol. It will ignore the version number (1.1 in this case) used in request messages.

Request, and reply, messages can optionally include headers. In the above example the Host, User-Agent, and Connection headers have been included. Our server will ignore all headers present in the request message.

Every line in the request message is terminated by the characters \r\n, ASCII codes 0x0D and Ox0A. This is commonly known as the MSDOS end-of-line characters. The request message terminates by a double MSDOS end-of-line, that is the four characters:

\r\n\r\n

Once the server has processed the request it will send a reply message. Here is an example:

HTTP/1.0 200 OK
Server: mini-httpd/0.1
Content-Type: text/plain

Here is the content of the file
requested by the client.

The HTTP/ string comes first, followed by the protocol version. Then a space followed by a numeric code called the status code (in this case 200), a space and a 1-line text message called the reason phrase (in this case OK). The Server and Content-Type headers follow, with their respective values. All lines are terminated by a MSDOS end-of-line, and the last header (if present) is followed by a double end-of-line.

An optional message body follows the double end-of-line. In the above example, the message body consist of the file requested by the client. The server shall close the connection after sending the last byte of the message body.

8.2   Features of mini-httpd

  • Our server will only accept requests using the GET method. On reception of any other method, it will reply a status code 501.

  • It will ignore all headers included in a request message

  • It will use HTTP/1.0 replies

  • It will be able to reply the following status codes:

    Status code Reason phrase
    200 OK
    404 Not Found
    501 Not Implemented
    500 Internal Server Error
  • It will include the following header in all HTTP replies:

    Server: mini-httpd v0.1
    
  • It will optionally include the header

    Content-Type: <MIME type>
    

    on those requests where the requested resource is a file whose extension is present in the following table:

    Extension <MIME type>
    .pdf application/pdf
    .png image/png
    .jpeg image/jpeg
    .jpg image/jpeg
    .txt text/plain
    .html text/html
    Any other Do not include the Content-Type header

    You are free to extend your web server with other mime types, see here http://www.sitepoint.com/web-foundations/mime-types-complete-list/. (NB: the command file -i guesses the MIME file type of a given file.)

  • After starting, the server will load the configuration file $HOME/mini-httpd.conf (the $HOME variable is an environment variable). It will exit if the file cannot be read. The file will look like this:

    port=8080
    cwd=/home/cesar/httpd-root/
    

    The variable port tells the server the port number on which it accepts new connections. The variable cwd provides an absolute path from which the relative paths provided in client request messages will be interpreted.

  • Upon reception of the signal SIGUSR1, our server will re-read the configuration file and apply the new settings.

  • If the resource requested is a directory, mini-httpd will generate an HTML page listing the files contained in the directory, and will include the header Content-Type: text/html.

    For instance, assume that the directory path/to/dir is requested and it contains the following files:

    $ ls -lha
    total 800
    drwxr-xr-x  20 cesar  staff   680B Sep 21 12:59 .
    drwxr-xr-x  14 cesar  staff   476B Sep 21 02:30 ..
    -rw-r--r--   1 cesar  staff   319B Sep  9 15:30 Makefile
    drwxr-xr-x  15 cesar  staff   510B Sep 21 02:30 code
    -rw-r--r--   1 cesar  staff    41K Sep 21 12:40 devel.html
    -rw-r--r--@  1 cesar  staff    87K Sep 18 11:59 e.pdf
    drwxr-xr-x   4 cesar  staff   136B Sep 10 00:44 fig
    -rw-r--r--   1 cesar  staff   1.8K Sep 17 00:45 index.html
    

    Then the following HTML will be generated:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <html>
    <head><title>Directory listing for "path/to/dir/"</title></head>
    <body>
    <h1>Directory listing for "path/to/dir/"</h1>
    <ul>
     <li><a href='path/to/dir/..'>..</a></li>
     <li><a href='path/to/dir/Makefile'>Makefile</a></li>
     <li><a href='path/to/dir/code'>code</a></li>
     <li><a href='path/to/dir/devel.html'>devel.html</a></li>
     <li><a href='path/to/dir/devel.rst'>devel.rst</a></li>
     <li><a href='path/to/dir/e.pdf'>e.pdf</a></li>
     <li><a href='path/to/dir/fig'>fig</a></li>
     <li><a href='path/to/dir/index.html'>index.html</a></li>
    </ul>
    </body>
    </html>
    

    The client browser will render the above HTML code like this.

8.3   Implementation

Severs, after doing some initialization, usually enter an infinite loop where they

  1. wait for a request,
  2. compute something,
  3. reply to the client.

This loop is usually called the service loop. The service loop for mini-httpd will be as follows:

  1. Wait for a new client (system call accept(2)).
  2. fork(2) a new process, which will deal with the client (that is, it will execute the function serve, see attached code below). The main process shall close the client socket and the new process shall close the accepting socket.
  3. Read the HTTP request (function read_request).
  4. Parse it (function parse_request) and build a reply (build_response).
  5. Send the HTTP status code and headers (write_response_headers).
  6. Send the message body (functions write_response_body_dir and write_response_body_file).
  7. Call exit(3) from the client process.
  8. From the main process, periodically call the wait(2) system call to clear the queue of terminated children processes (use flag WNOHANG to avoid getting block waiting for children to finish).

If the main process receives the signal SIGUSR1, it will have to reload the configuration file, chdir(2) into a new directory and reopen the accepting socket. Use the following design:

  • Make the signal handler to set a bit indicating that the signal has been received but the new configuration has not yet been applied.
  • Some system calls (such as accept(2) ;) will return the error EINTR when a signal is received. Detect this condition and, if the bit is set, apply the new configuration and clear the bit.

Your server will write informational and debug messages to the standard output, using the following format:

mini-httpd: starting!
mini-httpd: pid 2110
mini-httpd: argc 1
mini-httpd: (re-)loading configuration file...
mini-httpd: done
mini-httpd: port '8080' cwd '/home/cesar/httpd-root/'
...

8.4   Template code

Ver. 1: mini-httpd-20150921.tar.gz