[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
/*****************************************************************************/
/*
                                 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 <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <types.h>
#include <unixlib.h>
#include <unistd.h>

#include <ssdef.h>

#include <cgilib.h>

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

/*****************************************************************************/