Skip to content

Commit a887947

Browse files
committed
Add Dead Letter Header parser
1 parent 5adb005 commit a887947

File tree

7 files changed

+410
-7
lines changed

7 files changed

+410
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Samples updated to use "defer" instead of just suggesting it
66
* Add support for MQCB/MQCTL callback functions
77
* Add support for MQBEGIN transaction management
8+
* Add Dead Letter Header parser
89

910
## November 2018 - v3.2.0
1011
* Added GetPlatform to mqmetric so it can be used as a label/tag in collectors

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ At this point, you should have a compiled copy of the program in `$GOPATH/bin`.
125125

126126
All regular MQI verbs are now available through the `ibmmq` package.
127127

128-
There are no structure handlers for message headers such as MQRFH2 or MQDLH.
129-
130128
## History
131129

132130
See [CHANGELOG](CHANGELOG.md) in this directory.

ibmmq/mqi.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import "C"
5757

5858
import (
5959
"encoding/binary"
60+
"io"
6061
"strings"
6162
"unsafe"
6263
)
@@ -120,6 +121,8 @@ func (e *MQReturn) Error() string {
120121
return mqstrerror(e.verb, C.MQLONG(e.MQCC), C.MQLONG(e.MQRC))
121122
}
122123

124+
var endian binary.ByteOrder // Used by structure formatters such as MQCFH
125+
123126
/*
124127
* Copy a Go string in "strings"
125128
* to a fixed-size C char array such as MQCHAR12
@@ -139,7 +142,7 @@ func setMQIString(a *C.char, v string, l int) {
139142
/*
140143
* The C.GoStringN function can return strings that include
141144
* NUL characters (which is not really what is expected for a C string-related
142-
* function). So we have a utility function to remove any trailing nulls
145+
* function). So we have a utility function to remove any trailing nulls and spaces
143146
*/
144147
func trimStringN(c *C.char, l C.int) string {
145148
var rc string
@@ -150,7 +153,7 @@ func trimStringN(c *C.char, l C.int) string {
150153
} else {
151154
rc = s[0:i]
152155
}
153-
return rc
156+
return strings.TrimSpace(rc)
154157
}
155158

156159
/*
@@ -1261,3 +1264,30 @@ func (handle *MQMessageHandle) InqMP(goimpo *MQIMPO, gopd *MQPD, name string) (s
12611264

12621265
return goimpo.ReturnedName, propertyValue, nil
12631266
}
1267+
1268+
/*
1269+
GetHeader returns a structure containing a parsed-out version of an MQI
1270+
message header such as the MQDLH (which is currently the only structure
1271+
supported). Other structures like the RFH2 could follow.
1272+
1273+
The caller of this function needs to cast the returned structure to the
1274+
specific type in order to reference the fields.
1275+
*/
1276+
func GetHeader(md *MQMD, buf []byte) (interface{}, int, error) {
1277+
switch md.Format {
1278+
case MQFMT_DEAD_LETTER_HEADER:
1279+
return getHeaderDLH(md, buf)
1280+
}
1281+
1282+
mqreturn := &MQReturn{MQCC: int32(MQCC_FAILED),
1283+
MQRC: int32(MQRC_FORMAT_NOT_SUPPORTED),
1284+
}
1285+
1286+
return nil, 0, mqreturn
1287+
}
1288+
1289+
func readStringFromFixedBuffer(r io.Reader, l int32) string {
1290+
tmpBuf := make([]byte, l)
1291+
binary.Read(r, endian, tmpBuf)
1292+
return strings.TrimSpace(string(tmpBuf))
1293+
}

ibmmq/mqiDLH.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package ibmmq
2+
3+
/*
4+
Copyright (c) IBM Corporation 2016,2018
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
Contributors:
19+
Mark Taylor - Initial Contribution
20+
*/
21+
22+
/*
23+
#include <stdlib.h>
24+
#include <cmqc.h>
25+
#include <cmqcfc.h>
26+
*/
27+
import "C"
28+
29+
import (
30+
"bytes"
31+
"encoding/binary"
32+
)
33+
34+
type MQDLH struct {
35+
Reason int32
36+
DestQName string
37+
DestQMgrName string
38+
Encoding int32
39+
CodedCharSetId int32
40+
Format string
41+
PutApplType int32
42+
PutApplName string
43+
PutDate string
44+
PutTime string
45+
strucLength int // Not exported
46+
}
47+
48+
func NewMQDLH(md *MQMD) *MQDLH {
49+
dlh := new(MQDLH)
50+
dlh.Reason = MQRC_NONE
51+
dlh.CodedCharSetId = MQCCSI_UNDEFINED
52+
dlh.PutApplType = 0
53+
dlh.PutApplName = ""
54+
dlh.PutTime = ""
55+
dlh.PutDate = ""
56+
dlh.Format = ""
57+
dlh.DestQName = ""
58+
dlh.DestQMgrName = ""
59+
60+
dlh.strucLength = int(MQDLH_CURRENT_LENGTH)
61+
62+
if md != nil {
63+
dlh.Encoding = md.Encoding
64+
if md.CodedCharSetId == MQCCSI_DEFAULT {
65+
dlh.CodedCharSetId = MQCCSI_INHERIT
66+
} else {
67+
dlh.CodedCharSetId = md.CodedCharSetId
68+
}
69+
dlh.Format = md.Format
70+
71+
md.Format = MQFMT_DEAD_LETTER_HEADER
72+
md.MsgType = MQMT_REPORT
73+
md.CodedCharSetId = MQCCSI_Q_MGR
74+
}
75+
76+
if (C.MQENC_NATIVE % 2) == 0 {
77+
endian = binary.LittleEndian
78+
} else {
79+
endian = binary.BigEndian
80+
}
81+
82+
return dlh
83+
}
84+
85+
func (dlh *MQDLH) Bytes() []byte {
86+
buf := make([]byte, dlh.strucLength)
87+
offset := 0
88+
89+
copy(buf[offset:], "DLH ")
90+
offset += 4
91+
endian.PutUint32(buf[offset:], uint32(MQDLH_CURRENT_VERSION))
92+
offset += 4
93+
endian.PutUint32(buf[offset:], uint32(dlh.Reason))
94+
offset += 4
95+
copy(buf[offset:], dlh.DestQName)
96+
offset += int(MQ_OBJECT_NAME_LENGTH)
97+
copy(buf[offset:], dlh.DestQMgrName)
98+
offset += int(MQ_Q_MGR_NAME_LENGTH)
99+
endian.PutUint32(buf[offset:], uint32(dlh.Encoding))
100+
offset += 4
101+
endian.PutUint32(buf[offset:], uint32(dlh.CodedCharSetId))
102+
offset += 4
103+
copy(buf[offset:], dlh.Format)
104+
offset += int(MQ_FORMAT_LENGTH)
105+
endian.PutUint32(buf[offset:], uint32(dlh.PutApplType))
106+
offset += 4
107+
copy(buf[offset:], dlh.PutApplName)
108+
offset += int(MQ_PUT_APPL_NAME_LENGTH)
109+
copy(buf[offset:], dlh.PutDate)
110+
offset += int(MQ_PUT_DATE_LENGTH)
111+
copy(buf[offset:], dlh.PutTime)
112+
offset += int(MQ_PUT_TIME_LENGTH)
113+
114+
return buf
115+
}
116+
117+
/*
118+
We have a byte array for the message contents. The start of that buffer
119+
is the MQDLH structure. We read the bytes from that fixed header to match
120+
the C structure definition for each field. The DLH does not have multiple
121+
versions defined so we don't need to check that as we go through.
122+
*/
123+
func getHeaderDLH(md *MQMD, buf []byte) (*MQDLH, int, error) {
124+
125+
var version int32
126+
127+
dlh := NewMQDLH(nil)
128+
129+
r := bytes.NewBuffer(buf)
130+
_ = readStringFromFixedBuffer(r, 4) // StrucId
131+
binary.Read(r, endian, &version)
132+
binary.Read(r, endian, &dlh.Reason)
133+
dlh.DestQName = readStringFromFixedBuffer(r, MQ_OBJECT_NAME_LENGTH)
134+
dlh.DestQMgrName = readStringFromFixedBuffer(r, MQ_Q_MGR_NAME_LENGTH)
135+
136+
binary.Read(r, endian, &dlh.Encoding)
137+
binary.Read(r, endian, &dlh.CodedCharSetId)
138+
139+
dlh.Format = readStringFromFixedBuffer(r, MQ_FORMAT_LENGTH)
140+
141+
binary.Read(r, endian, &dlh.PutApplType)
142+
143+
dlh.PutApplName = readStringFromFixedBuffer(r, MQ_PUT_APPL_NAME_LENGTH)
144+
dlh.PutDate = readStringFromFixedBuffer(r, MQ_PUT_DATE_LENGTH)
145+
dlh.PutTime = readStringFromFixedBuffer(r, MQ_PUT_TIME_LENGTH)
146+
147+
return dlh, dlh.strucLength, nil
148+
}

ibmmq/mqiPCF.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ type MQCFH struct {
4747
ParameterCount int32
4848
}
4949

50-
var endian binary.ByteOrder
51-
5250
/*
5351
PCFParameter is a structure containing the data associated with
5452
various types of PCF element. Use the Type field to decide which

mqmetric/discover.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ func formatDescription(elem *MonElement) string {
865865
// we have to ensure uniqueness.
866866
if strings.Contains(elem.Description, "byte count") {
867867
s = s + "_bytes"
868-
} else if strings.HasSuffix(elem.Description," count") && !strings.Contains(s,"_count") {
868+
} else if strings.HasSuffix(elem.Description, " count") && !strings.Contains(s, "_count") {
869869
s = s + "_count"
870870
}
871871
}

0 commit comments

Comments
 (0)