diff --git a/6-RShell/questions.md b/6-RShell/questions.md index 43ffc1074f8ea23f1bd68675be2ef81b5b4900b3..6d110227a51fb19d5650e4a9957f45988293654a 100644 --- a/6-RShell/questions.md +++ b/6-RShell/questions.md @@ -1,19 +1,22 @@ 1. How does the remote client determine when a command's output is fully received from the server, and what techniques can be used to handle partial reads or ensure complete message transmission? -_answer here_ +Using EOF, the remote client can determine when a command's output is fully received. To handle this, we can use a loop to send and recv all data until reaching EOF. 2. This week's lecture on TCP explains that it is a reliable stream protocol rather than a message-oriented one. Since TCP does not preserve message boundaries, how should a networked shell protocol define and detect the beginning and end of a command sent over a TCP connection? What challenges arise if this is not handled correctly? -_answer here_ +The networked shell protocol can't define and detect the beginning and end of a command by itself. We need to do it manually. A technique is using a special character to mark the end of a logical stream. If it's not handled correctly, the network may send multiple receives, each may include a tab, a newline or a space, etc in the end of the command. 3. Describe the general differences between stateful and stateless protocols. -_answer here_ +Stateless protocol: It will not store the state of the protocol. Therefore, it's faster and less overhead, but less reliable +Stateful protocol: It will store the state of the protocol; thus, it has better reliability. However, stateful protocol requires more +memory and storage, leading to slower implementation speed. 4. Our lecture this week stated that UDP is "unreliable". If that is the case, why would we ever use it? -_answer here_ +Because it's faster and less overhead compared to TCP. It's a tradeoff, where sometimes the benefit of quick data transmission and low required memory storage will outweigh the risk of missing some data 5. What interface/abstraction is provided by the operating system to enable applications to use network communications? -_answer here_ \ No newline at end of file +Sockets are provided by the operating system to enable applications to use network communications. It's a programming interface, and also provide a "file" abstraction for making network communications. + diff --git a/6-RShell/starter/bats/student_tests.sh b/6-RShell/starter/bats/student_tests.sh index 638bc341446f7580a80c2aff52971b8023407ea8..471830a58c5702a0f0d259c0f0e055908059a8c0 100755 --- a/6-RShell/starter/bats/student_tests.sh +++ b/6-RShell/starter/bats/student_tests.sh @@ -12,3 +12,530 @@ EOF # Assertions [ "$status" -eq 0 ] } + +@test "Local Mode: No command provided" { + run ./dsh <<EOF + +exit +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="localmodedsh4>warning:nocommandsprovideddsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + +} + +@test "Local Mode: Simple Command" { + current=$(pwd) + cd /tmp + run "${current}/dsh" <<EOF +pwd +exit +EOF + +# Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/tmplocalmodedsh4>dsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Local Mode: Multiple wrong commands" { + run ./dsh <<EOF +echo " hello world " | hello | hi | ok +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="localmodedsh4>Wrongcommandlocalmodedsh4>dsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + +} + +@test "Local Mode: yes command" { + run ./dsh << EOF +yes "hello world " | head -n 3 +EOF +# Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output="hello world hello world hello world local modedsh4> dsh4> cmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + + +} + +@test "Server/Client: No command provided" { + + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF + +stop-server +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output="socket client mode: addr:10.246.251.14:1234dsh4> warning: no commands provideddsh4> cmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + +} + + +@test "Server/Client: Simple Command cd and pwd" { + + + + mkdir -p test + cd test + touch test.c + cd .. + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +cd test +ls +stop-server +EOF + +rm -rf test + +# Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output="socket client mode: addr:10.246.251.14:1234dsh4> cd testdsh4> test.clsdsh4> cmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Server/Client: test mkdir command" { + + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +mkdir -p mkdir-test +ls | grep mkdir-test +stop-server +EOF + +rm -rf mkdir-test + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output="socket client mode: addr:10.246.251.14:1234dsh4> mkdir -p mkdir-testdsh4> mkdir-testls | grep mkdir-testdsh4> cmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${output}" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + +} + +@test "Server/Client: test rm command" { + + touch rm_test_file rm_test_file_1 + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +rm -f rm_test_file +ls | grep rm_test +stop-server +EOF + +rm -f rm_test_file_1 + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output="socket client mode: addr:10.246.251.14:1234dsh4> rm -f rm_test_filedsh4> dsh4> rm_test_file_1ls | grep rm_testcmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${output}" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Server/Client: 2 commands with pipe" { + + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +ls | grep dshlib.c +stop-server +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="socketclientmode:addr:10.246.251.14:1234dsh4>dshlib.cls|grepdshlib.cdsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Server/Client: 3 commands with pipes" { + + mkdir -p student-test + cd student-test + touch test_file + cd .. + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +cd student-test | ls | grep test +stop-server +EOF + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="socketclientmode:addr:10.246.251.14:1234dsh4>test_filecdstudent-test|ls|greptestdsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + + rm -rf student-test + +} + +@test "Server/Client: try more max (8) commands" { + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +pwd | pwd | cd bats | pwd | pwd | pwd | pwd | grep dsh_cli.c | grep dshlib.c +stop-server +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output="socket client mode: addr:10.246.251.14:1234dsh4> pwd | pwd | cd bats | pwd | pwd | pwd | pwd | grep dsh_cli.c | grep dshlib.cdsh4> pwd | pwd | cd bats | pwd | pwd | pwd | pwd | grep dsh_cli.c | grep dshlib.ccmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + +} + +@test "Server/Client: mv command" { + + + rm -f mv_file mv_file_1 + + touch mv_file + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +mv mv_file mv_file_1 +ls | grep mv_file +stop-server +EOF + +rm -f mv_file_1 + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="socketclientmode:addr:10.246.251.14:1234dsh4>mvmv_filemv_file_1dsh4>dsh4>mv_file_1ls|grepmv_filecmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${output}" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + rm my_file +} + +@test "Server/Client: test remove file/directory command" { + + rm -rf student-test student-test-1 student-test-2 + mkdir -p student-test student-test-1 student-test-2 + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +rm -r student-test-1 +ls | grep test +stop-server +EOF + +rm -rf student-test student-test-2 + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="socketclientmode:addr:10.246.251.14:1234dsh4>rm-rstudent-test-1dsh4>student-teststudent-test-2ls|greptestdsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${output}" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Server/Client: test cat command" { + + rm -rf cat.txt + touch cat.txt + echo "This is a test file" >> cat.txt + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +cat cat.txt +stop-server +EOF + +rm -rf cat.txt + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="socketclientmode:addr:10.246.251.14:1234dsh4>Thisisatestfilecatcat.txtdsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] + +} + +@test "Server/Client: test cp command" { + + + rm -rf cp_dic_1 cp_dic_2 + mkdir cp_dic_1 cp_dic_2 + cd cp_dic_1 + touch cp_file_1 + cd .. + cd cp_dic_2 + touch cp_file_2 + cd .. + + run ./dsh -s -i 0.0.0.0 -p 1234 & + + sleep 0.1 + + run ./dsh -c -i 10.246.251.14 -p 1234 << EOF +cp cp_dic_1/cp_file_1 cp_dic_2/ +cd cp_dic_2 +ls | grep cp_file +stop-server +EOF + +rm -rf cp_dic_1 cp_dic_2 +# Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="socketclientmode:addr:10.246.251.14:1234dsh4>cpcp_dic_1/cp_file_1cp_dic_2/dsh4>cdcp_dic_2dsh4>cp_file_1cp_file_2ls|grepcp_filedsh4>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + + + + + + + + + diff --git a/6-RShell/starter/dsh_cli.c b/6-RShell/starter/dsh_cli.c index c443224971df06e2b3160fa9b13f44a6f45de18f..68fab16a055b002e0a6084fdc4d0a26e13147d80 100644 --- a/6-RShell/starter/dsh_cli.c +++ b/6-RShell/starter/dsh_cli.c @@ -129,7 +129,6 @@ int main(int argc, char *argv[]){ break; case MODE_SCLI: printf("socket client mode: addr:%s:%d\n", cargs.ip, cargs.port); - printf("%s\n", cargs.ip); rc = exec_remote_cmd_loop(cargs.ip, cargs.port); break; case MODE_SSVR: diff --git a/6-RShell/starter/rsh_cli.c b/6-RShell/starter/rsh_cli.c index 67f5571083803c66dc41a4f602f84609ebfff2fa..12effdf28b6fffd910d856d89bff6ce65d8f6776 100644 --- a/6-RShell/starter/rsh_cli.c +++ b/6-RShell/starter/rsh_cli.c @@ -121,6 +121,7 @@ int exec_remote_cmd_loop(char *address, int port) cmd_buff[strcspn(cmd_buff,"\n")] = '\0'; if (cmd_buff[0] == '\0'){ + printf(CMD_WARN_NO_CMD); continue; } // TODO send() over cli_socket diff --git a/6-RShell/starter/rsh_server.c b/6-RShell/starter/rsh_server.c index b5bde8ff352681c9c9155d54640f5ad1ac2a4195..8199a316a11cd5b08162e6ec6d0ca3ce6bec0739 100644 --- a/6-RShell/starter/rsh_server.c +++ b/6-RShell/starter/rsh_server.c @@ -468,10 +468,10 @@ int rsh_execute_pipeline(int cli_sock, command_list_t *clist) { } else { // Set up input pipe for all except first and last process if (i > 0) { - dup2(pipes[i-1][0], STDOUT_FILENO); + dup2(pipes[i-1][0], STDIN_FILENO); } if (i < clist->num-1){ - dup2(pipes[i][1], STDIN_FILENO); + dup2(pipes[i][1], STDOUT_FILENO); } } // Close all pipe ends in child