Sun Java System Web Server 6.1 SP12 NSAPI Programmer's Guide

Quality of Service Example

The code for the qos-handler (AuthTrans) and qos-error (Error) SAFs is provided as an example in case you want to define your own SAFs for quality of service handling.

For more information about predefined SAFs, see the Sun Java System Web Server 6.1 SP12 Administrator’s Configuration File Reference.

Installing the Example

Inside the default object in obj.conf, add the following AuthTrans and Error directives:

AuthTrans fn=qos-handler
...
Error fn=qos-error code=503

Source Code

The source code for this example is in the qos.c file in the plugins/nsapi/examples subdirectory of the server root directory.

#include "nspr.h"
#include "base/pblock.h"
#include "frame/log.h"
#include "frame/http.h"

/*-----------------------------------------------------------------
 decode : internal function used for parsing of QOS values in pblock
-------------------------------------------------------------------

void decode(const char* val, PRInt32* var, pblock* pb)
{
    char* pbval;
    if ( (!var) || (!val) || (!pb) )
         return;
    pbval = pblock_findval(val, pb);
    if (!pbval)
        return;

     *var = atoi(pbval);
}

/*----------------------------------------------------------------
 qos_error_sample

 This function is meant to be an error handler for an HTTP 503 error
 code, which is returned by qos_handler when QOS limits are exceeded
 and enforced.

 This sample function just prints out a message about which
 limits were exceeded.
------------------------------------------------------------------

NSAPI_PUBLIC int qos_error_sample(pblock *pb, Session *sn, Request *rq)
{
    char error[1024] = "";
    char* err_header = "<HTML><HEAD><TITLE>Unable to service request
		 </TITLE></HEAD><BODY>";
    char* err_footer = "</BODY></HTML>";

    PRBool ours = PR_FALSE;

    PRInt32 vs_bw = 0, vs_bwlim = 0, vs_bw_ef = 0,
            vs_conn = 0, vs_connlim = 0, vs_conn_ef = 0,
            vsc_bw = 0, vsc_bwlim = 0, vsc_bw_ef = 0,
            vsc_conn = 0, vsc_connlim = 0, vsc_conn_ef = 0,
            srv_bw = 0, srv_bwlim = 0, srv_bw_ef = 0,
            srv_conn = 0, srv_connlim = 0, srv_conn_ef = 0;

    pblock* apb = rq->vars;

    decode("vs_bandwidth", &vs_bw, apb);
    decode("vs_connections", &vs_conn, apb);

    decode("vs_bandwidth_limit", &vs_bwlim, apb);
    decode("vs_bandwidth_enforced", &vs_bw_ef, apb);

    decode("vs_connections_limit", &vs_connlim, apb);
    decode("vs_connections_enforced", &vs_conn_ef, apb);

    decode("vsclass_bandwidth", &vsc_bw, apb);
    decode("vsclass_connections", &vsc_conn, apb);

    decode("vsclass_bandwidth_limit", &vsc_bwlim, apb);
    decode("vsclass_bandwidth_enforced", &vsc_bw_ef, apb);

    decode("vsclass_connections_limit", &vsc_connlim, apb);
    decode("vsclass_connections_enforced", &vsc_conn_ef, apb);

    decode("server_bandwidth", &srv_bw, apb);
    decode("server_connections", &srv_conn, apb);

    decode("server_bandwidth_limit", &srv_bwlim, apb);
    decode("server_bandwidth_enforced", &srv_bw_ef, apb);

    decode("server_connections_limit", &srv_connlim, apb);
    decode("server_connections_enforced", &srv_conn_ef, apb);

    if ((vs_bwlim) && (vs_bw>vs_bwlim))
    {
        /* VS bandwidth limit was exceeded, display it */
        ours = PR_TRUE;
        sprintf(error, "<P>Virtual server bandwidth limit of %d . 
			  Current VS bandwidth : %d . <P>",
              vs_bwlim, vs_bw);
    };

    if ((vs_connlim) && (vs_conn>vs_connlim))
    {
        /* VS connection limit was exceeded, display it */
        ours = PR_TRUE;
        sprintf(error, "<P>Virtual server connection limit of %d . 
			  Current VS connections : %d . <P>",
              vs_connlim, vs_conn);
    };

    if ((vsc_bwlim) && (vsc_bw>vsc_bwlim))
    {
        /* VSCLASS bandwidth limit was exceeded, display it */
        ours = PR_TRUE;
        sprintf(error, "<P>Virtual server class bandwidth limit of %d . 
			  Current VSCLASS bandwidth : %d . <P>",
              vsc_bwlim, vsc_bw);
    };

    if ((vsc_connlim) && (vsc_conn>vsc_connlim))
    {
        /* VSCLASS connection limit was exceeded, display it */
        ours = PR_TRUE;
        sprintf(error, "<P>Virtual server class connection limit of %d . 
			  Current VSCLASS connections : %d . <P>",
              vsc_connlim, vsc_conn);
    };

    if ((srv_bwlim) && (srv_bw>srv_bwlim))
    {
        /* SERVER bandwidth limit was exceeded, display it */
        ours = PR_TRUE;
        sprintf(error, "<P>Global bandwidth limit of %d . 
				Current bandwidth : %d . <P>",
              srv_bwlim, srv_bw);
    };

    if ((srv_connlim) && (srv_conn>srv_connlim))
    {
        /* SERVER connection limit was exceeded, display it */
        ours = PR_TRUE;
        sprintf(error, "<P>Global connection limit of %d . 
				Current connections : %d . <P>",
              srv_connlim, srv_conn);
    };

    if (ours)
    {
        /* this was really a QOS failure, therefore send the error page */
        pb_param *pp = pblock_remove ("content-type", rq->srvhdrs);

        if (pp != NULL)
        param_free (pp);

        pblock_nvinsert ("content-type", "text/html", rq->srvhdrs);

        protocol_start_response(sn, rq);
       net_write(sn->csd, err_header, strlen(err_header));
        net_write(sn->csd, error, strlen(error));
       net_write(sn->csd, err_footer, strlen(err_footer));
        return REQ_PROCEED;
    }
    else
    {
        /* this 503 didn't come from a QOS SAF failure, 
					let someone else handle it */
        return REQ_PROCEED;
    };
}

/*---------------------------------------------------------------
qos_handler_sample

This is an NSAPI AuthTrans function.

It examines the QOS values in the request and compares them to the
QOS limits.

It does several things:
1) It will log errors if the QOS limits are exceeded.
2) It will return REQ_ABORTED with a 503 error code if the QOS limits
  are exceeded, and the QOS limits are set to be enforced. Otherwise
  it will return REQ_PROCEED.
------------------------------------------------------------------

NSAPI_PUBLIC int qos_handler_sample(pblock *pb, Session *sn, Request *rq)
{
    PRBool ok = PR_TRUE;

    PRInt32 vs_bw = 0, vs_bwlim = 0, vs_bw_ef = 0,
            vs_conn = 0, vs_connlim = 0, vs_conn_ef = 0,
            vsc_bw = 0, vsc_bwlim = 0, vsc_bw_ef = 0,
            vsc_conn = 0, vsc_connlim = 0, vsc_conn_ef = 0,
            srv_bw = 0, srv_bwlim = 0, srv_bw_ef = 0,
            srv_conn = 0, srv_connlim = 0, srv_conn_ef = 0;

    pblock* apb = rq->vars;

    decode("vs_bandwidth", &vs_bw, apb);
    decode("vs_connections", &vs_conn, apb);

    decode("vs_bandwidth_limit", &vs_bwlim, apb);
    decode("vs_bandwidth_enforced", &vs_bw_ef, apb);

    decode("vs_connections_limit", &vs_connlim, apb);
    decode("vs_connections_enforced", &vs_conn_ef, apb);

    decode("vsclass_bandwidth", &vsc_bw, apb);
    decode("vsclass_connections", &vsc_conn, apb);

    decode("vsclass_bandwidth_limit", &vsc_bwlim, apb);
    decode("vsclass_bandwidth_enforced", &vsc_bw_ef, apb);

    decode("vsclass_connections_limit", &vsc_connlim, apb);
    decode("vsclass_connections_enforced", &vsc_conn_ef, apb);

    decode("server_bandwidth", &srv_bw, apb);
    decode("server_connections", &srv_conn, apb);

    decode("server_bandwidth_limit", &srv_bwlim, apb);
    decode("server_bandwidth_enforced", &srv_bw_ef, apb);

    decode("server_connections_limit", &srv_connlim, apb);
    decode("server_connections_enforced", &srv_conn_ef, apb);

    if ((vs_bwlim) && (vs_bw>vs_bwlim))
    {
        /* bandwidth limit was exceeded, log it */
         ereport(LOG_FAILURE, "Virtual server bandwidth limit of %d exceeded. 
				 Current VS bandwidth : %d", &vs_bwlim, vs_bw);

        if (vs_bw_ef)
        {
            /* and enforce it */
            ok = PR_FALSE;
        };
    };

    if ((vs_connlim) && (vs_conn>vs_connlim))
    {
       /* connection limit was exceeded, log it */
        ereport(LOG_FAILURE, "Virtual server connection limit of %d exceeded. 
				Current VS connections : %d", &vs_connlim, vs_conn);

        if (vs_conn_ef)
        {
            /* and enforce it */
            ok = PR_FALSE;
        };
    };

    if ((vsc_bwlim) && (vsc_bw>vsc_bwlim))
    {
        /* bandwidth limit was exceeded, log it */
         ereport(LOG_FAILURE, "Virtual server class bandwidth limit of %d exceeded. 
				 Current VSCLASS bandwidth : %d", &vsc_bwlim, vsc_bw);

        if (vsc_bw_ef)
        {
            /* and enforce it */
            ok = PR_FALSE;
        };
    };

    if ((vsc_connlim) && (vsc_conn>vsc_connlim))
    {
        /* connection limit was exceeded, log it */
        ereport(LOG_FAILURE, "Virtual server class connection limit of %d exceeded. 
				Current VSCLASS connections : %d", &vsc_connlim, vsc_conn);

        if (vsc_conn_ef)
        {
            /* and enforce it */
            ok = PR_FALSE;
        };
    };


    if ((srv_bwlim) && (srv_bw>srv_bwlim))
    {
        /* bandwidth limit was exceeded, log it */
        ereport(LOG_FAILURE, "Global bandwidth limit of %d exceeded. 
				Current global bandwidth : %d", &srv_bwlim, srv_bw);

        if (srv_bw_ef)
        {
            /* and enforce it */
            ok = PR_FALSE;
        };
    };

    if ((srv_connlim) && (srv_conn>srv_connlim))
    {
        /* connection limit was exceeded, log it */
        ereport(LOG_FAILURE, "Global connection limit of %d exceeded. 
				Current global connections : %d", &srv_connlim, srv_conn);

        if (srv_conn_ef)
        {
            /* and enforce it */
            ok = PR_FALSE;
        };
    };

    if (ok)
    {
        return REQ_PROCEED;
    }
    else
    {
         /* one of the limits was exceeded
           therefore, we set HTTP error 503 "server too busy" */
        protocol_status(sn, rq, PROTOCOL_SERVICE_UNAVAILABLE, NULL);
        return REQ_ABORTED;
    };
}