University of Bridgeport

Operating Systems CPE408/CS503

UNIX Lab Assignment #3 – Single-Channel Multi-User Relay Chat

Summary

Unix Lab #3 is an extension of Unix Lab #2 and it introduces UNIX sockets for inter-process communication between two or more physical machines.

Introduction

In this assignment you are to modify Unix Lab #2 and extend it to provide for the messages being sent to the users of the other machine using sockets and TCP/IP.

In Lab #2, the system running on one machine was not client/server based but peer based, where each program instance was being able to communicate with another instance of it.

In this lab exercise, you are to create a “master process”, or a server. Clients on the same machine connect to it using message queues as was done in Lab #2 and users can chat since the master process is echoing all the messages it received to the other clients connected to it, except of course to the originating client.

Now, suppose the same system runs on other machines and all the local users logged in one specific machine can chat to each other. The problem is that users cannot chat across machines – that is because the master processes on those different machines are not inter-connected to each other. In, this assignment you are to solve that problem.

Specifics

Master processes should, in addition to their function already stated in the first paragraph of the Introduction section, communicate with the other master processes on other machines using sockets, which run over TCP/IP. Thus, each master process on every machine should, while starting up, read a configuration file, where it is stated to which other master processes should it connect to. Once connected, it would echo incoming messages to the other clients using message queues and it will also send the message to the other master processes it is connected to. On the same token, all the messages it receives from other master processes connected to it should be echoed to the local clients connected to it. Obviously, care should be taken while constructing the configuration files to specify how is each master process connected to the other one, to ensure that at the end all users receive all the messages and to make sure loops are not introduced.

Bonus

Required for graduate students.

As in Unix Lab #2, clients should have a GUI. Refer to the Unix Lab #2 for more details.

Demo specifics

It is more complicated to demonstrate all the features required to be implemented in this lab exercise, thus demo of it should be carefully planned. As a minimum, you should be logged in to at least two different Unix workstations (as an example, cpe.bridgeport.edu and axon.bridgeport.edu) with three different sessions (three different telnet windows per workstation, 6 telnet windows in total). In one window you will run the master process and in the other two windows you will run clients; the same for the remaining three windows that are connected to the other physical Unix machine. When a user types in one client window, message should be displayed on the other client windows (at the same machine as well as the remote machine).

Unix Socket Programming

Sockets, once created and connected can be used like file descriptors, thus it is easy to read and write to them. An extensive description of each socket function call is given in the manual pages for it, thus only a sequence of function calls for the server and the client will be presented here.

Include files required: <sys/types.h> and <sys/socket.h>. In this assignment you will use Internet sockets, thus type for the socket to be created is PF_INET that uses IP. Socket type is the connection-oriented one, SOCK_STREAM (uses TCP) as opposed to the connectionless (uses UDP).

Server / Client
Create socket – socket(….) / Create socket – socket(….)
Assign a name to it – bind (…) / …
Establish connection queue – listen(…) / …
Get a connection from queue – accept(…) / Initiate connection – connect(…)
read(…) / write(…)
write(…) / read(…)

Sequence of function calls to establish a connection between a client and a server

Resources

For this assignment, similarly to the previous one, you can consult USENET newsgroups, which are easily accessible by using website where you can find tons of articles, references and sample codes developed by your peers, professionals, etc.

You can refer to the CS435 – C&UNIX Programing course web site at:

A nice web-site which is a collection of links to other UNIX programming web sites is:

“Davin's collection of UNIX programming links”

Lastly, you can also refer to the textbook for this assignment, which was given in the syllabus:

John Shapley Gray, Interprocess Communications in UNIX, Second Edition, Prentice Hall PTR, 1997. ISBN: 0-13-899592-3

and UNIX manual pages, referred to as man.

Note: Interprocess Communications book by John Shapley Gray should be on reserve in the library. Further, man pages are very extensive regarding the system programming which is the type of the program developed in this lab exercise, thus it is highly recommended to go over them.

Sample Code

Only snippets of code will be given for this Lab exercise. You code should also have error checking capability, using perror() function as explained in Unix Lab #2.

You can also consult sample code of Unix Lab #2, regarding passing of the structure as an argument to the function or accessing its members through a pointer.

Server:

#define PORT 4000

int s; /* socket descriptor */

struct sockaddr_in serv_adr, client_adr; /* interent addresses of the server and client */

int new_s, client_len;

s = socket(AF_INET, SOCK_STREAM,0);

memset(&serv_adr, 0, sizeof(serv_adr));

serv_adr.sin_family = AF_INET; /* addres type */

serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); /* any interface */

serv_adr.sin_port = htons(PORT); /* which port */

bind(s, (struct sockaddr *) &serv_adr, sizeof(serv_adr)); /* bind a socket to the port */

listen(s, 5); /* Listen - a blocking function */

client_len = sizeof(client_adr);

new_s = accept(s, (struct sockaddr *) &client_adr, &client_len); /* accept client connection */

/* a fork should occur before reading/writing, so that the original server can continue */

/* accepting future connections, and a new process after fork is handling the connected one */

/* reading and writing */

read(new_s, buffer, BUFFER_SIZE);

write(new_s, buffer, sizeof(buffer));

Client:

int s, len;

struct sockaddr_in serv_adr;

struct hostent *host;

host = gethostbyname("whatever.bridgeport.edu"); /* should be from the config file */

/* check for NULL */

/* prepare the structure that holds information where should the socket be connected to */

memset(&serv_adr, 0, sizeof(serv_adr));

serv_adr.sin_family = AF_INET;

memcpy(&serv_adr.sin_adr, host->h_addr, host->h_length);

serv_adr.sin_port = htons(PORT);

s = socket(AF_INET, SOCK_STREAM, 0); /* create socket */

connect(s, (struct sockaddr *) &serv_adr, sizeof(serv_adr)); /* connect to the server */