Chapter Contents |
Previous |
Next |
appcsevr |
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.
#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.