home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / srev13h.zip / DAEMONS.DOC < prev    next >
Text File  |  2001-03-27  |  25KB  |  646 lines

  1. 20 January 1999.
  2.  
  3.                         Working with  SRE-http daemons.
  4.  
  5. I. Introduction.
  6.  
  7. When creating web-aware applications for SRE-http, the use of daemons can
  8. greatly improve performance.  Daemons, defined as threads that
  9. are always resident in memory, are used extensively in SRE-http. 
  10. In general, given the "seperate transient thread per request" nature of 
  11. GoServe/SRE-http, whenever the server needs to access "semi-permanent"
  12. information a daemon is usually there to help. For example; looking up usernames, 
  13. taking care of virtual directory resolution, and recording to the common log audit
  14. files are all handled by seperate daemons.
  15.  
  16. Although these functions could be performed using external REXX procedures, and 
  17. the OS/2 environment, daemons have certain advantages.  A minor advantage is that 
  18. load time is avoided (a small concern when external procedures are stored in REXX 
  19. macrospace).  A more important feature is that daemons can retain information in 
  20. memory, avoiding the need to reload configuration information and other data 
  21. files. Furthermore, this information can be retained in useful formats; in 
  22. particular, as stem variables. By combining this data storage capability with 
  23. search/sort/etc. code; it becomes relatively easy to create dynamic storage 
  24. "objects" with auto-refresh, lookup, and other database features.  
  25.  
  26. Although potentially useful, daemons are somewhat difficult to work with.  OS/2
  27. does not offer easy ways of transferring information between daemons; one 
  28. doesn't call a daemon the same way one would call a procedure stored in a
  29. library. Although it's not conceptually difficult to devise ways of overcoming
  30. this  drawback, the actual implementation of robust mechanisms can become
  31. tedious.
  32.  
  33. In order to overcome this drawback, SRE-http comes with SREF_DMN_, a set of
  34. daemon manipulation routines.  By using these procedures in both the
  35. daemon, and in the programs that rely upon the daemon, much of the hassle of 
  36. using daemons can be avoided. The remainder of this document discusses these
  37. procedures.
  38.  
  39.  
  40. II. The SREF_DMN_ procedures.
  41.  
  42. To create and use daemons, four actions are required:
  43.   1) Launching the daemon
  44.   2) Sending information to the daemon, and recieving a reply
  45.   3) Reading information into the daemon, and sending replies
  46.   4) Closing the daemon
  47.  
  48. Note that #1 and #4 are one time affairs; with #4 often never implemented. 
  49. Action #2 is associated with a program (i.e.; an addon) requiring some 
  50. information. Action #3 is associated with a daemon waiting till it's needed.  
  51.  
  52. SRE-http (as of version 1.2N) includes a family of "SREF_DMN_" 
  53. procedures that help implement these various actions. The following lists
  54. these procedures, with more detailed descriptions below.
  55.  
  56.       status=SREF_DMN_LAUNCH(daemon_name,file_name,optional_arg,logfile,errpre,verbose)
  57.       status=SREF_DMN_EXIST(daemon_name)
  58.        value=SREF_DMN_ASK(daemon_name,an_argument,max_wait)
  59.  request_info=SREF_DMN_WAIT(daemon_name,max_wait)
  60.  an_argument=SREF_DMN_VALUE(request_info)
  61.       status=SREF_DMN_REPLY(request_info,reply_stuff)
  62.       status=SREF_DMN_KILL(daemon_name)
  63.  
  64. Basically ...
  65.    SREF_DMN_LAUNCH is called (often by a stand-alone program)
  66.    to "launch" the daemon. SREF_DMN_ASK is used to read & supply
  67.    information to the daemon, and is often called from an 
  68.    SRE-http addon. SREF_DMN_WAIT, SREF_DMN_VALUE, and SREF_DMN_REPLY
  69.    are used by the daemon to return information (typically to
  70.    an addon). 
  71.  
  72.                         -------------------
  73.  
  74. SREF_DMN_LAUNCH(daemon_name,file_name,optional_arg,logfile,errpre,verbose)
  75. where:
  76.   daemon_name: A name that will be used to label this daemon. It is only used by 
  77.                   the SREF_DMN_ procedures
  78.   file_name: The file containing the program to launch as the daemon_name 
  79.              daemon. If not a fully qualified file name, it is
  80.              assumed to be under SRE-http's addon directory.
  81.  optional_arg: An optional argument that will be sent to the daemon upon
  82.                launching.
  83.  logfile: An optional log file that will be used for recording errors (errors
  84.           will also be written to the PMPRINTF window). This should be 
  85.           a fully qualified file name.
  86.   errpre: An optional "error prefix". If this is specified, when
  87.           SREF_DMN_ASK encounters an error, it will prepend this
  88.           string to an error message, and return it.  If this is
  89.           not specified, SREF_DMN_ASK will return a null string.
  90.  verbose: Verbosity of status messages: 1 to 4, 1 is a few, 4 is too many.
  91.           If verbose not specified, the value of the SRE_VERBOSE
  92.           variable is used (SRE_VERBOSE is set by versions 1.3b.0199.c and
  93.           above of SRE-http).
  94. Returns:
  95.                n  = if n > 0, then success; with n the "thread" the daemon 
  96.                     was launched on
  97. n  message   =  n<0 is an error code, followed by an error message 
  98.  
  99. SREF_DMN_LAUNCH will take the program (typically, a REXX program) in file_name
  100. and launch it in its own thread. It will also create some necessary "queues 
  101. and semaphores" that will be used by the SREF_DMN_ procedures.
  102.  
  103. Note that the daemon will remain active so long as the process that called
  104. SREF_DMN_LAUNCH is still alive.  If you use SRE-http to do this launching (say,
  105. with a CUSTOM_INITS, or by requesting your own "launch my daemon" addon), the
  106. "process" is GoServe; hence the daemon will stay live as long as your server is
  107. up and running.  
  108.  
  109. Although launching the daemon through SRE-http is convenient, if you intend to
  110. "kill the daemon" without killing GoServe/SRE-http, it is often safer to run 
  111. your "launch my daemon" program in a seperate process that you keep open as long
  112. as needed. 
  113.  
  114. When launching a daemon (in its own thread), SREF_DMN_LAUNCH will supply two
  115. arguments: the daemon_name and the value of optional_args. The program can use
  116. these as it sees fit.
  117.  
  118. CAUTION:
  119.     Some users report that if you launch several daemons in rapid succession, 
  120.     failures may occur (that is, the daemon might "disappear").  This seems
  121.     to be cured by inserting a few seconds delay (i.e.; using call syssleep(3))
  122.     right after each call do SREF_DMN_LAUNCH.
  123.  
  124.  
  125.                         -------------------
  126.  
  127. SREF_DMN_EXIST(daemon_name)
  128. where:
  129.   daemon_name: As above
  130. returns:
  131.     1 = Semaphore and queue exist
  132. Otherwise, an error code. Common error codes are:
  133.     0 = Queue does not exist
  134.  -187 = Semaphore does not exist
  135.  
  136. SREF_DMN_EXIST checks whether the deamon's queue and semaphore are open.
  137. If not, either the deamon was never launched, or something caused its
  138. semaphore or queue to be closed. In either case, you can't talk to it!
  139.  
  140.  
  141.  
  142.                         -------------------
  143.  
  144. SREF_DMN_ASK(daemon_name,an_argument,max_wait,semqueue)
  145. where:
  146.     daemon_name : The daemon_name used in SREF_DMN_LAUNCH
  147.       an_argument: An argument to send to this daemon. It can be 
  148.                      any length, and can be text or binary.  
  149.          max_wait: Optional. Maximum number of seconds to wait. If not 
  150.                      specified, SREF_DMN_ASK will wait forever.
  151.         semqueue:   Optional. Semaphore/queue information
  152. returns:
  153.         null string: A null string is returned if a time out occured, or if some
  154.                     kind of error  occured. You can examine the
  155.                     use the logfile (described below) to view
  156.                     additional information on the error.
  157.                                
  158.                     Or -- if you've specified an "error_prefix" in
  159.                     DMN_LAUNCH -- an error message will be returned
  160.                     instead of the nulll string.
  161.  
  162.                     For example, if  errpre="ERROR:" then an error 
  163.                     return could look like:
  164.                         ERROR: SREF_DMN_ASK: daemon semaphore missing: 
  165.  
  166.         otherwise: The "reply' returned by the daemon (see SREF_DMN_REPLY)
  167.  
  168. SREF_DMN_ASK will "send an_argument" to the daemon_name daemon, 
  169. and wait for a reply. You can think of SREF_DMN_ASK as a way of treating
  170. daemons as if they were procedures that can take one argument.  If you
  171. want to send mulitple arguments to your daemon, you'll have to concatenate
  172. them into an_argument, and have the daemon parse them out.
  173.  
  174. Note that  the daemon  might return a null string; which is 
  175. indistinguishable from the default "error return". If this might
  176. be a problem, you should specify an the errpre option SREF_DMN_LAUNCH,
  177. and then check for this "error_prefix" upon returning from SREF_DMH_ASK.
  178.  
  179. Semqueue is strictly optional -- if specified, it should be the value
  180. of the semqueue variable that is supplied to SRE-http addons.
  181. If supplied, semqueue will be used to specify a semaphore and queue
  182. to use to talk to the daemon.  If not specified  SREF_DMN_ASK will create 
  183. a thread specific semaphore and queue. The only advantage gained by 
  184. providing semqueue is a slight improvement in throughput 
  185. (since the overhead of creating a queue and semaphore is avoided).
  186.  
  187.  
  188. Special Feature:
  189.     Setting MAX_WAIT='NOWAIT' will cause the an_argument
  190.     to be added to the queue, and nothing else (a '' is
  191.     returned immediately)
  192.     Setting MAX_WAIT='CLEAR' will also add an_argument to the daemon's
  193.     queue and not wait for a return. It will ALSO clear this
  194.     queue BEFORE adding an_argument.
  195.  
  196. Note: if an error is encountred, SREF_DMN_ASK will write a note to
  197.       the PMPRINTF window. In addition, SREF_DMN_ASK will write a
  198.       note to a logfile. If you specified a logfile in SREF_DMN_LAUNCH,
  199.       that's the logfile it will used. Otherwise, it will use
  200.       DMN_daemon_name.LOG (in the current directory, wherever that
  201.       may be).
  202.  
  203.       In addition, if SREF_DMN_ASK is running under a GoServe/SRE-http process,
  204.       then an error message is recorded using the  SREF_ERROR procedure (see
  205.       SREFPRC.DOC for details).
  206.  
  207.                         -------------------
  208.  
  209. SREF_DMN_WAIT(daemon_name,max_wait)
  210. where:
  211.     daemon_name: As above
  212.         max_wait:  Optional. Maximum number of seconds to wait.
  213.                      If not specified, wait forever.
  214. returns one of:
  215.    i)  null string : If no request was sent to the daemon within max_wait seconds.
  216.   ii)  a string starting with ERROR, followd by an error message. For example:
  217.                 ERROR  Could not find daemon_name.
  218.  iii)  request_info: A package of request information.
  219.  
  220. SREF_DMN_WAIT will wait for a request to the daemon_name daemon;
  221. typically one that's sent by an SRE-http addon that calls 
  222. SREF_DMN_ASK. If a request is recieved, then a bundle of information is 
  223. returned.
  224.    ** This bundle is NOT meant to be directly used. 
  225.    ** Instead, you should use SREF_DMN_VALUE to extract the an_argument 
  226.    ** value from it.
  227.  
  228.   Example: request_info=SREF_DMN_WAIT('MyDaemon',100)
  229.  
  230.  
  231. Special Feature:
  232.    Setting MAX_WAIT='CLEAR' will cause the daemon's queue
  233.    to be cleared; with the last written entry returned.
  234.  
  235.                         -------------------
  236.  
  237.  
  238. SREF_DMN_VALUE(request_info)
  239. where:
  240.     request_info: A bundle of request information, as returned by SREF_DMN_WAIT
  241. returns:
  242.     an_argument: The "argument" being sent to the daemon. This will be 
  243.                    the value of an_argument used in a call to SREF_DMN_ASK.
  244.  
  245. SREF_DMN_VALUE is used to extract information from the request sent to this
  246. daemon.  You MUST provide it with a value returned by SREF_DMN_WAIT --
  247. if some other string is provided, a null string will be returned. Furthermore,
  248. if an ERROR response was returned to SREF_DMN_WAIT, then SREF_DMN_VALUE
  249. will return a null string.
  250.  
  251.                         -------------------
  252.  
  253. SREF_DMN_REPLY(request_info,reply_stuff)
  254. where:
  255.   request_info: the request_info returned by SREF_DMN_WAIT
  256.   reply_stuff: The information you want to return to the request. This is the value
  257.                that SREF_DMN_ASK will return -- it can be a text or binary       
  258.                string of any size. 
  259. returns one of:
  260.   i)  1 (success)
  261.  ii) an error message
  262.  
  263. SREF_DMN_REPLY is the counterpart to SREF_DMN_ASK -- it returns information
  264. to the requesting thread.  As with SREF_DMN_VALUE, the request_info must be 
  265. the value returned by SREF_DMN_WAIT -- request_info contains the "name"
  266. of the requesting thread, without which the daemon has no idea of who
  267. to respond to.
  268.  
  269.                         -------------------
  270.  
  271.                
  272. SREF_DMN_KILL(daemon_name)
  273. where:
  274.   daemon_name : as above
  275. returns:
  276.   1= success
  277. otherwise = an error message
  278.  
  279. Kills the daemon launched by SREF_DMN_LAUNCH.  This is an optional
  280. procedure, and is included to help clean up resources.
  281.  
  282. Unfortunately, REXX's ability to remove the queues and semaphores created
  283. by SREF_DMN_LAUNCH is somewhat flakey.  It is generally safer
  284. to simply kill the process that launched the daemon.  If you launched the
  285. daemon through GoServe/SRE-http, that can be a problem; since you'ld
  286. have to restart your server. 
  287.  
  288. Hence, in cases where you expect to be killing (and perhaps relaunching) the 
  289. daemon frequently, we recommend issuing SREF_DMN_LAUNCH from a seperate
  290. process, and stopping/restarting the process when you want to kill/re-launch
  291. the daemon.  That is, don't bother using SREF_DMN_KILL --  stop the
  292. process instead.
  293.  
  294.  
  295.                         -------------------
  296.  
  297.  
  298.  
  299. III. Example.
  300.  
  301. Let's assume you want to create a daemon called RUNNING_SUM.  It will take
  302. a number and a name, add it to a running sum specific to that name, and return 
  303. the new value of this running sum. Such a procedure might be useful when
  304. keeping track of resource utilization; say of some fancy addon that you
  305. wish to make available on a limited basis.  
  306.  
  307. The following code can be used to implement such a daemon. To try it out,
  308. you'll need to create the following files:
  309.   RUNSUM0.CMD -- A simple rexx program to launch the daemon.  Can be
  310.                 placed anywhere, such as in the GoServe working directory.
  311.   RUNSUM1.RXX -- The daemon itself -- put it in the Goserve working directory.
  312.   RUNSUM.CMD  -- An addon that ust counts how many times you've called RUNSUM.
  313.                  Put it in  the addon directory.
  314.   RUNSUM.HTM -- Requests RUNSUM.CMD. Put it in your GoServe data directory
  315.                 (the root of your web tree).
  316.  
  317. You can create these files by cutting and pasting the following code -- check
  318. out the embedded comments for further details. And, when creating
  319. the .RXX and .CMD files, be sure that the FIRST LINE IS A COMMENT
  320. (that is, the first 2 characters should be /*)
  321.  
  322.  
  323.                 
  324.         ------------------------------------------------------
  325.        ------ RUNSUM0.CMD. Put in \GOSERVE directory  ----------
  326.         ------------------------------------------------------
  327. /* RUNSUM0.CMD: Launch the running-sum daemon. 
  328.    This program should be run
  329.    from a seperate OS/2 box (or, you could start it by using SRE-http's
  330.    CUSTOM_INITS parameter) 
  331. */
  332. call initstuf           /* check to see if sref_dmn_ procedures are in macrospace */
  333. say "Note: you can use PMPRINTF to see daemon status messages"
  334. say
  335. /* RUNSUM.STM will be used to store running sums, 
  336.    the 1 signals "verbose" mode */
  337. astat=SREF_DMN_LAUNCH('RUNNING_SUM','RUNSUM.RXX','RUNSUM.STM  1',,'ErRor:')
  338. if word(astat,1)>0 then do
  339.   say " Running Sum daemon successfully launched on thread "astat
  340.   say " To kill the daemon, close this OS/2 box. "
  341.   say " To let it run, do NOT close this OS/2 box."
  342. end
  343. else do
  344.  say " Could not launch daemon. "
  345.  say " Error message: "astat
  346. end
  347. exit
  348.  
  349.  
  350. /* check initialization stuff */
  351. initstuf:procedure
  352.  
  353.  
  354. /*  Load REXX libraries */
  355. /* Load up advanced REXX functions */
  356. foo=rxfuncquery('sysloadfuncs')
  357. if foo=1 then do
  358.   call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  359.  
  360.   call SysLoadFuncs
  361. end
  362. foo=rxfuncquery('rexxlibregister')
  363. if foo=1 then do
  364.  call rxfuncadd 'rexxlibregister','rexxlib', 'rexxlibregister'
  365.  call rexxlibregister
  366. end
  367.  
  368. foo=macroquery('SREF_VERSION')
  369. if foo="" then do
  370.   say " SRE-http has not been initialized. Perhaps you need to "
  371.   say " hit your server with its first request? "
  372.   exit
  373. end
  374. return 1
  375.  
  376. /* END OF RUNSUM0.CMD */
  377.  
  378.  
  379.         ------------------------------------------------------
  380.          ------ RUNSUM.RXX. Put in \GOSERVE directory  ----------
  381.         ------------------------------------------------------
  382. /*RUNSUM.RXX : The running sum daemon */
  383.  
  384. parse arg da_name,old_file
  385.  
  386. parse var old_file oldfile verbose
  387.  
  388. signal on syntax name goterr ; signal on error name goterr 
  389.  
  390.  
  391. call pmprintf('RUNSUM.RXX launched as daemon: 'da_name)
  392.  
  393. /* read old information that's been stored in old_file (if specified) */
  394. if anarg<>' ' then do
  395.   if stream(oldfile,'c','query exists')="" then do
  396.         call pmprintf('RUNSUM.RXX: Warning: 'oldfile' not found.')
  397.   end
  398.   else do
  399.      foo=cvread(oldfile,'sums')  
  400.      if foo=0 then do
  401.         call pmprintf('RUNSUM.RXX: Warning: could not read 'oldfile'. Result will NOT be saved.')
  402.         oldfile=""           /* suppress attempts at writing to oldfile */
  403.      end
  404.      else do
  405.       oof=cvtails(sums,'tsums')
  406.       call pmprintf(' RUNSUM.RXX : Using 'oof' entries stored in: 'oldfile)
  407.      end
  408.   end
  409. end
  410.  
  411. didchange=0             /* flag indicating that A query was answered */
  412.  
  413. do forever
  414.     req_info=SREF_DMN_WAIT('RUNNING_SUM',30)   /*wait up to 30 seconds for a request */
  415.  
  416. /* 1) check for error, and pmprintf it if found. Note that SAY does not work from
  417.     within daemons-- hence the use of pmprintf */
  418.  
  419.     if abbrev(req_info,'ERROR')=1 then do           /* errror occurred */
  420.         parse var req_info . errmess
  421.         call pmprintf(' RunningSum Daemon error: '||errmess)
  422.         iterate                                       /* assume it was fluke, and try again */
  423.    end
  424.  
  425.    if verbose>0 then do
  426.        call pmprintf(' RUNNING_SUM Daemon: request length='length(req_info))
  427.    end
  428.  
  429. /* 2) timed out?  Take this opportunity to write SUMS. to anarg (if
  430. there have been any changes*/
  431.  
  432.    if req_info="" then do
  433.       if didchange>0 & oldfile<>"" then do
  434.          didchange=0
  435.          foo=cvwrite(oldfile,'SUMS')
  436.          if verbose>0 then call pmprintf(' RUNSUM.RXX :Wrote running sums to 'oldfile)
  437.       end
  438.       iterate      
  439.    end
  440.  
  441. /* 3) otherwise, we got legit request. Extract the useful information */
  442.  
  443.    stuff=SREF_DMN_VALUE(req_info)
  444.  
  445. /* check for error again -- this shouldn't happen, but ... */
  446.    if stuff="" then do
  447.         call pmprintf(' Running sum error. No information provided ' )           
  448.         iterate
  449.    end
  450.  
  451.    parse upper var stuff aname addvalue       /* parse out name and number */
  452.    
  453. /* explicitily save? Might be needed on busy sites (where 30 second timeout
  454.    never happens */
  455.  
  456.    select    
  457.     when strip(aname)='!SAVE' then do     /* save current values */
  458.        foo=cvwrite(oldfile,'SUMS')
  459.        writeme=' Saved running sums to 'oldfile
  460.     end
  461.  
  462.     when strip(aname)='*' then do  /* display all current sums */
  463.         foo=cvtails('SUMS','TSUMS')
  464.         nms=''
  465.         do mm=1 to foo 
  466.            aa=tsums.mm
  467.            aa2=strip(aa,'l','!')
  468.            aa3=sums.aa
  469.            nms=nms||aa2'='aa3'0d0a'x
  470.         end
  471.         writeme=nms
  472.     end
  473.  
  474.     otherwise do             /* it's a value, add and save it */
  475.       if datatype(addvalue)<>'NUM' then addvalue=0   /* bad input, assume number=0 */
  476.  
  477. /* using stem variables, get the current running sum for aname. If this is first
  478.     value for aname, then initialize a stem variable */
  479.        tmp='!'||aname
  480.        if symbol('SUMS.'||tmp)<>'VAR' then do
  481.             rsum=0
  482.        end
  483.        else do
  484.            rsum=sums.tmp
  485.        end
  486.  
  487.        sums.tmp=rsum+addvalue               /* add to the running sum */
  488.        didchange=1+didchange
  489.        writeme=sums.tmp
  490.      end
  491.    end
  492.  
  493.    astat=SREF_DMN_REPLY(req_info,writeme)   /* return the reply */
  494.  
  495. /* check for problems */
  496.    if astat<>1 then
  497.       call pmprintf('RunningSum error. Could not reply: 'astat)   /* note that an error occured */
  498.  
  499. end                     /* wait for next request */  
  500.  
  501. goterr:     /* jump here on error */
  502. call pmprintf(' Running Sum Daemon. Error at line ' sigl', rc= 'rc)
  503. exit
  504.  
  505.   
  506. /* End of RUNSUM.RXX */
  507.  
  508.  
  509.  
  510.  
  511.         ------------------------------------------------------
  512.          ------ RUNSUM.CMD. Put in \GOSERVE\ADDON directory  ----------
  513.         ------------------------------------------------------
  514. /* RUNSUM.CMD : A simple SRE-http addon to demonstrate the use of the
  515.                     RUNNING SUM daemon. 
  516.  
  517.  To use this, you must first  run RUNSUM1.CMD (either as a CUSTOM_INITS, or 
  518.  preferably in its own process).
  519.  
  520.  Requests for RUNSUM.CMD should look like:
  521.                 RUNSUM?name=name&value=value
  522.  
  523.  For an example of how to use this, see RUNSUM.HTM
  524. */
  525.  
  526. /* get request info supplied by SRE-http.  For this simple example, we don't
  527.    bother parse arg'ing all the arguments. */
  528.  
  529. parse arg  ddir, tempfile, reqstrg,list
  530.  
  531. if list="" then do
  532.    say " This SRE-http addon is NOT meant to be run from a command prompt."
  533.    exit
  534. end /* do */
  535.  
  536. /* start writing response to client */
  537. call lineout tempfile,' <html><head><title>Running Sum</title></head> <body>'
  538.  
  539. /* extract NAME and VALUE from LIST (list is the stuff following a ? in a GET request) */
  540.  
  541. aname="" ; addme=0              /* defaults */
  542. do until list=""
  543.  parse var list a1 '&' list
  544.  parse upper var a1 avar '=' aval
  545.  aval=strip(packur(translate(aval,' ','+')))
  546.  select 
  547.    when avar='NAME' then aname=aval
  548.    when avar='VALUE' then addme=aval
  549.    otherwise nop
  550.  end            /* select */
  551. end
  552.  
  553. /* no name given? Send an error response to the client */
  554. if aname="" then do
  555.    call lineout tempfile,' Sorry, you did not specify a name.'
  556.    call lineout tempfile,' </body></html> '
  557.    call lineout tempfile                /* make sure you close the response file! */
  558.    'FILE erase type text/html name ' tempfile
  559.    return 'No name specified '
  560. end
  561.  
  562. /* call the daemon and wait for up to 30 seconds */
  563. tmpval=aname' 'addme
  564. stuff=SREF_DMN_ASK('RUNNING_SUM',tmpval,30)  
  565.  
  566. if stuff="" then do             /* possible error message */
  567.    if errmess="" then  errmess="Timed out. "
  568.    call lineout tempfile,' Error in RUNNING_SUM daemon: 'errmess
  569.    call lineout tempfile,'<br> <em>Did you remember to first run RUNSUM0?'
  570. end
  571. else do            /* otherwise, return the current running sum */
  572.    select
  573.      when aname='*' then do
  574.        call lineout tempfile,'<h3>List of current values</h3><pre>'
  575.        call lineout tempfile,stuff
  576.        call lineout tempfile,'</pre>'
  577.      end /* do */
  578.      when aname='!SAVE' then do   
  579.         call lineout tempfile,'<p>'stuff
  580.      end /* do */
  581.      otherwise do
  582.        call lineout tempfile,' <h3> Running sum value </h3>'
  583.        call lineout tempfile,' The current running sum for <b> 'aname'</b> = <code> ' stuff '</code> '
  584.      end
  585.    end
  586. end
  587.  
  588. /*return the response to the client */
  589. call lineout tempfile,' </body></html> '
  590. call lineout tempfile                /* make sure you close the response file! */
  591. 'FILE erase type text/html name ' tempfile
  592. return 'RunningSum done '
  593.  
  594. /* End of RUNSUM.CMD */
  595.  
  596.  
  597.  
  598.         ------------------------------------------------------
  599.          ------ RUNSUM.HTM. Put in \WWW directory  ----------
  600.         ------------------------------------------------------
  601.  
  602. <!-- RUNSUM.HTM
  603.      This is a front-end to the running-sum daemon (RUNSUM.CMD) -->
  604. <html><head><title>Running Sum Daemon Demo </title></head>
  605. <body>
  606. <h2>Running-Sum Daemon Demo </h2>
  607.  
  608.      <FORM action="/RUNSUM" method="GET">
  609.            Enter your name: <input type="text" name="NAME" size=15> <br>
  610.            Enter the value to add: <input type="text"  name="VALUE" size=15> <br>
  611.           <input type="SUBMIT" value="Get the running sum">
  612.      </FORM>
  613.  
  614. <br>
  615. <h3>Special values for the name field</h3>
  616. <B>!SAVE</b>: Save results<br>
  617. <b>*</b>: Display a list of sums
  618.  
  619. </body></html>
  620.  
  621. <!-- End of RUNSUM.HTM -->
  622.  
  623.  
  624.         ------------------------------------------------------
  625.  
  626. NOTES:
  627.  
  628.    * After creating these files, point your browser at RUNSUM.HTM
  629.      and enter a few names/values.  You can even shut down your system,
  630.      and restart it -- values are retained in a special file!
  631.  
  632.    * To debug daemons, you can NOT use SAY commands -- when running
  633.      under GoServe, SAY commands issued from within a daemon do not appear
  634.      anywhere (not even in the PMPRINTF window). Instead, you can use the
  635.      PMPRINTF procedure (that's part of REXXLIB).
  636.  
  637.    * WE HIGHLY RECOMMEND INCLUDING "signal on syntax name some_location " AND
  638.      "signal on error name some_location" STATEMENTS IN YOUR DAEMON.  Daemons 
  639.      fail silently, but with these "signals" (and pmprintf's of SIGL at 
  640.      some_location), you'll save yourself a lot of grief.
  641.  
  642.  
  643. Good luck!
  644.  
  645. End of daemons.doc
  646.