Inter-User Communications Vehicle (IUCV) Functions

Introduction

The SAS/C Library defines the SIGIUCV asynchronous signal in support of programs that want to take advantage of IUCV communications. The library also provides a set of functions that invoke VM IUCV functions and the CMS support of IUCV. The SAS/C functions, when used in conjunction with the SIGIUCV signal, enable programs running in CMS to communicate with other virtual machines, CP system services, or themselves.

This chapter covers the SAS/C IUCV functions. Topics include a brief introduction to IUCV communications in a virtual machine, CMS support of IUCV, IUCV parameter lists and external interrupt data formats, and IUCV library functions.

Although an overview of the IUCV and CMS IUCV functions is provided, this discussion of IUCV communications is written primarily for programmers experienced with IUCV. A knowledge of CP and CMS is assumed. More detailed coverage of all aspects of IUCV can be found in the appropriate IBM publications for your release of VM. For a complete description of how the SAS/C Library supports asynchronous signals and the use of signal-related SAS/C functions, refer to Chapter 5, "Signal-Handling Functions," in SAS/C Library Reference, Volume 1 .

IUCV Communications Overview

IUCV is a communications facility that enables programs running in a virtual machine to communicate with programs in other virtual machines. An IUCV program also can send data to or receive data from a CP system service or communicate asynchronously with itself. IUCV allows any amount of data to be transferred during a single transaction.

IUCV transfers data in blocks known as messages. Messages travel from a source communicator to a target communicator along a route called the message path. Each communicator can have many paths and can be a source communicator on some paths and a target communicator on others simultaneously.

When you write a program that permits IUCV communication, you invoke IUCV functions to perform the following basic IUCV tasks:

Additional IUCV functions also perform these tasks: IUCV recognizes no entity smaller than a virtual machine. In order for several programs in a CMS virtual machine to use IUCV at the same time, CMS provides supporting IUCV routines that manage IUCV paths and route messages to the responsible programs. CMS IUCV maintains a table of IUCV programs and associates a name (provided by the program) with each IUCV path active in the virtual machine.

Programs written in assembler invoke IUCV functions via an instruction known as the IUCV macro instruction. The IUCV macro instruction specifies the IUCV function requested and a parameter list that contains the information needed to perform it. CMS IUCV services are provided by two assembler macros called HNDIUCV and CMSIUCV. HNDIUCV provides support for IUCV initialization and termination. CMSIUCV handles the connection to the communicating program. The CMSIUCV and HNDIUCV macros require that the program provide a name for CMS to use to keep track of IUCV paths. If a CMS IUCV macro in turn invokes an IUCV macro instruction, an IUCV parameter list also is required.

All SAS/C IUCV functions invoke either the IUCV macro instruction or one of the CMS IUCV macros. When a SAS/C function uses CMS IUCV support, the program must provide a name parameter and possibly an IUCV parameter list. When a SAS/C function invokes the IUCV macro instruction directly, the IUCV parameter list must be provided.

The SAS/C functions are described in detail in the following pages, including specification of their parameters and the CMS IUCV service or IUCV macro invoked. The <cmsiucv.h> header file, providing structure definitions for the IUCV parameter lists and external interrupt data, also is described.

To summarize the IUCV functions and tasks involved, the following table shows IUCV functions as implemented by the library. Listing the macro and parameter involved in the function call illustrates how the library interfaces with IUCV and CMS.


   SAS/C Function    Purpose              IUCV or CMS Macro

   iucvset           Initialize IUCV      Invoke HNDIUCV
                     communications       macro with SET
                                          parameter

   iucvacc           Accept a pending     Invoke CMSIUCV
                     connection           macro with ACCEPT
                                          parameter

   iucvconn          Request that a       Invoke CMSIUCV
                     path be              macro with CONNECT
                     established          parameter

   iucvsevr          Terminate an         Invoke CMSIUCV
                     existing path        macro with SEVER
                                          parameter

   iucvclr           Terminate IUCV       Invoke HNDIUCV
                     communications       macro with CLR
                                          parameter

   iucvrply          Respond to a         Invoke the IUCV
                     message              macro instruction
                                          for REPLY

   iucvrecv          Accept a message     Invoke the IUCV
                                          macro instruction
                                          for function
                                          RECEIVE

   iucvrej           Refuse a message     Invoke the IUCV
                                          macro instruction
                                          for function
                                          REJECT

   iucvsend          Send a message       Invoke the IUCV
                                          macro instruction
                                          for function SEND

   iucvqs            Temporarily suspend  Invoke the IUCV
                     communication        macro instruction
                                          for function
                                          QUIESCE

   iucvresm          Restore              Invoke the IUCV
                     communication after  macro instruction
                     a QUIESCE            for function
                                          RESUME

   iucvtcmp          Determine if a       Invoke the IUCV
                     message has been     macro instruction
                     completed            for function TEST
                                          COMPLETION

   iucvpurg          Terminate a message  Invoke the IUCV
                                          macro instruction
                                          for function PURGE

 

IUCV Signal Handling, and Message Processing

Inter-user communication is driven by asynchronous IUCV external interrupts. That is, IUCV requires synchronization and cooperation of communicating processes. As seen in the previous section, the library relies on IUCV and CMS support of IUCV to help coordinate these interrupts. However, programs initiate and handle IUCV interrupts in the context of SAS/C signal processing. All IUCV interrupts are identified by the asynchronous signal SIGIUCV. A program must first call signal or sigaction to establish a handler for SIGIUCV signals. Calling signal identifies a function (called a handler) that should be invoked when an IUCV interrupt occurs. The handler should call the signal function siginfo, which returns a pointer to a structure containing the external interrupt data.

Signal processing handles the IUCV interrupts associated with the basic IUCV tasks. IUCV external interrupts can be divided into those concerning connections and paths and those prompted by message transfer. The IUCV external interrupt types are summarized in the following table.


 Connection and PathInterrupts     Message Transfer
   Interrupts                        Interrupts
 

   Connection pending                Incoming priority message

   Connection complete               Incoming message
                                     nonpriority

   Path severed                      Incoming priority reply

   Path quiesced                     Priority reply

   Path resumed

 
The library, at the time of the first call to signal with the SIGIUCV signal identifier, initializes all library handling of IUCV external interrupts for the program and associates a SIGIUCV handler with the external interrupt. Although iucvset can be called any number of times within a program to establish multiple message paths, only one SIGIUCV handler can be associated with IUCV signals at any one time. Of course, programs can redefine handlers in subsequent calls to signal, or a single handler can use the external interrupt type to route the signal to subsidiary functions. Because each message is uniquely identified, the SIGIUCV handler can use this data to route signals of similar types to other functions.

A simple example of the complete IUCV communication process is given in the following table. In this example, calls to the signal functions sigblock, sigpause, and siginfo are combined with SAS/C IUCV function calls to process a message sent from a source virtual machine to a receiving or target virtual machine. Note that before any message transfer can occur, a call must be made to signal to identify the handler for subsequent SIGIUCV interrupts. Note also that the call to signal must be paired with a call to iucvset to initialize communication (step 1). These calls must be made by both sender and receiver before any inter-user communication can take place. Subsequent calls are traced back and forth across the table. In step 2, for example, the receiving program issues a call to sigpause to wait for the sending program's interrupt. In step 3, the sender issues an iucvconn to attempt a connection with the receiver, and so on.


  Sending Program     Purpose of Call     Receiving Program
   Function Called                         Function Called
 

   1. signal           Initialize          signal sigblock
   sigblock iucvset    communications      iucvset

                       Wait for            2. sigpause
                       interrupt

   3. iucvconn         Sender attempts     4. siginfo
                       to connect;
                       receiver
                       recognizes a
                       connection
                       pending

   5. sigpause         Sender waits        6. iucvacc
                       until receiver
                       accepts
                       connection

   7. siginfo          Sender recognizes
   iucvsend sigpause   connection is
                       complete, sends a
                       message, and
                       waits for the
                       reply

                       Receiver            8. siginfo
                       recognizes an       iucvrecv iucvrply
                       incoming message,   sigpause
                       receives it,
                       replies, and
                       waits

   9. siginfo          Sender recognizes
                       an incoming reply
                       and processes it

   10. iucvsevr        Message transfer    11. siginfo
   iucvclr             complete; sender
                       severs path and
                       clears; receiver
                       recognizes path
                       severed

 
In this table, many of the IUCV function calls occur based on the information returned from the call to siginfo. This signal function returns a pointer to one of three external interrupt structures. The structure pointed to depends on the interrupt subtype. These structures and their parameters are easily accessible to the program. The next section discusses the structures involved in IUCV communication and the information available to the program.

IUCV Parameter Lists and External Interrupt Data Formats

The header file for the IUCV functions is <cmsiucv.h>. Three structures cover all IUCV parameter lists and external interrupt data formats. Each structure used in IUCV communication is discussed on the following pages. As indicated by the comments, <cmsiucv.h> parameter list fields correspond to fields in the parameter lists for each individual IUCV function. These fields are explained in detail in the IBM documentation mentioned in Introduction .

The structure iucv_path_plist defines the ACCEPT, CONNECT, QUIESCE, RESUME, and SEVER parameter list. External interrupt data are defined for PENDING CONNECTION, CONNECTION COMPLETE, SEVER, QUIESCE, and RESUME external interrupts.

 struct iucv_path_plist {
    short pathid;                  /* IPPATHID                      */
    char flags1;                   /* IPFLAGS1                      */
    union {
       char rcode;                 /* IPRCODE                       */
       char type;                  /* IPTYPE                        */
    } ip;
    short msglim;                  /* IPMSGLIM                      */
    char fcncd;                    /* IMFCNCD                       */
    char _;
    char vmid[8];                  /* IPVMID                        */
    char pgm[8];                   /* IPUSER                        */
    char user[8];
    double _d;                     /* (used only for alignment)     */
 };

 typedef struct iucv_path_plist iucv_path_data;
 
The structure iucv_msg_plist defines the parameter list for the RECEIVE, REJECT, REPLY, and SEND functions. External interrupt data are defined for the pending message external interrupt.
 struct iucv_msg_plist {
    short pathid;                  /* IPPATHID                       */
    char flags1;                   /* IPFLAGS1                       */
    union {
       char rcode;                 /* IPRCODE                        */
       char type;                  /* IPTYPE                         */
    } ip;
    int msgid;                     /* IPMSGID                        */
    int tgrcls;                    /* IPTRGCLS                       */
    union {
       char data[8];               /* IPRMMSG1/IPRMMSG2              */
       struct _adlen bf1;          /* IPBFADR1/IPBFLN1F              */
    } msg;
    int srccls;                    /* IPSRCCLS                       */
    int msgtag;                    /* IPMSGTAG                       */
    struct _adlen bf2;             /* IPBFADR2/IPBFLN2F              */
    double _d;                     /* (used only for alignment)      */
 };

 typedef struct iucv_msg_plist iucv_msg_data;
 
The last of the three IUCV structures is iucv_comp_plist. This structure defines the parameter list for the PURGE and TEST COMPLETION functions. External interrupt data are defined for the complete message external interrupt.
 struct iucv_comp_plist {
    short pathid;                  /* IPPATHID                       */
    char flags1;                   /* IPFLAGS1                       */
    union {
       char type;                  /* IPTYPE                         */
       char rcode;                 /* IPRCODE                        */
    } ip;
    int msgid;                     /* IPMSGID                        */
    unsigned audit;                /* IPAUDIT (byte 4 not applicable)*/
    char msgdata[8];               /* IPRMMSG1/IPRMMSG2              */
    int srccls;                    /* IPSRCCLS                       */
    int msgtag;                    /* IPMSGTAG                       */
    int _;
    int bfln2f;                    /* IPBFLN2F                       */
    double _d;                     /* (used only for alignment)      */
 };

 typedef struct iucv_comp_plist iucv_comp_data;
 

The values for the interrupt subtypes, as defined for the structure variable ip.type, are shown in the following table:


  Variable             Value

   CONNECTION_PENDING    1

   CONNECTION_COMPLETE   2

   PATH_SEVERED          3

   PATH_QUIESCED         4

   PATH_RESUMED          5

   INCOMING_PRI_REPLY    6

   INCOMING_REPLY        7

   INCOMING_PRI_MSG      8

   INCOMING_MSG          9

 
The type definitions (such as iucv_path_data) and interrupt types (ip.type ) enable you to control the way your program handles IUCV interrupts. The following code illustrates how this can be done:
 iucv_path_data *XID;

 XID = (iucv_path_data *) siginfo();
 switch (XID->ip.type) {
    case CONNECTION_COMPLETE:
       break;
    case INCOMING_REPLY:   /* Get reply length. */
       rep_len = ((iucv_msg_data *)XID)->bf2.ln;
       break;
 }
 
In this section of code, a cast expression converts the value returned by siginfo to a pointer of type iucv_path_data so it can be assigned to XID. A case statement is then used to handle the possible interrupt subtypes returned in ip.type.

Message Queues

When an IUCV interrupt occurs, the library places the IUCV external interrupt data on a pending interrupt data queue until it is possible to raise the SIGIUCV signal. Refer to the section "Discovering Asynchronous Signals" in Chapter 5 of SAS/C Library Reference, Volume 1 . There is no limit on the number of interrupts that can be placed on the queue.

Return Codes

The library also interfaces with IUCV and CMS in providing return codes. The return codes operate as follows: For a complete list and explanation of IUCV function return codes, refer to the VM/SP System Programmer's Guide appropriate for your release.

Function Descriptions

Descriptions of each IUCV function follow. Each description includes a synopsis, description, discussions of return values and portability issues, and an example. Also, errors, cautions, diagnostics, implementation details, and usage notes are included if appropriate. A comprehensive example of IUCV communication as implemented by the SAS/C Library follows the function descriptions.

iucvacc -- Perform an IUCV ACCEPT

SYNOPSIS

 #include <cmsiucv.h>

 int iucvacc(const char *name, struct iucv_path_plist *acc_parmlst);
 

DESCRIPTION

iucvacc requests CMS to issue an IUCV ACCEPT. name points to a string that must match the name argument to a previously invoked iucvset function. acc_parmlst is a pointer to an IUCV ACCEPT parameter list.

RETURN VALUE

iucvacc returns 0 if the function call was successful. If signal(SIGIUCV,fp) has never been called, iucvacc returns -1. If the CMSIUCV macro returns a nonzero return code, iucvacc returns that value. If an IUCV error occurs, iucvacc returns 1, and the value of IPRCODE is available in acc_parmlst->ip.rcode.

CAUTION

You must call iucvset before calling iucvacc.

IMPLEMENTATION

iucvacc invokes the CMS CMSIUCV macro with the ACCEPT parameter.

EXAMPLE

 #include <cmsiucv.h>

    /* Issue an IUCV ACCEPT in response to a             */
    /* pending connection.                               */
 int rc;
    /* external interrupt data for a pending connection  */
 iucv_path_data *p_connect;
    /* other IUCV CONNECT parameter list initializations */
 .
 .
 .
 p_connect->ip.type = 0;

 rc = iucvacc("RECEIVER",p_connect);
 

iucvclr -- Terminate IUCV Communications

SYNOPSIS

 #include <cmsiucv.h>

 int iucvclr(const char *name);
 

DESCRIPTION

iucvclr terminates IUCV communications for a program. name points to a string that must match the name argument to a previously invoked iucvset function.

RETURN VALUE

iucvclr returns 0 if the function call was successful. If signal(SIGIUCV,fp) has not been called, iucvclr returns -1. If the HNDIUCV macro returns a nonzero return code, iucvclr returns that value. If an IUCV error occurs, iucvclr returns 1000 + the value of IPRCODE (as does HNDIUCV).

CAUTION

You must call iucvset before calling iucvclr.

IMPLEMENTATION

iucvclr invokes the CMS HNDIUCV macro with the CLR parameter and frees the external interrupt data queue associated with name.

EXAMPLE

 #include <cmsiucv.h>
 .
 .
 .
 rc = iucvclr("SENDER");
 

iucvconn -- Perform an IUCV CONNECT

SYNOPSIS

 #include <cmsiucv.h>

 int iucvconn(const char *name, struct iucv_path_plist *conn_parmlst);
 

DESCRIPTION

iucvconn requests CMS to issue an IUCV CONNECT. name points to a string that must match the name argument to a previously invoked iucvset function. conn_parmlst is a pointer to an IUCV CONNECT parameter list.

RETURN VALUE

iucvconn returns 0 if the function call was successful. If signal(SIGIUCV,fp) has not been called, iucvconn returns -1 . If the CMSIUCV macro returns a nonzero return code, iucvconn returns that value. If an IUCV error occurs, iucvconn returns 1, and the value of IPRCODE is available in conn_parmlst->ip.rcode.

CAUTION

You must call iucvset before calling iucvconn.

IMPLEMENTATION

iucvconn invokes the CMS CMSIUCV macro with the CONNECT parameter.

EXAMPLE

 #include <cmsiucv.h>
 #include <lcstring.h>

 int rc;
 struct iucv_path_plist path;
 .
 .
 .

    /* Name the receiving userid and program. */
 memset((char *) &path,0,sizeof(path));
 memcpyp(path.vmid,"USERID",sizeof(path.vmid),6,' ');
 memcpy(path.pgm,"RECEIVER",8);

 rc = iucvconn("SENDER",&path);
 

IUCV -- Perform IUCV Functions

SYNOPSIS

 #include <cmsiucv.h>

 int iucvpurg(struct iucv_comp_plist *comp_p);
 int iucvqs(struct iucv_path_plist *path_p);
 int iucvrecv(struct iucv_msg_plist *msg_p);
 int iucvrej(struct iucv_msg_plist *msg_p);
 int iucvresm(struct iucv_path_plist *path_p);
 int iucvrply(struct iucv_msg_plist *msg_p);
 int iucvsend(struct iucv_msg_plist *msg_p);
 int iucvtcmp(struct iucv_comp_plist *comp_p);
 

DESCRIPTION

Each of these functions performs an IUCV function. msg_p, path_p, and comp_p point to the IUCV parameter list associated with that function. The function names and IUCV functions are associated as follows:
   SAS/C function   IUCV function

   iucvpurg          PURGE

   iucvqs            QUIESCE

   iucvrecv          RECEIVE

   iucvrej           REJECT

   iucvresm          RESUME

   iucvrply          REPLY

   iucvsend          SEND

   iucvtcmp          TEST COMPLETION

 

RETURN VALUE

All of the functions return the condition code set by the IUCV macro instruction.

CAUTION

You must have established an IUCV signal handler with signal or sigaction and initialized IUCV communications with iucvset before invoking any of these functions.

IMPLEMENTATION

The functions invoke the IUCV macro with the associated function name and parameter list.

EXAMPLE

See the example for iucvset.

RELATED FUNCTIONS

sigaction, signal

SEE ALSO

Chapter 5, "Signal-Handling Functions," in SAS/C Library Reference, Third Edition, Volume 1.

iucvset -- Initialize IUCV Communications

SYNOPSIS

 #include <cmsiucv.h>

 int iucvset(const char *name, int *maxconns);
 

DESCRIPTION

iucvset identifies an IUCV program to CMS. name is a 1- to 8-character string identifying the communicating program's name. For example, a SAS/C program called sender.c may specify the name "SENDER". If name is less than eight characters long, it is padded with blanks on the right. If name is greater than eight characters, it is truncated. The maximum number of connections for the virtual machine is returned in the integer pointed to by maxconns.

You can call iucvset any number of times as long as each call uses a different name string.

RETURN VALUE

iucvset returns 0 if the function call was successful. iucvset returns a negative code as follows: If the HNDIUCV macro returns a nonzero return code, iucvset returns that value.

CAUTIONS

You must call signal or sigaction to establish an IUCV interrupt handler before calling iucvset. An IUCV program must be ready to handle incoming IUCV interrupts even before iucvset has returned.

IMPLEMENTATION

iucvset invokes the CMS HNDIUCV macro with the SET parameter. In addition, it allocates an initial 4K external interrupt data buffer.

EXAMPLE

 #include <cmsiucv.h>
 #include <stdio.h>

 int maxconns, rc;
 .
 .
 .

 rc = iucvset("SENDER",&maxconns);
 if (rc != 0)
    puts("iucvset failed.");
 

-- Perform an IUCV SEVER

SYNOPSIS

 #include <cmsiucv.h>

 int iucvsevr(const char *name, struct iucv_path_plist *svr_parmlst,
              const char *code);
 

DESCRIPTION

iucvsevr requests CMS to issue an IUCV SEVER. name points to a string that must match the name argument to a previously invoked iucvset function. svr_parmlst is a pointer to an IUCV SEVER parameter list.

code can be either "ALL" or "ONE". If it is "ONE", only the one path specified by svr_parmlist.pathid is severed (using SEVER). If code is "ALL", all paths owned by the program are severed. The "ALL" and "ONE" parameters must be coded exactly as shown, uppercase and enclosed in quotation marks, with no substitutions or variations in syntax.

RETURN VALUE

iucvsevr returns 0 if the function call was successful. If neither signal nor sigaction has not been called to handle the SIGIUCV signal, iucvsevr returns -1. If the CMSIUCV macro returns a nonzero return code, iucvsevr returns that value. If an IUCV error occurs, iucvsevr returns 1, and the value of IPRCODE is available in svr_parmlst->ip.rcode.

CAUTION

You must call iucvset before calling iucvsevr.

IMPLEMENTATION

iucvsevr invokes the CMS CMSIUCV macro with the SEVER parameter. The value of the CODE parameter depends on the value of code.

EXAMPLE

 #include <cmsiucv.h>

 short pathid;           /* PATHID to be severed */

 path.pathid = pathid;
 rc = iucvsevr("SENDER",&path,"ONE");
 

An Example of IUCV Communication

The following example illustrates how two virtual machines can communicate with each other by sending IUCV messages. The first example program is called SENDER. This program prompts for a message string to be input from the terminal and sends the string to the second example program, RECEIVER. RECEIVER displays the message and prompts for a reply string. The reply string is sent back to SENDER. SENDER displays the reply, and the cycle repeats until a zero-length line is entered in response to SENDER's prompt.

The SENDER program

This program has only two functions. The main function initializes signal processing and IUCV. It uses fgets to read message strings and printf to display reply strings. The sigpause function makes the program wait until a reply is sent. The sigblock function blocks SIGIUCV signals until the program is ready to handle them.

The iucvtrap function is the SIGIUCV signal handler. Only two IUCV interrupt types are expected: a CONNECTION COMPLETE interrupt in response to the IUCV CONNECT and an INCOMING REPLY in response to each IUCV SEND.

The source code for these examples is provided with the compiler and library. Ask your SAS Software Representative for SAS/C software products for information about obtaining copies of these programs.

                 /* SENDER */

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

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

    /* Set up stdin amparms.*/
 char *_stdiamp = "prompt=What message do I send?,eof=";

 int rep_len = 0;
 short pathid = 0;

 main()
 {
    struct iucv_path_plist path;    /* IUCV plist for CONNECT, SEVER  */
    struct iucv_msg_plist msg;      /* IUCV plist for SEND            */

       /* maximum number of IUCV connections for this virtual machine */
    int maxconns;
    int rc;                         /* return code from IUCV functions*/
    char message[120],              /* message buffer                 */
    reply[120];                     /* reply buffer                   */

       /* Initialize IUCV signal processing and establish a handler.  */
       /* Block IUCV signals until we're ready to handle them.        */
    signal(SIGIUCV,&iucvtrap);
    sigblock(1 << (SIGIUCV-1));

       /* Identify this program as SENDER. */
    if ((rc = iucvset("SENDER",&maxconns)) != 0) {
       printf("Return code from iucvset was %d\n",rc);
       exit(4);
    }
    printf("Maximum IUCV connections: %d\n",maxconns);
 
      /* Fill in the IUCV "path" parameter list with the target      */
      /* userid and the name of the target program. All of the other */
      /* parameters are superfluous in this program.                 */
    memset((void *) &path,0,sizeof(path));
    memcpy(path.vmid,"SASCUSER",8);
    memcpy(path.pgm,"RECEIVER",8);

      /* Request an IUCV CONNECT to the userid/program pair named    */
      /* in the parameter list.  Check for an IUCV error (return     */
      /* code of 1)and print the IUCV error code.                    */
    rc = iucvconn("SENDER",&path);
    if (rc != 0) {
       printf("Return code from iucvconn was %d\n",rc);
       if (rc == 1)
          printf("IPRCODE = %d\n",path.ip.rcode);
       exit(8);
    }

      /* Now we are ready. The first interrupt we receive is the     */
      /* CONNECTION COMPLETE interrupt that occurs when RECEIVER     */
      /* issues an IUCV ACCEPT.                                      */
    sigpause(0);

      /* Initialize the SEND parameter list with the pathid and      */
      /* buffer addresses and the length of the reply buffer.        */
    memset((void *) &msg,'\0',sizeof(msg));
    path.pathid = msg.pathid = pathid;
    msg.msg.bf1.adr = message;
    msg.bf2.adr = reply;
    msg.bf2.ln = sizeof(reply);

      /* Prompt for input messages and send until EOF.               */
    fgets(message,sizeof(message),stdin);
    while (!feof(stdin)) {
         /* Put message length in the SEND parameter list.           */
       msg.msg.bf1.ln = strlen(message) - 1;
         /* 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.                            */
       iucvsend(&msg);
       sigpause(0);
       rep_len = sizeof(reply) - rep_len;
       printf("RECEIVER replies \"%.*s\"\n",
               rep_len,reply);
       fgets(message,sizeof(message),stdin);
    }
 
       /* We are ready to quit. SEVER the IUCV path.  Check for IUCV   */
       /* errors as before.                                            */
    if ((rc = iucvsevr("SENDER",&path,"ONE")) != 0) {
       printf("Return code from iucvsever = %d\n",rc);
       if (rc == 1)
          printf("IPRCODE = %d\n",path.ip.rcode);
       exit(10);
    }

       /* Terminate IUCV communications for SENDER. */
    iucvclr("SENDER");
    exit(0);
 }

    /* The SIGIUCV signal handler. Signals are blocked until return.   */
 void iucvtrap(void)
 {
       /* Pointer to external interrupt data returned by siginfo. The  */
       /* type is arbitrary since it can point to any of the IUCV      */
       /* structures.                                                  */
    iucv_path_data *XID;

       /* Get a pointer to the external interrupt data.  Use the       */
       /* interrupt type to determine what to do.                      */
    XID = (iucv_path_data *) siginfo();
    switch (XID->ip.type) {
       case CONNECTION_COMPLETE:          /* Save the pathid for SEND. */
          pathid = XID->pathid;
          break;

          /* Extract the number of unused characters in the buffer.    */
       case INCOMING_REPLY:
          rep_len = ((iucv_msg_data *)XID)->bf2.ln;
          break;

          /* Handle unexpected termination of RECEIVER.                */
       case PATH_SEVERED:
          puts("Unexpected SEVER!");
          exit(20);

          /* Handle unexpected type of IUCV signal.                    */
       default:
          printf("Unexpected interrupt type %d\n",XID->ip.type);
          fflush(stdout);
          abort();
    }
       /* Reestablish this function as the SIGIUCV signal handler.     */
    signal(SIGIUCV,&iucvtrap);
    return;
 }
 

The RECEIVER program

This program defines three functions. The main function, again, initializes signal processing and IUCV. main calls sigpause to wait for the initial CONNECTION PENDING interrupt once and then repeatedly (until all connections are severed) for incoming messages.

The iucvtrap function is again the SIGIUCV signal handler. Three types of IUCV interrupts are expected: a CONNECTION PENDING for each sending program, a PATH SEVERED as each sending program finishes, and an INCOMING MSG interrupt for each message sent by a sending program.

Finally, the rcvrply function issues an IUCV RECEIVE for each incoming message and prompts for a reply string. It then sends the reply string via an IUCV REPLY.

                 /* RECEIVER */

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

 void iucvtrap(void);                  /* SIGIUCV signal handler      */

                                       /* stdin prompt string         */
 char *_stdiamp = "prompt=What do I reply to SENDER?";
 int connects = 0;                     /* number of connections made  */
 static void rcvrply(iucv_msg_data *); /* Declare internal functions. */

 void main()
 {
    int maxconns;               /* number of IUCV connections allowed */
    int rc;                     /* return code from IUCV functions    */

       /* Initialize IUCV signal processing and establish a handler.  */
       /* Block IUCV signals until we are ready to handle them.       */
    signal(SIGIUCV,&iucvtrap);
    sigblock(1 << (SIGIUCV-1));

       /* Identify this program as RECEIVER. */
    if ((rc = iucvset("RECEIVER",&maxconns)) != 0) {
       printf("Return code from iucvset was %d\n",rc);
       exit(4);
    }
    printf("Maximum IUCV connections: %d\n",maxconns);

       /* This call waits for the initial                             */
       /* CONNECTION PENDING interrupt.                               */
    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("RECEIVER");
    exit(0);
 }

    /* SIGIUCV signal handler. Signals are blocked until return.      */
 void iucvtrap(void) {
       /* Pointer to external interrupt data returned by siginfo. The */
       /* type is arbitrary because it can point to any of the IUCV   */
       /* structures.                                                 */
    iucv_path_data *XID;
    int rc;                               /* Return code from iucvacc.*/

       /* Get a pointer to the external interrupt data. Use the       */
       /* interrupt type to determine what to do.                     */
    XID = (iucv_path_data *) siginfo();
    switch (XID->ip.type) {
       case CONNECTION_PENDING:           /* Issue ACCEPT.            */
          XID->ip.type = 0;
          if ((rc = iucvacc("RECEIVER",XID)) != 0) {
             printf("Return code from iucvacc = %d\n",rc);
             if (rc == 1)
                printf("IPRCODE = %d\n",XID->ip.rcode);
             exit(8);
          }
             /* Keep track of the number of connections made.         */
          connects++;
          break;

          /* Call function to get message and send reply. */
       case INCOMING_MSG:

          rcvrply((iucv_msg_data *)XID);
          break;

       case PATH_SEVERED:             /* SENDER decided to stop.      */
          if ((rc = iucvsevr("RECEIVER",XID,"ONE")) != 0) {
             printf("Return code from iucvsevr = %d\n",rc);
             exit(8);
          }
          connects--;                 /* Update number of connections.*/
          break;

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

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

       /* Function to issue IUCV RECEIVE and print the message.       */
 static void rcvrply(m_data)
 iucv_msg_data *m_data;
 {
    int msg_len;                           /* incoming message length */
    char msg_buffer[120];                  /* message buffer          */

       /* Create IUCV RECEIVE parameter list using the external       */
       /* interrupt data area.  Issue the IUCV RECEIVE.               */
    m_data->msg.bf1.adr = msg_buffer;
    m_data->msg.bf1.ln = sizeof(msg_buffer);
    iucvrecv(m_data);

       /* Upon return, m_data->msg.bf1.ln contains the number of   */
       /* unused bytes in the message buffer.  Print the message.     */
    msg_len = sizeof(msg_buffer) - m_data->msg.bf1.ln;
    printf("SENDER says \"%.*s\"\n",
         msg_len,msg_buffer);

       /* Prompt for a reply message.  If EOF, quit.                  */
    fgets(msg_buffer,sizeof(msg_buffer),stdin);
    if (feof(stdin)) {
       puts("Terminating due to end-of-file.");
       exit(12);
    }

       /* Fill in IUCV REPLY parameter list with buffer               */
       /* address/length and send REPLY.                              */
    m_data->bf2.adr = msg_buffer;
    m_data->bf2.ln = strlen(msg_buffer) - 1;
    iucvrply(m_data);
 }
 

Guidelines and Cautions

For additional information concerning IUCV and CMS IUCV support, refer to your VM system's IBM documentation, which covers many topics relevant to IUCV communication including communication with CP system services, user environments, and specific details on the CMS support of IUCV functions.

In using SAS/C IUCV functions, be aware of the following points:

For more information on handling program interrupts and communications, refer to Chapter 5 of SAS/C Library Reference, Volume 1 .

Copyright (c) 1998 SAS Institute Inc. Cary, NC, USA. All rights reserved.