Hitachi

OpenTP1 Version 7 OpenTP1 メッセージキューイング機能 TP1/Message Queue 使用の手引


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 }