/*****************************************************************************/ /* accAgent.c *** EXPERIMENTAL/PROOF-OF-CONCEPT/EXAMPLE ONLY *** Pronouced: acker-jent (and again for no particular reason). Network accept-agents run as CGIplus scripts after initial connection acceptance. The idea is to provide a flexible mechanism for additional request acceptance processing. Accept-agents do not have the full complement of CGI variables available because this is *well* before request data has been received. As an accept-agent adds response latency to every request they should execute as expeditiously as possible. The accept-agent script activation path is a fixed "/cgiplus-bin/accagent" but as this is mapped before activation can be modified according to requirement. For example, two services on the one system can each have their own meta agents using the following: # WASD_CONFIG_MAP if (server-name:www1.net) map /cgiplus-bin/accagent /cgiplus-bin/accwww1 elif (server-name:www2) map /cgiplus-bin/accagent /cgiplus-bin/accwww2 endif At the very least, it should be mapped to any customised agent script: # WASD_CONFIG_MAP map /cgiplus-bin/accagent /cgiplus-bin/myaccagent And of course, other path SETings applied as required. An agent MUST provide an "AGENT-END: 200 ..." when successfully concluding, or an "AGENT-END: 502 ..." when wishing to register a (WATCHable) non-fatal error. These parallel HTTP status. 501 (not implemented) is reserved to server use. A 500 (internal server error) will abort the request, returning a 500 error report. 418 (I'm a teapot) will unceremoniously drop the request connection. All status are considered non-fatal and the connection continues without meaningful network accept-agent configuration. For server-internal processing detail see [SRC.HTTPD] NetAgentBegin() and NetAgentEnd(). COPYRIGHT --------- Copyright (C) 2021 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION LOG ----------- 01-JUN-2021 MGD initial */ /*****************************************************************************/ #define SOFTWAREVN "1.0.0" #define SOFTWARENM "ACCAGENT" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # error VAX not implemented #endif #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif #include #include #include #include #include #include #include #include #include #include #include #include int CgiPlusUsageCount; char *dropper; char SoftwareId[] = SOFTWAREID; /*****************************************************************************/ /* */ int main (int argc, char *argv[]) { int status; char *cptr, *sptr; if (argc > 1) { if (!strcasecmp (argv[1], "/version")) fprintf (stdout, "%%%s-I-VERSION, %s (%s)\n", SOFTWARENM, SOFTWAREID, CgiLibEnvironmentVersion()); exit (SS$_NORMAL); } CgiLibEnvironmentInit (0, NULL, 0); /* MUST only be executed in a CGIplus environment! */ if (!CgiLibEnvironmentIsCgiPlus ()) { CgiLibResponseHeader (502, "text/plain"); fputs ("CGIplus!\n", stdout); exit (SS$_NORMAL); } /* this is to test/demonstrate the connection dropper */ dropper = getenv("WASD_ACCAGENT_DROPPER"); for (;;) { /* block waiting for the next request */ CgiLibVar (""); CgiPlusUsageCount++; if (cptr = CgiLibVarNull("REQUEST_METHOD")) if (!*cptr) { /* proctored into existance */ CgiLibResponseHeader (204, "application/proctor"); CgiLibCgiPlusEOF (); continue; } cptr = CgiLibCgiPlusCallout ("AGENT-BEGIN: %s (%s) usage:%d", SoftwareId, CgiLibEnvironmentVersion(), CgiPlusUsageCount); if (*cptr != '2') { /* if callout response not "200 ..." */ status = atoi(cptr); CgiLibResponseHeader (status, "text/plain"); fprintf (stdout, "%d!\n", status); CgiLibCgiPlusEOF (); continue; } cptr = CgiLibVar ("REMOTE_ADDR"); if (!dropper) CgiLibCgiPlusCallout ("!AGENT-END: 502 no WASD_ACCAGENT_DROPPER"); else if (strstr (dropper, cptr)) CgiLibCgiPlusCallout ("!AGENT-END: 418 %s", cptr); else CgiLibCgiPlusCallout ("!AGENT-END: 200 %s", cptr); CgiLibCgiPlusEOF (); } } /*****************************************************************************/