My favorite APIs: TransmitFile

Back in NT 3.5ish, Microsoft first deployed IIS, our web server.  The people working on it very quickly realized that the server wasn’t up to snuff performance-wise.

A bit of profiling and they realized the problem – the application was doing:

            CreateFileEx(inputFile);
while (!eof(inputFile))
{
    ReadFile(inputFile, &inputBuffer);
    WriteFile(socket, inputBuffer);
}

The problem was the transfer through inputBuffer.  The file was in the cache in the kernel (from the read file), but the data had to be transferred from the cache, into the user mode inputBuffer, then back into the kernel to the in-kernel TCP buffer.  All those copies were making the web server CPU bound.

Needless to say, this wasn’t a good situation, so for NT 3.51, a new system call was added: TransmitFile.  TransmitFile was tailored for the web server, because it allowed the user to specify a set of user buffers that were to be prepended and appended to the file before and after the transfer.  So a web server could put the HTTP response headers in the prepend portion, and any trailing data needed in the append portion.

It turns out that TransmitFile was absolutely perfect for Exchange, because we were able to take advantage of it for both our POP3 and IMAP servers – we set the prepend portion to the +OK response for POP3, and the append portion to “<crlf>.<crlf>” for POP3 for example.

Now TransmitFile can be tricky to use – you need to lock the TCP/IP connection before and afterwards – if you attempt to send data on the connection before the TransmitFile completes, the results are “undefined” – it might work, you might get the data interleaved with the file contents.