first commit
This commit is contained in:
560
vendor/github.com/ibm-messaging/mq-golang/ibmmq/mqi.go
generated
vendored
Normal file
560
vendor/github.com/ibm-messaging/mq-golang/ibmmq/mqi.go
generated
vendored
Normal file
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
Package ibmmq provides a wrapper to a subset of the IBM MQ
|
||||
procedural interface (the MQI).
|
||||
|
||||
In this initial implementation not all the MQI verbs are
|
||||
included, but it does have the core operations required to
|
||||
put and get messages and work with topics.
|
||||
|
||||
The verbs are given mixed case names without MQ - Open instead
|
||||
of MQOPEN etc.
|
||||
|
||||
If an MQI call returns MQCC_FAILED or MQCC_WARNING, a custom error
|
||||
type is returned containing the MQCC/MQRC values as
|
||||
a formatted string. Use mqreturn:= err(*ibmmq.MQReturn) to access
|
||||
the particular MQRC or MQCC values.
|
||||
|
||||
The build directives for Windows assume the header and library files have
|
||||
been copied to a temporary location, because the default paths are not
|
||||
acceptable to Go (it does not like spaces or special characters like ~).
|
||||
Note: This problem appears to have been fixed in Go 1.9, and once that
|
||||
is fully available, the directives will be changed to a more reasonable
|
||||
path in this file. For example
|
||||
cgo windows CFLAGS -I"c:/Program Files/IBM/MQ/tools/c/include" -m64
|
||||
|
||||
The build directives for Linux assume the default MQ installation path
|
||||
in /opt/mqm. These would need to be changed in this file if you use a
|
||||
non-default path.
|
||||
*/
|
||||
package ibmmq
|
||||
|
||||
/*
|
||||
Copyright (c) IBM Corporation 2016
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific
|
||||
|
||||
Contributors:
|
||||
Mark Taylor - Initial Contribution
|
||||
*/
|
||||
|
||||
/*
|
||||
#cgo !windows CFLAGS: -I/opt/mqm/inc -D_REENTRANT
|
||||
#cgo windows CFLAGS: -I"C:/Program Files/IBM/MQ/Tools/c/include"
|
||||
#cgo !windows LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath=/opt/mqm/lib64 -Wl,-rpath=/usr/lib64
|
||||
#cgo windows LDFLAGS: -L "C:/Program Files/IBM/MQ/bin64" -lmqm
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cmqc.h>
|
||||
#include <cmqxc.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
This file contains the C wrappers, calling out to structure-specific
|
||||
functions where necessary.
|
||||
|
||||
Define some basic types to hold the
|
||||
references to MQ objects - hconn, hobj - and
|
||||
a simple way to pass the combination of MQCC/MQRC
|
||||
returned from MQI verbs
|
||||
|
||||
The object name is copied into the structures only
|
||||
for convenience. It's not really needed, but
|
||||
it can sometimes be nice to print which queue an hObj
|
||||
refers to during debug.
|
||||
*/
|
||||
|
||||
/*
|
||||
MQQueueManager contains the connection to the queue manager
|
||||
*/
|
||||
type MQQueueManager struct {
|
||||
hConn C.MQHCONN
|
||||
Name string
|
||||
}
|
||||
|
||||
/*
|
||||
MQObject contains a reference to an open object and the associated
|
||||
queue manager
|
||||
*/
|
||||
type MQObject struct {
|
||||
hObj C.MQHOBJ
|
||||
qMgr *MQQueueManager
|
||||
Name string
|
||||
}
|
||||
|
||||
/*
|
||||
MQReturn holds the MQRC and MQCC values returned from an MQI verb. It
|
||||
implements the Error() function so is returned as the specific error
|
||||
from the verbs. See the sample programs for how to access the
|
||||
MQRC/MQCC values in this returned error.
|
||||
*/
|
||||
type MQReturn struct {
|
||||
MQCC int32
|
||||
MQRC int32
|
||||
verb string
|
||||
}
|
||||
|
||||
func (e *MQReturn) Error() string {
|
||||
return mqstrerror(e.verb, C.MQLONG(e.MQCC), C.MQLONG(e.MQRC))
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a Go string into a fixed-size C char array such as MQCHAR12
|
||||
* Once the string has been copied, it can be immediately freed
|
||||
* Empty strings have first char set to 0 in MQI structures
|
||||
*/
|
||||
func setMQIString(a *C.char, v string, l int) {
|
||||
if len(v) > 0 {
|
||||
p := C.CString(v)
|
||||
C.strncpy(a, p, (C.size_t)(l))
|
||||
C.free(unsafe.Pointer(p))
|
||||
} else {
|
||||
*a = 0
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Conn is the function to connect to a queue manager
|
||||
*/
|
||||
func Conn(goQMgrName string) (MQQueueManager, error) {
|
||||
return Connx(goQMgrName, nil)
|
||||
}
|
||||
|
||||
/*
|
||||
Connx is the extended function to connect to a queue manager.
|
||||
*/
|
||||
func Connx(goQMgrName string, gocno *MQCNO) (MQQueueManager, error) {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqcno C.MQCNO
|
||||
|
||||
if (C.MQENC_NATIVE % 2) == 0 { // May be needed for conversion later
|
||||
endian = binary.LittleEndian
|
||||
} else {
|
||||
endian = binary.BigEndian
|
||||
}
|
||||
|
||||
qMgr := MQQueueManager{}
|
||||
mqQMgrName := unsafe.Pointer(C.CString(goQMgrName))
|
||||
defer C.free(mqQMgrName)
|
||||
|
||||
// Set up a default CNO if not provided.
|
||||
if gocno == nil {
|
||||
// Because Go programs are always threaded, and we cannot
|
||||
// tell on which thread we might get dispatched, allow handles always to
|
||||
// be shareable.
|
||||
gocno = NewMQCNO()
|
||||
gocno.Options = MQCNO_HANDLE_SHARE_NO_BLOCK
|
||||
} else {
|
||||
if (gocno.Options & (MQCNO_HANDLE_SHARE_NO_BLOCK |
|
||||
MQCNO_HANDLE_SHARE_BLOCK)) == 0 {
|
||||
gocno.Options |= MQCNO_HANDLE_SHARE_NO_BLOCK
|
||||
}
|
||||
}
|
||||
copyCNOtoC(&mqcno, gocno)
|
||||
|
||||
C.MQCONNX((*C.MQCHAR)(mqQMgrName), &mqcno, &qMgr.hConn, &mqcc, &mqrc)
|
||||
|
||||
if gocno != nil {
|
||||
copyCNOfromC(&mqcno, gocno)
|
||||
}
|
||||
|
||||
mqreturn := &MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQCONNX",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return qMgr, mqreturn
|
||||
}
|
||||
|
||||
qMgr.Name = goQMgrName
|
||||
|
||||
return qMgr, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Disc is the function to disconnect from the queue manager
|
||||
*/
|
||||
func (x *MQQueueManager) Disc() error {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
|
||||
C.MQDISC(&x.hConn, &mqcc, &mqrc)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQDISC",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return &mqreturn
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Open an object such as a queue or topic
|
||||
*/
|
||||
func (x *MQQueueManager) Open(good *MQOD, goOpenOptions int32) (MQObject, error) {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqod C.MQOD
|
||||
var mqOpenOptions C.MQLONG
|
||||
|
||||
object := MQObject{
|
||||
Name: good.ObjectName,
|
||||
qMgr: x,
|
||||
}
|
||||
|
||||
copyODtoC(&mqod, good)
|
||||
mqOpenOptions = C.MQLONG(goOpenOptions)
|
||||
|
||||
C.MQOPEN(x.hConn,
|
||||
(C.PMQVOID)(unsafe.Pointer(&mqod)),
|
||||
mqOpenOptions,
|
||||
&object.hObj,
|
||||
&mqcc,
|
||||
&mqrc)
|
||||
|
||||
copyODfromC(&mqod, good)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQOPEN",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return object, &mqreturn
|
||||
}
|
||||
|
||||
// ObjectName may have changed because it's a model queue
|
||||
object.Name = good.ObjectName
|
||||
|
||||
return object, nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Close the object
|
||||
*/
|
||||
func (object *MQObject) Close(goCloseOptions int32) error {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqCloseOptions C.MQLONG
|
||||
|
||||
mqCloseOptions = C.MQLONG(goCloseOptions)
|
||||
|
||||
C.MQCLOSE(object.qMgr.hConn, &object.hObj, mqCloseOptions, &mqcc, &mqrc)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQCLOSE",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return &mqreturn
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Sub is the function to subscribe to a topic
|
||||
*/
|
||||
func (x *MQQueueManager) Sub(gosd *MQSD, qObject *MQObject) (MQObject, error) {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqsd C.MQSD
|
||||
|
||||
subObject := MQObject{
|
||||
Name: gosd.ObjectName,
|
||||
qMgr: x,
|
||||
}
|
||||
|
||||
copySDtoC(&mqsd, gosd)
|
||||
|
||||
C.MQSUB(x.hConn,
|
||||
(C.PMQVOID)(unsafe.Pointer(&mqsd)),
|
||||
&qObject.hObj,
|
||||
&subObject.hObj,
|
||||
&mqcc,
|
||||
&mqrc)
|
||||
|
||||
copySDfromC(&mqsd, gosd)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQSUB",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return subObject, &mqreturn
|
||||
}
|
||||
|
||||
qObject.qMgr = x // Force the correct hConn for managed objects
|
||||
|
||||
return subObject, nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Cmit is the function to commit an in-flight transaction
|
||||
*/
|
||||
func (x *MQQueueManager) Cmit() error {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
|
||||
C.MQCMIT(x.hConn, &mqcc, &mqrc)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQCMIT",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return &mqreturn
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Back is the function to backout an in-flight transaction
|
||||
*/
|
||||
func (x *MQQueueManager) Back() error {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
|
||||
C.MQBACK(x.hConn, &mqcc, &mqrc)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQBACK",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return &mqreturn
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Put a message to a queue or publish to a topic
|
||||
*/
|
||||
func (object MQObject) Put(gomd *MQMD,
|
||||
gopmo *MQPMO, buffer []byte) error {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqmd C.MQMD
|
||||
var mqpmo C.MQPMO
|
||||
var ptr C.PMQVOID
|
||||
|
||||
bufflen := len(buffer)
|
||||
|
||||
copyMDtoC(&mqmd, gomd)
|
||||
copyPMOtoC(&mqpmo, gopmo)
|
||||
|
||||
if bufflen > 0 {
|
||||
ptr = (C.PMQVOID)(unsafe.Pointer(&buffer[0]))
|
||||
} else {
|
||||
ptr = nil
|
||||
}
|
||||
|
||||
C.MQPUT(object.qMgr.hConn, object.hObj, (C.PMQVOID)(unsafe.Pointer(&mqmd)),
|
||||
(C.PMQVOID)(unsafe.Pointer(&mqpmo)),
|
||||
(C.MQLONG)(bufflen),
|
||||
ptr,
|
||||
&mqcc, &mqrc)
|
||||
|
||||
copyMDfromC(&mqmd, gomd)
|
||||
copyPMOfromC(&mqpmo, gopmo)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQPUT",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return &mqreturn
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Put1 puts a single messsage to a queue or topic. Typically used for one-shot
|
||||
replies where it can be cheaper than multiple Open/Put/Close
|
||||
sequences
|
||||
*/
|
||||
func (x *MQQueueManager) Put1(good *MQOD, gomd *MQMD,
|
||||
gopmo *MQPMO, buffer []byte) error {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqmd C.MQMD
|
||||
var mqpmo C.MQPMO
|
||||
var mqod C.MQOD
|
||||
var ptr C.PMQVOID
|
||||
|
||||
copyODtoC(&mqod, good)
|
||||
copyMDtoC(&mqmd, gomd)
|
||||
copyPMOtoC(&mqpmo, gopmo)
|
||||
|
||||
bufflen := len(buffer)
|
||||
|
||||
if bufflen > 0 {
|
||||
ptr = (C.PMQVOID)(unsafe.Pointer(&buffer[0]))
|
||||
} else {
|
||||
ptr = nil
|
||||
}
|
||||
|
||||
C.MQPUT1(x.hConn, (C.PMQVOID)(unsafe.Pointer(&mqod)),
|
||||
(C.PMQVOID)(unsafe.Pointer(&mqmd)),
|
||||
(C.PMQVOID)(unsafe.Pointer(&mqpmo)),
|
||||
(C.MQLONG)(bufflen),
|
||||
ptr,
|
||||
&mqcc, &mqrc)
|
||||
|
||||
copyODfromC(&mqod, good)
|
||||
copyMDfromC(&mqmd, gomd)
|
||||
copyPMOfromC(&mqpmo, gopmo)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQPUT1",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return &mqreturn
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Get a message from a queue
|
||||
The length of the retrieved message is returned.
|
||||
*/
|
||||
func (object MQObject) Get(gomd *MQMD,
|
||||
gogmo *MQGMO, buffer []byte) (int, error) {
|
||||
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqmd C.MQMD
|
||||
var mqgmo C.MQGMO
|
||||
var datalen C.MQLONG
|
||||
var ptr C.PMQVOID
|
||||
|
||||
bufflen := len(buffer)
|
||||
|
||||
copyMDtoC(&mqmd, gomd)
|
||||
copyGMOtoC(&mqgmo, gogmo)
|
||||
|
||||
if bufflen > 0 {
|
||||
ptr = (C.PMQVOID)(unsafe.Pointer(&buffer[0]))
|
||||
} else {
|
||||
ptr = nil
|
||||
}
|
||||
|
||||
C.MQGET(object.qMgr.hConn, object.hObj, (C.PMQVOID)(unsafe.Pointer(&mqmd)),
|
||||
(C.PMQVOID)(unsafe.Pointer(&mqgmo)),
|
||||
(C.MQLONG)(bufflen),
|
||||
ptr,
|
||||
&datalen,
|
||||
&mqcc, &mqrc)
|
||||
|
||||
godatalen := int(datalen)
|
||||
copyMDfromC(&mqmd, gomd)
|
||||
copyGMOfromC(&mqgmo, gogmo)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQGET",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return 0, &mqreturn
|
||||
}
|
||||
|
||||
return godatalen, nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Inq is the function to inquire on an attribute of an object
|
||||
|
||||
Slices are returned containing the integer attributes, and all the
|
||||
strings concatenated into a single buffer - the caller needs to know
|
||||
how long each field in that buffer will be.
|
||||
|
||||
The caller passes in how many integer selectors are expected to be
|
||||
returned, as well as the maximum length of the char buffer to be returned
|
||||
*/
|
||||
func (object MQObject) Inq(goSelectors []int32, intAttrCount int, charAttrLen int) ([]int32,
|
||||
[]byte, error) {
|
||||
var mqrc C.MQLONG
|
||||
var mqcc C.MQLONG
|
||||
var mqCharAttrs C.PMQCHAR
|
||||
var goCharAttrs []byte
|
||||
var goIntAttrs []int32
|
||||
var ptr C.PMQLONG
|
||||
|
||||
if intAttrCount > 0 {
|
||||
goIntAttrs = make([]int32, intAttrCount)
|
||||
ptr = (C.PMQLONG)(unsafe.Pointer(&goIntAttrs[0]))
|
||||
} else {
|
||||
ptr = nil
|
||||
}
|
||||
if charAttrLen > 0 {
|
||||
mqCharAttrs = (C.PMQCHAR)(C.malloc(C.size_t(charAttrLen)))
|
||||
defer C.free(unsafe.Pointer(mqCharAttrs))
|
||||
} else {
|
||||
mqCharAttrs = nil
|
||||
}
|
||||
|
||||
// Pass in the selectors directly
|
||||
C.MQINQ(object.qMgr.hConn, object.hObj,
|
||||
C.MQLONG(len(goSelectors)),
|
||||
C.PMQLONG(unsafe.Pointer(&goSelectors[0])),
|
||||
C.MQLONG(intAttrCount),
|
||||
ptr,
|
||||
C.MQLONG(charAttrLen),
|
||||
mqCharAttrs,
|
||||
&mqcc, &mqrc)
|
||||
|
||||
mqreturn := MQReturn{MQCC: int32(mqcc),
|
||||
MQRC: int32(mqrc),
|
||||
verb: "MQINQ",
|
||||
}
|
||||
|
||||
if mqcc != C.MQCC_OK {
|
||||
return nil, nil, &mqreturn
|
||||
}
|
||||
|
||||
if charAttrLen > 0 {
|
||||
goCharAttrs = C.GoBytes(unsafe.Pointer(mqCharAttrs), C.int(charAttrLen))
|
||||
}
|
||||
|
||||
return goIntAttrs, goCharAttrs, nil
|
||||
}
|
||||
Reference in New Issue
Block a user