COMP6991 23T1 — Solving Modern Programming Problems with Rust A2

COMP6991 – 23T1
Assignment 2
Implementing a Rust IRC Server Change Log
Assignment Released
Implementation of a Rust IRC Server (IRIS)
In this second assignment we will be building an IRC Server in Rust. IRC is the “Internet Relay Chat” protocol. It is the ancient predecessor of services like Discord and Messenger; and is even still used today. You will only be implementing a server, and do not need to implement a client.
There are three parts to this assignment:
Part 1 is setting up your server. No knowledge of concurrency is required for this step.
Part 2 is supporting inter-user messaging and IRC channels, which will require concurrency. Part 3 is supporting plugins.
The goals of this assignment are:
1. Toexperienceconcurrentprogramminginrust.
2. Topracticedesigningandstructuringalargerrustprogram.
3. Tofocusonskillsanddesignpatternsthatwouldactuallybeusedwhensolvingmodernprogrammingproblems(i.e.
writing a pull request, writing re-usable code, etc.)
4. Tohavefunmakingausefulapplication.
We want to also be explicit about what the goals aren’t:
1. Toteach,orassess,anycontentrelatedtonetworking.YoudonotneedanyknowledgeofTCP,IP,oranyother networking concepts. If something seems related to that, and you think you need to understand it, please ask on the forums.
2. ToimplementafullycompliantIRCserver–we’veaskedyoutoimplementaminimumnumberofcommandstoget something functional.
3. TounderstandthefullIRCprotocol.YouwillnotneedtoreadanythingfromtheIRCprotocoldirectly–we’vequoted any relevant sections here.
4. Toassessyourabilitytowritelargeamountsofuselesscruftsolelyforustomarkyouon.Whereyou’rewritingcode, we have a reason for it. Where you’re writing text, it’s because we want to genuinely understand your thinking.
What you will submit
At the end of this assignment, you will submit a tarfile containing:
One crate, containing an IRC server implementation.
Any other crates required for your implementation.
A completed copy of mark_request.txt containing a list of features that you’ve completed; how to run your code; and good/bad things about your code. This is basically a pull-request on GitHub; but in a text file.
Part 0: Getting Started
Starter Code
We have provided starter code for this assignment; which you can access by downloading this tar file. Particularly, the file types.rs contains structs to represent every message your IRC server will need to send or receive.
There are some unit tests in types.rs that you can run to help understand the types. You are not expected to write your own unit tests for this assignment, except for design excellence.
You can also run the following command to fetch the starter code:
$ 6991 fetch assignment 02 Networking Terminology
This assignment does not require any knowledge of networking, but just to ensure everyone is on the same page with basic terminology:
Client and Server: the two sides of any connection. Servers handle the logic of communicating between many clients. Clients only ever interact directly with a server. For example, your browser is a “client” that sends a request to the 6991 webpage “server”, which gives you a response (i.e. – this page!).
Address: a web address. Often in this course, it will be localhost, which indicates the web-address of the current computer.
Port: a number between 1000 and 65535. Since computers can have multiple programs running at once, a port number helps identify which program should receive a message. IRIS servers will normally be on port 6991. IRC clients could have any port number.
IRC is specified by multiple internet standards. In this course, we will only implement a subset of functionality described in RFC 1459. That said, you should not consult that document. If any details are unclear from this assignment, please message the forum and we will clarify.
The IRC protocol is a text-based protocol, with the simplest client being any socket program capable of connecting to the server.
The IRC protocol consists of Clients and Servers. In a real IRC setup, servers connect to other servers to relay messages between clients (hence the Relay in IRC), but our system will only support a single server.
Each client is distinguished from other clients by a unique nickname having a maximum length of nine (9) characters. In addition to the nickname, all servers must know the real name of the client who has connected.
Servers and clients send each other messages which may or may not generate a reply. If the message contains a valid command, as described in later sections, the client should expect a reply as specified but it is not advised to wait forever for the reply; client to server and server to server communication is essentially asynchronous in nature.
Each IRC message may consist of up to three main parts: the prefix (optional), the command, and the command parameters (of which there may be up to 15). The prefix, command, and all parameters are separated by one (or more) ASCII space character(s) (0x20).
The presence of a prefix is indicated with a single leading ASCII colon character (‘:’, 0x3b), which must be the first character of the message itself. There must be no gap (whitespace) between the colon and the prefix. The prefix is used by servers to indicate the origin of the message.
The command must either be a valid IRC command or a three (3) digit number represented in ASCII text.
IRC messages are always lines of characters terminated with a CR-LF (Carriage Return – Line Feed, or \r\n) pair, and these messages shall not exceed 512 characters in length, counting all characters including the trailing CR-LF. Thus, there are 510 characters maximum allowed for the command and its parameters.
Most of the messages sent to the server generate a reply of some sort. The most common reply is the numeric reply, used for both errors and normal replies. The numeric reply must be sent as one message consisting of the sender prefix, the three digit numeric, and the target of the reply. A numeric reply is just like a normal message, except that the keyword is made up of 3 numeric digits rather than a string of letters.
Because you are building a server, clearly you will need a Client. We are happy to provide two clients for you to use.
The first is a small rust program (ircat) which can be used to send arbitrary messages to a server. It doesn’t have any concept of the IRC protocol, but it will let you control exactly what gets sent to your server. You should use this for debugging, and sending the example messages shown below. To access this program, run:
6991 ircat [server_address] [port]
You will need to run ircat, and your server on the same computer.
This means if you are running on CSE machines, you will need to make sure both of your ssh sessions are running on the same machine. You can check this by running hostname in both sessions. If they are not the same, you will need to switch one of your terminial sessions to a different machine using ssh.
The port and server address are the same as the ones you used to start your server.
where port is some large number (e.g. 9999).
If you run the command hostname – it will tell you
We strongly encourage you to use ircat as inspiration for how to develop your server. You can access the source code for ircat here.
The second is sic (the suckless IRC client). This is a C program which is a small, but useful IRC client. It makes it easier to “simulate” a real connection, since you don’t need to think about getting the messages exactly right.
6991 sic -h [server_address] -p [port] -n [nickname]
sic is written in C, so its code will not be useful to you. That said, you can access its code here. To run sic, use the options below:
sic [-h host] [-p port] [-n nick]
Sic expects most lines of text you send will start with a colon. The lines below describe what lines of text you can write:
:j #channel Join a channel
:l #channel Leave a channel
:m #channel/user message
Send a message to channel or user
:s #channel/user
Set default channel or user
Any line beginning with : is sent as a command to the server.
Throws an error, unless a default channel has been set, in which case it sends the text as a message to the default channel.
You are more than welcome to use your own, preferred IRC client. Since they are built to the same standard, they should function very similarly. However, you should ensure that your server does in fact function with sic as well.
Reference Solution
The reference IRIS server is available at 6991 iris. Please note that IRIS servers are open to anyone on CSE’s systems. We do not take responsibility for servers students run themselves.
To run the reference solution, you may need to specify a port (as, if someone else is running the reference solution, you will not be able to run the reference solution on the default port). To do this, run:
$ 6991 iris 127.0.0.1 [port]
where port is some large number (e.g. 9999).
If you run the command hostname – it will tell you what CSE server you are on.
Make sure that when you run a client, it is on the same CSE server, and that you specify the same port.
Part 1: Single-Client Server (25% performance)
In this part you will build the simplest possible IRC server, which only sends and receives commands from a single client. You will implement the following commands:
USER/NICK PING/PONG
001 (RPL_WELCOME) QUIT
Each of the above dotpoints is worth 5% of your functional correctness mark.
Connection Registration/Establishment
To begin a connection, the NICK and USER commands must be sent, by the client, in order. Should messages not be sent in that order, messages should be ignored.
Future parts of the assignment will involve storing values from the NICK and USER commands. How you do that is up to you. There’s no ‘requirement’ to store things in a particular way, as long as it lets you solve the parts of the assignment. You are also guaranteed that once connections have been established, you will not receive any more NICK or USER messages.
Parameters Errors
NICK nickname
ERR_NONICKNAMEGIVEN ERR_ERRONEUSNICKNAME ERR_NICKCOLLISION
The NICK message is used to give user a nickname. Nicknames must be at most 9 characters long, not begin with a number, and can only include ascii letters or numbers. If the server receives an identical NICK from a client which is directly connected, it shall issue an ERR_NICKCOLLISION to the local client, and ignore the NICK command.
Parameters Errors
USER ignored ignored ignored :realname
ERR_NEEDMOREPARAMS
USER ignored ignored ignored :Ronnie Reagan
The USER message is used at the beginning of connection to specify the real name of a new user. It must be noted that realname parameter must be the last parameter, because it may contain space characters and must be prefixed with a colon (‘:’) to make sure this is recognised as such. This command is only implemented in IRIS because all IRC clients send this message. The ignored fields are fields that a real IRC server would expect for the USER command, but in our implementation, they will not be used, and have been replaced with ignored.
Once a connection has been established, your server should reply to “PING” messages with a “PONG”.
Parameters Errors
PING :hostname
ERR_NOORIGIN
PING :clientname
The PING command is used to test the presence of an active server at the other end of the connection. When a PING message is received, the appropriate PONG message MUST be sent as reply to the server.
PONG (server reply only)
Parameters
Errors Examples
PONG :hostname
PONG :clientname
PONG message is a reply to PING message. It should contain the same parameters as the PING message that caused it. This is only a reply from a server, users cannot use a PONG command.
Once a connection has been established, your server should also send a welcome message to the client.
RPL_WELCOME (server reply only)
Parameters
Errors Examples
:hostname 001 nickname :Greeting Message…
:iris-server 001 tfpk :Hi Thomas Kunc, welcome to IRC
Upon success, the client will receive an RPL_WELCOME message indicating that the connection is now registered and known the to the entire IRC network. The reply message MUST contain the full name of the client. This is only a reply from the server, a user cannot use the 001 command.
Parameters
Errors Examples
QUIT :message for quitting
QUIT :Dinner-time!
QUIT is used to leave the connection. When the server receives this message, it should close the connection to the client. The client will not receive any further messages from the server. As described in the JOIN message below, if the client was connected to a channel; all other users connected to that channel should be sent the QUIT message of the quitting user, including a message. If no message is provided by the user, you should send the user’s nickname as the message. You can assume that a QUIT message will always be sent before a connection is closed.
Heads up! Over part 1 and 2, you’ll be implementing the PRIVMSG command. What follows is a description of the PRIVMSG command, with notes on what you need to implement in part 1.
PRIVMSG (sent to server)
Parameters Errors
PRIVMSG target :MSG
ERR_NORECIPIENT ERR_NOTEXTTOSEND ERR_NOSUCHNICK ERR_NOSUCHCHANNEL
PRIVMSG Zac :Lets give everyone full marks.
PRIVMSG Tom :Agreed, full marks for everyone!
PRIVMSG Zac :Want to grab ice cream before the workshop?
PRIVMSG is used to send private messages back to yourself, between users, as well as to send messages to channels. “target” is used to figure out who to send messages to. There are two options for targets.
If a nickname is the target, a message will just be sent to that person. If the target starts with a hash (#), then it will be sent to anyone in that channel.
Successful PRIVMSG messages are never acknowledged. The user who sent it must assume the message was sent successfully, unless their nick is also listed as the target, in which case they should receive the message.
If no recipient is specified, send back a “NORECIPIENT”. If a recipient is specified, but there is no text, send back “NOTEXTOTSEND”. If the user targets a channel, but the channel does not exist or is invalid, reply “NOSUCHCHANNEL”. Otherwise if the user’s target does not exist or is invalid, reply “NOSUCHNICK”.
In part 1, you only need to implement the ability to send messages to yourself. In sic (the IRC client), this will appear as two identical messages.
In part 2, if the user is not a part of the channel but the channel does exist, you may allow the user to send messages to the channel. (Or not, we won’t test this either way.)
PRIVMSG (sent to client)
Parameters
Errors Examples
:nickname PRIVMSG target :message
:tom PRIVMSG Zac :Lets give everyone full marks.
:zac PRIVMSG Tom :Agreed, full marks for everyone!
:shrey PRIVMSG Zac :Want to grab ice cream before the workshop?
The server should forward a PRIVMSG to it’s intended target, adding a prefix to indicate the sender. DESIGN EXCELLENCE:
Rust has crates which make logging easier and more readable. Find one that you like, and use it to improve the output of your server.
Write a suite of tests for your code that increases your confidence it works as expected.
Part 2: Multi-Client Server (50% performance)
In this part, you will make modifications to your server to support multiple users. You will implement:
More than one user joining the server. PRIVMSG to other users.
PRIVMSG to channels
Each of the above dotpoints is worth 10% of your functional correctness mark.
A very important design constraint applies in this assignment: Your server must not store user data any longer than necessary. This means you may not store messages indefinitely; nor may you store nicknames after they have left the server. Failure to follow this constraint will lead to a significant mark penalty.
Multiple Users
Your program should support more than one user connecting to the same server. PRIVMSG should support sending messages to other users on the channel.
Parameters Errors
ERR_NEEDMOREPARAMS ERR_NOSUCHCHANNEL
JOIN #haku
:tfpk JOIN #haku // This is sent to everyone else who is already in
the channel.
The JOIN command is used by a user to request to start listening to the specific channel. Once a user has joined a channel, they should receive information about all commands the server receives affecting the channel. This includes JOIN, PART, QUIT, and of course PRIVMSG. This allows channel members to keep track of the other channel members.
The NOSUCHCHANNEL error name is a bit misleading here: if a client attempts to join a channel with an invalid name (e.g. doesn’t start with ‘#’), then you should return NOSUCHCHANNEL. However, joining a valid channel name that doesn’t exist yet should create said channel, add the client to said channel, and return successfully.
If a client attempts to join a channel while they are already joined, you can handle this behaviour however you like — we won’t test this.
Parameters Errors
PART #channel
ERR_NEEDMOREPARAMS ERR_NOSUCHCHANNEL
PART #haku
:tfpk PART #haku // This is sent to everyone else who is already in
the channel.
The PART message causes the client sending the message to be removed from the list of active users of a channel.
If the client is not in the active list of users of the channel, or if the channel does not exist, return NOSUCHCHANNEL.
Part 3: Plugins (25% performance)
In this last main part of the assignment; you will refactor your program to support “plugins”. You can choose to design plugins however you would like, but your guiding design principle should be: your plugin system should be easy to use for someone who knows basic terminal commands; has cargo installed on their system; but does not know any Rust. It should also be easy for someone familiar with Rust to implement their own plugin; without modifying your code.
In this case, “without modifying your code” can be interpreted as not having to read and/or modify application logic code. For example, having the user add a predictable line of code to a short, stubbed-out plugins.rs file is acceptable – but if the user has to make changes elsewhere in the codebase to support this, or if the configuration is buried at an unpredictable point in the codebase, then this would require the user to have an understanding of how to read and/or write code in order to configure which plugins are enabled.
You will need to build two plugins:
A reminder system — a user tells the plugin that they want to remind a user about something in a specified number of seconds. Worth 15% of your final mark.
An example plugin — a well documented, minimal example that a developer could use to make their own plugin. This might be as simple as a plugin which replies to a specific message with a specified reply, or a plugin which replies to messages with the number of times it has been invoked.
But your system should be extensible to other commands.
DESIGN EXCELLENCE:
Allow plugins to be configured without touching the codebase at all, by configuring the plugins in an external configuration file that is read at runtime. This can be achieved by:
Having the server launch plugins as external processes, or
(NOT TAUGHT IN THIS COURSE) Use WASM to dynamically load and call plugins.
Part 4: Submit a Mark Request
When building modern software, you are expected to send in a pull request, explaining what you’ve done. In COMP6991, you must submit a “mark request”. This is contained in mark_request.txt.
The mark request helps us mark you — we will use it to help us find out what to mark. It is not meant to take more than 10 minutes to write. No marks are awarded for the mark request specifically; but if it is very inaccurate, we reserve the right to either request you resubmit it with a penalty; or mark using it as a basis (and therefore not mark things you’ve done).
Error Codes and Error Handling
You do not need to handle commands that requre connection registration/establishment.
E.G – The PING command requires a connection established via USER/NICK. Calling PING before said establishment is not something you need to handle.
No Such Nickname
A nickname cannot be found.
No Such Channel
A channel’s name is invalid, or the client was not part of the channel.
a PING command does not contain an argument.
No Recipient
A PRIVMSG command did not include the destination.
No Text To Send
A PRIVMSG command did not include a message.
Unknown Command
A command was not recognised.
No Nickname Given
A nickname parameter expected for a command and isn’t found.
Erroneous Nickname
A NICK message which is not valid (i.e. bad length or character set).
Need More Parameters
Returned by the server by numerous commands to indicate to the client that it didn’t supply enough parameters. Should only be used if no other error better explains the problem.
Other Information
Submission
See the instructions down the bottom of the page.
Using Other Crates
We are happy for you to use any crate that has been published on crates.io under four conditions:
You may not use any crates which were designed to work with IRC clients or servers.
The crate must not have been authored by anyone else in the course.
The crate must have at least 1000 downloads, excluding the last 30 days.
The crate must not impose license restrictions which require you to share your own code.
If you are in doubt (or think these restrictions unfairly constrain you from using a reasonable crate), ask on the course forum.
Marking Scheme
There are 3 things on which you will be marked:
Mechanical Style (10%) Functional Correctness (40%) Idiomatic Design (50%)
You can see how the marks break down here:
1. Mechanical Style (10%):
We will look at your crates, and make sure they:
Compile, with no warnings or errors. Raise no issues with 6991 cargo clippy Are formatted with rustfmt
Have any tests written for them pass
If they do all of the above, you get full. Otherwise, we will award partial marks. This is meant to be the “easy marks” of programming.
2. Functional Correctness (40%):
Your code should do what we describe. We will run the code through some obvious tests to make sure it behaves as we expect. For example, we will likely do the following:
Trying to start your program.
Testing out the commands listed above.
Testing out some simple error cases of the above commands (messages without targets, for example).
The marks available of each section of the assignment is shown next to the title of the section above.
Your functional correctness mark will be capped at 25% if only one client can connect at a time.
Your functional correctness mark will be capped at 75% if you do not implement support for plugins.
Your functional correctness mark will be capped at 100% if you implement support for plugins, and multiple clients can connect at a time.
3. Idiomatic Design (50%):
Your code should be well designed. This is where we will spend most of our time when marking. To help you, we have provided “design excellence” suggestions, which are ideas to make your design really excellent. You don’t have to do them, but they would be good ways of getting a great design.
The following list of properties will be marked in your program:
Code is abstracted appropriately.
Types are used appropriately to express data in the program.
The design does not impose unnecessary constraints on either the caller or callee through borrowing, lifetimes or ownership.
Uses traits sensibly to add expressiveness and avoid unnecessary code.
Data structures used are appropriate to store data.
Functions perform error handling; cases that are expected do not panic.
Code is sensibly organised, and split into appropriate modules.
Concurrency primitives should be used appropriately. Locks should not be held too long, but assumptions should not be made about the state of shared resources outside a locked section.
Documentation, where provided, is correct and readable.
(for plugins) appropriate documentation of how to create a plugin is provided.
(optional) Uses external crates effectively to achieve the above goals.
(optional) Where code is designed in a sub-optimal way, comments about how to improve it are made under “Design Limitations”.
If you have only completed part 1, then only 25% of the marks for this section will be available. If you have only completed part 2, then only 75% of the marks for this section will be available.
Your mark will be calculated based on the feedback you have received:
100% of Very little negative feedback is given on the above criteria; and at least one design excellence
available suggestions are implemented (or your own ideas which we consider equivalently excellent).
程序代写 CS代考 加QQ: 749389476
85% of available marks
65% of available marks
below 50% of available marks
Some minor comments are made about some of the above criteria. Above this mark, at least one design excellence feature was implemented (or your own idea is considered equivalently excellent).
Major comments are made about three or more criteria.
Assignments in this category are likely written as “translations from C”, and ignore many Rust features and design patterns.
75% of Major comments are made about one or two criteria, with multiple small comments in different areas. available
50% of Many areas have major comments made. available
Note that the following penalties apply to your total mark for plagiarism:
0 for the Submitting any other persons work. This includes joint work. assignment
On the forums, we were asked what constituted “good” error handling. Basically, the way we see it is that there are three “levels” to how we’ll mark error handling.
Level 1: Using panics is explicitly bad design, except where it’s obvious that you can manually verify the program will never crash. We would mark you down for using them, for breaking the guideline that functions perform error handling; cases that are expected do not panic.”
Level 2: Returning a Box could be fine design, if the expected outcome is just that you’ll ignore those errors; take some action no matter what the error is; or that you’ll bubble up the error and just print out what it is. If you rely on what the error was, then you should encode that explicitly in the type system. If you don’t, we’d comment under the guideline that “Types are used appropriately to express data in the program.”
Level 3: explicitly making types for all your errors, or even using external libraries that make types for your errors easier (a good example is the anyhow library) is excellent design, and would be rewarded under “design excellence” or “using crates”.
Formal Stuff
Assignment Conditions
Joint work is not permitted on this assignment. This is an individual assignment.
The work you submit must be entirely your own work. Submission of any work even partly written by any other person is not permitted.
The only exception being if you use small amounts (< 10 lines) of general purpose code (not specific to the assignment) obtained from a site such as Stack Overflow or other publicly available resources. You should attribute the source of this code clearly in an accompanying comment. Assignment submissions will be examined, both automatically and manually for work written by others. Do not request help from anyone other than the teaching staff of COMP6991. Do not post your assignment code to the course forum. Rationale: this assignment is an individual piece of work. It is designed to develop the skills needed to produce an entire working program. Using code written by or taken from other people will stop you learning these skills. The use of code-synthesis tools is permitted on this assignment, however beware -- the code it creates can be subtly broken or introduce design flaws. It is your job to figure out what code is good. Rationale: this assignment is intended to mimic the real world. These tools are available in the real world. Sharing, publishing, distributing your assignment work is not permitted. Do not provide or show your assignment work to any other person, other than the teaching staff of COMP6991. For example, do not share your work with friends. Do not publish your assignment code via the internet. For example, do not place your assignment in a public GitHub repository. You can publish Workshops or Labs (after they are due), but assignments are large investments for the course and worth a significant amount; so publishing them makes it harder for us and tempts future students. Rationale: by publishing or sharing your work you are facilitating other students to use your work, which is not permitted. If they submit your work, you may become involved in an academic integrity investigation. Sharing, publishing, distributing your assignment work after the completion of COMP6991 is not permitted. For example, do not place your assignment in a public GitHub repository after COMP6991 is over. Rationale:COMP6991 sometimes reuses assignment themes, using similar concepts and content. If students in future terms can find your code and use it, which is not permitted, you may become involved in an academic integrity investigation. Violation of the above conditions may result in an academic integrity investigation with possible penalties, up to and including a mark of 0 in COMP6991 and exclusion from UNSW. Relevant scholarship authorities will be informed if students holding scholarships are involved in an incident of plagiarism or other misconduct. If you knowingly provide or show your assignment work to another person for any reason, and work derived from it is submit