/*--------------------------------------------------------------------+ | | | 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 #include #include #include #include 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); } }