Chapter Contents

Previous

Next
appcsevr

APPC/VM Communication Example Programs

The following example programs illustrate how the APPC/VM interface can be used to communicate with a global resource manager program. The user program is named APPCSEND. The global resource manager program is named APPCSERV. These programs assume that the global resource is within the same TSAF collection.

Start APPCSERV first. When started, the APPCSEND program prompts for a message to be sent to APPCSERV. APPCSERV displays the message and prompts for a reply message. The reply, in turn, is sent back to APPCSEND, which displays the reply and prompts for another message. This cycle continues until APPCSEND gets a null input string.


The APPCSEND Program

This program has two functions: main , which contains the bulk of the program code, and appctrap , the SIGIUCV signal-handler function. The main function initializes IUCV signal processing and requests a connection to the target resource APPCSERV. If the request is granted, APPCSEND prompts the user for a message string and sends the message to APPCSERV. It then waits for a reply that, when received, is displayed on the terminal. If a null message is read, the path to APPCSEND is severed. The appctrap accepts the initial CONNECTION COMPLETE interrupt from APPCSERV. This function also handles the FUNCTION COMPLETE and SEVER INTERRUPT external interrupts.

Here is the APPCSEND program:

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

void appctrap(void);                /* Declare SIGIUCV handler.       */

                                    /* Set up stdin amparms.          */
char *_stdiamp = "prompt=What message do I send?\n, eof=";
static int rep_len = 0;
static short pathid = 0;
static short ident_pathid = 0;

main()
{
   struct appc_conn_plist conn;  /* APPC plist for CONNECT, SEVER     */
   struct appc_send_plist send;  /* APPC plist for SENDDATA, SENDCNFD */
   int maxconns,                 /* maximum number of IUCV connec-    */
                                 /* tions for this virtual machine    */
       rc;                       /* return code from APPC functions   */
   struct senddata {
      unsigned short length;     /* length of data to send            */
      char message[120+2];       /* message buffer                    */
   } logrec, reply;              /* log record and reply buffers      */

      /* 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 APPCSEND.                           */
   if ((rc = iucvset("APPCSEND",&maxconns)) != 0) {
      printf("Return code from iucvset was %d\n", rc);
      exit(4);
   }
   printf("Maximum IUCV connections: %d\n", maxconns);

      /* Fill in the APPC "conn" parameter list with the target       */
      /* resource id, "APPCSERV".                                     */

      /* Note that the resource name in IPRESID must be eight bytes   */
      /* long, padded on the right with blanks if necessary.          */
   memset(&conn, 0, sizeof(conn));
   conn.ip2.flags2 = IPLVLCF + IPMAPPED;
   memcpy(conn.resid, "APPCSERV",8);

      /* Request an APPC CONNECT to the resource named in the         */
      /* parameter list.  Check for an IUCV error (return code != 0)  */
      /* and print the APPC error code.                               */
   rc = appcconn("APPCSEND", &conn, 0);
   if (rc != 0) {
      printf("Return code from appcconn was %d\n", rc);
      if (rc == 1)
         printf("IPRCODE = x'%X'\n", conn.ip1.rcode);
      exit(8);
   }

      /* Now we're ready.  The first interrupt we will receive is the */
      /* CONNECTION COMPLETE interrupt that occurs when APPCSERV      */
      /* issues an APPC ACCEPT.                                       */
   sigpause(0);

      /* Initialize the SEND parameter list with the pathid and       */
      /* buffer addresses, and the length of the reply buffer.        */
   memset(&send, 0, sizeof(send));
   send.pathid = pathid;
   send.sendop = IPSNDRCV;
   send.bf1.adr  = (char *) &logrec;
   send.bf2.adr  = (char *) &reply;
   send.bf2.ln  = sizeof(reply);

      /* Prompt for input messages and send until EOF.                */
   fgets(logrec.message, sizeof(logrec.message), stdin);
   while (!feof(stdin)) {

         /* Put message length in the SEND parameter list.            */
      logrec.length = strlen(logrec.message) + 1;
      send.bf1.ln = logrec.length;

         /* Send message.  Wait (via sigpause) for reply. Upon        */
         /* receipt of reply, 'rep_len' contains the number of        */
         /* unused bytes in the reply buffer.  Print the reply        */
         /* and prompt for a new message.                             */
      appcsdta(&send);
      sigpause(0);
      rep_len = reply.length - sizeof(reply.length);
      printf("APPCSERV replies "%.*s"\n", rep_len,
              reply.message);
      fgets(logrec.message, sizeof(logrec.message), stdin);
   }

      /* We're ready to quit.  Ask the server if it's OK to sever.    */
      /* If so, then sever.                                           */

   memset(&send, 0, sizeof(send));
   send.pathid = pathid;
   send.ip2.flags2 = IPWAIT;       /* Specify WAIT=YES.               */
   send.sendop = IPCNFSEV;

   if ((rc = appcsdta(&send)) != 2) {
      printf("Return code from appcsdta = %d\n", rc);
      if (rc == 1)
         printf("IPRCODE = x'%X'\n", send.ip1.rcode);
      exit(12);
   }

   memset(&conn, 0, sizeof(conn));
   conn.pathid = pathid;
   conn.ip2.flags2 = IPWAIT;      /* Specify WAIT=YES.                */
   conn.sendop = IPSNORM;

   if ((rc = appcsevr("APPCSEND", &conn,"ONE")) != 2) {
      printf("Return code from appcsever = %d\n",rc);
      if (rc == 1)
         printf("IPRCODE = x'%X'\n", conn.ip1.rcode);
      exit(16);
   }

      /* Terminate APPC communications for APPCSEND.                  */
   iucvclr("APPCSEND");
   exit(0);
}

#pragma eject

/* The SIGIUCV signal handler.  Signals are blocked until return.     */

void appctrap(void)
{
   appc_conn_data *XID;             /* Pointer to external interrupt  */
                                    /* data returned by siginfo.      */
   int rc;

      /* 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_COMPLETE:
         pathid = XID->pathid;      /* Save the pathid.               */
         break;

      case APPC_FUNCTION_COMPLETE:
                                    /* See if it's for CONFIRM.       */
         if (XID->pathid == pathid && XID->ip2.whatrc == IPSNDCNF) {
            struct appc_send_plist *send =
               (struct appc_send_plist *)XID;
            send->sendop = IPCNFRMD;
            rc = appcscfd(send);
            if (rc != 2) {
               printf("Error %d confirming request to recv\n", rc);
               printf("IPRCODE = x'%X'}n", XID->ip1.rcode);
               exit(20);
            }
         }
         break;

      case APPC_SEVER_INTERRUPT:    /* Handle unexpected termination  */
                                    /* of APPCSERV.                   */
         puts("Unexpected SEVER!");
         exit(24);

      default:                      /* Handle unexpected signal type. */
         printf("Unexpected interrupt type x'%X'\n",XID->ip1.type);
         fflush(stdout);
         abort();
   }

      /* Re-establish this function as the SIGIUCV signal handler.    */
   signal(SIGIUCV, &appctrap);
   return;
}


The APPCSERV Program

The APPCSERV program contains three functions. The main function initializes IUCV signal processing and connects to the *IDENT system service. It then waits for connection requests. As long as some program is connected, it processes interrupts. The appctrap function is the IUCV signal handler that processes incoming external interrupts. Generally these are CONNECTION PENDING interrupts, which are requests from APPCSEND to connect, and incoming message interrupts, which are messages from APPCSEND. This function can also handle the SEVER interrupts that occur if *IDENT or APPCSEND sever the path and the single CONNECTION COMPLETE interrupt that indicates the connection to *IDENT is complete. Finally, rcvrply receives an incoming message, collects a reply from the user, and sends the reply to APPCSEND. Here is the APPSERV program:

#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 *);

main()
{
   int maxconns;               /* number of IUCV connections allowed  */
   int 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();
   }

      /* Reestablish 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",
      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", rc);
      printf("IPRCODE = x'%X'\n", int_data->ip1.rcode);
      exit(60);
   }
}


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.