Skip to content

Commit

Permalink
CS144 Lab 0 assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
keithw committed Sep 15, 2020
0 parents commit 05b462c
Show file tree
Hide file tree
Showing 63 changed files with 55,673 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
Language: Cpp
BasedOnStyle: LLVM
AllowAllParametersOfDeclarationOnNextLine: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakConstructorInitializers: BeforeComma
ColumnLimit: 120
CommentPragmas: '^(!|NOLINT)'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(_dt|_win)?$'
IndentCaseLabels: true
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
PenaltyReturnTypeOnItsOwnLine: 200
SpacesBeforeTrailingComments: 2
TabWidth: 4
UseTab: Never
...
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*.a
*.o
/build
CMakeCache.txt
CMakeFiles
Makefile
cmake_install.cmake
CTestTestfile.cmake
compile_commands.json
27 changes: 27 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required (VERSION 2.8.5)
cmake_policy (SET CMP0054 NEW)
project (Sponge)

include (etc/build_defs.cmake)
include (etc/build_type.cmake)
include (etc/cflags.cmake)

include (etc/doxygen.cmake)

include (etc/clang_format.cmake)
include (etc/clang_tidy.cmake)
include (etc/cppcheck.cmake)

include_directories ("${PROJECT_SOURCE_DIR}/libsponge/util")
include_directories ("${PROJECT_SOURCE_DIR}/libsponge/tcp_helpers")
include_directories ("${PROJECT_SOURCE_DIR}/libsponge")

add_subdirectory ("${PROJECT_SOURCE_DIR}/libsponge")

add_subdirectory ("${PROJECT_SOURCE_DIR}/apps")

add_subdirectory ("${PROJECT_SOURCE_DIR}/tests")

add_subdirectory ("${PROJECT_SOURCE_DIR}/doctests")

include (etc/tests.cmake)
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
For build prereqs, see [the CS144 VM setup instructions](https://web.stanford.edu/class/cs144/vm_howto).

## Sponge quickstart

To set up your build directory:

$ mkdir -p <path/to/sponge>/build
$ cd <path/to/sponge>/build
$ cmake ..

**Note:** all further commands listed below should be run from the `build` dir.

To build:

$ make

You can use the `-j` switch to build in parallel, e.g.,

$ make -j$(nproc)

To test (after building; make sure you've got the [build prereqs](https://web.stanford.edu/class/cs144/vm_howto) installed!)

$ make check_lab0

or

$ make check_lab1

etc.

The first time you run a `make check`, it may run `sudo` to configure two
[TUN](https://www.kernel.org/doc/Documentation/networking/tuntap.txt) devices for use during testing.

### build options

You can specify a different compiler when you run cmake:

$ CC=clang CXX=clang++ cmake ..

You can also specify `CLANG_TIDY=` or `CLANG_FORMAT=` (see "other useful targets", below).

Sponge's build system supports several different build targets. By default, cmake chooses the `Release`
target, which enables the usual optimizations. The `Debug` target enables debugging and reduces the
level of optimization. To choose the `Debug` target:

$ cmake .. -DCMAKE_BUILD_TYPE=Debug

The following targets are supported:

- `Release` - optimizations
- `Debug` - debug symbols and `-Og`
- `RelASan` - release build with [ASan](https://en.wikipedia.org/wiki/AddressSanitizer) and
[UBSan](https://developers.redhat.com/blog/2014/10/16/gcc-undefined-behavior-sanitizer-ubsan/)
- `RelTSan` - release build with
[ThreadSan](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Thread_Sanitizer)
- `DebugASan` - debug build with ASan and UBSan
- `DebugTSan` - debug build with ThreadSan

Of course, you can combine all of the above, e.g.,

$ CLANG_TIDY=clang-tidy-6.0 CXX=clang++-6.0 .. -DCMAKE_BUILD_TYPE=Debug

**Note:** if you want to change `CC`, `CXX`, `CLANG_TIDY`, or `CLANG_FORMAT`, you need to remove
`build/CMakeCache.txt` and re-run cmake. (This isn't necessary for `CMAKE_BUILD_TYPE`.)

### other useful targets

To generate documentation (you'll need `doxygen`; output will be in `build/doc/`):

$ make doc

To lint (you'll need `clang-tidy`):

$ make -j$(nproc) tidy

To run cppcheck (you'll need `cppcheck`):

$ make cppcheck

To format (you'll need `clang-format`):

$ make format

To see all available targets,

$ make help
1 change: 1 addition & 0 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_sponge_exec (webget)
51 changes: 51 additions & 0 deletions apps/webget.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "socket.hh"
#include "util.hh"

#include <cstdlib>
#include <iostream>

using namespace std;

void get_URL(const string &host, const string &path) {
// Your code here.

// You will need to connect to the "http" service on
// the computer whose name is in the "host" string,
// then request the URL path given in the "path" string.

// Then you'll need to print out everything the server sends back,
// (not just one call to read() -- everything) until you reach
// the "eof" (end of file).

cerr << "Function called: get_URL(" << host << ", " << path << ").\n";
cerr << "Warning: get_URL() has not been implemented yet.\n";
}

int main(int argc, char *argv[]) {
try {
if (argc <= 0) {
abort(); // For sticklers: don't try to access argv[0] if argc <= 0.
}

// The program takes two command-line arguments: the hostname and "path" part of the URL.
// Print the usage message unless there are these two arguments (plus the program name
// itself, so arg count = 3 in total).
if (argc != 3) {
cerr << "Usage: " << argv[0] << " HOST PATH\n";
cerr << "\tExample: " << argv[0] << " stanford.edu /class/cs144\n";
return EXIT_FAILURE;
}

// Get the command-line arguments.
const string host = argv[1];
const string path = argv[2];

// Call the student-written function.
get_URL(host, path);
} catch (const exception &e) {
cerr << e.what() << "\n";
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}
3 changes: 3 additions & 0 deletions doctests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_sponge_exec (address_dt)
add_sponge_exec (parser_dt)
add_sponge_exec (socket_dt)
21 changes: 21 additions & 0 deletions doctests/address_dt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "address.hh"

#include <cstdlib>
#include <iostream>
#include <stdexcept>

int main() {
try {
#include "address_example_1.cc"
#include "address_example_2.cc"
#include "address_example_3.cc"
if ((google_webserver.port() != 443) || (a_dns_server_numeric != 0x12'47'00'97)) {
throw std::runtime_error("unexpected value");
}
} catch (const std::exception &e) {
std::cerr << "This test requires Internet access and working DNS.\n";
std::cerr << "Error: " << e.what() << "\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
1 change: 1 addition & 0 deletions doctests/address_example_1.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const Address google_webserver("www.google.com", "https");
1 change: 1 addition & 0 deletions doctests/address_example_2.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const Address a_dns_server("18.71.0.151", 53);
1 change: 1 addition & 0 deletions doctests/address_example_3.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const uint32_t a_dns_server_numeric = a_dns_server.ipv4_numeric();
15 changes: 15 additions & 0 deletions doctests/parser_dt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "parser.hh"

#include <cstdint>
#include <cstdlib>
#include <stdexcept>
#include <vector>

int main() {
try {
#include "parser_example.cc"
} catch (...) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
32 changes: 32 additions & 0 deletions doctests/parser_example.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const uint32_t val1 = 0xdeadbeef;
const uint16_t val2 = 0xc0c0;
const uint8_t val3 = 0xff;
const uint32_t val4 = 0x0c05fefe;

// first, let's serialize it
std::string buffer;
buffer.push_back(0x32); // manually added to beginning of string
{
NetUnparser p;
p.u32(buffer, val1);
p.u16(buffer, val2);
p.u8(buffer, val3);
p.u32(buffer, val4);
} // p goes out of scope, data is in buffer

// now let's deserialize it
uint8_t out0, out3;
uint32_t out1, out4;
uint16_t out2;
{
NetParser p{std::string(buffer)}; // NOTE: starting at offset 0
out0 = p.u8(); // buffer[0], which we manually set to 0x32 above
out1 = p.u32(); // parse out val1
out2 = p.u16(); // val2
out3 = p.u8(); // val3
out4 = p.u32(); // val4
} // p goes out of scope

if (out0 != 0x32 || out1 != val1 || out2 != val2 || out3 != val3 || out4 != val4) {
throw std::runtime_error("bad parse");
}
26 changes: 26 additions & 0 deletions doctests/socket_dt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "socket.hh"

#include "address.hh"
#include "util.hh"

#include <array>
#include <cstdlib>
#include <random>
#include <stdexcept>
#include <sys/socket.h>
#include <vector>

int main() {
try {
{
#include "socket_example_1.cc"
} {
#include "socket_example_2.cc"
} {
#include "socket_example_3.cc"
}
} catch (...) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
20 changes: 20 additions & 0 deletions doctests/socket_example_1.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const uint16_t portnum = ((std::random_device()()) % 50000) + 1025;

// create a UDP socket and bind it to a local address
UDPSocket sock1;
sock1.bind(Address("127.0.0.1", portnum));

// create another UDP socket and send a datagram to the first socket without connecting
UDPSocket sock2;
sock2.sendto(Address("127.0.0.1", portnum), "hi there");

// receive sent datagram, connect the socket to the peer's address, and send a response
auto recvd = sock1.recv();
sock1.connect(recvd.source_address);
sock1.send("hi yourself");

auto recvd2 = sock2.recv();

if (recvd.payload != "hi there" || recvd2.payload != "hi yourself") {
throw std::runtime_error("wrong data received");
}
26 changes: 26 additions & 0 deletions doctests/socket_example_2.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const uint16_t portnum = ((std::random_device()()) % 50000) + 1025;

// create a TCP socket, bind it to a local address, and listen
TCPSocket sock1;
sock1.bind(Address("127.0.0.1", portnum));
sock1.listen(1);

// create another socket and connect to the first one
TCPSocket sock2;
sock2.connect(Address("127.0.0.1", portnum));

// accept the connection
auto sock3 = sock1.accept();
sock3.write("hi there");

auto recvd = sock2.read();
sock2.write("hi yourself");

auto recvd2 = sock3.read();

sock1.close(); // don't need to accept any more connections
sock2.close(); // you can call close(2) on a socket
sock3.shutdown(SHUT_RDWR); // you can also shutdown(2) a socket
if (recvd != "hi there" || recvd2 != "hi yourself") {
throw std::runtime_error("wrong data received");
}
14 changes: 14 additions & 0 deletions doctests/socket_example_3.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// create a pair of stream sockets
std::array<int, 2> fds{};
SystemCall("socketpair", ::socketpair(AF_UNIX, SOCK_STREAM, 0, fds.data()));
LocalStreamSocket pipe1{FileDescriptor(fds[0])}, pipe2{FileDescriptor(fds[1])};

pipe1.write("hi there");
auto recvd = pipe2.read();

pipe2.write("hi yourself");
auto recvd2 = pipe1.read();

if (recvd != "hi there" || recvd2 != "hi yourself") {
throw std::runtime_error("wrong data received");
}
Loading

0 comments on commit 05b462c

Please sign in to comment.