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; }; }