CS87 Lab 2:

A Client-Server Chat/Talk Program

Part 1 Due: Wednesday Feb 12 before 11:59pm
(push to your Lab02 git repo with Part1 tag by then)

Part 2 Due: Wednesday Feb 19 before 11:59pm
(push to your Lab02 git repo with Part2 tag by then)

Part 3 Due: Wednesday Feb 19 before 11:59pm
(required for taken-NW groups, optional for other groups)

(push to your Lab02 git repo with Part3 tag by then)

This lab should be done with your lab 2 partner

Lab 2 Goals:

Make use of the CS87 piazza page for questions and answers about socket programming, C strings, pthreads, Unix utilities. If you have taken Networks, please help your classmates who have not with socket programming questions.

Contents:

Lab 2 Overview
The main focus of this lab is learning client-server socket programming and implementing a specific message protocol for clients and servers to talk to each other. You will implement two versions of a chat or talk client and server program to allow users on different machines to talk. You will be given a protocol for how clients and servers communicate, and your solution must implement the protocol such that your clients and servers can communicate with other group's.

In this lab you will implement at least 2 different versions of the client and server.

  1. The Part 1 version: allows for one-at-a-time chat session between a single client on one machine and a single server on another machine. When the current chat session ends, another client can connect to the server end and start a new chat session. The client and server alternate sending messages back and forth (in a question and answer type style).

    The Part 1 solution is due in one week. I encourage you to finish this part early and get started in on Part2.

  2. The Part 2 version: allows for a chat session between multiple clients. In this version the server does not participate in the chat itself, but fosters allowing multiple clients to connect to the chat session. Clients participating in the group chat send their message to the server and the server shares it with all of the other clients participating in the chat session. In this version, clients can "speak" at anytime; there is no specified ordering or taking turns writing messages to the group. Individual clients can also come and go in a chat session.

    The Part 2 solution is due in two weeks.

  3. The Part 3 version (optional for non-NW groups, required for NW-groups): impelement the "Vote to let Join" chat server. With all the NW-groups, you will first develop a voting protocol that will allow all particpants currrently participating in a talk session decide if a new client can join in on the coverstaion. Defining a protocol means that agreeing on the message sequence for a "voting to let join" protocol--every lab group in the class must implement the same messaging protocol. Your individual server implementations can use their own voting algorithm (majority, at least one "yes", ...) to determine if a new client requester gets to join in on the coverstaion it is hosting, but all groups voting protocols (communication between clients and the server hosting) to make this decision must match. The result should be that clients and servers from different groups know how to participate in a voting protocol when a new client requests to join a chat session hosted by a server.

    The Part 3 solution is due in two weeks.

This assignment is very loosely based on Unix talk, which was a very early Chat or IM system. (Note that you will NOT be implementing the Unix talk protocol in this lab; instead you will implement a different protocol that has some similar general functionality.)

Lab 2 Starting Point Repo
  1. Both you and your partner should:
    1. Create a cs87/labs subdirectory on the CS system:
      mkdir cs87
      mkdir cs87/labs
      cd cs87/labs
      
    2. Get your Lab02 ssh-URL from the GitHub org for our class: cs87-s20
    3. On the CS system, cd into your cs87/labs subdirectory
    4. Clone a local copy of your shared repo in your private cs87/labs subdirectory:
      git clone [your_Lab02_URL]
      
      Then cd into your Lab02-you-partner subdirectory.
    If all was successful, you should see the following files when you run ls:
    Makefile README.md client.c cs87talk.c cs87talk.h server.c 
    
    If this didn't work, or for more detailed instructions on git see: the Using Git help page.

Starting Point files

With the starting point are several files, many have some starting point code written for you. These files include:
Message Protocols
Messaging Protocols define how two parties communicate--the protocol defines both the set of application-level (higher level) messages, the send-recv exchange in handling types, and the expected format of messages.

For this lab you will implement three different high-level message protocols as part of the cs87talk protocol. The three are:

  1. HELLO: a client introduces itself to the server before talking. The server will tell the client if it can join the chat or not as part of this exchange.
  2. MSG: an endpoint will send a message to another endpoint. A client can send a MSG to a server and a server can send a MSG to the client.
  3. QUIT: a client tells a server it is done and leaving the talk session.

Each part of the protocol is begun by one party sending to the other party 1 byte message tag. The tag value is used to indicate which of the three messaging protocols the client and server should run (the expected send-recv sequence between the client and server for the interaction type is indicated by the tag).

Protocols Definitions:

And see the cs87talk.h file for type and constant definitions that you should use in your implementation of these.
  1. HELLO: this protocol is initiated by the client when it wants to start a talk session with a server (the client should initiate this immediately after the TCP connection has been established and before trying to send talk messages to the server). The send-recv behavior is defined by:
    client                                server
    ======                                ====== 
    1. send HELLO_MSG tag -------------> recv 1 byte tag
    2. send len -----------------------> recv 1 byte len
    3. send name ----------------------> recv a len bytes name string 
    4. recv 1 byte tag <---------------- send 1 byte reply tag 
                                            (HELLO_OK or HELLO_ERROR)
    
    The client sends 3 values to the server in this order: the HELLO_MSG tag as a 1 byte value; a 1 byte len value, which is the number of bytes in the name string; and a len bytes message containing the name string (passed as a command line argument to the client program). The client then receives the 1 byte tag response from the server, indicating if the server is letting it join the talk session.

    The server will terminate the connection after it replies HELLO_ERROR. If it replies HELLO_OK, it will update state about this connection, and create a message buffer for this client with the client's name string as a prefix. All messages set by this client will be prefixed by the string "name:" to mark that this message was "said" by this client.

  2. MSG: send a message string from a client to a server or from a server to a client:
    initiator                           other end
    =========                           =========
    1. send MSG_DATA ------------------> recv 1 byte tag value
    2. send len -----------------------> recv 1 byte len value
    3. send data ----------------------> recv len byte message
    
    If the server is the "other end" it should store the received message in a string with the a "name:" prefix (the name is obtained from the HELLO protocol) to identify the sender. For example, if the server is communicating with Frey, and Frey initiates a MSG_DATA message, sending "hello there" as the data part, the server will store the received message in a string: "Freya: hello there".

    If the client is the "other end" it just receives the message of len bytes and creates a string from the len byte message (null terminate '\0' before printing out); the client side doesn't add a prefix to received messages. For example if the server sends the client a MSG_DATA message, with "hello there" as the data part, the client will store the recived message in a string "hello there".

  3. QUIT: when the client wants to drop out of the chat session it sends the QUIT message tag to the server:
    client                                server
    ======                                ====== 
    1. send QUIT -----------------------> recv 1 byte tag value
    

    After sending QUIT, the client should close its end of the socket and exit.

    The server then cleans up any state associated with this connection, including closing its end of the socket that was dedicated to this communication.

    After receiving a QUIT, the server process should not exit.

    • For Part 1, it should be ready to accept a new client connection for the next chat session.
    • For Part 2, this client has just left the group chat.


Part 1: One Client at a time talks with a server, alternating Client-Server Talk
In the first version of this assignment you will implement a client and server program that implement the messaging protocols described above. In this version, a client will connect to a server, and then the client and server will talk back and forth, each taking turns sending a message to the other. The server will have a dedicated talk session with this client until the client terminates the connection (either it closes its end of the socket or it sends a QUIT message). The client should exit after this, but the server should not exit, instead it is now available for another client to connect to it to have a talk session.

The behavior should be:

  1. client connects to a server using the TCP protocol. Run the client with the server's IP and and the client's chat name as command line args:
    ./cs87_client 130.58.68.67 tia
    
  2. the client initiates the HELLO protocol with the server
    1. if the server replies HELLO_ERROR, the client exits (no talking will take place)
    2. if the server responds with HELLO_OK, then the client and server will start a talk session
  3. the client and server will have a talk session that consists of some number of alternating message exchanges. the first MSG should be sent from client to server, then next from server to client, then by client to server, and so on.
  4. the talk session is ended by either the client sending a QUIT message or the server detecting that the client's end of the socket has been closed.
An individual message in (3) should be a line of texted entered by the user running the client (or server) side. I suggest using readline to read in a line of user input and return it as a string (and remember you are responsible for freeing the return string when done with it...run valgrind).

Sample Output

Here is sample output from two back-to-back talk sessions with a talk server. Your client and server program can print out any prompts and messages to the user than mine, but they should have this same alternating behavior and the server should handle only a single client connection and talk session at a time. Only after the current talk session ends, can the server accept the next talk session from another client (note where that is in the server output).
Requirements


Some extra features to add to your Part 2 (and Part3)
These are NOT required, but are some ideas for extra things to add to make your chat program a little more user friendly:

Help and Useful Utilities

Sockets and IP info:

C Programming, strings, pthreads, readline library:

Other Resources:


Part 2: Multi-client Chat
The Part 2 talk server changes the role of the server, allows multiple clients to simultaneously connect to the same server to all participate in a group chat, allows clients to send messages to others at any time (there is no predefined order or alternating behavior). In addition, new clients can enter an existing chat at any time, and current clients can leave at any time, and the chat continues on.

Requirements

Sample Output

Here is sample output from a multi-client chat session. Note that the server is not a participant in the chatting, but instead forwards a message from one client to all others (and note the name prefix). Also note that clients enter and leave and the chat continues.

A note about client-side I/O

Because you will have mulitple client threads sharing the same stdin and stdout, you will see messages from other clients being printed out in the same terminal window as the prompt and the input message the human user is typing in. This is fine.



Part 3: "Vote to let Join" mulit-connection Chat Server

This part is required for the lab2 partners who have taken a Networking course, and optional for the groups who have not.

For this part, you are going to add a new version of the HELLO protocol to your Part2 solution. When a new client wants to connect to a chat session (via the HELLO protocol), the current set of clients will decide if they are going to let the new client join the chat session or not. If the current set of clients in the chat choose NO, then the server will reply with HELLO_ERROR and not let the new client join. If the current set of clients choose yes, then the server will reply with HELLO_OK and the new client can join in the group chat.

Protocol for voting in a new chat member

All of the groups together will need to come up with a protocol for the server and the clients currently in the chat to make a decision. Your server/client should work with any other client/server that implements this voting to join protocol.

For this part, develp the messaging protocol between the server and clients in the chat to communicate a voting exchange. Your groups should agree on just the message protocol: what are the new tags, and what is the expected send-recv behavior for this protocol. This should be like defining the HELLO or MSG or QUIT protocols.

This protocol should be VERY simple. This is just the agreed message exchange between the server and clients already participating in a chat. It should be similar to one of the existing protocls like HELLO or MSG. If it starts to get longer than about 2x any of the current ones, step back and simplify.

In addition to message tags involved in this protocol, specify the type and size of any associated data sent. For example if you send the value numeric value 10, are you sending it as a 1 byte value, a 2 byte value, a 4 byte value, ... it is important to ensure that receiver and sender agree on the same number of bytes of the message sent and received.

Group's particular voting algorithms can differ (what they decide with the set of clients' yes and no votes), but the messaging protocol used by client and server processes should be the same; your group may choose any algorithm for tallying a result, but your group's client should know how to interpret a voting message request from another group's server, and your server should be able to have a voting interaction that includes another group's client program.

Publish your agreed upon protocol on piazza (you can create a new page for the Lab2 Voting Protocol off the top-level class wiki page. Use the chain looking link to do this).

Some Advice: in designing the protocol try very hard to separate out the protocol design from how it will be implemented. For example, worrying about race conditions or deadlock or clients exiting are all implementation issues and should not be part of the protocol (other than ensuring that your msgs send-recvs in the protocol are not a deadlock). Focus solely on the message exchange between clients and servers to initiate a voting session and to collect votes. Similarly, the particular voting algorithm is not part of the protocol. You do not need to agree on a voting algorithm; one group could choose a majority algorithm of the client's votes, another could choose a random vote, anther could do something else with the clients' votes.

Some requirements (and not)

  1. Your group's Part 3 client/server should be able to participate in a vote with other group's Part 3 server/client. Hence the voting protocol.
  2. You should think about, and handle, clients that exit during a voting event.

You do not need to support any number of simultaneous voting of letting in new clients. For example, if a second new client tries to join the chat during the voting decision for a current new client, it is fine to serialize the voting process: first complete the voting decision about the first new client, then start the voting process on the second new client.

Submit
Before the Due Date, one of you or your partner should push your solution to github from one of your local repos to the GitHub remote repo. (it doesn't hurt if you both push, but the last pushed version before the due date is the one I will grade, so be careful that you are pushing the version you want to submit for grading):

From one of your local repos (in your ~you/cs87/labs/Lab02-partner1-partner2 subdirectory)

git add *.c *.h  
git commit
git push
Also TAG your commit: because you are going to implement your Part 2 (and Part 3) in the same repo as your Part 1, you should add a git tag to your submitted solution to a particular part.

To do this:

# list all current tags associated with a repo
git tag -l

# create a new tag named Part1 with a tag message (optional)
# and share a tag: push the tag to the origin to share it:
git tag -a Part1 -m "soln to Part1"
git push origin Part1

# checking out a specific tagged version of the code
# (checkout Part1 version of code into a local repo named my_part1)"
git checkout -b my_part1 Part1

# to list other data along with the commit for a specific tag
# (this will show the commit number, date and who created the tag):
git show Part1
You must name it exactly Part1 (and Part2 for part2, and Part3 for part3) otherwise your professor will be very sad.

If you have git problems, take a look at the "Troubleshooting" and "Advanced Features" sections of the Using git page.