Overview: Implement a simplified version of the Internet super-server, known as inetd. This version will support TCP services only (no UDP). Also, implement three services: echo, daytime, and chargen.
inetd implementation: [This description is based heavily on that in Stevens' "UNIX Network Programming" book].
inetd listens for incoming connections on several ports. When a new connection is established, inetd handles all the dirty work of setting up the socket, then forks a child process which connects file descriptors 0, 1 and 2 to the socket and execs a server handler process.
The details: on startup, inetd will read a file called inetd.conf and will create a stream socket for all the services specified in the file.
# this is the inetd.conf file that you should use echo in.echo daytime in.daytime # the time of day in a human-readable string chargen in.chargen users finger -ns
All data including and following a hash mark ('#') is a comment
and should be ignored. Blank lines should be ignored. Note that there
can be arguments to the name of the server program to run, as is the
You will write the programs in.echo, in.daytime, and in.chargen. (See descriptions, below.) The last program, finger, is already written and should be executed when someone logs into the users port.
As each socket is created, a bind is executed for every socket, specifying the well-known port for the server. This TCP port number is obtained by performing a look-up on the configuration file services:
# this is the services file that you will use # except you should change these port numbers echo 6011 daytime 6012 chargen 6013 users 6014
For each socket, a listen() is then executed; in this way, inetd listens to multiple sockets simultaneously.
A select is then executed, to wait for the first socket to become ready for reading. Remember that a socket is considered ready for reading when a connection request arrives for that socket. At this point the inetd daemon just waits for the select() system call to return.
When a socket does show as ready for reading, an accept() system call is executed to accept the connection.
The inetd daemon fork()s and the child process handles the service request. The child closes all the file descriptors other than the socket descriptor that was just accepted and then calls dup2 to cause the socket to be duplicated on file descriptors 0, 1, and 2. The accepted socket descriptor is then closed. By doing this, the only file descriptors that are open in the child are 0, 1, and 2, and these three are all connected (through use of dup2()) to the socket. The practical upshot of all this is that everything that comes in on the socket can be read from the child processes stdin and everything that the child writes to stdout or stderr goes out on the socket!
The child process now does an exec() to execute the appropriate server program to handle the request, passing the arguments that are specified in the inetd.conf file.
Finally, the parent process must close the accepted socket (so it doesn't eventually run out of socket descriptors), and then should go back and call select() again, waiting for another connection.
You must set up a signal handler using sigaction() that handles SIGCHLD and reaps the zombies as they appear.
The in.echo server: This service reads a character, then writes the same character back out.
The in.daytime server: This service gets the current
system time then prints it out in a format like this:
The in.chargen server: this program outputs a bunch of characters with a newline after every 72 characters. The characters should be ascending ASCII characters that look something like this:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij $%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijk [and it keeps printing this kind of stuff forever...]
System calls you are NOT ALLOWED to use: system() and signal(). Anything else is fair game.
Directories: Place the project in your ~/298C-02/final/ subdirectory. Create a single Makefile that will build inetd, in.echo, in.daytime, and in.chargen. Also, put the services and inetd.conf files in the same directory.
Extra Credit: 10 points if you hand it in before midnight on Monday December 8. (Be sure to send us e-mail if you do this!!) If you miss that deadline, you can still get 5 extra credit points if you hand it in before midnight on Wednesday December 10.
Late policy: 30 points per day. Don't hand it in late.