This project is the implementation of an anonymous chat that runs over a p2p network based on the example project by Carmine Spagnuolo for the ADC class at the Università degli Studi di Salerno.
The main requirement for this work were asynchronous and anonymous communication. We were able to achieve those requirements through the usage of the publish/subscribe paradigm, a well known paradigm in the asynchronous communication literature, and the framework/library TomP2P.
Further information regarding this assignment can be found at the ADC class page.
A user must start a new peer in order to join the network and interact with it.
For better explanation, the lifecycle of a peer can be divided in 3 different stages: Join, Interact and Leave.
To join the network and start chatting a new object AnonymousChatImpl
must be instantiated.
In the constructor, the peer is created and booted on the p2p network through the library functions provided by TomP2P.
Each peer is going to request a DNS table, where peers address and id are stored, and check if another active peer with the same ID is already in the network. Once the peer checked he's the only one with said ID, the table is updated and all the other peers in the network are notified.
Then the peer is going to start a crash detection mechanism. This FD (Failure Detector) is based on a simplified version of the Gossipping Protocol which inquire a random number of network nodes at random intervals to update his local information. This was used to keep the DNS table always updated even if a user didn't perform the shutdown procedure correctly.
After the FD is correctly set up, the peer starts to listen for incoming messages.
Once a peer has been correctly booted into the p2p network, the user can interact with the API through the provided methods:
createRoom(String _room_name)
Check if a room with the same name already exist, if it doesn't create it and set the current peer as room member. If the room exist, checks if at least 1 peer is still active. If all the peers inside the room are crashed, delete the room, notify the network about the changes and start the create procedure again.joinRoom(String _room_name)
Check if a room with the provided name exist and if so join it.leaveRoom(String _room_name)
Check if a room with the provided name exist and the current peer is inside it. If so, remove the peer from the room and if it's empty, delete it.sendMessage(String _room_name, String _text_message)
Check if the room exist and the peer joined it. If so, send a message to all the peers in the room.
A peer that wants to leave the network, can invoke the method leaveNetwork()
. This will update the DNS information, remove the peer from any room he was in and announce the peer shutdown on the network allowing the DHT to update properly.
A support class, ShutDownProcedure
has also been provided in order to be called by a Java Shutdown Hook as it has been done on the example application.
However, those operations are not required, they just relieves some stress on the p2p network, the fault detector will eventually keep the network consistent (eventual consistency).
The package it.adc.p2p.chat
provides 5 Java Classes and 1 Java Interface:
AnonymousChat
Interface that define the publish/subscribe paradigm.AnonymousChatImpl
Class that implements the AnonymousChat interface, exploiting TomP2P library and providing a basic API for anonymous chats.PeerFailureDetector
Class used to implement an asynchronous task that periodically spot crashed peers in the network.MessageListener
Class that implements a listener used by the peers to listen for incoming messages.ShutDownProcedure
Class that define the operations to perform once the JVM exit or is terminated.StartChat
Class that use the provided API to start an example anonymous chat.
The package it.adc.p2p.chat.exceptions
provides 4 Java Exception:
DNSException
Exception triggered when something went wrong during the peers DNS update/creation.DuplicatePeer
Exception triggered when a peer try to join the network with an ID another peer already claimed.FailedMasterPeerBootstrap
Exception triggered when an error occur during the bootstrap to the master peer.NetworkError
Exception triggered when a peer wasn't able to contact the network.
A series of unit tests have been provided in the test package it.adc.p2p.chat
to check out all the API functionalities.
TestAnonymousChat::testCase_DuplicatePeers()
Test that checks the API behavior when there is multiple peers with same ID.TestAnonymousChat::testCase_MasterBootstrapping()
Test that checks different behavior of the API when a correct or incorrect bootstrap to the p2p network happen.TestAnonymousChat::testCase_CreateNonExistingRoom()
Test that checks the API behavior when a peer try to create a new room.TestAnonymousChat::testCase_CreateExistingRoom()
Test that checks the API behavior when a peer try to create a room that already exist.TestAnonymousChat::testCase_JoinRoom()
Test that checks the API behavior when a peer try to join a room that exist and a room that doesn't exist.TestAnonymousChat::testCase_SendMessage()
Test that checks the API behavior when a correct or incorrect message sending is performed.TestAnonymousChat::testCase_LeaveRoom()
Test that checks the API behavior when a peer try to leave a room he already joined, a room he never joined or a room that doesn't exist.
For a better overview of all the plugins and libraries used, check out the pom.xml
in the project root.
This project provides a simple example of an anonymous chat that uses the provided API. To start this example follow the steps below.
Docker must be installed on your machine in order to run this project. Check the official docker get-started page for more information.
- Download the Dockerfile
curl -OL https://raw.githubusercontent.com/Guilty994/liguori_domenico_adc_2021/master/Dockerfile
- Build the Docker image
docker build --no-cache -t anonchat .
- Start a new master peer
docker run --name MASTER -e ID=0 -e MASTERIP="127.0.0.1" -it anonchat
- Check the @container_address
docker ps docker inspect <container ID>
- Start a new peers using the @container_address as MASTERIP and varying the unique @peerid ∈ [1, +∞]
docker run --name PEER_[peer id] -e ID=@peerid -e MASTERIP="@container_address" -it anonchat