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.