Remote Pipe.

Introduction.

You will implement a "remote pipe" in this programming assignment. This pipe will allow you to pipeline execution of two commands and works similar to the local pipe except that the commands are executed on possibly different computer systems. The example of such remote pipe is:
    cat FileName | rpipe ernie wc
In this example the output of the cat command is sent as the input of the wc command via the remote pipe and the wc is executed on the host ernie(cat is executed locally).

Remote pipe will require two executables:
    rpipe - remote pipe client
    rpiped - remote pipe server (daemon process)

The client will be reading from its standard input (that can be redirected as in the example above by using regular UNIX shell pipes) and sending the data read to the remote pipe server via the socket. The server must be concurrent so that several remote pipe clients can be served simultaneously. The master server process will have to fork a separate process for each incoming connection request and let the child process take care of the request handling. The forked child process will read data from the socket and feed it to the required executable.
 

Security.

You will have to implement a simple authentication mechanism so that the server will reject connections from unauthorized clients. The authentication will involve an exchange of some password and a connection confirmation between the client and server. Both client and server will use a randomly generated 32-bit string as a password that is hard-coded in both executables. Note that without this security mechanism anyone, anywhere can connect to your rpiped and execute commands as you.
 

Communication between client and server.

As communication media client and server will be using TCP/IP sockets. Server will be listening on a "well-known" port number that both client and server must agree on. You should use the last five digits of your social security number + 10000 as this port number. The server will create and bind socket to this port number, if this attempt fails (e.g. this port number may be already in use) the server will try to bind the socket to a different port number until it succeeds and will report the port number to which it has bound the socket.

Client's command line syntax is:
    rpipe [-h hostname] [-p port-number] executable-name
where:

The syntax of the server command is:
    rpiped [-m max-connections] [-p port-number]
where:

Design issues.

The server process should keep track of the created child processes. First of all, the server will have to collect the exit status of each forked child process - you will have to use waitpid system call and install a signal handler for the SIGCHLD signal. The server main loop may look like:
    while(true){
        newsockfd = accept(...);
        if(fork() == 0) {// child process
            handleRequest(newsockfd);
        }
        close(newsockfd);
    }
Since this is a concurrent server, it cannot wait for the child processes in the main loop. You will have to catch child termination signal and handle it appropriately.
Secondly, the server may not create more than the max-connections child processes and, thus, it must have a counter of the number of currently executing children; every time the child process terminates the signal handler will decrement this counter and every time the server accepts a new connection and forks a new child process, it (master server process) will increment this counter.

The system call accept() is blocking until a new connection request is received, at this point the server should fork a new child process (or reject connection if the max is achieved); however, accept() may be interrupted by a signal (such as a child termination notification signal) and will return -1 (with errno set to EINT). Your server should not fork any dummy processes if the accept() was interrupted by a signal and should simply ignore such interruptions (just continue the loop).