IC221: Systems Programming (SP18)


Home Policy Calendar Units Assignments Resources

Project 03: nvycat : The Navy Netcat

Table of Contents

Project Preliminaries

Project Learning Goals

The goal of this project are:

  1. Use client and server sockets dependent on command line arguments
  2. Implement the functionality of netcat
  3. Use threading to avoid blocking

Project Grading and Due Date

This project is graded out of 100 points and is due on Tue. 1 May at 2359. Late submissions will not be allowed.

We will apply the following grading rubric to this project.

  • 60% Complete a nvycat that can connect to a server at a domain name and port specified on the command line and reads whatever is written to the socket
  • 75% Complete a nvycat that can connect to a server at a domain name and port specified on the command line, writes anything provided from stdin to the socket, and can reads whatever is written to the socket (not in a loop – one shot).
  • 82% Complete a nvycat that can connect to a server at a domain name and port specified on the command line, writes anything provided from stdin to the socket, and can reads whatever is written to the socket, in a loop, synchronously (one read for every write).
  • 92% Complete a nvycat that can connect to a server at a domain name and port specified on the command line, writes anything provided from stdin to the socket, and can reads whatever is written to the socket, in a loop, asynchronously by using threading to allow for reading and writing at the same time.
  • 100% Complete a nvycat that can connect to a server at a domain name and port specified on the command line, or act as server binding to a particular port and perform asynchronous reading and writing from the stdin/stdout to the socket.

Additional Requirements:

  • You must provide a Makefile to compile your program
  • You must ensure that there are no memory leaks and no deadlock possible
  • You must provide a README file for your program describing tasks completed and processes used. This is also the place to provide additional details to your grader.
  • You must provide a man.txt file describing the operations of your command line tool.

Project Setup:

  • Run the following command in your terminal
~aviv/bin/ic221-up
  • Then change into the following directory
cd ic221/proj/03
  • You will find all the material you need to complete this lab in that directory.
  • During the course of this lab, we will refer to the ic221/proj/03 as the project directory

Project Submission

To submit this lab you will place all relevant content into your lab directory:

ic221/proj/03

Then issue the submission script

~aviv/bin/ic221-submit

Select the option for proj/03, and confirm. You should see SUCCESS at the end. You may submit multiple times up until the submission deadline. Only your final submission will be considered for grading.


Project Description

In this project, you will implement your own version of the netcat utility called nvycat (the Navy Network Cat). netcat is one of the most useful tools in network programming, and, in fact, you should use netcat as a testing tool for your project.

When complete, your nvycat utiltity will be able to do the following things:

  1. Connect to a server at a given port sepcified on the command line
  2. Read from stdin and write any data to the socket, to be sent to the server
  3. Read from the socket (from the server) and write that data to stdout
  4. Perform reading/writing asynchronously so that it will not block on read() either on the socket or stdin prior to writing data to the screen.
  5. Act as a server if the -l argument is given.

Here's a demo of a working version of the nvycat acting in different ways.

First, nvycat can act as a simple client interacting with remote servers on different ports. (Note the GET ... is typed by me and sent to the server, the response is printed to stdout.)

 $ printf "GET /~aviv/index.html HTTP/1.1\r\nHost: csmidn.academy.usna.edu\r\n\r\n"  | ./nvycat csmidn.academy.usna.edu 80
HTTP/1.1 200 OK
Date: Wed, 18 Apr 2018 13:38:05 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Sun, 15 Apr 2018 21:56:16 GMT
ETag: "28-569ea2cb36e5d"
Accept-Ranges: bytes
Content-Length: 40
Content-Type: text/html

<html>
  <h1> You did it! </h1>
</html>
$ printf "GET /~aviv/saturn.txt HTTP/1.1\r\nHost: csmidn.academy.usna.edu\r\n\r\n"  | ./nvycat csmidn.academy.usna.edu 80
HTTP/1.1 200 OK
Date: Wed, 18 Apr 2018 13:37:32 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Tue, 14 Mar 2017 20:28:56 GMT
ETag: "1e2-54ab6ad53b200"
Accept-Ranges: bytes
Content-Length: 482
Vary: Accept-Encoding
Content-Type: text/plain

                                        _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
               
aviv@saddleback: sol $ ./nvycat faculty.cs.usna.edu 6666

MMMMMMMMMMMMMMMMMMMMM.                             MMMMMMMMMMMMMMMMMMMMM
 `MMMMMMMMMMMMMMMMMMMM           M\  /M           MMMMMMMMMMMMMMMMMMMM'
   `MMMMMMMMMMMMMMMMMMM          MMMMMM          MMMMMMMMMMMMMMMMMMM'  
     MMMMMMMMMMMMMMMMMMM-_______MMMMMMMM_______-MMMMMMMMMMMMMMMMMMM    
      MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM    
      MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM    
      MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM    
     .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM.    
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM  
                   `MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM'                
                          `MMMMMMMMMMMMMMMMMM'                    
                              `MMMMMMMMMM'                              
                                 MMMMMM                              
                                  MMMM                                  
                                   MM

Second, nvycat can act as a server, and either plain ol' netcat or a nvycat can connect to it, allowing for chatting. Note, that this communication between two machines.

On the server, it is listening on port 2233, and on the client, it connected and wrote the saturn.txt to the socket, appearing on the server.

  aviv@mich302csd02u: sol $ ./nvycat -l 2233
                                         _.oo.
                 _.u[[/;:,.         .odMMMMMM'
              .o888UU[[[/;:-.  .o@P^    MMM^
             oN88888UU[[[/;::-.        dP^
            dNMMNN888UU[[[/;:--.   .o@P^
           ,MMMMMMN888UU[[/;::-. o@^
           NNMMMNN888UU[[[/~.o@P^
           888888888UU[[[/o@^-..
          oI8888UU[[[/o@P^:--..
       .@^  YUU[[[/o@^;::---..
     oMP     ^/o@P^;:::---..
  .dMMM    .o@^ ^;::---...
 dMMMMMMM@^`       `^^^^
YMMMUP^
 ^^
./nvycat mich302csd02u.academy.usna.edu 2233 < saturn.txt

You can also have two way communications:

 aviv@mich302csd02u: sol $ ./nvycat -l 3322
I'm the client!
Nice to meet you, I'm the server
The client or server enters Ctrl-D to end the session
  ./nvycat mich302csd02u.academy.usna.edu 3322
I'm the client!
Nice to meet you, I'm the server
The client or server enters Ctrl-D to end the session

Binding to remotely accessible address for the server

One thing that you'll need to do is make your server socket bind to address that is remotely accessible. This means, you'll need to set up the sin_addr field directly rather than resolve a hostname. Fortunately, if you set this to 0, e.g., via INADDR_ANY, that is all you need.

Dealing with errors

There are a ton(!) of systems calls in this, all of which could fail. You should check for all system call failures and domain resolution errors and print appropriate messages using perror() and written to stderr. Below is an incomplete example:

aviv@mich302csd02u: sol $ ./nvycat 
ERROR: require arguments
aviv@mich302csd02u: sol $ ./nvycat a
ERROR: require arguments
aviv@mich302csd02u: sol $ ./nvycat a b
ERROR: invalid port
aviv@mich302csd02u: sol $ ./nvycat a 10
getaddrinfo: Name or service not known
aviv@mich302csd02u: sol $ ./nvycat -l 10
bind: Permission denied
aviv@mich302csd02u: sol $ ./nvycat mich302csd01u 10
connect: Connection refused

More Tips

  • Use netcat for testing. It's super useful.
  • Don't try and do everything all at once, for example, start with just doing a simple client that doesn't go back and forth, then add that functionality later.
  • Keep it simple when it comes to threading. Only place things within child-threads that really need to be there.
  • In your nvycat, if the socket is ever closed by the remote host (e.g., you read 0 bytes) then you should exit.
  • If the main-thread dies, all threads die. Don't forget to join and use exit() judiciously.