529 lines
22 KiB
HTML
529 lines
22 KiB
HTML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE html
|
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html lang="en-us" xml:lang="en-us">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="security" content="public" />
|
|
<meta name="Robots" content="index,follow" />
|
|
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))' />
|
|
<meta name="DC.Type" content="reference" />
|
|
<meta name="DC.Title" content="Example: Diagnostic reporting" />
|
|
<meta name="abstract" content="This example program illustrates the use of the Send Nonprogram Message API, QMHSNDM, the Receive Program Message API, QMHRCVPM, and the Change Exception Message API, QMHCHGEM. The program produces a diagnostic report of errors that occur when the QMHSNDM API is used to send a message to more than one message queue." />
|
|
<meta name="description" content="This example program illustrates the use of the Send Nonprogram Message API, QMHSNDM, the Receive Program Message API, QMHRCVPM, and the Change Exception Message API, QMHCHGEM. The program produces a diagnostic report of errors that occur when the QMHSNDM API is used to send a message to more than one message queue." />
|
|
<meta name="DC.Relation" scheme="URI" content="apiexmp.htm" />
|
|
<meta name="copyright" content="(C) Copyright IBM Corporation 1998, 2006" />
|
|
<meta name="DC.Rights.Owner" content="(C) Copyright IBM Corporation 1998, 2006" />
|
|
<meta name="DC.Format" content="XHTML" />
|
|
<meta name="DC.Identifier" content="apiexdirep" />
|
|
<meta name="DC.Language" content="en-us" />
|
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
|
<!-- US Government Users Restricted Rights -->
|
|
<!-- Use, duplication or disclosure restricted by -->
|
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
|
<link rel="stylesheet" type="text/css" href="./ibmdita.css" />
|
|
<link rel="stylesheet" type="text/css" href="./ic.css" />
|
|
<title>Example: Diagnostic reporting</title>
|
|
</head>
|
|
<body id="apiexdirep"><a name="apiexdirep"><!-- --></a>
|
|
<!-- Java sync-link --><script language="Javascript" src="../rzahg/synch.js" type="text/javascript"></script>
|
|
<h1 class="topictitle1">Example: Diagnostic reporting</h1>
|
|
<div><p>This example program illustrates the use of the Send Nonprogram
|
|
Message API, QMHSNDM, the Receive Program Message API, QMHRCVPM, and the Change
|
|
Exception Message API, QMHCHGEM. The program produces a diagnostic report
|
|
of errors that occur when the QMHSNDM API is used to send a message to more
|
|
than one message queue.</p>
|
|
<div class="section"><p>The program calls the QMHSNDM API to send a message
|
|
to message queues that do not exist. The QMHSNDM API returns a generic exception
|
|
message, CPF2469. This message indicates that the API also returned one or
|
|
more diagnostic messages describing the errors. After the program receives
|
|
the exception message and verifies that it is message CPF2469, it uses the
|
|
QMHCHGEM API to handle the exception message. The QMHRCVPM API is used to
|
|
receive the diagnostic messages. The program prints the exception message,
|
|
the diagnostic messages, and the message help.</p>
|
|
<div class="note"><span class="notetitle">Note:</span> Read the <a href="codedisclaimer.htm">Code license and disclaimer information</a> for
|
|
important legal information.</div>
|
|
</div>
|
|
<div class="section"><h4 class="sectiontitle">Diagnostic Report (DIAGRPT) program</h4><pre>/********************************************************************/
|
|
/* */
|
|
/* MODULE NAME: DIAGRPT - Diagnostic Report */
|
|
/* LANGUAGE: ILE C for OS/400 */
|
|
/* */
|
|
/* FUNCTION: This module will produce a diagnostic report that */
|
|
/* could be used in diagnosing the errors that */
|
|
/* occurred using the QMHSNDM API to send a message */
|
|
/* to multiple message queues. */
|
|
/* */
|
|
/* This program purposely causes the QMHSNDM API to */
|
|
/* try to send a message to message queues that do */
|
|
/* not exist. As a result, the generic CPF2469 */
|
|
/* exception is returned indicating that one or more */
|
|
/* diagnostic messages were returned identifying the */
|
|
/* error(s) on the send operation. */
|
|
/* */
|
|
/* The program looks for and handles the CPF2469 */
|
|
/* exception. It then receives and prints out the */
|
|
/* exception and the previous diagnostics. */
|
|
/* */
|
|
/* Dependency: A print file must be created before calling */
|
|
/* program DIAGRPT. The print file should be created */
|
|
/* using the following command: */
|
|
/* */
|
|
/* CRTPRTF FILE(PRTDIAG) CTLCHAR(*FCFC) */
|
|
/* CHLVAL((1 (13))) */
|
|
/********************************************************************/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <except.h>
|
|
#include <qmhchgem.h> /* From QSYSINC/H */
|
|
#include <qmhrcvpm.h> /* From QSYSINC/H */
|
|
#include <qmhsndm.h> /* From QSYSINC/H */
|
|
#include <qusec.h> /* From QSYSINC/H */
|
|
|
|
#define DIAG_TYPE "02"
|
|
#define BUF_SIZE 80
|
|
|
|
/*********************************************************************/
|
|
/* Type definition for error code structure */
|
|
/*********************************************************************/
|
|
typedef struct error_code_struct
|
|
{
|
|
Qus_EC_t ec_fields;
|
|
char Exception_Data[100];
|
|
} error_code_struct;
|
|
|
|
/*********************************************************************/
|
|
/* Type definition for qualified name structure */
|
|
/*********************************************************************/
|
|
typedef struct qual_name_struct
|
|
{
|
|
char name[10];
|
|
char libr[10];
|
|
} qual_name_struct;
|
|
|
|
/*********************************************************************/
|
|
/* Type definition for message information structure used on the */
|
|
/* receive. F is the fixed portion of the record and V is the */
|
|
/* variable length portion of the record. */
|
|
/*********************************************************************/
|
|
typedef struct msg_info_struct
|
|
{
|
|
Qmh_Rcvpm_RCVM0200_t F;
|
|
char V[1200];
|
|
} msg_info_struct;
|
|
|
|
FILE *prtf;
|
|
char buf[80];
|
|
char received[7];
|
|
int exception_count;
|
|
|
|
|
|
/*********************************************************************/
|
|
/* Function to handle errors received on the API calls. */
|
|
/*********************************************************************/
|
|
static void excp_handler(_INTRPT_Hndlr_Parms_T *excp_info)
|
|
{
|
|
error_code_struct Error_Code;
|
|
|
|
/* If the exception is CPF2469, increment the exception counter, */
|
|
/* and mark the exception as handled by the QMHCHGEM API */
|
|
|
|
if (strncmp(excp_info->Msg_Id,"CPF2469",7) == 0) {
|
|
memcpy(received,(excp_info->Msg_Id),7);
|
|
exception_count++;
|
|
QMHCHGEM(&(excp_info->Target), 0,
|
|
(char *)(&(excp_info->Msg_Ref_Key)),
|
|
"*HANDLE ", "", 0, &Error_Code);
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* BuildQList: Routine to build the message queue list. */
|
|
/********************************************************************/
|
|
void BuildQList( qual_name_struct *QueueList, int NumQueue)
|
|
{
|
|
int i;
|
|
|
|
strncpy(QueueList[0].name,"QPGMR ",10);
|
|
strncpy(QueueList[1].name,"SNOOPY ",10);
|
|
strncpy(QueueList[2].name,"QSECOFR ",10);
|
|
strncpy(QueueList[3].name,"PEANUTS ",10);
|
|
strncpy(QueueList[4].name,"QUSER ",10);
|
|
|
|
for (i = 0; i < NumQueue ; i++ )
|
|
{
|
|
strncpy(QueueList[i].libr,"*LIBL ",10);
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* PrintError: Routine to print error information and exit. */
|
|
/********************************************************************/
|
|
void PrintError(char *errstring, char exception[7])
|
|
{
|
|
|
|
memset(buf,' ',BUF_SIZE);
|
|
buf[0] = '0';
|
|
strncpy(buf+1,errstring,strlen(errstring));
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
|
|
memset(buf,' ',BUF_SIZE);
|
|
buf[0] = '0';
|
|
strncpy(buf+1,"Exception received->",20);
|
|
strncpy(buf+21,exception,strlen(exception));
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
fclose(prtf);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* PrintData: Routine to print varying length character string data.*/
|
|
/********************************************************************/
|
|
void PrintData(char *strname, void *strptr, int strlgth)
|
|
{
|
|
char *strdata = strptr;
|
|
int i,lgth,remain;
|
|
|
|
/* Write the description and the data that will fit on one line */
|
|
memset(buf,' ',BUF_SIZE);
|
|
buf[0] = '0';
|
|
lgth = strlen(strname);
|
|
strncpy(buf+1,strname,lgth);
|
|
lgth++;
|
|
|
|
/* remain = MIN(strlgth,80 - lgth) */
|
|
remain = (strlgth < 80 - lgth) ? strlgth : 80 - lgth;
|
|
strncpy(buf+lgth,strdata,remain);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
|
|
/* Now write the remainder of the data */
|
|
if (strlgth > (80 - lgth ))
|
|
{
|
|
/* Adjust pointer to data not printed yet */
|
|
strdata = strdata + (80 - lgth);
|
|
|
|
for (i = 0; i < strlgth; i = i + 70, strdata = strdata + 70 )
|
|
{
|
|
/* lgth = MIN(strlgth-i,70) */
|
|
lgth = (strlgth-i < 70) ? strlgth-i : 70;
|
|
|
|
memset(buf,' ',BUF_SIZE);
|
|
strncpy(buf,"0 ",10);
|
|
memcpy(buf+10,strdata,lgth);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* PrintMessage: Routine to print the message data and text. */
|
|
/********************************************************************/
|
|
void PrintMessage(msg_info_struct *Msg)
|
|
|
|
{
|
|
char *DataPtr; /* Pointer to the varying length character data*/
|
|
int DataLen; /* Length of the varying length character data */
|
|
char CharType[10]; /* Message type as a string */
|
|
|
|
PrintData("Message ID->",Msg->F.Message_Id,7);
|
|
/* Convert Message Type to a character string to be printed out */
|
|
if (memcmp(Msg->F.Message_Type,"02",2)==0)
|
|
strncpy(CharType,"DIAGNOSTIC", 10);
|
|
else if (memcmp(Msg->F.Message_Type,"15",2)==0)
|
|
strncpy(CharType,"ESCAPE ",10);
|
|
PrintData("Message Type->",CharType,10);
|
|
|
|
/* First point to the beginning of the message data */
|
|
/* in the structure and get the length of data returned. */
|
|
DataPtr = Msg->V;
|
|
DataLen = Msg->F.Length_Data_Returned;
|
|
/* If there is non-blank data, print it out */
|
|
if ((DataLen > 0) && (strspn(DataPtr," ") < DataLen))
|
|
PrintData("Message data received->",DataPtr,DataLen);
|
|
|
|
/* Point to the beginning of the message text field and get the */
|
|
/* length of message text returned. */
|
|
DataPtr += DataLen;
|
|
DataLen = Msg->F.Length_Message_Returned;
|
|
/* If there is non-blank text, print it out */
|
|
if ((DataLen > 0) && (strspn( DataPtr," ") < DataLen))
|
|
PrintData("Message text received->",DataPtr,DataLen);
|
|
|
|
/* Now update to point to the beginning of the message */
|
|
/* help text field and get the length of message help text */
|
|
/* returned. */
|
|
DataPtr += DataLen;
|
|
DataLen = Msg->F.Length_Help_Returned;
|
|
/* If there is non-blank message help text, print it out */
|
|
if ((DataLen > 0) && (strspn( DataPtr," ") < DataLen))
|
|
PrintData("Message help text received->",DataPtr,DataLen);
|
|
strncpy(buf,"- ",43);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* */
|
|
/* Start of main program. */
|
|
/* */
|
|
/*********************************************************************/
|
|
|
|
main()
|
|
{
|
|
|
|
|
|
error_code_struct ErrorCode;
|
|
|
|
qual_name_struct MsgQList[5];
|
|
qual_name_struct MsgFile;
|
|
qual_name_struct RpyMsgQ;
|
|
|
|
msg_info_struct MsgInfo;
|
|
|
|
char MsgData[128];
|
|
char MsgText[512];
|
|
char MsgHelp[512];
|
|
char PgmMsgQ[10];
|
|
char MsgType[10];
|
|
char MsgAction[10];
|
|
char Format[8];
|
|
char MsgId[7];
|
|
char MsgKey[4];
|
|
|
|
int MsgTextLen;
|
|
int MsgInfoLen;
|
|
int NumMsgQ;
|
|
int PgmCount;
|
|
int WaitTime;
|
|
int morediag;
|
|
|
|
|
|
/* Initialize variables */
|
|
exception_count = 0;
|
|
memcpy(ErrorCode.ec_fields.Exception_Id," ",7);
|
|
ErrorCode.ec_fields.Bytes_Provided = 0;
|
|
|
|
memcpy(MsgId," ",7);
|
|
memcpy(MsgFile.name," ",10);
|
|
memcpy(MsgFile.libr," ",10);
|
|
strcpy(MsgText,"This is an immediate, informational message");
|
|
MsgTextLen = strlen(MsgText);
|
|
memcpy(MsgType,"*INFO ",10);
|
|
memcpy(RpyMsgQ.name," ",10);
|
|
memcpy(RpyMsgQ.libr," ",10);
|
|
|
|
/* Build the list of message queues to send the message to */
|
|
NumMsgQ = 5;
|
|
BuildQList(MsgQList,NumMsgQ);
|
|
|
|
|
|
/* Enable the exception handler around the call to QMHSNDM */
|
|
#pragma exception_handler(excp_handler, 0, 0, _C2_MH_ESCAPE)
|
|
|
|
/* Send the message to the list of message queues. */
|
|
QMHSNDM( MsgId,
|
|
&MsgFile,
|
|
MsgText,
|
|
MsgTextLen,
|
|
MsgType,
|
|
&MsgQList,
|
|
NumMsgQ,
|
|
&RpyMsgQ,
|
|
&MsgKey,
|
|
&ErrorCode);
|
|
|
|
/* Disable the exception handler */
|
|
#pragma disable_handler
|
|
|
|
/* If an error occurred on the send, produce an exception report */
|
|
/* identifying what errors occurred. */
|
|
if (exception_count != 0)
|
|
{
|
|
|
|
/* Open printer file using first character forms control and */
|
|
/* write the header information. */
|
|
prtf = fopen ("PRTDIAG", "wb type=record recfm=FA lrecl=80");
|
|
memset(buf,' ',BUF_SIZE);
|
|
strncpy(buf,"1 DIAGNOSTIC REPORT",43);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
strncpy(buf," -----------------",43);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
strncpy(buf,"- ",43);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
|
|
/* Do the setup to first receive the exception signalled. */
|
|
memcpy(Format,"RCVM0200",8);
|
|
memcpy(PgmMsgQ,"* ",10);
|
|
memcpy(MsgType,"*EXCP ",10);
|
|
memcpy(MsgKey," ",4);
|
|
memcpy(MsgAction,"*OLD ",10);
|
|
PgmCount = 0;
|
|
WaitTime = 0;
|
|
MsgInfoLen = 1276;
|
|
|
|
/* Now change bytes_provided to 116 so that if any errors occur */
|
|
/* on the receive, the error information will be returned in the*/
|
|
/* error code structure instead of generating more exceptions */
|
|
/* which will clutter up the program message queue. */
|
|
ErrorCode.ec_fields.Bytes_Provided = 116;
|
|
|
|
/* Receive the last exception type message on the program */
|
|
/* message queue */
|
|
QMHRCVPM(&MsgInfo,
|
|
MsgInfoLen,
|
|
Format,
|
|
PgmMsgQ,
|
|
PgmCount,
|
|
MsgType,
|
|
MsgKey,
|
|
WaitTime,
|
|
MsgAction,
|
|
&ErrorCode);
|
|
|
|
/* Test for any errors on the receive */
|
|
if (ErrorCode.ec_fields.Bytes_Available > 0)
|
|
{
|
|
PrintError("QMHRCVPM - Did not complete successfully",
|
|
ErrorCode.ec_fields.Exception_Id);
|
|
}
|
|
|
|
/* An exception message was received successfully. Now see if */
|
|
/* the message received is the same exception that was signalled*/
|
|
/* If not, there is an error. */
|
|
if (strncmp(MsgInfo.F.Message_Id,received,7) != 0)
|
|
{
|
|
PrintError("QMHRCVPM - Wrong exception received",
|
|
MsgInfo.F.Message_Id);
|
|
}
|
|
|
|
|
|
/* The exception message was received successfully. */
|
|
/* Print the message data and text for the exception message. */
|
|
PrintMessage(&MsgInfo);
|
|
|
|
/* If the message was the generic CPF2469, there are one or */
|
|
/* more diagnostic messages to go with the CPF2469 on the queue.*/
|
|
/* Receive the diagnostic messages previous to the CPF2469 until*/
|
|
/* a non-diagnostic message is received or there are no more */
|
|
/* messages. */
|
|
if (strncmp(MsgInfo.F.Message_Id,"CPF2469",7) == 0)
|
|
{
|
|
memcpy(MsgType,"*PRV ",10);
|
|
memcpy(MsgKey,MsgInfo.F.Message_Key,4);
|
|
morediag = 1;
|
|
|
|
while(morediag)
|
|
{
|
|
/* Receive the previous diagnostic */
|
|
QMHRCVPM(&MsgInfo,
|
|
MsgInfoLen,
|
|
Format,
|
|
PgmMsgQ,
|
|
PgmCount,
|
|
MsgType,
|
|
MsgKey,
|
|
WaitTime,
|
|
MsgAction,
|
|
&ErrorCode);
|
|
|
|
/* Test for error on the receive */
|
|
if (ErrorCode.ec_fields.Bytes_Available > 0)
|
|
{
|
|
PrintError("QMHRCVPM - Did not complete successfully",
|
|
ErrorCode.ec_fields.Exception_Id);
|
|
}
|
|
|
|
/* If bytes available = 0 OR the next message is not a */
|
|
/* diagnostic message, we are done. */
|
|
if ((MsgInfo.F.Bytes_Available == 0) ||
|
|
(strncmp(MsgInfo.F.Message_Type,DIAG_TYPE,2) != 0) )
|
|
{
|
|
morediag = 0;
|
|
}
|
|
else /* A diagnostic was received */
|
|
{
|
|
/* Print the message data and text for the diagnostic */
|
|
/* message */
|
|
PrintMessage(&MsgInfo);
|
|
|
|
/* Now copy the message key of the diagnostic message */
|
|
/* received to the MsgKey parameter to use on the next */
|
|
/* call to QMHRCVPM. */
|
|
memcpy(MsgKey,MsgInfo.F.Message_Key,7);
|
|
}
|
|
|
|
} /* End of while morediag = 1 */
|
|
|
|
} /* End of if CPF2469 received */
|
|
|
|
/* Write trailer */
|
|
memset(buf,' ',BUF_SIZE);
|
|
strncpy(buf,"- END OF DIAGNOSTIC REPORT",48);
|
|
fwrite(buf,1,BUF_SIZE,prtf);
|
|
|
|
/* Close the print file */
|
|
fclose(prtf);
|
|
|
|
} /* End of if error on send */
|
|
|
|
} /* End mainline */
|
|
</pre>
|
|
</div>
|
|
<div class="section"><h4 class="sectiontitle">Printed diagnostic report</h4><p>The DIAGRPT program produces
|
|
a report like this:</p>
|
|
<pre>Message ID->CPF2469
|
|
Message Type->ESCAPE
|
|
Message text received->Error occurred when sending message.
|
|
Message help text received->Recovery . . . : See messages
|
|
previously listed for a description of the error.
|
|
Correct the error, and then try the
|
|
command again.
|
|
|
|
Message ID->CPF2403
|
|
Message Type->DIAGNOSTIC
|
|
Message data received->PEANUTS *LIBL
|
|
Message text received->Message queue PEANUTS in *LIBL not found.
|
|
Message help text received->Cause . . . . . : The message queue you
|
|
specified was not found in the library you specified. One
|
|
of the following occurred: -- The queue name was not
|
|
entered correctly. -- The queue does not exist in the
|
|
specified library. -- You specified the wrong library name.
|
|
Recovery . . . : Do one of the following and try the
|
|
request again: -- Correct or change the message queue
|
|
name or library name used in the message queue (MSGQ)
|
|
parameter or the to-message queue (TOMSGQ) parameter.
|
|
-- Create the message queue using the Create Message
|
|
Queue (CRTMSGQ) command.
|
|
|
|
|
|
Message ID->CPF2403
|
|
Message Type->DIAGNOSTIC
|
|
Message data received->SNOOPY *LIBL
|
|
Message text received->Message queue SNOOPY in *LIBL not found.
|
|
Message help text received->Cause . . . . . : The message queue
|
|
you specified was not found in the library you specified.
|
|
One of the following occurred: -- The queue name was not
|
|
entered correctly. -- The queue does not exist in the
|
|
specified library. -- You specified the wrong library
|
|
name. Recovery . . . : Do one of the following and
|
|
try the request again: -- Correct or change the message
|
|
queue name or library name used in the message queue
|
|
(MSGQ) parameter or the to-message queue (TOMSGQ)
|
|
parameter. -- Create the message queue using the Create
|
|
Message Queue (CRTMSGQ) command.
|
|
End of Diagnostic Report</pre>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="familylinks">
|
|
<div class="parentlink"><strong>Parent topic:</strong> <a href="apiexmp.htm" title="Contains example programs that use APIs and exit programs.">Examples: APIs</a></div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |