z/OS MVS Programming: Writing Servers for APPC/MVS
Previous topic | Next topic | Contents | Contact z/OS | Library | PDF


Sample Client Program

z/OS MVS Programming: Writing Servers for APPC/MVS
SA23-1396-00

This program is the client part of the sample client/server application that began in Sample APPC/MVS Server.

Sample Error Routine and Header File shows the source code for the error routine (SRVERROR) used by this application, and the C language header file used to define error codes for the SRVERROR routine.

/**********************************************************************/
/*    This program is a sample client for a client/server pair        */
/*    written in C/370 to demonstrate the use of APPC/MVS allocate    */
/*    queue services.  This client program uses the CPI-C             */
/*    interface and uses no MVS-specific services.                    */
/*                                                                    */
/*                                                                    */
/*  COPYRIGHT --                                                      */
/*                                                                    */
/*  (C) Copyright IBM Corp. 1992                                      */
/*  All rights reserved.                                              */
/*  U.S, Government Users Restricted Rights -- Use,                   */
/*  duplication, or disclosure restricted by GSA ADP Schedule         */
/*  Contract with IBM Corp.    Program Property of IBM.               */
/*                                                                    */
/*  This program is provided to you for tutorial purposes only.       */
/*  You may not use the program for commercial purposes.              */
/*  This program is a sample working solution intended                */
/*  to show the use of APPC/MVS allocate queue services.              */
/*  Independent of its particular use, this program is                */
/*  supplied as an example and provided "as is" without               */
/*  warranty of any kind, either express or implied, including,       */
/*  but not limited to, the implied warranties of                     */
/*  merchantability and fitness for a particular purpose.             */
/*  The entire risk about the quality and performance of the          */
/*  program is with you.  Should the program prove defective,         */
/*  you assume the entire cost of all necessary servicing,            */
/*  repair, or correction.                                            */
/*                                                                    */
/*  In no event will IBM be liable to you for any damages or          */
/*  any lost profits, lost savings or other incidental or             */
/*  consequential damages arising out of the use of or                */
/*  inability to use the program even if IBM had been advised         */
/*  of the possibility of such damages, or for any claim by any       */
/*  other party.                                                      */
/*                                                                    */
/*                                                                    */
/*  MODULE NAME --                                                    */
/*                                                                    */
/*       DRV1.C                                                       */
/*                                                                    */
/*                                                                    */
/*  ENTRY POINTS --                                                   */
/*                                                                    */
/*       Normal C entry executed on the client platform.              */
/*                                                                    */
/*                                                                    */
/*  STATUS --                                                         */
/*                                                                    */
/*       Version 1, Release 0                                         */
/*                                                                    */
/*                                                                    */
/*  FUNCTION --                                                       */
/*                                                                    */
/*       This program is provided as an example of APPC/MVS           */
/*       allocate queue services.  This program is the client half    */
/*       of a client/server pair.  It invokes the server and waits    */
/*       for the server to respond by sending data.                   */
/*                                                                    */
/*                                                                    */
/*  INPUT --                                                          */
/*                                                                    */
/*       None                                                         */
/*                                                                    */
/*  OUTPUT --                                                         */
/*                                                                    */
/*       None.                                                        */
/*                                                                    */
/*                                                                    */
/*  RETURN INFORMATION --                                             */
/*                                                                    */
/*       None.                                                        */
/*                                                                    */
/*                                                                    */
/*  CHANGE HISTORY --                                                 */
/*                                                                    */
/*       08/31/91 - Module created.                                   */
/*                                                                    */
/**********************************************************************/
/**********************************************************************/
/*                                                                    */
/*  Include the header files which define the services used by        */
/*  this program.  STDIO and STRING are standard C libraries.         */
/*  ATBCMC is the interface definition file (IDF) for the CPI-C       */
/*  services.  ERRCDE is the header file for the srverror function    */
/*  that handles error conditions detected by this program.           */
/*                                                                    */
/*  The '#pragma runopts(execops)' is a C/370 option which permits    */
/*  the caller to specify runtime options to C/370 before             */
/*  specifying parameters to this program.  This was done to permit   */
/*  the caller to specify /NOSPIE and /NOSTAE to prevent C/370        */
/*  from suppressing a user abend which might be generated by the     */
/*  srverror function.                                                */
/*                                                                    */
/**********************************************************************/
 #pragma runopts(execops)
 #include <STDIO.H>
 #include <STRING.H>
 #include <ATBCMC.H>
 #include <ERRCDE.H>
/**********************************************************************/
/*                                                                    */
/*                      MAINLINE CODE                                 */
/*                                                                    */
/**********************************************************************/
main()

{

/**********************************************************************/
/*                                                                    */
/*                      DECLARE VARIABLES                             */
/*                                                                    */
/*  conv_id - conversation identifier returned by APPC on the CMINIT  */
/*             call and used on subsequent calls                      */
/*                                                                    */
/*  sym_dest - symbolic destination name identifying the server       */
/*             (TP name, LU name, and logon mode).  Note that this    */
/*             variable is one character longer than the symbolic     */
/*             destination name parameter.  Since a value is placed   */
/*             in this parameter using the strcpy() function we must  */
/*             provide an extra character for the null since it       */
/*             must not be a part of the passed value.                */
/*                                                                    */
/*  return_code - used to hold return codes from APPC services        */
/*                                                                    */
/*  buffer - The buffer which is used to receive data from the        */
/*            partner program (server).  The buffer is 19 characters  */
/*            long because we know that is how much data the server   */
/*            will be sending.                                        */
/*                                                                    */
/*  requested_length - The length of the buffer we will provide to    */
/*                      the receive (CMRCV) service.                  */
/*                                                                    */
/*  data_received - A returned parameter from the CMRCV service which */
/*                   will indicate whether any data was received from */
/*                   the server.                                      */
/*                                                                    */
/*  received_length - A returned parameter from the CMRCV server which*/
/*                     will indicate the amount of data placed into   */
/*                     our buffer by APPC.                            */
/*                                                                    */
/*  status_received - A returned parameter from the CMRCV service     */
/*                     which will indicate whether any status was     */
/*                     received from the server.                      */
/*                                                                    */
/*  rts_received - A returned parameter from the CMRCV service which  */
/*                  indicates whether the partner has requested send  */
/*                  control.  Should always be set to                 */
/*                  rts_not_received in this application since this   */
/*                  program always immediately grants the server      */
/*                  send control.                                     */
/*                                                                    */
/*  srverror_return_code - The return code from the srverror function.*/
/*                                                                    */
/**********************************************************************/
  char conv_id[8];
  char sym_dest[9];
  long int return_code;
  char buffer[19];
  long int requested_length;
  long int data_received;
  long int received_length;
  long int status_received;
  long int rts_received;
  int srverror_return_code;

/**********************************************************************/
/*                                                                    */
/*  Set the sym_dest variable to the symbolic destination name.       */
/*  There must be an entry defined in the side information table      */
/*  for this value.  It must contain an LU name and TP name which     */
/*  correspond to the values for which the server has registered.     */
/*  See APPC/MVS Planning and Management for information about adding */
/*  Side Information.                                                 */
/*                                                                    */
/*  The srverror function return code is initialized to zero.
/*                                                                    */
/**********************************************************************/
  strcpy(sym_dest,"SRVORDER");
  srverror_return_code = 0;

/**********************************************************************/
/*                                                                    */
/*                   INITIALIZE THE CONVERSATION                      */
/*                                                                    */
/*  Call the Initialize_Conversation service (CMINIT), providing      */
/*  the symbolic destination name defined just above.  If all goes    */
/*  well, a conversation identifier will be returned in the conv_id   */
/*  variable.                                                         */
/*                                                                    */
/*  If all is not well (i.e. the return code is not CM_OK) then       */
/*  invoke the srverror function providing a description of the       */
/*  problem encountered (CMINIT return code error), the expected      */
/*  return code value, and the actual return code received.           */
/*  The srverror function will then act appropriately and             */
/*  return a return code indicating whether to continue processing.   */
/*                                                                    */
/*  Of course, in this case any non-zero return code should result    */
/*  in termination of processing; the srverror function, however,     */
/*  can update an error log, issue an operator message, or take other */
/*  appropriate action.                                               */
/*                                                                    */
/**********************************************************************/
  CMINIT(conv_id,
         sym_dest,
         &return_code);
  if (return_code != CM_OK)
   {
    error_description.problem = CMINIT_RET_CODE_ERROR;
    error_description.error_reason.rc_problem.expected_return_code =
         CM_OK;
    error_description.error_reason.rc_problem.actual_return_code =
         return_code;
    srverror_return_code = srverror(error_description);
   }

/**********************************************************************/
/*                                                                    */
/*                  ALLOCATE THE CONVERSATION                         */
/*                                                                    */
/*  If all is well, allocate the conversation by calling the CMALLC   */
/*  service.  The only input parameter is the conversation identifier */
/*  returned by CMINIT.                                               */
/*                                                                    */
/*  If the allocate function fails (non-zero return code), we again   */
/*  check with the srverror function to find out if we should         */
/*  continue processing.                                              */
/*                                                                    */
/**********************************************************************/

  if (srverror_return_code==0)
   {
    CMALLC(conv_id,
          &return_code);

    if (return_code != CM_OK)
     {
      error_description.problem = CMALLC_RET_CODE_ERROR;
      error_description.error_reason.rc_problem.expected_return_code =
           CM_OK;
      error_description.error_reason.rc_problem.actual_return_code =
           return_code;
      srverror_return_code = srverror(error_description);
     }
   }
/**********************************************************************/
/*                                                                    */
/*                  RECEIVE DATA FROM THE SERVER                      */
/*                                                                    */
/*  Next two tasks are accomplished by calling one function.  When    */
/*  the CMRCV service is called from send state, notification is      */
/*  first sent to the server that it has been granted send control    */
/*  and then this program waits for the server to send data.          */
/*  Note that we set the requested_length parameter to the size of    */
/*  the receive buffer.                                               */
/*                                                                    */
/*  Next the returned parameters will be examined and the srverror    */
/*  function invoked if any unexpected results occur.                 */
/*                                                                    */
/**********************************************************************/
  if (srverror_return_code==0)
   {
    requested_length = sizeof(buffer);

    cmrcv (conv_id,
          buffer,
          &requested_length,
          &data_received,
          &received_length,
          &status_received,
          &rts_received,
          &return_code);
/**********************************************************************/
/*                                                                    */
/*  The first returned parameter to examine is naturally the return   */
/*  code.  Two values may be expected on this call.  Since we know    */
/*  the partner will deallocate the conversation after sending the    */
/*  data, we expect to get a return code of CM_DEALLOCATED_NORMAL.    */
/*  It is possible, however, that the return code may not have arrived*/
/*  yet, so a return code of CM_OK might be returned.  If neither     */
/*  value is found, the srverror function is invoked.                 */
/*                                                                    */
/**********************************************************************/
    if (return_code != CM_OK)
      if (return_code != CM_DEALLOCATED_NORMAL)
       {
        error_description.problem = CMRCV_RET_CODE_ERROR;
        error_description.error_reason.rc_problem.
             expected_return_code = CM_OK;
        error_description.error_reason.rc_problem.
             actual_return_code = return_code;
        srverror_return_code = srverror(error_description);
       }

/**********************************************************************/
/*                                                                    */
/*  If the return code is OK or DEALLOCATED_NORMAL, then we can       */
/*  examine the data received field to determine if any data was      */
/*  received.  If data was received, then we can examine the          */
/*  received_length field to determine how much data was received.    */
/*  If we received the expected length, then we can proceed to        */
/*  examine the data itself to verify it is as expected.              */
/*                                                                    */
/*  Note that in a real application the actual value of the expected  */
/*  data would probably not be known, but this check can be easily    */
/*  replaced with a check verifying that the data is in some expected */
/*  format (for example, if the expected data were inventory record   */
/*  updates you might expect the data to consist of item identifiers  */
/*  and quantities in four byte integer pairs).                       */
/*                                                                    */
/*  If any returned values are not as expected, the srverror function */
/*  is invoked.                                                       */
/*                                                                    */
/**********************************************************************/
    if ((return_code==CM_OK)|(return_code==CM_DEALLOCATED_NORMAL))
     {
      if (data_received!=CM_COMPLETE_DATA_RECEIVED)
       {
        error_description.problem = CMRCV_DATA_RCV_ERROR;
        error_description.error_reason.data_rcv_problem.
             expected_data_rcv = CM_COMPLETE_DATA_RECEIVED;
        error_description.error_reason.data_rcv_problem.
             actual_data_rcv = data_received;
        srverror_return_code = srverror(error_description);
       }

      if (srverror_return_code == 0)
       {
        if (received_length != requested_length)
         {
          error_description.problem = CMRCV_RCVD_LEN_ERROR;
          error_description.error_reason.length_problem.
               expected_length = requested_length;
          error_description.error_reason.length_problem.
               actual_length = received_length;
          srverror_return_code = srverror(error_description);
         }

        if (srverror_return_code == 0)
         {
          if (strcmp(buffer,"123456789012345678"))
           {
            error_description.problem = CMRCV_BUFFER_ERROR;
            error_description.error_reason.data_problem.
                 expected_data = "123456789012345678";
            error_description.error_reason.data_problem.
                 actual_data = buffer;
            srverror_return_code = srverror(error_description);
           }
         }
       }
/**********************************************************************/
/*                                                                    */
/*  At this point we have verified that all the information we        */
/*  expected to receive has arrived.  We have not examined the status */
/*  received field since we expected to receive no status.  Just to   */
/*  be complete, we will verify that we did in fact receive no status */
/*  and invoke the srverror function if status did turn up.           */
/*  Note that this check occurs inside a conditional which ensures    */
/*  that we only examine the status_received field when the return    */
/*  code  is CM_OK since the status field is not set for the          */
/*  CM_DEALLOCATED_NORMAL return code (or other non-zero return codes)*/
/*                                                                    */
/**********************************************************************/
      if (srverror_return_code == 0)
       {
        if (return_code == CM_OK)
         {
          if (status_received != CM_NO_STATUS_RECEIVED)
           {
            error_description.problem = CMRCV_STATUS_ERROR;
            error_description.error_reason.status_problem.
                 expected_status = CM_NO_STATUS_RECEIVED;
            error_description.error_reason.status_problem.
                 actual_status = status_received;
            srverror_return_code = srverror(error_description);
           }
         }
       }
     }
   }
/**********************************************************************/
/*                                                                    */
/*  At this point, the client has received the data from the server   */
/*  and could perform any processing required such as updating a      */
/*  local database with new information.                              */
/*                                                                    */
/**********************************************************************/
/**********************************************************************/
/*                                                                    */
/*  As mentioned above, it is possible the notification of the end    */
/*  of the conversation might not have arrived on the first receive   */
/*  as a DEALLOCATED_NORMAL return code.  In this case, we need to    */
/*  issue another CMRCV to get this return code.  Note that we set    */
/*  the requested_length to zero for this receive since we expect no  */
/*  data to arrive.  After the receive completes, the return code     */
/*  is inspected and the srverror function is invoked if an           */
/*  unexpected value is found.  We also examine the data_received     */
/*  field to verify it is set to CM_NO_DATA_RECEIVED.                 */
/*                                                                    */
/**********************************************************************/
  if (srverror_return_code == 0)
   {
    if (return_code == CM_OK)
     {
      requested_length = 0;

      cmrcv (conv_id,
            buffer,
            &requested_length,
            &data_received,
            &received_length,
            &status_received,
            &rts_received,
            &return_code);

      if (return_code != CM_DEALLOCATED_NORMAL)
       {
        error_description.problem = CMRCV_RET_CODE_ERROR;
        error_description.error_reason.rc_problem.
             expected_return_code = CM_DEALLOCATED_NORMAL;
        error_description.error_reason.rc_problem.
             actual_return_code = return_code;
        srverror_return_code = srverror(error_description);
       }

      if (srverror_return_code == 0)
       {
        if (data_received != CM_NO_DATA_RECEIVED)
         {
          error_description.problem = CMRCV_DATA_RCV_ERROR;
          error_description.error_reason.data_rcv_problem.
               expected_data_rcve = CM_NO_DATA_RECEIVED;
          error_description.error_reason.data_rcv_problem.
               actual_data_rcv = data_received;
          srverror_return_code = srverror(error_description);
         }
       }
     }
   }

/**********************************************************************/
/*                                                                    */
/*  The function of the client is complete.                           */
/*                                                                    */
/**********************************************************************/
 return srverror_return_code;
}

Go to the previous page Go to the next page




Copyright IBM Corporation 1990, 2014