From d256c28b5444d97991e9f7b3a9a3e4280e1144dc Mon Sep 17 00:00:00 2001
From: vyvyvyThao <wn73@drexel.edu>
Date: Thu, 13 Mar 2025 22:13:57 -0400
Subject: [PATCH] upload

---
 6-RShell/bats/assignment_tests.sh |  36 ++
 6-RShell/bats/student_tests.sh    | 148 ++++++
 6-RShell/dsh                      | Bin 0 -> 59104 bytes
 6-RShell/dsh_cli.c                | 149 ++++++
 6-RShell/dshlib.c                 | 365 +++++++++++++++
 6-RShell/dshlib.h                 |  92 ++++
 6-RShell/makefile                 |  31 ++
 6-RShell/questions.md             |  19 +
 6-RShell/rsh_cli.c                | 258 +++++++++++
 6-RShell/rsh_server.c             | 745 ++++++++++++++++++++++++++++++
 6-RShell/rshlib.h                 |  78 ++++
 11 files changed, 1921 insertions(+)
 create mode 100644 6-RShell/bats/assignment_tests.sh
 create mode 100644 6-RShell/bats/student_tests.sh
 create mode 100755 6-RShell/dsh
 create mode 100644 6-RShell/dsh_cli.c
 create mode 100644 6-RShell/dshlib.c
 create mode 100644 6-RShell/dshlib.h
 create mode 100644 6-RShell/makefile
 create mode 100644 6-RShell/questions.md
 create mode 100644 6-RShell/rsh_cli.c
 create mode 100644 6-RShell/rsh_server.c
 create mode 100644 6-RShell/rshlib.h

diff --git a/6-RShell/bats/assignment_tests.sh b/6-RShell/bats/assignment_tests.sh
new file mode 100644
index 0000000..7a8a30c
--- /dev/null
+++ b/6-RShell/bats/assignment_tests.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bats
+
+############################ DO NOT EDIT THIS FILE #####################################
+# File: assignement_tests.sh
+# 
+# DO NOT EDIT THIS FILE
+#
+# Add/Edit Student tests in student_tests.sh
+# 
+# All tests in this file must pass - it is used as part of grading!
+########################################################################################
+
+@test "Pipes" {
+    run "./dsh" <<EOF                
+ls | grep dshlib.c
+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="dshlib.clocalmodedsh4>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 ]
+}
\ No newline at end of file
diff --git a/6-RShell/bats/student_tests.sh b/6-RShell/bats/student_tests.sh
new file mode 100644
index 0000000..48122f5
--- /dev/null
+++ b/6-RShell/bats/student_tests.sh
@@ -0,0 +1,148 @@
+#!/usr/bin/env bats
+
+# File: student_tests.sh
+# Testing the remote shell server implementation
+
+# helper function to start server in background
+setup() {
+    # create a test directory and files
+    mkdir -p rshell_test
+    cd rshell_test
+    echo "test content" > testfile.txt
+    
+    # start server in background with test port
+    ../dsh -s -p 5555 &
+    SERVER_PID=$!
+    sleep 1
+}
+
+# helper function to cleanup after each test
+teardown() {
+    # kill server if it's running
+    if [ -n "$SERVER_PID" ]; then
+        kill $SERVER_PID 2>/dev/null || true
+        wait $SERVER_PID 2>/dev/null || true
+    fi
+    
+    # cleanup test directory
+    cd ..
+    rm -rf rshell_test
+}
+
+@test "test_server_startup" {
+    # check if server process is running
+    ps -p $SERVER_PID
+    [ "$?" -eq 0 ]
+}
+
+# test server file creation
+@test "test_server_file_operations" {
+    # create a file through client command
+    echo "touch serverfile.txt" | ../dsh -c -p 5555
+    
+    # verify file exists on server side
+    [ -f "serverfile.txt" ]
+}
+
+# test server directory operations
+@test "test_server_directory_operations" {
+    # create directory through client
+    echo "mkdir testdir" | ../dsh -c -p 5555
+    
+    # verify directory exists on server side
+    [ -d "testdir" ]
+    
+    # change into directory and create file
+    {
+        echo "cd testdir"
+        echo "touch inside.txt"
+    } | ../dsh -c -p 5555
+    
+    # verify file exists in correct location on server
+    [ -f "testdir/inside.txt" ]
+}
+
+# test server file content modification
+@test "test_server_file_modification" {
+    # create and write to file through client
+    {
+        echo "echo 'server content' > server_write.txt"
+        echo "exit"
+    } | ../dsh -c -p 5555
+    
+    # verify file content on server side
+    [ -f "server_write.txt" ]
+    grep -q "server content" "server_write.txt"
+}
+
+# test server pipe operations
+@test "test_server_pipe_operations" {
+    # create test files on server side
+    echo "line1\nline2\nline3" > input.txt
+    
+    # use pipe operation through client
+    echo "cat input.txt | grep line2 > output.txt" | ../dsh -c -p 5555
+    
+    # verify result on server side
+    [ -f "output.txt" ]
+    grep -q "line2" "output.txt"
+}
+
+# test ls command
+@test "test_server_ls" {
+    echo "ls > ls.txt" | ../dsh -c -p 5555
+    [ -f "ls.txt" ]
+    grep -q "testfile.txt" "ls.txt"
+}
+
+# test server stop command
+@test "test_server_stop" {
+    # tend stop-server command
+    echo "stop-server" | ../dsh -c -p 5555
+    
+    # wait
+    sleep 1
+    
+    # verify server process is no longer running
+    ! ps -p $SERVER_PID
+}
+
+# test server concurrent file access (if extra credit implemented)
+# @test "test_server_concurrent_access" {
+#     # create a test file
+#     echo "initial" > /tmp/rshell_test/concurrent.txt
+    
+#     # start two clients modifying the same file
+#     {
+#         echo "echo 'client1' >> concurrent.txt"
+#         echo "exit"
+#     } | ../dsh -c -p 5555 &
+    
+#     {
+#         echo "echo 'client2' >> concurrent.txt"
+#         echo "exit"
+#     } | ../dsh -c -p 5555 &
+    
+#     # wait for both to complete
+#     wait
+    
+#     # verify both writes occurred on server side
+#     grep -q "client1" "/tmp/rshell_test/concurrent.txt"
+#     grep -q "client2" "/tmp/rshell_test/concurrent.txt"
+# }
+
+# test server working directory persistence
+@test "test_server_working_directory" {
+    # create nested directories
+    mkdir -p dir1/dir2
+    
+    # change directory and verify through file creation
+    {
+        echo "cd dir1/dir2"
+        echo "pwd > pwd.txt"
+    } | ../dsh -c -p 5555
+    
+    # verify pwd.txt exists in correct directory on server
+    [ -f "dir1/dir2/pwd.txt" ]
+    grep -q "dir2" "dir1/dir2/pwd.txt"
+}
diff --git a/6-RShell/dsh b/6-RShell/dsh
new file mode 100755
index 0000000000000000000000000000000000000000..f0986ffee5e69623bdb243354d3231acdf40615c
GIT binary patch
literal 59104
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

literal 0
HcmV?d00001

diff --git a/6-RShell/dsh_cli.c b/6-RShell/dsh_cli.c
new file mode 100644
index 0000000..68fab16
--- /dev/null
+++ b/6-RShell/dsh_cli.c
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <argp.h>
+#include <getopt.h>
+
+#include "dshlib.h"
+#include "rshlib.h"
+
+
+/*
+ * Used to pass startup parameters back to main
+ */
+#define MODE_LCLI   0       //Local client
+#define MODE_SCLI   1       //Socket client
+#define MODE_SSVR   2       //Socket server
+
+typedef struct cmd_args{
+  int   mode;
+  char  ip[16];   //e.g., 192.168.100.101\0
+  int   port;
+  int   threaded_server;
+}cmd_args_t;
+
+
+
+//You dont really need to understand this but the C runtime library provides
+//an getopt() service to simplify handling command line arguments.  This
+//code will help setup dsh to handle triggering client or server mode along
+//with passing optional connection parameters. 
+
+void print_usage(const char *progname) {
+  printf("Usage: %s [-c | -s] [-i IP] [-p PORT] [-x] [-h]\n", progname);
+  printf("  Default is to run %s in local mode\n", progname);
+  printf("  -c            Run as client\n");
+  printf("  -s            Run as server\n");
+  printf("  -i IP         Set IP/Interface address (only valid with -c or -s)\n");
+  printf("  -p PORT       Set port number (only valid with -c or -s)\n");
+  printf("  -x            Enable threaded mode (only valid with -s)\n");
+  printf("  -h            Show this help message\n");
+  exit(0);
+}
+
+void parse_args(int argc, char *argv[], cmd_args_t *cargs) {
+  int opt;
+  memset(cargs, 0, sizeof(cmd_args_t));
+
+  //defaults
+  cargs->mode = MODE_LCLI;
+  cargs->port = RDSH_DEF_PORT;
+
+  while ((opt = getopt(argc, argv, "csi:p:xh")) != -1) {
+      switch (opt) {
+          case 'c':
+              if (cargs->mode != MODE_LCLI) {
+                  fprintf(stderr, "Error: Cannot use both -c and -s\n");
+                  exit(EXIT_FAILURE);
+              }
+              cargs->mode = MODE_SCLI;
+              strncpy(cargs->ip, RDSH_DEF_CLI_CONNECT, sizeof(cargs->ip) - 1);
+              break;
+          case 's':
+              if (cargs->mode != MODE_LCLI) {
+                  fprintf(stderr, "Error: Cannot use both -c and -s\n");
+                  exit(EXIT_FAILURE);
+              }
+              cargs->mode = MODE_SSVR;
+              strncpy(cargs->ip, RDSH_DEF_SVR_INTFACE, sizeof(cargs->ip) - 1);
+              break;
+          case 'i':
+              if (cargs->mode == MODE_LCLI) {
+                  fprintf(stderr, "Error: -i can only be used with -c or -s\n");
+                  exit(EXIT_FAILURE);
+              }
+              strncpy(cargs->ip, optarg, sizeof(cargs->ip) - 1);
+              cargs->ip[sizeof(cargs->ip) - 1] = '\0';  // Ensure null termination
+              break;
+          case 'p':
+              if (cargs->mode == MODE_LCLI) {
+                  fprintf(stderr, "Error: -p can only be used with -c or -s\n");
+                  exit(EXIT_FAILURE);
+              }
+              cargs->port = atoi(optarg);
+              if (cargs->port <= 0) {
+                  fprintf(stderr, "Error: Invalid port number\n");
+                  exit(EXIT_FAILURE);
+              }
+              break;
+          case 'x':
+              if (cargs->mode != MODE_SSVR) {
+                  fprintf(stderr, "Error: -x can only be used with -s\n");
+                  exit(EXIT_FAILURE);
+              }
+              cargs->threaded_server = 1;
+              break;
+          case 'h':
+              print_usage(argv[0]);
+              break;
+          default:
+              print_usage(argv[0]);
+      }
+  }
+
+  if (cargs->threaded_server && cargs->mode != MODE_SSVR) {
+      fprintf(stderr, "Error: -x can only be used with -s\n");
+      exit(EXIT_FAILURE);
+  }
+}
+
+
+
+/* DO NOT EDIT
+ * main() logic fully implemented to:
+ *    1. run locally (no parameters)
+ *    2. start the server with the -s option
+ *    3. start the client with the -c option
+*/
+int main(int argc, char *argv[]){
+  cmd_args_t cargs;
+  int rc;
+
+  memset(&cargs, 0, sizeof(cmd_args_t));
+  parse_args(argc, argv, &cargs);
+
+  switch(cargs.mode){
+    case MODE_LCLI:
+      printf("local mode\n");
+      rc = exec_local_cmd_loop();
+      break;
+    case MODE_SCLI:
+      printf("socket client mode:  addr:%s:%d\n", cargs.ip, cargs.port);
+      rc = exec_remote_cmd_loop(cargs.ip, cargs.port);
+      break;
+    case MODE_SSVR:
+      printf("socket server mode:  addr:%s:%d\n", cargs.ip, cargs.port);
+      if (cargs.threaded_server){
+        printf("-> Multi-Threaded Mode\n");
+      } else {
+        printf("-> Single-Threaded Mode\n");
+      }
+      rc = start_server(cargs.ip, cargs.port, cargs.threaded_server);
+      break;
+    default:
+      printf("error unknown mode\n");
+      exit(EXIT_FAILURE);
+  }
+
+  printf("cmd loop returned %d\n", rc);
+}
\ No newline at end of file
diff --git a/6-RShell/dshlib.c b/6-RShell/dshlib.c
new file mode 100644
index 0000000..c242131
--- /dev/null
+++ b/6-RShell/dshlib.c
@@ -0,0 +1,365 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "dshlib.h"
+
+void printDragon(){
+    const char dragon[39][103] = {
+"                                                                        @%%%%                       \n",                       
+"                                                                     %%%%%%                         \n",                         
+"                                                                    %%%%%%                          \n",                          
+"                                                                 % %%%%%%%           @              \n",              
+"                                                                %%%%%%%%%%        %%%%%%%           \n",           
+"                                       %%%%%%%  %%%%@         %%%%%%%%%%%%@    %%%%%%  @%%%%        \n",        
+"                                  %%%%%%%%%%%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%%%%%%%%%%%%          \n",          
+"                                %%%%%%%%%%%%%%%%%%%%%%%%%%   %%%%%%%%%%%% %%%%%%%%%%%%%%%           \n",           
+"                               %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%     %%%            \n",            
+"                             %%%%%%%%%%%%%%%%%%%%%%%%%%%%@ @%%%%%%%%%%%%%%%%%%        %%            \n",            
+"                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%                \n",                
+"                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              \n",              
+"                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%@              \n",              
+"      %%%%%%%%@           %%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%      %%                \n",                
+"    %%%%%%%%%%%%%         %%@%%%%%%%%%%%%           %%%%%%%%%%% %%%%%%%%%%%%      @%                \n",                
+"  %%%%%%%%%%   %%%        %%%%%%%%%%%%%%            %%%%%%%%%%%%%%%%%%%%%%%%                        \n",                        
+" %%%%%%%%%       %         %%%%%%%%%%%%%             %%%%%%%%%%%%@%%%%%%%%%%%                       \n",                   
+"%%%%%%%%%@                % %%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%                     \n",              
+"%%%%%%%%@                 %%@%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  \n",         
+"%%%%%%%@                   %%%%%%%%%%%%%%%           %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              \n",    
+"%%%%%%%%%%                  %%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%      %%%%  \n",
+"%%%%%%%%%@                   @%%%%%%%%%%%%%%         %%%%%%%%%%%%@ %%%% %%%%%%%%%%%%%%%%%   %%%%%%%%\n",
+"%%%%%%%%%%                  %%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%% %%%%%%%%%\n",
+"%%%%%%%%%@%%@                %%%%%%%%%%%%%%%%@       %%%%%%%%%%%%%%     %%%%%%%%%%%%%%%%%%%%%%%%  %%\n",
+" %%%%%%%%%%                  % %%%%%%%%%%%%%%@        %%%%%%%%%%%%%%   %%%%%%%%%%%%%%%%%%%%%%%%%% %%\n",
+"  %%%%%%%%%%%%  @           %%%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%% \n",
+"   %%%%%%%%%%%%% %%  %  %@ %%%%%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%% \n",
+"    %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%           @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%%%%%% \n",
+"     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              %%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%   \n",
+"      @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  %%%%%%%%%%%%%%%%%%%%%%%%%               \n",
+"        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%%%%%%  %%%%%%%          \n",
+"           %%%%%%%%%%%%%%%%%%%%%%%%%%                           %%%%%%%%%%%%%%%  @%%%%%%%%%         \n",
+"              %%%%%%%%%%%%%%%%%%%%           @%@%                  @%%%%%%%%%%%%%%%%%%   %%%        \n",
+"                  %%%%%%%%%%%%%%%        %%%%%%%%%%                    %%%%%%%%%%%%%%%    %         \n",
+"                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%            \n",
+"                %%%%%%%%%%%%%%%%%%%%%%%%%%  %%%% %%%                      %%%%%%%%%%  %%%@          \n",
+"                     %%%%%%%%%%%%%%%%%%% %%%%%% %%                          %%%%%%%%%%%%%@          \n",
+"                                                                                 %%%%%%%@           \n"
+    };
+
+
+    for (int i = 0; i < sizeof(dragon) / sizeof(dragon[0]); i++) {
+        for (int j = 0; j < sizeof(dragon[0]) / sizeof(dragon[0][0]); j++) {
+            if (dragon[i][j] == 0) break;
+            putchar((char)dragon[i][j]);
+        }
+    }
+}
+
+/*
+ * Implement your exec_local_cmd_loop function by building a loop that prompts the 
+ * user for input.  Use the SH_PROMPT constant from dshlib.h and then
+ * use fgets to accept user input.
+ * 
+ *      while(1){
+ *        printf("%s", SH_PROMPT);
+ *        if (fgets(cmd_buff, ARG_MAX, stdin) == NULL){
+ *           printf("\n");
+ *           break;
+ *        }
+ *        //remove the trailing \n from cmd_buff
+ *        cmd_buff[strcspn(cmd_buff,"\n")] = '\0';
+ * 
+ *        //IMPLEMENT THE REST OF THE REQUIREMENTS
+ *      }
+ * 
+ *   Also, use the constants in the dshlib.h in this code.  
+ *      SH_CMD_MAX              maximum buffer size for user input
+ *      EXIT_CMD                constant that terminates the dsh program
+ *      SH_PROMPT               the shell prompt
+ *      OK                      the command was parsed properly
+ *      WARN_NO_CMDS            the user command was empty
+ *      ERR_TOO_MANY_COMMANDS   too many pipes used
+ *      ERR_MEMORY              dynamic memory management failure
+ * 
+ *   errors returned
+ *      OK                     No error
+ *      ERR_MEMORY             Dynamic memory management failure
+ *      WARN_NO_CMDS           No commands parsed
+ *      ERR_TOO_MANY_COMMANDS  too many pipes used
+ *   
+ *   console messages
+ *      CMD_WARN_NO_CMD        print on WARN_NO_CMDS
+ *      CMD_ERR_PIPE_LIMIT     print on ERR_TOO_MANY_COMMANDS
+ *      CMD_ERR_EXECUTE        print on execution failure of external command
+ * 
+ *  Standard Library Functions You Might Want To Consider Using (assignment 1+)
+ *      malloc(), free(), strlen(), fgets(), strcspn(), printf()
+ * 
+ *  Standard Library Functions You Might Want To Consider Using (assignment 2+)
+ *      fork(), execvp(), exit(), chdir()
+ */
+
+int build_cmd_list(char *cmd_line, command_list_t *clist)
+{
+    if (strlen(cmd_line) == 0) {
+        printf(CMD_WARN_NO_CMD);
+        return OK;
+    }
+
+    // Initialize command list
+    clist->num = 0;
+    memset(clist->commands, 0, sizeof(clist->commands));
+
+    // Split by pipe
+    char *saveptr1;  // For the pipe tokenization
+    char *saveptr2;  // For the argument tokenization
+    char *cmd_copy = strdup(cmd_line);
+    if (!cmd_copy) return ERR_MEMORY;
+
+    char *cmd = strtok_r(cmd_copy, "|", &saveptr1);
+    while (cmd != NULL) {
+        // Trim leading/trailing spaces
+        while (*cmd == ' ') cmd++;
+        char *end = cmd + strlen(cmd) - 1;
+        while (end > cmd && *end == ' ') {
+            *end = '\0';
+            end--;
+        }
+
+        if (strlen(cmd) == 0) {
+            cmd = strtok_r(NULL, "|", &saveptr1);
+            continue;
+        }
+
+        // Check command limit
+        if (clist->num >= CMD_MAX) {
+            free(cmd_copy);
+            return ERR_TOO_MANY_COMMANDS;
+        }
+
+        // Parse command and arguments
+        cmd_buff_t *curr_cmd = &clist->commands[clist->num];
+        curr_cmd->argc = 0;
+
+        // Split command into arguments
+        char *arg = strtok_r(cmd, " ", &saveptr2);
+        while (arg != NULL) {
+            if (curr_cmd->argc >= CMD_ARGV_MAX) {
+                free(cmd_copy);
+                return ERR_CMD_OR_ARGS_TOO_BIG;
+            }
+            curr_cmd->argv[curr_cmd->argc++] = strdup(arg);
+            arg = strtok_r(NULL, " ", &saveptr2);
+        }
+        curr_cmd->argv[curr_cmd->argc] = NULL;
+
+        clist->num++;
+        cmd = strtok_r(NULL, "|", &saveptr1);
+    }
+
+    free(cmd_copy);
+    return OK;
+}
+
+int exec_local_cmd_loop()
+{
+    char cmd_buff[SH_CMD_MAX];
+    int rc = 0;
+    command_list_t clist;
+    memset(&clist, 0, sizeof(command_list_t));
+
+    while(1) {
+        printf("%s", SH_PROMPT);
+        
+        if (fgets(cmd_buff, SH_CMD_MAX, stdin) == NULL) {
+            printf("\n");
+            break;
+        }
+
+        // Remove trailing newline
+        cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
+
+        // Skip empty commands
+        if (strlen(cmd_buff) == 0) {
+            printf(CMD_WARN_NO_CMD);
+            continue;
+        }
+
+        // Parse commands by pipe
+        rc = build_cmd_list(cmd_buff, &clist);
+        if (rc != OK) {
+            if (rc == ERR_TOO_MANY_COMMANDS) {
+                printf(CMD_ERR_PIPE_LIMIT, CMD_MAX);
+            }
+            continue;
+        }
+
+        // Handle built-in commands
+        if (clist.num == 1) {
+            if (strcmp(clist.commands[0].argv[0], EXIT_CMD) == 0) {
+                break;
+            } else if (strcmp(clist.commands[0].argv[0], "cd") == 0) {
+                if (clist.commands[0].argv[1]) {
+                    if (chdir(clist.commands[0].argv[1]) != 0) {
+                        perror("cd");
+                        rc = ERR_CMD_ARGS_BAD;
+                    }
+                }
+                continue;
+            } else if (strcmp(clist.commands[0].argv[0], "dragon") == 0) {
+                printDragon();
+                continue;
+            } else if (strcmp(clist.commands[0].argv[0], "rc") == 0) {
+                printf("%d\n", rc);
+                continue;
+            }
+        }
+
+        // Handle external commands with pipes
+        pid_t pids[CMD_MAX];
+        int pipes[CMD_MAX - 1][2];
+
+        // Create pipes
+        for (int i = 0; i < clist.num - 1; i++) {
+            if (pipe(pipes[i]) == -1) {
+                perror("pipe");
+                rc = ERR_MEMORY;
+                continue;
+            }
+        }
+
+        // Execute each command
+        for (int i = 0; i < clist.num; i++) {
+            pids[i] = fork();
+            
+            if (pids[i] < 0) {
+                perror("fork");
+                rc = ERR_MEMORY;
+                break;
+            }
+
+            if (pids[i] == 0) {  // Child process
+                // Set up pipe connections
+                if (i > 0) {
+                    // Connect to previous pipe's read end
+                    dup2(pipes[i-1][0], STDIN_FILENO);
+                }
+                
+                if (i < clist.num - 1) {
+                    // Connect to next pipe's write end
+                    dup2(pipes[i][1], STDOUT_FILENO);
+                }
+
+                // Handle redirections by checking arguments
+                char *new_argv[CMD_ARGV_MAX];
+                int new_argc = 0;
+                
+                for (int j = 0; j < clist.commands[i].argc; j++) {
+                    char *arg = clist.commands[i].argv[j];
+                    
+                    if (strcmp(arg, "<") == 0 && j + 1 < clist.commands[i].argc) {
+                        // Input redirection
+                        int fd = open(clist.commands[i].argv[j + 1], O_RDONLY);
+                        if (fd == -1) {
+                            perror("open input file");
+                            exit(1);
+                        }
+                        dup2(fd, STDIN_FILENO);
+                        close(fd);
+                        j++; // Skip the filename
+                        continue;
+                    }
+                    
+                    if (strcmp(arg, ">") == 0 && j + 1 < clist.commands[i].argc) {
+                        // Output redirection (overwrite)
+                        int fd = open(clist.commands[i].argv[j + 1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
+                        if (fd == -1) {
+                            perror("open output file");
+                            exit(1);
+                        }
+                        dup2(fd, STDOUT_FILENO);
+                        close(fd);
+                        j++; // Skip the filename
+                        continue;
+                    }
+                    
+                    if (strcmp(arg, ">>") == 0 && j + 1 < clist.commands[i].argc) {
+                        // Output redirection (append)
+                        int fd = open(clist.commands[i].argv[j + 1], O_WRONLY | O_CREAT | O_APPEND, 0644);
+                        if (fd == -1) {
+                            perror("open output file");
+                            exit(1);
+                        }
+                        dup2(fd, STDOUT_FILENO);
+                        close(fd);
+                        j++; // Skip the filename
+                        continue;
+                    }
+                    
+                    // If not a redirection operator, add to new argv
+                    new_argv[new_argc++] = arg;
+                }
+                new_argv[new_argc] = NULL;
+
+                // Close all pipe ends in child
+                for (int j = 0; j < clist.num - 1; j++) {
+                    close(pipes[j][0]);
+                    close(pipes[j][1]);
+                }
+
+                // Execute the command with cleaned up arguments
+                execvp(new_argv[0], new_argv);
+                perror("execvp");
+                exit(errno);
+            }
+        }
+
+        // Parent process: close all pipe ends
+        for (int i = 0; i < clist.num - 1; i++) {
+            close(pipes[i][0]);
+            close(pipes[i][1]);
+        }
+
+        // Wait for all children to complete and get the last command's status
+        for (int i = 0; i < clist.num; i++) {
+            int status;
+            waitpid(pids[i], &status, 0);
+            if (i == clist.num - 1) {  // Only use the last command's status
+                if (WIFEXITED(status)) {
+                    rc = WEXITSTATUS(status);
+                } else {
+                    rc = ERR_EXEC_CMD;
+                }
+            }
+        }
+
+    }
+
+    return OK;
+}
+
+int free_cmd_list(command_list_t *cmd_lst) {
+    if (cmd_lst == NULL) {
+        return OK;
+    }
+
+    // Free each command's arguments
+    for (int i = 0; i < cmd_lst->num; i++) {
+        cmd_buff_t *curr_cmd = &cmd_lst->commands[i];
+        for (int j = 0; j < curr_cmd->argc; j++) {
+            free(curr_cmd->argv[j]);
+        }
+        curr_cmd->argv[curr_cmd->argc] = NULL;
+        curr_cmd->argc = 0;
+    }
+
+    // Reset the number of commands
+    cmd_lst->num = 0;
+    return OK;
+}
diff --git a/6-RShell/dshlib.h b/6-RShell/dshlib.h
new file mode 100644
index 0000000..b4cc21b
--- /dev/null
+++ b/6-RShell/dshlib.h
@@ -0,0 +1,92 @@
+#ifndef __DSHLIB_H__
+    #define __DSHLIB_H__
+
+
+//Constants for command structure sizes
+#define EXE_MAX 64
+#define ARG_MAX 256
+#define CMD_MAX 8
+#define CMD_ARGV_MAX (CMD_MAX + 1)
+// Longest command that can be read from the shell
+#define SH_CMD_MAX EXE_MAX + ARG_MAX
+
+typedef struct command
+{
+    char exe[EXE_MAX];
+    char args[ARG_MAX];
+} command_t;
+
+#include <stdbool.h>
+
+typedef struct cmd_buff
+{
+    int  argc;
+    char *argv[CMD_ARGV_MAX];
+    char *_cmd_buffer;
+    char *input_file;  // extra credit, stores input redirection file (for `<`)
+    char *output_file; // extra credit, stores output redirection file (for `>`)
+    bool append_mode; // extra credit, sets append mode fomr output_file
+} cmd_buff_t;
+
+typedef struct command_list{
+    int num;
+    cmd_buff_t commands[CMD_MAX];
+}command_list_t;
+
+//Special character #defines
+#define SPACE_CHAR  ' '
+#define PIPE_CHAR   '|'
+#define PIPE_STRING "|"
+
+#define SH_PROMPT       "dsh4> "
+#define EXIT_CMD        "exit"
+#define RC_SC           99
+#define EXIT_SC         100
+
+//Standard Return Codes
+#define OK                       0
+#define WARN_NO_CMDS            -1
+#define ERR_TOO_MANY_COMMANDS   -2
+#define ERR_CMD_OR_ARGS_TOO_BIG -3
+#define ERR_CMD_ARGS_BAD        -4      //for extra credit
+#define ERR_MEMORY              -5
+#define ERR_EXEC_CMD            -6
+#define OK_EXIT                 -7
+
+
+
+//prototypes
+int alloc_cmd_buff(cmd_buff_t *cmd_buff);
+int free_cmd_buff(cmd_buff_t *cmd_buff);
+int clear_cmd_buff(cmd_buff_t *cmd_buff);
+int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff);
+int close_cmd_buff(cmd_buff_t *cmd_buff);
+int build_cmd_list(char *cmd_line, command_list_t *clist);
+int free_cmd_list(command_list_t *cmd_lst);
+
+//built in command stuff
+typedef enum {
+    BI_CMD_EXIT,
+    BI_CMD_DRAGON,
+    BI_CMD_CD,
+    BI_CMD_RC,              //extra credit command
+    BI_CMD_STOP_SVR,        //new command "stop-server"
+    BI_NOT_BI,
+    BI_EXECUTED,
+} Built_In_Cmds;
+Built_In_Cmds match_command(const char *input); 
+Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd);
+
+//main execution context
+int exec_local_cmd_loop();
+int exec_cmd(cmd_buff_t *cmd);
+int execute_pipeline(command_list_t *clist);
+
+
+//output constants
+#define CMD_OK_HEADER       "PARSED COMMAND LINE - TOTAL COMMANDS %d\n"
+#define CMD_WARN_NO_CMD     "warning: no commands provided\n"
+#define CMD_ERR_PIPE_LIMIT  "error: piping limited to %d commands\n"
+#define BI_NOT_IMPLEMENTED "not implemented"
+
+#endif
\ No newline at end of file
diff --git a/6-RShell/makefile b/6-RShell/makefile
new file mode 100644
index 0000000..b14b072
--- /dev/null
+++ b/6-RShell/makefile
@@ -0,0 +1,31 @@
+# Compiler settings
+CC = gcc
+CFLAGS = -Wall -Wextra -g
+
+# Target executable name
+TARGET = dsh
+
+# Find all source and header files
+SRCS = $(wildcard *.c)
+HDRS = $(wildcard *.h)
+
+# Default target
+all: $(TARGET)
+
+# Compile source to executable
+$(TARGET): $(SRCS) $(HDRS)
+	$(CC) $(CFLAGS) -o $(TARGET) $(SRCS)
+
+# Clean up build files
+clean:
+	rm -f $(TARGET)
+
+test:
+	bats $(wildcard ./bats/*.sh)
+
+valgrind:
+	echo "pwd\nexit" | valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./$(TARGET) 
+	echo "pwd\nexit" | valgrind --tool=helgrind --error-exitcode=1 ./$(TARGET) 
+
+# Phony targets
+.PHONY: all clean test
\ No newline at end of file
diff --git a/6-RShell/questions.md b/6-RShell/questions.md
new file mode 100644
index 0000000..43ffc10
--- /dev/null
+++ b/6-RShell/questions.md
@@ -0,0 +1,19 @@
+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_
+
+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_
+
+3. Describe the general differences between stateful and stateless protocols.
+
+_answer here_
+
+4. Our lecture this week stated that UDP is "unreliable". If that is the case, why would we ever use it?
+
+_answer here_
+
+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
diff --git a/6-RShell/rsh_cli.c b/6-RShell/rsh_cli.c
new file mode 100644
index 0000000..35acdcf
--- /dev/null
+++ b/6-RShell/rsh_cli.c
@@ -0,0 +1,258 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <fcntl.h>
+
+#include "dshlib.h"
+#include "rshlib.h"
+
+
+
+
+/*
+ * exec_remote_cmd_loop(server_ip, port)
+ *      server_ip:  a string in ip address format, indicating the servers IP
+ *                  address.  Note 127.0.0.1 is the default meaning the server
+ *                  is running on the same machine as the client
+ *              
+ *      port:   The port the server will use.  Note the constant 
+ *              RDSH_DEF_PORT which is 1234 in rshlib.h.  If you are using
+ *              tux you may need to change this to your own default, or even
+ *              better use the command line override -c implemented in dsh_cli.c
+ *              For example ./dsh -c 10.50.241.18:5678 where 5678 is the new port
+ *              number and the server address is 10.50.241.18    
+ * 
+ *      This function basically implements the network version of 
+ *      exec_local_cmd_loop() from the last assignemnt.  It will:
+ *  
+ *          1. Allocate buffers for sending and receiving data over the 
+ *             network
+ *          2. Create a network connection to the server, getting an active
+ *             socket by calling the start_client(server_ip, port) function.
+ *          2. Go into an infinite while(1) loop prompting the user for
+ *             input commands. 
+ * 
+ *             a. Accept a command from the user via fgets()
+ *             b. Send that command to the server using send() - it should
+ *                be a null terminated string
+ *             c. Go into a loop and receive client requests.  Note each
+ *                receive might not be a C string so you need to print it
+ *                out using:
+ *                     printf("%.*s", (int)bytes_received, rsp_buff);
+ *                this version of printf() uses the "%.*s" flag that indicates
+ *                that the rsp_buff might be a null terminated string, or
+ *                it might not be, if its not, print exactly bytes_received
+ *                bytes. 
+ *             d. In the recv() loop described above. Each time you receive
+ *                data from the server, see if the last byte received is the
+ *                EOF character. This indicates the server is done and you can
+ *                send another command by going to the top of the loop.  The
+ *                best way to do this is as follows assuming you are receiving
+ *                data into a buffer called recv_buff, and you received
+ *                recv_bytes in the call to recv:
+ * 
+ *                  recv_bytes = recv(sock, recv_buff, recv_buff_sz, 0)
+ *                  
+ *                if recv_bytes:
+ *                  <negative_number>: communication error
+ *                    0:    Didn't receive anything, likely server down
+ *                  > 0:    Got some data. Check if the last byte is EOF
+ *                          is_eof = (recv_buff[recv_bytes-1] == RDSH_EOF_CHAR) ? 1 : 0;
+ *                    if is_eof is true, this is the last part of the transmission
+ *                    from the server and you can break out of the recv() loop. 
+ * 
+ *   returns:
+ *          OK:      The client executed all of its commands and is exiting
+ *                   either by the `exit` command that terminates the client
+ *                   or the `stop-server` command that terminates both the
+ *                   client and the server. 
+ *          ERR_MEMORY:             If this function cannot allocate memory via
+ *                                  malloc for the send and receive buffers
+ *          ERR_RDSH_CLIENT:        If the client cannot connect to the server. 
+ *                                  AKA the call to start_client() fails.
+ *          ERR_RDSH_COMMUNICATION: If there is a communication error, AKA
+ *                                  any failures from send() or recv().
+ * 
+ *   NOTE:  Since there are several exit points and each exit point must
+ *          call free() on the buffers allocated, close the socket, and
+ *          return an appropriate error code.  Its suggested you use the
+ *          helper function client_cleanup() for these purposes.  For example:
+ * 
+ *   return client_cleanup(cli_socket, request_buff, resp_buff, ERR_RDSH_COMMUNICATION);
+ *   return client_cleanup(cli_socket, request_buff, resp_buff, OK);
+ *
+ *   The above will return ERR_RDSH_COMMUNICATION and OK respectively to the main()
+ *   function after cleaning things up.  See the documentation for client_cleanup()
+ *      
+ */
+int exec_remote_cmd_loop(char *address, int port)
+{
+    char *cmd_buff;
+    char *rsp_buff;
+    int cli_socket;
+    ssize_t io_size;
+    int is_eof;
+    int rc = OK;
+
+    // Allocate buffers
+    cmd_buff = malloc(RDSH_COMM_BUFF_SZ);
+    rsp_buff = malloc(RDSH_COMM_BUFF_SZ);
+    if (cmd_buff == NULL || rsp_buff == NULL) {
+        return client_cleanup(-1, cmd_buff, rsp_buff, ERR_MEMORY);
+    }
+
+    // Connect to server
+    cli_socket = start_client(address, port);
+    if (cli_socket < 0){
+        perror("start client");
+        return client_cleanup(cli_socket, cmd_buff, rsp_buff, ERR_RDSH_CLIENT);
+    }
+
+    while (1) 
+    {
+        printf(SH_PROMPT);
+
+        // get command input
+        if (fgets(cmd_buff, RDSH_COMM_BUFF_SZ, stdin) == NULL) {
+            break;
+        }
+
+        // remove trailing newline
+        cmd_buff[strcspn(cmd_buff, "\n")] = 0;
+
+        // send command to server (including null terminator)
+        if (send(cli_socket, cmd_buff, strlen(cmd_buff) + 1, 0) < 0) {
+            perror("send");
+            return client_cleanup(cli_socket, cmd_buff, rsp_buff, ERR_RDSH_COMMUNICATION);
+        }
+
+        // receive response from server
+        while ((io_size = recv(cli_socket, rsp_buff, RDSH_COMM_BUFF_SZ, 0)) > 0) {
+            // check if this is the last chunk
+            is_eof = (rsp_buff[io_size-1] == RDSH_EOF_CHAR) ? 1 : 0;
+            
+            // print the received data
+            if (is_eof) {
+                printf("%.*s", (int)(io_size-1), rsp_buff);
+            } else {
+                printf("%.*s", (int)io_size, rsp_buff);
+            }
+
+            // if EOF, receiving done
+            if (is_eof) {
+                break;
+            }
+        }
+
+        if (io_size < 0) {
+            perror("recv");
+            return client_cleanup(cli_socket, cmd_buff, rsp_buff, ERR_RDSH_COMMUNICATION);
+        }
+
+        if (io_size == 0) {
+            // server closed connection
+            return client_cleanup(cli_socket, cmd_buff, rsp_buff, ERR_RDSH_COMMUNICATION);
+        }
+
+        // exit command
+        if (strcmp(cmd_buff, EXIT_CMD) == 0) {
+            break;
+        }
+    }
+
+    return client_cleanup(cli_socket, cmd_buff, rsp_buff, OK);
+}
+
+/*
+ * start_client(server_ip, port)
+ *      server_ip:  a string in ip address format, indicating the servers IP
+ *                  address.  Note 127.0.0.1 is the default meaning the server
+ *                  is running on the same machine as the client
+ *              
+ *      port:   The port the server will use.  Note the constant 
+ *              RDSH_DEF_PORT which is 1234 in rshlib.h.  If you are using
+ *              tux you may need to change this to your own default, or even
+ *              better use the command line override -c implemented in dsh_cli.c
+ *              For example ./dsh -c 10.50.241.18:5678 where 5678 is the new port
+ *              number and the server address is 10.50.241.18    
+ * 
+ *      This function basically runs the client by: 
+ *          1. Creating the client socket via socket()
+ *          2. Calling connect()
+ *          3. Returning the client socket after connecting to the server
+ * 
+ *   returns:
+ *          client_socket:      The file descriptor fd of the client socket
+ *          ERR_RDSH_CLIENT:    If socket() or connect() fail
+ * 
+ */
+int start_client(char *server_ip, int port){
+    struct sockaddr_in addr;
+    int cli_socket;
+    int ret;
+
+    // Create socket
+    cli_socket = socket(AF_INET, SOCK_STREAM, 0);
+    if (cli_socket == -1) {
+        perror("socket");
+        return ERR_RDSH_CLIENT;
+    }
+
+    // Set up address structure
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = inet_addr(server_ip);
+    addr.sin_port = htons(port);
+
+    // Connect to server
+    ret = connect(cli_socket, (struct sockaddr *)&addr, sizeof(addr));
+    if (ret == -1) {
+        perror("connect");
+        close(cli_socket);
+        return ERR_RDSH_CLIENT;
+    }
+
+    return cli_socket;
+}
+
+/*
+ * client_cleanup(int cli_socket, char *cmd_buff, char *rsp_buff, int rc)
+ *      cli_socket:   The client socket
+ *      cmd_buff:     The buffer that will hold commands to send to server
+ *      rsp_buff:     The buffer that will hld server responses
+ * 
+ *   This function does the following: 
+ *      1. If cli_socket > 0 it calls close(cli_socket) to close the socket
+ *      2. It calls free() on cmd_buff and rsp_buff
+ *      3. It returns the value passed as rc
+ *  
+ *   Note this function is intended to be helper to manage exit conditions
+ *   from the exec_remote_cmd_loop() function given there are several
+ *   cleanup steps.  We provide it to you fully implemented as a helper.
+ *   You do not have to use it if you want to develop an alternative
+ *   strategy for cleaning things up in your exec_remote_cmd_loop()
+ *   implementation. 
+ * 
+ *   returns:
+ *          rc:   This function just returns the value passed as the 
+ *                rc parameter back to the caller.  This way the caller
+ *                can just write return client_cleanup(...)
+ *      
+ */
+int client_cleanup(int cli_socket, char *cmd_buff, char *rsp_buff, int rc){
+    //If a valid socket number close it.
+    if(cli_socket > 0){
+        close(cli_socket);
+    }
+
+    //Free up the buffers 
+    free(cmd_buff);
+    free(rsp_buff);
+
+    //Echo the return value that was passed as a parameter
+    return rc;
+}
\ No newline at end of file
diff --git a/6-RShell/rsh_server.c b/6-RShell/rsh_server.c
new file mode 100644
index 0000000..b0eb66c
--- /dev/null
+++ b/6-RShell/rsh_server.c
@@ -0,0 +1,745 @@
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <limits.h> 
+#include <errno.h>   // For errno
+
+//INCLUDES for extra credit
+//#include <signal.h>
+//#include <pthread.h>
+//-------------------------
+
+#include "dshlib.h"
+#include "rshlib.h"
+
+
+/*
+ * start_server(ifaces, port, is_threaded)
+ *      ifaces:  a string in ip address format, indicating the interface
+ *              where the server will bind.  In almost all cases it will
+ *              be the default "0.0.0.0" which binds to all interfaces.
+ *              note the constant RDSH_DEF_SVR_INTFACE in rshlib.h
+ * 
+ *      port:   The port the server will use.  Note the constant 
+ *              RDSH_DEF_PORT which is 1234 in rshlib.h.  If you are using
+ *              tux you may need to change this to your own default, or even
+ *              better use the command line override -s implemented in dsh_cli.c
+ *              For example ./dsh -s 0.0.0.0:5678 where 5678 is the new port  
+ * 
+ *      is_threded:  Used for extra credit to indicate the server should implement
+ *                   per thread connections for clients  
+ * 
+ *      This function basically runs the server by: 
+ *          1. Booting up the server
+ *          2. Processing client requests until the client requests the
+ *             server to stop by running the `stop-server` command
+ *          3. Stopping the server. 
+ * 
+ *      This function is fully implemented for you and should not require
+ *      any changes for basic functionality.  
+ * 
+ *      IF YOU IMPLEMENT THE MULTI-THREADED SERVER FOR EXTRA CREDIT YOU NEED
+ *      TO DO SOMETHING WITH THE is_threaded ARGUMENT HOWEVER.  
+ */
+int start_server(char *ifaces, int port, int is_threaded){
+    int svr_socket;
+    int rc;
+
+    //
+    //TODO:  If you are implementing the extra credit, please add logic
+    //       to keep track of is_threaded to handle this feature
+    //
+
+    svr_socket = boot_server(ifaces, port);
+    if (svr_socket < 0){
+        int err_code = svr_socket;  //server socket will carry error code
+        return err_code;
+    }
+
+    rc = process_cli_requests(svr_socket);
+
+    stop_server(svr_socket);
+
+
+    return rc;
+}
+
+/*
+ * stop_server(svr_socket)
+ *      svr_socket: The socket that was created in the boot_server()
+ *                  function. 
+ * 
+ *      This function simply returns the value of close() when closing
+ *      the socket.  
+ */
+int stop_server(int svr_socket){
+    return close(svr_socket);
+}
+
+/*
+ * boot_server(ifaces, port)
+ *      ifaces & port:  see start_server for description.  They are passed
+ *                      as is to this function.   
+ * 
+ *      This function "boots" the rsh server.  It is responsible for all
+ *      socket operations prior to accepting client connections.  Specifically: 
+ * 
+ *      1. Create the server socket using the socket() function. 
+ *      2. Calling bind to "bind" the server to the interface and port
+ *      3. Calling listen to get the server ready to listen for connections.
+ * 
+ *      after creating the socket and prior to calling bind you might want to 
+ *      include the following code:
+ * 
+ *      int enable=1;
+ *      setsockopt(svr_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
+ * 
+ *      when doing development you often run into issues where you hold onto
+ *      the port and then need to wait for linux to detect this issue and free
+ *      the port up.  The code above tells linux to force allowing this process
+ *      to use the specified port making your life a lot easier.
+ * 
+ *  Returns:
+ * 
+ *      server_socket:  Sockets are just file descriptors, if this function is
+ *                      successful, it returns the server socket descriptor, 
+ *                      which is just an integer.
+ * 
+ *      ERR_RDSH_COMMUNICATION:  This error code is returned if the socket(),
+ *                               bind(), or listen() call fails. 
+ * 
+ */
+int boot_server(char *ifaces, int port){
+    int svr_socket;
+    int ret;
+    
+    struct sockaddr_in addr;
+
+    // Create socket
+    svr_socket = socket(AF_INET, SOCK_STREAM, 0);
+    if (svr_socket == -1) {
+        perror("socket");
+        return ERR_RDSH_COMMUNICATION;
+    }
+
+    // Enable address reuse
+    int enable = 1;
+    if (setsockopt(svr_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
+        perror("setsockopt");
+        close(svr_socket);
+        return ERR_RDSH_COMMUNICATION;
+    }
+
+    // Set up address structure
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = inet_addr(ifaces);
+    addr.sin_port = htons(port);
+
+    // Bind socket
+    if (bind(svr_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        perror("bind");
+        close(svr_socket);
+        return ERR_RDSH_COMMUNICATION;
+    }
+
+    /*
+     * Prepare for accepting connections. The backlog size is set
+     * to 20. So while one request is being processed other requests
+     * can be waiting.
+     */
+    ret = listen(svr_socket, 20);
+    if (ret == -1) {
+        perror("listen");
+        close(svr_socket);
+        return ERR_RDSH_COMMUNICATION;
+    }
+
+    return svr_socket;
+}
+
+/*
+ * process_cli_requests(svr_socket)
+ *      svr_socket:  The server socket that was obtained from boot_server()
+ *   
+ *  This function handles managing client connections.  It does this using
+ *  the following logic
+ * 
+ *      1.  Starts a while(1) loop:
+ *  
+ *          a. Calls accept() to wait for a client connection. Recall that 
+ *             the accept() function returns another socket specifically
+ *             bound to a client connection. 
+ *          b. Calls exec_client_requests() to handle executing commands
+ *             sent by the client. It will use the socket returned from
+ *             accept().
+ *          c. Loops back to the top (step 2) to accept connecting another
+ *             client.  
+ * 
+ *          note that the exec_client_requests() return code should be
+ *          negative if the client requested the server to stop by sending
+ *          the `stop-server` command.  If this is the case step 2b breaks
+ *          out of the while(1) loop. 
+ * 
+ *      2.  After we exit the loop, we need to cleanup.  Dont forget to 
+ *          free the buffer you allocated in step #1.  Then call stop_server()
+ *          to close the server socket. 
+ * 
+ *  Returns:
+ * 
+ *      OK_EXIT:  When the client sends the `stop-server` command this function
+ *                should return OK_EXIT. 
+ * 
+ *      ERR_RDSH_COMMUNICATION:  This error code terminates the loop and is
+ *                returned from this function in the case of the accept() 
+ *                function failing. 
+ * 
+ *      OTHERS:   See exec_client_requests() for return codes.  Note that positive
+ *                values will keep the loop running to accept additional client
+ *                connections, and negative values terminate the server. 
+ * 
+ */
+int process_cli_requests(int svr_socket){
+    int     cli_socket;
+    int     rc = OK;    
+
+    while(1){
+        // Accept client connection
+        cli_socket = accept(svr_socket, NULL, NULL);
+        if (cli_socket == -1) {
+            perror("accept");
+            return ERR_RDSH_COMMUNICATION;
+        }
+
+        // Handle client requests
+        rc = exec_client_requests(cli_socket);
+        close(cli_socket);
+
+        // If client requested server stop, break the loop
+        if (rc == OK_EXIT) {
+            break;
+        }
+    }
+
+    return rc;
+}
+
+/*
+ * exec_client_requests(cli_socket)
+ *      cli_socket:  The server-side socket that is connected to the client
+ *   
+ *  This function handles accepting remote client commands. The function will
+ *  loop and continue to accept and execute client commands.  There are 2 ways
+ *  that this ongoing loop accepting client commands ends:
+ * 
+ *      1.  When the client executes the `exit` command, this function returns
+ *          to process_cli_requests() so that we can accept another client
+ *          connection. 
+ *      2.  When the client executes the `stop-server` command this function
+ *          returns to process_cli_requests() with a return code of OK_EXIT
+ *          indicating that the server should stop. 
+ * 
+ *  Note that this function largely follows the implementation of the
+ *  exec_local_cmd_loop() function that you implemented in the last 
+ *  shell program deliverable. The main difference is that the command will
+ *  arrive over the recv() socket call rather than reading a string from the
+ *  keyboard. 
+ * 
+ *  This function also must send the EOF character after a command is
+ *  successfully executed to let the client know that the output from the
+ *  command it sent is finished.  Use the send_message_eof() to accomplish 
+ *  this. 
+ * 
+ *  Of final note, this function must allocate a buffer for storage to 
+ *  store the data received by the client. For example:
+ *     io_buff = malloc(RDSH_COMM_BUFF_SZ);
+ *  And since it is allocating storage, it must also properly clean it up
+ *  prior to exiting.
+ * 
+ *  Returns:
+ * 
+ *      OK:       The client sent the `exit` command.  Get ready to connect
+ *                another client. 
+ *      OK_EXIT:  The client sent `stop-server` command to terminate the server
+ * 
+ *      ERR_RDSH_COMMUNICATION:  A catch all for any socket() related send
+ *                or receive errors. 
+ */
+int exec_client_requests(int cli_socket) {
+    int io_size;
+    char *io_buff;
+    int rc = OK;
+    command_list_t cmd_list;
+    Built_In_Cmds cmd_type;
+    char response[256];
+
+    io_buff = malloc(RDSH_COMM_BUFF_SZ);
+    if (io_buff == NULL){
+        return ERR_RDSH_SERVER;
+    }
+
+    while(1) {
+        // Receive message from client
+        io_size = recv(cli_socket, io_buff, RDSH_COMM_BUFF_SZ, 0);
+        if (io_size <= 0) {
+            if (io_size == 0) {
+                // Client closed connection
+                break;
+            }
+            perror("recv");
+            free(io_buff);
+            return ERR_RDSH_COMMUNICATION;
+        }
+
+        // Parse the command
+        if (build_cmd_list(io_buff, &cmd_list) != OK) {
+            // Send error message to client
+            send_message_string(cli_socket, CMD_WARN_NO_CMD);
+            send_message_eof(cli_socket);
+            continue;
+        }
+
+        // Check if it's a built-in command
+        cmd_type = rsh_match_command(cmd_list.commands[0].argv[0]);
+        
+        switch (cmd_type) {
+            case BI_CMD_EXIT:
+                // Send goodbye message and close client connection
+                send_message_string(cli_socket, RCMD_MSG_CLIENT_EXITED);
+                send_message_eof(cli_socket);
+                free_cmd_list(&cmd_list);
+                free(io_buff);
+                close(cli_socket);  // Close client connection
+                return OK;  // Return OK to allow server to accept new connections
+
+            case BI_CMD_STOP_SVR:
+                // Send goodbye message
+                send_message_string(cli_socket, RCMD_MSG_SVR_STOP_REQ);
+                send_message_eof(cli_socket);
+                free_cmd_list(&cmd_list);
+                free(io_buff);
+                return OK_EXIT;
+
+            case BI_CMD_CD:
+                if (cmd_list.commands[0].argc < 2) {
+                    // No directory specified, just print current directory
+                    char cwd[4096];
+                    if (getcwd(cwd, sizeof(cwd)) != NULL) {
+                        send_message_string(cli_socket, cwd);
+                    } else {
+                        send_message_string(cli_socket, "Error getting current directory");
+                    }
+                } else {
+                    // Change to specified directory
+                    if (chdir(cmd_list.commands[0].argv[1]) != 0) {
+                        snprintf(response, sizeof(response), "cd: %s: %s\n", 
+                                cmd_list.commands[0].argv[1], strerror(errno));
+                        send_message_string(cli_socket, response);
+                    } else {
+                        char cwd[4096];
+                        if (getcwd(cwd, sizeof(cwd)) != NULL) {
+                            send_message_string(cli_socket, cwd);
+                        }
+                    }
+                }
+                send_message_eof(cli_socket);
+                break;
+
+            case BI_CMD_DRAGON:
+                // Create a temporary file to store dragon output
+                FILE *temp = tmpfile();
+                if (temp != NULL) {
+                    // Save stdout
+                    int saved_stdout = dup(STDOUT_FILENO);
+                    // Redirect stdout to temp file
+                    dup2(fileno(temp), STDOUT_FILENO);
+                    // Print dragon
+                    printDragon();
+                    // Restore stdout
+                    dup2(saved_stdout, STDOUT_FILENO);
+                    close(saved_stdout);
+                    // Reset file pointer
+                    rewind(temp);
+                    // Read and send dragon output
+                    char dragon_buff[1024];
+                    size_t bytes_read;
+                    while ((bytes_read = fread(dragon_buff, 1, sizeof(dragon_buff), temp)) > 0) {
+                        if (send(cli_socket, dragon_buff, bytes_read, 0) != bytes_read) {
+                            perror("send");
+                            free_cmd_list(&cmd_list);
+                            free(io_buff);
+                            return ERR_RDSH_COMMUNICATION;
+                        }
+                    }
+                }
+                send_message_eof(cli_socket);
+                break;
+
+            case BI_CMD_RC:
+                snprintf(response, sizeof(response), RCMD_MSG_SVR_RC_CMD, rc);
+                send_message_string(cli_socket, response);
+                send_message_eof(cli_socket);
+                break;
+
+            default:
+                // Execute non-built-in commands using pipeline
+                rc = rsh_execute_pipeline(cli_socket, &cmd_list);
+                if (rc < 0) {
+                    free_cmd_list(&cmd_list);
+                    free(io_buff);
+                    return rc;
+                }
+                send_message_eof(cli_socket);
+                break;
+        }
+
+        free_cmd_list(&cmd_list);
+    }
+
+    free(io_buff);
+    return rc;
+}
+
+/*
+ * send_message_eof(cli_socket)
+ *      cli_socket:  The server-side socket that is connected to the client
+
+ *  Sends the EOF character to the client to indicate that the server is
+ *  finished executing the command that it sent. 
+ * 
+ *  Returns:
+ * 
+ *      OK:  The EOF character was sent successfully. 
+ * 
+ *      ERR_RDSH_COMMUNICATION:  The send() socket call returned an error or if
+ *           we were unable to send the EOF character. 
+ */
+int send_message_eof(int cli_socket){
+    int send_len = (int)sizeof(RDSH_EOF_CHAR);
+    int sent_len;
+    sent_len = send(cli_socket, &RDSH_EOF_CHAR, send_len, 0);
+
+    if (sent_len != send_len){
+        return ERR_RDSH_COMMUNICATION;
+    }
+    return OK;
+}
+
+
+/*
+ * send_message_string(cli_socket, char *buff)
+ *      cli_socket:  The server-side socket that is connected to the client
+ *      buff:        A C string (aka null terminated) of a message we want
+ *                   to send to the client. 
+ *   
+ *  Sends a message to the client.  Note this command executes both a send()
+ *  to send the message and a send_message_eof() to send the EOF character to
+ *  the client to indicate command execution terminated. 
+ * 
+ *  Returns:
+ * 
+ *      OK:  The message in buff followed by the EOF character was 
+ *           sent successfully. 
+ * 
+ *      ERR_RDSH_COMMUNICATION:  The send() socket call returned an error or if
+ *           we were unable to send the message followed by the EOF character. 
+ */
+int send_message_string(int cli_socket, char *buff){
+    int send_len = strlen(buff);
+    int sent_len;
+
+    // Send the message
+    sent_len = send(cli_socket, buff, send_len, 0);
+    if (sent_len != send_len) {
+        return ERR_RDSH_COMMUNICATION;
+    }
+
+    // Send EOF character
+    return send_message_eof(cli_socket);
+}
+
+
+/*
+ * rsh_execute_pipeline(int cli_sock, command_list_t *clist)
+ *      cli_sock:    The server-side socket that is connected to the client
+ *      clist:       The command_list_t structure that we implemented in
+ *                   the last shell. 
+ *   
+ *  This function executes the command pipeline.  It should basically be a
+ *  replica of the execute_pipeline() function from the last deliverable. 
+ *  The only thing different is that you will be using the cli_sock as the
+ *  main file descriptor on the first executable in the pipeline for STDIN,
+ *  and the cli_sock for the file descriptor for STDOUT, and STDERR for the
+ *  last executable in the pipeline.  See picture below:  
+ * 
+ *      
+ *┌───────────┐                                                    ┌───────────┐
+ *│ cli_sock  │                                                    │ cli_sock  │
+ *└─────┬─────┘                                                    └────▲──▲───┘
+ *      │   ┌──────────────┐     ┌──────────────┐     ┌──────────────┐  │  │    
+ *      │   │   Process 1  │     │   Process 2  │     │   Process N  │  │  │    
+ *      │   │              │     │              │     │              │  │  │    
+ *      └───▶stdin   stdout├─┬──▶│stdin   stdout├─┬──▶│stdin   stdout├──┘  │    
+ *          │              │ │   │              │ │   │              │     │    
+ *          │        stderr├─┘   │        stderr├─┘   │        stderr├─────┘    
+ *          └──────────────┘     └──────────────┘     └──────────────┘   
+ *                                                      WEXITSTATUS()
+ *                                                      of this last
+ *                                                      process to get
+ *                                                      the return code
+ *                                                      for this function       
+ * 
+ *  Returns:
+ * 
+ *      EXIT_CODE:  This function returns the exit code of the last command
+ *                  executed in the pipeline.  If only one command is executed
+ *                  that value is returned.  Remember, use the WEXITSTATUS()
+ *                  macro that we discussed during our fork/exec lecture to
+ *                  get this value. 
+ */
+int rsh_execute_pipeline(int cli_sock, command_list_t *clist) {
+    int pipes[clist->num - 1][2];  // Array of pipes
+    pid_t pids[clist->num];
+    int pids_st[clist->num];      // Array to store process IDs
+    int exit_code;
+
+    // Create all necessary pipes
+    for (int i = 0; i < clist->num - 1; i++) {
+        if (pipe(pipes[i]) == -1) {
+            perror("pipe");
+            return ERR_RDSH_COMMUNICATION;
+        }
+    }
+
+    for (int i = 0; i < clist->num; i++) {
+        pids[i] = fork();
+        
+        if (pids[i] < 0) {
+            perror("fork");
+            return ERR_RDSH_COMMUNICATION;
+        }
+
+        if (pids[i] == 0) {  // Child process
+            // First process: redirect stdin from client socket
+            if (i == 0) {
+                dup2(cli_sock, STDIN_FILENO);
+                close(cli_sock);
+            }
+
+            // Last process: redirect stdout and stderr to client socket
+            if (i == clist->num - 1) {
+                dup2(cli_sock, STDOUT_FILENO);
+                dup2(cli_sock, STDERR_FILENO);
+                close(cli_sock);
+            }
+
+            // Set up pipes between processes
+            if (i > 0) {
+                dup2(pipes[i-1][0], STDIN_FILENO);
+                close(pipes[i-1][0]);
+                close(pipes[i-1][1]);
+            }
+            if (i < clist->num - 1) {
+                dup2(pipes[i][1], STDOUT_FILENO);
+                close(pipes[i][0]);
+                close(pipes[i][1]);
+            }
+
+            // Close all other pipe ends
+            for (int j = 0; j < clist->num - 1; j++) {
+                close(pipes[j][0]);
+                close(pipes[j][1]);
+            }
+
+            // Handle redirections by checking arguments
+            char *new_argv[CMD_ARGV_MAX];
+            int new_argc = 0;
+            
+            for (int j = 0; j < clist->commands[i].argc; j++) {
+                char *arg = clist->commands[i].argv[j];
+                
+                if (strcmp(arg, "<") == 0 && j + 1 < clist->commands[i].argc) {
+                    // Input redirection
+                    int fd = open(clist->commands[i].argv[j + 1], O_RDONLY);
+                    if (fd == -1) {
+                        perror("open input file");
+                        exit(1);
+                    }
+                    dup2(fd, STDIN_FILENO);
+                    close(fd);
+                    j++; // Skip the filename
+                    continue;
+                }
+                
+                if (strcmp(arg, ">") == 0 && j + 1 < clist->commands[i].argc) {
+                    // Output redirection (overwrite)
+                    int fd = open(clist->commands[i].argv[j + 1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
+                    if (fd == -1) {
+                        perror("open output file");
+                        exit(1);
+                    }
+                    dup2(fd, STDOUT_FILENO);
+                    close(fd);
+                    j++; // Skip the filename
+                    continue;
+                }
+                
+                if (strcmp(arg, ">>") == 0 && j + 1 < clist->commands[i].argc) {
+                    // Output redirection (append)
+                    int fd = open(clist->commands[i].argv[j + 1], O_WRONLY | O_CREAT | O_APPEND, 0644);
+                    if (fd == -1) {
+                        perror("open output file");
+                        exit(1);
+                    }
+                    dup2(fd, STDOUT_FILENO);
+                    close(fd);
+                    j++; // Skip the filename
+                    continue;
+                }
+                
+                // If not a redirection operator, add to new argv
+                new_argv[new_argc++] = arg;
+            }
+            new_argv[new_argc] = NULL;
+
+            // Execute the command with cleaned up arguments
+            execvp(new_argv[0], new_argv);
+            perror("execvp");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // Parent process: close all pipe ends
+    for (int i = 0; i < clist->num - 1; i++) {
+        close(pipes[i][0]);
+        close(pipes[i][1]);
+    }
+
+    // Wait for all children
+    for (int i = 0; i < clist->num; i++) {
+        waitpid(pids[i], &pids_st[i], 0);
+    }
+
+    // Get exit code of last process
+    exit_code = WEXITSTATUS(pids_st[clist->num - 1]);
+    
+    // Check for EXIT_SC in any process
+    for (int i = 0; i < clist->num; i++) {
+        if (WEXITSTATUS(pids_st[i]) == EXIT_SC) {
+            exit_code = EXIT_SC;
+            break;
+        }
+    }
+    
+    return exit_code;
+}
+
+/**************   OPTIONAL STUFF  ***************/
+/****
+ **** NOTE THAT THE FUNCTIONS BELOW ALIGN TO HOW WE CRAFTED THE SOLUTION
+ **** TO SEE IF A COMMAND WAS BUILT IN OR NOT.  YOU CAN USE A DIFFERENT
+ **** STRATEGY IF YOU WANT.  IF YOU CHOOSE TO DO SO PLEASE REMOVE THESE
+ **** FUNCTIONS AND THE PROTOTYPES FROM rshlib.h
+ **** 
+ */
+
+/*
+ * rsh_match_command(const char *input)
+ *      cli_socket:  The string command for a built-in command, e.g., dragon,
+ *                   cd, exit-server
+ *   
+ *  This optional function accepts a command string as input and returns
+ *  one of the enumerated values from the BuiltInCmds enum as output. For
+ *  example:
+ * 
+ *      Input             Output
+ *      exit              BI_CMD_EXIT
+ *      dragon            BI_CMD_DRAGON
+ * 
+ *  This function is entirely optional to implement if you want to handle
+ *  processing built-in commands differently in your implementation. 
+ * 
+ *  Returns:
+ * 
+ *      BI_CMD_*:   If the command is built-in returns one of the enumeration
+ *                  options, for example "cd" returns BI_CMD_CD
+ * 
+ *      BI_NOT_BI:  If the command is not "built-in" the BI_NOT_BI value is
+ *                  returned. 
+ */
+Built_In_Cmds rsh_match_command(const char *input)
+{
+    if (strcmp(input, "exit") == 0)
+        return BI_CMD_EXIT;
+    if (strcmp(input, "dragon") == 0)
+        return BI_CMD_DRAGON;
+    if (strcmp(input, "cd") == 0)
+        return BI_CMD_CD;
+    if (strcmp(input, "stop-server") == 0)
+        return BI_CMD_STOP_SVR;
+    if (strcmp(input, "rc") == 0)
+        return BI_CMD_RC;
+    return BI_NOT_BI;
+}
+
+/*
+ * rsh_built_in_cmd(cmd_buff_t *cmd)
+ *      cmd:  The cmd_buff_t of the command, remember, this is the 
+ *            parsed version fo the command
+ *   
+ *  This optional function accepts a parsed cmd and then checks to see if
+ *  the cmd is built in or not.  It calls rsh_match_command to see if the 
+ *  cmd is built in or not.  Note that rsh_match_command returns BI_NOT_BI
+ *  if the command is not built in. If the command is built in this function
+ *  uses a switch statement to handle execution if appropriate.   
+ * 
+ *  Again, using this function is entirely optional if you are using a different
+ *  strategy to handle built-in commands.  
+ * 
+ *  Returns:
+ * 
+ *      BI_NOT_BI:   Indicates that the cmd provided as input is not built
+ *                   in so it should be sent to your fork/exec logic
+ *      BI_EXECUTED: Indicates that this function handled the direct execution
+ *                   of the command and there is nothing else to do, consider
+ *                   it executed.  For example the cmd of "cd" gets the value of
+ *                   BI_CMD_CD from rsh_match_command().  It then makes the libc
+ *                   call to chdir(cmd->argv[1]); and finally returns BI_EXECUTED
+ *      BI_CMD_*     Indicates that a built-in command was matched and the caller
+ *                   is responsible for executing it.  For example if this function
+ *                   returns BI_CMD_STOP_SVR the caller of this function is
+ *                   responsible for stopping the server.  If BI_CMD_EXIT is returned
+ *                   the caller is responsible for closing the client connection.
+ * 
+ *   AGAIN - THIS IS TOTALLY OPTIONAL IF YOU HAVE OR WANT TO HANDLE BUILT-IN
+ *   COMMANDS DIFFERENTLY. 
+ */
+Built_In_Cmds rsh_built_in_cmd(cmd_buff_t *cmd)
+{
+    Built_In_Cmds ctype = BI_NOT_BI;
+    ctype = rsh_match_command(cmd->argv[0]);
+
+    switch (ctype)
+    {
+    // case BI_CMD_DRAGON:
+    //     print_dragon();
+    //     return BI_EXECUTED;
+    case BI_CMD_EXIT:
+        return BI_CMD_EXIT;
+    case BI_CMD_STOP_SVR:
+        return BI_CMD_STOP_SVR;
+    case BI_CMD_RC:
+        return BI_CMD_RC;
+    case BI_CMD_CD:
+        chdir(cmd->argv[1]);
+        return BI_EXECUTED;
+    default:
+        return BI_NOT_BI;
+    }
+}
diff --git a/6-RShell/rshlib.h b/6-RShell/rshlib.h
new file mode 100644
index 0000000..6ae2ca9
--- /dev/null
+++ b/6-RShell/rshlib.h
@@ -0,0 +1,78 @@
+#ifndef __RSH_LIB_H__
+    #define __RSH_LIB_H__
+
+#include "dshlib.h"
+
+//common remote shell client and server constants and definitions
+
+
+//Constants for communication
+//Note that these should work fine in a local VM but you will likely have
+//to change the port number if you are working on tux.
+#define RDSH_DEF_PORT           1234        //Default port #
+#define RDSH_DEF_SVR_INTFACE    "0.0.0.0"   //Default start all interfaces
+#define RDSH_DEF_CLI_CONNECT    "127.0.0.1" //Default server is running on
+                                            //localhost 127.0.0.1
+
+//constants for buffer sizes
+#define RDSH_COMM_BUFF_SZ       (1024*64)   //64K
+#define STOP_SERVER_SC          200         //returned from pipeline excution
+                                            //if the command is to stop the
+                                            //server.  See documentation for 
+                                            //exec_client_requests() for more info
+
+//end of message delimiter.  This is super important.  TCP is a stream, therefore
+//the protocol designer is responsible for managing where messages begin and end
+//there are many common techniques for this, but one of the simplest ways is to
+//use an end of stream marker.  Since rsh is a "shell" program we will be using
+//ascii code 0x04, which is commonly used as the end-of-file (EOF) character in
+//linux based systems. 
+static const char RDSH_EOF_CHAR = 0x04;    
+
+//rdsh specific error codes for functions
+#define ERR_RDSH_COMMUNICATION  -50     //Used for communication errors
+#define ERR_RDSH_SERVER         -51     //General server errors
+#define ERR_RDSH_CLIENT         -52     //General client errors
+#define ERR_RDSH_CMD_EXEC       -53     //RSH command execution errors
+#define WARN_RDSH_NOT_IMPL      -99     //Not Implemented yet warning
+
+//Output message constants for server
+#define CMD_ERR_RDSH_COMM   "rdsh-error: communications error\n"
+#define CMD_ERR_RDSH_EXEC   "rdsh-error: command execution error\n"
+#define CMD_ERR_RDSH_ITRNL  "rdsh-error: internal server error - %d\n"
+#define CMD_ERR_RDSH_SEND   "rdsh-error: partial send.  Sent %d, expected to send %d\n"
+#define RCMD_SERVER_EXITED  "server appeared to terminate - exiting\n"
+
+//Output message constants for client
+#define RCMD_MSG_CLIENT_EXITED  "client exited: getting next connection...\n"
+#define RCMD_MSG_SVR_STOP_REQ   "client requested server to stop, stopping...\n"
+#define RCMD_MSG_SVR_EXEC_REQ   "rdsh-exec:  %s\n"
+#define RCMD_MSG_SVR_RC_CMD     "rdsh-exec:  rc = %d\n"
+
+//client prototypes for rsh_cli.c - - see documentation for each function to
+//see what they do
+int start_client(char *address, int port);
+int client_cleanup(int cli_socket, char *cmd_buff, char *rsp_buff, int rc);
+int exec_remote_cmd_loop(char *address, int port);
+    
+
+//server prototypes for rsh_server.c - see documentation for each function to
+//see what they do
+int start_server(char *ifaces, int port, int is_threaded);
+int boot_server(char *ifaces, int port);
+int stop_server(int svr_socket);
+int send_message_eof(int cli_socket);
+int send_message_string(int cli_socket, char *buff);
+int process_cli_requests(int svr_socket);
+int exec_client_requests(int cli_socket);
+int rsh_execute_pipeline(int socket_fd, command_list_t *clist);
+
+Built_In_Cmds rsh_match_command(const char *input);
+Built_In_Cmds rsh_built_in_cmd(cmd_buff_t *cmd);
+
+//eliminate from template, for extra credit
+void set_threaded_server(int val);
+int exec_client_thread(int main_socket, int cli_socket);
+void *handle_client(void *arg);
+
+#endif
\ No newline at end of file
-- 
GitLab