This Is Not The Course Website You Are Looking For

This course website is from a previous semester. If you are currently in the class, please make sure you are viewing the latest course website instead of this old one.

The goal of this homework assignment is to allow you to practice communicating across the Internet via sockets and performing parallel computing with multiple processes in C. The first activity involves implementing a HTTP library, while the second activity requires you to use this library to build a thor utility that resembles curl (except with the ability to make many requests using multiple processes).

For this assignment, record your source code and any responses to the following activities in the homework09 folder of your assignments GitHub repository and push your work by noon, Saturday, May 08.

Activity 0: Preparation

Before starting this homework assignment, you should first perform a git pull to retrieve any changes in your remote GitHub repository:

$ cd path/to/repository                   # Go to assignments repository

$ git checkout master                     # Make sure we are in master branch

$ git pull --rebase                       # Get any remote changes not present locally

Next, create a new branch for this assignment:

$ git checkout -b homework09              # Create homework09 branch and check it out

You are now ready to work on the activities below.

Frequently Asked Questions

Activity 1: HTTP Library (7 Points)

As discussed in class, web clients such as your web browser utilize HTTP to request data from remote web servers. This communication involves the client using a TCP or streaming socket to connect to a server to send a request that looks something like this:

GET /path HTTP/1.0
Host: domain.com

The first line of the request specifies the operation (ie. GET) followed by the resource being request (ie. /PATH) and then the protocol spoken by the client (ie. HTTP/1.0). After this first line, comes a series of headers, one of which is the Host or the name of the machine we are requesting the resource from. To terminate the headers, the client writes a blank line.

DOS Line Endings

It turns out that the HTTP protocol uses our friend, DOS line endings. This means that each line in the HTTP request and response is terminated by \r\n or CRLF. Keep this in mind when writing your request and reading the response.

Once the request has been written to the server, the client then waits to read back the response, which looks something like this:

HTTP/1.1 200 OK
Content-Length: 1983

<html>
...
</html>

The first line of the response contains the status of the request. Successful requests have 200 OK while non-successful requests will have different status codes such as 301 Moved Permanently or 404 Not Found. After this first line, the response will contain a series of headers, one of which is the Content-Length that tells the client how large the contents of the response body should be. Following the headers is a blank line, and then the contents of the response. This is usually the file or resource that was requested (ie. HTML or image data).

Note: Not all HTTP servers will return a Content-Length, so keep that in mind when implementing your HTTP client.

The overall goal of this assignment is for you to build your own version curl that speaks basic HTTP using TCP sockets as described above. Additionally, your version of a HTTP client will support hammering the HTTP server by using multiple child processes to make concurrent HTTP requests.

The remainder of this document details how you are to first build a library that supports communicating via HTTP and then the thor utility that provides a command-line interface to the library's functionality.

Skeleton Code

To help you get started, the instructor has provided you with the following skeleton code:

# Go to assignments repository
$ cd path/to/assignments/repository

# ------------------------------------------------
# MAKE SURE YOU ARE NOT INSIDE homework09
# MAKE SURE YOU ARE AT THE TOP-LEVEL DIRECTORY
# ------------------------------------------------

# Download skeleton code tarball
$ curl -LO https://raw.githubusercontent.com/nd-cse-20289-sp21/cse-20289-sp21-assignments/master/homework09/homework09.tar.gz

# Extract skeleton code tarball
$ tar xzvf homework09.tar.gz

Once downloaded and extracted, you should see the following files in your homework09 directory:

homework09
    \_ Makefile               # This is the Makefile for building all the project artifacts
    \_ README.md              # This is the README file for recording your responses
    \_ bin                    # This contains the binary executables and test scripts
      \_ loki.py              # This is the Python script that implements a HTTP server
      \_ test_http.sh         # This is the shell script for testing the HTTP functions
      \_ test_socket.sh       # This is the shell script for testing the socket functions
      \_ test_thor.sh         # This is the shell script for testing the thor utility
      \_ test_timestamp.sh    # This is the shell script for testing the timestamp functions
      \_ test_url.sh          # This is the shell script for testing the URL structure
    \_ include                # This contains the header files
      \_ hammer.h             # This is the C header file for hammer functions
      \_ http.h               # This is the C header file for HTTP functions
      \_ macros.h             # This is the C header file for macros
      \_ socket.h             # This is the C header file for socket functions
      \_ timestamp.h          # This is the C header file for timestamp functions
      \_ url.h                # This is the C header file for URL structure
    \_ lib                    # This contains the library files
    \_ src                    # This contains the C implementation files
      \_ hammer.c             # This is the C implementation file for the hammer functions
      \_ http.c               # This is the C implementation file for the HTTP functions
      \_ socket.c             # This is the C implementation file for the socket functions
      \_ thor.c               # This is the C implementation file for the thor utility
      \_ timestamp.c          # This is the C implementation file for the timestamp functions
      \_ url.c                # This is the C implementation file for the URL structure
    \_ tests                  # This contains the unit test C implementation files
      \_ unit_http.c          # This is the C implementation file for the HTTP unit test
      \_ unit_socket.c        # This is the C implementation file for the socket unit test
      \_ unit_timestamp.c     # This is the C implementation file for the timestamp unit test
      \_ unit_url.c           # This is the C implementation file for the URL unit test

The details on what you need to implement are described in the following sections.

Task 0: Headers

The following is a description of the header files included in the skeleton code.

include/url.h

The include/url.h file is the header file for the URL struct. In addition to the function prototypes, this header defines the following type:

typedef struct {
    char *host;     /* Parsed URL host */
    char *port;     /* Parsed URL port */
    char *path;     /* Parsed URL path */
} URL;

This defines a URL struct type consisting of three [string]s:

  1. host contains the host component of a URL.
  2. port contains the port component of a URL.
  3. path contains the path component of a URL.

As shown above, a URL may contain five different components: protocol, host, port, path, and query string. The URL struct only needs to store the host, port, and path of any URL provided by the user.

Missing URL Components

Note: Not all URLs will specify every component explicitly. Some may be missing the protocol or the port or even the path (the host must always be given).

For instance, here are some valid URLs you will need to support:

If the port is not specified, then you are to assume the default HTTP port: 80. If a path is not specified, then you can assume an empty path: "".

include/hammer.h, include/http.h, include/socket.h, include/timestamp.h

The include/hammer.h, include/http.h, include/socket.h, and include/timestamp.h header files contain function prototypes but do not introduce any new types or [structs].

More details on how to implement the functions declared in these header files is provided below.

include/macros.h

Finally, the include/macros.h header file provides a debug macro that you can use to insert debugging statements into your code (rather than printf):

debug("foo = %d", foo);

The advantage of using this macro is that it displays the file name, line number, and function name where the command is called in its output, along with the formatted message you specified.

Likewise, the header file also provides a streq macro that you can use instead of strcmp:

if (streq(source, target)) {
    ...
}

For this task, you do not need to modify these header files. Instead, you should review them and ensure you understand the provided code.

Task 1: Makefile

Once again, the Makefile contains all the rules or recipes for building the project artifacts (e.g. libthor.a, thor, etc.). Although the provided Makefile contains most of the variable definitions and test recipes, you must add the appropriate rules for libthor.a, unit_http, unit_socket, unit_timestamp, unit_url, thor, and any intermediate objects. The dependencies for these targets are shown in the DAG below:

Makefile Variables

You must use the CC, CFLAGS, LD, LDFLAGS, AR, and ARFLAGS variables when appropriate in your rules.

Once you have a working Makefile, you should be able to run the following commands:

# Build all TARGETS
$ make
Compiling src/thor.o...
Compiling src/url.o...
Compiling src/socket.o...
Compiling src/http.o...
Compiling src/timestamp.o...
Compiling src/hammer.o...
Linking lib/libthor.a...
Linking bin/thor...


# Run all tests
$ make test
Compiling tests/unit_url.o...
Linking bin/unit_url...
Testing url...

# Simulate build with tracing output
$ make -n
echo Compiling src/thor.o...
gcc -g -Wall -std=gnu99 -Iinclude -c -o src/thor.o src/thor.c
echo Compiling src/url.o...
gcc -g -Wall -std=gnu99 -Iinclude -c -o src/url.o src/url.c
echo Compiling src/socket.o...
gcc -g -Wall -std=gnu99 -Iinclude -c -o src/socket.o src/socket.c
echo Compiling src/http.o...
gcc -g -Wall -std=gnu99 -Iinclude -c -o src/http.o src/http.c
echo Compiling src/timestamp.o...
gcc -g -Wall -std=gnu99 -Iinclude -c -o src/timestamp.o src/timestamp.c
echo Compiling src/hammer.o...
gcc -g -Wall -std=gnu99 -Iinclude -c -o src/hammer.o src/hammer.c
echo Linking lib/libthor.a...
ar rcs lib/libthor.a src/url.o src/socket.o src/http.o src/timestamp.o src/hammer.o
echo Linking bin/thor...
gcc -Llib -o bin/thor src/thor.o lib/libthor.a

Depending on your compiler, you may see some warnings with the initial skeleton code. Likewise, the test programs will all fail in some fashion.

Task 2: src/url.c

The src/url.c file contains the C implementation for the URL struct. For this task, you will need to implement the following functions:

  1. URL * url_parse(const char *url_string)

    This function allocates a new URL struct, sets its host, port, and path fields based on the components in the given url_string, and returns the allocated struct.

    Note:

    • You must check if allocation fails.

    • You must allocate and copy host, port, and path (consider strdup).

    • You may wish to copy the url_string to a local buffer that you can manipulate.

    • You may wish to use strstr and strchr to search the local buffer for the appropriate delimiters (e.g. HOST_DELIMITER, PATH_DELIMITER, and PORT_DELIMITER) and split the string into different components.

  2. void url_delete(URL *url)

    This function deallocates the given URL struct and any previously allocated fields such as host, port, and path.

As you implement src/url.c, you can test it by running the test-url target:

# Run test-url target
$ make test-url
Compiling tests/unit_url.o...
Linking bin/unit_url...
Testing url...
 url_parse                                          ... Success
 url_delete                                         ... Success

   Score 2.50

# Run unit_url manually
$ bin/unit_url 0

Task 3: src/socket.c

The src/socket.c file contains the C implementation for the socket functions. For this task, you will need to implement the following function:

  1. FILE *socket_dial(const char *host, const char *port)

    This function uses socket to connect to the given host and port using TCP and returns a read/writable FILE stream corresponding to the socket.

    Note:

As you implement src/socket.c, you can test it by running the test-socket target:

# Run test-socket target
$ make test-socket
Compiling tests/unit_socket.o...
Linking bin/unit_socket...
Testing socket...
 socket_dial_success                                ... Success
 socket_dial_failure                                ... Success

   Score 1.00

# Run unit_socket manually
$ bin/unit_socket 0

Task 4: src/http.c

The src/http.c file contains the C implementation for time related functions. For this task, you will need to implement the following function:

  1. ssize_t http_get(const URL *url, FILE *stream)

    This function makes a HTTP request to the given url using socket_dial and writes the response body to the given stream. It returns the number of bytes written to the output stream or -1 if any error was experienced during the HTTP request.

    Note:

    • You must check if any of the system calls fail.

    • You will want to follow the HTTP transaction steps described above and outlined below:

      1. Connect to remote host and port.
      2. Send HTTP request to remote server.
      3. Read response status and verify success.
      4. Read response headers (until there is an empty line).
      5. Read response body and copy to stream.
      6. Close connection.
      7. Return number of bytes written to stream.

    • Remember that HTTP uses DOS line endings and terminates each line with \r\n.

    • You may wish to use strstr to check the response status.

    • You may wish to use sscanf to parse the response headers for the value of Content-Length.

    • You may wish to use fgets to read the response status and headers.

    • You must use fread and fwrite to read the response body since it may contain binary data.

    • If the server provides a Content-Length and the number of bytes written to steam does not match, then the function should return -1 to indicate an error. Otherwise, if there is no Content-Length or the number of bytes written matches, then it should return the number of bytes written.

As you implement src/http.c, you can test it by running the test-http target:

# Run test-http target
$ make test-http
Compiling tests/unit_http.o...
Linking bin/unit_http...
Testing http...
 http_get_success                                   ... Success
 http_get_failure                                   ... Success

   Score 3.00

# Run unit_http manually
$ bin/unit_http 0

Task 5: src/timestamp.c

The src/timestamp.c file contains the C implementation for time related functions. For this task, you will need to implement the following function:

  1. double timestamp()

    This function returns a double that corresponds to the current time in seconds.

    Note:

    • You must check if any of the system calls fail.

    • You must use gettimeofday to account for both seconds and microseconds using this formula:

      timestamp = seconds + (microseconds / 1000000.0).
      

As you implement src/timestamp.c, you can test it by running the test-timestamp target:

# Run test-timestamp target
$ make test-timestamp
Compiling tests/unit_timestamp.o...
Linking bin/unit_timestamp...
Testing timestamp...
 timestamp                                          ... Success

   Score 0.50

# Run unit_timestamp manually
$ bin/unit_timestamp 0

Task 6: src/hammer.c

The src/hammer.c file contains the C implementation for hammer function. For this task, you will need to implement the following function:

  1. bool hammer(const URL *url, FILE *stream, size_t n)

    This function uses fork to first create n processes where each child process performs a HTTP request using the http_get() function on the given url and stream, and then displays the computed bandwidth for that individual request. Afterwards, the parent process must wait on each child process and displays the total elapsed time for the whole function. It will return true if all child processes reported success, otherwise false.

    Note:

    • You must check if any of the system calls fail.

    • The parent must fork all the child processes and then wait for them. It will need to use the timestamp() function to compute the overall elapsed time for the function.

    • Each child must compute the bandwidth by using the following formula:

      bandwidth = bytes_written / 1048576.0 / (end_time - start_time)
      

      bytes_written will be returned from http_get() while end_time and start_time can be retrieved from timestamp().

To test the hammer function, you will need to implement the thor utility, which will call this function.

Activity 2: Thor (7 Points)

Once you have a working HTTP library, you are to complete the src/thor.c program:

# Display usage
$ ./bin/thor -h
Usage: ./bin/thor [options] URL
    -n N   How many times to hammer the URL

The bin/thor program takes the given URL and makes N requests to it using multiple processes which write their responses to standard output. If N is not specified, then it defaults to 1.

Examples

Here are some examples of bin/thor in action:

# Throw one hammer at example.com
$ ./bin/thor example.com
<!doctype html>
    <title>Example Domain</title>
...
</body>
</html>
Bandwidth: 0.05 MB/s
Elapsed Time: 0.02 seconds

# Throw two hammers at example.com
$ ./bin/thor -n 2 example.com
<!doctype html>
    <title>Example Domain</title>
...
</body>
</body>
</html>
</html>
Bandwidth: 0.05 MB/s
Bandwidth: 0.05 MB/s
Elapsed Time: 0.02 seconds

Note: Each child process should print the bandwidth it computes to stderr, while the parent prints the elapsed time to stderr.

Task 1: src/thor.c

The src/thor.c file contains the C implementation of the thor tool described above.

To complete this program, you will need to do the following:

  1. Parse the command-line arguments.
  2. Parse the given URL with url_parse().
  3. Hammer the given URL with hammer().

As you implement src/thor.c, you can test it by running the test-thor target:

# Run test-thor target
$ make test-thor
Compiling src/thor.o...
Linking bin/thor...
Testing thor...
 thor                                               ... Success
 thor -h                                            ... Success
 thor -?                                            ... Success
 thor http://nd.edu                                 ... Success
 thor -n 1 http://nd.edu                            ... Success
 thor http://example.com                            ... Success
 thor -n 2 http://example.com                       ... Success
 thor http://h4x0r.space:9898/appa.png              ... Success
 thor -n 3 http://h4x0r.space:9898/appa.png         ... Success
 thor h4x0r.space:9898/walden.txt                   ... Success
 thor -n 4 h4x0r.space:9898/walden.txt              ... Success

   Score 7.00

# Run test_thor.sh manually
$ bin/test_thor.sh

Activity 3: Quiz (2 Points)

Once you have completed all the activities above, you are to complete the following reflection quiz:

As with Reading 01, you will need to store your answers in a homework09/answers.json file. You can use the form above to generate the contents of this file, or you can write the JSON by hand.

To test your quiz, you can use the check.py script:

$ ./check.py
Checking homework09 quiz ...
     Q01 0.40
     Q02 0.40
     Q03 0.30
     Q04 0.30
     Q05 0.30
     Q06 0.30
   Score 2.00 / 2.00
  Status Success

Guru Point: Thor.py, TROLL, IRC Bot, VPS (4 2 Points)

For this week, there are four Guru Point opportunities.

Academic Dishonesty

Due to the widespread academic dishonesty surrounding recent Guru Points, only two of these opportunities will be available.

Self-Service Extension

Remember that you can always forgo these Guru Points for two extra days to do the homework. That is, if you need an extension, you can simply skip the Guru Points and you will automatically have until Monday to complete the assignment for full credit.

Just leave a note on your Pull Request of your intensions.

Thor.py (1 Point)

Now that you have an idea of how sockets and processes work at the [system call] level, let's return to Python and consider how we can use these mechanisms at a higher level.

For extra credit, you are to use Python along with requests and concurrent.futures to implement a version of thor (called thor.py) with the following usage:

# Display help message
$ ./thor.py
Usage: thor.py [-h HAMMERS -t THROWS] URL
    -h  HAMMERS     Number of hammers to utilize (1)
    -t  THROWS      Number of throws per hammer  (1)
    -v              Display verbose output

Skeleton

Here is a basic skeleton, thor.py, that you can start with:

import concurrent.futures
import os
import requests
import sys
import time

# Functions

def usage(status=0):
    progname = os.path.basename(sys.argv[0])
    print(f'''Usage: {progname} [-h HAMMERS -t THROWS] URL
    -h  HAMMERS     Number of hammers to utilize (1)
    -t  THROWS      Number of throws per hammer  (1)
    -v              Display verbose output
    ''')
    sys.exit(status)

def hammer(url, throws, verbose, hid):
    ''' Hammer specified url by making multiple throws (ie. HTTP requests).

    - url:      URL to request
    - throws:   How many times to make the request
    - verbose:  Whether or not to display the text of the response
    - hid:      Unique hammer identifier

    Return the average elapsed time of all the throws.
    '''
    return 0

def do_hammer(args):
    ''' Use args tuple to call `hammer` '''
    return hammer(*args)

def main():
    hammers = 1
    throws  = 1
    verbose = False

    # Parse command line arguments
    pass

    # Create pool of workers and perform throws
    pass

# Main execution

if __name__ == '__main__':
    main()

Examples

Below are some examples of thor.py in action:

# Perform single throw
$ ./thor.py http://example.com
Hammer: 0, Throw:   0, Elapsed Time: 0.03
Hammer: 0, AVERAGE   , Elapsed Time: 0.03
TOTAL AVERAGE ELAPSED TIME: 0.03

# Perform 10 throws
$ ./thor.py -t 10 http://example.com
Hammer: 0, Throw:   0, Elapsed Time: 0.03
Hammer: 0, Throw:   1, Elapsed Time: 0.03
Hammer: 0, Throw:   2, Elapsed Time: 0.03
Hammer: 0, Throw:   3, Elapsed Time: 0.03
Hammer: 0, Throw:   4, Elapsed Time: 0.03
Hammer: 0, Throw:   5, Elapsed Time: 0.03
Hammer: 0, Throw:   6, Elapsed Time: 0.03
Hammer: 0, Throw:   7, Elapsed Time: 0.03
Hammer: 0, Throw:   8, Elapsed Time: 0.03
Hammer: 0, Throw:   9, Elapsed Time: 0.03
Hammer: 0, AVERAGE   , Elapsed Time: 0.03
TOTAL AVERAGE ELAPSED TIME: 0.03

# Perform 5 throws requests with 2 hammers
$ ./thor.py -t 5 -h 2 http://example.com
Hammer: 1, Throw:   0, Elapsed Time: 0.03
Hammer: 0, Throw:   0, Elapsed Time: 0.03
Hammer: 1, Throw:   1, Elapsed Time: 0.03
Hammer: 0, Throw:   1, Elapsed Time: 0.03
Hammer: 1, Throw:   2, Elapsed Time: 0.03
Hammer: 0, Throw:   2, Elapsed Time: 0.03
Hammer: 1, Throw:   3, Elapsed Time: 0.03
Hammer: 0, Throw:   3, Elapsed Time: 0.03
Hammer: 1, Throw:   4, Elapsed Time: 0.03
Hammer: 1, AVERAGE   , Elapsed Time: 0.03
Hammer: 0, Throw:   4, Elapsed Time: 0.03
Hammer: 0, AVERAGE   , Elapsed Time: 0.03
TOTAL AVERAGE ELAPSED TIME: 0.03

# Perform single throw with verbose output
$ ./thor.py -v http://example.com
<!doctype html>
...
</html>

Hammer: 0, Throw:   0, Elapsed Time: 0.03
Hammer: 0, AVERAGE   , Elapsed Time: 0.03
TOTAL AVERAGE ELAPSED TIME: 0.03

Hints

Testing

To verify that your thor.py works, you can use the provided test_thor_py.sh script:

Testing ./thor.py...
Functions                                                        ... Success

Usage
    no arguments                                                 ... Success
    bad arguments                                                ... Success

Single Hammer
    https://example.com                                          ... Success
    https://example.com (-v)                                     ... Success
    https://yld.me                                               ... Success
    https://yld.me (-v)                                          ... Success
    https://yld.me/izE?raw=1                                     ... Success
    https://yld.me/izE?raw=1 (-v)                                ... Success

Single Hammer, Multiple Throws
    https://example.com (-t 4)                                   ... Success
    https://example.com (-t 4 -v)                                ... Success
    https://yld.me (-t 4)                                        ... Success
    https://yld.me (-t 4 -v)                                     ... Success
    https://yld.me/izE?raw=1 (-t 4)                              ... Success
    https://yld.me/izE?raw=1 (-t 4 -v)                           ... Success

Multiple Hammers
    https://example.com (-h 2)                                   ... Success
    https://example.com (-h 2 -v)                                ... Success
    https://yld.me (-h 2)                                        ... Success
    https://yld.me (-h 2 -v)                                     ... Success
    https://yld.me/izE?raw=1 (-h 2)                              ... Success
    https://yld.me/izE?raw=1 (-p 2 -v)                           ... Success

Multiple Hammers, Multiple Throws
    https://example.com (-h 2 -t 4)                              ... Success
    https://example.com (-h 2 -t 4 -v)                           ... Success
    https://yld.me (-h 2 -t 4)                                   ... Success
    https://yld.me (-h 2 -t 4 -v)                                ... Success
    https://yld.me/izE?raw=1 (-h 2 -t 4)                         ... Success
    https://yld.me/izE?raw=1 (-h 2 -t 4 -v)                      ... Success

Verification

To get credit for this Guru Point, you must show either the instructor or TA a demonstration of your thor.py in action (or attach a video / screenshot to your Pull Request). You have up until Tuesday, May 11 to verify your guru point.

TROLL (1 Point)

For extra credit, you are to use C and system calls to implement your own version of the TROLL from Homework 01. Recall, that the TROLL was a process that intercepted signals such as SIGINT and SIGTERM and taunted you when you tried to terminate it. Your version of the TROLL should do something similar (prevent easy termination)... but its taunts and other aesthetic details are up to you.

Verification

To get credit for this Guru Point, you must show either the instructor or TA a demonstration of your TROLL in action (or attach a video / screenshot to your Pull Request). You have up until Tuesday, May 11 to verify your guru point.

IRC Bot (1 Point)

For extra credit, you are to use Python and sockets to implement your own version of bobbit, an IRC chat bot. Your bot should connect to the chat.ndlug.org server and join the #bots channel. It should be able to respond to at least one type of command or message. The particular operation is up to you.

To help you get started, here are some resources:

NDLUG IRC

To connect to the NDLUG server yourself, you can register via regserv.ndlug.org, which will setup a Lounge and IRC account for you.

The Lounge is a web-based IRC client that you can use from any web browser, but you are free to connect to the IRC server from any IRC client such as Weechat, Hexchat, or Textual using chat.ndlug.org as the hostname and 6697 as the port.

A basic IRC client session looks like this:

USER ircle-pbui 0 * :pbui's bot
NICK ircle-pbui
JOIN #bots
PRIVMSG #bots :I've fallen and I can't get up!
  1. The USER command sets the users real name and registers the user.

  2. The NICK command sets the users nickname.

  3. The JOIN command allows the user to join in a channel (in this case #bots).

  4. The PRIVMSG command allows the user to send a message (in this case to the channel #bots).

Here is a basic skeleton, ircle.py, that you can start with:

import asyncio
import os
import sys

# Constants

HOST = 'chat.ndlug.org'
PORT = 6697
NICK = f'ircle-{os.environ["USER"]}'

# Functions

async def ircle():
    reader, writer = await asyncio.open_connection(HOST, PORT, ssl=True)

    # Identify ourselves
    writer.write(f'USER {NICK} 0 * :{NICK}\r\n'.encode())
    writer.write(f'NICK {NICK}\r\n'.encode())
    await writer.drain()

    # Join #bots channel
    writer.write(f'JOIN #bots\r\n'.encode())
    await writer.drain()

    # Write message to channel
    writer.write(f"PRIVMSG #bots :I've fallen and I can't get up!\r\n".encode())
    await writer.drain()

    # Read and display
    while True:
        message = (await reader.readline()).decode().strip()
        print(message)

# Main execution

def main():
    asyncio.run(ircle())

if __name__ == '__main__':
    main()

Asynchronous Python

The ircle.py example code uses the new asyncio features of Python 3 to perform event-driven and concurrent programming. You will learn more about this style of programming in Programming Paradigms.

Verification

To get credit for this Guru Point, you must have your IRC bot join the #bots channel on the chat.ndlug.org server and demonstrate its functionality yourself (by logging into the server with your own account). You have up until Tuesday, May 11 to verify your guru point.

VPS (1 Point)

For extra extra credit, you are to sign up for virtual private server on a service such as Digital Ocean, Linode, Amazon Web Services, Microsoft Azure, Google Cloud, or Vultr and run the loki.py HTTP server from that VPS.

GitHub Student Developer Pack

As mentioned in class, you are eligible for the GitHub Student Developer Pack, which provides you with credits to Digital Ocean and Microsoft Azure (among many other free goodies).

Verification

To get credit for this Guru Point, you must show either the instructor or TA a demonstration of using thor to hammer loki.py running on your VPS (or attach a video / screenshot to your Pull Request). You have up until Tuesday, May 11 to verify your guru point.

Submission

To submit your assignment, please commit your work to the homework09 folder in your assignments GitHub repository. Your homework09 folder should only contain at the following files:

Note: You must not modify any of the provided test scripts or unit tests.

#--------------------------------------------------
# BE SURE TO DO THE PREPARATION STEPS IN ACTIVITY 0
#--------------------------------------------------

$ cd homework09                           # Go to Homework 09 directory
...
$ git add Makefile                        # Mark changes for commit
$ git add bin/*.sh bin/*.py               # Mark changes for commit
$ git add include/*.h                     # Mark changes for commit
$ git add lib/.gitkeep                    # Mark changes for commit
$ git add tests/*.c                       # Mark changes for commit
$ git commit -m "homework09: import"      # Record changes
...
$ git add src/url.c                       # Mark changes for commit
$ git commit -m "homework09: url"         # Record changes
...
$ git add src/socket.c                    # Mark changes for commit
$ git commit -m "homework09: socket"      # Record changes
...
$ git add src/http.c                      # Mark changes for commit
$ git commit -m "homework09: http"        # Record changes
...
$ git add src/timestamp.c                 # Mark changes for commit
$ git commit -m "homework09: timestamp"   # Record changes
...
$ git add src/hammer.c                    # Mark changes for commit
$ git commit -m "homework09: hammer"      # Record changes
...
$ git add src/thor.c                      # Mark changes for commit
$ git commit -m "homework09: thor"        # Record changes
...
$ git add answers.json                    # Mark changes for commit
$ git commit -m "homework09: quiz"        # Record changes
$ git push -u origin homework09           # Push branch to GitHub

Pull Request

Remember to create a Pull Request and assign the appropriate TA from the Reading 13 TA List.

DO NOT MERGE your own Pull Request. The TAs use open Pull Requests to keep track of which assignments to grade. Closing them yourself will cause a delay in grading and confuse the TAs.