Machine Problem 3: A Concurrent MTA
Out: Wednesday, February 13, 2008
Due: Friday, February 29, 2008
Note: I think this ought to be a one-week
problem. But depending on how you coded MP2, you might be in a corner
where it will take you more than one week's worth of work to do this.
Preliminaries
In this problem you're extending the functionality of the simple Mail
Transfer Agent (MTA) you wrote for the preceding machine problem. In
particular, you're going to write a server that can
processes multiple messages concurrently. By concurrently, I mean
that, if your MTA is waiting for some additional information from one
client, it should be able to process requests from additional
clients. In particular, your server should be able to successfully
receive and forward a mail message from one client while receiving a
message from another. Further, your MTA should support concurrent
forwarding. Namely, if a message has multiple recipients, the lack of
response from one destination should not delay the delivery of the
message to the others. Finally, you should be able to receive
additional messages from the same client even before the previous one
has been forwarded. Note this may lead to out-of-order forwarding of
messages in many cases.
Specifications
Before beginning, read RFC 2821
and RFC 2822,
which document the Simple Mail Transfer Protocol (SMTP) and the
Internet Message Format.
General Requirements
The requirements are as before. Changes are in italic.
Your MTA must perform the following general functions:
- It will accept mail addressed to any user on its own
machine.
- It will forward email messages on to another MTA for delivery.
The other MTA may be the one at amber.ccs.neu.edu
or the MTA at one of your classmates' machines
(129.10.112.*).
- When the MTA accepts a TCP connection, it will spawn a new
thread or process to handle that connection. You may have a
reasonable limit on the number of concurrent connections open at one
time.
You are responsible for the following requirements:
- Your MTA must support the following SMTP commands: HELO, MAIL,
DATA, RCPT, QUIT, and RSET. You neet not
support any other commands, but you MTA should respond to them
with a legal SMTP error code.
- Your MTA must be able to properly receive multiple, simultaneous messages from
well-behaved MUAs like Outlook Express, Thunderbird, or Eudora.
It should properly lock the mail files so that
multiple concurrent messages to the same recipient are spooled
correctly.
- Your MTA must fill in any missing headers
that are required by RFC 2822, add a Message-Id header if it's
missing, and add a Received: header. If this is not
possible, then your MTA should reject the message with an
appropriate reply code. (This is a
clarification of the requirement on MP2).
- You must support the use of dotted-quad IP addresses (RFC 2822
domain literals) instead of domain names in both the HELO, MAIL,
and RCPT commands. In particular, you should be able to send mail
to name@[129.10.112.xxx] or the like.
- Your MTA should deliver each message to
every specified recipient if possible. If an error occurs, and it is
possible for your MTA to continue processing additional messages, it
should do so. If it encounters an unrecoverable error, i.e., socket(),
bind(), or listen() fails, it should print an error message and call
exit(1). (If you use a language other than C, interpret this
requirement in terms of the system call bindings in your language.)
If message delivery for any particular recipient fails at
the appropriate mail exchanger (ie, 192.10.112.xxx for messages
addressed there, or amber.ccs.neu.edu otherwise), the message should
be queued for an additional attempt. The amount of time to wait before
attempting a second delivery should be specified on the command
line. If, after two attempts at every listed mail exchanger, the
message cannot be delivered to a particular recipient, an
"undeliverable mail" message should be generated.
-
You may not use
the fork() system call, or its equivalent in whatever programming
language you use.
- You do not need to handle messages with more than 255
recipients. (And don't try this, either! Amber has enough work to do
without all you guys flooding it with messages.)
- You do not need to handle mail messages larger than 65535
bytes.
Non-Requirements
You do not need to bother with the following things. You should just
ignore them as best you can.
- If the argument to the RCPT TO: command is not of the form
user@domain.name (where domain.name could also be something more
complicated, like foo.bar.baz.edu or a dotted-quad IP address
like [129.10.112.xxx]), you should refuse to accept the
message.
You don't need to queue messages that
cannot be delivered. Any destination address that is unable to
accept the message immediately should be treated as a delivery
failure, and an "undeliverable mail" notification should be
returned to the sender immediately. (Now you do have to
do something, see above). Test this by sending mail to some
nonexistent address at ccs.neu.edu.
- You don't need to handle any other SMTP commands like EXPN, VRFY,
HELP, ETRN, NOOP, or VERB. You may simply return an error message if
your MTA receives one of these commands.
- You do not need to handle ESMTP extensions. You do not need to
recognize EHLO or any of the additional parameters to standard SMTP
commands.
- You do not need to implement the data transparency procedure
described in Section 4.5.2 of the RFC. Basically, you can assume your
MTA will never receive a message with a period as the first character of a
line.
- You do not need to implement any sort of loop detection.
Testing
- (5 points) Create a testing framework that can send out a
bunch of messages to your MTA in an automated fashion. For example,
you could modify your original MTA so that it can take its input
from a file full of mail messages, rather than from a port. Other
implementations are possible. For convenience, let's call this a
"mail gun". Note that the mail gun should send all the mail to your
MTA, regardless of the recipients listed in the messages.
- (5 points) Test the message-queueing properties of your
MTA, by sending some messages to a non-operating MTA. (You should
have no trouble finding one of those!)
- (10 points) Install your mail gun on at least two of your
machines (the more the merrier!), and test the concurrency
properties of your MTA by having them all fire at your MTA
simultaneously. Keep a log of your MTA's actions so that you
can confirm that multiple threads or processes are working
concurrently. Make sure the log includes instances of multiple
messages for a single local recipient arriving
concurrently.
- (5 points) List as part of your documentation the major
potential race conditions in your code, and explain how you
eliminated them.
Turnin procedure
We will be building and testing your submission. You can assume that
we have the following tools: build-essential, sun-java6-jdk,
mono-gmcs, ocaml-nox, scheme, and ghc-6.8.2. If your submission
requires any other tools, you should list them in your README or
INSTALLATION files, and include information on where to download and
how to install them.
Your deliverables should include a description of your program and its
parts, and a description of what header processing (and other
processing) you do.
Attribution: If you got portions of your program
from external libraries (on the internet or wherever), tell us what
they are and where you got them. Otherwise we will assume that you
wrote every line yourself, and nasty things will happen if that turns
out to be false.
Submit your package as a gzipped tar file. You can build this by
doing something like
mkdir mp3
cp {all files} mp3
tar cvf mp3.tar mp3
gzip mp3.tar
mv mp3.tar.gz yourname-mp3.tar.gz
Send yourname-mp2.tar.gz to xindong@ccs.neu.edu.