TCP REPL commands
This section lists REPL commands for working with sockets. These commands should only be implemented on hosts.
There are two types of commands:
-
Basic commands are small wrappers around Socket API functions so that we can test them. These commands don’t do much more than call their respective API function (but see the sections on each command for details):
-
a
: Listen and accept on a port (like a “server”) -
c
: Connect to a socket (like a “client”) -
s
: Send data using a socket -
r
: Receive data on a socket -
cl
: Close a socket
-
-
Other commands: are a bit more involved:
-
ls
: List all sockets -
sf
: Use your Socket API to send a file -
rf
: Use your Socket API to receive a file
-
The following sections describe the format of each REPL command.
Note: This specification is not as strict as IP. In particular, we do not specify exact messages that should be printed when certain commands return, especially when errors occur. In cases where the specification does not give a specific format, you are free to choose your own behavior.
For example, if a command results in an error, you can choose what the error message looks like.
We will be grading your work manually, so any implementation that that can perform the actions specified here and produce the same output is sufficient. Therefore, please try to stick to the parts that are specified, but don’t worry if you need to take liberties on things that are not.
About socket IDs
In the REPL, all sockets are identified by an ID number so we can refer to them in commands. This means that you will need some way to map socket IDs to socket objects in your TCP stack.
Depending on how you implement your socket API, this mapping (ie, IDs to socket objects) may occur inside your TCP stack, or as part of your REPL.
c: Connect to a port
Connect to an IP and port using VConnect, returning an ID number for the socket.
Example
> c 10.0.0.1 9999
Specification
Format:
c <vip> <port>
Param | Example | Description |
---|---|---|
vip | 10.0.0.1 | Virtual IP of destination |
port | 8000 | Destination port for TCP connection |
On successful connection, no output is expected from this command. On error, a message should be printed indicating the error from VConnect
.
a: Listen + Accept incoming connections
Create a listening socket on the specified port and create a thread to accept new connections asynchronously.
Format:
a <port>
where <port>
is the TCP port on which to listen.
If the listen socket is created successfully, no output is expected from this command. If the socket creation fails, a message should be printed indicating the error.
What this command does
After creating the listen socket, this command should start up a thread/goroutine that continually calls VAccept
to accept new connections from clients, like this (in pesudo-Go):
func ACommand(port) {
listenConn := VListen(port)
for {
clientConn, err := listenConn.VAccept()
// . . .
}
}
The idea here is to emulate the behavior of a server accepting connections (like your Snowcast server). Once a client connects, this thread doesn’t need to do anything with the new client socket, so long as it is usable by other REPL commands (eg. s
, r
, etc.) afterward.
After the client socket has been created, the thread should continue accepting further connections.
s: Send to a socket
Example
Send bytes to a socket using VWrite.
> s 0 aaaa
Sent 4 bytes
Specification
Format:
s <socket ID> <bytes>
Param | Example | Description |
---|---|---|
socket ID | 0 | Socket ID number. MUST be a normal socket, not a listen socket |
bytes | hello | ASCII string of data to send. Will not contain spaces (ie, you can stop parsing at any whitespace) |
Note: Even though the REPL
s
command only sends strings, theVWrite
function in your socket APIMUST
be able to send arbitrary bytes, since you will need to send files with arbitrary data (withsf
andrf
).Since this command is just for testing your sockets, we just use it with simple strings to keep the text parsing easier.
This command MUST
block until VWrite
returns.
On a successful send, s
should print the number of bytes sent to standard out. On error, a message should be printed indicating the error.
r: Receive
Read data on a socket using VRead
. This command MUST
block until VRead
returns.
Example
> r 0 5
Read 5 bytes: hello
Format
> r <socket ID> <numbytes>
Param | Example | Description |
---|---|---|
socket ID | 0 | Socket ID to read from |
numbytes | 10 | Number of bytes to read |
When VRead
returns, this command should print the number of bytes returned, and any data.
Note:
VRead
may return fewer bytes than the number of bytes requested withnumbytes
–this is expected. Yourr
command should print whatever number of bytes was returned byVRead
. For example, the following behavior is valid:> r 0 10 Read 2 bytes: ab
ls: List sockets
List all sockets, along with their TCP state.
Example:
Here’s an example table with two sockets. Socket 0 is a listen socket, socket 1 is a socket for a client that connected to this listen socket.
> ls
SID LAddr LPort RAddr RPort Status
0 0.0.0.0 9999 0.0.0.0 0 LISTEN
1 10.1.0.2 9999 10.0.0.1 46810 ESTABLISHED
Specification
Format (after first line):
<socket ID> <laddr> <lport> <raddr> <rport> <status>
Param | Example | Description |
---|---|---|
socket ID | 0 | Socket ID |
laddr | 10.1.0.2 | Local IP address: this should be the IP address of this node, which is used as the source address on packets sent using this socket. |
lport | 9999 | Local TCP port |
raddr | 10.0.0.1 | Remote IP address: IP address of the other endpoint for this socket, which is used as the destination address on packets sent using this socket |
rport | 46810 | Remote TCP port |
status | ESTABLISHED | Connection state, per the TCP state machine |
Notes
-
Listen sockets are not connected to a remote endpoint and thus have no remote IP/port. By convention, we write the remote IP and port for listen sockets as
0.0.0.0
and 0, respectively. Similarly, the local IP should also be0.0.0.0
.
cl: Close socket
Initiate connection teardown by calling VClose
. This function MUST NOT
block.
Format:
cl <socket ID>
Under normal operation, no output is expected after running this command. On error, a message should be printed describing the error.
sf: Send file
Send a file to an IP and port using your Socket API (VConnect
, VWrite
, VClose
, etc.).
Example
> sf path/to/some_file 10.1.0.2 9999
Sent 1048576 total bytes
This command sends the file at path/to/some_file
to address 10.1.0.2 on port 9999.
Specification
Format:
sf <file path> <addr> <port>
where <file path>
is the path to a file and <addr>
and <port>
are the destination IP address and port numbers, respectively.
On successful operation, this command should print the total number of bytes sent–there is no required format to emulate, so long as you include this information.
On error, this command should print a message indicating the failure.
Notes
- This command
MUST
operate asynchronously to the REPL. In other words, it must create a separate thread/goroutine that does the send process, so that you can run other REPL commands while the file transmission is in progress. - This command
MUST NOT
print all of the file’s contents to the terminal by default, as the file may be very large. (It’s okay to do this with your own logging/debugging config, though)
rf: Receive file
> rf path/to/some_destination_file 9999
[ . . .]
Received 1048576 total bytes
This command starts a new thread that waits for a connection on the specified listening port. After a client connects, it receives data until the sender closes the connection, writing the output to the destination file.
Specification
Format:
rf <dest file> <port>
where <destfile>
is the path for the file to be written and <addr>
and <port>
is the port number to listen for a connection.
On successful operation, this command should print the total number of bytes received–there is no required format to emulate, so long as you include this information.
On error, this command should print a message indicating the failure.
Notes
- This command
MUST
operate asynchronously to the REPL–in other words, it must create a separate thread/goroutine that does the send process, so that you can run other REPL commands while the file transmission is in progress. - This command
MUST NOT
print all of the file’s contents to the terminal by default, as the file may be very large. (It’s okay to do this with your own logging/debugging config, though) - If the destination file
<dest file>
exists, itMUST
be overwritten (truncated) with the new contents. The resulting file should contain the bytes received on during the latest connection only - The listen socket opened by
rf
only needs to accept one client connection. You do not need to continuously check for new connections after the first client has connected. After the receive file operation finishes, the listen port should be closed.
Modifications for Congestion Control (capstone only)
Implementations with congestion control should add two additional REPL commands (lc
, sc
), as well as modify s
and sf
to support specifying a congestion control method.
Here’s a summary of the changes (again, we will not be strict on the formatting, so long as you can do these things):
Command | Description |
---|---|
lc | Prints the available congestion control algorithm names, eg. reno , tahoe , … |
sc <socket ID> <string> | Sets the congestion control algorithm for the given socket. To disable congestion control, use the string: none
|
s | You should modify your ls command to also list the congestion control algorithm (if any) each socket is using, and the congestion window size as well. |
sf | You should modify your sf command to optionally take in a congestion control algorithm, with the options being: reno , tahoe , …. The default for no argument is none . |
Reference only
The following commands are provided only in the reference version for debugging purposes. You do not need to implement them.
drop
Configures a probabilistic drop rate when forwarding packets. The input must be a number between 0 and 1. drop 0
forwards all packets, drop 1
drops all packets.
This command only works on the reference vrouter
. You do not need to implement this.
Example
> drop 0.02
This example drops 2% of packets forwarded. No output is expected from this command.
Notes
- Instead of specifying this command each time you start up, you can pass it as a command-line option when starting the router using
--drop
. For info, see here. - If you want to drop packets in a predictable way for testing, you can configure the random seed used when dropping packets using
--drop-rate-seed
. For more info, see here.