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:

  1. It will accept mail addressed to any user on its own machine.
  2. 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.*).
  3. 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:

  1. 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.
  2. 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.
  3. 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).
  4. 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.
  5. 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.

  6. You may not use the fork() system call, or its equivalent in whatever programming language you use.
  7. 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.)
  8. 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.
  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. You do not need to implement any sort of loop detection.

Testing

  1. (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.
  2. (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!)
  3. (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.
  4. (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.