C Program to Send an MQSC Command to a z/OS Queue Manager

I was surfing on mqseries.net today and someone asked for help to fix their program that was attempting to send an MQSC command to a z/OS queue manager.

The person had taken someone else’s program that sent a PCF message to a distributed queue manager, twisted and attempted to make it send an MQSC command to a z/OS queue manager. In short, it was garbage. Sorry, but it is.

I have a bunch of programs and code snippets that send an MQSC command to a z/OS queue manager, so I decided to dust-off one and make it available to the world (via this blog).

You can download it as a zip file from here or you can copy from below:

/*
 * SendCmdTozOS.c is a simple MQ program that will send an MQSC command
 * to a z/OS queue manager's command queue and then wait for a response.
 *
 * Input Parameters:
 *    QMgrName ChlName hostname(port) "MQSC command"
 *
 * Where
 *    QMgrName is the queue manager name
 *    ChlName is the name of the channel to be used
 *    hostname(port) is the hostname and port number
 *    "MQSC command" is the MQSC command you want to send to the z/OS queue manager
 * i.e.
 *    SendCmdTozOS MQT1 TEST.CHL 10.10.10.10(1415) "DIS QL(*)"
 *
 * @author Roger Lacroix, Capitalware Inc.
 * @return 0 for ok or 1 for failed.
 * @version 1.0.0
 * @license Apache 2 License
 */
#define PROGRAM_NAME  "SendCmdTozOS"
static const char * EYECATCHER_EyeCatcher  = PROGRAM_NAME "  ";
static const char * EYECATCHER_Version     = "1.0.0" ;
static const char * EYECATCHER_Datestamp   = __DATE__ ;
static const char * EYECATCHER_Timestamp   = __TIME__ ;
static const char * EYECATCHER_Filename    = __FILE__ ;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <cmqc.h>
#include <cmqxc.h>

/* Some basic defines for this program */
#define SYSTEM_MODEL_REPLY_QUEUE       "SYSTEM.COMMAND.REPLY.MODEL"
#define SYSTEM_COMMAND_INPUT           "SYSTEM.COMMAND.INPUT"
#define TEMP_DYNAMIC_QUEUE_PREFIX      "CSQ.*"
#define STR_EQ                         0
#define WORK_BUFFER_SIZE               1024

/* Return codes for internal subroutines. */
typedef enum MY_RC_E
{
        RC_OK                 = 0,
        RC_WARNING            = 4,
        RC_FAILED             = 8,
        /* */
        RC_MAX                = 0x7FFFFFFF
} MY_RC_T;

/* Prototypes */
MY_RC_T ConnectXToQMgr(MQHCONN *, MQLONG *, char *, char *, char *, MQLONG);
MY_RC_T DisconnectFromQMgr(MQHCONN *, char *);
MY_RC_T OpenDynamicQueue(MQHCONN , MQHOBJ *, char *, char *, char *, char *);
MY_RC_T CloseDynamicQueue(MQHCONN , MQHOBJ *, char *);
MY_RC_T PutMessage(MQHCONN , char *, char *, char *, char *);
MY_RC_T ProcessCmdMessages(MQHCONN , MQHOBJ , char *);

/*
 * ==================================================================
 *
 * Function Name
 *  main
 *
 * Description
 *  This routine will:
 *  - Connect to a remote z/OS queue manager
 *  - Open a temporary dynamic queue
 *  - Put a message on the queue manager's command queue
 *  - Get a reply message from the temporary dynamic queue
 *  - Close the temporary dynamic queue
 *  - Disconnect from the queue manager
 *
 * Input parameters
 *  argc         - number of input parameters
 *  **argv       - pointer to the array of input parameters
 *
 * Return Value
 *  int
 * ------------------------------------------------------------------
 */
int main(int argc, char **argv)
{
   MQHCONN  HConn;                  /* connection handle              */
   MQHOBJ   HReplyQ;                /* object handle                  */
   MQLONG   ConnectionRC;           /* reason code for MQCONN         */
   char     QMgrName[MQ_Q_MGR_NAME_LENGTH+1];      /* z/OS QMgr name */
   char     channelName[MQ_CHANNEL_NAME_LENGTH+1]; /* z/OS Channel to QMgr */
   char     hostname[WORK_BUFFER_SIZE+1];          /* z/OS hostname/IP address and port# */
   char     MQSCCommand[WORK_BUFFER_SIZE+1];       /* MQSC command the user wishes to have executed */
   char     ResolvedQName[MQ_Q_NAME_LENGTH+1];

   if (argc != 5)
   {
      printf("%s QMgrName ChlName hostname(port) \"MQSC command\"\n", PROGRAM_NAME);
      return(1);
   }

   printf("%s v%s starting\n", PROGRAM_NAME, EYECATCHER_Version);

   strncpy(QMgrName, argv[1], MQ_Q_MGR_NAME_LENGTH);
   QMgrName[MQ_Q_MGR_NAME_LENGTH] = 0x00;

   strncpy(channelName, argv[2], MQ_CHANNEL_NAME_LENGTH);
   channelName[MQ_CHANNEL_NAME_LENGTH] = 0x00;

   strncpy(hostname, argv[3], WORK_BUFFER_SIZE);
   hostname[WORK_BUFFER_SIZE] = 0x00;

   strncpy(MQSCCommand, argv[4], WORK_BUFFER_SIZE);
   MQSCCommand[WORK_BUFFER_SIZE] = 0x00;

   printf("Using values:\n");
   printf("   QMgrName    : %s\n", QMgrName);
   printf("   hostname    : %s\n", hostname);
   printf("   channelName : %s\n", channelName);
   printf("   MQSC command: %s\n", MQSCCommand);

   if (RC_OK == ConnectXToQMgr(&HConn,
                               &ConnectionRC,
                               QMgrName,
                               hostname,
                               channelName,
                               MQCNO_NONE))
   {
      /* Open the Dynamic Input Q */
      if (RC_OK == OpenDynamicQueue(HConn,
                                    &HReplyQ,
                                    ResolvedQName,
                                    QMgrName,
                                    SYSTEM_MODEL_REPLY_QUEUE,
                                    TEMP_DYNAMIC_QUEUE_PREFIX))
      {
         /* Put the MQSC command on the queue manager's command queue */
         if (RC_OK == PutMessage(HConn,
                                 QMgrName,
                                 SYSTEM_COMMAND_INPUT,
                                 ResolvedQName,
                                 MQSCCommand))
         {
            ProcessCmdMessages(HConn, HReplyQ, ResolvedQName);
         }

         CloseDynamicQueue(HConn, &HReplyQ, ResolvedQName);
      }

      /* Disconnect from the queue manager */
      if (ConnectionRC != MQRC_ALREADY_CONNECTED)
      {
         DisconnectFromQMgr(&HConn, QMgrName);
      }
   }

   printf("%s ending.\n", PROGRAM_NAME);
   return(0);
}

/*
 * ==================================================================
 *
 * Function Name
 *  ConnectXToQMgr
 *
 * Description
 *  This routine will establish a connection between
 *  this application and a remote queue manager.
 *
 * Input parameters
 *  *Hconn       - pointer to the conn. handle returned from MQCONN
 *  *connectRC   - pointer to the RC returned from MQCONN
 *  QMgrName     - Queue Manager name
 *  *hostname    - hostname/IP address and port #
 *  *channelName - channel name to qeue manager
 *  Options      - connection options
 *
 * Output
 *  *Hconn       - pointer to the conn. handle returned from MQCONN
 *  *connectRC   - pointer to the RC returned from MQCONN
 *
 * Return Value
 *  MY_RC_T
 * ------------------------------------------------------------------
 */
MY_RC_T ConnectXToQMgr(MQHCONN            *Hconn,
                       MQLONG             *connectRC,
                       char               *QMgrName,
                       char               *hostname,
                       char               *channelName,
                       MQLONG             Options)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   MY_RC_T     rcode = RC_OK;
   MQLONG      mqCC;                                    /* completion code from QMgr */
   MQCD        ClientConn = {MQCD_CLIENT_CONN_DEFAULT}; /* Client connection channel */
   MQCNO       cno = {MQCNO_DEFAULT};                   /* Connect Options */

   /* --------------------------------------------
    * Code section
    * --------------------------------------------
    */
   strncpy(ClientConn.ConnectionName,
           hostname,
           MQ_CONN_NAME_LENGTH);

   strncpy(ClientConn.ChannelName,
           channelName,
           MQ_CHANNEL_NAME_LENGTH);

   /* Point the MQCNO to the client connection definition */
   cno.ClientConnPtr = &ClientConn;
   cno.Version = MQCNO_VERSION_2;
   cno.Options = Options;

   MQCONNX( QMgrName,        /* queue manager      */
            &cno,            /* connection options */
            Hconn,           /* connection handle  */
            &mqCC,           /* completion code    */
            connectRC);      /* reason code        */

   printf("MQConn  CC=%d RC=%d on connection to %s\n",
          mqCC,
          *connectRC,
          QMgrName );

   if (mqCC == MQCC_FAILED)
      rcode = RC_FAILED;
   else
      rcode = RC_OK;

   return (rcode);
}

/*
 * ==================================================================
 *
 * Function Name
 *  DisconnectFromQMgr
 *
 * Description
 *  This routine will sever an existing connection between this
 *  application and the queue manager.
 *
 * Input parameters
 *  *Hconn       - pointer to the conn. handle returned from MQCONN
 *  QMgrName     - Queue Manager name
 *
 * Output
 *  *Hconn       - pointer to the conn. handle returned from MQCONN
 *
 * Return Value
 *  MY_RC_T
 * ------------------------------------------------------------------
 */
MY_RC_T DisconnectFromQMgr(MQHCONN            *Hconn,
                           char               *QMgrName)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   MY_RC_T     rcode = RC_OK;
   MQLONG      mqCC;      /* completion code from QMgr */
   MQLONG      mqRC;      /* reason code from QMgr */

   /* --------------------------------------------
    * Code section
    * ------------------------------------- -------
    */
   MQDISC( Hconn,       /* connection handle */
           &mqCC,       /* completion code   */
           &mqRC);      /* reason code       */

   printf("MQDisc  CC=%d RC=%d on disconnecting from %s\n",
          mqCC,
          mqRC,
          QMgrName );

   if (mqCC == MQCC_FAILED)
      rcode = RC_FAILED;
   else
      rcode = RC_OK;

   return (rcode);
}

/*
 * ==================================================================
 *
 * Function Name
 *  OpenDynamicQueue
 *
 * Description
 *  This routine will create and open the temporary dynamic input queue.
 *
 * Input parameters
 *   Hconn       - connection handle
 *  *HObj        - pointer to the object handle returned from MQOPEN
 *  *ResolvedQName - pointer to object name returned from MQOPEN
 *  QMgrName     - Queue Manager name
 *  ModelQName   - Model Q name
 *  DynQName     - Dynamic Q name
 *
 * Output
 *  *ResolvedQName - pointer to object name returned from MQOPEN
 *
 * Return Value
 *  MY_RC_T
 * ------------------------------------------------------------------
 */
MY_RC_T OpenDynamicQueue(MQHCONN            Hconn,
                         MQHOBJ             *HObj,
                         char               *ResolvedQName,
                         char               *QMgrName,
                         char               *ModelQName,
                         char               *DynQName)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   MY_RC_T     rcode = RC_OK;
   MQLONG      mqCC;       /* completion code from QMgr */
   MQLONG      mqRC;       /* reason code from QMgr */
   MQOD        od = {MQOD_DEFAULT};
   MQLONG      OpenOptions = MQOO_FAIL_IF_QUIESCING | MQOO_INPUT_SHARED;

   /* --------------------------------------------
    * Code section
    * --------------------------------------------
    */
   strcpy( od.ObjectQMgrName, QMgrName);
   strcpy(od.ObjectName, ModelQName);
   strcpy(od.DynamicQName, DynQName);

   MQOPEN( Hconn,            /* connection handle */
           &od,              /* object descriptor */
           OpenOptions,      /* open options      */
           HObj,             /* object handle     */
           &mqCC,            /* completion code   */
           &mqRC);           /* reason code       */

   printf("MQOpen  CC=%d RC=%d for %s\n",
          mqCC,
          mqRC,
          DynQName );

   if ( mqCC == MQCC_OK )
   {
      strncpy(ResolvedQName, od.ObjectName, MQ_Q_NAME_LENGTH);
      ResolvedQName[MQ_Q_NAME_LENGTH] = 0x00;

      printf("Dynamic Queue Name: %s\n",
             ResolvedQName );
      rcode = RC_OK;
   }
   else
   {
      rcode = RC_FAILED;
   }

   return (rcode);
}

/*
 * ==================================================================
 *
 * Function Name
 *  CloseDynamicQueue
 *
 * Description
 *  This routine will close and delete the temporary dynamic queue.
 *
 * Input parameters
 *   Hconn       - connection handle
 *  *HObj        - pointer to the object handle
 *  *QName       - pointer to Q name
 *
 * Output
 *  *HObj        - pointer to the object handle
 *
 * Return Value
 *  MY_RC_T
 * ------------------------------------------------------------------
 */
MY_RC_T CloseDynamicQueue(MQHCONN            Hconn,
                          MQHOBJ             *HObj,
                          char               *QName)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   MY_RC_T     rcode = RC_OK;
   MQLONG      mqCC;       /* completion code from QMgr */
   MQLONG      mqRC;       /* reason code from QMgr */
   MQLONG      CloseOptions = MQCO_DELETE_PURGE; /* delete the queue and any messages */

   /* --------------------------------------------
    * Code section
    * --------------------------------------------
    */
   MQCLOSE( Hconn,
            HObj,
            CloseOptions,
            &mqCC,
            &mqRC);

   printf("MQClose CC=%d RC=%d for %s\n",
          mqCC,
          mqRC,
          QName);

   if (mqCC == MQCC_FAILED)
      rcode = RC_FAILED;
   else
      rcode = RC_OK;

   return (rcode);
}

/*
 * ==================================================================
 *
 * Function Name
 *  PutMessage
 *
 * Description
 *  This routine will put a message on a queue.
 *
 * Input parameters
 *  Hconn        - connection handle
 *  QMgrName     - pointer to Queue Manager name
 *  QMgrName     - pointer to Queue name
 *  ReplyQName   - pointer to Reply Q name
 *  messageData  - pointer to message data
 *
 * Output
 *  None.
 *
 * Return Value
 *  MY_RC_T
 * ------------------------------------------------------------------
 */
MY_RC_T PutMessage(MQHCONN            Hconn,
                  char               *QMgrName,
                  char               *QName,
                  char               *ReplyQName,
                  char               *messageData)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   MY_RC_T     rcode = RC_OK;
   MQLONG      mqCC;       /* completion code from QMgr */
   MQLONG      mqRC;       /* reason code from QMgr */
   MQOD        od = {MQOD_DEFAULT};    /* Object Descriptor    */
   MQMD        md = {MQMD_DEFAULT};    /* Message Descriptor   */
   MQPMO       pmo = {MQPMO_DEFAULT};  /* put message options  */

   /* --------------------------------------------
    * Code section
    * --------------------------------------------
    */
   /* Set OPEN options */
   strncpy(od.ObjectQMgrName, QMgrName, MQ_Q_MGR_NAME_LENGTH);
   strncpy(od.ObjectName, QName, MQ_Q_NAME_LENGTH);

   /* Set MQPUT options */
   pmo.Options = MQPMO_FAIL_IF_QUIESCING | MQPMO_NO_SYNCPOINT;

   /* Setup Message Descriptor */
   md.MsgType        = MQMT_REQUEST;
   md.Expiry         = MQEI_UNLIMITED;
   md.Feedback       = MQFB_NONE;
   md.Encoding       = MQENC_NATIVE;
   md.Priority       = MQPRI_PRIORITY_AS_Q_DEF;
   md.Persistence    = MQPER_PERSISTENCE_AS_Q_DEF;

   memcpy(md.MsgId,    MQMI_NONE, sizeof(md.MsgId) );
   memcpy(md.CorrelId, MQCI_NONE, sizeof(md.CorrelId) );
   memcpy(md.GroupId,  MQGI_NONE, sizeof(md.GroupId));
   memcpy(md.Format,   MQFMT_STRING, sizeof(md.Format) );
   strncpy(md.ReplyToQ, ReplyQName, MQ_Q_NAME_LENGTH );

   MQPUT1(Hconn,              /* connection handle   */
          &od,                /* object descriptor   */
          &md,                /* message descriptor  */
          &pmo,               /* put message options */
          strlen(messageData),/* buffer length       */
          messageData,        /* message buffer      */
          &mqCC,              /* completion code     */
          &mqRC);             /* reason code         */

   printf("MQPUT1  CC=%d RC=%d for %s\n",
          mqCC,
          mqRC,
          QName );

   if (mqCC == MQCC_FAILED)
      rcode = RC_FAILED;
   else
      rcode = RC_OK;

   return (rcode);
}

/*
 * ==================================================================
 *
 * Function Name
 *  ProcessCmdMessages
 *
 * Description
 *  This routine will get all reply messages from our temporary
 *  dynamic queue.
 *
 * Input parameters
 *  Hconn    - connection handle
 *  HObj     - Object handle for reply Q
 *  QName    - reply queue name
 *
 * Output
 *  Response messages will be written to stdout
 *
 * Return Value
 *  MY_RC_T
 * ------------------------------------------------------------------
 */
MY_RC_T ProcessCmdMessages(MQHCONN          Hconn,
                           MQHOBJ           HObj,
                           char             *QName)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   MY_RC_T      rcode = RC_OK;
   MQLONG       mqCC;       /* completion code from QMgr */
   MQLONG       mqRC;       /* reason code from QMgr */
   MQLONG       bufLen = 0; /* length of the buffer */
   MQLONG       msgLen = 0; /* length of the return message */
   MQMD         md = {MQMD_DEFAULT};
   MQGMO        gmo = {MQGMO_DEFAULT};
   char         Continue   = 'Y';
   char         ResponseBuffer[WORK_BUFFER_SIZE+1]; /* way too big but that is ok! */

   /* --------------------------------------------
    * Code section
    * --------------------------------------------
    */
   gmo.Options = MQGMO_FAIL_IF_QUIESCING | MQGMO_CONVERT | MQGMO_WAIT | MQGMO_NO_SYNCPOINT;
   gmo.WaitInterval = 5 * 1000; /* wait up to 5 seconds */

   /*
    * Loop through the messages on the queue.
    */
   while ( Continue == 'Y' )
   {
      bufLen = WORK_BUFFER_SIZE;
      memcpy(md.MsgId, MQMI_NONE, sizeof(md.MsgId));
      memcpy(md.CorrelId, MQCI_NONE, sizeof(md.CorrelId));
      memcpy(md.Format, MQFMT_NONE, (size_t)MQ_FORMAT_LENGTH);

      MQGET(Hconn,               /* connection handle                 */
            HObj,                /* object handle                     */
            &md,                 /* message descriptor                */
            &gmo,                /* get message options               */
            bufLen,              /* buffer length                     */
            ResponseBuffer,      /* message buffer                    */
            &msgLen,             /* message length                    */
            &mqCC,               /* completion code                   */
            &mqRC);              /* reason code                       */

      if ( mqCC == MQCC_OK )
      {
         ResponseBuffer[msgLen] = 0x00; /* add a null */
         printf("Response: %s\n", ResponseBuffer);

         if (memcmp(ResponseBuffer,"CSQ9022I",8) == STR_EQ)
            Continue = 'N';  /* no more messages to follow */
      }
      else if ( (mqCC != MQCC_OK) &&
                (mqRC == MQRC_NO_MSG_AVAILABLE) )
      {
         /* No more messages on the queue. */
         Continue = 'N';
      }
      else
      {
         printf("MQGET   CC=%d RC=%d for %s\n",
                mqCC,
                mqRC,
                QName );

         rcode = RC_FAILED;
         Continue = 'N';
      }

   }  /* while ( Continue == 'Y' ) */

   return (rcode);
}

Regards,
Roger Lacroix
Capitalware Inc.

This entry was posted in C, IBM MQ, Linux, Open Source, Programming, Unix, Windows.

2 Responses to C Program to Send an MQSC Command to a z/OS Queue Manager