10 Jan 1997

NSAPI

Efficiency

In Unix and Windows NT, every executable program (every ".exe") runs as a separate process. All the storage that the program uses, all the files that it opens, all its network sessions and database transactions are tracked by the system. When the process ends, usually because the program exits, the system can free the storage, close the files, terminate the sessions, and backout any incomplete transactions. Creating and deleting processes involves lots of system overhead.

Modern Web servers maintain a pool of worker processes. New requests are assigned to an idle worker. When the response has been generated, the worker puts itself back in the pool for reassignment. After handling a certain number of requests (typically between 32 and 128 requests), the worker process exits and the system free sup any storage, files, or other resources that were left allocated by any program errors. The master process in the Server then creates a new worker process to handle a new block of requests.

Most operating systems today provide an alternative called a thread. The thread provides independent execution, but it does not isolate storage and other resources. By default, a Netscape 1.x Unix Web Server created a pool of 16 worker processes. A Netscape 2.x Unix Web Server, in contrast, creates a pool of four worker processes each of which starts four threads. In either case the server can handle 16 concurrent requests. In the second design, however, four requests are handled within a common process where they share storage, file handles, and database resources.

Normally a Unix process stops executing while I/O is active to disk or to a network session. When threads are uses, only the thread making the I/O request has to stop. Other threads can continue to service other requests, making their own independent network or disk requests.

Threads were specifically omitted from the original Unix design. By the time that NT was being developed, it had become clear that any network server needs threads for maximum efficiency. Therefore, threads are a standard feature of NT, but a late addition to most Unix systems.

Netscape is committed to a universal system that runs on NT and all versions of Unix. It has to use threads for NT, but it cannot count on native thread support on the Unix side. To accommodate this, Netscape runs a subroutine package that simulates standard thread services on most of its Unix servers. This presents two problems.

Such restrictions make the NSAPI environment extremely hostile for ordinary application programming. It is unlikely that anyone but the most sophisticated system programmer can navigate through all the limitations, restrictions, and constraints needed to code an NSAPI program properly. Therefore, NSAPI is more likely to be used by software vendors who use it to connect their products to the Netscape server rather than by customers who use it for application programming.

Coding an Application Using NSAPI

As the name suggests, the Netscape Application Programming Interface (NSAPI) is a collection of header files and functions that are used to program server extensions. Windows has one set of system services (WIN32) while Unix provides a separate set of functions to perform the same operations. NSAPI is intended to provide a single common set of services that work the same on all systems.

On all systems, a C program can dynamically allocate storage using the malloc() function. If a program forgets to free this storage explicitly, then it will be freed automatically when the process ends. However, when the process is reused over and over for multiple requests, the storage could remain allocated for some time. So NSAPI provides the "MALLOC()" macro. MALLOC allocates memory just like the standard malloc() function, but it keeps track of the allocated storage in control blocks related to the current Web request. After the final response is sent to the remote Browser, Netscape automatically frees any storage allocated by the MALLOC macro during the processing of the request.

NSAPI provides its own functions for standard services, like file and network I/O. These functions work within the dummy threading used on some Unix systems. If a program used standard file I/O or socket functions, then a request might block all threads in the process until it completes.

If NSAPI provides its own version of a standard C function, you should use it. For example, Netscape provides a function named "util_itoa()" that provides the same services as the conventional "itoa()" library routine. If you try to use the standard routine, your program will fail on some Unix systems.

An NSAPI routine is written as a C function with a particular set of arguments:

NSAPI_PUBLIC int example(pblock *pb, Session *sn, Request *rq)

The ns-home/nsapi/include directory tree contains header files that define the NSAPI_PUBLIC prefix, the pblock and other structures, and the NSAPI functions supplied by Netscape. You need to study the NSAPI documentation and the example in ns-home/nsapi/examples to learn how to use them.

NSAPI functions can be called when the Netscape Server is initializing, and when it is processing a new request. They can resolve URLs or perform access control checks. However, if you plan to use this interface for an application program, as a more efficient alternative to CGI, then you will probably as that the function be called at the last step in the Service phase of the request.

The Netscape Server has stored all the information from the URL, request headers, and network session in "pblock" structures. The functions that Netscape provides through the NSAPI interface can locate any of this information and can set other parameters that determine the code and header information returned as the response. For example:

method=pblock_findval("method", rq->reqpb);
clientip = pblock_findval("ip",sn->client);
request_header("user-agent",&browser, sn, rq);
request_header("cookie",&cookies, sn, rq);

This sequence locates the method ("GET" or "POST"), the IP address of the client browser, the type of browser from the request header, and the so-called "cookie" data presented by the Browser with the request.

After the request has been examined, if the C function is now committed to send back a data response it might generate a sequence of the form:

param_free(pblock_remove("content-type", rq->srvhdrs));
pblock_nvinsert("content-type", "text/html", rq->srvhdrs);
pblock_nvinsert("set-cookie", "chocolate=chip;", rq->srvhdrs);
protocol_status(sn, rq, PROTOCOL_OK, NULL);
protocol_start_response(sn, rq);

The first function removes any default data type, and the second one indicates that the response will be HTML data. The third statement sets up "cookie" data that the browser will echo back the next time it calls this application. A "200 OK" status is then indicated and the status and any queued header lines are generated and sent back to the Browser over the network connection. After you send the status and header lines, the NSAPI routine then sends the HTML text of the rest of the response by calling the net_write() function one or more times.

Building the Application

An NSAPI application must be linked as a shared library module. In Windows, this is a DLL. In Unix, it is generally a file with the *.so extension. The particular options needed to build the shared library module depend on the operating system and the version of the Netscape Server in use. The trick is to look at ns-home/nsapi/examples/Makefile to see how Netscape builds its sample NSAPI routine. Then create your own Makefile using the same options.

In Windows, one can define a Visual C++ project to generate the DLL containing the NSAPI code. There are some preprocessor symbols to define, and the Netscape libhttpd.lib library must be included in the link phase. Windows provides the simplest debugging environment, because the httpd.exe routine can be run by Visual C++ to call the DLL under the debugger.

Once the DLL or shared library is built, the Netscape server must be configured to load and call it. First, add Init statements to the ns-home/httpd-hostname/config/obj.conf file.

Init fn="load-modules" shlib="f:/myapp/something.dll" funcs="myrequest,myinit"
Init fn="myinit"

The shlib parameter here has a Windows NT path. There would not be a disk letter in Unix. The first statement loads SOMETHING.DLL and indicates that it has two NSAPI_PUBLIC functions named myrquest() and myinit(). Netscape adds these names to a global table of functions, so in real life use more original names that are sure to be unique. The second statement calls the myinit() function to perform initialization needed during server startup.

Another statement will be added later in the obj.conf file to call the myrequest() function at some point during the processing of requests. There are several strategies about how this function will be configured, so no specific example is provided here.

Continue Back PCLT

Copyright 1996 PC Lube and Tune -- Distributed Applications and the Web H. Gilbert