This commit is contained in:
louiscklaw
2025-01-31 19:24:01 +08:00
parent 1d3678b2fb
commit 4afadb4bfd
54 changed files with 2604 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,2 @@
# Use the Google style in this project.
BasedOnStyle: Google

View File

@@ -0,0 +1,12 @@
.vagrant
*.log
*.o
project-1_elec3120/client
project-1_elec3120/receiver
project-1_elec3120/sender
project-1_elec3120/server
project-1_elec3120/tests/testing_server
**/*.pyc
**/handin.tar.gz
**/*.pcap
!**/test.pcap

View File

@@ -0,0 +1,24 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
fail_fast: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://gitlab.com/daverona/pre-commit-cpp
rev: 0.8.0 # use the most recent version
hooks:
- id: clang-format # formatter of C/C++ code based on a style guide: LLVM, Google, Chromium, Mozilla, and WebKit available
args: ["-style=Google"]
- id: cpplint # linter (or style-error checker) for Google C++ Style Guide
- id: cppcheck # static analyzer of C/C++ code
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
args: ["--line-length", "79"]

View File

@@ -0,0 +1,3 @@
filter=-legal/copyright
filter=-build/include,-build/c++11
filter=-readability/casting

View File

@@ -0,0 +1,5 @@
Copyright (C) 2023 Carnegie Mellon University and Hong Kong University of Science and Technology
This repository is adopted from the TCP in the Wild course project from the Computer Networks course taught at Carnegie Mellon University, and is used for the Computer Networks (ELEC 3120) course taught at Hong Kong University of Science and Technology.
No part of the project may be copied and/or distributed without the express permission of the course staff. Everyone is prohibited from releasing their forks in any public places.

View File

@@ -0,0 +1,155 @@
# ELEC 3120 Project 1: TCP in the Wild
Welcome to Project 1! Please read the handout and starter code thoroughly before you begin. This README contains a quick summary to get your testing environment set up.
## Setting up the environment
You can use Vagrant and Docker to automatically setup the environment. This should work both on Linux as well as on macOS (including Apple Silicon macs).
Start by downloading and installing [Vagrant](https://www.vagrantup.com/downloads) and [Docker](https://docs.docker.com/desktop/). For macOS, you may use homebrew to install Vagrant but **do not** use homebrew to install Docker. Instead, download Docker Desktop from the link above.
Install Vagrant and Docker:
```bash
# In Azure instance terminal under Ubuntu environment
# In the project directory
bash install_env.sh
```
Once you have both Vagrant and Docker Desktop installed, navigate inside this repo and run:
```bash
# In your project root folder where your Vagrantfile is located
vagrant up --provider=docker # builds the server and client containers using Docker.
vagrant ssh {client | server} # connects to either the client or server using SSH.
```
Vagrant keeps all files synchronized between your host machine and the two containers. In other words, the code will update automatically on the containers as you edit it on your computer. Similarly, debugging files and other files generated on the containers will automatically appear on your host machine.
## Files
The following files have been provided for you:
* `backend.c`: This file contains the backend code that will run in a separate thread from the application. This is where most of your logic should go. The backend should deal with most of the TCP functionality, including the state machine, timeouts, retransmissions, buffering, congestion control, etc.
* `cmu_tcp.c`: This contains the main socket functions required of your TCP socket including reading, writing, opening and closing. Since TCP needs to works asynchronously with the application, these functions are relatively simple and interact with the backend running in a separate thread.
* `Vagrantfile`: Defines the structure, IP addresses, and dependencies in the containers. Feel free to modify this file to add any additional testing tools as you see fit. Remember to document your changes in `tests.txt`!
* `README.md`: A description of your files, as well as your algorithm, if you choose to implement it in CP2.
* `tests.txt`: A brief writeup describing your testing strategy, and any tools you used in the process of testing.
* `gen_graph.py`: Takes in a PCAP file and generates a graph. Feel free to modify this file to profile Reno and your own algorithm in CP2.
* `capture_packets.sh`: Captures packets from the server and client containers and saves them to a PCAP file.
* `tcp.lua`: A Lua plugin that allows Wireshark to decode CMU-TCP headers. Copy the file to the directory described in <https://www.wireshark.org/docs/wsug_html_chunked/ChPluginFolders.html> to use the plugin.
* `test_cp1.py`: Test script for CP1 that is executed with `make test`. You should add your own tests to this file.
* `test_cp2.py`: Test script for CP2 that can be executed with `make test`. You should add your own tests to this file.
* `grading.h`: These are variables that we will use to test your implementation. We will be replacing this file when running tests, and hence you should test your implementation with different values.
* `server.c`: An application using the server side of your transport protocol. We will test your code using a different server program, so do not keep any variables or functions here that your protocol uses.
* `client.c`: An application using the client side of your transport protocol. We will test your code using a different client application, so do not keep any variables or functions here that your protocol uses.
* `cmu_packet.h`: This file describes the basic packet format and header and provides helper functions that will help you handle packets. You are not allowed to modify this file! The scripts that we provide to help you graph your packet traces rely on this file being unchanged. All the communication between your server and client will use UDP as the underlying protocol. All packets will begin with the common header described as follows:
* Course Number [4 bytes]
* Source Port [2 bytes]
* Destination Port [2 bytes]
* Sequence Number [4 bytes]
* Acknowledgement Number [4 bytes]
* Header Length [2 bytes]
* Packet Length [2 bytes]
* Flags [1 byte]
* Advertised Window [2 bytes]
* Extension length [2 bytes]
* Extension Data [You may use it when designing your own congestion control algorithm]
## Manual test
You can manually test your code by running the server and client applications in the containers while also capturing packets using `capture_packets.sh`. You can then use the same script or [Wireshark](https://www.wireshark.org/#download) to view the packets.
Open two terminals. One will be used to access the server container and the other will be used to access the client container.
On the **server** terminal:
```bash
# Access the server container and navigate to the project directory.
vagrant ssh server
cd /vagrant/project-1_elec3120/
# Compile.
make
# Start packet capture.
./utils/capture_packets.sh start cap.pcap
# Start the server.
./server
```
On the **client** terminal:
```bash
# Access the client container and navigate to the project directory.
vagrant ssh client
cd /vagrant/project-1_elec3120/
# Note that you don't need to recompile the code here as we already did it on the server and the code is synchronized between the two containers.
# Start the client.
./client
```
Once the server is done. Stop the packet capture and analyze the packets. In the **server** terminal:
```bash
# Stop the packet capture.
./utils/capture_packets.sh stop cap.pcap
# Analyze the packets.
./utils/capture_packets.sh analyze cap.pcap
```
You can also access the capture file (`cap.pcap` in this example) from your host machine and open it with Wireshark. You should use the `utils/tcp.lua` plugin to decode CMU-TCP headers. To do so, copy the file to the directory described in <https://www.wireshark.org/docs/wsug_html_chunked/ChPluginFolders.html>.
## Automatic tests
You should also run automatic tests. On either the client or server container, navigate to `/vagrant/project-1_elec3120/` and run:
```bash
make test
```
Note that the test files are _incomplete_! You are expected to build upon them and write more extensive tests (doing so will help you write better code and save you grief during debugging)!
## Submission
To submit your code to Gradescope, make sure that all the files that should be included are committed and then run:
```bash
./utils/prepare_submission.sh
```
This will generate a file called `handin.tar.gz` at the repository's root directory. Upload this file to Gradescope.
## [Optional] Automatic code formatting and analysis
We provided a [pre-commit](https://pre-commit.com/) configuration file that you can use to automatically format and statically check your code whenever you commit. Either use the pre-commit already installed in one of the containers or install it in your local machine:
```bash
pip3 install pre-commit
```
And then run the following command in the root directory of this repo to install the pre-commit hook:
```bash
pre-commit install
```
Now, pre-commit will automatically run whenever you commit. If you want to run it manually, you can run:
```bash
make format
```
## [Optional]SSH login remote server
Using username and password to log in to your instance:
```bash
ssh username@IP_address
```
For convenience, you can also use the public key to login without password: [ssh_setting](ssh_connection.md)

View File

@@ -0,0 +1,56 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
$VAGRANT_EXTRA_STEPS = <<~SCRIPT
git config --global --add safe.directory '*'
echo "cd /vagrant" >> /home/vagrant/.bashrc
SCRIPT
$SET_NETWORK = <<~'SCRIPT'
IFNAME=$(ifconfig | grep -B1 10.0.1. | grep -o "^\w*")
echo "export IFNAME=$IFNAME" >> /home/vagrant/.bashrc
sudo echo "export IFNAME=$IFNAME" >> /root/.bashrc
sudo tcset $IFNAME --rate 100Mbps --delay 20ms
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' \
/etc/ssh/sshd_config
sudo service sshd restart
SCRIPT
Vagrant.configure(2) do |config|
config.ssh.forward_agent = true
config.vm.synced_folder "project-1_elec3120", "/vagrant/project-1_elec3120"
config.vm.provision "shell",
inline: "sudo /vagrant/project-1_elec3120/setup/setup.sh"
config.vm.provision "shell", inline: $VAGRANT_EXTRA_STEPS
config.ssh.insert_key = false
config.vm.provider "docker" do |docker, override|
override.vm.box = nil
docker.image = "rofrano/vagrant-provider:ubuntu-22.04"
docker.remains_running = true
docker.has_ssh = true
docker.privileged = true
docker.create_args = ["--cgroupns=host"]
docker.volumes = ["/sys/fs/cgroup:/sys/fs/cgroup:rw"]
end
config.vm.provider "virtualbox" do |v, override|
override.vm.box = "ubuntu/jammy64"
end
config.vm.define :client, primary: true do |host|
host.vm.hostname = "client"
host.vm.network "private_network", ip: "10.0.1.2", netmask: 8,
mac: "080027a7feb1", virtualbox__intnet: "15441"
host.vm.provision "shell", inline: $SET_NETWORK
end
config.vm.define :server do |host|
host.vm.hostname = "server"
host.vm.network "private_network", ip: "10.0.1.1", netmask: 8,
mac: "08002722471c", virtualbox__intnet: "15441"
host.vm.provision "shell", inline: $SET_NETWORK
end
end

View File

@@ -0,0 +1,28 @@
# install vagrant
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install -y vagrant
# install docker
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# add docker permition
sudo groupadd -f docker
sudo usermod -aG docker $USER
newgrp docker

Binary file not shown.

View File

@@ -0,0 +1,32 @@
TOP_DIR = .
INC_DIR = $(TOP_DIR)/inc
SRC_DIR = $(TOP_DIR)/src
BUILD_DIR = $(TOP_DIR)/build
CC=gcc
FLAGS = -pthread -fPIC -g -ggdb -pedantic -Wall -Wextra -DDEBUG -I$(INC_DIR)
OBJS = $(BUILD_DIR)/cmu_packet.o $(BUILD_DIR)/cmu_tcp.o $(BUILD_DIR)/backend.o
all: server client tests/testing_server
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(FLAGS) -c -o $@ $<
server: $(OBJS) $(SRC_DIR)/server.c
$(CC) $(FLAGS) $(SRC_DIR)/server.c -o server $(OBJS)
client: $(OBJS) $(SRC_DIR)/client.c
$(CC) $(FLAGS) $(SRC_DIR)/client.c -o client $(OBJS)
tests/testing_server: $(OBJS)
$(CC) $(FLAGS) tests/testing_server.c -o tests/testing_server $(OBJS)
format:
pre-commit run --all-files
test:
sudo -E python3 tests/test_cp1.py
sudo -E python3 tests/test_cp1_basic_ack_packets.py
clean:
rm -f $(BUILD_DIR)/*.o peer client server
rm -f tests/testing_server

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python3
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
from scapy.all import rdpcap, Raw, IP
import matplotlib.pyplot as plt
# Change this to be your pcap file
# You can capture a pcap file with wireshark or tcpdump
# https://support.rackspace.com/how-to/capturing-packets-with-tcpdump/
FILE_TO_READ = "capture.pcap"
packets = rdpcap(FILE_TO_READ)
packet_list = []
times = []
base = 0
server_port = 15441
num_packets = 0
# This script assumes that only the client is sending data to the server.
for packet in packets:
payload = packet[Raw].load
if IP not in packet:
continue
if int.from_bytes(payload[:4], byteorder="big") != 15441:
continue
# Count the number of data packets going into the network.
if packet[IP].dport == server_port:
hlen = int.from_bytes(payload[16:18], byteorder="big")
plen = int.from_bytes(payload[18:20], byteorder="big")
if plen > hlen: # Data packet
num_packets = num_packets + 1
time = packet.time
if base == 0:
base = time
packet_list.append(num_packets)
times.append(time - base)
# Count the number of ACKs from server to client.
elif packet[IP].sport == server_port:
mask = int.from_bytes(payload[20:21], byteorder="big")
if (mask & 4) == 4: # ACK PACKET
num_packets = max(num_packets - 1, 0)
time = packet.time
if base == 0:
base = time
packet_list.append(num_packets)
times.append(time - base)
if __name__ == "__main__":
# https://matplotlib.org/users/pyplot_tutorial.html for how to format and
# make a good quality graph.
print(packet_list)
plt.scatter(times, packet_list)
plt.savefig("graph.pdf")

View File

@@ -0,0 +1,33 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This file defines the function signatures for the CMU-TCP backend that should
* be exposed. The backend runs in a different thread and handles all the socket
* operations separately from the application.
*/
#ifndef PROJECT_1_ELEC3120_INC_BACKEND_H_
#define PROJECT_1_ELEC3120_INC_BACKEND_H_
/**
* Launches the CMU-TCP backend.
*
* @param in the socket to be used for backend processing.
*/
void* begin_backend(void* in);
#endif // PROJECT_1_ELEC3120_INC_BACKEND_H_

View File

@@ -0,0 +1,182 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
* Defines a CMU-TCP packet and define helper functions to create and manipulate
* packets.
*
* Do NOT modify this file.
*/
#ifndef PROJECT_1_ELEC3120_INC_CMU_PACKET_H_
#define PROJECT_1_ELEC3120_INC_CMU_PACKET_H_
#include <stdint.h>
typedef struct {
uint32_t identifier; // Identifier for the CMU-TCP protocol.
uint16_t source_port; // Source port.
uint16_t destination_port; // Destination port.
uint32_t seq_num; // Sequence number.
uint32_t ack_num; // Acknowledgement number.
uint16_t hlen; // Header length.
uint16_t plen; // Packet length.
uint8_t flags; // Flags.
uint16_t advertised_window; // Advertised window.
uint16_t extension_length; // Extension length.
uint8_t extension_data[]; // Extension data.
} __attribute__((__packed__)) cmu_tcp_header_t;
#define SYN_FLAG_MASK 0x8
#define ACK_FLAG_MASK 0x4
#define FIN_FLAG_MASK 0x2
#define IDENTIFIER 15441
// Maximum Segment Size. Make sure to update this if your CCA requires extension
// data for all packets, as this reduces the payload and thus the MSS.
#define MSS (MAX_LEN - sizeof(cmu_tcp_header_t))
/* Helper functions to get/set fields in the header */
uint16_t get_src(cmu_tcp_header_t* header);
uint16_t get_dst(cmu_tcp_header_t* header);
uint32_t get_seq(cmu_tcp_header_t* header);
uint32_t get_ack(cmu_tcp_header_t* header);
uint16_t get_hlen(cmu_tcp_header_t* header);
uint16_t get_plen(cmu_tcp_header_t* header);
uint8_t get_flags(cmu_tcp_header_t* header);
uint16_t get_advertised_window(cmu_tcp_header_t* header);
uint16_t get_extension_length(cmu_tcp_header_t* header);
uint8_t* get_extension_data(cmu_tcp_header_t* header);
void set_src(cmu_tcp_header_t* header, uint16_t src);
void set_dst(cmu_tcp_header_t* header, uint16_t dst);
void set_seq(cmu_tcp_header_t* header, uint32_t seq);
void set_ack(cmu_tcp_header_t* header, uint32_t ack);
void set_hlen(cmu_tcp_header_t* header, uint16_t hlen);
void set_plen(cmu_tcp_header_t* header, uint16_t plen);
void set_flags(cmu_tcp_header_t* header, uint8_t flags);
void set_advertised_window(cmu_tcp_header_t* header,
uint16_t advertised_window);
void set_extension_length(cmu_tcp_header_t* header, uint16_t extension_length);
void set_extension_data(cmu_tcp_header_t* header, uint8_t* extension_data);
/**
* Sets all the header fields.
*
* Review TCP headers for more information about what each field means.
*
* @param header The header to set the fields.
* @param src Source port.
* @param dst Destination port.
* @param seq Sequence number.
* @param ack Acknowledgement number.
* @param hlen Header length.
* @param plen Packet length.
* @param flags Packet flags.
* @param advertised_window Advertised window.
* @param extension_length Header extension length.
* @param extension_data Header extension data.
*/
void set_header(cmu_tcp_header_t* header, uint16_t src, uint16_t dst,
uint32_t seq, uint32_t ack, uint16_t hlen, uint16_t plen,
uint8_t flags, uint16_t adv_window, uint16_t ext,
uint8_t* ext_data);
/**
* Gets a pointer to the packet payload.
*
* @param pkt The packet to get the payload.
*
* @return A pointer to the payload.
*/
uint8_t* get_payload(uint8_t* pkt);
/**
* Gets the length of the packet payload.
*
* @param pkt The packet to get the payload length.
*
* @return The length of the payload.
*/
uint16_t get_payload_len(uint8_t* pkt);
/**
* Sets the packet payload.
*
* @param pkt The packet to set the payload.
* @param payload A pointer to the payload to be set.
* @param payload_len The length of the payload.
*/
void set_payload(uint8_t* pkt, uint8_t* payload, uint16_t payload_len);
/**
* Allocates and initializes a packet.
*
* @param src The source port.
* @param dst The destination port.
* @param seq The sequence number.
* @param ack The acknowledgement number.
* @param hlen The header length.
* @param plen The packet length.
* @param flags The flags.
* @param adv_window The advertised window.
* @param ext_len The header extension length.
* @param ext_data The header extension data.
* @param payload The payload.
* @param payload_len The length of the payload.
*
* @return A pointer to the newly allocated packet. User must `free` after use.
*/
uint8_t* create_packet(uint16_t src, uint16_t dst, uint32_t seq, uint32_t ack,
uint16_t hlen, uint16_t plen, uint8_t flags,
uint16_t adv_window, uint16_t ext_len, uint8_t* ext_data,
uint8_t* payload, uint16_t payload_len);
/**
* Checks if a given sequence number comes before another sequence number.
*
* @param seq1 the first sequence number.
* @param seq2 the second sequence number.
* @return 1 if seq1 comes before seq2, 0 otherwise.
*/
static inline int before(uint32_t seq1, uint32_t seq2) {
return (int32_t)(seq1 - seq2) < 0;
}
/**
* Checks if a given sequence number comes after another sequence number.
*
* @param seq1 the first sequence number.
* @param seq2 the second sequence number.
* @return 1 if seq1 comes after seq2, 0 otherwise.
*/
static inline int after(uint32_t seq1, uint32_t seq2) {
return before(seq2, seq1);
}
/**
* Checks if a given sequence number is between two others.
*
* @param seq the sequence number.
* @param low the lower bound.
* @param high the upper bound.
* @return 1 if low <= seq <= high, 0 otherwise.
*/
static inline int between(uint32_t seq, uint32_t low, uint32_t high) {
return high - low >= seq - low;
}
#endif // PROJECT_1_ELEC3120_INC_CMU_PACKET_H_

View File

@@ -0,0 +1,145 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This file defines the API for the CMU TCP implementation.
*/
#ifndef PROJECT_1_ELEC3120_INC_CMU_TCP_H_
#define PROJECT_1_ELEC3120_INC_CMU_TCP_H_
#include <netinet/in.h>
#include <pthread.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "cmu_packet.h"
#include "grading.h"
#define EXIT_SUCCESS 0
#define EXIT_ERROR -1
#define EXIT_FAILURE 1
typedef struct {
uint32_t next_seq_expected;
uint32_t last_ack_received;
pthread_mutex_t ack_lock;
} window_t;
/**
* CMU-TCP socket types. (DO NOT CHANGE.)
*/
typedef enum {
TCP_INITIATOR = 0,
TCP_LISTENER = 1,
} cmu_socket_type_t;
/**
* This structure holds the state of a socket. You may modify this structure as
* you see fit to include any additional state you need for your implementation.
*/
typedef struct {
int socket;
pthread_t thread_id;
uint16_t my_port;
struct sockaddr_in conn;
uint8_t* received_buf;
int received_len;
pthread_mutex_t recv_lock;
pthread_cond_t wait_cond;
uint8_t* sending_buf;
int sending_len;
cmu_socket_type_t type;
pthread_mutex_t send_lock;
int dying;
pthread_mutex_t death_lock;
window_t window;
} cmu_socket_t;
/*
* DO NOT CHANGE THE DECLARATIONS BELOW
*/
/**
* Read mode flags supported by a CMU-TCP socket.
*/
typedef enum {
NO_FLAG = 0, // Default behavior: block indefinitely until data is available.
NO_WAIT, // Return immediately if no data is available.
TIMEOUT, // Block until data is available or the timeout is reached.
} cmu_read_mode_t;
/**
* Constructs a CMU-TCP socket.
*
* An Initiator socket is used to connect to a Listener socket.
*
* @param sock The structure with the socket state. It will be initialized by
* this function.
* @param socket_type Indicates the type of socket: Listener or Initiator.
* @param port Port to either connect to, or bind to. (Based on socket_type.)
* @param server_ip IP address of the server to connect to. (Only used if the
* socket is an initiator.)
*
* @return 0 on success, -1 on error.
*/
int cmu_socket(cmu_socket_t* sock, const cmu_socket_type_t socket_type,
const int port, const char* server_ip);
/**
* Closes a CMU-TCP socket.
*
* @param sock The socket to close.
*
* @return 0 on success, -1 on error.
*/
int cmu_close(cmu_socket_t* sock);
/**
* Reads data from a CMU-TCP socket.
*
* If there is data available in the socket buffer, it is placed in the
* destination buffer.
*
* @param sock The socket to read from.
* @param buf The buffer to read into.
* @param length The maximum number of bytes to read.
* @param flags Flags that determine how the socket should wait for data. Check
* `cmu_read_mode_t` for more information. `TIMEOUT` is not
* implemented for CMU-TCP.
*
* @return The number of bytes read on success, -1 on error.
*/
int cmu_read(cmu_socket_t* sock, void* buf, const int length,
cmu_read_mode_t flags);
/**
* Writes data to a CMU-TCP socket.
*
* @param sock The socket to write to.
* @param buf The data to write.
* @param length The number of bytes to write.
*
* @return 0 on success, -1 on error.
*/
int cmu_write(cmu_socket_t* sock, const void* buf, int length);
/*
* You can declare more functions after this point if you need to.
*/
#endif // PROJECT_1_ELEC3120_INC_CMU_TCP_H_

View File

@@ -0,0 +1,43 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This files defines constants used for grading. Do NOT modify this file as
* any changes will be overwritten by the autograder.
*/
#ifndef PROJECT_1_ELEC3120_INC_GRADING_H_
#define PROJECT_1_ELEC3120_INC_GRADING_H_
/*
* DO NOT CHANGE THIS FILE
* This contains the variables for your TCP implementation
* and we will replace this file during the autolab testing with new variables.
*/
// packet lengths
#define MAX_LEN 1400
// window variables
#define WINDOW_INITIAL_WINDOW_SIZE (MSS * 16)
#define WINDOW_INITIAL_SSTHRESH (MSS * 64)
#define WINDOW_INITIAL_RTT 3000 // ms
#define WINDOW_INITIAL_ADVERTISED MSS
// Max TCP Buffer
#define MAX_NETWORK_BUFFER 65535 // (2^16 - 1) bytes
#endif // PROJECT_1_ELEC3120_INC_GRADING_H_

View File

@@ -0,0 +1,56 @@
attrs==22.1.0
bcrypt==4.0.0
certifi==2022.9.24
cffi==1.15.1
chardet==5.0.0
charset-normalizer==2.1.1
contourpy==1.0.5
cryptography==38.0.1
cycler==0.11.0
DataProperty==0.55.0
dbus-python==1.2.18
distro==1.6.0
docker==6.0.0
fabric==2.7.1
fonttools==4.37.4
humanreadable==0.1.0
idna==3.4
iniconfig==1.1.1
invoke==1.7.3
kiwisolver==1.4.4
loguru==0.6.0
matplotlib==3.6.0
mbstrdecoder==1.1.1
msgfy==0.2.0
numpy==1.23.3
packaging==21.3
paramiko==2.11.0
path==16.5.0
pathlib2==2.3.7.post1
pathvalidate==2.5.2
Pillow==9.2.0
pluggy==1.0.0
py==1.11.0
pycparser==2.21
PyGObject==3.42.0
PyNaCl==1.5.0
pyparsing==3.0.9
pyroute2==0.7.3
pytest==7.1.3
python-dateutil==2.8.2
pytz==2022.4
requests==2.28.1
scapy==2.4.5
SimpleSQLite==1.3.0
six==1.16.0
sqliteschema==1.3.0
ssh-import-id==5.11
subprocrunner==2.0.0
tabledata==1.3.0
tcconfig==0.28.0
tomli==2.0.1
typepy==1.3.0
typing==3.7.4.3
urllib3==1.26.12
voluptuous==0.13.1
websocket-client==1.4.1

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential vim \
emacs tree tmux git gdb valgrind python3-dev libffi-dev libssl-dev \
clang-format iperf3 tshark iproute2 iputils-ping net-tools tcpdump cppcheck
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y python3 python3-pip \
python-tk libpython3.10-dev libcairo2 libcairo2-dev pre-commit
pip3 install --upgrade pip
pip3 install -r $SCRIPT_DIR/../requirements.txt

View File

@@ -0,0 +1,277 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This file implements the CMU-TCP backend. The backend runs in a different
* thread and handles all the socket operations separately from the application.
*
* This is where most of your code should go. Feel free to modify any function
* in this file.
*/
#include "backend.h"
#include <poll.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "cmu_packet.h"
#include "cmu_tcp.h"
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
/**
* Tells if a given sequence number has been acknowledged by the socket.
*
* @param sock The socket to check for acknowledgements.
* @param seq Sequence number to check.
*
* @return 1 if the sequence number has been acknowledged, 0 otherwise.
*/
int has_been_acked(cmu_socket_t *sock, uint32_t seq) {
int result;
while (pthread_mutex_lock(&(sock->window.ack_lock)) != 0) {
}
result = after(sock->window.last_ack_received, seq);
pthread_mutex_unlock(&(sock->window.ack_lock));
return result;
}
/**
* Updates the socket information to represent the newly received packet.
*
* In the current stop-and-wait implementation, this function also sends an
* acknowledgement for the packet.
*
* @param sock The socket used for handling packets received.
* @param pkt The packet data received by the socket.
*/
void handle_message(cmu_socket_t *sock, uint8_t *pkt) {
cmu_tcp_header_t *hdr = (cmu_tcp_header_t *)pkt;
uint8_t flags = get_flags(hdr);
switch (flags) {
case ACK_FLAG_MASK: {
uint32_t ack = get_ack(hdr);
if (after(ack, sock->window.last_ack_received)) {
sock->window.last_ack_received = ack;
}
break;
}
default: {
socklen_t conn_len = sizeof(sock->conn);
uint32_t seq = sock->window.last_ack_received;
// No payload.
uint8_t *payload = NULL;
uint16_t payload_len = 0;
// No extension.
uint16_t ext_len = 0;
uint8_t *ext_data = NULL;
uint16_t src = sock->my_port;
uint16_t dst = ntohs(sock->conn.sin_port);
uint32_t ack = get_seq(hdr) + get_payload_len(pkt);
uint16_t hlen = sizeof(cmu_tcp_header_t);
uint16_t plen = hlen + payload_len;
uint8_t flags = ACK_FLAG_MASK;
uint16_t adv_window = 1;
uint8_t *response_packet =
create_packet(src, dst, seq, ack, hlen, plen, flags, adv_window,
ext_len, ext_data, payload, payload_len);
sendto(sock->socket, response_packet, plen, 0,
(struct sockaddr *)&(sock->conn), conn_len);
free(response_packet);
seq = get_seq(hdr);
if (seq == sock->window.next_seq_expected) {
sock->window.next_seq_expected = seq + get_payload_len(pkt);
payload_len = get_payload_len(pkt);
payload = get_payload(pkt);
// Make sure there is enough space in the buffer to store the payload.
sock->received_buf =
realloc(sock->received_buf, sock->received_len + payload_len);
memcpy(sock->received_buf + sock->received_len, payload, payload_len);
sock->received_len += payload_len;
}
}
}
}
/**
* Checks if the socket received any data.
*
* It first peeks at the header to figure out the length of the packet and then
* reads the entire packet.
*
* @param sock The socket used for receiving data on the connection.
* @param flags Flags that determine how the socket should wait for data. Check
* `cmu_read_mode_t` for more information.
*/
void check_for_data(cmu_socket_t *sock, cmu_read_mode_t flags) {
cmu_tcp_header_t hdr;
uint8_t *pkt;
socklen_t conn_len = sizeof(sock->conn);
ssize_t len = 0;
uint32_t plen = 0, buf_size = 0, n = 0;
while (pthread_mutex_lock(&(sock->recv_lock)) != 0) {
}
switch (flags) {
case NO_FLAG:
len = recvfrom(sock->socket, &hdr, sizeof(cmu_tcp_header_t), MSG_PEEK,
(struct sockaddr *)&(sock->conn), &conn_len);
break;
case TIMEOUT: {
// Using `poll` here so that we can specify a timeout.
struct pollfd ack_fd;
ack_fd.fd = sock->socket;
ack_fd.events = POLLIN;
// Timeout after 3 seconds.
if (poll(&ack_fd, 1, 3000) <= 0) {
break;
}
}
// Fallthrough.
case NO_WAIT:
len = recvfrom(sock->socket, &hdr, sizeof(cmu_tcp_header_t),
MSG_DONTWAIT | MSG_PEEK, (struct sockaddr *)&(sock->conn),
&conn_len);
break;
default:
perror("ERROR unknown flag");
}
if (len >= (ssize_t)sizeof(cmu_tcp_header_t)) {
plen = get_plen(&hdr);
pkt = malloc(plen);
while (buf_size < plen) {
n = recvfrom(sock->socket, pkt + buf_size, plen - buf_size, 0,
(struct sockaddr *)&(sock->conn), &conn_len);
buf_size = buf_size + n;
}
handle_message(sock, pkt);
free(pkt);
}
pthread_mutex_unlock(&(sock->recv_lock));
}
/**
* Breaks up the data into packets and sends a single packet at a time.
*
* You should most certainly update this function in your implementation.
*
* @param sock The socket to use for sending data.
* @param data The data to be sent.
* @param buf_len The length of the data being sent.
*/
void single_send(cmu_socket_t *sock, uint8_t *data, int buf_len) {
uint8_t *msg;
uint8_t *data_offset = data;
size_t conn_len = sizeof(sock->conn);
int sockfd = sock->socket;
if (buf_len > 0) {
while (buf_len != 0) {
uint16_t payload_len = MIN(buf_len, MSS);
uint16_t src = sock->my_port;
uint16_t dst = ntohs(sock->conn.sin_port);
uint32_t seq = sock->window.last_ack_received;
uint32_t ack = sock->window.next_seq_expected;
uint16_t hlen = sizeof(cmu_tcp_header_t);
uint16_t plen = hlen + payload_len;
uint8_t flags = 0;
uint16_t adv_window = 1;
uint16_t ext_len = 0;
uint8_t *ext_data = NULL;
uint8_t *payload = data_offset;
msg = create_packet(src, dst, seq, ack, hlen, plen, flags, adv_window,
ext_len, ext_data, payload, payload_len);
buf_len -= payload_len;
while (1) {
// FIXME: This is using stop and wait, can we do better?
sendto(sockfd, msg, plen, 0, (struct sockaddr *)&(sock->conn),
conn_len);
check_for_data(sock, TIMEOUT);
if (has_been_acked(sock, seq)) {
break;
}
}
data_offset += payload_len;
}
}
}
void *begin_backend(void *in) {
cmu_socket_t *sock = (cmu_socket_t *)in;
int death, buf_len, send_signal;
uint8_t *data;
while (1) {
while (pthread_mutex_lock(&(sock->death_lock)) != 0) {
}
death = sock->dying;
pthread_mutex_unlock(&(sock->death_lock));
while (pthread_mutex_lock(&(sock->send_lock)) != 0) {
}
buf_len = sock->sending_len;
if (death && buf_len == 0) {
break;
}
if (buf_len > 0) {
data = malloc(buf_len);
memcpy(data, sock->sending_buf, buf_len);
sock->sending_len = 0;
free(sock->sending_buf);
sock->sending_buf = NULL;
pthread_mutex_unlock(&(sock->send_lock));
single_send(sock, data, buf_len);
free(data);
} else {
pthread_mutex_unlock(&(sock->send_lock));
}
check_for_data(sock, NO_WAIT);
while (pthread_mutex_lock(&(sock->recv_lock)) != 0) {
}
send_signal = sock->received_len > 0;
pthread_mutex_unlock(&(sock->recv_lock));
if (send_signal) {
pthread_cond_signal(&(sock->wait_cond));
}
}
pthread_exit(NULL);
return NULL;
}

View File

@@ -0,0 +1,86 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This file implements a simple CMU-TCP client. Its purpose is to provide
* simple test cases and demonstrate how the sockets will be used.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "cmu_tcp.h"
void functionality(cmu_socket_t *sock) {
uint8_t buf[9898];
int read;
FILE *fp;
cmu_write(sock, "hi there", 8);
cmu_write(sock, " https://www.youtube.com/watch?v=dQw4w9WgXcQ", 44);
cmu_write(sock, " https://www.youtube.com/watch?v=Yb6dZ1IFlKc", 44);
cmu_write(sock, " https://www.youtube.com/watch?v=xvFZjo5PgG0", 44);
cmu_write(sock, " https://www.youtube.com/watch?v=8ybW48rKBME", 44);
cmu_write(sock, " https://www.youtube.com/watch?v=xfr64zoBTAQ", 45);
cmu_read(sock, buf, 200, NO_FLAG);
cmu_write(sock, "hi there", 9);
cmu_read(sock, buf, 200, NO_FLAG);
printf("R: %s\n", buf);
read = cmu_read(sock, buf, 200, NO_WAIT);
printf("Read: %d\n", read);
fp = fopen("/vagrant/project-1_elec3120/src/cmu_tcp.c", "rb");
read = 1;
while (read > 0) {
read = fread(buf, 1, 2000, fp);
if (read > 0) {
cmu_write(sock, buf, read);
}
}
}
int main() {
int portno;
char *serverip;
char *serverport;
cmu_socket_t socket;
serverip = getenv("server15441");
if (!serverip) {
serverip = "10.0.1.1";
}
serverport = getenv("serverport15441");
if (!serverport) {
serverport = "15441";
}
portno = (uint16_t)atoi(serverport);
if (cmu_socket(&socket, TCP_INITIATOR, portno, serverip) < 0) {
exit(EXIT_FAILURE);
}
functionality(&socket);
if (cmu_close(&socket) < 0) {
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,160 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
* This file implements helper functions to create and manipulate packets.
*
* Do NOT modify this file.
*/
#include "cmu_packet.h"
#include <arpa/inet.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
uint16_t get_src(cmu_tcp_header_t* header) {
return ntohs(header->source_port);
}
uint16_t get_dst(cmu_tcp_header_t* header) {
return ntohs(header->destination_port);
}
uint32_t get_seq(cmu_tcp_header_t* header) { return ntohl(header->seq_num); }
uint32_t get_ack(cmu_tcp_header_t* header) { return ntohl(header->ack_num); }
uint16_t get_hlen(cmu_tcp_header_t* header) { return ntohs(header->hlen); }
uint16_t get_plen(cmu_tcp_header_t* header) { return ntohs(header->plen); }
uint8_t get_flags(cmu_tcp_header_t* header) { return header->flags; }
uint16_t get_advertised_window(cmu_tcp_header_t* header) {
return ntohs(header->advertised_window);
}
uint16_t get_extension_length(cmu_tcp_header_t* header) {
return ntohs(header->extension_length);
}
uint8_t* get_extension_data(cmu_tcp_header_t* header) {
return (uint8_t*)(header + 1);
}
void set_src(cmu_tcp_header_t* header, uint16_t src) {
header->source_port = htons(src);
}
void set_dst(cmu_tcp_header_t* header, uint16_t dst) {
header->destination_port = htons(dst);
}
void set_seq(cmu_tcp_header_t* header, uint32_t seq) {
header->seq_num = htonl(seq);
}
void set_ack(cmu_tcp_header_t* header, uint32_t ack) {
header->ack_num = htonl(ack);
}
void set_hlen(cmu_tcp_header_t* header, uint16_t hlen) {
header->hlen = htons(hlen);
}
void set_plen(cmu_tcp_header_t* header, uint16_t plen) {
header->plen = htons(plen);
}
void set_flags(cmu_tcp_header_t* header, uint8_t flags) {
header->flags = flags;
}
void set_advertised_window(cmu_tcp_header_t* header, uint16_t adv_window) {
header->advertised_window = htons(adv_window);
}
void set_extension_length(cmu_tcp_header_t* header, uint16_t ext) {
header->extension_length = htons(ext);
}
void set_extension_data(cmu_tcp_header_t* header, uint8_t* ext_data) {
memcpy(header->extension_data, ext_data, get_extension_length(header));
}
void set_header(cmu_tcp_header_t* header, uint16_t src, uint16_t dst,
uint32_t seq, uint32_t ack, uint16_t hlen, uint16_t plen,
uint8_t flags, uint16_t adv_window, uint16_t ext,
uint8_t* ext_data) {
header->identifier = htonl(IDENTIFIER);
header->source_port = htons(src);
header->destination_port = htons(dst);
header->seq_num = htonl(seq);
header->ack_num = htonl(ack);
header->hlen = htons(hlen);
header->plen = htons(plen);
header->flags = flags;
header->advertised_window = htons(adv_window);
header->extension_length = htons(ext);
memcpy(header->extension_data, ext_data, ext);
}
uint8_t* get_payload(uint8_t* pkt) {
cmu_tcp_header_t* header = (cmu_tcp_header_t*)pkt;
uint16_t ext_len = get_extension_length(header);
int offset = sizeof(cmu_tcp_header_t) + ext_len;
return (uint8_t*)header + offset;
}
uint16_t get_payload_len(uint8_t* pkt) {
cmu_tcp_header_t* header = (cmu_tcp_header_t*)pkt;
return get_plen(header) - get_hlen(header);
}
void set_payload(uint8_t* pkt, uint8_t* payload, uint16_t payload_len) {
cmu_tcp_header_t* header = (cmu_tcp_header_t*)pkt;
uint16_t ext_len = get_extension_length(header);
int offset = sizeof(cmu_tcp_header_t) + ext_len;
memcpy((uint8_t*)header + offset, payload, payload_len);
}
uint8_t* create_packet(uint16_t src, uint16_t dst, uint32_t seq, uint32_t ack,
uint16_t hlen, uint16_t plen, uint8_t flags,
uint16_t adv_window, uint16_t ext_len, uint8_t* ext_data,
uint8_t* payload, uint16_t payload_len) {
if (hlen < sizeof(cmu_tcp_header_t)) {
return NULL;
}
if (plen < hlen) {
return NULL;
}
uint8_t* packet = malloc(sizeof(cmu_tcp_header_t) + payload_len);
if (packet == NULL) {
return NULL;
}
cmu_tcp_header_t* header = (cmu_tcp_header_t*)packet;
set_header(header, src, dst, seq, ack, hlen, plen, flags, adv_window, ext_len,
ext_data);
uint8_t* pkt_payload = get_payload(packet);
memcpy(pkt_payload, payload, payload_len);
return packet;
}

View File

@@ -0,0 +1,201 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This file implements the high-level API for CMU-TCP sockets.
*/
#include "cmu_tcp.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "backend.h"
int cmu_socket(cmu_socket_t *sock, const cmu_socket_type_t socket_type,
const int port, const char *server_ip) {
int sockfd, optval;
socklen_t len;
struct sockaddr_in conn, my_addr;
len = sizeof(my_addr);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
return EXIT_ERROR;
}
sock->socket = sockfd;
sock->received_buf = NULL;
sock->received_len = 0;
pthread_mutex_init(&(sock->recv_lock), NULL);
sock->sending_buf = NULL;
sock->sending_len = 0;
pthread_mutex_init(&(sock->send_lock), NULL);
sock->type = socket_type;
sock->dying = 0;
pthread_mutex_init(&(sock->death_lock), NULL);
// FIXME: Sequence numbers should be randomly initialized. The next expected
// sequence number should be initialized according to the SYN packet from the
// other side of the connection.
sock->window.last_ack_received = 0;
sock->window.next_seq_expected = 0;
pthread_mutex_init(&(sock->window.ack_lock), NULL);
if (pthread_cond_init(&sock->wait_cond, NULL) != 0) {
perror("ERROR condition variable not set\n");
return EXIT_ERROR;
}
switch (socket_type) {
case TCP_INITIATOR:
if (server_ip == NULL) {
perror("ERROR server_ip NULL");
return EXIT_ERROR;
}
memset(&conn, 0, sizeof(conn));
conn.sin_family = AF_INET;
conn.sin_addr.s_addr = inet_addr(server_ip);
conn.sin_port = htons(port);
sock->conn = conn;
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.sin_port = 0;
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) {
perror("ERROR on binding");
return EXIT_ERROR;
}
break;
case TCP_LISTENER:
memset(&conn, 0, sizeof(conn));
conn.sin_family = AF_INET;
conn.sin_addr.s_addr = htonl(INADDR_ANY);
conn.sin_port = htons((uint16_t)port);
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval,
sizeof(int));
if (bind(sockfd, (struct sockaddr *)&conn, sizeof(conn)) < 0) {
perror("ERROR on binding");
return EXIT_ERROR;
}
sock->conn = conn;
break;
default:
perror("Unknown Flag");
return EXIT_ERROR;
}
getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
sock->my_port = ntohs(my_addr.sin_port);
pthread_create(&(sock->thread_id), NULL, begin_backend, (void *)sock);
return EXIT_SUCCESS;
}
int cmu_close(cmu_socket_t *sock) {
while (pthread_mutex_lock(&(sock->death_lock)) != 0) {
}
sock->dying = 1;
pthread_mutex_unlock(&(sock->death_lock));
pthread_join(sock->thread_id, NULL);
if (sock != NULL) {
if (sock->received_buf != NULL) {
free(sock->received_buf);
}
if (sock->sending_buf != NULL) {
free(sock->sending_buf);
}
} else {
perror("ERROR null socket\n");
return EXIT_ERROR;
}
return close(sock->socket);
}
int cmu_read(cmu_socket_t *sock, void *buf, int length, cmu_read_mode_t flags) {
uint8_t *new_buf;
int read_len = 0;
if (length < 0) {
perror("ERROR negative length");
return EXIT_ERROR;
}
while (pthread_mutex_lock(&(sock->recv_lock)) != 0) {
}
switch (flags) {
case NO_FLAG:
while (sock->received_len == 0) {
pthread_cond_wait(&(sock->wait_cond), &(sock->recv_lock));
}
// Fall through.
case NO_WAIT:
if (sock->received_len > 0) {
if (sock->received_len > length)
read_len = length;
else
read_len = sock->received_len;
memcpy(buf, sock->received_buf, read_len);
if (read_len < sock->received_len) {
new_buf = malloc(sock->received_len - read_len);
memcpy(new_buf, sock->received_buf + read_len,
sock->received_len - read_len);
free(sock->received_buf);
sock->received_len -= read_len;
sock->received_buf = new_buf;
} else {
free(sock->received_buf);
sock->received_buf = NULL;
sock->received_len = 0;
}
}
break;
default:
perror("ERROR Unknown flag.\n");
read_len = EXIT_ERROR;
}
pthread_mutex_unlock(&(sock->recv_lock));
return read_len;
}
int cmu_write(cmu_socket_t *sock, const void *buf, int length) {
while (pthread_mutex_lock(&(sock->send_lock)) != 0) {
}
if (sock->sending_buf == NULL)
sock->sending_buf = malloc(length);
else
sock->sending_buf = realloc(sock->sending_buf, length + sock->sending_len);
memcpy(sock->sending_buf + sock->sending_len, buf, length);
sock->sending_len += length;
pthread_mutex_unlock(&(sock->send_lock));
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,88 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
*
* This file implements a simple CMU-TCP server. Its purpose is to provide
* simple test cases and demonstrate how the sockets will be used.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "cmu_tcp.h"
#define BUF_SIZE 10000
/*
* Param: sock - used for reading and writing to a connection
*
* Purpose: To provide some simple test cases and demonstrate how
* the sockets will be used.
*
*/
void functionality(cmu_socket_t *sock) {
uint8_t buf[BUF_SIZE];
FILE *fp;
int n;
n = cmu_read(sock, buf, BUF_SIZE, NO_FLAG);
printf("R: %s\n", buf);
printf("N: %d\n", n);
cmu_write(sock, "hi there", 9);
n = cmu_read(sock, buf, 200, NO_FLAG);
printf("R: %s\n", buf);
printf("N: %d\n", n);
cmu_write(sock, "https://www.youtube.com/watch?v=dQw4w9WgXcQ", 44);
sleep(1);
n = cmu_read(sock, buf, BUF_SIZE, NO_FLAG);
printf("N: %d\n", n);
fp = fopen("/tmp/file.c", "w");
fwrite(buf, 1, n, fp);
fclose(fp);
}
int main() {
int portno;
char *serverip;
char *serverport;
cmu_socket_t socket;
serverip = getenv("server15441");
if (!serverip) {
serverip = "10.0.1.1";
}
serverport = getenv("serverport15441");
if (!serverport) {
serverport = "15441";
}
portno = (uint16_t)atoi(serverport);
if (cmu_socket(&socket, TCP_LISTENER, portno, serverip) < 0) {
exit(EXIT_FAILURE);
}
functionality(&socket);
if (cmu_close(&socket) < 0) {
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1 @@
Describe your tests here

View File

@@ -0,0 +1,124 @@
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
import os
import subprocess
from scapy.all import (
Packet,
IntField,
ShortField,
StrLenField,
ByteEnumField,
bind_layers,
)
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP
CODE_DIR = "/vagrant/project-1_elec3120"
PCAP = "/vagrant/project-1_elec3120/tests/test.pcap"
IFNAME = os.getenv("IFNAME")
# Which host are we running this pytest script on, server or client?
# If we are running pytest on the server VM, we want the testing host to be the
# client VM and vice versa.
HOSTNAME = subprocess.check_output("hostname").strip()
if HOSTNAME.decode("utf-8") == "client":
TESTING_HOSTNAME = "server"
HOSTNAME = "client"
elif HOSTNAME.decode("utf-8") == "server":
TESTING_HOSTNAME = "client"
HOSTNAME = "server"
else:
raise RuntimeError(
f"Unexpected hostname: {HOSTNAME}. You must run these tests in the "
f"client or server VM."
)
# You might need to update these for the network setting on your VMs.
IP_ADDRS = {"client": "10.0.1.2", "server": "10.0.1.1"}
MAC_ADDRS = {"client": "08:00:27:a7:fe:b1", "server": "08:00:27:22:47:1c"}
HOST_IP = IP_ADDRS[HOSTNAME]
HOST_MAC = MAC_ADDRS[HOSTNAME]
HOST_PORT = 1234
TESTING_HOST_IP = IP_ADDRS[TESTING_HOSTNAME]
TESTING_HOST_MAC = MAC_ADDRS[TESTING_HOSTNAME]
TESTING_HOST_PORT = 15441
# We can use these commands to start/stop the testing server in a background
# process.
START_TESTING_SERVER_CMD = (
"tmux new -s pytest_server -d /vagrant/"
"project-1_elec3120/tests/testing_server"
)
STOP_TESTING_SERVER_CMD = "tmux kill-session -t pytest_server"
# Default scapy packets headers we'll use to send packets.
eth = Ether(src=HOST_MAC, dst=TESTING_HOST_MAC)
ip = IP(src=HOST_IP, dst=TESTING_HOST_IP)
udp = UDP(sport=HOST_PORT, dport=TESTING_HOST_PORT)
FIN_MASK = 0x2
ACK_MASK = 0x4
SYN_MASK = 0x8
TIMEOUT = 3
"""
These tests assume there is only one connection in the PCAP
and expects the PCAP to be collected on the server. All of
the basic tests pass on the starter code, without you having
to make any changes. You will need to add to these tests as
you add functionality to your implementation. It is also
important to understand what the given tests are testing for!
"""
# we can make CMUTCP packets using scapy
class CMUTCP(Packet):
name = "CMU TCP"
fields_desc = [
IntField("identifier", 15441),
ShortField("source_port", HOST_PORT),
ShortField("destination_port", TESTING_HOST_PORT),
IntField("seq_num", 0),
IntField("ack_num", 0),
ShortField("hlen", 25),
ShortField("plen", 25),
ByteEnumField(
"flags",
0,
{
FIN_MASK: "FIN",
ACK_MASK: "ACK",
SYN_MASK: "SYN",
FIN_MASK | ACK_MASK: "FIN ACK",
SYN_MASK | ACK_MASK: "SYN ACK",
},
),
ShortField("advertised_window", 1),
ShortField("extension_length", 0),
StrLenField(
"extension_data",
None,
length_from=lambda pkt: pkt.extension_length,
),
]
def answers(self, other):
return isinstance(other, CMUTCP)
bind_layers(UDP, CMUTCP)

View File

@@ -0,0 +1,185 @@
#!/usr/bin/env python3
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
from pathlib import Path
from scapy.all import rdpcap
from fabric import Connection
from common import PCAP, CMUTCP, ACK_MASK, IP_ADDRS
def test_pcap_packets_max_size():
"""Basic test: Check packets are smaller than max size"""
print("Running test_pcap_packets_max_size()")
print(
"Please note that it's now testing on a sample test.pcap file. "
"You should generate your own pcap file and run this test."
)
packets = rdpcap(PCAP)
if len(packets) <= 10:
print("Test Failed")
return
for pkt in packets:
if CMUTCP in pkt:
if len(pkt[CMUTCP]) > 1400:
print("Found packet with length greater than max size")
print("Test Failed")
return
print("Test passed")
def test_pcap_acks():
"""Basic test: Check that every data packet sent has a corresponding ACK
Ignore handshake packets.
"""
print("Running test_pcap_acks()")
print(
"Please note that it's now testing on a sample test.pcap file. "
"You should generate your own pcap file and run this test."
)
packets = rdpcap(PCAP)
if len(packets) <= 10:
print("Test Failed")
return
expected_acks = []
ack_nums = []
for pkt in packets:
if CMUTCP in pkt:
# Ignore handshake packets, should test in a different test.
if pkt[CMUTCP].flags == 0:
payload_len = pkt[CMUTCP].plen - pkt[CMUTCP].hlen
expected_acks.append(pkt[CMUTCP].seq_num + payload_len)
elif pkt[CMUTCP].flags == ACK_MASK:
ack_nums.append(pkt[CMUTCP].ack_num)
# Probably not the best way to do this test!
if set(expected_acks) == set(ack_nums):
print("Test Passed")
else:
print("Test Failed")
# This will try to run the server and client code.
def test_run_server_client():
"""Basic test: Run server and client, and initiate the file transfer."""
print("Running test_run_server_client()")
# We are using `tmux` to run the server and client in the background.
#
# This might also help you debug your code if the test fails. You may call
# `getchar()` in your code to pause the program at any point and then use
# `tmux attach -t pytest_server` or `tmux attach -t pytest_client` to
# attach to the relevant TMUX session and see the output.
start_server_cmd = (
"tmux new -s pytest_server -d /vagrant/project-1_elec3120/server"
)
start_client_cmd = (
"tmux new -s pytest_client -d /vagrant/project-1_elec3120/client"
)
stop_server_cmd = "tmux kill-session -t pytest_server"
stop_client_cmd = "tmux kill-session -t pytest_client"
failed = False
original_file = Path("/vagrant/project-1_elec3120/src/cmu_tcp.c")
received_file = Path("/tmp/file.c")
received_file.unlink(missing_ok=True)
with (
Connection(
host=IP_ADDRS["server"],
user="vagrant",
connect_kwargs={"password": "vagrant"},
) as server_conn,
Connection(
host=IP_ADDRS["client"],
user="vagrant",
connect_kwargs={"password": "vagrant"},
) as client_conn,
):
try:
server_conn.run(start_server_cmd)
server_conn.run("tmux has-session -t pytest_server")
client_conn.run(start_client_cmd)
client_conn.run("tmux has-session -t pytest_client")
# Exit when server finished receiving file.
server_conn.run(
"while tmux has-session -t pytest_server; do sleep 1; done",
hide=True,
)
except Exception:
failed = True
try:
client_conn.run("tmux has-session -t pytest_client", hide=True)
print("stop client")
client_conn.run(stop_client_cmd, hide=True)
except Exception:
# Ignore error here that may occur if client already shut down.
pass
try:
server_conn.local("tmux has-session -t pytest_server", hide=True)
print("stop server")
server_conn.local(stop_server_cmd, hide=True)
except Exception:
# Ignore error here that may occur if server already shut down.
pass
if failed:
print("Test failed: Error running server or client")
return
# Compare SHA256 hashes of the files.
server_hash_result = server_conn.run(f"sha256sum {received_file}")
client_hash_result = client_conn.run(f"sha256sum {original_file}")
if not server_hash_result.ok or not client_hash_result.ok:
print("Test failed: Error getting file hashes")
return
server_hash = server_hash_result.stdout.split()[0]
client_hash = client_hash_result.stdout.split()[0]
if server_hash != client_hash:
print("Test failed: File hashes do not match")
return
print("Test passed")
def test_basic_reliable_data_transfer():
"""Basic test: Check that when you run server and client starter code
that the input file equals the output file
"""
# Can you think of how you can test this? Give it a try!
pass
def test_basic_retransmit():
"""Basic test: Check that when a packet is lost, it's retransmitted"""
# Can you think of how you can test this? Give it a try!
pass
if __name__ == "__main__":
test_pcap_packets_max_size()
test_pcap_acks()
test_run_server_client()

View File

@@ -0,0 +1,128 @@
#!/usr/bin/env python3
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
from fabric import Connection
from scapy.all import sr1, Raw
from common import (
CMUTCP,
ACK_MASK,
TIMEOUT,
IFNAME,
SYN_MASK,
START_TESTING_SERVER_CMD,
STOP_TESTING_SERVER_CMD,
TESTING_HOST_IP,
ip,
udp,
)
payloads = ["pa", "pytest 1234567"]
def test_basic_ack_packets():
print("Running test_basic_ack_packets()")
"""Basic test: Check if when you send data packets, the server responds
with correct ack packet with a correct ack number.
"""
print("Running test_sequence_number()")
for payload in payloads:
print("Testing payload size " + str(len(payload)))
with Connection(
host=TESTING_HOST_IP,
user="vagrant",
connect_kwargs={"password": "vagrant"},
) as conn:
try:
conn.run(START_TESTING_SERVER_CMD)
conn.run("tmux has-session -t pytest_server")
syn_pkt = (
ip /
udp /
CMUTCP(plen=25, seq_num=1000, flags=SYN_MASK)
)
syn_ack_pkt = sr1(syn_pkt, timeout=TIMEOUT, iface=IFNAME)
if (
syn_ack_pkt is None
or syn_ack_pkt[CMUTCP].flags != SYN_MASK | ACK_MASK
or syn_ack_pkt[CMUTCP].ack_num != 1000 + 1
):
print(
"Listener (server) did not properly respond to SYN "
"packet."
)
print("Test Failed")
conn.run(STOP_TESTING_SERVER_CMD)
return
print(syn_ack_pkt[CMUTCP].seq_num)
ack_pkt = (
ip /
udp /
CMUTCP(
plen=25,
seq_num=1001,
ack_num=syn_ack_pkt[CMUTCP].seq_num + 1,
flags=ACK_MASK,
)
)
empty_pkt = sr1(ack_pkt, timeout=0.5, iface=IFNAME)
if empty_pkt is not None:
print("Listener (server) should not respond to ack pkt.")
print("Test Failed")
conn.run(STOP_TESTING_SERVER_CMD)
return
data_pkt = (
ip /
udp /
CMUTCP(
plen=25 + len(payload),
seq_num=1001,
ack_num=syn_ack_pkt[CMUTCP].seq_num + 1,
flags=ACK_MASK,
)
/ Raw(load=payload)
)
server_ack_pkt = sr1(data_pkt, timeout=TIMEOUT, iface=IFNAME)
if (
server_ack_pkt is None
or server_ack_pkt[CMUTCP].flags != ACK_MASK
or server_ack_pkt[CMUTCP].ack_num != 1001 + len(payload)
):
print(
"Listener (server) did not properly respond to data "
"packet."
)
print("Test Failed")
conn.run(STOP_TESTING_SERVER_CMD)
return
finally:
try:
conn.run(STOP_TESTING_SERVER_CMD)
except Exception:
# Ignore error here that may occur if server stopped.
pass
print("Test Passed")
if __name__ == "__main__":
test_basic_ack_packets()

View File

@@ -0,0 +1,87 @@
/**
*Copyright (C) 2023 Carnegie Mellon University and
*Hong Kong University of Science and Technology
*This repository is adopted from the TCP in the
*Wild course project from the Computer Networks
*course taught at Carnegie Mellon University, and
*is used for the Computer Networks (ELEC 3120)
*course taught at Hong Kong University of Science
*and Technology.
*No part of the project may be copied and/or
*distributed without the express permission of
*the course staff. Everyone is prohibited from
*releasing their forks in any public places.
*
* This file implements a simple CMU-TCP server used for testing.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "cmu_tcp.h"
/*
* Param: sock - used for reading and writing to a connection
*
*
*/
void functionality(cmu_socket_t *sock) {
uint8_t buf[9898];
FILE *fp;
int n;
int read;
// Wait to hear from an initiator
n = 0;
while (n == 0) {
n = cmu_read(sock, buf, 9898, NO_FLAG);
}
printf("read something %d\n", n);
// Send over a random file
fp = fopen("/vagrant/project-1_elec3120/tests/random.input", "rb");
read = 1;
while (read > 0) {
read = fread(buf, 1, 2000, fp);
if (read > 0) cmu_write(sock, buf, read);
}
}
/*
* Param: argc - count of command line arguments provided
* Param: argv - values of command line arguments provided
*
* Purpose: To provide a sample listener for the TCP connection.
*
*/
int main() {
int portno;
char *serverip;
char *serverport;
cmu_socket_t socket;
serverip = getenv("server15441");
if (!serverip) {
serverip = "10.0.1.1";
}
serverport = getenv("serverport15441");
if (!serverport) {
serverport = "15441";
}
portno = (uint16_t)atoi(serverport);
printf("starting initiator\n");
if (cmu_socket(&socket, TCP_LISTENER, portno, serverip) < 0)
exit(EXIT_FAILURE);
printf("finished socket\n");
functionality(&socket);
sleep(5);
if (cmu_close(&socket) < 0) exit(EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
HOST=$(hostname)
IFNAME=$(ifconfig | grep -B1 10.0.1. | grep -o "^\w*")
FUNCTION_TO_RUN=$1
PCAP_NAME=$2
if [ -z "$FUNCTION_TO_RUN" ]
then
echo "usage: ./capture_packets.sh < start | stop | analyze > PCAP_NAME"
echo "Expecting name of function to run: start, stop, or analyze."
exit 1
fi
if [ -z "$PCAP_NAME" ]
then
PCAP_NAME=$HOST.pcap
echo NO PCAP_NAME PARAM SO USING DEFAULT FILE: $PCAP_NAME
fi
start() {
sudo tcpdump -i $IFNAME -w $PCAP_NAME udp > /dev/null 2> /dev/null < \
/dev/null &
}
stop() {
sudo pkill -f "tcpdump -i $IFNAME -w $PCAP_NAME udp"
}
analyze() {
tshark -X lua_script:$DIR/tcp.lua -R "cmutcp and not icmp" -r $PCAP_NAME \
-T fields \
-e frame.time_relative \
-e ip.src \
-e cmutcp.source_port \
-e ip.dst \
-e cmutcp.destination_port \
-e cmutcp.seq_num \
-e cmutcp.ack_num \
-e cmutcp.hlen \
-e cmutcp.plen \
-e cmutcp.flags \
-e cmutcp.advertised_window \
-e cmutcp.extension_length \
-E header=y -E separator=, \
-2
}
$FUNCTION_TO_RUN

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Copyright (C) 2023 Carnegie Mellon University and
# Hong Kong University of Science and Technology
# This repository is adopted from the TCP in the
# Wild course project from the Computer Networks
# course taught at Carnegie Mellon University, and
# is used for the Computer Networks (ELEC 3120)
# course taught at Hong Kong University of Science
# and Technology.
# No part of the project may be copied and/or
# distributed without the express permission of
# the course staff. Everyone is prohibited from
# releasing their forks in any public places.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "Preparing submission..."
echo "Make sure to commit all files that you want to submit."
cd $SCRIPT_DIR/../..
git archive -o handin.tar.gz HEAD
echo "Upload handin.tar.gz to Gradescope."

View File

@@ -0,0 +1,72 @@
-- Copyright (C) 2023 Carnegie Mellon University and
-- Hong Kong University of Science and Technology
-- This repository is adopted from the TCP in the
-- Wild course project from the Computer Networks
-- course taught at Carnegie Mellon University, and
-- is used for the Computer Networks (ELEC 3120)
-- course taught at Hong Kong University of Science
-- and Technology.
-- No part of the project may be copied and/or
-- distributed without the express permission of
-- the course staff. Everyone is prohibited from
-- releasing their forks in any public places.
tcp = Proto("cmutcp", "CMU TCP")
local f_identifier = ProtoField.uint32("cmutcp.identifier", "Identifier")
local f_source_port = ProtoField.uint16("cmutcp.source_port", "Source Port")
local f_destination_port = ProtoField.uint16("cmutcp.destination_port", "Destination Port")
local f_seq_num = ProtoField.uint32("cmutcp.seq_num", "Sequence Number")
local f_ack_num = ProtoField.uint32("cmutcp.ack_num", "ACK Number")
local f_hlen = ProtoField.uint16("cmutcp.hlen", "Header Length")
local f_plen = ProtoField.uint16("cmutcp.plen", "Packet Length")
local f_flags = ProtoField.uint8("cmutcp.flags", "Flags")
local f_advertised_window = ProtoField.uint16("cmutcp.advertised_window", "Advertised Window")
local f_extension_length = ProtoField.uint16("cmutcp.extension_length", "Extension Length")
local f_extension_data = ProtoField.string("cmutcp.extension_data", "Extension Data")
tcp.fields = { f_identifier, f_source_port, f_destination_port, f_seq_num, f_ack_num, f_hlen, f_plen, f_flags, f_advertised_window, f_extension_length , f_extension_data}
function tcp.dissector(tvb, pInfo, root) -- Tvb, Pinfo, TreeItem
if (tvb:len() ~= tvb:reported_len()) then
return 0 -- ignore partially captured packets
-- this can/may be re-enabled only for unfragmented UDP packets
end
local t = root:add(tcp, tvb(0,25))
t:add(f_identifier, tvb(0,4))
t:add(f_source_port, tvb(4,2))
t:add(f_destination_port, tvb(6,2))
t:add(f_seq_num, tvb(8,4))
t:add(f_ack_num, tvb(12,4))
t:add(f_hlen, tvb(16,2))
t:add(f_plen, tvb(18,2))
local f = t:add(f_flags, tvb(20,1))
t:add(f_advertised_window, tvb(21,2))
t:add(f_extension_length, tvb(23,2))
local extension_length = tvb(23,1):int()
t:add(f_extension_data, tvb(25,extension_length))
local flag = tvb(20,1):uint()
if bit.band(flag, 8) ~= 0 then
f:add(tvb(20,1), "SYN")
end
if bit.band(flag, 4) ~= 0 then
f:add(tvb(20,1), "ACK")
end
if bit.band(flag, 2) ~= 0 then
f:add(tvb(20,1), "FIN")
end
pInfo.cols.protocol = "CMU TCP"
end
-- have to put the port for the server here
local udpDissectorTable = DissectorTable.get("udp.port")
udpDissectorTable:add("15441", tcp)
io.stderr:write("tcp.lua is successfully loaded\n")

View File

@@ -0,0 +1,88 @@
<h1 style="text-align: center;">SSH Key Configuration Guide</h1>
This guide will walk you through the process of configuration of SSH key for remote SSH connections to servers on both Windows and Linux. Fast-connecting to a sever using SSH public key authentication is a SSH connection trick that makes it easy to connect to a remote server.
## Generating SSH Keys
### Windows
#### Step 1: Open Powershell Bash
Open the Powershell terminal to prepare for SSH key generation.
#### Step 2: Generate SSH Keys
In the Powershell terminal, use the following command to generate SSH keys:
```bash
# In powershell bash
ssh-keygen
```
Save it by default, the system will save the keys to [your home directory]/.ssh/id_rsa. Unless you are an expert you should use the default option and press Enter.
#### Step 3: View SSH Keys
To view the generated SSH keys, run the following command:
```bash
# In powershell bash
cat ~/.ssh/id_rsa.pub
```
Copy the displayed key and configure it on your server.
### Linux-like systems
#### Step 1: Open Terminal
Open the terminal to prepare for SSH key generation.
#### Step 2: Generate SSH Keys
In the terminal, use the following command to generate SSH keys:
```bash
# In termianl
ssh-keygen
```
Follow the prompts to input the file save path and a passphrase. Generally, you can accept the default values by pressing Enter.
#### Step 3: View SSH Keys
To view the generated SSH keys, run the following command:
```bash
# In termianl
cat ~/.ssh/id_rsa.pub
```
Copy the displayed key and configure it on your server.
## Server Configuration
On your Azure instance/server which your code running on, add the SSH publish key you generated to the `~/.ssh/authorized_keys` file to allow remote SSH access. Ensure that your server has SSH access properly configured.
If you don't have the `authorized_keys` file under the `~/.ssh/`, just create a blank one:
```bash
# In the server terminal, use the following command
touch ~/.ssh/authorized_keys
```
On your own PC, write the alias of the server in the `~/.ssh/config` file:
![](md_img/ssh_config.png)
```bash
Host elec3120us # the alias for server
HostName 20.38.43.192 # server IP address
User elec3120 # server usrname
```
You have now successfully generated SSH keys and are ready for remote SSH connections to your server by typing the following to connect to server _elec3120@20.38.43.192_:
```bash
ssh elec3120us
```
We hope this guide is helpful!

View File

@@ -0,0 +1 @@
{"dependencies":[["ipaddr",[">= 1.2.4"]],["rubyntlm",["~> 0.6.0",">= 0.6.3"]],["nori",["~> 2.0"]],["multi_json",["~> 1.14"]],["little-plugger",["~> 1.1"]],["logging",[">= 1.6.1","< 3.0"]],["httpclient",["~> 2.2",">= 2.2.0.2"]],["rexml",["~> 3.2"]],["builder",[">= 2.1.2"]],["gyoku",["~> 1.0"]],["ffi",["~> 1.9"]],["gssapi",["~> 1.2"]],["erubi",[">= 0"]],["winrm",[">= 2.3.6","< 3.0"]],["rubyzip",["~> 2.3.2"]],["winrm-fs",[">= 1.3.5","< 2.0"]],["winrm-elevated",[">= 1.2.3","< 2.0"]],["wdm",["~> 0.1.1"]],["log4r",["~> 1.1.9","< 1.1.11"]],["excon",["~> 0.73"]],["vagrant_cloud",["~> 3.1.1"]],["pairing_heap",[">= 0.3.0"]],["stream",["~> 0.5.3"]],["rgl",["~> 0.5.10"]],["rb-kqueue",["~> 0.2.0"]],["net-ssh",["~> 7.0"]],["net-scp",["~> 4.0"]],["net-sftp",["~> 4.0"]],["date",[">= 0"]],["time",[">= 0"]],["io-wait",[">= 0"]],["timeout",[">= 0"]],["net-protocol",[">= 0"]],["net-ftp",["~> 0.2"]],["mime-types-data",["~> 3.2015"]],["mime-types",["~> 3.3"]],["rb-inotify",["~> 0.9",">= 0.9.10"]],["rb-fsevent",["~> 0.10",">= 0.10.3"]],["listen",["~> 3.7"]],["concurrent-ruby",["~> 1.0"]],["i18n",["~> 1.12"]],["hashicorp-checkpoint",["~> 0.1.5"]],["google-protobuf",["~> 3.23"]],["googleapis-common-protos-types",["~> 1.3"]],["grpc",["~> 1.56.0"]],["ed25519",["~> 1.3.0"]],["childprocess",["~> 4.1.0"]],["bcrypt_pbkdf",["~> 1.1"]],["vagrant",[">= 1.9.2"]],["netrc",["~> 0.8"]],["domain_name",["~> 0.5"]],["http-cookie",[">= 1.0.2","< 2.0"]],["http-accept",[">= 1.7.0","< 2.0"]],["rest-client",[">= 1.6.0"]],["vagrant-share",["= 2.0.0"]]],"checksum":"1ae33a57574240b0c1da847fb943e2eec9d44bbee4792fb20a14462bc766d076","vagrant_version":"2.4.1"}

View File

@@ -0,0 +1 @@
1.5:cb3e5e76-03f3-48ba-9686-2671cb60aa3b

View File

@@ -0,0 +1 @@
{"name":"ubuntu/jammy64","version":"20240417.0.0","provider":"virtualbox","directory":"boxes/ubuntu-VAGRANTSLASH-jammy64/20240417.0.0/virtualbox"}

View File

@@ -0,0 +1 @@
cb3e5e76-03f3-48ba-9686-2671cb60aa3b

View File

@@ -0,0 +1 @@
2198e36e6f2b4f3483c39f13b7ab405f

View File

@@ -0,0 +1,8 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAA
AAtzc2gtZWQyNTUxOQAAACAIKEfG3PaOX2SXKEgj9m2wF9oT+Tm38WRa3P3k
2wvIrQAAAJCDuT7Gg7k+xgAAAAtzc2gtZWQyNTUxOQAAACAIKEfG3PaOX2SX
KEgj9m2wF9oT+Tm38WRa3P3k2wvIrQAAAEC70ZbHu/ean0p89XwO0ebyTGfR
O7GXhZ0U8uww7SYCiwgoR8bc9o5fZJcoSCP2bbAX2hP5ObfxZFrc/eTbC8it
AAAAB3ZhZ3JhbnQBAgMEBQY=
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1 @@
{"virtualbox":{"/vagrant_data":{"guestpath":"/vagrant_data","hostpath":"D:/_workspace/comission-playlist/ahhim526/_ref/vagrant_helloworld/data","disabled":false,"__vagrantfile":true},"/vagrant":{"guestpath":"/vagrant","hostpath":"D:/_workspace/comission-playlist/ahhim526/_ref/vagrant_helloworld","disabled":false,"__vagrantfile":true}}}

View File

@@ -0,0 +1 @@
D:/_workspace/comission-playlist/ahhim526/_ref/vagrant_helloworld

View File

@@ -0,0 +1,12 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
# This file loads the proper rgloader/loader.rb file that comes packaged
# with Vagrant so that encoded files can properly run with Vagrant.
if ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"]
require File.expand_path(
"rgloader/loader", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"])
else
raise "Encoded files can't be read outside of the Vagrant installer."
end

View File

@@ -0,0 +1,80 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "ubuntu/jammy64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
config.vm.synced_folder "./data", "/vagrant_data"
# Disable the default share of the current code directory. Doing this
# provides improved isolation between the vagrant box and your host
# by making sure your Vagrantfile isn't accessible to the vagrant box.
# If you use this you may want to enable additional shared subfolders as
# shown above.
# config.vm.synced_folder ".", "/vagrant", disabled: true
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
vb.memory = "2048"
end
#
# View the documentation for the provider you are using for more
# information on available options.
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y apache2
hostnamectl set-hostname louistest-vm
SHELL
end

View File

@@ -0,0 +1 @@
3

View File

@@ -0,0 +1,9 @@
vagrant init hashicorp/bionic64
vagrant box add hashicorp/bionic64
vagrant up
vagrant ssh
vagrant destroy
vagrant box list
vagrant box remove hashicorp/bionic64
vagrant plugin install vagrant-share
vagrant share

View File

@@ -0,0 +1,5 @@
vagrant destroy -f
vagrant up
@REM vagrant plugin install vagrant-share
echo "done"

7
ahhim526/gitUpdate.bat Normal file
View File

@@ -0,0 +1,7 @@
git status .
@pause
git add .
git commit -m"update ahhim526,"
start git push

3
ahhim526/meta.md Normal file
View File

@@ -0,0 +1,3 @@
---
tags: HKUST, ELEC3120, vagrant
---