1
votes

I'm tasked with sending a test message to an (as yet) unknown MQ endpoint.

I've stood a trial version of IBM WebSphere MQ (v8.0.0.5) on a server, which I believe is configured correctly.

However, given the code included below I get either the exception:

An unhandled exception of type 'IBM.WMQ.MQException' occurred in amqmdnet.dll

Additional information: 2059

Or if I am on the server itself using localhost instead of the remote server name, the constructor line hangs.

This is C#:

Hashtable connectionProperties = new Hashtable();

string connectionType = MQC.TRANSPORT_MQSERIES_MANAGED
connectionProperties.Add(MQC.TRANSPORT_PROPERTY, connectionType);

// Set up the rest of the connection properties, based on the
// connection type requested
switch (_connectionType)
{
    case MQC.TRANSPORT_MQSERIES_BINDINGS:
        break;
    case MQC.TRANSPORT_MQSERIES_CLIENT:
    case MQC.TRANSPORT_MQSERIES_XACLIENT:
    case MQC.TRANSPORT_MQSERIES_MANAGED:
        connectionProperties.Add(MQC.HOST_NAME_PROPERTY, "server.com");
        connectionProperties.Add(MQC.CHANNEL_PROPERTY, "SYSTEM.DEF.CLNTCONN");      
        break;
}

MQQueueManager qMgr = new MQQueueManager("test", connectionProperties);
MqClientTest mqClientTest=new MqClientTest("TEST_QM","localhost", "SYSTEM.DEF.CLNTCONN");

Is there anything we're missing in this?


Update 1:

In the amqerr01.log file in the errors folder, we now have the text:

AMQ6183: An internal WebSphere MQ error has occurred.

Update 2:

The "internal WebSphere MQ error" was likely due to my probing the 1414 port to see if the port was "up" and listening. Seems it was and it obviously didn't like me doing that.

Update 3:

@Roger suggested I use 127.0.0.1 and capitals, which I've now applied - and changed the example above to reflect.

@JoshMc kindly pointed to a second AMQERR01.LOG file within the Queue Manager folder. I now get the error:

14/11/2017 15:35:08 - Process(336.6) User(xxxx) Program(amqrmppa.exe) Host(xxxx) Installation(xxxx) VRMF(8.0.0.5) QMgr(TEST_QM) AMQ9519: Channel 'SYSTEM.DEF.CLNTCONN' not found.

EXPLANATION: The requested operation failed because the program could not find a definition of channel 'SYSTEM.DEF.CLNTCONN'.

TEST_QM is my Queue Manager, with the default (?) channel SYSTEM.DEF.CLNTCONN

2
Looks like you haven't used the port. If you don't specify the port number then it would take the default port i.e 1414.subbaraoc
Yeah, we should be on 1414 by default as you say. It took the longest time to understand why we weren't listening on 1414 (using netstat -a) then we found a Listener. So, we're now listening to 1414.Program.X
1. What is the channel name you are specifying? If it is a channel that starts with SYSTEM. then the a default CHLAUTH rule will block it. 2. If you are not being blocked by that rule because either you are using a different channel or disabled CHLAUTH, then what user are you connecting with, if it is a user in the mqm group or assuming you are on windows, any user in the windows administrator group, or the MUSR_MQADMIN user, MQ v8 is configured by default to require a password to be specified via CONNAUTH for all Administrative users.JoshMc
Note there are two AMQERR01.LOG files, one that is in the errors directory directly below the MQ install location and one that is under the qmgrs/<qmgr name>/errors directory under the MQ install location, have you looked at the second location?JoshMc
The FDC files would be created in the errors directory under the install directory not the queue manager directory. If the probe simply connects and disconnects, then normally MQ will no longer log anything. if the probe connects and some data that is unexpected is sent to MQ then it will normally produce a FDC file. If you know that it corresponds to the port probing then it is safe to ignore. If it generates too much data there is even a way to tell MQ to disable producing those errors.JoshMc

2 Answers

1
votes

With IBM MQ there are always a pair of channels that work together. For example if one MQ Queue Manager needs to send to message to another queue manager it would normally have a SDR (Sender) channel defined, which would point to a RCVR (Receiver) channel with the same name on the other queue manager.

For a MQ client connection the client application side of the channel is called a MQCD, and the MQ Queue Manager side is a SVRCONN (Server Connection) channel. The client side MQCD can be specified in a few different ways. The way you are demonstrating in the example you posted is programmatically specifying the MQCD information (channel name, hostname, etc).

An alternate way to specify the information is by pointing to a CCDT (Client Channel Definition Table) which is commonly referred to as a Channel Table, this is where a CLNTCONN channel would be used, since you are not using a Channel table I'll move on to why you are getting an error, but at the end of this answer I'll provide more details on Channel Tables.


In summary your application should not be specifying a CLNTCONN channel as the MQC.CHANNEL_PROPERTY it should be pointing to a SVRCONN channel.

Two things to note:

  1. You should not use the predefined SYSTEM.* channels for this purpose (for example SYSTEM.DEF.SVRCONN), you should define a new channel for your application to use. The default channels are meant to hold parameters that you want to be the defaults when creating a new channel of the same type.
  2. MQ v7.1 and later come with a few CHLAUTH rules enabled by default which will block access to the SYSTEM.* channels.

If you want to define a SVRCONN channel using the command line program runmqsc on Windows run the following on a CMD prompt:

echo DEFINE CHL(TEST_QM_CHANNEL1) CHLTYPE(SVRCONN)|runmqsc TEST_QM

Few more details about Channel Tables:

Prior to MQ v8 the only supported method to generate a Channel Table was by defining CLNTCONN channels on a queue manager which creates a file called AMQCLCHL.TAB under the queue manager name folder in a directory called @ipcc. The reason a queue manager comes with a channel called SYSTEM.DEF.CLNTCONNis to provide the default values when you create a new CLNTCONN channel. With v8 and later you can create the channel table using only the runmqsc -n mode, this will directly edit the channel table vs needing to create a CLNTCONN channel on a queue manager. The MQ Client for v8 and later now comes with a client version of runmqsc that can be used to create and alter channel tables.

An application can point to the channel table file in a few different ways, a common way is by setting two environment variables (MQCHLLIB and MQCHLTAB). The app then does not specify channel name, host name, etc in the program, it only needs to specify the name of the queue manager to connect to.

The order and where MQ looks for connection information is documented at the IBM v7.5 (or later) Knowledge Center page "Connecting IBM WebSphere MQ MQI client applications to queue managers". Note this link is for MQI clients, but the same basic order applies to .NET clients as well.

0
votes

localhost

Try using 127.0.0.1 rather than localhost.

"rx" and "swift_test_tx"

Since you are new to MQ, it is time for you to read up on MQ Best Practices. One item is that it is NOT a good idea to use lowercase characters for MQ objects names. i.e. queues, channels, etc... MQ will always fold to uppercase any names that are not in quotes. So, it is just better to uppercase the names to begin with (less problems in the future).

Next, did you open port 1414 in your firewall? If not, then open the port for both TCP & UDP.

Here's an example of a C# program to put a message to a queue in a remote queue manager:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using IBM.WMQ;

/// <summary> Program Name
/// MQTest51
///
/// Description
/// This C# class will connect to a remote queue manager
/// and put a message to a queue under a managed .NET environment.
///
/// Sample Command Line Parameters
/// -h 127.0.0.1 -p 1414 -c TEST.CHL -m MQWT1 -q TEST.Q1
///
/// </summary>
namespace MQTest51
{
   class MQTest51
   {
      private Hashtable inParms = null;
      private Hashtable qMgrProp = null;
      private System.String qManager;
      private System.String outputQName;

      /*
      * The constructor
      */
      public MQTest51()
         : base()
      {
      }

      /// <summary> Make sure the required parameters are present.</summary>
      /// <returns> true/false
      /// </returns>
      private bool allParamsPresent()
      {
         bool b = inParms.ContainsKey("-h") && inParms.ContainsKey("-p") &&
                  inParms.ContainsKey("-c") && inParms.ContainsKey("-m") &&
                  inParms.ContainsKey("-q");
         if (b)
         {
            try
            {
               System.Int32.Parse((System.String)inParms["-p"]);
            }
            catch (System.FormatException e)
            {
               b = false;
            }
         }

         return b;
      }

      /// <summary> Extract the command-line parameters and initialize the MQ variables.</summary>
      /// <param name="args">
      /// </param>
      /// <throws>  IllegalArgumentException </throws>
      private void init(System.String[] args)
      {
         inParms = Hashtable.Synchronized(new Hashtable());
         if (args.Length > 0 && (args.Length % 2) == 0)
         {
            for (int i = 0; i < args.Length; i += 2)
            {
               inParms[args[i]] = args[i + 1];
            }
         }
         else
         {
            throw new System.ArgumentException();
         }

         if (allParamsPresent())
         {
            qManager = ((System.String)inParms["-m"]);
            outputQName = ((System.String)inParms["-q"]);

            qMgrProp = new Hashtable();

            qMgrProp.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);

            qMgrProp.Add(MQC.HOST_NAME_PROPERTY, ((System.String)inParms["-h"]));
            qMgrProp.Add(MQC.CHANNEL_PROPERTY, ((System.String)inParms["-c"]));

            try
            {
               qMgrProp.Add(MQC.PORT_PROPERTY, System.Int32.Parse((System.String)inParms["-p"]));
            }
            catch (System.FormatException e)
            {
               qMgrProp.Add(MQC.PORT_PROPERTY, 1414);
            }

            if (inParms.ContainsKey("-u"))
               qMgrProp.Add(MQC.USER_ID_PROPERTY, ((System.String)inParms["-u"]));

            if (inParms.ContainsKey("-x"))
               qMgrProp.Add(MQC.PASSWORD_PROPERTY, ((System.String)inParms["-x"]));

            if ( (inParms.ContainsKey("-u")) && (inParms.ContainsKey("-x")) )
               qMgrProp.Add(MQC.USE_MQCSP_AUTHENTICATION_PROPERTY, true);
         }
         else
         {
            throw new System.ArgumentException();
         }
      }

      /// <summary> Connect, open queue, write a message, close queue and disconnect.
      ///
      /// </summary>
      /// <throws>  MQException </throws>
      private void testSend()
      {
         System.String line;
         int openOptions = MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING;

         try
         {
            MQQueueManager _qMgr = new MQQueueManager(qManager, qMgrProp);
            System.Console.Out.WriteLine("MQTest51 successfully connected to " + qManager);

            MQQueue queue = _qMgr.AccessQueue(outputQName, openOptions, null, null, null); // no alternate user id
            System.Console.Out.WriteLine("MQTest51 successfully opened " + outputQName);

            MQPutMessageOptions pmo = new MQPutMessageOptions();

            // Define a simple MQ message, and write some text in UTF format..
            MQMessage sendmsg = new MQMessage();
            sendmsg.Format = MQC.MQFMT_STRING;
            sendmsg.Feedback = MQC.MQFB_NONE;
            sendmsg.MessageType = MQC.MQMT_DATAGRAM;

            line = "This is a test message embedded in the MQTest51 program.";

            sendmsg.MessageId = MQC.MQMI_NONE;
            sendmsg.CorrelationId = MQC.MQCI_NONE;
            sendmsg.WriteString(line);

            // put the message on the queue

            queue.Put(sendmsg, pmo);
            System.Console.Out.WriteLine("Message Data>>>" + line);

            queue.Close();
            System.Console.Out.WriteLine("MQTest51 closed: " + outputQName);
            _qMgr.Disconnect();
            System.Console.Out.WriteLine("MQTest51 disconnected from " + qManager);
         }
         catch (MQException mqex)
         {
            System.Console.Out.WriteLine("MQTest51 cc=" + mqex.CompletionCode + " : rc=" + mqex.ReasonCode);
         }
         catch (System.IO.IOException ioex)
         {
            System.Console.Out.WriteLine("MQTest51 ioex=" + ioex);
         }
      }

      /// <summary> main line</summary>
      /// <param name="args">
      /// </param>
      //        [STAThread]
      public static void Main(System.String[] args)
      {
         MQTest51 write = new MQTest51();

         try
         {
            write.init(args);
            write.testSend();
         }
         catch (System.ArgumentException e)
         {
            System.Console.Out.WriteLine("Usage: MQTest51 -h host -p port -c channel -m QueueManagerName -q QueueName [-u userID] [-x passwd]");
            System.Environment.Exit(1);
         }
         catch (MQException e)
         {
            System.Console.Out.WriteLine(e);
            System.Environment.Exit(1);
         }

         System.Environment.Exit(0);
      }
   }
}