3.7.3 サンプルUOCのコーディング例
0010 /*******************************************************/
0020 /* */
0030 /* Program name: MsgEdit */
0040 /* */
0050 /* Description: Sample program of the user exit */
0060 /* routine for message editing */
0070 /* */
0080 /*******************************************************/
0090 /* */
0100 /* Function: */
0110 /* */
0120 /* This sample program processes messages whose */
0130 /* reference header (MQRMH) has the object type */
0140 /* matching with the message editing exit user data of */
0150 /* the channel definition. */
0160 /* When the channel type is sender, server or clussdr, */
0170 /* the program takes the data of the file with the */
0180 /* send object name described in the message reference */
0190 /* header, and copies the whole data length from the */
0200 /* offset to the application data area of the */
0210 /* transmission buffer. */
0220 /* If the program cannot copy all the messages in the */
0230 /* file to the available area in the */
0240 /* transmission buffer, an error will be returned. */
0250 /* An error will also be returned when an error occurs */
0260 /* while accessing the file. */
0270 /* A successful return will set the following */
0280 /* information: Channel exit parameter block */
0290 /* (dcmtcq_uoc_mqxcp structure) */
0300 /* ExitResponse = DCMTCQ_MQXCC_OK */
0310 /* ExitResponse2 = DCMTCQ_MQXR2_USE_TRAN_BUFFER */
0320 /* Transmission buffer list */
0330 /* (dcmtcq_uoc_buffinf structure) */
0340 /* Used_buff_length += Data_length */
0350 /* An error return will set the following information: */
0360 /* Channel exit parameter block */
0370 /* (dcmtcq_uoc_mqxcp structure) */
0380 /* ExitResponse = DCMTCQ_MQXCC_SUPPRESS_FUNCTION */
0390 /* Feedback = MQFB_STOPPED_BY_MSG_EXIT */
0400 /* */
0410 /* When the channel type is requester, receiver or */
0420 /* clusrcvr, the program takes the messages in the */
0430 /* application data area of the transmission buffer, */
0440 /* and outputs the whole data length from the offset */
0450 /* to the file with the destination object name */
0460 /* specified in the message reference header. */
0470 /* If the offset value is 0, the program creates a */
0480 /* new file. Otherwise, the messages are added to the */
0490 /* end of the file. */
0500 /* If the message being added encounters the condition */
0510 /* that the offset value is so small that the file's */
0520 /* trailing end is not reached, the program discards */
0530 /* the message. */
0540 /* If the offset value is greater, the program returns */
0550 /* an error. */
0560 /* The user exit routine will return an error when */
0570 /* accessing the file encounters an abnormality. */
0580 /* A successful return will set the following */
0590 /* information: */
0600 /* Channel exit parameter block */
0610 /* (dcmtcq_uoc_mqxcp structure) */
0620 /* ExitResponse = DCMTCQ_MQXCC_OK */
0630 /* ExitResponse2 = DCMTCQ_MQXR2_USE_TRAN_BUFFER */
0640 /* Transmission buffer list */
0650 /* (dcmtcq_uoc_buffinf structure) */
0660 /* Used_buff_length = Transmission header (MQXQH) */
0670 /* length + Message_reference_header_length */
0680 /* An error return will set the following information: */
0690 /* Channel exit parameter block */
0700 /* (dcmtcq_uoc_mqxcp structure) */
0710 /* ExitResponse = DCMTCQ_MQXCC_SUPPRESS_FUNCTION */
0720 /* Feedback = MQFB_STOPPED_BY_MSG_EXIT */
0730 /* */
0740 /*******************************************************/
0750 /* */
0760 /* The program does not convert the application data */
0770 /* containing the message reference header. In order */
0780 /* to use this program for transmission between */
0790 /* different machines requiring data conversion, add */
0800 /* a data conversion process. */
0810 /* */
0820 /*******************************************************/
0830
0840 #include <errno.h>
0850 #include <stdio.h>
0860 #include <stdlib.h>
0870 #include <stddef.h>
0880 #include <string.h>
0890 #include <ctype.h>
0900
0910 #include <cmqc.h>
0920 #include <dcmtcquo.h>
0930
0940 long MsgEdit(dcmtcq_uoc_parmlist *ParmList);
0950
0960 /*******************************************************/
0970 /* Constants */
0980 /*******************************************************/
0990 #define MAX_FILENAME_LENGTH 256
1000 #define LOGICAL_OFFSET_VAL 1000000000L
1010
1020
1030 long MsgEdit(dcmtcq_uoc_parmlist *ParmList)
1040 {
1050 PMQXQH pMQXQH;
1060 PMQRMH pMQRMH;
1070 MQLONG FileDataOffset;
1080 /* offset of data within file */
1090 MQLONG FeedbackCode = 0; /* feedback code */
1100 char *pMsgData; /* pointer to data
1110 within reference msg */
1120 char DestFileName[MAX_FILENAME_LENGTH+1];
1130 /* Name of file at receiving end */
1140 char SrcFileName[MAX_FILENAME_LENGTH+1];
1150 /* Name of file at sending end */
1160 FILE *fd = NULL; /* file descriptor */
1170 char mode[4]; /* file open mode */
1180 long position; /* position within file. */
1190 int rc; /* return code */
1200 size_t itemswritten; /* returned by fwrite */
1210 size_t bytesread; /* returned by fread */
1220 char dummy; /* work area */
1230 MQLONG MsgSpace;
1240 /* Space remaining in input buffer */
1250 MQLONG ReadLength; /* Number of bytes to read
1260 from file */
1270 MQLONG WriteLength; /* Number of bytes to write
1280 to file */
1290 int WriteData = 1; /* Do we write the data */
1300 MQLONG InputDataLength; /* Length requested
1310 in reference msg */
1320
1330 ParmList->mqcxp_adr->ExitResponse = DCMTCQ_MQXCC_OK;
1340 ParmList->mqcxp_adr->ExitResponse2 =
1350 DCMTCQ_MQXR2_USE_TRAN_BUFFER;
1360
1370 switch(ParmList->mqcxp_adr->ExitId)
1380 {
1390 case DCMTCQ_MQXT_CHANNEL_MSGEDT_EXIT:
1400 break;
1410 default:
1420 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
1430 goto UOC_EXIT;
1440 }
1450
1460 switch(ParmList->mqcxp_adr->ExitReason)
1470 {
1480 case DCMTCQ_MQXR_INIT:
1490 goto UOC_EXIT;
1500 case DCMTCQ_MQXR_TERM:
1510 goto UOC_EXIT;
1520 case DCMTCQ_MQXR_MSG:
1530 break;
1540 case DCMTCQ_MQXR_ALT:
1550 goto UOC_EXIT;
1560 default:
1570 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
1580 goto UOC_EXIT;
1590 }
1600
1610 /*****************************************************/
1620 /* Get addresses of transmission header and message */
1630 /* itself. The message should start with a reference */
1640 /* message header. */
1650 /*****************************************************/
1660
1670 pMQXQH = (PMQXQH)
1680 (ParmList->tbuflist_adr->Buffinf_array[0].Buffer_addr);
1690 pMQRMH = (PMQRMH)
1700 (ParmList->tbuflist_adr->Buffinf_array[0]
1710 .Buffer_addr + sizeof(MQXQH));
1720
1730 /*****************************************************/
1740 /* If the message format does not indicate a */
1750 /* reference message then ignore the message. */
1760 /*****************************************************/
1770 if (memcmp(pMQXQH->MsgDesc.Format,
1780 MQFMT_REF_MSG_HEADER,
1790 MQ_FORMAT_LENGTH))
1800 {
1810 goto UOC_EXIT;
1820 }
1830
1840 /*****************************************************/
1850 /* If the object type does not match the type */
1860 /* specified in the channel definition then ignore */
1870 /* the message. */
1880 /*****************************************************/
1890 if (memcmp(pMQRMH->ObjectType,
1900 ParmList->mqcxp_adr->ExitData,
1910 sizeof(pMQRMH->ObjectType)))
1920 {
1930 goto UOC_EXIT;
1940 }
1950
1960 /*****************************************************/
1970 /* Check that the SrcEnv field lies within the */
1980 /* structure */
1990 /*****************************************************/
2000 if (pMQRMH->SrcEnvLength < 0 ||
2010 (pMQRMH->SrcEnvLength > 0 &&
2020 (pMQRMH->SrcEnvLength + pMQRMH->SrcEnvOffset) >
2030 pMQRMH->StrucLength))
2040 {
2050 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
2060 goto UOC_EXIT;
2070 }
2080
2090 /*****************************************************/
2100 /* Check that the SrcName field lies within the */
2110 /* structure */
2120 /*****************************************************/
2130 if (pMQRMH->SrcNameLength < 0 ||
2140 (pMQRMH->SrcNameLength > 0 &&
2150 (pMQRMH->SrcNameLength + pMQRMH->SrcNameOffset) >
2160 pMQRMH->StrucLength))
2170 {
2180 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
2190 goto UOC_EXIT;
2200 }
2210
2220 /*****************************************************/
2230 /* Check that the DestEnv field lies within the */
2240 /* structure */
2250 /*****************************************************/
2260 if (pMQRMH->DestEnvLength < 0 ||
2270 (pMQRMH->DestEnvLength > 0 &&
2280 (pMQRMH->DestEnvLength + pMQRMH->DestEnvOffset) >
2290 pMQRMH->StrucLength))
2300 {
2310 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
2320 goto UOC_EXIT;
2330 }
2340
2350 /*****************************************************/
2360 /* Check that the DestName field lies within the */
2370 /* structure */
2380 /*****************************************************/
2390 if (pMQRMH->DestNameLength < 0 ||
2400 (pMQRMH->DestNameLength > 0 &&
2410 (pMQRMH->DestNameLength + pMQRMH->DestNameOffset) >
2420 pMQRMH->StrucLength))
2430 {
2440 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
2450 goto UOC_EXIT;
2460 }
2470
2480 /*****************************************************/
2490 /* Check that the message contains a complete MQRMH */
2500 /* structure */
2510 /*****************************************************/
2520 if (pMQRMH->StrucLength >
2530 (MQLONG)(ParmList->tbuflist_adr->
2540 Buffinf_array[0].Used_buff_length - sizeof(MQXQH)))
2550 {
2560 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
2570 goto UOC_EXIT;
2580 }
2590
2600 /*****************************************************/
2610 /* Extract the following values from the reference */
2620 /* message. */
2630 /* Offset of data within the file. */
2640 /* Length of data to be read or written */
2650 /* Name of file on destination system. */
2660 /* Name of file on source system. */
2670 /*****************************************************/
2680 FileDataOffset = pMQRMH->DataLogicalOffset2 *
2690 LOGICAL_OFFSET_VAL +
2700 pMQRMH->DataLogicalOffset;
2710 InputDataLength = pMQRMH->DataLogicalLength;
2720 memset(DestFileName, 0, sizeof(DestFileName));
2730 memset(SrcFileName, 0, sizeof(SrcFileName));
2740 memcpy(DestFileName,
2750 (char *)pMQRMH + pMQRMH->DestNameOffset,
2760 (size_t)pMQRMH->DestNameLength);
2770 memcpy(SrcFileName,
2780 (char *)pMQRMH + pMQRMH->SrcNameOffset,
2790 (size_t)pMQRMH->SrcNameLength);
2800
2810 /*****************************************************/
2820 /* Move the data to or from the file. */
2830 /*****************************************************/
2840 switch (ParmList->mqcd_adr->ChannelType)
2850 {
2860 /***************************************************/
2870 /* For server and sender channels append data from */
2880 /* the file to the reference message and return it */
2890 /* to the caller. */
2900 /***************************************************/
2910 case DCMTCQ_MQCHT_SENDER:
2920 case DCMTCQ_MQCHT_SERVER:
2930 case DCMTCQ_MQCHT_CLUSSDR:
2940
2950 /*************************************************/
2960 /* Calculate space remaining at end of input */
2970 /* buffer and pointer to start of the space. */
2980 /* If the length of the agent buffer is greater */
2990 /* than the MaxMsglength for the channel plus */
3000 /* the transmission header size, then use the */
3010 /* MaxMsgLength in the calculation. */
3020 /* If InputDataLength > 0 this means that only */
3030 /* that length is required. In this case, if the */
3040 /* length specified is less than the space in */
3050 /* the buffer then read just this length. */
3060 /*************************************************/
3070 MsgSpace = ((ParmList->tbuflist_adr->
3080 Buffinf_array[0].Buff_length >
3090 (MQLONG)(ParmList->mqcd_adr->MaxMsgLength
3100 + sizeof(MQXQH)))
3110 ? (ParmList->mqcd_adr->MaxMsgLength)
3120 : (MQLONG)(ParmList->tbuflist_adr->
3130 Buffinf_array[0].Buff_length -
3140 sizeof(MQXQH)))
3150 - pMQRMH->StrucLength;
3160 pMsgData = (PMQCHAR)pMQRMH + pMQRMH->StrucLength;
3170 ReadLength = (InputDataLength > 0 &&
3180 InputDataLength < MsgSpace)
3190 ? InputDataLength
3200 : MsgSpace;
3210
3220 /*************************************************/
3230 /* Open the file for reading */
3240 /*************************************************/
3250 fd = fopen(SrcFileName, "rb");
3260
3270 if (fd == NULL)
3280 {
3290 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
3300 goto UOC_EXIT;
3310 }
3320
3330 /*************************************************/
3340 /* Position the file to the specified offset. */
3350 /*************************************************/
3360 rc = fseek(fd, FileDataOffset, SEEK_SET);
3370
3380 if (rc)
3390 {
3400 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
3410 goto UOC_EXIT;
3420 }
3430
3440 /*************************************************/
3450 /* Read the data from the specified offset into */
3460 /* the buffer */
3470 /*************************************************/
3480 bytesread = fread(pMsgData, 1, (size_t)ReadLength, fd);
3490
3500 if (ferror(fd))
3510 {
3520 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
3530 goto UOC_EXIT;
3540 }
3550 else
3560 if (feof(fd) ||
3570 (InputDataLength > 0 &&
3580 InputDataLength == (MQLONG)bytesread))
3590 {
3600 /***********************************************/
3610 /* End of file reached or all the requested */
3620 /* data has been read. */
3630 /* Set MQRMHF_LAST flag. */
3640 /***********************************************/
3650 pMQRMH->Flags |= MQRMHF_LAST;
3660 }
3670 else
3680 {
3690 /***********************************************/
3700 /* May have read last byte of the file (EOF is */
3710 /* only set when attempting to read beyond the */
3720 /* last byte). */
3730 /* Try reading one more byte. */
3740 /***********************************************/
3750
3760 fread(&dummy, 1, 1, fd);
3770
3780 if (ferror(fd))
3790 {
3800 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
3810 goto UOC_EXIT;
3820 }
3830 else
3840 if (feof(fd))
3850 {
3860 /*********************************************/
3870 /* End of file reached before buffer was */
3880 /* filled. Set MQRMHF_LAST flag. */
3890 /*********************************************/
3900 pMQRMH->Flags |= MQRMHF_LAST;
3910 }
3920 else
3930 {
3940 /*********************************************/
3950 /* End of file not reached. */
3960 /*********************************************/
3970 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
3980 goto UOC_EXIT;
3990 }
4000 }
4010
4020 /*************************************************/
4030 /* Set the MQRMH.DataLogicalLength field to the */
4040 /* number of bytes read. */
4050 /* Set DataLength to the increased size of the */
4060 /* message. */
4070 /* The size of the message has increased by the */
4080 /* number of bytes read from the file plus the */
4090 /* difference in the sizes of the input and */
4100 /* converted reference messages. */
4110 /*************************************************/
4120 pMQRMH->DataLogicalLength = bytesread;
4130 ParmList->tbuflist_adr->
4140 Buffinf_array[0].Used_buff_length += bytesread;
4150 break;
4160
4170 /***************************************************/
4180 /* For requester and receiver channels, copy data */
4190 /* from the reference message into the file. */
4200 /* If this is the first part of the file then */
4210 /* (re)create the file first. */
4220 /* If this is the last part of the file then */
4230 /* return the reference message to the caller, */
4240 /* otherwise discard it. */
4250 /***************************************************/
4260 case DCMTCQ_MQCHT_REQUESTER:
4270 case DCMTCQ_MQCHT_RECEIVER:
4280 case DCMTCQ_MQCHT_CLUSRCVR:
4290
4300 /*************************************************/
4310 /* Calculate address of data appended to MQRMH */
4320 /* header. */
4330 /* Calculate length of data to be written to the */
4340 /* file. */
4350 /*************************************************/
4360 pMsgData = (PMQCHAR)(pMQXQH + 1) + pMQRMH->StrucLength;
4370 WriteLength = ParmList->tbuflist_adr->
4380 Buffinf_array[0].Used_buff_length -
4390 sizeof(MQXQH) - pMQRMH->StrucLength;
4400
4410 /*************************************************/
4420 /* If the data offset within the file is zero */
4430 /* then the file is created for writing. If it */
4440 /* already exists, its contents are destroyed. */
4450 /* Otherwise it is opened for appending. */
4460 /*************************************************/
4470 strcpy(mode,
4480 (FileDataOffset == 0) ? "wb" : "ab");
4490
4500 fd = fopen(DestFileName, mode);
4510
4520 if (fd == NULL)
4530 {
4540 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
4550 goto UOC_EXIT;
4560 }
4570
4580 /*************************************************/
4590 /* If the data offset within the file is not */
4600 /* zero, check the current size of the file. */
4610 /* If it matches the data offset, then write the */
4620 /* data to the file. */
4630 /* Otherwise ignore the message. */
4640 /* If the data offset is zero then write the */
4650 /* data to the file. */
4660 /*************************************************/
4670 if (FileDataOffset != 0)
4680 {
4690
4700 rc = fseek(fd, 0, SEEK_END);
4710
4720 if (rc)
4730 {
4740 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
4750 goto UOC_EXIT;
4760 }
4770
4780 position = ftell(fd);
4790
4800 if (position < 0)
4810 {
4820 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
4830 goto UOC_EXIT;
4840 }
4850
4860 if (position > FileDataOffset)
4870 {
4880 /*********************************************/
4890 /* File is bigger than the offset of this */
4900 /* segment. */
4910 /* This can happen during recovery when a */
4920 /* channel terminates half way through a */
4930 /* file transfer. */
4940 /* Our only response is to not write the */
4950 /* data */
4960 /*********************************************/
4970 WriteData = 0;
4980 }
4990
5000 if (position < FileDataOffset)
5010 {
5020 /*********************************************/
5030 /* File is smaller than the offset of this */
5040 /* segment. We must have lost a segment, */
5050 /* alert the user to the error */
5060 /*********************************************/
5070 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
5080 goto UOC_EXIT;
5090 }
5100 }
5110
5120 /*************************************************/
5130 /* Write the data to the specified offset in the */
5140 /* file. */
5150 /* The amount of data to be written is the */
5160 /* length of the message minus the transmission */
5170 /* and reference message headers */
5180 /*************************************************/
5190 if (WriteData && (WriteLength > 0))
5200 {
5210 itemswritten = fwrite(pMsgData, (size_t)WriteLength, 1, fd);
5220
5230 if (!itemswritten)
5240 {
5250 FeedbackCode = MQFB_STOPPED_BY_MSG_EXIT;
5260 goto UOC_EXIT;
5270 }
5280 }
5290
5300 /*************************************************/
5310 /* ExitResponse is left at DCMTCQ_MQXCC_OK which */
5320 /* means that the reference message (minus the */
5330 /* appended data) will be put to the target */
5340 /* queue. */
5350 /*************************************************/
5360 ParmList->tbuflist_adr->
5370 Buffinf_array[0].Used_buff_length =
5380 sizeof(MQXQH) + pMQRMH->StrucLength;
5390 break;
5400
5410 /***************************************************/
5420 /* For other channel types, ignore the message. */
5430 /***************************************************/
5440 default:
5450 goto UOC_EXIT;
5460 }
5470
5480 UOC_EXIT:
5490
5500 /*****************************************************/
5510 /* Close the file if necessary. */
5520 /*****************************************************/
5530 if (fd)
5540 {
5550 fclose(fd);
5560 }
5570
5580 /*****************************************************/
5590 /* If an error has occurred, tell the caller to DLQ */
5600 /* the message. */
5610 /* Set the feedback code to be returned in an */
5620 /* exception report (if requested). */
5630 /*****************************************************/
5640 if (FeedbackCode)
5650 {
5660 ParmList->mqcxp_adr->ExitResponse =
5670 DCMTCQ_MQXCC_SUPPRESS_FUNCTION;
5680 ParmList->mqcxp_adr->Feedback = FeedbackCode;
5690 }
5700
5710 return(0) ;
5720 }
ページの先頭へ