Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Asynchronous IO within ISAPI Modules

0.00/5 (No votes)
3 May 2000 1  
How to use asynchronous IO to send data from an ISAPI module

Introduction

Asynchronous IO under ISAPI is often viewed as something of a black art. But it's actually quite straight forward and it will yield the highest level of performance and scalability for your application.

A Project to Demonstrate Asynchronous IO

Browsing the Code Project site, I stumbled across an example ISAPI project by Jorge Lodos Vigil which demonstrated sending back a page of HTML and an image. Two different types of data are returned by Jorges' ISAPI. The page is contained in an in-memory buffer while image is contained in a file on disk. Sending a buffer of data to a client and sending a file to a client just happens to encompass the two possible ways to send data asynchronously using the ISAPI API - WriteClient and TransmitFile.

ImageServer Project

The ImageServer ISAPI extension essentially brokers requests for images from some hidden directory. ImageServer satisfies those requests by returning a page of HTML containing an IMG element that has, as its source, the ImageServer extension. The source URL is specially formatted to let ImageServer know that it should send back the actual image instead of a containing page.

Two Ways to Perform Asynchronous IO

Within the context of an ISAPI module, there are two ways to receive or send data asynchronously. You can use ReadClient or WriteClient to read/write an arbitrary buffer of data to the client asynchronously or you can use TransmitFile to send a file to a client asynchronously. TransmitFile is a Win32 function which is accessed by using the ISAPI function ServerSupportFunction and specifying the HSE_REQ_TRANSMIT_FILE option.

The MSDN online library provides a good overview of asynchronous IO but in general, you will need to perform these steps:

  • Setup a callback through which you will be notified when an IO completion event occurs.
  • Start the asynchronous IO.
  • Return HSE_STATUS_PENDING from the HttpExtensionProc.
  • When IO completes, cleanup any context information and notify IIS you're done with this session.

There's really only one other thing to keep in mind about asynchronous IO. That is, whatever data is being sent to the client must survive until a completion notification is received. Which means, it's almost always going to be placed on the heap.

This last requirement usually entails the most grief from a design standpoint. The extreme levels of performance and reliability required from ISAPI extensions precludes a design that constantly accesses the heap. Limiting access to the heap is often accomplished by implementing pools of buffer objects that are re-used.

ImageServers requirements are not as stringent. When ImageServer needs a buffer, or transmission context, it simply creates it on the heap. Likewise, when it's finished with a buffer, it just destroys it. Although creating a protected buffer pool is not difficult, it would distract from the central purpose of ImageServer - which is to demonstrate basic asynchronous IO.

Tour of the Code

The code is simple and heavily commented so it should be easy to understand. Here are the highlights of what you'll find.

  • There is one main class CImageServer which encapsulates all the functionality required for this application. This class is declared in Server.h and implemented in Server.cpp.
  • A single static instance of CImageServer resides in ImageServer.cpp. Also in this file are the main entry points for the ISAPI DLL - DllMain, GetExtensionVersion, TerminateExtension and HttpExtensionProc. They are all basic boiler plate code except HttpExtensionProc which delegates its behavior CImageServer::ServiceRequest
  • There are two other classes which serve as transmission contexts for the asynchronous IO calls. The first is CFilePacket which is a context for TransmitFile. The second is tWriteClientPacket, which is actually a structure not a class. It serves as a context for, you guessed it, WriteClient. Both CFilePacket and tWriteClientPacket are declared as nested classes/structures inside the declaration of CImageServer. There was no real need for this but it makes the code a little cleaner as those classes are only used inside the functions of CImageServer.

Understanding how CImageServer works is best accomplished by reading the source. Everything starts with CImageServer::ServiceRequest and the comments will guide you from there.

Setup

As with any ISAPI module, you'll have to locate the DLL in some path your web server has access too - with execute permissions. You'll also need a directory containing images that matches whatever you've hard coded into CImageServer::GetImageDirectory.


About the Author

The company I work for, Financial Insight Systems Inc., specializes in creating high performance internet applications using Microsoft Back Office products. I have a MCSD, with certifications in Visual C++ and SQL Server, and for the last five years, most of my time has been spent developing ISAPI modules and Winsock based client/server solutions. Suggestions and comments are welcome.

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here