From b5da76720f57a331c1491dccb601444b0f0bde7f Mon Sep 17 00:00:00 2001
From: Andrei Stan <andreistan2003@gmail.com>
Date: Thu, 14 Nov 2024 00:02:49 +0200
Subject: [PATCH] {README,src}: Update statement and fix linter

Signed-off-by: Andrei Stan <andreistan2003@gmail.com>
---
 README.md         | 79 ++++++++++++++++++++++++++++++-----------------
 src/Makefile      |  2 +-
 src/consumer.c    |  4 ++-
 src/consumer.h    |  9 +++---
 src/firewall.c    |  2 +-
 src/packet.h      | 11 +++++--
 src/producer.h    |  2 +-
 src/ring_buffer.h |  2 +-
 8 files changed, 69 insertions(+), 42 deletions(-)

diff --git a/README.md b/README.md
index dba22a0..b7b33e4 100644
--- a/README.md
+++ b/README.md
@@ -8,15 +8,31 @@
 
 ## Statement
 
-A firewall is a program that checks network packets against a series of filters which provide a decision regarding dropping or allowing the packets to continue to the uppper level in the TCP/IP stack.
-In the case of this project, instead of a network card, there will be a producer thread that buffers packets into a circular buffer, out of which consumer threads will take packets and process them in order to decide whether they advance to the upper levels of the stack.
-You will have to implement the circular buffer and the consumer threads in order to provide a log file with the firewall's decisions ordered by a timestamp.
+A firewall is a program that checks network packets against a series of filters which provide a decision regarding dropping or allowing the packets to continue to their intended destination.
+
+**In a real setup**, the network card will receive real packets (e.g. packets having [`Ethernet`](https://en.wikipedia.org/wiki/Ethernet_frame), [`IP`](https://en.wikipedia.org/wiki/IPv4) headers plus payload) from the network and will send them to the firewall for processing.
+The firewall will decide if the packets are to be dropped or not and, if not, passes them further.
+
+**In this assignment**, instead of real network packets, we'll deal with made up packets consisting of a made up source (a number), a made up destination (also a number), a timestamp (also a number) and some payload.
+And instead of the network card providing the packets, we'll have a **producer thread** creating these packets.
+
+The created packets will be inserted into a [`circular buffer`](https://en.wikipedia.org/wiki/Circular_buffer), out of which **consumer threads** (which implement the firewall logic) will take packets and process them in order to decide whether they advance to the destination.
+
+The result of this processing is a log file in which the firewall will record the decision taken (PASS or DROP) for each packet, along with other information such as timestamp.
+
+The purpose of this assignment is to:
+
+- implement the circular buffer, along with synchronization mechanisms for it to work in a multithreaded program
+
+- implement the consumer threads, which consume packets and process them
+
+- provide the log file containing the result of the packet processing
 
 ## Support Code
 
 The support code consists of the directories:
 
-- `src/` contains the skeleton for the parallelized firewall and the already implemented serial code.
+- `src/` contains the skeleton for the parallelized firewall and the already implemented serial code in `src/serial.c`.
   You will have to implement the missing parts marked as `TODO`
 
 - `utils/` contains utility files used for debugging and logging.
@@ -37,6 +53,7 @@ When there are new packets that need to be handled, the `consumer` threads must
 **Waiting in a `while()` loop or sleeping is not considered a valid synchronization mechanism and points will be deducted.**
 
 Implement the `consumer` related functions marked with `TODO` in the `src/consumer.c` file.
+**The number of consumer threads will be passed as the 3rd command-line argument**
 
 ### Ring Buffers
 
@@ -49,12 +66,12 @@ Thus, the shared ring buffer offers the following fields:
 - `cap` the size of the internal buffer.
 - `data` pointer to the internal buffer.
 
-Apart from these fields you have to add syncronization primitives in order to allow multiple threads to access the ring buffer in a deterministic manner.
+Apart from these fields you have to add synchronization primitives in order to allow multiple threads to access the ring buffer in a deterministic manner.
 You can use mutexes, semaphores, conditional variables and other synchronization mechanisms offered by the `pthread` library.
 
 You will have to implement the following interface for the ring buffer:
 
-- `ring_buffer_init()`: initialize the ring buffer (allocate memory and syncronization primitives).
+- `ring_buffer_init()`: initialize the ring buffer (allocate memory and synchronization primitives).
 - `ring_buffer_enqueue()`: add elements to the ring buffer.
 - `ring_buffer_dequeue()`: remove elements from the ring buffer.
 - `ring_buffer_destroy()`: free up the memory used by the ring_buffer.
@@ -65,12 +82,15 @@ You will have to implement the following interface for the ring buffer:
 The output of the firewall will be a log file with the rows containing the firewall's decision, the hash of the packet and its timestamp.
 The actual format can be found in the serial implementation (at `src/serial.c`).
 
-When parallelly processing the packets the threads will finish up the work in a non deterministic order.
+When processing the packets in parallel the threads will finish up the work in a non deterministic order.
+The packet processing functions are already implemented in `src/packet.c`
+
 We would like the logs to be sorted by the packet timestamp, the order that they came in from the producer.
 Thus, the `consumers` should insert the packet information to the log file such as the result is ordered by timestamp.
+The printing format can be found in `./src/serial.c`
 
 The logs must be written to the file in ascending order during packet processing.
-**Sorting the log file after the consumer threads have finshed processing is not considered a valid synchronization mechanism and points will be deducted.**
+**Sorting the log file after the consumer threads have finished processing is not considered a valid synchronization mechanism and points will be deducted.**
 
 ## Operations
 
@@ -121,7 +141,8 @@ When using `grade.sh` you will get a maximum of 90/100 points for general correc
 ### Restrictions
 
 - Threads must yield the cpu when waiting for empty/full buffers i.e. not doing `busy waiting`.
-- The logs must be written as they are processed and not after the processing is done and ordered scendingly by the timestamp.
+- The logs must be written as they are processed and not after the processing is done, in ascending order by the timestamp.
+- The number of running threads must be at least `num_consumers + 1`, where `num_consumers` is the 3rd command-line argument of the `firewall` binary.
 
 ### Grades
 
@@ -139,26 +160,26 @@ A successful run will show the output:
 ```console
 student@so:~/.../assignments/parallel-firewall/tests$ make check
 [...]
-Test [    10 packets, sort False, 1 thread ] ...................... passed ... 3  
-Test [ 1,000 packets, sort False, 1 thread ] ...................... passed ... 3  
-Test [20,000 packets, sort False, 1 thread ] ...................... passed ... 4  
-Test [    10 packets, sort True , 2 threads] ...................... passed ... 5  
-Test [    10 packets, sort True , 4 threads] ...................... passed ... 5  
-Test [   100 packets, sort True , 2 threads] ...................... passed ... 5  
-Test [   100 packets, sort True , 4 threads] ...................... passed ... 5  
-Test [ 1,000 packets, sort True , 2 threads] ...................... passed ... 5  
-Test [ 1,000 packets, sort True , 4 threads] ...................... passed ... 5  
-Test [10,000 packets, sort True , 2 threads] ...................... passed ... 5  
-Test [10,000 packets, sort True , 4 threads] ...................... passed ... 5  
-Test [20,000 packets, sort True , 2 threads] ...................... passed ... 5  
-Test [20,000 packets, sort True , 4 threads] ...................... passed ... 5  
-Test [ 1,000 packets, sort False, 4 threads] ...................... passed ... 5  
-Test [ 1,000 packets, sort False, 8 threads] ...................... passed ... 5  
-Test [10,000 packets, sort False, 4 threads] ...................... passed ... 5  
-Test [10,000 packets, sort False, 8 threads] ...................... passed ... 5  
-Test [20,000 packets, sort False, 4 threads] ...................... passed ... 5  
-Test [20,000 packets, sort False, 8 threads] ...................... passed ... 5  
-                                                                                  
+Test [    10 packets, sort False, 1 thread ] ...................... passed ... 3
+Test [ 1,000 packets, sort False, 1 thread ] ...................... passed ... 3
+Test [20,000 packets, sort False, 1 thread ] ...................... passed ... 4
+Test [    10 packets, sort True , 2 threads] ...................... passed ... 5
+Test [    10 packets, sort True , 4 threads] ...................... passed ... 5
+Test [   100 packets, sort True , 2 threads] ...................... passed ... 5
+Test [   100 packets, sort True , 4 threads] ...................... passed ... 5
+Test [ 1,000 packets, sort True , 2 threads] ...................... passed ... 5
+Test [ 1,000 packets, sort True , 4 threads] ...................... passed ... 5
+Test [10,000 packets, sort True , 2 threads] ...................... passed ... 5
+Test [10,000 packets, sort True , 4 threads] ...................... passed ... 5
+Test [20,000 packets, sort True , 2 threads] ...................... passed ... 5
+Test [20,000 packets, sort True , 4 threads] ...................... passed ... 5
+Test [ 1,000 packets, sort False, 4 threads] ...................... passed ... 5
+Test [ 1,000 packets, sort False, 8 threads] ...................... passed ... 5
+Test [10,000 packets, sort False, 4 threads] ...................... passed ... 5
+Test [10,000 packets, sort False, 8 threads] ...................... passed ... 5
+Test [20,000 packets, sort False, 4 threads] ...................... passed ... 5
+Test [20,000 packets, sort False, 8 threads] ...................... passed ... 5
+
 Checker:                                                                    90/100
 ```
 
diff --git a/src/Makefile b/src/Makefile
index b26921e..30cc2bb 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,7 +4,7 @@ CPPFLAGS := -I$(UTILS_PATH)
 CFLAGS := -Wall -Wextra
 
 CFLAGS += -ggdb -O0
-LDLIBS := -lpthread 
+LDLIBS := -lpthread
 
 SRCS:= ring_buffer.c producer.c consumer.c packet.c $(UTILS_PATH)/log/log.c
 HDRS := $(patsubst %.c,%.h,$(SRCS))
diff --git a/src/consumer.c b/src/consumer.c
index 192d852..4c349d2 100644
--- a/src/consumer.c
+++ b/src/consumer.c
@@ -26,7 +26,9 @@ int create_consumers(pthread_t *tids,
 	(void) out_filename;
 
 	for (int i = 0; i < num_consumers; i++) {
-		/* TODO: Launch consumer threads */
+		/*
+		 * TODO: Launch consumer threads
+		 **/
 	}
 
 	return num_consumers;
diff --git a/src/consumer.h b/src/consumer.h
index 891681c..70a911c 100644
--- a/src/consumer.h
+++ b/src/consumer.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: BSD-3-Clause
+/* SPDX-License-Identifier: BSD-3-Clause */
 
 #ifndef __SO_CONSUMER_H__
 #define __SO_CONSUMER_H__
@@ -13,9 +13,8 @@ typedef struct so_consumer_ctx_t {
 } so_consumer_ctx_t;
 
 int create_consumers(pthread_t *tids,
-					 int num_consumers,
-		 			 so_ring_buffer_t *rb,
-					 const char *out_filename);
+					int num_consumers,
+					so_ring_buffer_t *rb,
+					const char *out_filename);
 
 #endif /* __SO_CONSUMER_H__ */
-
diff --git a/src/firewall.c b/src/firewall.c
index 3b4b4a4..10c7e31 100644
--- a/src/firewall.c
+++ b/src/firewall.c
@@ -68,7 +68,7 @@ int main(int argc, char **argv)
 	/* start publishing data */
 	publish_data(&ring_buffer, argv[1]);
 
-	/* TODO: wait for child processes to finish execution*/
+	/* TODO: wait for child threads to finish execution*/
 	(void) threads;
 
 	free(thread_ids);
diff --git a/src/packet.h b/src/packet.h
index d2dac42..6a45f8a 100644
--- a/src/packet.h
+++ b/src/packet.h
@@ -1,8 +1,13 @@
-// SPDX-License-Identifier: BSD-3-Clause
+/* SPDX-License-Identifier: BSD-3-Clause */
 
 #ifndef __SO_PACKET_H__
 #define __SO_PACKET_H__
 
+/* For pleasing the checkpatch. */
+#ifndef __packed
+#define __packed __attribute((__packed__))
+#endif /* __packed */
+
 #define PKT_SZ 256
 
 typedef enum {
@@ -12,13 +17,13 @@ typedef enum {
 
 #define RES_TO_STR(decision) ((decision == PASS) ? "PASS" : "DROP")
 
-typedef struct __attribute__((packed)) so_hdr_t {
+typedef struct __packed so_hdr_t {
 	unsigned int source;
 	unsigned int dest;
 	unsigned long timestamp;
 } so_hdr_t;
 
-typedef struct __attribute__((packed)) so_packet_t {
+typedef struct __packed so_packet_t {
 	so_hdr_t hdr;
 	char payload[PKT_SZ - sizeof(so_hdr_t)];
 } so_packet_t;
diff --git a/src/producer.h b/src/producer.h
index 7cef1dc..1ee9663 100644
--- a/src/producer.h
+++ b/src/producer.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: BSD-3-Clause
+/* SPDX-License-Identifier: BSD-3-Clause */
 
 #ifndef __SO_PRODUCER_H__
 #define __SO_PRODUCER_H__
diff --git a/src/ring_buffer.h b/src/ring_buffer.h
index ca0717f..b3b66af 100644
--- a/src/ring_buffer.h
+++ b/src/ring_buffer.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: BSD-3-Clause
+/* SPDX-License-Identifier: BSD-3-Clause */
 
 #ifndef __SO_RINGBUFFER_H__
 #define __SO_RINGBUFFER_H__
-- 
GitLab