Introduction

Brian Wade

IBM Corporation
VM Development
28 Oct 1998

Table of Contents

Introduction

Module Build

Run-Time Environment

Server-Wide Initialization and Termination

  • Module Entry Point
  • Example
  • PROFILE RSK
  • Configuration Parameters
  • Example
  • Structure of A Running Server

    Interacting with Line Drivers

  • Line Driver Behavior
  • Entry Points
  • Initialization Entry Point
  • Service Entry Point
  • Termination Entry Point
  • Connecting Your Service to a Line Driver
  • Use of CMS IPC
  • Messages to Instance
  • Message to Line Driver
  • The ssClient APIs
  • Example
  • Anchors

  • APIs
  • Example
  • Memory Management

  • APIs
  • ssMemoryCreateDS
  • ssMemoryAllocate
  • ssMemoryRelease
  • ssMemoryDelete
  • Commands
  • Block-oriented DASD

  • APIs
  • Commands
  • Example
  • File Caching

  • Details
  • APIs
  • Commands
  • Example
  • Authorization

  • Setup
  • Minidisk
  • Shared File System
  • Users, Objects, and Actions
  • APIs
  • Simple APIs
  • ssAuthPermitUser
  • ssAuthTestOperations
  • Operator Commands
  • Example
  • Enrollment

  • Details
  • APIs
  • Commands
  • Example
  • Worker Machines

  • APIs
  • Commands
  • User ID Mapping

  • Commands
  • APIs
  • Example
  • Monitor Data

  • Commands
  • Example

  • Introduction

    The Reusable Server Kernel is an execution infrastructure for a CMS-based server program. It solves problems repeatedly encountered in the construction of such servers. Namely, the RSK provides assistance in all of the following areas:

    • Multithreading
    • Heterogeneous connectivity
    • Authorization
    • File caching
    • Memory management
    • Anchors
    • Worker machine management
    • Large-scale DASD I/O
    • Enrollment
    • Client user ID normalization

    Instead of consisting solely of entry points, the RSK is in fact a CMS-based server program. To use it, you attach your own business-specific logic to the RSK's execution infrastructure. When you use the RSK, you write only logic that applies to the particular business problem you are trying to solve. The RSK supplies the rest of what's necessary to let your server run well on CMS.

    This workbook provides supplementary, illustrative information for specific RSK topics. It is intended to be used together with the book VM/ESA Reusable Server Kernel Programmer's Guide and Reference, which is part of the VM/ESA library.


    Module Build

    This discussion assumes you have your text decks ready. Among your text decks should be included:

    • The deck that defines RSKMAIN, your server's entry point. Maybe that's RSKMAIN TEXT.

    • Text decks for the services you wrote - their initialization, service, and termination entry points.

    You might have supplied additional text decks that contain other parts of your server. For example, such decks might contain the code for long-running threads you create in your RSKMAIN.

    Build your module in usual CMS fashion. Some remarks:

    • You will need to GLOBAL some text libraries:
      BKWLIB
      RSK library
      DMSPSLK
      Supplemental RSK library
      DMSAMT
      CMS/MT text library
      VMMTLIB
      CMS/MT text library
      VMLIB
      CMS CSL stub library
      CMSSAA
      CMS SAA stub library
      You must put BKWLIB ahead of DMSAMT.

    • You will need INCLUDE commands only if the loader won't pick up your text decks automatically.

    • You need to include VMSTART by hand.

    Here is a sample sequence of commands. In this example, text files RSKMAIN, MYINIT, MYSERV, and MYTERM comprise the application.

    GLOBAL TXTLIB BKWLIB DMSPSLK DMSAMT VMMTLIB VMLIB CMSSAA
    LOAD RSKMAIN ( CLEAR DUP AUTO LIBE NOINV FULLMAP RLDSAVE
    INCLUDE MYINIT ( NOCLEAR DUP AUTO LIBE NOINV FULLMAP RLDSAVE
    INCLUDE MYSERV ( NOCLEAR DUP AUTO LIBE NOINV FULLMAP RLDSAVE
    INCLUDE MYTERM ( NOCLEAR DUP AUTO LIBE NOINV FULLMAP RLDSAVE
    INCLUDE VMSTART ( NOCLEAR DUP AUTO LIBE NOINV FULLMAP RLDSAVE RESET VMSTART
    GENMOD MYSERVER ( MAP STR
    

    When the build is done, you will have MYSERVER MODULE and a load map.


    Run-Time Environment

    Each module you supply must be prepared to handle the RSK run-time environment. This environment is nothing more than a simple procedure entry and exit linkage scheme that makes it unnecessary to call CMSSTOR for save areas or automatic storage. No other traditional run-time services (exception handling, for example) are provided.

    Roughly, the registers are used like this:

    R1
    Pointer to OS Type I parameter list
    R12
    Run-time anchor block pointer
    R13
    Save area pointer
    R14
    Return address
    R15
    Module entry point

    Macro SSPRLG implements the procedure entry linkage. Some remarks:

    • You use R0 to pass SSPRLG the number of bytes you need for automatic storage. This number must be a multiple of 8. The number you pass in R0 should include 120 bytes for the RSK's use.

    • SSPRLG returns the address of the new save area in R2.

    • Your automatic storage area (the storage you requested via R0) starts at offset 120 (hex X'78') into the new save area. (The first 120 bytes are used by the RSK.)

    Here is an example:

    RSKMAIN         CSECT   ,
    RSKMAIN         AMODE  31
    RSKMAIN         RMODE  ANY
                    STM    14,12,12(13)      Save registers
                    LR     11,15             Establish base register
                    USING  RSKMAIN,11
                    LA     R0,DSASIZE        Number of bytes needed
                    SSPRLG                   Get save area
                    LR     15,13             R15 = A(prev DSA)
                    LR     13,2              R13 = A(my DSA)
                    ST     15,4(,13)         Write my back pointer
                    ST     13,8(,15)         Write prev's fwd pointer
                    LM     15,2,16(15)       Restore R15-R2
    

    Procedure exit is simple as well:

                    L      R13,4(,R13)       R13 = A(prev DSA)
                    LA     R0,DSASIZE        Auto storage size
                    SSEPIL                   Release it
                    L      R14,12(,R13)      Get return address
                    LM     R0,R12,20(R13)    Restore rest of registers
                    BR     R14               Return to caller
    

    Do whatever you want between entry and exit, but if you call some other module, make sure R12-R15 are set up correctly.

    Finally, note that the run-time environment is implemented by module BKWRTE MODULE. You must have this module on one of the accessed file modes prior to starting your server.

    BKWRTE MODULE is a CMS/MT language environment manager. CMS loads BKWRTE as a nucleus extension just prior to starting your module and calls entry points inside BKWRTE as part of its management of the threads in your server. Each of the following actions results in CMS calling BKWRTE:

    • Process creation: BKWRTE does nothing.

    • Process deletion: BKWRTE does nothing.

    • Thread creation: BKWRTE does nothing.

    • Passing control to a new thread: BKWRTE allocates storage to contain the save area chain for the new thread and sets up the structures necessary to permit this storage to be extended later if necessary. It then sets the registers according to the RSK's linkage conventions and passes control to the thread's entry point.

    • Thread deletion: BKWRTE releases the thread's save area storage.

    Server-Wide Initialization and Termination


    Module Entry Point

    Your code gets control at entry point RSKMAIN. Your RSKMAIN is passed an OS Type I parameter list pointed to by R1. The parameter list contains:

    Offset
    Usage
    0
    A(CMS extended parameter list)
    4
    A(CMS tokenized parameter list)
    8
    A(SCBLOCK)

    So, if you need to refer to any of those data areas, you can do so. The RSK doesn't do anything with any of those parameter lists.

    The RSKMAIN you supply has a few jobs:

    1. It performs server-wide initialization, such as adjusting the virtual machine configuration, reading your own configuration or tailoring file, or creating threads or other objects (queues, mutexes) that should exist for the life of your server.

    2. It identifies, or binds, one or more services. These services, identified by name, are the core of your server.

    3. It calls ssServerRun to run the server program. When control returns from ssServerRun, the server has ended.

    4. It performs any server-wide cleanup.

    5. It returns to its caller.
    Warning
    You must bind all of your services before you call ssServerRun.

    RSK APIs available to RSKMAIN:

    • ssServiceBind
    • ssServerRun

    The rest of the RSK APIs are not available because the RSK does not set up its execution environment (control blocks, vectors, etc.) until you call ssServerRun.


    Example

     @PROCESS ENVIRONMENT(VM/ESAOS) OPT(MAX);                               00001000
                                                                            00002000
     /*********************************************************/            00003000
     /*                                                       */            00004000
     /* sample application... appl writer just supplies       */            00005000
     /* entry point RSKMAIN and we do the rest.               */            00006000
     /*                                                       */            00007000
     /* note runtime environment as                           */            00008000
     /* illustrated by PL/X procedure options                 */            00009000
     /*                                                       */            00010000
     /*********************************************************/            00011000
                                                                            00012000
     rskmain: procedure                                                     00013000
     (                                                                      00014000
      pl_epptr,                         /* A(eplist)     */                 00015000
      pl_tpptr,                         /* A(tplist)     */                 00016000
      pl_scptr                          /* A(SCBLOCK)    */                 00017000
     )                                                                      00018000
     options                                                                00019000
     (                                                                      00020000
      id                                /* generates identifier  */         00021000
      reentrant                         /* no static data pls    */         00022000
      amode(31)                         /* 31-bit addresses      */         00023000
      rmode(any)                        /* can reside anywhere   */         00024000
      datareg(13)                       /* R13 is stack ptr      */         00025000
      savearea(120)                     /* size of a save area   */         00026000
      stack('SSPRLG ','SSEPIL ')        /* hi-perf auto stg mgmt */         00027000
     );                                                                     00028000
                                                                            00029000
     /* passed parameters */                                                00030000
     declare                                                                00031000
      pl_epptr   pointer(31),                                               00032000
      pl_tpptr   pointer(31),                                               00033000
      pl_scptr   pointer(31);                                               00034000
                                                                            00035000
     /***********************************************/                      00036000
     /* macros                                      */                      00037000
     /***********************************************/                      00038000
                                                                            00039000
     ?RegEqu;                                                               00040000
     %include syslib(ssplxsrv);                                             00041000
     %include syslib(sstbind);                                              00042000
                                                                            00043000
     /***********************************************/                      00044000
     /* automatic storage                           */                      00045000
     /***********************************************/                      00046000
                                                                            00047000
     declare                                                                00048000
                                                                            00049000
      /* work variables */                                                  00050000
      p            pointer(31),                                             00051000
                                                                            00052000
      /* return and reason codes */                                         00053000
      rc           fixed(31),                                               00054000
      re           fixed(31);                                               00055000
                                                                            00056000
     /***********************************************/                      00057000
     /* protect the RAB                             */                      00058000
     /***********************************************/                      00059000
                                                                            00060000
     respecify (r12) restricted;                                            00061000
                                                                            00062000
     /******************************************************************/   00063000
     /* run our tests                                                  */   00064000
     /******************************************************************/   00065000
                                                                            00066000
     /******************************************************************/   00067000
     /* do a bunch of ssServiceBind calls                                   00068000
     /******************************************************************/   00069000
                                                                            00070000
     /*******************************/                                      00071000
     /* bind the ECHO service       */                                      00072000
     /*******************************/                                      00073000
                                                                            00074000
     p = 0;                                                                 00075000
     call ssServiceBind                                                     00076000
     (                                                                      00077000
      rc,                                                                   00078000
      re,                                                                   00079000
      c_ech_myname,                                                         00080000
      length(c_ech_myname),                                                 00081000
      p,                                                                    00082000
      addr(ep_ech_svthread),                                                00083000
      addr(ep_sst_term),                                                    00084000
      ss_srv_srvtype_normal                                                 00085000
     );                                                                     00086000
     if (rc^=ss_srv_rc_success ) then                                       00087000
      return code (-1);                                                     00088000
                                                                            00089000
     /*******************************/                                      00090000
     /* bind the SGEXER service     */                                      00091000
     /*******************************/                                      00092000
                                                                            00093000
     p = 0;                                                                 00094000
     call ssServiceBind                                                     00095000
     (                                                                      00096000
      rc,                                                                   00097000
      re,                                                                   00098000
      c_exr_myname,                                                         00099000
      length(c_exr_myname),                                                 00100000
      p,                                                                    00101000
      addr(ep_exr_svthread),                                                00102000
      addr(ep_sst_term),                                                    00103000
      ss_srv_srvtype_normal                                                 00104000
     );                                                                     00105000
     if (rc^=ss_srv_rc_success ) then                                       00106000
      return code (-1);                                                     00107000
                                                                            00108000
     /*******************************/                                      00109000
     /* bind the HTTP service       */                                      00110000
     /*******************************/                                      00111000
                                                                            00112000
     p = 0;                                                                 00113000
     call ssServiceBind                                                     00114000
     (                                                                      00115000
      rc,                                                                   00116000
      re,                                                                   00117000
      c_htt_myname,                                                         00118000
      length(c_htt_myname),                                                 00119000
      p,                                                                    00120000
      addr(ep_htt_svthread),                                                00121000
      addr(ep_sst_term),                                                    00122000
      ss_srv_srvtype_normal                                                 00123000
     );                                                                     00124000
     if (rc^=ss_srv_rc_success ) then                                       00125000
      return code(-1);                                                      00126000
                                                                            00127000
     /******************************************************************/   00128000
     /* now run the server program                                     */   00129000
     /******************************************************************/   00130000
                                                                            00131000
     call ssServerRun ( rc, re );                                           00132000
                                                                            00133000
     /******************************************************************/   00134000
     /* return to caller                                               */   00135000
     /******************************************************************/   00136000
                                                                            00137000
     /* all done */                                                         00138000
     return code (re);                                                      00139000
                                                                            00140000
     end rskmain;                                                           00141000
                                                                            00142000
    

    PROFILE RSK

    Shortly after you call ssServerRun, the RSK drives Rexx program PROFILE RSK. This is the RSK's profile file, and herein is where you do the work necessary to configure your server, start services, and perform other operator commands.

    Entry conditions for PROFILE RSK:

    • If you parse arg, you'll see the command line that started your server module.

    • Default subcommand handler is ADDRESS RSK, a subcom that interprets RSK operator commands.

    You should do several things in PROFILE RSK:

    1. Take care of basic initialization chores, such as linking and accessing appropriate disks, starting a log file, or whatever.

    2. Use the RSK's CONFIG command to set whatever configuration variables need setting, such as:
      • Names of important RSK files, such as authorization files or the user ID mapping file
      • The user ID of your system's RSCS machine
      • The size of the CP APPLDATA buffer
      • Any other variables appropriate for your application

    3. Issue the RUNSERV command. This activates the RSK's built-in services and line drivers and starts your server running.

    4. Issue line driver commands to connect your bound services to various line drivers. The following considerations apply:

      • TCP/IP: service's port number, adapter address, and number of sockets

      • UDP/IP: service's port number, adapter address, and number of concurrent requests

      • APPC/VM: service's transaction program name, resource type, and maximum number of concurrent clients

      • Spool: service's filename

      • Subcom: service's prefix

      • IUCV: service's CMSIUCV exit name and maximum number of concurrent clients

      • MSG: service's prefix

      • CONSOLE: service's prefix

      You will want to issue line driver commands to start both the RSK's built-in services (the operator command handlers) and the services you supplied. Be careful to put these commands into PROFILE RSK in the correct order.

    5. Issue the WAITSERV command to wait for the server to finish.

    6. When WAITSERV returns, do whatever cleanup chores are appropriate and then return to your caller. The return code you specify is returned to your RSKMAIN as the reason code returned by ssServerRun. Your response in RSKMAIN will probably be to reflect the return code onward via R15.

    Configuration Parameters

    The RSK defines a number of configuration parameters that control the way it operates. These parameters fall into a few broad categories:

    • They name certain important data files the RSK uses while it runs.

    • They describe whether the RSK is to perform authorization checking on the operator commands submitted to it.

    • They control the configuration of the monitor data the RSK collects.

    • They govern what the RSK is to do if it is unable to map a client's user ID from something transport-specific to something transport-independent.

    • They govern how certain RSK line drivers are to behave when said line drivers are confronted with client input that appears otherwise unprocessable.

    • They control the amounts of memory used by various portions of the RSK.

    All of these parameters are set via the operator command CONFIG.

    For example, the AUTHCHECK_ family of parameters controls whether the RSK's operator command processors are to perform authorization checking on the commands they handle. These parameters are:

    Parameter
    Controls the...
    AUTHCHECK_AUTH
    AUTH service
    AUTHCHECK_CMS
    CMS service
    AUTHCHECK_CACHE
    CACHE service
    AUTHCHECK_CONFIG
    CONFIG service
    AUTHCHECK_CP
    CP service
    AUTHCHECK_LD
    The RSK's line drivers
    AUTHCHECK_SERVER
    SERVER service
    AUTHCHECK_SGP
    SGP service
    AUTHCHECK_USERID
    USERID service
    AUTHCHECK_WORKER
    WORKER service

    The formal documentation contains a table explaining all of the configuration parameters and how they are used. You should take time to review the table and become familiar with the configuration parameters and what they do. You will be able to set up a successful PROFILE RSK only if you first understand how to set these configuration variables.


    Example

    /* */
     
    /********************************************************/
    /*                                                      */
    /* test profile for Reusable Server Kernel              */
    /*                                                      */
    /* remember that when this gets control, the default    */
    /* command environment is ADDRESS RSK                   */
    /*                                                      */
    /* You have to customize this to your environment       */
    /*                                                      */
    /* (C) Copyright 1998 International Business            */
    /*     Machines, Incorporated.  All Rights Reserved.    */
    /*                                                      */
    /********************************************************/
     
    /*
    parse arg what
    say 'Args: /'what'/'
    */
     
    sampledir = 'BKW.CRADLE.TEST'
     
    /************************************************/
    /* initialization things                        */
    /************************************************/
     
    /* grab the storage group disks */
    x = diag(8,'LINK BKW 1000 1000 MW')
    x = diag(8,'LINK BKW 1001 1001 MW')
    x = diag(8,'LINK BKW 1002 1002 MW')
    x = diag(8,'LINK BKW 1003 1003 MW')
    x = diag(8,'LINK BKW 1004 1004 MW')
    x = diag(8,'LINK BKW 1005 1005 MW')
    x = diag(8,'LINK BKW 1006 1006 MW')
    x = diag(8,'LINK BKW 1007 1007 MW')
     
    /************************************************/
    /* set names of key data files                  */
    /************************************************/
     
    'CONFIG SGP_FILE       SSTEST   VSSSGP  ' sampledir
    'CONFIG UMAP_FILE      SSTEST   VSSUMAP ' sampledir
     
    'CONFIG AUT_LOCATION   SFS'
    'CONFIG AUT_DATA_1     SSTEST   VSSAUD1 ' sampledir
    'CONFIG AUT_INDEX_1    SSTEST   VSSAUX1 ' sampledir
     
    /*
    'CONFIG AUT_LOG        SSTEST   VSSAUL  ' sampledir
    'CONFIG AUT_DATA_2     SSTEST   VSSAUD2 ' sampledir
    'CONFIG AUT_INDEX_2    SSTEST   VSSAUX2 ' sampledir
    */
     
    /************************************************/
    /* set the rest of the config stuff             */
    /************************************************/
     
    /* look up RSCS userid */
    address command 'IDENTIFY ( LIFO'
    parse pull . . . . rscsid .
    'CONFIG RSCS_USERID' rscsid
     
    /* set monitor data stuff */
    'CONFIG MON_PRODUCT_ID SSTEST-fnn010100'
    'CONFIG MON_KERNEL_ROWS 56'
    'CONFIG MON_USER_SIZE 0'
     
    /* set implicit command rerouting preferences */
    'CONFIG VM_CONSOLE ON'
    'CONFIG VM_SUBCOM  ON'
    'CONFIG VM_MSG     ON'
    'CONFIG VM_SPOOL   OFF'
     
    /* set unmapped userid preferences */
    'CONFIG NOMAP_APPC  OFF'
    'CONFIG NOMAP_IUCV  OFF'
    'CONFIG NOMAP_MSG   OFF'
    'CONFIG NOMAP_SPOOL OFF'
    'CONFIG NOMAP_TCP   OFF'
    'CONFIG NOMAP_UDP   OFF'
     
    /* set authorization memory controls */
    'CONFIG AUT_CACHE 10000'
    'CONFIG AUT_FREE  1000'
     
    /* turn on authorization checking */
    'CONFIG AUTHCHECK_AUTH    ON'
    'CONFIG AUTHCHECK_CACHE   ON'
    'CONFIG AUTHCHECK_CMS     ON'
    'CONFIG AUTHCHECK_CONFIG  ON'
    'CONFIG AUTHCHECK_CP      ON'
    'CONFIG AUTHCHECK_ENROLL  ON'
    'CONFIG AUTHCHECK_LD      ON'
    'CONFIG AUTHCHECK_MONITOR ON'
    'CONFIG AUTHCHECK_SERVER  ON'
    'CONFIG AUTHCHECK_SGP     ON'
    'CONFIG AUTHCHECK_USERID  ON'
    'CONFIG AUTHCHECK_WORKER  ON'
     
    /************************************************/
    /* run the server                               */
    /************************************************/
     
    'RUNSERV'
    if (rc<>0) then
    do
     say 'RC='rc 'from RUNSERV'
     return rc
    end
     
    /************************************************/
    /* server came up... set about making it go     */
    /************************************************/
     
    /************************************/
    /* start things that need to run    */
    /* via SUBCOM (used later herein)   */
    /************************************/
     
    'SUBCOM START APPC'
    'SUBCOM START AUTH'
    'SUBCOM START CACHE'
    'SUBCOM START CONSOLE'
    'SUBCOM START ENROLL'
    'SUBCOM START IUCV'
    'SUBCOM START MONITOR'
    'SUBCOM START MSG'
    'SUBCOM START SERVER'
    'SUBCOM START SGP'
    'SUBCOM START SPOOL'
    'SUBCOM START TCP'
    'SUBCOM START UDP'
    'SUBCOM START USERID'
    'SUBCOM START WORKER'
     
    /************************************/
    /* start base RSK services          */
    /************************************/
     
    'CONSOLE START APPC'
    'CONSOLE START AUTH'
    'CONSOLE START CACHE'
    'CONSOLE START CMS'
    'CONSOLE START CONFIG'
    'CONSOLE START CP'
    'CONSOLE START ENROLL'
    'CONSOLE START IUCV'
    'CONSOLE START MONITOR'
    'CONSOLE START MSG'
    'CONSOLE START SERVER'
    'CONSOLE START SGP'
    'CONSOLE START SPOOL'
    'CONSOLE START SUBCOM'
    'CONSOLE START TCP'
    'CONSOLE START UDP'
    'CONSOLE START USERID'
    'CONSOLE START WORKER'
     
    'MSG START APPC'
    'MSG START AUTH'
    'MSG START CACHE'
    'MSG START CMS'
    'MSG START CONFIG'
    'MSG START CONSOLE'
    'MSG START CP'
    'MSG START ENROLL'
    'MSG START IUCV'
    'MSG START MONITOR'
    'MSG START SERVER'
    'MSG START SGP'
    'MSG START SPOOL'
    'MSG START SUBCOM'
    'MSG START TCP'
    'MSG START USERID'
    'MSG START WORKER'
     
    /*
    'SPOOL START AUTH'
    'SPOOL START CMS'
    'SPOOL START CP'
    'SPOOL START SERVER'
    'SPOOL START SGP'
    'SPOOL START SUBCOM'
    'SPOOL START TCP'
    'SPOOL START USERID'
    */
    'SPOOL START ECHO'
     
    /************************************/
    /* start storage groups             */
    /************************************/
     
    'SGP START 0 t0   BLOCKRW NODS'
    'SGP START 1 t1   BLOCKRW NODS'
    'SGP START 2 t2   BLOCKRW NODS'
     
    /************************************/
    /* start sample server              */
    /************************************/
     
    'ENROLL LOAD HTTPCNFG DISK 0 HTTPCNFG VSSENR' sampledir
    'ENROLL LOAD HTTPMIME DISK 0 HTTPMIME VSSENR' sampledir
     
    'CACHE CREATE HTTPFILE 32768'
     
    'CONSOLE START ECHO'
    'CONSOLE START SGEXER'
     
    'MSG START ECHO'
    'MSG START SGEXER'
     
    'TCP START ECHO 426'
    'TCP START HTTP 428'
     
    'UDP START ECHO 526'
    'UDP START HTTP 528'
     
    'IUCV START ECHO 40'
    'IUCV REPORT ON'
     
    'APPC START ECHO GLOBAL 40 BKWG0000'
    'APPC REPORT ON'
     
    'WORKER ADD cgiserv TEST001'
    'WORKER ADD cgiserv TEST002'
     
    /************************************************/
    /* wait for server completion                   */
    /************************************************/
     
    'WAITSERV'
     
    /************************************************/
    /* do author-supplied termination logic         */
    /************************************************/
     
    /* void */
     
    return 0
     
    

    Structure of A Running Server

    The RSK organizes your server into a set of CMS threads. Each thread is in its own dispatch class. The following notes apply:

    • Each line driver is made up of a detector for its device and a thread that processes both device activity and IPCs from your application (your service threads).

    • The line drivers' detectors are:

      • The IUCV, TCP/IP, UDP/IP, APPC/VM, and MSG line drivers use HNDIUCV exits to detect device activity.

      • The SPOOL line driver uses an HNDIO exit.

      • The CONSOLE driver uses a CMS event monitor, listening for VMCON1ECB.

      • The SUBCOM line driver sets up a subcom via SUBCOM SET.

      All of these detectors do basically the same thing - they capture information about the device activity and send an IPC message to the line driver's queue so as to awaken the line driver thread and thereby cause it to handle the device.

    • The line driver threads wait in QueueReceiveBlock for messages to arrive (each line driver has its own queue). When an IPC message arrives, the line driver thread wakes up and handles the request:

      • Device activity: handle the device activity

      • Request from a service instance: handle the request

    • Depending on client activity, there might be one or more instance threads running. When there is no work to do, these threads are waiting in QueueReceiveBlock. As work arrives for them, the line drivers awaken them by sending them IPC messages telling them what's happened.

    • The RSK supplies certain built-in services. These, like your services, wait in QueueReceiveBlock for work to do. When work arrives, they handle it and respond through their line drivers.

    Interacting with Line Drivers

    There are many aspects to interacting with line drivers:

    • The line driver's behavior, generally speaking

    • Your initialization routine

    • Your service routine

    • Your termination routine

    • Connecting your service to a line driver

    • Use of CMS IPC

    • The ssClient APIs

    Line Driver Behavior

    When a new client arrives, the line driver either creates a thread to handle the client or takes a thread from a free pool it maintains. In either case, the thread is caused to begin running the service entry point for the service to which the client has connected. The thread runs until your service routine returns.

    This means that your service will probably be running on multiple threads simultaneously. Even the "mundane" line drivers, like CONSOLE, do this. Be prepared for this behavior.

    For example, if you used ssServiceBind to define a service called MYSERV, and if you informed the UDP/IP line driver that it was to make MYSERV available on port 992, then when a datagram arrived at port 992, the UDP line driver would arrange for a thread to call MYSERV's service entry point. This would transfer control to your code.

    Your service routine uses QueueReceiveBlock to learn of work needing its attention. For each received message, your code performs the appropriate action and calls QueueReceiveBlock again.

    Eventually it is time for the relationship with the client to end. At this point your code sends an IPC message to its line driver to inform the line driver that the relationship is terminated. Your code then returns to its caller.


    Entry Points

    Your service is made up of three routines (entry points):

    • An initialization routine, which the RSK drives just prior to delivering client activity to your service.

    • A service routine, which the RSK drives each time it routes a client to your service. The service routine runs on its own thread and uses CMS IPC to wait for client activity.

    • A termination routine, which the RSK drives when it determines that your service will not handle any more clients.

    Initialization Entry Point

    When it drives your initialization routine, the RSK passes your routine the following OS Type I parameter list (R1 points to this vector):

    Offset
    Use
    0
    A(return code)
    4
    A(reason code)
    8
    A(S-block)

    The return code and reason code are outputs which your routine must supply. If either supplied value is non-zero, the RSK will abandon its attempt to start your service. The S-block pointer is an input. The S-block is an RSK control block providing fundamental descriptive information about the service being started. See the documentation for more information.

    The initialization routine's job is to perform any initialization functions that are service-specific.

    Service Entry Point

    Each time a client arrives, the RSK drives your service entry point on a dedicated thread. The RSK builds the following parameter list for the service entry point:

    Offset
    Use
    0
    A(S-block)
    4
    A(C-block)

    As mentioned earlier, the S-block provides descriptive information about the particular service in question. The C-block provides descriptive information about the relationship between the client, the RSK, and the service thread (also called the instance).

    The C-block is probably the most important data structure the RSK builds for the application. It contains information crucial to the correct operation of your service, such as:

    • The handle of the queue the instance should use when it receives and transmits IPC messages
    • The match key the instance should use when it attempts to receive IPC messages
    • The message key the instance should use when it transmits messages to its line driver
    • The mapped user ID of the client
    • Counters showing how much data has moved through the instance

    See the documentation for more information.

    Termination Entry Point

    When the RSK drives your termination routine, it supplies the following parameter list:

    Offset
    Use
    0
    A(S-block)

    The termination routine's job is to perform any termination functions that are service-specific.


    Connecting Your Service to a Line Driver

    You use a line driver's START command to connect your service to a line driver. When you connect your service to a line driver, you make it possible for your service to interact with clients who send requests to your server via the line driver's transport method.

    Each RSK line driver supports a START command which nominates the service to be started and which gives transport-specific information about how the line driver is to prepare to be contacted by clients. Specifically,

    • TCP/IP: service's port number, adapter address, and number of sockets

    • UDP/IP: service's port number, adapter address, and number of concurrent requests

    • APPC/VM: service's transaction program name, resource type, and maximum number of concurrent clients

    • Spool: service's filename

    • Subcom: service's prefix

    • IUCV: service's CMSIUCV exit name and maximum number of concurrent clients

    • MSG: service's prefix

    • CONSOLE: service's prefix

    You can issue these commands via PROFILE RSK, or by hand, or via some kind of programmable operator.


    Use of CMS IPC

    Messages to Instance

    When the instance gets control, its job is to wait to be told about client activity and then process whatever client activity occurred.

    The waiting is accomplished via QueueReceiveBlock. The following information will be helpful in constructing the call:

    QRB Parameter
    Source
    Queue handle
    Comes from C-block
    Match key
    Comes from C-block

    When QueueReceiveBlock returns, it will supply a message in the following form:

    Field
    Use
    0.32
    Instance's key
    32.4
    Message type
    0
    Message from line driver to instance
    36.2
    Client status bits
    X'8000'
    Client has closed connection
    X'4000'
    Connection closed abnormally
    X'2000'
    Client has finished transmitting
    X'1000'
    RSK line driver is asking that you stop
    X'0800'
    New data is available from client

    When you receive this message, you should act on the bits in the following way:

    1. If connection closed abnormally or client has closed connection or RSK line driver is asking you to stop, clean up from the handling of this client, transmit the termination message to the line driver, and return.

    2. If new data is available, process it, via one or more calls to ssClientDataGet. This will probably result in one or more calls to ssClientDataPut.

    3. If client is done sending, send any last response data to the client, clean up from the handling of this client, transmit the termination message to the line driver, and return.

    4. If you have not yet encountered a reason to exit, go back and do another QueueReceiveBlock.

    Message to Line Driver

    When the instance queues data for the client, or when the instance otherwise requires the line driver to take some action, the instance informs the line driver of this need by sending it a CMS IPC message via call to QueueSend. The message is to be built in the following way:

    0.32
    Line driver's key (from C-block)
    32.4
    Message type
    1
    Message from instance to line driver
    36.32
    Instance's key (from C-block)
    68.2
    Instance status bits
    X'8000'
    Instance is stopping
    X'4000'
    Instance queued output for client

    The message should be sent to the line driver queue as identified by the queue handle field of the C-block.

    If the instance is using this message to inform the line driver that it is terminating, it should return to its caller after it transmits the message.


    The ssClient APIs

    When the line driver informs the instance that data are waiting from the client, the instance should respond by calling ssClientDataGet. This routine has the following features:

    • You can retrieve the data destructively or non-destructively.

    • You can have the data retrieved to a VM Data Space.

    • You can determine how much data is waiting to be retrieved without actually retrieving anything.

    • After your retrieval operation completes, you are always told how much additional data waits to be retrieved.

    When your instance is ready to write to the client, it should use routine ssClientDataPut. This routine has the following features:

    • The data buffer you supply can reside in a VM Data Space.

    • After your output is queued, the RSK counts the number of bytes waiting to be transmitted and returns this number to you as an output.

    Example

     @PROCESS TITLE('BKWRST - ep_rec_svthread')                             00001000
              ENVIRONMENT(VM/ESAOS) OPT(MAX) FLAG(I);                       00002000
                                                                            00003000
     /* @LIST OFF; */                                                       00004000
     @EJECT;                                                                00005000
                                                                            00006000
    */*START OF SPECIFICATION*********************************************/ 00007000
    */*                                                                  */ 00008000
    */*                       PROLOGUE                                   */ 00009000
    */*                                                                  */ 00010000
    */* MODULE-NAME:  BKWRST                                             */ 00011000
    */*                                                                  */ 00012000
    */* DESCRIPTIVE-NAME: ep_rec_svthread                                */ 00013000
    */*                                                                  */ 00014000
    */*   COPYRIGHT =                                                    */ 00015000
     GENERATE;/*                                                            00016000
     *      THIS MODULE IS "RESTRICTED MATERIAL OF IBM"                     00017000
     *      5799-EFR (C) COPYRIGHT IBM CORP. 1991                           00018000
     *      LICENSED MATERIALS-PROPERTY OF IBM                              00019000
     *      SEE COPYRIGHT INSTRUCTIONS, G120-2083                           00020000
     *                                                                      00021000
     @ENDGEN;*/                                                             00022000
    */*                                                                  */ 00023000
    */* STATUS: VM/ESA Version 2 Release 3.0                             */ 00024000
    */*                                                                  */ 00025000
    */* FUNCTION: service thread for generalized line-mode service       */ 00026000
    */*                                                                  */ 00027000
    */* NOTES:                                                           */ 00028000
    */*    DEPENDENCIES: None                                            */ 00029000
    */*    RESTRICTIONS: None                                            */ 00030000
    */*    REGISTER-CONVENTIONS: R1  - List of ptrs to the parameters    */ 00031000
    */*                          R12 - RAB address                       */ 00032000
    */*                          R13 - dynamic storage area              */ 00033000
    */*                          R14 - Return address                    */ 00034000
    */*                          R15 - Entry point address               */ 00035000
    */*    PATCH-LABEL: None                                             */ 00036000
    */*                                                                  */ 00037000
    */* MODULE-TYPE: Procedure                                           */ 00038000
    */*    PROCESSOR: PL/X                                               */ 00039000
    */*    MODULE-SIZE: refer to assembler listing                       */ 00040000
    */*    ATTRIBUTES: MP-capable, enabled, AMODE 31, RMODE ANY          */ 00041000
    */*                                                                  */ 00042000
    */* ENTRY-POINT:  see MODULE-NAME                                    */ 00043000
    */*                                                                  */ 00044000
    */* PURPOSE:  see FUNCTION                                           */ 00045000
    */*                                                                  */ 00046000
    */* LINKAGE:                                                         */ 00047000
    */*  OS Type I call, with the addition that R12                      */ 00048000
    */*  points to the RAB (runtime anchor block), a data structure      */ 00049000
    */*  used for managing the stack                                     */ 00050000
    */*                                                                  */ 00051000
    */* INPUT: See procedure statement                                   */ 00052000
    */*                                                                  */ 00053000
    */* OUTPUT: See procedure statement                                  */ 00054000
    */*                                                                  */ 00055000
    */* EXIT-NORMAL: as follows:                                         */ 00056000
    */*                                                                  */ 00057000
    */* EXIT-ERROR: as follows:                                          */ 00058000
    */*                                                                  */ 00059000
    */* EXTERNAL REFERENCES:                                             */ 00060000
    */*                                                                  */ 00061000
    */*    ROUTINES:                                                     */ 00062000
    */*                                                                  */ 00063000
    */*    CONTROL-BLOCKS: ....                                          */ 00064000
    */*                                                                  */ 00065000
    */* CALLED-BY: ......                                                */ 00066000
    */*                                                                  */ 00067000
    */* SUBROUTINES: None                                                */ 00068000
    */*                                                                  */ 00069000
    */* ERROR MESSAGES: None                                             */ 00070000
    */*                                                                  */ 00071000
    */* MACROS:                                                          */ 00072000
    */*                                                                  */ 00073000
    */* CHANGE-ACTIVITY:                                                 */ 00074000
    */*                                                                  */ 00075000
    */* OPERATION:                                                       */ 00076000
    */*                                                                  */ 00077000
    */*    1)                                                            */ 00078000
    */*                                                                  */ 00079000
    */*    2)                                                            */ 00080000
    */*                                                                  */ 00081000
    */*                                                                  */ 00082000
    */*END OF SPECIFICATION***********************************************/ 00083000
    */* A000000-999999     NEW FOR VM/ESA Version 2 Release 3.0  @VR74PVM*/ 00084000
    */********************************************************************/ 00085000
     @EJECT COMPILE ASM;                                                    00086000
                                                                            00087000
     ep_rec_svthread: procedure                                             00088000
     (                                                                      00089000
      pl_sblock,                        /* my S-block          */           00090000
      pl_cblock                         /* my C-block          */           00091000
     )                                                                      00092000
     options                                                                00093000
     (                                                                      00094000
      id                                /* generates identifier  */         00095000
      reentrant                         /* no static data pls    */         00096000
      amode(31)                         /* 31-bit addresses      */         00097000
      rmode(any)                        /* can reside anywhere   */         00098000
      datareg(13)                       /* R13 is stack ptr      */         00099000
      savearea(120)                     /* size of a save area   */         00100000
      stack('SSPRLG ','SSEPIL ')        /* hi-perf auto stg mgmt */         00101000
     );                                                                     00102000
                                                                            00103000
     /* parameters */                                                       00104000
     declare                                                                00105000
      pl_sblock  pointer(31),                                               00106000
      pl_cblock  pointer(31);                                               00107000
                                                                            00108000
     /*******************************************/                          00109000
     /* macros                                  */                          00110000
     /*******************************************/                          00111000
                                                                            00112000
     ?RegEqu;                         /* registers          */              00113000
     %include syslib(vmplxmtr);       /* CMS bindings       */              00114000
     %include syslib(vmplxipc);       /* CMS bindings       */              00115000
                                                                            00116000
     %include syslib(ssplxmem);       /* skySgpXxx bindings */              00117000
     %include syslib(ssplxsrv);       /* skyService stuff   */              00118000
     %include syslib(ssplxcli);       /* skyService stuff   */              00119000
                                                                            00120000
     %include syslib(bkwgen);        /* internal bindings  */               00121000
     %include syslib(bkwrec);                                               00122000
     %include syslib(bkwusi);        /* I am USERID...     */               00123000
     %include syslib(bkwsrv);        /* ... or SERVER...   */               00124000
     %include syslib(bkwcfg);        /* ... or CONFIG...   */               00125000
     %include syslib(bkwtcp);        /* ... or TCP...      */               00126000
     %include syslib(bkwaut);        /* ... or AUTH...     */               00127000
     %include syslib(bkwsgp);        /* ... or SGP...      */               00128000
     %include syslib(bkwcp);         /* ... or CP...       */               00129000
     %include syslib(bkwenr);        /* ... or ENROLL...   */               00130000
     %include syslib(bkwmon);        /* ... or MONITOR...  */               00131000
     %include syslib(bkwcac);        /* ... or CACHE...    */               00132000
     %include syslib(bkwicv);        /* ... or IUCV...     */               00133000
     %include syslib(bkwwrk);        /* ... or WORKER...   */               00134000
     %include syslib(bkwnam);        /* names of things    */               00135000
                                                                            00136000
     /*******************************************/                          00137000
     /* based variables                         */                          00138000
     /*******************************************/                          00139000
                                                                            00140000
     declare                                                                00141000
      word      fixed(31) based,      /* a full word    */                  00142000
      halfword  fixed(16) based,      /* a halfword     */                  00143000
      byte      fixed(8) based,       /* a byte         */                  00144000
      chars     character(*) based;   /* char string    */                  00145000
                                                                            00146000
     /*******************************************/                          00147000
     /* automatic storage                       */                          00148000
     /*******************************************/                          00149000
                                                                            00150000
     declare                                                                00151000
                                                                            00152000
      /* anchor stuff */                                                    00153000
      skya      pointer(31),                                                00154000
                                                                            00155000
      /* my subpool */                                                      00156000
      my_subpool         char(8),           /* my subpool       */          00157000
                                                                            00158000
      /* rc/re for CSL calls */                                             00159000
      rc                 fixed(31),         /* return code  */              00160000
      re                 fixed(31),         /* reason code  */              00161000
                                                                            00162000
      /* preallocated message buffers */                                    00163000
      mb                 character(length(vmss_imsg)),                      00164000
      rb                 character(length(vmss_lmsg)),                      00165000
                                                                            00166000
      /* pointers to said buffers */                                        00167000
      mp                 pointer(31),       /* msg pointer     */           00168000
      rp                 pointer(31),       /* reply pointer   */           00169000
                                                                            00170000
      /* stuff for QueueReceiveBlock */                                     00171000
      ml                 fixed(31),         /* msg length      */           00172000
      ko                 fixed(31),         /* key offset      */           00173000
      kl                 fixed(31),         /* key length      */           00174000
      suid               character(8),      /* sender UID      */           00175000
      spid               fixed(31),         /* sender PID      */           00176000
      reptok             fixed(31),         /* reply token     */           00177000
                                                                            00178000
      /* stuff for working off commands */                                  00179000
      curcmdbuf     char(1024),     /* cmd buffer   */                      00180000
      curcmdptr     pointer(31),    /* cmd pointer  */                      00181000
      curcmdlen     fixed(31),      /* cmd length   */                      00182000
                                                                            00183000
      /* record of whether i made any output */                             00184000
      imadeoutput   fixed(31),                                              00185000
                                                                            00186000
      /* work variables */                                                  00187000
      i             fixed(31),      /* work variable */                     00188000
      j             fixed(31),      /* work variable */                     00189000
      k             fixed(31),      /* work variable */                     00190000
      p             pointer(31);    /* work pointer  */                     00191000
                                                                            00192000
     /*************************************************/                    00193000
     /* protect runtime                               */                    00194000
     /*************************************************/                    00195000
                                                                            00196000
     respecify (r12) restricted;                                            00197000
                                                                            00198000
     /*********************************************************/            00199000
     /* CODE BEGINS HERE                                      */            00200000
     /*********************************************************/            00201000
                                                                            00202000
     call ep_get_anchor ( skya );                                           00203000
                                                                            00204000
     /* might as well do this now */                                        00205000
     curcmdptr = addr(curcmdbuf(5));                                        00206000
                                                                            00207000
     /* and decide who I am */                                              00208000
     call choose_subpool;                                                   00209000
                                                                            00210000
     /* set up buffer pointers */                                           00211000
     mp = addr(mb);                                                         00212000
     rp = addr(rb);                                                         00213000
                                                                            00214000
     /*****************************************************************/    00215000
     /* here's the big service loop.  just do a receive, using my     */    00216000
     /* instance key from the C-block as the receive key.  everything */    00217000
     /* i have to pay attention to will come to me as an IPC message  */    00218000
     /* keyed according to my instance key.  when the receive is      */    00219000
     /* complete, then examine the message further to see what I      */    00220000
     /* have to do with this new piece of work.                       */    00221000
     /*****************************************************************/    00222000
                                                                            00223000
     do forever;                                                            00224000
                                                                            00225000
      /* i haven't made output yet */                                       00226000
      imadeoutput = 0;                                                      00227000
                                                                            00228000
      /****************************************************************/    00229000
      /* receive notice of more work.                                 */    00230000
      /****************************************************************/    00231000
                                                                            00232000
      /* wait for something to do */                                        00233000
      call QueueReceiveBlock                                                00234000
      (                                                                     00235000
       rc,                                /* return code  */                00236000
       re,                                /* reason code  */                00237000
       pl_cblock->vmss_cblock.vc_qh,      /* queue handle */                00238000
       pl_cblock->vmss_cblock.vc_ikey,    /* match key    */                00239000
       length(vmss_cblock.vc_ikey),       /* its length   */                00240000
       0,                                 /* timeout      */                00241000
       mp->chars,                         /* msg buffer   */                00242000
       length(mb),                        /* its length   */                00243000
       ml,                                /* msg length   */                00244000
       ko,                                /* key offset   */                00245000
       kl,                                /* key length   */                00246000
       suid,                              /* sender UID   */                00247000
       spid,                              /* sender PID   */                00248000
       reptok                             /* reply token  */                00249000
      );                                                                    00250000
      if (rc^=vm_ipc_success) then                                          00251000
       goto done;                                                           00252000
                                                                            00253000
      /**************************************************************/      00254000
      /* process work received.                                     */      00255000
      /**************************************************************/      00256000
                                                                            00257000
      /*******************************************************/             00258000
      /* pay attention to what my line driver is telling me  */             00259000
      /* in the vi_cbits field of the message it sent.  it   */             00260000
      /* might be telling me that something is up with my    */             00261000
      /* client and that I need to do something instead of   */             00262000
      /* working off the input queue.  recall these bits     */             00263000
      /* are:                                                */             00264000
      /*                                                     */             00265000
      /*  vi_b_cclose         client has closed connection   */             00266000
      /*  vi_b_aclose         connection closed abnormally   */             00267000
      /*  vi_b_newdata        there is new data on queue     */             00268000
      /*  vi_b_cdone          client is done sending         */             00269000
      /*  vi_b_ldstop         line driver says STOP          */             00270000
      /*                                                     */             00271000
      /* if the client has closed or the connection has      */             00272000
      /* closed abnormally, we're done; don't even bother    */             00273000
      /* working off any pending client input.               */             00274000
      /*                                                     */             00275000
      /*******************************************************/             00276000
                                                                            00277000
      if ( (mp->vi_b_cclose=1) |                                            00278000
           (mp->vi_b_aclose=1) |                                            00279000
           (mp->vi_b_ldstop=1)   ) then                                     00280000
       goto done;                                                           00281000
                                                                            00282000
      if (mp->vi_b_newdata=0) then                                          00283000
       goto cmdsdone;                                                       00284000
                                                                            00285000
      /*******************************************************/             00286000
      /* work off every whole command in the client queue.   */             00287000
      /*******************************************************/             00288000
                                                                            00289000
      do forever;                                                           00290000
                                                                            00291000
       /**************************************************/                 00292000
       /* see if there is another command in the queue.  */                 00293000
       /**************************************************/                 00294000
                                                                            00295000
       /* grab command length */                                            00296000
       p = addr(curcmdlen);                                                 00297000
       call ssClientDataGet                                                 00298000
       (                                                                    00299000
        rc,                    /* return code     */                        00300000
        re,                    /* reason code     */                        00301000
        ss_cli_iam_instance,   /* i am instance   */                        00302000
        pl_cblock,             /* C-block ptr     */                        00303000
        ss_cli_method_peek,    /* peek it         */                        00304000
        0,                     /* ALET            */                        00305000
        p->chars,              /* to here         */                        00306000
        4,                     /* four bytes      */                        00307000
        i,                     /* amt given       */                        00308000
        j                      /* amt additional  */                        00309000
       );                                                                   00310000
       if ((rc^=0) | (i<4)) then                                            00311000
        goto cmdsdone;                                                      00312000
                                                                            00313000
       /* not all here? */                                                  00314000
       if (j < curcmdlen) then                                              00315000
        goto cmdsdone;                                                      00316000
                                                                            00317000
       /* there's enough... grab it */                                      00318000
       i = curcmdlen + 4;                                                   00319000
       call ssClientDataGet                                                 00320000
       (                                                                    00321000
        rc,                    /* return code     */                        00322000
        re,                    /* reason code     */                        00323000
        ss_cli_iam_instance,   /* i am instance   */                        00324000
        pl_cblock,             /* C-block ptr     */                        00325000
        ss_cli_method_read,    /* read it         */                        00326000
        0,                     /* ALET            */                        00327000
        curcmdbuf,             /* to here         */                        00328000
        i,                     /* amount to get   */                        00329000
        j,                     /* amt given       */                        00330000
        k                      /* amt left        */                        00331000
       );                                                                   00332000
                                                                            00333000
       /*******************************************************/            00334000
       /* perform the command.  do_command will use the       */            00335000
       /* ssClientDataPut routine to queue output for the     */            00336000
       /* client, and via return code it will signal me       */            00337000
       /* whether it did so.                                  */            00338000
       /*******************************************************/            00339000
                                                                            00340000
       /* handle command */                                                 00341000
       i = curcmdlen;                                                       00342000
                                                                            00343000
       select;                                                              00344000
                                                                            00345000
        /* am I AUTH? */                                                    00346000
        when (my_subpool = c_aut_subpool)                                   00347000
         call ep_aut_do_command                                             00348000
         (                                                                  00349000
          skya,                           /* big pointer     */             00350000
          pl_cblock,                      /* my C-block      */             00351000
          curcmdptr->chars,               /* command buffer  */             00352000
          i,                              /* command length  */             00353000
          rc                              /* return code     */             00354000
         );                                                                 00355000
                                                                            00356000
        /* am I CACHE? */                                                   00357000
        when (my_subpool = c_csv_subpool)                                   00358000
         call ep_csv_do_command                                             00359000
         (                                                                  00360000
          skya,                           /* big pointer     */             00361000
          pl_cblock,                      /* my C-block      */             00362000
          curcmdptr->chars,               /* command buffer  */             00363000
          i,                              /* command length  */             00364000
          rc                              /* return code     */             00365000
         );                                                                 00366000
                                                                            00367000
        /* am I CMS? */                                                     00368000
        when (my_subpool = c_cms_subpool)                                   00369000
         call ep_cms_do_command                                             00370000
         (                                                                  00371000
          skya,                           /* big pointer     */             00372000
          pl_cblock,                      /* my C-block      */             00373000
          curcmdptr->chars,               /* command buffer  */             00374000
          i,                              /* command length  */             00375000
          rc                              /* return code     */             00376000
         );                                                                 00377000
                                                                            00378000
        /* am I CONFIG? */                                                  00379000
        when (my_subpool = c_cfg_subpool)                                   00380000
         call ep_cfg_do_command                                             00381000
         (                                                                  00382000
          skya,                           /* big pointer     */             00383000
          pl_cblock,                      /* my C-block      */             00384000
          curcmdptr->chars,               /* command buffer  */             00385000
          i,                              /* command length  */             00386000
          rc                              /* return code     */             00387000
         );                                                                 00388000
                                                                            00389000
        /* am I CP? */                                                      00390000
        when (my_subpool = c_cp_subpool)                                    00391000
         call ep_cp_do_command                                              00392000
         (                                                                  00393000
          skya,                           /* big pointer     */             00394000
          pl_cblock,                      /* my C-block      */             00395000
          curcmdptr->chars,               /* command buffer  */             00396000
          i,                              /* command length  */             00397000
          rc                              /* return code     */             00398000
         );                                                                 00399000
                                                                            00400000
        /* am I ENROLL? */                                                  00401000
        when (my_subpool = c_enr_subpool)                                   00402000
         call ep_enr_do_command                                             00403000
         (                                                                  00404000
          skya,                           /* big pointer     */             00405000
          pl_cblock,                      /* my C-block      */             00406000
          curcmdptr->chars,               /* command buffer  */             00407000
          i,                              /* command length  */             00408000
          rc                              /* return code     */             00409000
         );                                                                 00410000
                                                                            00411000
        /* am I IUCV or APPC? */                                            00412000
        when ( (my_subpool = c_icv_subpool) |                               00413000
               (my_subpool = c_apc_subpool)   )                             00414000
         call ep_icv_do_command                                             00415000
         (                                                                  00416000
          skya,                           /* big pointer     */             00417000
          pl_cblock,                      /* my C-block      */             00418000
          curcmdptr->chars,               /* command buffer  */             00419000
          i,                              /* command length  */             00420000
          rc                              /* return code     */             00421000
         );                                                                 00422000
                                                                            00423000
        /* am I MONITOR? */                                                 00424000
        when (my_subpool = c_msv_subpool)                                   00425000
         call ep_mon_do_command                                             00426000
         (                                                                  00427000
          skya,                           /* big pointer     */             00428000
          pl_cblock,                      /* my C-block      */             00429000
          curcmdptr->chars,               /* command buffer  */             00430000
          i,                              /* command length  */             00431000
          rc                              /* return code     */             00432000
         );                                                                 00433000
                                                                            00434000
        /* am I SERVER? */                                                  00435000
        when (my_subpool = c_srv_subpool)                                   00436000
         call ep_srv_do_command                                             00437000
         (                                                                  00438000
          skya,                           /* big pointer     */             00439000
          pl_cblock,                      /* my C-block      */             00440000
          curcmdptr->chars,               /* command buffer  */             00441000
          i,                              /* command length  */             00442000
          rc                              /* return code     */             00443000
         );                                                                 00444000
                                                                            00445000
        /* am I SGP? */                                                     00446000
        when (my_subpool = c_sgp_subpool)                                   00447000
         call ep_sgp_do_command                                             00448000
         (                                                                  00449000
          skya,                           /* big pointer     */             00450000
          pl_cblock,                      /* my C-block      */             00451000
          curcmdptr->chars,               /* command buffer  */             00452000
          i,                              /* command length  */             00453000
          rc                              /* return code     */             00454000
         );                                                                 00455000
                                                                            00456000
        /* am I TCP or UDP? */                                              00457000
        when ( (my_subpool = c_tcp_subpool) |                               00458000
               (my_subpool = c_udp_subpool) )                               00459000
         call ep_tcp_do_command                                             00460000
         (                                                                  00461000
          skya,                           /* big pointer     */             00462000
          pl_cblock,                      /* my C-block      */             00463000
          curcmdptr->chars,               /* command buffer  */             00464000
          i,                              /* command length  */             00465000
          rc                              /* return code     */             00466000
         );                                                                 00467000
                                                                            00468000
        /* am I USERID? */                                                  00469000
        when (my_subpool = c_uid_subpool)                                   00470000
         call ep_uid_do_command                                             00471000
         (                                                                  00472000
          skya,                           /* big pointer     */             00473000
          pl_cblock,                      /* my C-block      */             00474000
          curcmdptr->chars,               /* command buffer  */             00475000
          i,                              /* command length  */             00476000
          rc                              /* return code     */             00477000
         );                                                                 00478000
                                                                            00479000
        /* am I WORKER? */                                                  00480000
        when (my_subpool = c_wrk_subpool)                                   00481000
         call ep_wrk_do_command                                             00482000
         (                                                                  00483000
          skya,                           /* big pointer     */             00484000
          pl_cblock,                      /* my C-block      */             00485000
          curcmdptr->chars,               /* command buffer  */             00486000
          i,                              /* command length  */             00487000
          rc                              /* return code     */             00488000
         );                                                                 00489000
                                                                            00490000
        /* I'm not anyone? */                                               00491000
        otherwise                                                           00492000
         Generate ( DC X'0000' );                                           00493000
                                                                            00494000
       end; /* select */                                                    00495000
                                                                            00496000
       /* keep track of output */                                           00497000
       imadeoutput = imadeoutput + rc;                                      00498000
                                                                            00499000
      end; /* do forever */                                                 00500000
                                                                            00501000
      /*******************************************************/             00502000
      /* all commands complete.  if i made output, tell      */             00503000
      /* the line driver.  then handle whether the line      */             00504000
      /* driver is telling me to stop.                       */             00505000
      /*******************************************************/             00506000
                                                                            00507000
      cmdsdone:                                                             00508000
                                                                            00509000
      /* notify driver if needed */                                         00510000
      if (imadeoutput^=0) then                                              00511000
      do;                                                                   00512000
                                                                            00513000
       /* build message for line driver */                                  00514000
       rp->vl_lkey = pl_cblock->vmss_cblock.vc_lkey;                        00515000
       rp->vl_type = ss_srv_msgtype_linedriver;                             00516000
       rp->vl_ikey = pl_cblock->vmss_cblock.vc_ikey;                        00517000
       rp->vl_ibits = 0;                                                    00518000
       rp->vl_b_newdata = 1;                                                00519000
                                                                            00520000
       /* tell line driver i made some output */                            00521000
       call QueueSend                                                       00522000
       (                                                                    00523000
        rc,                               /* return code     */             00524000
        re,                               /* reason code     */             00525000
        pl_cblock->vmss_cblock.vc_qh,     /* ld queue handle */             00526000
        rp->chars,                        /* message buffer  */             00527000
        length(rb),                       /* message length  */             00528000
        offset(vl_lkey),                  /* key offset      */             00529000
        length(vl_lkey)                   /* key length      */             00530000
       );                                                                   00531000
                                                                            00532000
      end; /* i made output */                                              00533000
                                                                            00534000
      /* stop if needed */                                                  00535000
      if (mp->vi_b_cdone=1) then                                            00536000
       goto done;                                                           00537000
                                                                            00538000
      /**************************************************************/      00539000
      /* PROCESSING OF IPC MESSAGE HAS COMPLETED                    */      00540000
      /**************************************************************/      00541000
                                                                            00542000
     end; /* do forever */                                                  00543000
                                                                            00544000
     /*****************************************************************/    00545000
     /* end of big service loop                                       */    00546000
     /*****************************************************************/    00547000
                                                                            00548000
     done:                                                                  00549000
                                                                            00550000
     /* emit 'I stopped' message */                                         00551000
     rp->vl_lkey = pl_cblock->vmss_cblock.vc_lkey;                          00552000
     rp->vl_type = ss_srv_msgtype_linedriver;                               00553000
     rp->vl_ikey = mp->vi_ikey;                                             00554000
     rp->vl_ibits = 0;                                                      00555000
     rp->vl_b_stopack = 1;                                                  00556000
                                                                            00557000
     /* and ship it to my line driver */                                    00558000
     call QueueSend                                                         00559000
     (                                                                      00560000
      rc,                                  /* return code    */             00561000
      re,                                  /* reason code    */             00562000
      pl_cblock->vmss_cblock.vc_qh,        /* queue handle   */             00563000
      rp->chars,                           /* message buffer */             00564000
      length(rb),                          /* message length */             00565000
      offset(vl_lkey),                     /* key offset     */             00566000
      length(vl_lkey)                      /* key length     */             00567000
     );                                                                     00568000
                                                                            00569000
     /* and return! */                                                      00570000
     return code(0);                                                        00571000
                                                                            00572000
     /*****************************************************************/    00573000
     /* local procedures implemented as macros                        */    00574000
     /*****************************************************************/    00575000
                                                                            00576000
     %include syslib(plxdll);                                               00577000
     %include syslib(bkwrcs);                                               00578000
                                                                            00579000
     end ep_rec_svthread;                                                   00580000
                                                                            00581000
    

    Anchors

    The RSK provides a simple callable anchor facility that lets the server author set and query the value of a server-wide anchor word. This facility complements the function available through CSL routine ThreadSetUserData.

    The envisioned use for the RSK's facility is that early on in the life of the server, the author's code will call ssAnchorSet to install the value of the anchor word. This anchor word would probably be the address of some main control block. At other times as necessary, the author's code would call ssAnchorGet to retrieve the value of the anchor word, thereby obtaining (for example) the address of the main control block.

    Routine ssAnchorGet also returns the address and length of the CP APPLDATA buffer the RSK maintains for the server. The author's code can place important counters or other values into the monitor buffer and they will be collected in APPLDATA records as part of CP's monitor data processing.


    APIs

    • ssAnchorSet: set value of anchor word

    • ssAnchorGet: retrieve value of anchor word and address of user monitor buffer

    Example

     
     /* bindings */
     %include syslib(ssplxanc);
     
     
     /* automatic variables */
     declare
      rc          fixed(31),
      re          fixed(31),
      anchor      pointer(31),
      monbufptr   pointer(31),
      monbuflen   fixed(31);
     
     
     /* to set the anchor */
     call ssAnchorSet ( rc, re, anchor );
     
     
     /* to retrieve the anchor and the monitor info */
     call ssAnchorGet ( rc, re, anchor, monbufptr, monbuflen );
     
    

    Memory Management

    The RSK provides a callable memory API that front-ends CMS's CMSSTOR facility. This API offers the additional feature that it can allocate and release storage in VM Data Spaces. Use of VM Data Spaces is subject to any limits imposed by the server's CP directory entry (statement XCONFIG ADDRSPACE).


    APIs

    ssMemoryCreateDS

    To use the RSK's memory API with VM Data Spaces, the first step is to create a "subpool" to represent the data space. Here is an example call:

     
     %include syslib(ssplxmem);
     
     declare
      rc           fixed(31),
      re           fixed(31),
      subpool      char(8),
      pagecount    fixed(31),
      storkey      fixed(31),
      optcount     fixed(31),
      optarray(4)  fixed(31),
      asit         char(8),
      alet         fixed(31);
     
     subpool = 'MYDSPACE';
     pagecount = 256 * 16;  /* 16 MB */
     storkey = 0;
     optcount = 0;
     
     /* if we wanted to supply a DMSSPCC option array, */
     /* we'd do so via the OPTCOUNT and OPTARRAY parms */
     
     call ssMemoryCreateDS
     (
      rc,                    /* return code  */
      re,                    /* reason code  */
      subpool,               /* subpool name */
      pagecount,             /* num of pages */
      storkey,               /* storage key  */
      optcount,              /* option count */
      optarray,              /* option array */
      asit,                  /* DS ASIT      */
      alet                   /* DS ALET      */
     );
     
    

    If the call is successful, the RSK will have created the data space and will be ready for you to allocate storage from it. Keep track of the ALET because you will need it to refer to the buffers you allocate.

    ssMemoryAllocate

    You can use ssMemoryAllocate to allocate and release storage in:

    • Data spaces you created via ssMemoryCreateDS, or

    • Global subpools you create explicitly via SUBPOOL CREATE, or

    • Global subpools you create implicitly by first mention via call to ssMemoryAllocate.

    ssMemoryAllocate supports doubleword-aligned and page-aligned requests and also supports variably-sized allocation.

     
     %include syslib(ssplxmem);
     
     declare
      rc          fixed(31),
      re          fixed(31),
      subpool     char(8),
      min         fixed(31),
      max         fixed(31),
      amtgot      fixed(31),
      storptr     pointer(31);
     
     subpool = 'MYDSPACE';
     min = 32;     /* at least 32 bytes */
     max = 1024;   /* as much as 1 KB   */
     
     call ssMemoryAllocate
     (
      rc,                     /* return code    */
      re,                     /* reason code    */
      min,                    /* min needed     */
      max,                    /* max wanted     */
      subpool,                /* subpool name   */
      ss_mem_align_page,      /* alignment reqt */
      storptr,                /* storage ptr    */
      amtgot                  /* amt obtained   */
     );
     
    

    ssMemoryRelease

    The only warning here is that you should release only storage you acquired via call to ssMemoryAllocate. If you went directly to CMSSTOR, go directly there to release.

     
     %include syslib(ssplxmem);
     
     declare
      rc          fixed(31),
      re          fixed(31),
      subpool     char(8),
      amtgot      fixed(31),
      storptr     pointer(31);
     
     subpool = 'MYDSPACE';
     
     call ssMemoryRelease
     (
      rc,               /* return code    */
      re,               /* reason code    */
      amtgot,           /* amt to release */
      subpool,          /* subpool name   */
      storptr           /* storage ptr    */
     );
     
    

    ssMemoryDelete

    Use this to delete subpools you created via call to ssMemoryCreateDS or manipulated via call to ssMemoryAllocate.

     
     %include syslib(ssplxmem);
     
     declare
      rc          fixed(31),
      re          fixed(31),
      subpool     char(8);
     
     subpool = 'MYDSPACE';
     
     call ssMemoryDelete
     (
      rc,               /* return code   */
      re,               /* reason code   */
      subpool           /* subpool name  */
     );
     
    

    Commands

    In front-ending CMSSTOR, the RSK keeps a cache of storage ready for giving out via ssMemoryAllocate. CMSSTOR "thinks" this storage is allocated, of course.

    There is a threshold governing how much storage the RSK will cache in this way. If the free storage cache grows too large, the RSK will do releases to CMSSTOR.

    The threshold is set via the CONFIG MEM_MAXFREE command. This threshold applies on a per-subpool basis. Refer to the formal documentation for more information.


    Block-oriented DASD

    The RSK provides a block-oriented model for reading and writing minidisks, whether CKD or FBA. The purpose of the APIs and associated commands is to give the server access to a large, high-speed pool of persistent storage blocks. The server is free to impose whatever logical structure makes sense for the problem at hand. The minidisks read and written via this facility do not contain useful CMS file systems - that is, this facility is not able to provide access to files stored on CMS minidisks.

    Minidisks used by the RSK's DASD model must be formatted at 4 KB and reserved. The RSK provides no facility for performing these initialization steps automatically.

    The RSK organizes minidisks into sets called storage groups. Storage groups have the following properties:

    • Each storage group can contain up to 16 TB (X'100000000' 4 KB blocks), spread over up to 13,000 minidisks.

    • The RSK supports up to 1024 storage groups.

    • The server operator can request that I/O to the storage group be performed via any of these means, on a per-storage-group basis:

      • MAPMDISK: the RSK maps the minidisks' 4 KB blocks into the pages of one or more VM Data Spaces. To read the blocks, the RSK performs MVCL from the corresponding pages. To write the blocks, the RSK performs MVCL to the corresponding pages and then issues MAPMDISK SAVE to cause the pages to be committed.

      • DIAG X'250': the RSK starts an I/O operation to one or more minidisks in the storage group and receives external interrupts informing it of the I/O's completion.

      • DIAG X'A4': the RSK calls a CP API to perform I/O to the minidisks in a storage group. CP returns control to the RSK when the I/O is complete.

    • I/O to a storage group is thread-synchronous and thread-blocking. By thread-synchronous we mean that the calling thread does not get control back until the I/O is complete. By thread-blocking we mean that if the virtual machine must wait for the I/O to complete, only the requesting thread waits; the virtual CPU is used to run other threads while we are waiting for the I/O to finish. (Not true if DIAG X'A4' is used.)

    Figure 1 illustrates the notion of storage groups.

    Figure 1. RSK DASD


                      Storage Group 0                 SG 1           SG n
           *-----------------------------------*    *------*  ...  *------*
           |      3F0              Data Space  |    |      |       |      |
           |  0 *------*        *- *---------* |    |      |       |      |
           |  1 *------* -*     |  |  pgs 0  | |    |      |       |      |
           |    | data |  *-----*  |  to 48  | |    |      |       |      |
           |    |      |  |     *- *---------* |    |      |       |      |
           | 49 *------* -*     |  |         | |    |      |       |      |
           |                    |  | pgs 49  | |    |      |       |      |
           |      2E4        *--*  | to 146  | |    |      |       |      |
           |  0 *------*     |  |  |         | |    |      |       |      |
           |    |      |     |  |  |         | |    |      |       |      |
           |  2 *------* -*  |  |  |         | |    |      |       |      |
           |    | data |  |  |  *- *---------* |    |      |       |      |
           |    |      |  *--*  |  | pgs 147 | |    |      |       |      |
           |    |      |  |     |  | to 215  | |    |      |       |      |
           |    |      |  |  *--*  |         | |    |      |       |      |
           |    |      |  |  |  *- *---------* |    |      |       |      |
           |    |      |  |  |     more than   |    |      |       |      |
           | 99 *------* -*  |     1 DS if     |    |      |       |      |
           |                 |     needed      |    |      |       |      |
           |                 |                 |    |      |       |      |
           |      1A32       |   Disk  Blks    |    |      |       |      |
           |  0 *------*     |   ----  ----    |    |      |       |      |
           |    |      |     |    3F0    49    |    |      |       |      |
           |  2 *------* -*  |    2E4    98    |    |      |       |      |
           |    |      |  |  |   1A32    69    |    |      |       |      |
           |    | data |  *--*         ----    |    |      |       |      |
           |    |      |  |             216    |    |      |       |      |
           | 70 *------* -*                    |    |      |       |      |
           *-----------------------------------*    *------*       *------*
                             ^                         ^              ^
                             V                         V              V
           *--------------------------------------------------------------*
           |   I/O engine:                                                |
           |   - Read via MVCL; write via MVCL then MAPMDISK SAVE         |
           |   - APIs for I/O and admin/maint operations                  |
           |   - Commands for admin/maint operations                      |
           *--------------------------------------------------------------*
                     ^    ^    ^    ^    ^    ^    ^    ^    ^    ^
                     |    |    |    |    |    |    |    |    |    |
                   *------------------------------------------------*
                                    server threads
    

    The grouping of minidisks into storage groups is recorded in the file pointed to by configuration parameter SGP_FILE.

    When a storage group is brought online it is assigned a symbolic name. This symbolic name is how the storage group is identified in the ssSgpRead and ssSgpWrite API calls. This lets the server operator change the configuration of the storage groups without breaking programs.

    Beyond this there is not a lot to say about these storage groups. There exist APIs and commands to bring storage groups online and offline, and there are APIs for performing reads and writes to storage groups.


    APIs

    All of these APIs are prototyped in SSASMSGP MACRO and SSPLXSGP COPY.

    APIs for performing operator functions:

    • ssSgpStart: brings a storage group online

    • ssSgpStop: takes a storage group offline

    APIs for performing I/O:

    • ssSgpRead: reads blocks from a storage group.

    • ssSgpWrite: writes blocks to a storage group.

    Various other APIs:

    • ssSgpCreate: create a new storage group

    • ssSgpDelete: delete a storage group

    • ssSgpQuery: obtain information about a storage group

    Commands

    There are analogs for most of the APIs, for example:

    • SGP START: start a storage group

    • SGP STOP: stop a storage group

    • SGP LIST: obtain a list of storage groups

    • SGP MDLIST: list minidisks of a specific storage group

    The SGP service can be attached to any of the record-oriented line drivers, and then SGP commands can be issued via that line driver. For example, if we start the SGP service through the console driver, we can then type these SGP commands on the console.


    Example

                                                                            00001000
     /* bindings */                                                         00002000
     %include syslib(ssplxsgp);                                             00003000
                                                                            00004000
                                                                            00005000
     /* variables */                                                        00006000
     declare                                                                00007000
      rc          fixed(31),                                                00008000
      re          fixed(31),                                                00009000
      sgid        char(8),                                                  00010000
      curstart    fixed(31),      /* zero-origin start */                   00011000
      curcount    fixed(31),      /* num of blocks     */                   00012000
      bufptr      pointer(31);                                              00013000
                                                                            00014000
                                                                            00015000
     /* doing a write is like this... */                                    00016000
     call ssSgpWrite                                                        00017000
     (                                                                      00018000
      rc,                 /* return code    */                              00019000
      re,                 /* reason code    */                              00020000
      sgid,               /* sg name        */                              00021000
      curstart,           /* page number    */                              00022000
      curcount,           /* page count     */                              00023000
      0,                  /* buffer ALET    */                              00024000
      bufptr->chars       /* buffer itself  */                              00025000
     );                                                                     00026000
                                                                            00027000
                                                                            00028000
     /* reading pages is like this... */                                    00029000
     call ssSgpRead                                                         00030000
     (                                                                      00031000
      rc,                 /* return code    */                              00032000
      re,                 /* reason code    */                              00033000
      sgid,               /* sg name        */                              00034000
      curstart,           /* page number    */                              00035000
      curcount,           /* page count     */                              00036000
      0,                  /* buffer ALET    */                              00037000
      bufptr->chars       /* buffer itself  */                              00038000
     );                                                                     00039000
                                                                            00040000
    

    File Caching

    The RSK provides an API set that performs caching of CMS files read from minidisk, SFS, or BFS. Cached files are held in VM Data Spaces. The server author uses the caching capability by calling the RSK's file reading routines instead of calling the CSL (DMSOPEN, BPX1OPN) or the FS macros (FSREAD). The RSK resolves the server's read request from a VM Data Space if possible.

    The caching API does more than just cache file data. Recognizing that the data are likely to be consumed in a different code page and record format than that in which they were stored, the RSK lets the opener specify translation schemes that govern how the RSK will transform the file data as it loads the data into the cache. This lets frequently-accessed files' data be transformed only once.


    Details

    • The server operator uses the RSK's CACHE command set to create one or more file caches. Each file cache is its own VM Data Space.

    • Each cache is managed in LRU fashion.

    • To open a file for reading, the server calls ssCacheFileOpen, supplying the following inputs:

      • Name of cache to use

      • Name of file to be opened

      • Any relevant ESM data

      • Which file system to search (minidisk/SFS or BFS)

      • How to translate data read from the file

      • How to expect records to be delineated in the read file

      • How to organize the records in the cached file

      Under some conditions, the RSK will attempt to determine whether the file resides in minidisk/SFS or in the BFS and will use the corresponding CSL routine automatically.

    • ssCacheFileOpen returns several pieces of information about the cached file:

      • A token the caller can use in calling ssCacheFileRead

      • The ALET and address of the cached data

      The latter lets the caller go after the data without an API call if he desires (just enter AR mode and read the buffer).

    • When the caller closes the file (via ssCacheFileClose), the file becomes eligible for displacement from the cache, providing no other callers have the file open.

    • Regarding concurrency, a given file can be open multiple times concurrently, and multiple reads can be in progress against a given file simultaneously.

    APIs

    There are just a few APIs.

    • ssCacheCreate: create a file cache
    • ssCacheDelete: delete a file cache
    • ssCacheFileOpen: cache a file
    • ssCacheFileRead: read cached data
    • ssCacheFileClose: close a cached file
    • ssCacheQuery: obtain stats about a cache
    • ssCacheXlTabSet: install a translation table

    Commands

    • CACHE CREATE: create a file cache
    • CACHE DELETE: delete a file cache
    • CACHE LIST: show a list of file caches

    Example

                                                                            00932000
     /**************************************************/                   00933000
     /* set open options based on translation type.    */                   00934000
     /* ssCacheFileOpen handles data conversions.      */                   00935000
     /**************************************************/                   00936000
                                                                            00937000
     num_flags = 4;                                                         00938000
     flag_names(1) = ss_cac_ofn_recmethod_fs;                               00939000
     flag_names(2) = ss_cac_ofn_xlate;                                      00940000
     flag_names(3) = ss_cac_ofn_recmethod_cache;                            00941000
                                                                            00942000
     select;                                                                00943000
                                                                            00944000
      /* BINARY:  do it as-is */                                            00945000
      when ( (filtertype(1::6) = 'binary') &                                00946000
             (filtertypelen = 6)            ) then                          00947000
      do;                                                                   00948000
       flag_values(1) = '00000000'x;                                        00949000
       flag_values(2) = 0;                                                  00950000
       flag_values(3) = '01000000'x;                                        00951000
      end;                                                                  00952000
                                                                            00953000
      /* ASCII:  it depends */                                              00954000
      when ( (filtertype(1::5) = 'ascii') &                                 00955000
             (filtertypelen = 5)            ) then                          00956000
      do;                                                                   00957000
       if (fs_type = fs_sfs) then                                           00958000
       do;                                                                  00959000
        flag_values(1) = '00000000'x;                                       00960000
        flag_values(2) = 0;                                                 00961000
        flag_values(3) = '01020D0A'x;                                       00962000
       end;                                                                 00963000
       else                                                                 00964000
       do;                                                                  00965000
        flag_values(1) = '01011500'x;                                       00966000
        flag_values(2) = 0;                                                 00967000
        flag_values(3) = '01020D0A'x;                                       00968000
       end;                                                                 00969000
      end;                                                                  00970000
                                                                            00971000
      /* DOS:  X'0D0A' markers */                                           00972000
      when ( (filtertype(1::3) = 'dos') &                                   00973000
             (filtertypelen = 3)            ) then                          00974000
      do;                                                                   00975000
       flag_values(1) = '01020D0A'x;                                        00976000
       flag_values(2) = 0;                                                  00977000
       flag_values(3) = '01020D0A'x;                                        00978000
      end;                                                                  00979000
                                                                            00980000
      /* UNIX:  X'0A' markers */                                            00981000
      when ( (filtertype(1::4) = 'unix') &                                  00982000
             (filtertypelen = 4)            ) then                          00983000
      do;                                                                   00984000
       flag_values(1) = '01010A00'x;                                        00985000
       flag_values(2) = 0;                                                  00986000
       flag_values(3) = '01020D0A'x;                                        00987000
      end;                                                                  00988000
                                                                            00989000
      /* CMS: insert record lengths */                                      00990000
      when ( (filtertype(1::3) = 'cms') &                                   00991000
             (filtertypelen = 3)            ) then                          00992000
      do;                                                                   00993000
       if (fs_type = fs_sfs) then                                           00994000
        flag_values(1) = '00000000'x;                                       00995000
       else                                                                 00996000
        flag_values(1) = '01011500'x;                                       00997000
       flag_values(2) = 0;                                                  00998000
       flag_values(3) = '02020000'x;                                        00999000
      end;                                                                  01000000
                                                                            01001000
      /* MODULE: it depends, due to how    */                               01002000
      /* OPENVM PUTBFS behaves for MODULEs */                               01003000
      when ( (filtertype(1::6) = 'module') &                                01004000
             (filtertypelen = 6)            ) then                          01005000
      do;                                                                   01006000
       if (fs_type = fs_sfs) then                                           01007000
       do;                                                                  01008000
        flag_values(1) = '00000000'x;                                       01009000
        flag_values(2) = 0;                                                 01010000
        flag_values(3) = '02020000'x;                                       01011000
       end;                                                                 01012000
       else                                                                 01013000
       do;                                                                  01014000
        flag_values(1) = '00000000'x;                                       01015000
        flag_values(2) = 0;                                                 01016000
        flag_values(3) = '01000000'x;                                       01017000
       end;                                                                 01018000
      end;                                                                  01019000
                                                                            01020000
      /* CGI: this is an escape for later */                                01021000
      when ( (filtertype(1::3) = 'cgi') &                                   01022000
             (filtertypelen = 3)            ) then                          01023000
      do;                                                                   01024000
       goto giveerr;                                                        01025000
      end;                                                                  01026000
                                                                            01027000
      /* HIDE: refuse to serve file */                                      01028000
      when ( (filtertype(1::4) = 'hide') &                                  01029000
             (filtertypelen = 4)            ) then                          01030000
      do;                                                                   01031000
       goto giveerr;                                                        01032000
      end;                                                                  01033000
                                                                            01034000
      /* other types - 7BIT, 8BIT, EBCDIC, etc. */                          01035000
      otherwise                                                             01036000
      do;                                                                   01037000
       if (fs_type = fs_sfs) then                                           01038000
        flag_values(1) = '00000000'x;                                       01039000
       else                                                                 01040000
        flag_values(1) = '01011500'x;                                       01041000
       flag_values(2) = 1;                                                  01042000
       flag_values(3) = '01020D0A'x;                                        01043000
      end;                                                                  01044000
                                                                            01045000
     end; /* end select */                                                  01046000
                                                                            01047000
     /* set up for BFS/RFS for ssCacheFileOpen */                           01048000
                                                                            01049000
     flag_names(4) = ss_cac_ofn_bfs;                                        01050000
     if (fs_type = fs_bfs) then                                             01051000
      flag_values(4) = ss_cac_ofv_yes;                                      01052000
     else                                                                   01053000
      flag_values(4) = ss_cac_ofv_no;                                       01054000
                                                                            01055000
     /**************************************************/                   01056000
     /* try opening the file now.  try uppercasing if  */                   01057000
     /* first open fails with not_found.               */                   01058000
     /**************************************************/                   01059000
                                                                            01060000
     /*                                                                     01061000
     ?DMSMSG                                                                01062000
      TEXT('Filespec &1 &2')                                                01063000
      SUB(DEC,filespec_len,HEX4,(filespec,filespec_len));                   01064000
     */                                                                     01065000
                                                                            01066000
     do while (fileopen=0);                                                 01067000
                                                                            01068000
      ssCacheFileOpen                                                       01069000
      (                                                                     01070000
       rc,                  /* return code    */                            01071000
       re,                  /* reason code    */                            01072000
       filcache,            /* cache name     */                            01073000
       filespec,            /* file name      */                            01074000
       filespec_len,        /* name length    */                            01075000
       c,                   /* ESM data       */                            01076000
       0,                   /* none           */                            01077000
       num_flags,           /* flag count     */                            01078000
       flag_names,          /* flag names     */                            01079000
       flag_values,         /* flag values    */                            01080000
       file_token,          /* file token     */                            01081000
       cache_alet,          /* cache ALET     */                            01082000
       file_addr,           /* cache address  */                            01083000
       file_size,           /* file size      */                            01084000
       file_update          /* update time    */                            01085000
      );                                                                    01086000
                                                                            01087000
      if (rc=0) then                                                        01088000
      do;                                                                   01089000
       fileopen = 1;                                                        01090000
       /*                                                                   01091000
       ?DMSMSG                                                              01092000
        TEXT('Date: &1')                                                    01093000
        SUB(CHAR,file_update);                                              01094000
       */                                                                   01095000
      end;                                                                  01096000
      else                                                                  01097000
      do;                                                                   01098000
                                                                            01099000
       /* announce error */                                                 01100000
       ?DMSMSG                                                              01101000
        TEXT('&1: RC=&2 RE=&3 from ssCacheFileOpen')                        01102000
        SUB(CHAR,(filespec,filespec_len),DEC,rc,DEC,re);                    01103000
                                                                            01104000
       /* if not_found, uc and try again */                                 01105000
       if ( (re^=ss_cac_re_file_not_found) |                                01106000
            (ucfs=1) ) then                                                 01107000
        goto giveerr;                                                       01108000
       else                                                                 01109000
       do;                                                                  01110000
        call xlate                                                          01111000
        (                                                                   01112000
         addr(uce),                                                         01113000
         addr(filespec),                                                    01114000
         filespec_len                                                       01115000
        );                                                                  01116000
        ucfs = 1;                                                           01117000
       end;                                                                 01118000
                                                                            01119000
      end; /* open error */                                                 01120000
                                                                            01121000
     end; /* while */                                                       01122000
                                                                            01123000
     /* if we get here, the file is open */                                 01124000
                                                                            01125000
    

    Authorization

    In many situations, a server is nothing more than an access method for objects of various kinds. For example, an HTTP server is a just a server that sends files over socket connections when browsers ask for them.

    When servers are acting as access methods, it is sometimes appropriate for the server to impose authorization rules on the set of clients, operations, and objects. Taken together, this set of rules describes "who can do what to whom". Typically, for each object controlled by the server, there will be a small set of rules for each authorized user, each rule listing the subset of operations the user is permitted to perform.

    The RSK supports the construction and maintenance of such an authorization rule set by providing a rule base manager in the form of a set of APIs and operator commands. This rule base manager understands the abstract notions of user, object, and action, but the actual objects defined, users defined, and actions defined are left to the server designer to decide. The RSK's rule manager just relates users, objects, and actions, whatever they are defined to be. Unlike ESMs such as RACF, the RSK does not actually protect objects.

    It is expected that servers needing to protect their objects will store the rule base in the RSK's rule base manager. When clients ask to perform certain operations on objects, the server can call the RSK, supplying the object name, the client name, and a vector of proposed operations. The RSK will respond with an yea/nay vector, and the server will interpret said response and either do the client's bidding or send a negative response.


    Setup

    The authorization rules are kept in a pair of CMS files. The pair can be stored on minidisk or in the CMS Shared File System. (Storing the files on an accessed SFS directory counts as SFS.) The setup process varies according to the storage medium you choose.

    Minidisk

    When the files are on minidisk, the RSK keeps twin copies of the pair (four files in all) and keeps a log file that describes which pair is up-to-date at the moment. This scheme lets the RSK recover from an incomplete update (device failure, etc.).

    When you use minidisk, observe the following guidelines:

    • Though you can put all five files on a single minidisk, best protection is achieved with pair 1 and the log file on one minidisk and pair 2 on another minidisk. If possible, put these two minidisks on separate packs.

    • Minidisks containing authorization files must have no files open for output on them except the authorization files themselves. In fact, it would be a good idea to use these minidisks only for authorization files and not for any other purpose.

    Then proceed in PROFILE RSK as illustrated in this snippet from a mythical PROFILE RSK:

     
    /* this assumes minidisk 1 is at filemode K and */
    /* minidisk 2 is at filemode L */
     
    'CONFIG AUT_LOCATION MINIDISK'
     
    fn = 'RULEBASE'
     
    dfile = fn 'RSKAUD'
    xfile = fn 'RSKAUX'
     
    'CONFIG AUT_DATA_1  ' dfile 'K'
    'CONFIG AUT_INDEX_1 ' xfile 'K'
     
    'CONFIG AUT_DATA_2  ' dfile 'L'
    'CONFIG AUT_INDEX_2 ' xfile 'L'
     
    'CONFIG AUT_LOG     ' fn 'RSKAUL K'
     
    

    Shared File System

    When the files are in SFS, the RSK uses SFS's work unit support to commit changes together. Thus, only one pair of files is needed and no log file is needed.

    This snippet from a mythical PROFILE RSK configures the authorization data to reside in SFS:

     
    'CONFIG AUT_LOCATION SFS'
     
    fn = 'RULEBASE'
    authdir = 'MYPOOL:SERVER.AUTHDATA'
     
    'CONFIG AUT_DATA_1  ' fn 'RSKAUD' authdir
    'CONFIG AUT_INDEX_1 ' fn 'RSKAUX' authdir
     
    

    Users, Objects, and Actions

    A user is just a 1- to 64-byte string identifying a user.

    An action is just a 4-byte string identifying an action.

    An object class is just a set of actions. The object class is identified by an eight-byte name. For example, object class FRED might be the set of actions READ, WRIT, EXEC, and ERAS. There is no hierarchy in these operations.

    An object is a specific item that belongs to an object class. The object is identified by a 1- to 256-byte name. For example, object My Data File might belong to object class FRED and therefore would have FRED's actions defined on it.


    APIs

    Simple APIs

    These do pretty much what you would expect.

    • ssAuthCreateClass: create an object class.

    • ssAuthModifyClass: modify an object class.

    • ssAuthCreateObject: create an object. The object starts life with no rules associated with it.

    These APIs remove objects, classes, and users from the rule base.

    • ssAuthDeleteObject: delete all of the rules associated with an object, and optionally delete the object.

    • ssAuthDeleteClass: delete all of the objects in a given class (including their rules), and optionally delete the class.

    • ssAuthDeleteUser: find all of the rules associated with a given user and delete them.

    These APIs produce listings of various kinds.

    • ssAuthListClasses: produce a listing of the classes in the rule base.

    • ssAuthListObjects: produce a listing of the objects in a given class (with wildcard matching).

    These APIs perform various queries against the rule base.

    • ssAuthQueryObject: look up the set of rules associated with the given object.

    • ssAuthQueryRule: look up the rule associated with the given (object,user) pair.

    The remaining APIs are complex enough to warrant their own sections.

    ssAuthPermitUser

    This API accepts an (object,user) pair as input, so as to identify the rule to be modified. It also accepts other input information describing how said rule is to be modified. The modification instructions are passed in as two arrays and a scalar.

    Consider first the two n-element arrays. The first array contains a list of operations defined on the object's class. The second n-element array tells whether the corresponding action is to be added to or deleted from the rule. For example, consider these two three-element arrays:

    op array      action array
    --------      ------------
    READ          ss_aut_add_operation
    WRIT          ss_aut_remove_operation
    EXEC          ss_aut_add_operation
    

    This would add READ and EXEC permissions to the rule and remove WRIT permission from the rule.

    The scalar describes how the arrays are to be applied:

    Value
    Meaning
    ss_aut_add_all
    First add all defined operations to the current rule, then apply the arrays.
    ss_aut_delete_all
    First completely delete the current rule, then apply the arrays.
    ss_aut_use_arrays
    Just apply the arrays to the current rule.

    With a little thought you can see how this structure lets the current rule be edited easily.

    ssAuthPermitUser returns an n-element vector in response. The elements of the vector describe the results of applying the arrays:

    Value
    Meaning
    ss_aut_op_not_defined
    The operation was not defined on the object's class.
    ss_aut_op_permitted
    The operation is now permitted.
    ss_aut_op_not_permitted
    The operation is now not permitted.
    ss_aut_no_change
    The array entry did not result in a rule change.

    ssAuthTestOperations

    This entry point lets you test a proposed set of operations against a rule in the rule base.

    The rule to be tested is identified by ordered pair (object,user).

    The proposal is an n-element vector of operations you believe are defined on the object.

    The response is an n-element vector of responses. Each element of the vector is one of the following scalars:

    Value
    Meaning
    ss_aut_op_permitted
    The operation is permitted.
    ss_aut_op_not_permitted
    The operation is not permitted.
    ss_aut_not_defined
    The operation is not defined on this object class.

    This can be used to test many operations simultaneously. Also, this is good for locking because writes to the rule set are disabled while the test is being conducted.


    Operator Commands

    These parallel the API set. They all start with AUTH.

    • CRECLASS: create an object class

    • CREOBJECT: create an object

    • DELCLASS: delete the objects in a class, and also the class itself

    • DELOBJECT: delete the rules for an object, and also the object itself

    • DELUSER: delete the rules for a user

    • LISTCLASS: list defined classes

    • LISTOBJECT: list objects in a class

    • MODCLASS: modify object class

    • PERMIT: change a rule

    • QOBJECT: list rules for an object

    Example

    *COPY BKWCAU                                                            00001000
                                                                            00002000
     /*********************************************************/            00003000
     /*                                                       */            00004000
     /* check_auth:  checks to see whether things are OK.     */            00005000
     /* if things are NOT OK then return with a nonzero rc.   */            00006000
     /*                                                       */            00007000
     /* caller must include:                                  */            00008000
     /*   ssplxaut                                            */            00009000
     /*   ssplxsrv                                            */            00010000
     /*                                                       */            00011000
     /* caller must declare:                                  */            00012000
     /*   rc    fixed(31)                                     */            00013000
     /*                                                       */            00014000
     /*********************************************************/            00015000
                                                                            00016000
     check_auth: procedure                                                  00017000
     (                                                                      00018000
      ca_cblock,       /* C-block addr  */                                  00019000
      ca_sn,           /* service name  */                                  00020000
      ca_snl,          /* name length   */                                  00021000
      ca_cw,           /* check word    */                                  00022000
      ca_op            /* op type       */                                  00023000
     );                                                                     00024000
                                                                            00025000
      /* parameters */                                                      00026000
      declare                                                               00027000
       ca_cblock   pointer(31),                                             00028000
       ca_sn       char(8),                                                 00029000
       ca_snl      fixed(31),                                               00030000
       ca_cw       fixed(31),                                               00031000
       ca_op       char(4);                                                 00032000
                                                                            00033000
      /* automatic storage */                                               00034000
      declare                                                               00035000
        re         fixed(31),                                               00036000
        results    fixed(31),                                               00037000
        userid_len fixed(31),                                               00038000
        i          fixed(31);                                               00039000
                                                                            00040000
      /* pretend it's OK */                                                 00041000
      rc = 0;                                                               00042000
                                                                            00043000
      /* if AUTHCHECK_LD is off or he is inside this */                     00044000
      /* virtual machine, it's OK */                                        00045000
                                                                            00046000
      if ( (ca_cw=0) |                                                      00047000
           (ca_cblock->vmss_cblock.vc_userid = '*       ') ) then           00048000
       return;                                                              00049000
                                                                            00050000
      /*****************************************************/               00051000
      /* call to ssAuthTestOperations goes here.  the call */               00052000
      /* is configured like this:                          */               00053000
      /*                                                   */               00054000
      /*  OBJECT:  name of the service being manipulated   */               00055000
      /*  USER:    userid from C-block                     */               00056000
      /*  ACTION:  STRT or STOP                            */               00057000
      /*                                                   */               00058000
      /*****************************************************/               00059000
                                                                            00060000
      i = 1;                                                                00061000
      do while ((ca_cblock->vmss_cblock.vc_userid(i) ^= ' ') &              00062000
                (i <= 8));                                                  00063000
       i= i + 1;                                                            00064000
      end;                                                                  00065000
                                                                            00066000
      userid_len = i - 1;                                                   00067000
      call ssAuthTestOperations                                             00068000
      (                                                                     00069000
       rc,                                  /* return code  */              00070000
       re,                                  /* reason code  */              00071000
       ca_cblock->vmss_cblock.vc_userid,    /* userid       */              00072000
       userid_len,                          /* its length   */              00073000
       ca_sn,                               /* object name  */              00074000
       ca_snl,                              /* its length   */              00075000
       1,                                   /* op count     */              00076000
       ca_op,                               /* op name      */              00077000
       results                              /* results      */              00078000
      );                                                                    00079000
                                                                            00080000
      /* if call worked, check results */                                   00081000
      if (rc=0) then                                                        00082000
       if (results^=ss_aut_op_permitted) then                               00083000
        rc = 1;                                                             00084000
                                                                            00085000
      /* and return to caller */                                            00086000
      return;                                                               00087000
                                                                            00088000
      end check_auth;                                                       00089000
                                                                            00090000
    

    Enrollment

    Many servers face the problem of holding onto enrollment information describing the clients they serve. The RSK provides an enrollment API that lets the server hold onto this data easily. The RSK's enrollment engine holds onto enrollment records by keeping them in a VM Data Space. This lets the RSK hold onto hundreds of thousands of enrollment records using in-memory techniques.

    While this engine was designed to hold enrollment records, it is really just a simple indexed access method with a single key and no wildcarding. Feel free to put it to other uses, such as holding your server's configuration parameters.

    The RSK supports memory-only enrollment sets. These sets are empty each time the server starts and are never written to disk. This might be useful for tracking transient indexed sets, such as information about the set of currently-connected clients.


    Details

    Some notes:

    • Record keys are 64 bytes long and case-sensitive.

    • Record data can be up to 65,450 bytes long.

    • Transactions against permanent sets are recorded in an SFS file and committed when you say so.

    APIs

    Operations on sets:

    • ssEnrollLoad: load enrollment set from SFS into data space

    • ssEnrollCommit: commit changes made to an enrollment set

    • ssEnrollDrop: unload enrollment set from data space

    Operations on records:

    • ssEnrollRecordGet retrieve record, given key

    • ssEnrollRecordInsert: insert or replace record

    • ssEnrollRecordDelete: delete record, given key

    Maintenance operations:

    • ssEnrollList: list loaded enrollment sets

    • ssEnrollRecordList: list keys in particular set

    For example,

     
     %include syslib(ssplxenr);
     
     declare
      rc            fixed(31),
      re            fixed(31),
      setname       char(8),
      key           char(64),
      buffer        char(512),
      amtgot        fixed(31);
     
     /* retrieve BKW's record */
     
     setname = 'MYDIRECT';
     key = 'BKW';
     
     call ssEnrollRecordGet
     (
      rc,                   /* return code   */
      re,                   /* reason code   */
      setname,              /* set name      */
      key,                  /* key to use    */
      buffer,               /* output buffer */
      length(buffer),       /* buffer size   */
      amtgot                /* amt returned  */
     );
     
    

    Commands

    All of these start with ENROLL.

    Operations on sets:

    • LOAD: load enrollment set from SFS

    • DROP: drop enrollment set from data space

    • COMMIT: commit changes to enrollment set

    Operations on records:

    • GET: display contents of record

    • INSERT: insert or replace record

    • REMOVE: remove record from set

    Maintenance operations:

    • LIST: display list of loaded sets

    • RECLIST: display keys from given set

    Example

    enroll list
    ENROLL   Name     Pages  Entries    InUse D K
    ENROLL   ----     -----  -------    ----- - -
    ENROLL   HTTPCNFG 256    3          1     0 d
    ENROLL   HTTPMIME 256    209        6     0 d
    RSK>
    cp q spaces
    CP       ASIT               STORAGE P/S ACC SPACE IDENTIFICATION
    CP       36F3344000000013      128M PRV R/W MPTEST:BASE
    CP       36F334C000000007        1M PRV R/W MPTEST:BKW_HTTPCNFG
    CP       36F3350000000007        1M PRV R/W MPTEST:BKW_HTTPMIME
    CP       36F3340000000012      128M PRV R/W MPTEST:BKW_HTTPFILE
    CP       BKWHCP0900I RC=0 from CP.
    RSK>
    enroll reclist HTTPCNFG
    ENROLL   LOGGING
    ENROLL   ROOT
    ENROLL   FSTYPE
    RSK>
    

    Worker Machines

    Certain kinds of work are best done in isolation. Running CGI programs, for example, should be done in a way that an errant CGI can't destroy your server's ability to turn HTTP transactions. Recognizing this, the RSK supports the notion of worker machines and offers an API that lets the server distribute work among virtual machines.

    Design points:

    • The RSK organizes worker machines into classes and considers each member of a given class to be functionally equivalent.

    • When you call ssWorkerAllocate, you specify the class in which you are interested. In response, the RSK selects a worker and establishes an IUCV connection to it. The RSK then arranges a C-block to represent the connection and returns the C-block address to you as an output.

    • If necessary, the RSK will XAUTOLOG the worker machine for you. Further, if the worker appears hung or unresponsive, the RSK will FORCE it and re-XAUTOLOG it in an attempt to reset it.

    • You can tune the worker selection logic so that the RSK will either tend to keep the logged-on set small or tend to log on as many workers as possible. Depending on the nature of your worker transactions, one of these strategies might be more appropriate than the other.

    • The RSK attempts to distribute work evenly to the logged-on workers, "evenness" being evaluated as the number of IUCV connections to each worker.

    • The RSK uses distributable IUCV in talking to the workers. If your systems are so configured, your workers could be on another VM system. You can suppress the RSK's FORCE and XAUTOLOG logic in this case, but you must manage the worker pool yourself.

    • Your code uses ssClientDataGet, ssClientDataPut, and CMS IPC to interact with the worker, just as if the worker were a client. Notices about worker activity will appear on your line driver queue, just like notices about activity from your "real" client.

    APIs

    There is only one API: ssWorkerAllocate.

     
     %include syslib(ssplxwrk);
     
     declare
      rc         fixed(31),
      re         fixed(31),
      icblock    pointer(31),
      class      char(8),
      ocount     fixed(31),
      onames(4)  fixed(31),
      ovals(4)   fixed(31),
      wcblock    pointer(31),
      connid     fixed(31);
     
     /* set up classname */
     class = 'MYWCLASS';
     
     /* set up options array */
     
     ocount = 2;
     
     /* i prefer an empty worker if possible */
     onames(1) = ss_wrk_ofn_prefer_empty;
     ovals(1) = ss_wrk_ofv_yes;
     
     /* try all workers in pool */
     onames(2) = ss_wrk_ofn_retry_count;
     ovals(2) = 0;
     
     /* now make the call */
     call ssWorkerAllocate
     (
      rc,             /* return code    */
      re,             /* reason code    */
      icblock,        /* my C-block     */
      class,          /* worker class   */
      ocount,         /* option count   */
      onames,         /* option names   */
      ovals,          /* option vals    */
      wcblock,        /* worker C-block */
      connid          /* connection ID  */
     );
     
     /* if RC=0, watch for notifications in my line */
     /* driver queue -- 'message type' field of IPC */
     /* message will contain the connection ID      */
     
    

    Commands

    These all start with WORKER:

    • ADD: add a worker to a class

    • CLASSES: shows a summary of defined classes

    • DELCLASS: gets rid of a worker class

    • DELETE: removes a worker from a class

    • DISTRIBUTE: suppresses FORCE/AUTOLOG logic

    • MACHINES: summarizes activity in a given class

    • RESET: resets RSK's state memory about a class

    • STATUS: status of all active worker connections

    User ID Mapping

    Because the RSK lets you write a service without regard for the transport technology the client uses to reach you, it is necessary for the RSK to provide some transport-independent means of identifying clients for you. If the RSK provided no such mechanism, it would be nearly impossible for you to perform authorization checking for the objects your server manages.

    Said another way, because the RSK offers transport independence, a given user (person) could connect to your server over a number of different transport protocols. As the author of a transport-independent server, you would want your client to be able to access his resources with the same privileges no matter what transport technology he used to connect to you.

    The RSK attempts to address this problem by having all of its line drivers map transport-specific user identifiers through a mapping file. The result of the mapping -- a single-token user identifier -- is passed to you as the identifier of the user.

    The crux of the mapping support is a mapping file that contains rules about how userids should be mapped. Each record in the file has the following form:

    MAP <transport> <node> <userid> <mapped_userid>
    
    where:

    Token
    Meaning

    MAP
    identifies a mapping record

    <transport>
    the transport technology to which this record applies

    <node>
    the second-order qualifier that appears in the transport-specific user identifier

    <userid>
    the first-order qualifier that appears in the transport-specific user identifier

    <mapped_userid>
    the mapped user ID that should be passed to your code

    You should craft the <transport>, <node>, and <userid> tokens in your mapping records according to Table 1.

    Table 1. Use of Mapping Tokens

    <transport> <node> <userid>
    TCP, UDP dotted-decimal IP address *
    APPC LU name conversation security user ID
    MSG, SPOOL, IUCV CP node VM user ID
    CONSOLE, SUBCOM n/a n/a

    Note that LISTFILE-like wildcarding (* and %) can be used in the <transport>, <node>, and <userid> fields. For example, to match all nodes starting with GDL, one could write GDL* in the <node> field.


    Commands

    • Use CONFIG UMAP_FILE to nominate the user ID mapping file.

    • Use USERID RELOAD to have the RSK re-read the mapping file after you've changed it.

    APIs

    The mapping function itself is available to you via call to ssUseridMap. (Maybe you can think of another use for this besides mapping user IDs.)


    Example

    * Userid map file (node userid validated_userid)
    * File is processed from top to bottom, first match wins
     
    * APPC/VM stuff (LU name, IPVMID)
    MAP APPC    '*USERID:*         BKW       BKW       ; Brian Wade
    MAP APPC    '*USERID:*         DRQ       BKW       ; Brian Wade
    MAP APPC    '*USERID:*         BKW7      BKW       ; Brian Wade
    MAP APPC    '*USERID:*         WADEB     BKW       ; Brian Wade
     
    * TCP/IP mapping
    MAP TCP     9.130.57.10        *         BKW
    MAP TCP     9.130.57.120       *         BKW2
    MAP TCP     9.130.79.171       *         VMWEB
     
    * userid/nodeid stuff (spool, MSG, SMSG)
    MAP *     GDLVM7               BKW       BKW       ; Brian Wade
    MAP *     GDLVM7               DRQ       BKW       ; Brian Wade
    MAP *     GDLVM7               BKW7      BKW       ; Brian Wade
    MAP *     GDLVM7               WADEB     BKW       ; Brian Wade
    MAP *     WSCVM                BKW       BKW       ; Brian Wade
    MAP *     GDLVMWEB             EWEBADM   BKW       ; Brian Wade
    MAP *     GDLVMWEB             BKW       BKW       ; Brian Wade
     
    MAP *     GDLVM7               DONOVANM  DONOVANM  ; Mike Donovan
     
    * anything that falls through
    MAP *     *                    *         $UNKNOWN  ; Everyone else
     
    

    Monitor Data

    The RSK collects data describing the operation of its various subsystems and uses CP's APPLDATA facility to cause the collected data to accrue in CP monitor data records. The RSK uses a single monitor buffer, declared via DIAG X'DC'. (This will work only if OPTION APPLMON appears in the server's CP directory entry.)

    The RSK divides the monitor buffer into 72-byte fragments called monitor rows. Each monitor row contains information about a specific facet of RSK operation. After the RSK's monitor rows, there is a portion of the monitor buffer called the application area. This area is reserved for the server author's use; anything written to that buffer lands in CP APPLDATA records. The server can obtain the address of the application area by calling ssAnchorGet.

    The first monitor row, called the kernel row, contains enough information so that you can deduce the organization of the rest of the monitor buffer. The size of a monitor row, the number of monitor rows, and the size of the application area all appear in the kernel row.

    The first eight bytes of a monitor row give a generic description of the kind of information being accrued in the row. For example, the first eight bytes might be LINEDRV to indicate that information about a line driver is being accrued. Note, though, that if the first eight bytes are zero, the row is not in use and should be ignored. The second eight bytes always contain a further qualifier of some kind - in the LINEDRV example, the second qualifier is the name of the line driver. You should refer to the formal documentation for the descriptions of all of the possible kinds of monitor buffers.

    If you are writing a program to reduce or analyze the collected monitor records, you will want to know the following pieces of information about the monitor buffer:

    • The first row is always the kernel row.

    • Subsequent rows are either unused (as indicated by the first eight bytes being zero) or in use for a specific purpose. The specific purpose is notated in the first eight bytes of the buffer.

    • From one sample to the next you will notice rows coming and going. This is just indicative of the RSK changing configuration in response to operator commands.

    Commands

    As regards the RSK's monitor data, there are a few commands you should know.

    • CONFIG MON_KERNEL_ROWS n tells how many rows the RSK should reserve in the monitor buffer. If you reserve too few rows, the RSK will issue a message when it tries to allocate a monitor row but finds none free.

    • CONFIG MON_USER_SIZE n tells how many bytes long the application area should be.

    • CONFIG MON_PRODUCT_ID identifier lets you set the 16-byte product identifier the RSK uses to label the monitor buffer.

    • MONITOR DISPLAY type subtype lets you display all the monitor rows matching the type and subtype you specify. This is useful, for example, for displaying all of the MEM rows if you want to see the rows having to do with subpool activity.

    • MONITOR USER shows you the application area of the monitor buffer.

    • SERVER MONITOR shows you the number of monitor rows and the size of the application area.

    Example

    server config
    SERVER   Parameter            Value
    SERVER   ---------            -----
    (some stuff deleted)
    SERVER   MON_PRODUCT_ID       SSTEST-FNN010100
    SERVER   MON_USER_SIZE        32
    SERVER   MON_KERNEL_ROWS      55
    (some stuff deleted)
    RSK>
    server monitor
    SERVER   BKWSRV0301I Monitor buffer at 07E59000.00000F98, 55 rows, 7 free
    RSK>
    monitor display kernel
    MONITOR  KERNEL            at 07E59000.00000048
    MONITOR  D2C5D9D5 C5D34040 40404040 40404040 00000037 00000048 00000020 00000001
    MONITOR  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000
    RSK>
    monitor display linedrv
    MONITOR  LINEDRV  SPOOL    at 07E59558.00000048
    MONITOR  D3C9D5C5 C4D9E540 E2D7D6D6 D3404040 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000
    MONITOR  LINEDRV  MSG      at 07E59630.00000048
    MONITOR  D3C9D5C5 C4D9E540 D4E2C740 40404040 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000
    MONITOR  LINEDRV  SUBCOM   at 07E59708.00000048
    MONITOR  D3C9D5C5 C4D9E540 E2E4C2C3 D6D44040 00000000 00000020 00000000 0000023E
    MONITOR  00000000 000004F0 00000000 00000000 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000
    MONITOR  LINEDRV  CONSOLE  at 07E597E0.00000048
    MONITOR  D3C9D5C5 C4D9E540 C3D6D5E2 D6D3C540 00000000 00000002 00000000 0000001D
    MONITOR  00000000 0000011C 00000000 00000000 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000
    MONITOR  LINEDRV  TCP      at 07E59AB0.00000048
    MONITOR  D3C9D5C5 C4D9E540 E3C3D740 40404040 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    MONITOR  00000000 00000000
    RSK>
    monitor user
    MONITOR  User data at 07E59F78.00000020
    MONITOR  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    RSK>
     
    CP SPOOL CONSOLE STOP CLOSE