Skip to content

ppatrik-dev/chat-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IPK Project 2 - Client for a chat server using the IPK25-CHAT protocol

Table of Contents

Introduction

This project is implementation of the client for a chat server using the IPK25-CHAT protocol, with implemented TCP protocol variant. Protocol variant using UDP protocol is not implemented at this moment.

TCP

Transmission Control Protocol is reliable, connection oriented transport protocol. Communication through this protocol is provided by stream of bytes between sender and receiver. Before sending data, a connection needs to be established between these devices, which is called three-way handshake. After created connection, the transport layer protocol ensures correct, ordered and error-checked application data delivery. [1], [2]

Socket

Network socket is software structure provided by operating system, which serves as communication endpoint for process to receive and send data across the network or communicate with other processes on the local device. Socket is bound to transport protocol, IP address and port number. For each created socket there is an socket descriptor which is used with read and write operations. [3], [4]

Program details

  • Implemented in C++ programming language, by C++20 standard.
  • Developed on Linux 24.04 LTS with g++ 13.3.0 compiler.
  • Build is done by make command.
  • Supported network protocol IPv4

Usage

Print help message:

./ipk25chat-client -h

Connect to local server with TCP protocol on port 6789:

./ipk25chat-client -t tcp -s localhost -p 6789

Connect to remote server with TCP protocol on default port 4567:

./ipk25chat-client -t tcp -s anton5.fit.vutbr.cz

Options

Option Default Value Description
-t User input (tcp or udp) Transport protocol used for connection
-s User input Server IP or hostname
-p 4567 Server port
-d 250 UDP confirmation timeout (ms)
-r 3 UDP max retransmissions number
-h Prints program help message and exits

Note Client accepts udp protocol option value and UDP protocol variant options, even when the UDP protocol variant is not implemented. Program parse the arguments and exists.

Implementation

The client's behaviour was implemented based on the Client FSM specified in assignment. Following flow diagram represents the client's actions based on the events and inputs.

Flow Diagram
Flow Diagram

Client design

The core of the client is implemented in the Client run method. While the client is not in the END state, monitoring stdin for user entered commands and chat messages and the socket for client-server communication using poll function [5]. Also handling client termination with C-c, using sigint signal handler [6], which sends BYE message to the server.

Connection termination

In case the client should gracefully terminate the connection the BYE message is sent to the server, client state is set to END state and connection is closed with shutdown function [7]. In case of sending ERR message indicating the error, also the client exit code is set to non-zero ERROR_CODE value.

OOP design

Implementation of the client is divided into three classes, as shown in the class diagram.

Class Diagram
Class Diagram

ArgParser

Class implementing program arguments parsing with function parse_arguments. This function is using function getopt from getopt library. In case of -h argument prints help message to console and exists program, otherwise storing parsed arguments values to Client static members.

Client

Abstract class with interface for protocol variant subclasses, implemented as following pure virtual methods.

  • send_auth_message send_join_message send_msg_message send_bye_message send_err_message handle_err_message process_received_message

Before creating protocol variant instance, the Client constructor is called, which initiliaze object values as client state, display_name and exit code. Also storing pointer to protocol client instance and resolving server hostname to IP address.

Important methods implemented in this class:

  • resolve_server_address

    • Resolving server hostname to IP address using getaddrinfo and storing the address in string format using inet_ntop function. If server IP address is specified than no translation is done and the IP address is stored as string in dot-decimal format.
  • handle_user_command

    • Parsing provided user command, using stream class istringstream from <sstream> header. When the used command is not supported prints local error, otherwise try to parse command arguments and try to send command type message to the server or execute local command.
  • handle_user_message

    • Method checks for valid user message content using defined regular expression. In case that input chat message is longer than allowed maximum message length, the message is truncated before sending to the server.
  • receive_request_response

    • This method is used after the request message is sent to the server. It starts waiting for request response for 5 seconds using poll with set timeout. After the response is received it calls received message processing function. In case no response was received in time, it returns false value.

TCP Client

Class implementing the Client interface and handling TCP protocol variant functionality. When constructing TCP Client instance, there is created socket for TCP communication and established connection with the server using connect function. The connection termination is handled by shutdown function in close_connection method and close socket in destructor.

Important methods implemented in this class:

  • process_received_message

    • When the message from server is received, this method append the message to string variable message_stream, in which all received messages from server are appended. Next while the get_message_from_stream parse and extract correctly terminated message from the stream the client calls parse_received_message. If the message is accepted by the grammar, then based on the message type and current client state the action is taken according to the behaviour defined in Client FSM.
  • get_message_from_stream

    • Search for \r\n substring in message_stream, when the search fails return false value indicating there is no terminated message at this moment, for example one message can be send in more segments (also multiple terminated messages can come in one segment). If the search succeed the first terminated message is extracted without the CRLF and erased from the stream.
  • parse_received_message

    • This method handles received message parsing according to the defined message grammar. The received message is tokenized using istringstream and then individual tokens are matched using recursive descent parsing. Function used in token matching is match_token which compare two strings with case insensitive [8]. Message arguments matching is done by using static check_{argument} methods from the Client class.

Testing

While testing the client functionality, multiple scenarios were tested manually as described in test case visualization, for example invalid command arguments, invalid message content, received malformed messages, unexpected messages in the current state, graceful connection termination, etc. The client's implementation was also validated by student public tests, with all TCP protocol tests passed.

TCP protocol variant

This client protocol variant was first tested locally using localhost server, and then the client functionality was verified with the remote reference discord server.

Local server

Client local testing was done be using ncat program, which starts listening on specified port, and send manually entered messages to the client application.

Test case

  1. Run the tcpdump to capture the traffic to pcap file.
sudo tcpdump -i lo tcp port 4567 -w test/pcap/local-server.pcap
  1. Open server listening on port 4567 with CRLF messages termination using ncat program.
ncat -l 4567 -C
  1. Run the client application.
./ipk25chat-client -t tcp -s localhost
  1. Send messages between client and server.

Server sent messages marked with orange and received messages with purple color.

AUTH xprochp00 AS ppatrik USING abc123
REPLY NOK IS Auth failed.
AUTH xprochp00 AS ppatrik USING xyz123
REPLY OK IS Auth success.
MSG FROM server IS ppatrik joined the default.
MSG FROM ppatrik IS Hello, world!
JOIN general AS ppatrik
REPLY OK IS Join success.
MSG FROM server IS ppatrik joined general.
BYE FROM ppatrik

Client user inputs marked with purple and received messages with orange color.

/auth xprochp00 abc123 ppatrik
Action Failure: Auth failed.
/auth xprochp00 xyz123 ppatrik
Action Success: Auth success.
server: ppatrik joined the default.
Hello, world!
/join general
Action Success: Join success.
server: ppatrik joined general.
  1. Use Wireshark to analyze the captured traffic with IPK25-CHAT plugin.

Local server

Remote server

Client remote testing was done be using reference server anton5.fit.vutbr.cz. Program connects to the server as an authenticated user with student login and personal secret. After authentication the client is automatically joined to the general channel and start to chat with other users or can switch to another channel.

Test case

  1. Run the tcpdump to capture the traffic to pcap file.
sudo tcpdump -i eth0 tcp and host anton5.fit.vutbr.cz and port 4567 -w test/pcap/remote-server.pcap
  1. Run the client application.
./ipk25chat-client -t tcp -s anton5.fit.vutbr.cz
  1. Send and receive messages.

Client inputs marked with green and messages received from the server marked with blue color.

/auth xprochp *-*-*-*-* ppatrik
Action Failure: Authentication failed - No such user identity xprochp with provided secret found.
/auth xprochp00 *-*-*-*-* ppatrik
Server: ppatrik has joined `discord.general` via TCP.
Hello
Server: tesst has joined `discord.general` via TCP.
tesst: heyy
Server: tesst has left `discord.general`.
Server: fifo has joined `discord.general` via TCP.
fifo: adsf
Server: fifo has left `discord.general`.
/join cistafantazia
Action Success: Channel discord.cistafantazia successfully joined.
Server: ppatrik has switched from `discord.general` to `discord.cistafantazia`.
Server: ppatrik has joined `discord.cistafantazia` via TCP.
Aligator, are you here ?

Warning The personal secret is not displayed in the test case visualization, for security reasons.

  1. Use Wireshark to analyze the captured traffic with IPK25-CHAT plugin.

Remote server

Important This documentation was written without any generated sections or other use of AI.

Bibliography

[1] Eddy, W. Transmission Control Protocol (TCP) [online]. August 2022. [cited 2025-04-15]. DOI: 10.17487/RFC9293. Available at: https://datatracker.ietf.org/doc/html/rfc9293

[2] Wikipedia. Transmission Control Protocol [online]. April 2025. [cited 2025-04-15]. Available at: https://en.wikipedia.org/wiki/Transmission_Control_Protocol

[3] Joel M. Winett. The Definition of a Socket [online]. May 1971. [cited 2025-04-15]. Available at: https://datatracker.ietf.org/doc/html/rfc147

[4] Wikipedia. Network socket [online]. February 2025. [cited 2025-04-15]. Available at: https://en.wikipedia.org/wiki/Network_socket

[5] Linux manual page. poll(2) [online]. July 2024. [cited 2025-04-17]. Available at: https://man7.org/linux/man-pages/man2/poll.2.html

[6] Geeksforgeeks. Signals in C language [online]. December 2024. [cited 2025-04-17]. Available at: https://www.geeksforgeeks.org/signals-c-language/

[7] Linux manual page. shutdown(2) [online]. July 2024. [cited 2025-04-17]. Available at: https://man7.org/linux/man-pages/man2/shutdown.2.html

[8] OpenAI. ChatGPT (GPT-4o) [online]. April 2025. How to compare two strings with case insensitive in C++. [cited 2025-04-16]. Available at: https://chatgpt.com/

About

IPK25-CHAT client

Topics

Resources

License

Stars

Watchers

Forks