Skip to content

Commit a20b130

Browse files
committed
Added MQCD structure for programmatic client connections instead of requiring CCDT
1 parent 5a4979a commit a20b130

File tree

13 files changed

+330
-14
lines changed

13 files changed

+330
-14
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ At this point, you should have a compiled copy of the code in $GOPATH/bin.
103103

104104
## Limitations
105105

106-
Not all of the MQI verbs are available through the ibmmq package. This initial
107-
implementation concentrates on the core API calls needed to put and get messages. Currently unavailable
108-
verbs include:
106+
Not all of the MQI verbs are available through the ibmmq package. This
107+
implementation concentrates on the core API calls needed to put and get messages.
108+
Currently unavailable verbs include:
109109
* MQSET
110110
* All of the message property manipulators
111111
* MQCB
@@ -167,7 +167,13 @@ See the [README](cmd/mq_json/README.md) for more details.
167167

168168
14 Dec 2016
169169
* Minor updates to this README for formatting
170-
* Removed the pointless xxx_CURRENT_LENGTH definitions from cmqc
170+
* Removed xxx_CURRENT_LENGTH definitions from cmqc
171+
172+
10 Jan 2017
173+
* Added support for the MQCD structure to allow programmable client
174+
connectivity, without requiring a CCDT. See the clienttest program
175+
for an example of using it.
176+
* Moved sample programs into subdirectory
171177

172178
## Health Warning
173179

cmd/samples/clienttest/clienttest.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
This is a short sample to show how to connect to a remote
3+
queue manager in a Go program without requiring external
4+
client configuration such as a CCDT. Only the basic
5+
parameters are needed here - channel name and connection information -
6+
along with the queue manager name.
7+
8+
For example, run as
9+
clienttest QMGR1 "SYSTEM.DEF.SVRCONN" "myhost.example.com(1414)"
10+
11+
There is no attempt in this sample to configure security features
12+
such as userid/password or TLS.
13+
14+
If an error occurs, the error is reported.
15+
*/
16+
package main
17+
18+
/*
19+
Copyright (c) IBM Corporation 2017
20+
21+
Licensed under the Apache License, Version 2.0 (the "License");
22+
you may not use this file except in compliance with the License.
23+
You may obtain a copy of the License at
24+
25+
http://www.apache.org/licenses/LICENSE-2.0
26+
27+
Unless required by applicable law or agreed to in writing, software
28+
distributed under the License is distributed on an "AS IS" BASIS,
29+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30+
See the License for the specific
31+
32+
Contributors:
33+
Mark Taylor - Initial Contribution
34+
*/
35+
36+
import (
37+
"fmt"
38+
"ibmmq"
39+
"os"
40+
"time"
41+
)
42+
43+
func main() {
44+
var qMgrName string
45+
var err error
46+
var qMgr ibmmq.MQQueueManager
47+
48+
if len(os.Args) != 4 {
49+
fmt.Println("clienttest <qmgrname> <channelname> <conname>")
50+
fmt.Println(" All parms required")
51+
os.Exit(1)
52+
}
53+
54+
// Which queue manager do we want to connect to
55+
qMgrName = os.Args[1]
56+
57+
// Allocate the MQCNO and MQCD structures needed for the
58+
// MQCONNX call.
59+
cno := ibmmq.NewMQCNO()
60+
cd := ibmmq.NewMQCD()
61+
62+
// Fill in the required fields in the
63+
// MQCD channel definition structure
64+
cd.ChannelName = os.Args[2]
65+
cd.ConnectionName = os.Args[3]
66+
67+
// Reference the CD structure from the CNO
68+
// and indicate that we want to use the client
69+
// connection method.
70+
cno.ClientConn = cd
71+
cno.Options = ibmmq.MQCNO_CLIENT_BINDING
72+
73+
// And connect. Wait a short time before
74+
// disconnecting.
75+
qMgr, mqreturn, err := ibmmq.Connx(qMgrName, cno)
76+
if err == nil {
77+
fmt.Printf("Connection to %s succeeded.\n", qMgrName)
78+
d, _ := time.ParseDuration("10s")
79+
time.Sleep(d)
80+
qMgr.Disc()
81+
} else {
82+
fmt.Printf("Connection to %s failed.\n", qMgrName)
83+
fmt.Println(err)
84+
}
85+
86+
fmt.Println("Done.")
87+
os.Exit((int)(mqreturn.MQCC))
88+
89+
}
File renamed without changes.

ibmmq/mqi.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ package ibmmq
5151
#include <stdlib.h>
5252
#include <string.h>
5353
#include <cmqc.h>
54+
#include <cmqxc.h>
5455
*/
5556
import "C"
5657

ibmmq/mqiMQCD.go

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package ibmmq
2+
3+
/*
4+
Copyright (c) IBM Corporation 2016
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
16+
17+
Contributors:
18+
Mark Taylor - Initial Contribution
19+
*/
20+
21+
/*
22+
23+
#include <stdlib.h>
24+
#include <string.h>
25+
#include <cmqc.h>
26+
#include <cmqxc.h>
27+
28+
*/
29+
import "C"
30+
31+
import (
32+
"unsafe"
33+
)
34+
35+
/*
36+
MQCD is a structure containing the MQ Channel Definition (MQCD)
37+
Only fields relevant to a client connection are included in the
38+
Go version of this structure.
39+
*/
40+
type MQCD struct {
41+
ChannelName string
42+
ConnectionName string
43+
DiscInterval int32
44+
SecurityExit string
45+
SecurityUserData string
46+
MaxMsgLength int32
47+
HeartbeatInterval int32
48+
SSLCipherSpec string
49+
SSLPeerName string
50+
SSLClientAuth int32
51+
KeepAliveInterval int32
52+
SharingConversations int32
53+
PropertyControl int32
54+
ClientChannelWeight int32
55+
ConnectionAffinity int32
56+
DefReconnect int32
57+
CertificateLabel string
58+
}
59+
60+
/*
61+
NewMQCD fills in default values for the MQCD structure, based on the
62+
MQCD_CLIENT_CONN_DEFAULT
63+
*/
64+
func NewMQCD() *MQCD {
65+
66+
cd := new(MQCD)
67+
68+
cd.ChannelName = ""
69+
cd.DiscInterval = 6000
70+
cd.SecurityExit = ""
71+
cd.SecurityUserData = ""
72+
cd.MaxMsgLength = 4194304
73+
cd.ConnectionName = ""
74+
cd.HeartbeatInterval = 1
75+
cd.SSLCipherSpec = ""
76+
cd.SSLPeerName = ""
77+
cd.SSLClientAuth = int32(C.MQSCA_REQUIRED)
78+
cd.KeepAliveInterval = -1
79+
cd.SharingConversations = 10
80+
cd.PropertyControl = int32(C.MQPROP_COMPATIBILITY)
81+
cd.ClientChannelWeight = 0
82+
cd.ConnectionAffinity = int32(C.MQCAFTY_PREFERRED)
83+
cd.DefReconnect = int32(C.MQRCN_NO)
84+
cd.CertificateLabel = ""
85+
86+
return cd
87+
}
88+
89+
/*
90+
It is expected that copyXXtoC and copyXXfromC will be called as
91+
matching pairs.
92+
Most of the fields in the MQCD structure are not relevant for client
93+
channels, but the default settings of such fields may still not be 0
94+
or NULL (they are just ignored). The values here are taken from
95+
MQ_CLIENT_CONN_DEFAULT structure for consistency.
96+
*/
97+
func copyCDtoC(mqcd *C.MQCD, gocd *MQCD) {
98+
99+
setMQIString((*C.char)(&mqcd.ChannelName[0]), gocd.ChannelName, C.MQ_CHANNEL_NAME_LENGTH)
100+
mqcd.Version = C.MQCD_VERSION_11
101+
mqcd.ChannelType = C.MQCHT_CLNTCONN
102+
mqcd.TransportType = C.MQXPT_TCP
103+
setMQIString((*C.char)(&mqcd.Desc[0]), "", C.MQ_CHANNEL_DESC_LENGTH)
104+
setMQIString((*C.char)(&mqcd.QMgrName[0]), "", C.MQ_OBJECT_NAME_LENGTH)
105+
setMQIString((*C.char)(&mqcd.XmitQName[0]), "", C.MQ_OBJECT_NAME_LENGTH)
106+
setMQIString((*C.char)(&mqcd.ShortConnectionName[0]), "", C.MQ_SHORT_CONN_NAME_LENGTH)
107+
setMQIString((*C.char)(&mqcd.MCAName[0]), "", C.MQ_MCA_NAME_LENGTH)
108+
setMQIString((*C.char)(&mqcd.ModeName[0]), "", C.MQ_MODE_NAME_LENGTH)
109+
setMQIString((*C.char)(&mqcd.TpName[0]), "", C.MQ_TP_NAME_LENGTH)
110+
mqcd.BatchSize = 50
111+
mqcd.DiscInterval = 6000
112+
mqcd.ShortRetryCount = 10
113+
mqcd.ShortRetryInterval = 60
114+
mqcd.LongRetryCount = 999999999
115+
mqcd.LongRetryInterval = 1200
116+
setMQIString((*C.char)(&mqcd.SecurityExit[0]), gocd.SecurityExit, C.MQ_EXIT_NAME_LENGTH)
117+
setMQIString((*C.char)(&mqcd.MsgExit[0]), "", C.MQ_EXIT_NAME_LENGTH)
118+
setMQIString((*C.char)(&mqcd.SendExit[0]), "", C.MQ_EXIT_NAME_LENGTH)
119+
setMQIString((*C.char)(&mqcd.ReceiveExit[0]), "", C.MQ_EXIT_NAME_LENGTH)
120+
mqcd.SeqNumberWrap = 999999999
121+
mqcd.MaxMsgLength = C.MQLONG(gocd.MaxMsgLength)
122+
mqcd.PutAuthority = C.MQPA_DEFAULT
123+
mqcd.DataConversion = C.MQCDC_NO_SENDER_CONVERSION
124+
setMQIString((*C.char)(&mqcd.SecurityUserData[0]), gocd.SecurityUserData, C.MQ_EXIT_DATA_LENGTH)
125+
setMQIString((*C.char)(&mqcd.MsgUserData[0]), "", C.MQ_EXIT_DATA_LENGTH)
126+
setMQIString((*C.char)(&mqcd.SendUserData[0]), "", C.MQ_EXIT_DATA_LENGTH)
127+
setMQIString((*C.char)(&mqcd.ReceiveUserData[0]), "", C.MQ_EXIT_DATA_LENGTH)
128+
setMQIString((*C.char)(&mqcd.UserIdentifier[0]), "", C.MQ_USER_ID_LENGTH)
129+
setMQIString((*C.char)(&mqcd.Password[0]), "", C.MQ_PASSWORD_LENGTH)
130+
setMQIString((*C.char)(&mqcd.MCAUserIdentifier[0]), "", C.MQ_USER_ID_LENGTH)
131+
mqcd.MCAType = C.MQMCAT_PROCESS
132+
setMQIString((*C.char)(&mqcd.ConnectionName[0]), gocd.ConnectionName, C.MQ_CONN_NAME_LENGTH)
133+
setMQIString((*C.char)(&mqcd.RemoteUserIdentifier[0]), "", C.MQ_USER_ID_LENGTH)
134+
setMQIString((*C.char)(&mqcd.RemotePassword[0]), "", C.MQ_PASSWORD_LENGTH)
135+
setMQIString((*C.char)(&mqcd.MsgRetryExit[0]), "", C.MQ_EXIT_NAME_LENGTH)
136+
setMQIString((*C.char)(&mqcd.MsgRetryUserData[0]), "", C.MQ_EXIT_DATA_LENGTH)
137+
mqcd.MsgRetryCount = 10
138+
mqcd.MsgRetryInterval = 1000
139+
mqcd.HeartbeatInterval = 1
140+
mqcd.BatchInterval = 0
141+
mqcd.NonPersistentMsgSpeed = C.MQNPMS_FAST
142+
mqcd.StrucLength = C.MQCD_CURRENT_LENGTH
143+
mqcd.ExitNameLength = C.MQ_EXIT_NAME_LENGTH
144+
mqcd.ExitDataLength = C.MQ_EXIT_DATA_LENGTH
145+
mqcd.MsgExitsDefined = 0
146+
mqcd.SendExitsDefined = 0
147+
mqcd.ReceiveExitsDefined = 0
148+
mqcd.MsgExitPtr = C.MQPTR(nil)
149+
mqcd.MsgUserDataPtr = C.MQPTR(nil)
150+
mqcd.SendExitPtr = C.MQPTR(nil)
151+
mqcd.SendUserDataPtr = C.MQPTR(nil)
152+
mqcd.ReceiveExitPtr = C.MQPTR(nil)
153+
mqcd.ReceiveUserDataPtr = C.MQPTR(nil)
154+
mqcd.ClusterPtr = C.MQPTR(nil)
155+
mqcd.ClustersDefined = 0
156+
mqcd.NetworkPriority = 0
157+
mqcd.LongMCAUserIdLength = 0
158+
mqcd.LongRemoteUserIdLength = 0
159+
mqcd.LongMCAUserIdPtr = C.MQPTR(nil)
160+
mqcd.LongRemoteUserIdPtr = C.MQPTR(nil)
161+
C.memset((unsafe.Pointer)(&mqcd.MCASecurityId[0]), 0, C.MQ_SECURITY_ID_LENGTH)
162+
C.memset((unsafe.Pointer)(&mqcd.RemoteSecurityId[0]), 0, C.MQ_SECURITY_ID_LENGTH)
163+
setMQIString((*C.char)(&mqcd.SSLCipherSpec[0]), gocd.SSLCipherSpec, C.MQ_SSL_CIPHER_SPEC_LENGTH)
164+
if gocd.SSLPeerName != "" {
165+
mqcd.SSLPeerNamePtr = C.MQPTR(unsafe.Pointer(C.CString(gocd.SSLPeerName)))
166+
mqcd.SSLPeerNameLength = C.MQLONG(len(gocd.SSLPeerName))
167+
}
168+
mqcd.SSLClientAuth = C.MQLONG(gocd.SSLClientAuth)
169+
mqcd.KeepAliveInterval = C.MQLONG(gocd.KeepAliveInterval)
170+
setMQIString((*C.char)(&mqcd.LocalAddress[0]), "", C.MQ_LOCAL_ADDRESS_LENGTH)
171+
mqcd.BatchHeartbeat = 0
172+
for i := 0; i < 2; i++ {
173+
mqcd.HdrCompList[i] = C.MQCOMPRESS_NOT_AVAILABLE
174+
}
175+
for i := 0; i < 16; i++ {
176+
mqcd.MsgCompList[i] = C.MQCOMPRESS_NOT_AVAILABLE
177+
}
178+
mqcd.CLWLChannelRank = 0
179+
mqcd.CLWLChannelPriority = 0
180+
mqcd.CLWLChannelWeight = 50
181+
mqcd.ChannelMonitoring = C.MQMON_OFF
182+
mqcd.ChannelStatistics = C.MQMON_OFF
183+
mqcd.SharingConversations = C.MQLONG(gocd.SharingConversations)
184+
mqcd.PropertyControl = C.MQLONG(gocd.PropertyControl)
185+
mqcd.MaxInstances = 999999999
186+
mqcd.MaxInstancesPerClient = 999999999
187+
mqcd.ClientChannelWeight = C.MQLONG(gocd.ClientChannelWeight)
188+
mqcd.ConnectionAffinity = C.MQLONG(gocd.ConnectionAffinity)
189+
mqcd.BatchDataLimit = 5000
190+
mqcd.UseDLQ = C.MQUSEDLQ_YES
191+
mqcd.DefReconnect = C.MQLONG(gocd.DefReconnect)
192+
setMQIString((*C.char)(&mqcd.CertificateLabel[0]), gocd.CertificateLabel, C.MQ_CERT_LABEL_LENGTH)
193+
194+
return
195+
}
196+
197+
/*
198+
Most of the parameters in the MQCD are input only.
199+
Just need to clear up anything that was allocated in the copyCDtoC function
200+
*/
201+
func copyCDfromC(mqcd *C.MQCD, gocd *MQCD) {
202+
203+
if mqcd.SSLPeerNamePtr != nil {
204+
C.free(unsafe.Pointer(mqcd.SSLPeerNamePtr))
205+
}
206+
207+
return
208+
}

0 commit comments

Comments
 (0)