www.sas.com > Service and Support > Technical Support
 
Technical Support SAS - The power to know(tm)
  TS Home | Intro to Services | News and Info | Contact TS | Site Map | FAQ | Feedback


/*--------------------------------------------------------------------+
|                                                                     |
|              Copyright 1996 (c), SAS Institute Inc.                  |
|                Unpublished - All Rights Reserved                    |
|                                                                     |
|                     S A S / C  S A M P L E                          |
|                                                                     |
|       Name: APPCSERV                                                |
|                                                                     |
|   Language: C                                                       |
|                                                                     |
| EntryPoint: MAIN                                                    |
|                                                                     |
| EntryType : OS Entry Linkage                                        |
|                                                                     |
| Files Note: 'prefix' is the installation defined high level         |
|             qualifier for the SAS/C product.                        |
|                                                                     |
|    Purpose: Demonstrate SAS/C APPC/VM support.                      |
|                                                                     |
| MVS -  Not Supported for MVS                                        |
|                                                                     |
|     Source: prefix.SAMPLE.C(APPSERV)                                |
|                                                                     |
| CMS -                                                               |
|     Source: SAMPLC   MACLIB (APPCSERV)                              |
|                                                                     |
|    Compile: global maclib lc370                                     |
|             lc370 appcserv                                          |
|                                                                     |
|       Link: global txtlib lc370bas lc370std                         |
|             load (appcserv                                          |
|             genmod appcserv(from @main                              |
|                                                                     |
|    Execute:  See the SAS/C Language Reference Vol 2,                |
|              chapter 'APPC/VM Functions' for details.               |
|                                                                     |
|      Notes:                                                         |
|            - This sample for CMS only.                              |
|            - The userid executing APPCSERV will need directory      |
|              statement authorizing IUCV with the *IDENT system      |
|              service option.  The following were used to            |
|              test this sample:                                      |
|                                                                     |
|              IUCV ALLOW                                             |
|              IUCV *IDENT       appcserv   local                     |
|                                                                     |
|                                                                     |
+--------------------------------------------------------------------*/
#pragma eject

#include <lcsignal.h>
#include <lcstring.h>
#include <lcio.h>
#include <cmsappc.h>
#include <stdlib.h>

void appctrap(void);              /* Declare SIGIUCV signal handler.*/
                                  /* Establish stdin prompt string. */
char *_stdiamp = "prompt=What do I reply to SENDER?\n,eof=";
int connects = 0;                 /* Number of connections made.    */
static short ident_pathid = 0;    /* used for *IDENT                 */

/*-------------------------------------------------------------------+
| Declare internal functions.                                        |
+-------------------------------------------------------------------*/

static void rcvrply(struct appc_send_plist *);

void main()

   {

   int maxconns,                  /* Number of IUCV connections     */
                                  /* allowed.                       */
       rc;                        /* Return code from functions     */

   struct iucv_path_plist conn;   /* IUCV CONNECT parameter list    */
   ident_parms   ident;           /* *IDENT parameters              */

   /*----------------------------------------------------------------+
   | Initialize IUCV signal processing and establish a handler.      |
   | Block IUCV signals until we're ready to handle them.            |
   +----------------------------------------------------------------*/

   signal(SIGIUCV,&appctrap);
   sigblock(1 << (SIGIUCV-1));

   /*----------------------------------------------------------------+
   | Identify this program as APPCSERV.                              |
   +----------------------------------------------------------------*/

   if ((rc = iucvset("APPCSERV",&maxconns)) != 0) {
      printf("Return code from iucvset APPCSERV was %d\n",rc);
      exit(4);
      }
   printf("Maximum IUCV connections: %d\n",maxconns);

   /*----------------------------------------------------------------+
   | Declare another name for connecting to *IDENT.                  |
   +----------------------------------------------------------------*/

   if ((rc = iucvset("IDENTHAN",&maxconns)) != 0) {
      printf("Return code from iucvset IDENTHAN was %d\n",rc);
      exit(8);
      }

   /*----------------------------------------------------------------+
   | Create an *IDENT parameter list.                                |
   +----------------------------------------------------------------*/

   memset(&ident, 0 ,sizeof(ident));
   memcpy(ident.name, "APPCSERV", 8);
   ident.fcode = MANAGE_RESOURCE;
   ident.flag  = ALLOW_SECURITY_NONE;
   ident.ntype = RESOURCE_ID;

   /*----------------------------------------------------------------+
   | Stow "*IDENT" in IPVMID and copy *IDENT parms to CONNECT plist. |
   | Execute an IUCV CONNECT to *IDENT.                              |
   +----------------------------------------------------------------*/

   memset(&conn, 0, sizeof(conn));
   memcpy(conn.vmid, "*IDENT  ", 8);
   memcpy(conn.pgm, &ident, sizeof(ident));

   rc = iucvconn("IDENTHAN", &conn);
   if (rc != 0) {
      printf("Return code from iucvconn IDENTHAN was %d\n",rc);
      if (rc == 1)
         printf("IPRCODE = x'%X'\n",conn.ip.rcode);
      exit(12);
      }
   ident_pathid = conn.pathid;    /* Save IDENTHAN pathid           */
   sigpause(0);                   /* Wait for CONNECTION COMPLETE   */
                                  /*  from *IDENT                   */

   /*----------------------------------------------------------------+
   | Wait for initial CONNECTION PENDING from APPCSEND.              |
   +----------------------------------------------------------------*/

   sigpause(0);

   /*----------------------------------------------------------------+
   | As long as some SENDER is connected, wait for incoming messages.|
   +----------------------------------------------------------------*/

   while (connects > 0) sigpause(0);

   /*----------------------------------------------------------------+
   | All paths have been terminated.  Terminate IUCV processing.     |
   +----------------------------------------------------------------*/

   iucvclr("APPCSERV");
   iucvclr("IDENTHAN");

   exit(0);

   }

#pragma eject
/*-------------------------------------------------------------------+
| SIGIUCV signal handler.  Signals are blocked until return.         |
+-------------------------------------------------------------------*/

void appctrap(void)

   {
   struct appc_send_plist recv;   /* used to receive allocate        */
   struct appc_send_plist *send;  /* APPC SEVER plist pointer       */
   appc_conn_data *XID;           /* Pointer to external interrupt  */
                                  /* data returned by siginfo.      */
   int rc;                        /* Return code from iucvacc.      */
   ident_parms ident;             /* so we can test RCODE            */
   char  *allocate_data;          /* ptr to allocate data            */

   /*----------------------------------------------------------------+
   | Get a pointer to the external interrupt data.  Use the interrupt|
   | type to determine what to do.                                   |
   +----------------------------------------------------------------*/

   XID = (appc_conn_data *) siginfo();
   switch (XID->ip1.type) {

      case APPC_CONNECTION_PENDING:
                                  /* Retrieve allocation data        */
         allocate_data = malloc(XID->bf2.ln);
         memset(&recv, 0, sizeof(recv));
         recv.pathid = XID->pathid;
         recv.ip2.flags2 = IPWAIT;
         recv.bf1.adr = allocate_data;
         recv.bf1.ln = XID->bf2.ln;
         rc = appcrecv(&recv);
         if (rc != 2) {
            printf("Error %d receiving allocation data\n", rc);
            printf("IPRCODE = x'%X'\n", recv.ip1.rcode);
            printf("IPAUDIT = %x\n", recv.audit);
            exit(16);
            }

         XID->ip1.type = 0;       /* Accept the connection          */
         XID->ip2.flags2 = 0;
         if ((rc = iucvacc("APPCSERV",
                              (struct iucv_path_plist *) XID)) != 2) {
            printf("Return code from iucvacc = %d\n",rc);
            if (rc == 1)
               printf("IPRCODE = x'%X'\n",XID->ip1.rcode);
            exit(20);
            }
         connects++;              /* Keep track of the number of    */
         break;                   /* connections made.              */

      case APPC_INCOMING_MSG:
                                  /* Call message handler           */
         rcvrply((struct appc_send_plist *)XID);
         break;

      case PATH_SEVERED:
                                  /* *IDENT decided to stop.        */
         if (XID->pathid == ident_pathid) {
            memcpy(&ident, XID->resid, sizeof(ident));
            if (ident.rcode != 0x00) {
               printf("*IDENT path severed. rcode = %x\n", ident.rcode);
               exit(24);
               }
            }
         else {                   /* An IUCV sever?  Really?         */
            printf("Unexpected sever. IPPATHID = %d\n", XID->pathid);
            exit(28);
            }
         break;

      case CONNECTION_COMPLETE:
                                  /* *IDENT connection complete      */
         if (XID->pathid == ident_pathid) {
            puts("Connection to *IDENT complete\n");
            }
         else {                   /* Some other connection?          */
            printf("Unexpected connection complete. Path = %d\n",
                                                          XID->pathid);
            exit(32);
            }
         break;

      case APPC_SEVER_INTERRUPT:
                                  /* APPCSEND decided to stop.      */
         send = (struct appc_send_plist *) XID;
         send->ip2.flags2 = IPWAIT;
         send->sendop = IPSNORM;
         send->bf1.adr = NULL;
         send->bf1.ln = 0;
         if ((rc = appcsevr("APPCSERV", send, "ONE")) != 2) {
            printf("Return code from appcsevr = %d\n",rc);
            printf("IPRCODE is x'%X'\n", send->ip1.rcode);
            exit(36);
            }

         connects--;              /* Update number of connections.  */
         break;


      default:                    /* Handle other interrupt types.  */
         printf("Unexpected interrupt type %d\n",XID->ip1.type);
         fflush(stdout);
         abort();
      }

   /*----------------------------------------------------------------+
   | Re-establish this function as the SIGIUCV signal handler.       |
   +----------------------------------------------------------------*/

   signal(SIGIUCV, appctrap);
   return;
   }

#pragma eject
/*-------------------------------------------------------------------+
| Function to issue APPC RECEIVE and print the message.              |
+-------------------------------------------------------------------*/

static void rcvrply(struct appc_send_plist *int_data)

   {
   int msg_len;                   /* Incoming message length.       */
   struct senddata {
      unsigned short length;      /* length of data to send          */
      char message(|120+2|);      /* Message buffer.                */
      } logrec;
   int rc = 0;                    /* return code                     */

   /*----------------------------------------------------------------+
   | Create APPC RECEIVE parameter list using the external           |
   | interrupt data area.  Issue the APPC RECEIVE.                   |
   +----------------------------------------------------------------*/

   int_data->ip2.flags2 = IPWAIT;
   int_data->bf1.adr = (char *) &logrec;
   int_data->bf1.ln = sizeof(logrec);
   rc = appcrecv(int_data);
   if (rc != 2) {
      printf("Return code from receive = %d\n", rc);
      printf("IPRCODE is x'%X'\n", int_data->ip1.rcode);
      exit(40);
      }

   /*----------------------------------------------------------------+
   | Perhaps the sender wants to sever.  If so, confirm sever.       |
   +----------------------------------------------------------------*/

   if (int_data->ip2.whatrc == IPCNFSEV) {
      int_data->sendop = IPCNFRMD;
      if ((rc = appcscfd(int_data)) != 2) {
         printf("Error %d attempting to confirm sever\n", rc);
         printf("IPRCODE is x'%X'\n", int_data->ip1.rcode);
         exit(44);
         }
      return;
      }

   /*----------------------------------------------------------------+
   | If the return code is anything else, bad news.                  |
   +----------------------------------------------------------------*/

   if (int_data->ip2.whatrc != IPSEND) {
      puts("Protocol error.  Sender not in receive state\n");
      exit(48);
      }

   /*----------------------------------------------------------------+
   | Upon return, int_data->bf2.ln contains the number of unused     |
   | bytes in the message buffer.  Print the message.                |
   +----------------------------------------------------------------*/

   msg_len = sizeof(logrec) - int_data->bf2.ln - 2;
   printf("SENDER says \"%.*s\"\n", msg_len, logrec.message);

   /*----------------------------------------------------------------+
   | Prompt for a reply message.  If EOF, quit.                      |
   +----------------------------------------------------------------*/

   fgets(logrec.message, sizeof(logrec.message), stdin);
   if (feof(stdin)) {
      puts("Terminating due to end-of-file.\n");
      exit(52);
      }

   /*----------------------------------------------------------------+
   | Fill in APPC SENDDATA parameter list with buffer address/length.|
   | Send reply.                                                     |
   +----------------------------------------------------------------*/

   int_data->ip2.flags2 = IPWAIT;
   int_data->sendop = IPDATA;

   int_data->bf1.adr = (char *) &logrec;
   logrec.length = strlen(logrec.message) + 1;
   int_data->bf1.ln = logrec.length;
   rc = appcsdta(int_data);
   if (rc != 2) {
      printf("Error %d on reply SENDDATA\n", rc);
      printf("IPRCODE is x'%X'\n", int_data->ip1.rcode);
      exit(56);
      }

   /*----------------------------------------------------------------+
   | We are still in SEND state.  Ask to turn conversation around.   |
   +----------------------------------------------------------------*/

   int_data->ip2.flags2 = IPWAIT;
   int_data->sendop = IPPREPRC;

   if ((rc = appcscnf(int_data)) != 2) {
      printf("Error requesting confirmation to receive. rc = %d\n",
         rc);
      printf("IPRCODE = x'%X'\n", int_data->ip1.rcode);
      exit(60);
      }

   }

Copyright (c) 2000 SAS Institute Inc. All Rights Reserved.
Terms of Use & Legal Information | Privacy Statement