diff --git a/chatserver/client.py b/chatserver/client.py index 9ad3c98..00e4254 100644 --- a/chatserver/client.py +++ b/chatserver/client.py @@ -1,3 +1,4 @@ +import os import socket import sys import select @@ -15,13 +16,25 @@ def main(): SERVER_HOST = sys.argv[1] SERVER_PORT = int(sys.argv[2]) + # Prompt user for a local directory path for file operations + while True: + local_path = input("Enter a local directory path for sending/receiving files: ").strip() + if os.path.isdir(local_path): + print(f"Using directory: {local_path}") + break + else: + print("Invalid directory. Please enter a valid path.") + # create a socket object client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # connect to the server client_socket.connect((SERVER_HOST, SERVER_PORT)) print(f"Connected to chat server at {SERVER_HOST}:{SERVER_PORT}") - + + # Send the local path to the server + client_socket.send(f"SET_PATH {local_path}".encode('utf-8')) + while True: # use select to wait for either server messages or user input read_sockets, _, _ = select.select([client_socket, sys.stdin], [], []) @@ -33,8 +46,35 @@ def main(): if not server_message: print("Disconnected from server") return - print(f"\n{server_message}") - print("> ", end="", flush=True) + if server_message.startswith("FILE_REQUEST"): + # Handle file request + _, sending_username, filename = server_message.split() + file_path = os.path.join(local_path, filename) + if os.path.isfile(file_path): + file_size = os.path.getsize(file_path) + with open(file_path, "rb") as f: + file_bytes = f.read() + filetype = "File" + client_socket.send( + f"@{sending_username}@CLIENT -f {filename} {filetype} {file_size} {file_bytes.decode('latin1')} ENDFILE".encode('utf-8') + ) + else: + client_socket.send( + f"@{sending_username}@CLIENT -f {filename} NOTFOUND".encode('utf-8') + ) + elif server_message.startswith("FILE_TRANSFER"): + # Handle file transfer + _, sending_username, filename, filetype, filelength = server_message.split() + file_bytes = client_socket.recv(int(filelength)) + end_marker = client_socket.recv(BUFFER_SIZE).decode('utf-8') + if end_marker == "ENDFILE": + file_path = os.path.join(local_path, filename) + with open(file_path, "wb") as f: + f.write(file_bytes) + print(f"Received file '{filename}' from {sending_username}.") + else: + print(f"\n{server_message}") + print("> ", end="", flush=True) else: # prompt for user input client_message = input() diff --git a/chatserver/server.py b/chatserver/server.py index ee1d18b..59ffe71 100644 --- a/chatserver/server.py +++ b/chatserver/server.py @@ -1,3 +1,4 @@ +import os import socket import select @@ -5,6 +6,18 @@ CHATPORT = 8181 BUFFER_SIZE = 1024 MAX_CONNECT_QUEUE = 10 +def format_file_info(file_path): + """Helper function to format file information.""" + file_size = os.path.getsize(file_path) + if file_size < 1000: + size_str = f"{file_size} B" + elif file_size < 1000000: + size_str = f"{file_size / 1000:.2f} KB" + else: + size_str = f"{file_size / 1000000:.2f} MB" + file_type = "Directory" if os.path.isdir(file_path) else "File" + return f"{os.path.basename(file_path)} - {file_type} - {size_str}" + def main(): # set the flag variable to true for infinite loop quitFlag = True @@ -31,6 +44,8 @@ def main(): # keep track of the states of each client connected, and if they are # technically in an 'unsafe' state like in change username or chatroom mode. client_states = {} + # Add a dictionary to store user-specific paths + user_paths = {} # let the user know the server is listening on port CHATPORT. print(f"Chatserver listening on port: {CHATPORT}") @@ -50,6 +65,7 @@ def main(): client_socket.send(b"\nUse '%!' to exit, or '%?' for help.\n") client_socket.send(b"\nType in a username: ") client_states[client_socket] = "WAITING_FOR_USERNAME" + user_paths[client_socket] = None # Initialize path for new client # otherwise the socket is a client socket. else: # try to receive the message from the client @@ -62,6 +78,7 @@ def main(): chat_rooms[sock] = "default" sock.send(b"\nUsername accepted. You are now in the 'default' chatroom.") client_states[sock] = "NORMAL" + user_paths[sock] = None # Initialize path for the user elif state == "WAITING_FOR_NEW_USERNAME": usernames[sock] = message.strip() sock.send(b"\nUsername changed successfully.") @@ -75,8 +92,82 @@ def main(): if old_chatroom != "default" and old_chatroom not in chat_rooms.values(): print(f"\nChatroom '{old_chatroom}' is empty and removed.") client_states[sock] = "NORMAL" - else: - if message.strip() == "%!": + elif state == "NORMAL": + if message.startswith("@") and "-ls" in message: + # Parse the message format: @RECEIVING_USERNAME@SENDING_USERNAME -ls + parts = message.split() + if len(parts) >= 2 and "-ls" in parts[1]: + usernames_part = parts[0] + if usernames_part.count("@") == 2: + receiving_username, sending_username = usernames_part[1:].split("@") + # Find the receiving user's socket + receiving_sock = next( + (s for s, u in usernames.items() if u == receiving_username), None + ) + sending_sock = next( + (s for s, u in usernames.items() if u == sending_username), None + ) + if receiving_sock and sending_sock: + user_path = user_paths.get(receiving_sock) + if user_path and os.path.isdir(user_path): + # List files in the receiving user's directory + files = os.listdir(user_path) + if files: + file_list = "\n".join( + [format_file_info(os.path.join(user_path, f)) for f in files] + ) + sending_sock.send( + f"Files in {receiving_username}'s directory:\n{file_list}".encode('utf-8') + ) + else: + sending_sock.send( + f"No files in {receiving_username}'s directory.".encode('utf-8') + ) + else: + sending_sock.send( + f"Error: {receiving_username} has no valid directory set.".encode('utf-8') + ) + else: + sock.send(b"Error: One or both users not found.") + else: + sock.send(b"Error: Invalid message format.") + elif message.startswith("@") and "-f" in message: + # Parse the message format: @RECEIVING_USERNAME@SENDING_USERNAME -f FILENAME + parts = message.split() + if len(parts) >= 3 and "-f" in parts[1]: + usernames_part = parts[0] + if usernames_part.count("@") == 2: + receiving_username, sending_username = usernames_part[1:].split("@") + # Find the receiving user's socket + receiving_sock = next( + (s for s, u in usernames.items() if u == receiving_username), None + ) + sending_sock = next( + (s for s, u in usernames.items() if u == sending_username), None + ) + if receiving_sock and sending_sock: + if len(parts) == 3: + # File request: @RECEIVING_USERNAME@SENDING_USERNAME -f FILENAME + filename = parts[2] + receiving_sock.send( + f"FILE_REQUEST {sending_username} {filename}".encode('utf-8') + ) + elif len(parts) > 5 and parts[-1] == "ENDFILE": + # File transfer: @RECEIVING_USERNAME@SENDING_USERNAME -f FILENAME FILETYPE FILELENGTH FILEBYTES ENDFILE + filename = parts[2] + filetype = parts[3] + filelength = int(parts[4]) + filebytes = " ".join(parts[5:-1]).encode('utf-8') + receiving_sock.send( + f"FILE_TRANSFER {sending_username} {filename} {filetype} {filelength}".encode('utf-8') + ) + receiving_sock.send(filebytes) + receiving_sock.send(b"ENDFILE") + else: + sock.send(b"Error: One or both users not found.") + else: + sock.send(b"Error: Invalid message format.") + elif message.strip() == "%!": sock.close() socket_list.remove(sock) del usernames[sock] diff --git a/echoserver/Makefile b/echoserver/Makefile deleted file mode 100644 index 221b29f..0000000 --- a/echoserver/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -CC = gcc -Wall -std=c11 -pedantic -SOURCES = echoserver.c -OBJECTS = echoserver.o - -all: echoserver - -echoserver: $(OBJECTS) - $(CC) $(OBJECTS) -o echoserver - -echoserver.o: echoserver.c - $(CC) -c echoserver.c -o echoserver.o - -clean: - rm -f $(OBJECTS) echoserver echoserver.out - -clean_objects: - rm -f $(OBJECTS) - -run: - ./echoserver diff --git a/echoserver/README.md b/echoserver/README.md deleted file mode 100644 index fb81333..0000000 --- a/echoserver/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Running the echoserver -Use `make` to compile the echoserver. -Use `make run` to run the echoserver. This will run on an infinite loop. -Use `Ctrl+C` to stop the echoserver. - -## echoserver communication -Communicating with the server can happen using telnet in TCP mode. - -## echoserver information -The echoserver runs on TCP port 8888. \ No newline at end of file diff --git a/echoserver/echoserver.c b/echoserver/echoserver.c deleted file mode 100644 index 73e2bbc..0000000 --- a/echoserver/echoserver.c +++ /dev/null @@ -1,150 +0,0 @@ -// header files -#include "echoserver.h" - -// constants -// echoserver port is 8888 -#define ECHOPORT 8888 -#define BUFFER_SIZE 1024 -#define MAX_CONNECT_QUEUE 10 - -// prototypes - -// main function -int main(int argc, char **argv) -{ - // initialize program (variables and structs) - bool quitFlag = true; - int socketEchoFD; - int clientEchoFD; - int reuseAddrOpt = 1; - int keepAliveOpt = 1; - char message[BUFFER_SIZE]; - int messageBytes; - struct sockaddr_in serverAddr; - struct sockaddr_storage clientAddr; - socklen_t clientSize; - memset(&serverAddr, 0, sizeof(serverAddr)); - memset(&clientAddr, 0, sizeof(clientAddr)); - // define a TCP socket - socketEchoFD = socket(AF_INET, SOCK_STREAM, 0); - if(socketEchoFD < 0) - { - printf("Unable to create the socket.\n"); - return -1; - } - // use the setsockopt function to make the socket accept different configurations - // allow for the reuse of the address/bind. - setsockopt(socketEchoFD, SOL_SOCKET, SO_REUSEADDR, &reuseAddrOpt, sizeof(reuseAddrOpt)); - // also need to set the socket to keepalive using setsockopt - setsockopt(socketEchoFD, SOL_SOCKET, SO_KEEPALIVE, &keepAliveOpt, sizeof(keepAliveOpt)); - // bind the TCP socket to port 8888 / ECHOPORT - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = INADDR_ANY; - serverAddr.sin_port = htons(ECHOPORT); - int bindCheck = bind(socketEchoFD, &serverAddr, sizeof(serverAddr)); - if(bindCheck < 0) - { - printf("Unable to bind the socket to the port or address.\n Is either in use?"); - return -1; - } - // use fnctl to set the non-blocking flag for the socket - fcntl(socketEchoFD, F_SETFL, O_NONBLOCK); - // the server will now accept client connections by listening. - listen(socketEchoFD, MAX_CONNECT_QUEUE); - // create a file descriptor set, to keep track of the sockets in use using fd_set and FD_ZERO? - fd_set socketList; - FD_ZERO(&socketList); - // add the socketEchoFD to the file descriptor set using fd_set - FD_SET(socketEchoFD, &socketList); - // max file descriptor, this will be used to 'find' the socket currently connected - int maxFD = socketEchoFD; - // while loop that will continue to listen for messages from clients. - printf("Echoserver listening on port: %d\n", ECHOPORT); - while (quitFlag) - { - // set of active connections - fd_set activeSet = socketList; - // use the select() function here to check the set of sockets - int selectedFD = select(maxFD+1, &activeSet, NULL, NULL, NULL); - // check to make sure select() didn't error out. - if(selectedFD == -1) - { - // - printf("\nUnable to select socket to listen to.\n"); - return -1; - } - // for loop that loops up to the max file descriptor. - for(int fileIter = 0; fileIter <= maxFD; fileIter++) - { - // check to see if the file descriptor is in the set of sockets using FD_ISSET() - if(FD_ISSET(fileIter, &activeSet)) - { - // if the server socket is being written to/read from, - if(fileIter == socketEchoFD) - { - // create a client socket using accept - clientSize = sizeof(clientAddr); - clientEchoFD = accept(socketEchoFD, &clientAddr, &clientSize); - // check to see if the client socket is connected (-1) - if(clientEchoFD == -1) - { - printf("\nCould not connect the client to a socket.\n"); - return -1; - } - else - { - // set the non blocking flag using fnctl - fcntl(clientEchoFD, F_SETFL, O_NONBLOCK); - // add the client socket to the set of file descriptor sockets - FD_SET(clientEchoFD, &socketList); - // check to see if the new socket FD is greater than the current max (clientSocket > maxFD) - if(clientEchoFD > maxFD) - { - // if it is, set the new max. - maxFD = clientEchoFD; - } - printf("\nConnected client to socket.\n"); - } - printf("\nAccepted connection from new client.\n"); - } - // if the client socket(s) are being written to/read from, - else - { - // grab the data from the client, save to message. - messageBytes = recv(fileIter, message, BUFFER_SIZE, 0); - // make sure that the connection is still open before attempting to send. - if(messageBytes <= 0) // old: messageBytes <= 0 - { - // if it is not open, close the socket and remove the socket from the socket list using FD_CLR() - close(fileIter); - FD_CLR(fileIter, &socketList); - printf("\nClient has closed connection.\n"); - } - else - { - // if it is open, send the message back to the client over the client socket - send(fileIter, message, messageBytes, 0); - printf("\nMessage has been sent back to client.\n"); - } - } - } - } - } - // close the socket - close(socketEchoFD); - // profit??? - return 0; -} - -// function definitions - -/* -Name: ??? -Process: ??? -Function Input/Parameters: ??? -Function Output/Parameters: ??? -Function Output/Returned: ??? -Device Input/Device: ??? -Device Output/Device: ??? -Dependencies: ??? -*/ \ No newline at end of file diff --git a/echoserver/echoserver.h b/echoserver/echoserver.h deleted file mode 100644 index b1ef31c..0000000 --- a/echoserver/echoserver.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef ECHOSERVER -#define ECHOSERVER - -// included libraries -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// data structures - -// function prototypes - -#endif // ECHOSERVER \ No newline at end of file diff --git a/networksim/CS460Homework4_CBvCB_graph.png b/networksim/CS460Homework4_CBvCB_graph.png deleted file mode 100644 index 0005c3a..0000000 Binary files a/networksim/CS460Homework4_CBvCB_graph.png and /dev/null differ diff --git a/networksim/CS460Homework4_Cubic_graph.png b/networksim/CS460Homework4_Cubic_graph.png deleted file mode 100644 index b98c5b3..0000000 Binary files a/networksim/CS460Homework4_Cubic_graph.png and /dev/null differ diff --git a/networksim/CS460Homework4_NRvCB_graph.png b/networksim/CS460Homework4_NRvCB_graph.png deleted file mode 100644 index b325280..0000000 Binary files a/networksim/CS460Homework4_NRvCB_graph.png and /dev/null differ diff --git a/networksim/CS460Homework4_NRvNR_graph.png b/networksim/CS460Homework4_NRvNR_graph.png deleted file mode 100644 index ba38290..0000000 Binary files a/networksim/CS460Homework4_NRvNR_graph.png and /dev/null differ diff --git a/networksim/CS460Homework4_NewReno_graph.png b/networksim/CS460Homework4_NewReno_graph.png deleted file mode 100644 index 9c251a6..0000000 Binary files a/networksim/CS460Homework4_NewReno_graph.png and /dev/null differ diff --git a/networksim/CS460Homework4_graph.png b/networksim/CS460Homework4_graph.png deleted file mode 100644 index 81b2168..0000000 Binary files a/networksim/CS460Homework4_graph.png and /dev/null differ diff --git a/networksim/CS460Homework4_graph_5p.png b/networksim/CS460Homework4_graph_5p.png deleted file mode 100644 index 8a24d71..0000000 Binary files a/networksim/CS460Homework4_graph_5p.png and /dev/null differ diff --git a/networksim/README.md b/networksim/README.md deleted file mode 100644 index c81d21b..0000000 --- a/networksim/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Adapted tcp-variants-comparison file -The `tcp-variants-comparison.cc` file has been adapted to allow for multiple TCP variants to be run in one simulation. -In order to change the variants ran, find line 510-524. This is where the magic of which variants to run is. -The code relies on multiple flows to also be ran, which can be found using the number of cases - 1. If you want to test the file, you'll want to replace the file with this modified version, which must then be rebuilt. You should be able to use `./ns3 build tcp-variants-comparison` (or `./ns3 build examples/tcp-variants-comparison` might work better) although this hasn't been tested, and the best method is to use ccache to cache the build before making the modification. - -## How to find the cwnd of multiple TCP variants (how to run) -The command `./ns3 run tcp-variants-comparison --command-template="%s --tracing=1 --prefix_name=CS460Homework4_TCPCmp --num_flows=3 --access_delay=50ms"` can be used to find the comparisons between TCP variants. You'll want the number of flows to equal the amount of cases in the switch statement. \ No newline at end of file diff --git a/networksim/tcp-variants-comparison.cc b/networksim/tcp-variants-comparison.cc deleted file mode 100644 index 09d3142..0000000 --- a/networksim/tcp-variants-comparison.cc +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Copyright (c) 2013 ResiliNets, ITTC, University of Kansas - * - * SPDX-License-Identifier: GPL-2.0-only - * - * Authors: Justin P. Rohrer, Truc Anh N. Nguyen , Siddharth Gangadhar - * - * - * James P.G. Sterbenz , director - * ResiliNets Research Group https://resilinets.org/ - * Information and Telecommunication Technology Center (ITTC) - * and Department of Electrical Engineering and Computer Science - * The University of Kansas Lawrence, KS USA. - * - * Work supported in part by NSF FIND (Future Internet Design) Program - * under grant CNS-0626918 (Postmodern Internet Architecture), - * NSF grant CNS-1050226 (Multilayer Network Resilience Analysis and Experimentation on GENI), - * US Department of Defense (DoD), and ITTC at The University of Kansas. - * - * "TCP Westwood(+) Protocol Implementation in ns-3" - * Siddharth Gangadhar, Trúc Anh Ngọc Nguyễn , Greeshma Umapathi, and James P.G. Sterbenz, - * ICST SIMUTools Workshop on ns-3 (WNS3), Cannes, France, March 2013 - */ - -#include "ns3/applications-module.h" -#include "ns3/core-module.h" -#include "ns3/enum.h" -#include "ns3/error-model.h" -#include "ns3/event-id.h" -#include "ns3/flow-monitor-helper.h" -#include "ns3/internet-module.h" -#include "ns3/ipv4-global-routing-helper.h" -#include "ns3/network-module.h" -#include "ns3/point-to-point-module.h" -#include "ns3/tcp-header.h" -#include "ns3/traffic-control-module.h" -#include "ns3/udp-header.h" - -#include -#include -#include - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE("TcpVariantsComparison"); - -static std::map firstCwnd; //!< First congestion window. -static std::map firstSshThr; //!< First SlowStart threshold. -static std::map firstRtt; //!< First RTT. -static std::map firstRto; //!< First RTO. -static std::map> cWndStream; //!< Congstion window output stream. -static std::map> - ssThreshStream; //!< SlowStart threshold output stream. -static std::map> rttStream; //!< RTT output stream. -static std::map> rtoStream; //!< RTO output stream. -static std::map> nextTxStream; //!< Next TX output stream. -static std::map> nextRxStream; //!< Next RX output stream. -static std::map> inFlightStream; //!< In flight output stream. -static std::map cWndValue; //!< congestion window value. -static std::map ssThreshValue; //!< SlowStart threshold value. - -/** - * Get the Node Id From Context. - * - * @param context The context. - * @return the node ID. - */ -static uint32_t -GetNodeIdFromContext(std::string context) -{ - const std::size_t n1 = context.find_first_of('/', 1); - const std::size_t n2 = context.find_first_of('/', n1 + 1); - return std::stoul(context.substr(n1 + 1, n2 - n1 - 1)); -} - -/** - * Congestion window tracer. - * - * @param context The context. - * @param oldval Old value. - * @param newval New value. - */ -static void -CwndTracer(std::string context, uint32_t oldval, uint32_t newval) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - if (firstCwnd[nodeId]) - { - *cWndStream[nodeId]->GetStream() << "0.0 " << oldval << std::endl; - firstCwnd[nodeId] = false; - } - *cWndStream[nodeId]->GetStream() << Simulator::Now().GetSeconds() << " " << newval << std::endl; - cWndValue[nodeId] = newval; - - if (!firstSshThr[nodeId]) - { - *ssThreshStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << ssThreshValue[nodeId] << std::endl; - } -} - -/** - * Slow start threshold tracer. - * - * @param context The context. - * @param oldval Old value. - * @param newval New value. - */ -static void -SsThreshTracer(std::string context, uint32_t oldval, uint32_t newval) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - if (firstSshThr[nodeId]) - { - *ssThreshStream[nodeId]->GetStream() << "0.0 " << oldval << std::endl; - firstSshThr[nodeId] = false; - } - *ssThreshStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << newval << std::endl; - ssThreshValue[nodeId] = newval; - - if (!firstCwnd[nodeId]) - { - *cWndStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << cWndValue[nodeId] << std::endl; - } -} - -/** - * RTT tracer. - * - * @param context The context. - * @param oldval Old value. - * @param newval New value. - */ -static void -RttTracer(std::string context, Time oldval, Time newval) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - if (firstRtt[nodeId]) - { - *rttStream[nodeId]->GetStream() << "0.0 " << oldval.GetSeconds() << std::endl; - firstRtt[nodeId] = false; - } - *rttStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << newval.GetSeconds() << std::endl; -} - -/** - * RTO tracer. - * - * @param context The context. - * @param oldval Old value. - * @param newval New value. - */ -static void -RtoTracer(std::string context, Time oldval, Time newval) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - if (firstRto[nodeId]) - { - *rtoStream[nodeId]->GetStream() << "0.0 " << oldval.GetSeconds() << std::endl; - firstRto[nodeId] = false; - } - *rtoStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << newval.GetSeconds() << std::endl; -} - -/** - * Next TX tracer. - * - * @param context The context. - * @param old Old sequence number. - * @param nextTx Next sequence number. - */ -static void -NextTxTracer(std::string context, SequenceNumber32 old [[maybe_unused]], SequenceNumber32 nextTx) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - *nextTxStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << nextTx << std::endl; -} - -/** - * In-flight tracer. - * - * @param context The context. - * @param old Old value. - * @param inFlight In flight value. - */ -static void -InFlightTracer(std::string context, uint32_t old [[maybe_unused]], uint32_t inFlight) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - *inFlightStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << inFlight << std::endl; -} - -/** - * Next RX tracer. - * - * @param context The context. - * @param old Old sequence number. - * @param nextRx Next sequence number. - */ -static void -NextRxTracer(std::string context, SequenceNumber32 old [[maybe_unused]], SequenceNumber32 nextRx) -{ - uint32_t nodeId = GetNodeIdFromContext(context); - - *nextRxStream[nodeId]->GetStream() - << Simulator::Now().GetSeconds() << " " << nextRx << std::endl; -} - -/** - * Congestion window trace connection. - * - * @param cwnd_tr_file_name Congestion window trace file name. - * @param nodeId Node ID. - */ -static void -TraceCwnd(std::string cwnd_tr_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - cWndStream[nodeId] = ascii.CreateFileStream(cwnd_tr_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + - "/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow", - MakeCallback(&CwndTracer)); -} - -/** - * Slow start threshold trace connection. - * - * @param ssthresh_tr_file_name Slow start threshold trace file name. - * @param nodeId Node ID. - */ -static void -TraceSsThresh(std::string ssthresh_tr_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - ssThreshStream[nodeId] = ascii.CreateFileStream(ssthresh_tr_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + - "/$ns3::TcpL4Protocol/SocketList/0/SlowStartThreshold", - MakeCallback(&SsThreshTracer)); -} - -/** - * RTT trace connection. - * - * @param rtt_tr_file_name RTT trace file name. - * @param nodeId Node ID. - */ -static void -TraceRtt(std::string rtt_tr_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - rttStream[nodeId] = ascii.CreateFileStream(rtt_tr_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + "/$ns3::TcpL4Protocol/SocketList/0/RTT", - MakeCallback(&RttTracer)); -} - -/** - * RTO trace connection. - * - * @param rto_tr_file_name RTO trace file name. - * @param nodeId Node ID. - */ -static void -TraceRto(std::string rto_tr_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - rtoStream[nodeId] = ascii.CreateFileStream(rto_tr_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + "/$ns3::TcpL4Protocol/SocketList/0/RTO", - MakeCallback(&RtoTracer)); -} - -/** - * Next TX trace connection. - * - * @param next_tx_seq_file_name Next TX trace file name. - * @param nodeId Node ID. - */ -static void -TraceNextTx(std::string& next_tx_seq_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - nextTxStream[nodeId] = ascii.CreateFileStream(next_tx_seq_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + - "/$ns3::TcpL4Protocol/SocketList/0/NextTxSequence", - MakeCallback(&NextTxTracer)); -} - -/** - * In flight trace connection. - * - * @param in_flight_file_name In flight trace file name. - * @param nodeId Node ID. - */ -static void -TraceInFlight(std::string& in_flight_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - inFlightStream[nodeId] = ascii.CreateFileStream(in_flight_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + - "/$ns3::TcpL4Protocol/SocketList/0/BytesInFlight", - MakeCallback(&InFlightTracer)); -} - -/** - * Next RX trace connection. - * - * @param next_rx_seq_file_name Next RX trace file name. - * @param nodeId Node ID. - */ -static void -TraceNextRx(std::string& next_rx_seq_file_name, uint32_t nodeId) -{ - AsciiTraceHelper ascii; - nextRxStream[nodeId] = ascii.CreateFileStream(next_rx_seq_file_name); - Config::Connect("/NodeList/" + std::to_string(nodeId) + - "/$ns3::TcpL4Protocol/SocketList/1/RxBuffer/NextRxSequence", - MakeCallback(&NextRxTracer)); -} - -int -main(int argc, char* argv[]) -{ - std::string transport_prot = "TcpWestwoodPlus"; - double error_p = 0.0; - std::string bandwidth = "2Mbps"; - std::string delay = "0.01ms"; - std::string access_bandwidth = "10Mbps"; - std::string access_delay = "45ms"; - bool tracing = false; - std::string prefix_file_name = "TcpVariantsComparison"; - uint64_t data_mbytes = 0; - uint32_t mtu_bytes = 400; - uint16_t num_flows = 1; - double duration = 100.0; - uint32_t run = 0; - bool flow_monitor = false; - bool pcap = false; - bool sack = true; - std::string queue_disc_type = "ns3::PfifoFastQueueDisc"; - std::string recovery = "ns3::TcpClassicRecovery"; - - CommandLine cmd(__FILE__); - cmd.AddValue("transport_prot", - "Transport protocol to use: TcpNewReno, TcpLinuxReno, " - "TcpHybla, TcpHighSpeed, TcpHtcp, TcpVegas, TcpScalable, TcpVeno, " - "TcpBic, TcpYeah, TcpIllinois, TcpWestwoodPlus, TcpLedbat, " - "TcpLp, TcpDctcp, TcpCubic, TcpBbr", - transport_prot); - cmd.AddValue("error_p", "Packet error rate", error_p); - cmd.AddValue("bandwidth", "Bottleneck bandwidth", bandwidth); - cmd.AddValue("delay", "Bottleneck delay", delay); - cmd.AddValue("access_bandwidth", "Access link bandwidth", access_bandwidth); - cmd.AddValue("access_delay", "Access link delay", access_delay); - cmd.AddValue("tracing", "Flag to enable/disable tracing", tracing); - cmd.AddValue("prefix_name", "Prefix of output trace file", prefix_file_name); - cmd.AddValue("data", "Number of Megabytes of data to transmit", data_mbytes); - cmd.AddValue("mtu", "Size of IP packets to send in bytes", mtu_bytes); - cmd.AddValue("num_flows", "Number of flows", num_flows); - cmd.AddValue("duration", "Time to allow flows to run in seconds", duration); - cmd.AddValue("run", "Run index (for setting repeatable seeds)", run); - cmd.AddValue("flow_monitor", "Enable flow monitor", flow_monitor); - cmd.AddValue("pcap_tracing", "Enable or disable PCAP tracing", pcap); - cmd.AddValue("queue_disc_type", - "Queue disc type for gateway (e.g. ns3::CoDelQueueDisc)", - queue_disc_type); - cmd.AddValue("sack", "Enable or disable SACK option", sack); - cmd.AddValue("recovery", "Recovery algorithm type to use (e.g., ns3::TcpPrrRecovery", recovery); - cmd.Parse(argc, argv); - - transport_prot = std::string("ns3::") + transport_prot; - - SeedManager::SetSeed(1); - SeedManager::SetRun(run); - - // User may find it convenient to enable logging - // LogComponentEnable("TcpVariantsComparison", LOG_LEVEL_ALL); - // LogComponentEnable("BulkSendApplication", LOG_LEVEL_INFO); - // LogComponentEnable("PfifoFastQueueDisc", LOG_LEVEL_ALL); - - // Calculate the ADU size - Header* temp_header = new Ipv4Header(); - uint32_t ip_header = temp_header->GetSerializedSize(); - NS_LOG_LOGIC("IP Header size is: " << ip_header); - delete temp_header; - temp_header = new TcpHeader(); - uint32_t tcp_header = temp_header->GetSerializedSize(); - NS_LOG_LOGIC("TCP Header size is: " << tcp_header); - delete temp_header; - uint32_t tcp_adu_size = mtu_bytes - 20 - (ip_header + tcp_header); - NS_LOG_LOGIC("TCP ADU size is: " << tcp_adu_size); - - // Set the simulation start and stop time - double start_time = 0.1; - double stop_time = start_time + duration; - - // 2 MB of TCP buffer - Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(1 << 21)); - Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(1 << 21)); - Config::SetDefault("ns3::TcpSocketBase::Sack", BooleanValue(sack)); - - Config::SetDefault("ns3::TcpL4Protocol::RecoveryType", - TypeIdValue(TypeId::LookupByName(recovery))); - // Select TCP variant - TypeId tcpTid; - NS_ABORT_MSG_UNLESS(TypeId::LookupByNameFailSafe(transport_prot, &tcpTid), - "TypeId " << transport_prot << " not found"); - Config::SetDefault("ns3::TcpL4Protocol::SocketType", - TypeIdValue(TypeId::LookupByName(transport_prot))); - - // Create gateways, sources, and sinks - NodeContainer gateways; - gateways.Create(1); - NodeContainer sources; - sources.Create(num_flows); - NodeContainer sinks; - sinks.Create(num_flows); - - // Configure the error model - // Here we use RateErrorModel with packet error rate - Ptr uv = CreateObject(); - uv->SetStream(50); - RateErrorModel error_model; - error_model.SetRandomVariable(uv); - error_model.SetUnit(RateErrorModel::ERROR_UNIT_PACKET); - error_model.SetRate(error_p); - - PointToPointHelper UnReLink; - UnReLink.SetDeviceAttribute("DataRate", StringValue(bandwidth)); - UnReLink.SetChannelAttribute("Delay", StringValue(delay)); - UnReLink.SetDeviceAttribute("ReceiveErrorModel", PointerValue(&error_model)); - - InternetStackHelper stack; - stack.InstallAll(); - - TrafficControlHelper tchPfifo; - tchPfifo.SetRootQueueDisc("ns3::PfifoFastQueueDisc"); - - TrafficControlHelper tchCoDel; - tchCoDel.SetRootQueueDisc("ns3::CoDelQueueDisc"); - - Ipv4AddressHelper address; - address.SetBase("10.0.0.0", "255.255.255.0"); - - // Configure the sources and sinks net devices - // and the channels between the sources/sinks and the gateways - PointToPointHelper LocalLink; - LocalLink.SetDeviceAttribute("DataRate", StringValue(access_bandwidth)); - LocalLink.SetChannelAttribute("Delay", StringValue(access_delay)); - - Ipv4InterfaceContainer sink_interfaces; - - DataRate access_b(access_bandwidth); - DataRate bottle_b(bandwidth); - Time access_d(access_delay); - Time bottle_d(delay); - - uint32_t size = static_cast((std::min(access_b, bottle_b).GetBitRate() / 8) * - ((access_d + bottle_d) * 2).GetSeconds()); - - Config::SetDefault("ns3::PfifoFastQueueDisc::MaxSize", - QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, size / mtu_bytes))); - Config::SetDefault("ns3::CoDelQueueDisc::MaxSize", - QueueSizeValue(QueueSize(QueueSizeUnit::BYTES, size))); - - for (uint32_t i = 0; i < num_flows; i++) - { - NetDeviceContainer devices; - devices = LocalLink.Install(sources.Get(i), gateways.Get(0)); - tchPfifo.Install(devices); - address.NewNetwork(); - Ipv4InterfaceContainer interfaces = address.Assign(devices); - - devices = UnReLink.Install(gateways.Get(0), sinks.Get(i)); - if (queue_disc_type == "ns3::PfifoFastQueueDisc") - { - tchPfifo.Install(devices); - } - else if (queue_disc_type == "ns3::CoDelQueueDisc") - { - tchCoDel.Install(devices); - } - else - { - NS_FATAL_ERROR("Queue not recognized. Allowed values are ns3::CoDelQueueDisc or " - "ns3::PfifoFastQueueDisc"); - } - address.NewNetwork(); - interfaces = address.Assign(devices); - sink_interfaces.Add(interfaces.Get(1)); - } - - NS_LOG_INFO("Initialize Global Routing."); - Ipv4GlobalRoutingHelper::PopulateRoutingTables(); - - uint16_t port = 50000; - Address sinkLocalAddress(InetSocketAddress(Ipv4Address::GetAny(), port)); - PacketSinkHelper sinkHelper("ns3::TcpSocketFactory", sinkLocalAddress); - - for (uint32_t i = 0; i < sources.GetN(); i++) - { - // Assign a different TCP variant to each flow - std::string tcpVariant; - switch (i % 2) // Example: Rotate between two TCP variants - { - case 0: - tcpVariant = "ns3::TcpNewReno"; - break; - case 1: - tcpVariant = "ns3::TcpCubic"; - break; - default: - tcpVariant = "ns3::TcpNewReno"; - } - - // Set the TCP variant for this flow - Config::Set("/NodeList/" + std::to_string(sources.Get(i)->GetId()) + - "/$ns3::TcpL4Protocol/SocketType", - StringValue(tcpVariant)); - - // Configure the BulkSend application - Address remoteAddress(InetSocketAddress(sink_interfaces.GetAddress(i, 0), port)); - BulkSendHelper ftp("ns3::TcpSocketFactory", remoteAddress); - ftp.SetAttribute("SendSize", UintegerValue(tcp_adu_size)); - ftp.SetAttribute("MaxBytes", UintegerValue(data_mbytes * 1000000)); - - ApplicationContainer sourceApp = ftp.Install(sources.Get(i)); - sourceApp.Start(Seconds(start_time * i)); - sourceApp.Stop(Seconds(stop_time - 3)); - - // Configure the PacketSink application - sinkHelper.SetAttribute("Protocol", TypeIdValue(TcpSocketFactory::GetTypeId())); - ApplicationContainer sinkApp = sinkHelper.Install(sinks.Get(i)); - sinkApp.Start(Seconds(start_time * i)); - sinkApp.Stop(Seconds(stop_time)); - } - - // Set up tracing if enabled - if (tracing) - { - std::ofstream ascii; - Ptr ascii_wrap; - ascii.open(prefix_file_name + "-ascii"); - ascii_wrap = new OutputStreamWrapper(prefix_file_name + "-ascii", std::ios::out); - stack.EnableAsciiIpv4All(ascii_wrap); - - for (uint16_t index = 0; index < num_flows; index++) - { - std::string flowString; - if (num_flows > 1) - { - flowString = "-flow" + std::to_string(index); - } - - firstCwnd[index + 1] = true; - firstSshThr[index + 1] = true; - firstRtt[index + 1] = true; - firstRto[index + 1] = true; - - Simulator::Schedule(Seconds(start_time * index + 0.00001), - &TraceCwnd, - prefix_file_name + flowString + "-cwnd.data", - index + 1); - Simulator::Schedule(Seconds(start_time * index + 0.00001), - &TraceSsThresh, - prefix_file_name + flowString + "-ssth.data", - index + 1); - Simulator::Schedule(Seconds(start_time * index + 0.00001), - &TraceRtt, - prefix_file_name + flowString + "-rtt.data", - index + 1); - Simulator::Schedule(Seconds(start_time * index + 0.00001), - &TraceRto, - prefix_file_name + flowString + "-rto.data", - index + 1); - Simulator::Schedule(Seconds(start_time * index + 0.00001), - &TraceNextTx, - prefix_file_name + flowString + "-next-tx.data", - index + 1); - Simulator::Schedule(Seconds(start_time * index + 0.00001), - &TraceInFlight, - prefix_file_name + flowString + "-inflight.data", - index + 1); - Simulator::Schedule(Seconds(start_time * index + 0.1), - &TraceNextRx, - prefix_file_name + flowString + "-next-rx.data", - num_flows + index + 1); - } - } - - if (pcap) - { - UnReLink.EnablePcapAll(prefix_file_name, true); - LocalLink.EnablePcapAll(prefix_file_name, true); - } - - // Flow monitor - FlowMonitorHelper flowHelper; - if (flow_monitor) - { - flowHelper.InstallAll(); - } - - Simulator::Stop(Seconds(stop_time)); - Simulator::Run(); - - if (flow_monitor) - { - flowHelper.SerializeToXmlFile(prefix_file_name + ".flowmonitor", true, true); - } - - Simulator::Destroy(); - return 0; -} diff --git a/timeserver/Makefile b/timeserver/Makefile deleted file mode 100644 index 6f7d8b7..0000000 --- a/timeserver/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -CC = gcc -Wall -std=c11 -pedantic -SOURCES = timeserver.c -OBJECTS = timeserver.o - -all: timeserver - -timeserver: $(OBJECTS) - $(CC) $(OBJECTS) -o timeserver - -timeserver.o: timeserver.c - $(CC) -c timeserver.c -o timeserver.o - -clean: - rm -f $(OBJECTS) timeserver timeserver.out - -clean_objects: - rm -f $(OBJECTS) - -run: - ./timeserver diff --git a/timeserver/README.md b/timeserver/README.md deleted file mode 100644 index b9d8b6a..0000000 --- a/timeserver/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Running the timeserver -Use `make` to compile the timeserver. -Use `make run` to run the timeserver. This will run on an infinite loop. -Use `Ctrl+C` to stop the timeserver. - -## timeserver communication -Communicating with the server can happen using netcat in UDP mode (-u flag). - -## timeserver information -The timeserver runs on UDP port 8888. -The timeserver will wait for `time\r\n` to be sent on this port, and if received, -will send back a response of the time (in ms) since January 1st, 1970 (UNIX Epoch). - -## pcap information -A demonstration of the timeserver has been captured with Wireshark in the -included `demo.pcap` file. \ No newline at end of file diff --git a/timeserver/demo.pcap b/timeserver/demo.pcap deleted file mode 100644 index 6c48bde..0000000 Binary files a/timeserver/demo.pcap and /dev/null differ diff --git a/timeserver/timeserver.c b/timeserver/timeserver.c deleted file mode 100644 index 6eef908..0000000 --- a/timeserver/timeserver.c +++ /dev/null @@ -1,83 +0,0 @@ -// header files -#include "timeserver.h" - -// constants -// timeserver port is 8888 -#define TIMEPORT 8888 -#define BUFFER_SIZE 1024 - -// prototypes - -// main function -int main(int argc, char **argv) -{ - // initialize program (variables and structs) - bool quitFlag = true; - int socketTimeFD; - char message[BUFFER_SIZE]; - struct sockaddr_in serverAddr, clientAddr; - memset(&serverAddr, 0, sizeof(serverAddr)); - memset(&clientAddr, 0, sizeof(clientAddr)); - // define a UDP socket - socketTimeFD = socket(AF_INET, SOCK_DGRAM, 0); - if(socketTimeFD < 0) - { - printf("Unable to create the socket."); - return -1; - } - // bind the UDP socket to port 8888 / TIMEPORT - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = INADDR_ANY; - serverAddr.sin_port = htons(TIMEPORT); - int bindCheck = bind(socketTimeFD, &serverAddr, sizeof(serverAddr)); - if(bindCheck < 0) - { - printf("Unable to bind the socket to the port or address.\n Is either in use?"); - return -1; - } - // while loop to see if the "time\r\n" has been received (recv call?) - printf("Timeserver listening on port: %d\n", TIMEPORT); - while(quitFlag) - { - int clientAddrLen; - int receivedDataLen; - // grab the data from the client - receivedDataLen = recvfrom(socketTimeFD, message, BUFFER_SIZE, MSG_WAITALL, &clientAddr, &clientAddrLen); - message[receivedDataLen] = '\0'; - // if "time\r\n" is received, then send() back the linux epoch. - if(strcmp(message, "time\n") == 0 || strcmp(message, "time\r\n") == 0) - { - // setup the reply message - char reply[BUFFER_SIZE]; - // add the current time to the reply - sprintf(reply, "%d", time(NULL)); - // send the reply to the requestee - sendto(socketTimeFD, (const char *)reply, strlen(reply), 0, (const struct sockaddr *) &clientAddr, clientAddrLen); - // log the time command recv'd - printf("\nServer received time. Replied with: %d\n", time(NULL)); - } - else if (strcmp(message, "close\n") == 0 || strcmp(message, "quit\n") == 0 || strcmp(message, "q\n") == 0) - { - // if the server recv'd the close command, then close the server. - printf("\nServer received close.\n"); - quitFlag = false; - } - } - // close the socket - close(socketTimeFD); - // profit??? - return 0; -} - -// function definitions - -/* -Name: ??? -Process: ??? -Function Input/Parameters: ??? -Function Output/Parameters: ??? -Function Output/Returned: ??? -Device Input/Device: ??? -Device Output/Device: ??? -Dependencies: ??? -*/ \ No newline at end of file diff --git a/timeserver/timeserver.h b/timeserver/timeserver.h deleted file mode 100644 index 1a8135b..0000000 --- a/timeserver/timeserver.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TIMESERVER -#define TIMESERVER - -// included libraries -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// data structures - -// function prototypes - -#endif // TIMESERVER \ No newline at end of file