#ifndef SERVER_H
#define SERVER_H

#include <stdint.h>

// Message types
#define MESSAGE_TYPE_REGULAR 0
#define MESSAGE_TYPE_END 1

// Maximum message size
#define MAX_MESSAGE_SIZE 1024

#pragma pack(push, 1)
struct RegularMessage {
  uint8_t type;                                // 1 byte
  uint32_t ip;                                 // 4 bytes
  uint16_t port;                               // 2 bytes
  uint8_t data[MAX_MESSAGE_SIZE - 1 - 2 - 4];  // 1017 bytes
};
#pragma pack(pop)

#endif


A Simple Group Chat Server with Fuzzing Clients

In this task, you will write a simple group chat server program and a client program. The server will accept multiple clients and relay client messages back to the clients. Each client, on the other hand, will be a fuzzer generating messages and sending and receiving those messages to and from the server.
Group Chat Server

The group chat server accepts client connections, receives client messages, and echoes those messages back to all clients. The following are the requirements of the server.
* The command-line interface should be able to start the server as follows. $ ./server <port number> <# of clients>  
* The executable of your server should be named server.
* The server should bind to port port number.
* <# of clients> is the expected number of clients.
    * A client can join any time and leave any time.
    * You do not need to handle cases where this number is just too big and our container cannot handle that many clients. We will not test with more than 100 clients.
* The server should use AF_INET.
* The server should bind to all available IP addresses for the local host.
* The server should receive all messages from each and every client as they send them.
* When the server receives a message from a client, it should send the message to all clients, including the sender.
* Message ordering
    * When a client sends multiple messages, all clients should receive the messages in the original sending order.
    * In addition, all clients should receive all messages in the same order.
        * For example, suppose we have three clients, C0, C1, and C2.
        * Consider the following scenario.
            * C0 sends a message, M0, which is received by the server.
            * C1 then sends a message, M1, which is also received by the server.
            * Lastly, C2 sends a message, M2, which is again received by the server.
        * Based on the above scenario, C0, C1, and C2 should all receive M0 first, M1 next, and then M2.
    * This message ordering is not a trick requirement. It is just what you expect from a group chat room.
* Note: the simplest way to test a server is to use telnet <IP> <port>.
    * Suppose your local IP address is 192.168.68.6 and you run the server, which binds to port 8000.
    * telnet 192.168.68.6 8000 will act as a client connected to the server.
    * 127.0.0.1 is a local IP address that refers to the local machine, so telnet 127.0.0.1 8000 will also work.
    * localhost is a host name that refers to the local machine, so telnet localhost 8000 works as well.
    * You can enter messages on your terminal as a standard input to telnet and they will be sent to the server.
Messaging Protocol

The following is how the server and the clients should format and interpret messages they send and receive.
* For clarity, we use two terms---a group chat message and a message.
    * A group chat message refers to what we would normally call a "message" in the context of a group chat app.
    * A message is a piece of data sent by a client or a server through a socket. As described below, this may or may not contain a group chat message.
* The message size should be no more than 1024 bytes.
* Both for the server side and the client side, a message should always start with a one-byte (uint8_t) "type."
    * 0 means that it is a regular message that contains a group chat message.
        * We refer to this as a type 0 message.
    * 1 means that it is a special "end of execution" message.
        * Two-Phase Commit Protocol below fully explains this.
        * We refer to this as a type 1 message.
* Both for the server and the clients, a new line character '\n' always marks the end of a message.
    * However, you need to be careful with this due to the requirement described next.
* When the server receives a type 0 message from a client, the server should get the sender's address (IP and port) and include the address in the message sent to all clients.
    * Consider a typical group chat app. When a client sends a group chat message, everyone should know who sent it. We achieve this by having the server add the sender's address to each group chat message.
    * The IP address should be of type uint32_t. It should come after the first byte that indicates the type (0).
    * The port number should be of type uint16_t. It should come after the IP address.
    * Note that only the server performs this address inclusion. A client does not do this.
    * Also note that the address and the port number are numbers, uint32_t and uint16_t, respectively. They are not strings. This means that those numbers can contain a byte value that is '\n', which, in our protocol, indicates the end of a message. You need to be careful with this when you send and receive messages.
* In summary, when the server receives a message from a client, it should interpret the first 1 byte as the type. If it is 0, then the server should interpret the rest of the message as a group chat message until it reads '\n'.
    * If it is 1, the server should follow the description in Two-Phase Commit Protocol below.
* Similarly, when a client receives a message from the server, it should interpret the first 1 byte as the type. If it is 0, then the client should interpret the next 4 bytes as the original sender's IP address, the next 2 bytes as the original sender's port number, and the rest as a group chat message until it reads '\n'.
    * If it is 1, the client should follow the description in Two-Phase Commit Protocol below.
Fuzzing Clients

The client program is a simple custom fuzzer that generates messages and sends those messages to the server. It also receives messages sent by the server. It is a custom fuzzer in the sense that it does not use a fuzzing framework such as libFuzzer discussed in A5. The following are the requirements.
* The command-line interface should be able to start a client as follows. $ ./client <IP address> <port number> <# of messages> <log file path>  
* The executable should be named client.
* IP and port are the IP address and the port number of the server, respectively.
* A client should follow the above message protocol when sending and receiving messages.
* After it starts, a client should keep generating and sending random messages. <# of messages> should be the number of messages sent.
    * The random messages should be of type 0.
    * After sending <# of messages> messages, the client should stop sending type 0 messages, and prepare for termination as described below in Two-Phase Commit Protocol.
    * You can use getentropy() to generate random bytes. Read man getentropy to understand how to use it.
    * Since getentropy() gives you random bytes that you may not be able to print out, use the following function to convert it to a hex string. #include <stdint.h>
    * #include <stdio.h>
    * #include <unistd.h>
    * 
    * /*
    *  * `buf` should point to an array that contains random bytes to convert to a
    *  * hex string.
    *  *
    *  * `str` should point to a buffer used to return the hex string of the random
    *  * bytes. The size of the buffer should be twice the size of the random bytes
    *  * (since a byte is two characters in hex) plus one for NULL.
    *  *
    *  * `size` is the size of the `str` buffer.
    *  *
    *  * For example,
    *  *
    *  *   uint8_t buf[10];
    *  *   char str[10 * 2 + 1];
    *  *   getentropy(buf, 10);
    *  *   if (convert(buf, sizeof(buf), str, sizeof(str)) != 0) {
    *  *     exit(EXIT_FAILURE);
    *  *   }
    *  */
    * int convert(uint8_t *buf, ssize_t buf_size, char *str, ssize_t str_size) {
    *   if (buf == NULL || str == NULL || buf_size <= 0 ||
    *       str_size < (buf_size * 2 + 1)) {
    *     return -1;
    *   }
    * 
    *   for (int i = 0; i < buf_size; i++)
    *     sprintf(str + i * 2, "%02X", buf[i]);
    *   str[buf_size * 2] = '\0';
    * 
    *   return 0;
    * }  
* A client should print out each and every type 0 message it receives from the server and store them in a file named <log file path>.
    * Use this format: "%-15s%-10u%s", e.g., printf("%-15s%-10u%s", ip, port, str);
    * For example, 192.267.128.205 9000 9391DE3E275ADB19637D
    * Make sure you print out one message per line. Adjust the format string accordingly regarding the new line character.
* Note that a client should be able to send messages and receive messages concurrently.
Two-Phase Commit Protocol

To gracefully end the execution for both the server and the clients, the server and the clients should collectively implement a simplified two-phase commit protocol signaling the end of execution as follows.
* After sending # of messages messages, each client should send a type 1 message to the server (as opposed to a type 0 message described in Message Protocol). This is to indicate that the client is done sending messages.
* After the server receives a type 1 message from each and every client, it should send a type 1 message to all clients. It should then terminate itself.
* Each client should terminate after receiving a type 1 message from the server.
Code Structure and CMake

* You need to use the same code structure as previous tasks with src/ and include/.
* You also need to write CMakeLists.txt that produces two executables, server and client.A Simple Group Chat Server with Fuzzing Clients
* 
* In this task, you will write a simple group chat server program and a client program. The server will accept multiple clients and relay client messages back to the clients. Each client, on the other hand, will be a fuzzer generating messages and sending and receiving those messages to and from the server.
* Group Chat Server
* 
* The group chat server accepts client connections, receives client messages, and echoes those messages back to all clients. The following are the requirements of the server.
* The command-line interface should be able to start the server as follows. $ ./server <port number> <# of clients>  
* The executable of your server should be named server.
* The server should bind to port port number.
* <# of clients> is the expected number of clients.
    * A client can join any time and leave any time.
    * You do not need to handle cases where this number is just too big and our container cannot handle that many clients. We will not test with more than 100 clients.
* The server should use AF_INET.
* The server should bind to all available IP addresses for the local host.
* The server should receive all messages from each and every client as they send them.
* When the server receives a message from a client, it should send the message to all clients, including the sender.
* Message ordering
    * When a client sends multiple messages, all clients should receive the messages in the original sending order.
    * In addition, all clients should receive all messages in the same order.
        * For example, suppose we have three clients, C0, C1, and C2.
        * Consider the following scenario.
            * C0 sends a message, M0, which is received by the server.
            * C1 then sends a message, M1, which is also received by the server.
            * Lastly, C2 sends a message, M2, which is again received by the server.
        * Based on the above scenario, C0, C1, and C2 should all receive M0 first, M1 next, and then M2.
    * This message ordering is not a trick requirement. It is just what you expect from a group chat room.
* Note: the simplest way to test a server is to use telnet <IP> <port>.
    * Suppose your local IP address is 192.168.68.6 and you run the server, which binds to port 8000.
    * telnet 192.168.68.6 8000 will act as a client connected to the server.
    * 127.0.0.1 is a local IP address that refers to the local machine, so telnet 127.0.0.1 8000 will also work.
    * localhost is a host name that refers to the local machine, so telnet localhost 8000 works as well.
    * You can enter messages on your terminal as a standard input to telnet and they will be sent to the server.
* Messaging Protocol
* 
* The following is how the server and the clients should format and interpret messages they send and receive.
* For clarity, we use two terms---a group chat message and a message.
    * A group chat message refers to what we would normally call a "message" in the context of a group chat app.
    * A message is a piece of data sent by a client or a server through a socket. As described below, this may or may not contain a group chat message.
* The message size should be no more than 1024 bytes.
* Both for the server side and the client side, a message should always start with a one-byte (uint8_t) "type."
    * 0 means that it is a regular message that contains a group chat message.
        * We refer to this as a type 0 message.
    * 1 means that it is a special "end of execution" message.
        * Two-Phase Commit Protocol below fully explains this.
        * We refer to this as a type 1 message.
* Both for the server and the clients, a new line character '\n' always marks the end of a message.
    * However, you need to be careful with this due to the requirement described next.
* When the server receives a type 0 message from a client, the server should get the sender's address (IP and port) and include the address in the message sent to all clients.
    * Consider a typical group chat app. When a client sends a group chat message, everyone should know who sent it. We achieve this by having the server add the sender's address to each group chat message.
    * The IP address should be of type uint32_t. It should come after the first byte that indicates the type (0).
    * The port number should be of type uint16_t. It should come after the IP address.
    * Note that only the server performs this address inclusion. A client does not do this.
    * Also note that the address and the port number are numbers, uint32_t and uint16_t, respectively. They are not strings. This means that those numbers can contain a byte value that is '\n', which, in our protocol, indicates the end of a message. You need to be careful with this when you send and receive messages.
* In summary, when the server receives a message from a client, it should interpret the first 1 byte as the type. If it is 0, then the server should interpret the rest of the message as a group chat message until it reads '\n'.
    * If it is 1, the server should follow the description in Two-Phase Commit Protocol below.
* Similarly, when a client receives a message from the server, it should interpret the first 1 byte as the type. If it is 0, then the client should interpret the next 4 bytes as the original sender's IP address, the next 2 bytes as the original sender's port number, and the rest as a group chat message until it reads '\n'.
    * If it is 1, the client should follow the description in Two-Phase Commit Protocol below.
* Fuzzing Clients
* 
* The client program is a simple custom fuzzer that generates messages and sends those messages to the server. It also receives messages sent by the server. It is a custom fuzzer in the sense that it does not use a fuzzing framework such as libFuzzer discussed in A5. The following are the requirements.
* The command-line interface should be able to start a client as follows. $ ./client <IP address> <port number> <# of messages> <log file path>  
* The executable should be named client.
* IP and port are the IP address and the port number of the server, respectively.
* A client should follow the above message protocol when sending and receiving messages.
* After it starts, a client should keep generating and sending random messages. <# of messages> should be the number of messages sent.
    * The random messages should be of type 0.
    * After sending <# of messages> messages, the client should stop sending type 0 messages, and prepare for termination as described below in Two-Phase Commit Protocol.
    * You can use getentropy() to generate random bytes. Read man getentropy to understand how to use it.
    * Since getentropy() gives you random bytes that you may not be able to print out, use the following function to convert it to a hex string. #include <stdint.h>
    * #include <stdio.h>
    * #include <unistd.h>
    * 
    * /*
    *  * `buf` should point to an array that contains random bytes to convert to a
    *  * hex string.
    *  *
    *  * `str` should point to a buffer used to return the hex string of the random
    *  * bytes. The size of the buffer should be twice the size of the random bytes
    *  * (since a byte is two characters in hex) plus one for NULL.
    *  *
    *  * `size` is the size of the `str` buffer.
    *  *
    *  * For example,
    *  *
    *  *   uint8_t buf[10];
    *  *   char str[10 * 2 + 1];
    *  *   getentropy(buf, 10);
    *  *   if (convert(buf, sizeof(buf), str, sizeof(str)) != 0) {
    *  *     exit(EXIT_FAILURE);
    *  *   }
    *  */
    * int convert(uint8_t *buf, ssize_t buf_size, char *str, ssize_t str_size) {
    *   if (buf == NULL || str == NULL || buf_size <= 0 ||
    *       str_size < (buf_size * 2 + 1)) {
    *     return -1;
    *   }
    * 
    *   for (int i = 0; i < buf_size; i++)
    *     sprintf(str + i * 2, "%02X", buf[i]);
    *   str[buf_size * 2] = '\0';
    * 
    *   return 0;
    * }  
* A client should print out each and every type 0 message it receives from the server and store them in a file named <log file path>.
    * Use this format: "%-15s%-10u%s", e.g., printf("%-15s%-10u%s", ip, port, str);
    * For example, 192.267.128.205 9000 9391DE3E275ADB19637D
    * Make sure you print out one message per line. Adjust the format string accordingly regarding the new line character.
* Note that a client should be able to send messages and receive messages concurrently.
* Two-Phase Commit Protocol
* 
* To gracefully end the execution for both the server and the clients, the server and the clients should collectively implement a simplified two-phase commit protocol signaling the end of execution as follows.
* After sending # of messages messages, each client should send a type 1 message to the server (as opposed to a type 0 message described in Message Protocol). This is to indicate that the client is done sending messages.
* After the server receives a type 1 message from each and every client, it should send a type 1 message to all clients. It should then terminate itself.
* Each client should terminate after receiving a type 1 message from the server.
* Code Structure and CMake
* 
* You need to use the same code structure as previous tasks with src/ and include/.
* 	•	You also need to write CMakeLists.txt that produces two executables, server and client.