I have an application that is required to put a very simple message to a remote Queue.
The Queue used is provided by a 3rd party and its an IBM WebSphere MQ (Version 7.5).
I tried to use amqmdnet.dll with the example code below but I understood there should be an MQ Client installed on my server to do this.
So my question:
Is there any way to put a message in a queue without all these requirements? like a simple REST or SOAP client ?
I am open to use different languages to implement such a component i just don't want to install a 3rd party application on the server (its a hosting environment)
// ===========================================================================
// Licensed Materials - Property of IBM
// 5724-H72
// (c) Copyright IBM Corp. 2003, 2005
// ===========================================================================
using System;
using System.Collections;
using IBM.WMQ;
class MQSample
{
// The type of connection to use, this can be:-
// MQC.TRANSPORT_MQSERIES_BINDINGS for a server connection.
// MQC.TRANSPORT_MQSERIES_CLIENT for a non-XA client connection
// MQC.TRANSPORT_MQSERIES_XACLIENT for an XA client connection
// MQC.TRANSPORT_MQSERIES_MANAGED for a managed client connection
const String connectionType = MQC.TRANSPORT_MQSERIES_CLIENT;
// Define the name of the queue manager to use (applies to all connections)
const String qManager = "your_Q_manager";
// Define the name of your host connection (applies to client connections only)
const String hostName = "your_hostname";
// Define the name of the channel to use (applies to client connections only)
const String channel = "your_channelname";
/// <summary>
/// Initialise the connection properties for the connection type requested
/// </summary>
/// <param name="connectionType">One of the MQC.TRANSPORT_MQSERIES_ values</param>
static Hashtable init(String connectionType)
{
Hashtable connectionProperties = new Hashtable();
// Add the connection type
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, hostName);
connectionProperties.Add(MQC.CHANNEL_PROPERTY, channel);
break;
}
return connectionProperties;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static int Main(string[] args)
{
try
{
Hashtable connectionProperties = init(connectionType);
// Create a connection to the queue manager using the connection
// properties just defined
MQQueueManager qMgr = new MQQueueManager(qManager, connectionProperties);
// Set up the options on the queue we want to open
int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT;
// Now specify the queue that we want to open,and the open options
MQQueue system_default_local_queue =
qMgr.AccessQueue("SYSTEM.DEFAULT.LOCAL.QUEUE", openOptions);
// Define a WebSphere MQ message, writing some text in UTF format
MQMessage hello_world = new MQMessage();
hello_world.WriteUTF("Hello World!");
// Specify the message options
MQPutMessageOptions pmo = new MQPutMessageOptions(); // accept the defaults,
// same as MQPMO_DEFAULT
// Put the message on the queue
system_default_local_queue.Put(hello_world, pmo);
// Get the message back again
// First define a WebSphere MQ message buffer to receive the message
MQMessage retrievedMessage =new MQMessage();
retrievedMessage.MessageId =hello_world.MessageId;
// Set the get message options
MQGetMessageOptions gmo =new MQGetMessageOptions(); //accept the defaults
//same as MQGMO_DEFAULT
// Get the message off the queue
system_default_local_queue.Get(retrievedMessage,gmo);
// Prove we have the message by displaying the UTF message text
String msgText = retrievedMessage.ReadUTF();
Console.WriteLine("The message is: {0}", msgText);
// Close the queue
system_default_local_queue.Close();
// Disconnect from the queue manager
qMgr.Disconnect();
}
//If an error has occurred in the above,try to identify what went wrong.
//Was it a WebSphere MQ error?
catch (MQException ex)
{
Console.WriteLine("A WebSphere MQ error occurred: {0}", ex.ToString());
}
catch (System.Exception ex)
{
Console.WriteLine("A System error occurred: {0}", ex.ToString());
}
return 0;
}//end of start
}//end of sample
Instead of picking MQC.TRANSPORT_MQSERIES_CLIENT which would cause the amqmdnet.dll to function in unmanaged mode and rely on other non-.NET dlls, you can select MQC.TRANSPORT_MQSERIES_MANAGED to cause it to function in managed mode which means it does not require any other dlls to function.
At MQ v7.5 even in managed mode you can not use the amqmdnet.dll by itself, at that version IBM did not support this configuration. At IBM MQ v8 and later IBM does support using the amqmdnet.dll by itself. You can download the the MQ v8 or MQ v9 redistributable client from one of the links below. Just find the amqmdnet.dll from the zip file and use it.
MQ is fully backward compatible, it should not be an issue for you to connect to a MQ 7.5 queue manager from a higher version client. Also note that MQ v7.5 goes out of support on April 30th 2018, to keep support from IBM the 3rd party will need to either upgrade or pay extra money for extended support.
IBM MQ v8.0 Client
IBM MQ v9.0 Client
Related
I wrote a console app on .NET, to read without consuming the messages from an IBM MQ queue.
Worked perfect.
Now, I need to migrate that app into .NET Core. Can't figure out why it is extremely slow.
How it works:
target framework .NET Core 3.1
IBMMQDotNetClient NuGet package installed
created a helper class, static, with a static constructor where I initialise MQEnvironment properties like so:
MQEnvironment.CertificateLabel = "ibmwebsphere"; // this is the friendlyname on mmc certificate
MQEnvironment.SSLKeyRepository = "*SYSTEM";
added a method called Init where I initialise connection to MQManager like so:
Hashtable properties = new Hashtable();
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
properties.Add(MQC.HOST_NAME_PROPERTY, hostName); // I read the hostName from a config file
properties.Add(MQC.PORT_PROPERTY, port); // I read the port from a config file
properties.Add(MQC.CHANNEL_PROPERTY, channelName); // I read the channel from a config file
properties.Add(MQC.SSL_CIPHER_SPEC_PROPERTY, cipherSpec); // I read the cipher spec from a config file, it's something like TLS_RSA_WITH_AES_256_CBC_SHA256
Then, I'm going to create a connection to the queue manager using the connection, and read messages one by one until coming to end of the queue.
var queueManager = new MQQueueManager(qm, properties); // I read the qm from a config file
var queue = queueManager.AccessQueue(queueName, MQC.MQOO_BROWSE + MQC.MQOO_FAIL_IF_QUIESCING); // I read the queueName from a config file
var mqGMO = new MQGetMessageOptions();
mqGMO.Options = MQC.MQGMO_FAIL_IF_QUIESCING + MQC.MQGMO_NO_WAIT + MQC.MQGMO_BROWSE_NEXT; mqGMO.MatchOptions = MQC.MQMO_NONE;
try {
while (true) {
MQMessage queueMessage = new MQMessage();
queue.Get(queueMessage, mqGMO); // code gets apparently stuck on this line,
// overprocessing, for many minutes until it gets to the next line,
// even though I mentioned "NO_WAIT" in the options.
// Note this only happens for .NET Core, but not in .NET framework.
var message = queueMessage.ReadString(queueMessage.MessageLength);
string fileName = message.Substring(0,3); // some processing here to extract some info from each message
}
}
catch(MQException ex)
{
if(err.ReasonCode.CompareTo(MQC.MQRC_NO_MSG_AVAILABLE) == 0)
{
// harmless exception to indicate there are no messages on the queue
}
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
Of course it would be preferable to use a listener, not sure how to do that yet, it would be part of optimising, but for now - why is working so slow on line:
queue.Get(queueMessage, mqGMO); // but, again, as mentioned, only with the amqmdnetstd.dll (.NET Core), because if I use amqmdnet.dll (.NET framework), it works super fast, and it's supposed to be the other way around.
I do need to use .NET Standard/Core because I will run this in Linux, currently testing in Windows.
Don't use the MQEnvironment class as it is not threaded safe. Also, don't mix and match between MQEnvironment class and using MQ HashTable. Put your SSL/TLS information as a property in the MQ HashTable.
i.e.
properties.Add(MQC.SSL_PEER_NAME_PROPERTY, "ibmwebsphere");
properties.Add(MQC.SSL_CERT_STORE_PROPERTY, "*SYSTEM");
There isn't enough of your code to test to see why it might be failing.
I wrote and posted a blog item called: IBM MQ For .NET Core Primer. In the blog post, I included a fully functioning C# MQ example (MQTest62L.cs) that was built and run using .NET Core v3.1 and everything worked perfectly (see very bottom of post). Hence, I would suggest you follow my instructions, download, compile and run MQTest62L.cs to see if the issue is your code or MQ Client library.
Note: I was using Windows 10 Pro, IBM MQ v9.2.0.0 and .NET Core v3.1.415.
Below Code is just working fine with IBMMQ 8.0 DLL and server when I switch to 7.5 (both DLL and server) it is giving me this error using same certificate
The SSL key repository cannot be used because MQ cannot obtain a
password to access it. Reasons giving rise to this error include: &B
(a) the key database file and password stash file are not present in
the location configured for the key repository, &B (b) the key
database file exists in the correct place but that no password stash
file has been created for it, &B (c) the files are present in the
correct place but the userid under
public void test() {
Environment.SetEnvironmentVariable("MQCCSID", "437");
MQQueueManager mQQueueManager = null;
MQQueue mQQueue = null;
Hashtable hashTable = null;
try {
hashTable = new Hashtable();
// Setup properties for connection
hashTable.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
hashTable.Add(MQC.HOST_NAME_PROPERTY, "IP");
hashTable.Add(MQC.PORT_PROPERTY, 1414);
hashTable.Add(MQC.CHANNEL_PROPERTY, "Channel");
hashTable.Add(MQC.PASSWORD_PROPERTY, "123");
hashTable.Add(MQC.USER_ID_PROPERTY, "user");
mQQueueManager = new MQQueueManager("QueueName", hashTable);
// Open queue for browsing
mQQueue = mQQueueManager.AccessQueue("que", MQC.MQOO_BROWSE | MQC.MQOO_FAIL_IF_QUIESCING);
ListOfMessages = new List < MQMessageDto > ();
// In a loop browse all messages till we reach end of queue
while (true) {
try {
// Need to create objects everytime
var mQMessage = new MQMessage();
var mQGetMessageOptions = new MQGetMessageOptions {
// Use browse next option to start browsing
Options = MQC.MQGMO_BROWSE_NEXT
};
mQQueue.Get(mQMessage, mQGetMessageOptions);
ListOfMessages.Add(new MQMessageDto() {
Id = ListOfMessages.Count + 1,
Message = Encoding.UTF8.GetString(mQMessage.ReadBytes(mQMessage.MessageLength))
});
} catch (MQException mqex) {
if (ListOfMessages.Count == 0) {
MessageBox.Show("There is no messages in MQ");
}
mQQueue.Close();
break;
}
}
mQQueueManager.Disconnect();
grdMessages.DataSource = ListOfMessages;
grdMessages.Columns["Id"].Width = (int)(grdMessages.Width * 0.1);
grdMessages.Columns["Message"].Width = (int)(grdMessages.Width * 0.8);
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
What are you describing means you have wrong configuration at IBM side, and Since you are using IBM MQ 7.5. I think you got the path for the SSL key repository wrong, it should point to the key name not the folder.
Also make sure that you have selected Optional from SSL tab inside your Channel.
For more details.. More details about this issue can be found here about error this error code:
2538 error on MQ for SSL channel connection
You didn't mention which specific level of 7.5 you are using. If it is 7.5.0.7 or earlier, the stash file will likely be the problem:
https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.mig.doc/q128820_.htm
Older versions of the cryptographic provider used by MQ (GSKit) use a different stash file format for the keystore password.
While newer GSKit versions can handle the old stash file format, the new format is not readable by older GSKit versions. If you are using a level which uses the new format, you can create a backwards-compatible stash file with the -v1stash option:
runmqakm -keydb -stashpw -db <filename> -pw <password> -v1stash
A better alternative, as MQ 7.5 is out of support, would be to use a newer client level, which can still communicate with a 7.5 queue manager if required.
For reference, the first GSKit level which uses the new stash file format is 8.0.50.69. Levels of GSKit bundled with MQ are listed here: https://www.ibm.com/support/pages/levels-jre-and-gskit-bundled-ibm-mq
Regarding:
When I upgraded my client to V9 I'm getting "MQRC_Q_MGR_NOT_AVAILABLE" on client and "4/23/2020 21:03:22 - Process(11764.64) User() Program(amqrmppa.exe) Host(HOST) Installation(Installation1) VRMF(7.5.0.2) QMgr() Remote channel '' did not specify a CipherSpec. Remote channel '' did not specify a CipherSpec when the local channel expected one to be specified. &P The remote host is '...* (...)'. &P The channel did not start. Change the remote channel '' on host ()' to specify a CipherSpec so that both ends of the channel have matching CipherSpecs." in server
display the cipher spec being used dis chl(xxx) SSLCIPH
You may have specified something which is no longer supported by the underlying TLS support.
dis chl(xxx)
I am trying to automatically create an SSH connection for a program that uses an SSH tunnel to update a local database from a remote PostgreSQL server. Up to this time, I have been manually opening a tunnel with PuTTY (including local port forwarding instructions with the -L command). I want to use ssh.net to automatically open the port when the program is run. Once the connection is made, the program uses Entity Framework Core to access the remote database.
When I open the SSH connection with PuTTY, the program runs fine. This is the PuTTY command:
//plink.exe -i "C:\Users\user.name\Desktop\host_private_key.ppk" -L 6544:111.22.33.66:6543 -N user#address.io -pw *PASSWORD*"
(login details removed for privacy)
This is the ssh.net code that I have trying to open the same connection:
public void MakeSSHTunnel()
{
string password = "password";
// path of RSA private key in openSSH format:
string privateKeyPath = "C:/Users/user.name/.ssh/id_rsa";
try
{
// creates variable to transmit RSA private key + passphrase to server via SSH.NET, openSSH compatible.
var privateKeyFile = new PrivateKeyFile(privateKeyPath, password);
string serverAddress = "address.io";
string user = "user";
// allows for the remote port forwarding options required by the server
using (var client = new SshClient(serverAddress, user, privateKeyFile))
{
client.Connect();
var tunnel = new ForwardedPortLocal(6544, "111.22.33.66", 6543);
client.AddForwardedPort(tunnel);
// testing weather the connection has been successful:
if (client.IsConnected)
{
Console.WriteLine("OPENTUNNEL.CS: Connection to {0} successful.", serverAddress);
state = "Open";
}
else
{
Console.WriteLine("Connection to {0} failed.");
state = "Closed";
}
tunnel.Exception += delegate (object sender, ExceptionEventArgs e)
{
Console.WriteLine(e.Exception.ToString());
};
tunnel.Start();
Program.RunBackup();
// ... closes the port ... //
tunnel.Stop();
client.Disconnect();
}
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e);
}
}
I am confused since in the above, the if (client.IsConnected) returns true.
The error seems to be occurring when the Entity Framework Core OnConfiguring() method passes details of the connection with its optionsBuilder:
optionsBuilder.UseNpgsql($"Host=127.0.0.1;Port=6544;Database=user;Username=user;Password=databasePassworh;CommandTimeout=300;Timeout=300;SSL Mode=Require;Trust Server Certificate=true;Convert Infinity DateTime=true");
The errors that are arising are:
NpgsqlException: Exception while connecting
and:
ExtendedSocketException: No connection could be made because the target machine actively refused it. 127.0.0.1:6544
I have double checked all passwords, and read through all the SSH.NET documentation and code examples, and left all the previously working (via PuTTY) code untouched.
If anyone can see what I'm doing wrong, I would be grateful. C#, SSH.NET and port forwarding are new to me, please tell me where I'm being an idiot.
This code is now working. I believe the problem was that in line:
var tunnel = new ForwardedPortLocal(6544, "111.22.33.66", 6543);
the 'bound port' did not include an address. I had seen examples where this was undefined, and had followed these. On stepping through the code, I noticed that the field was blank, and decided to try 127.0.0.1. This is now successfully connecting to the database. It works with:
var tunnel = new ForwardedPortLocal("127.0.0.1", 6544, "111.22.33.66", 6543);
Thanks for looking into this and for your contributions.
I am trying to make a CoAP NON server using CoAPSharp binary in Visual Studio 2015. My target device is Raspberry Pi with Windows IoT core.
"Remotesender" part has the error. I don't know how to solve it
/// <summary>
/// Called when a request is received
/// </summary>
/// <param name="coapReq">The CoAPRequest object</param>
void OnCoAPRequestReceived(CoAPRequest coapReq)
{
//This sample only works on NON requests of type GET
//This sample simualtes a temperature sensor at the path "sensors/temp"
string reqURIPath = (coapReq.GetPath() != null) ? coapReq.GetPath ().ToLower() : "";
/**
* Draft 18 of the specification, section 5.2.3 states, that if against a NON message,
* a response is required, then it must be sent as a NON message
*/
if (coapReq.MessageType.Value != CoAPMessageType.NON)
{
//only NON combination supported..we do not understand this send a RST back
CoAPResponse msgTypeNotSupported = new CoAPResponse (CoAPMessageType.RST, /*Message type*/
CoAPMessageCode.NOT_IMPLEMENTED, /*Not implemented*/
coapReq.ID.Value /*copy message Id*/);
msgTypeNotSupported.Token = coapReq.Token; //Always match the request/response token
msgTypeNotSupported.RemoteSender = coapReq.RemoteSender;
//send response to client
this._coapServer.Send(msgTypeNotSupported);
}
else if (coapReq.Code.Value != CoAPMessageCode.GET)
{
//only GET method supported..we do not understand this send a RST back
CoAPResponse unsupportedCType = new CoAPResponse (CoAPMessageType.RST, /*Message type*/
CoAPMessageCode.METHOD_NOT_ALLOWED, /*Method not allowed*/
coapReq.ID.Value /*copy message Id*/);
unsupportedCType.Token = coapReq.Token; //Always match the request/response token
unsupportedCType.RemoteSender = coapReq.RemoteSender;
//send response to client
this._coapServer.Send(unsupportedCType);
}
else if (reqURIPath != "sensors/temp")
{
//classic 404 not found..we do not understand this send a RST back
CoAPResponse unsupportedPath = new CoAPResponse (CoAPMessageType.RST, /*Message type*/
CoAPMessageCode.NOT_FOUND, /*Not found*/
coapReq.ID.Value /*copy message Id*/);
unsupportedPath.Token = coapReq.Token; //Always match the request/response token
unsupportedPath.RemoteSender = coapReq.RemoteSender;
//send response to client
this._coapServer.Send(unsupportedPath);
}
else
{
//All is well...send the measured temperature back
//Again, this is a NON message...we will send this message as a JSON
//string
Hashtable valuesForJSON = new Hashtable();
valuesForJSON.Add("temp", this.GetRoomTemperature());
string tempAsJSON = JSONResult.ToJSON(valuesForJSON);
//Now prepare the object
CoAPResponse measuredTemp = new CoAPResponse(CoAPMessageType.NON, /*Message type*/
CoAPMessageCode.CONTENT, /*Carries content*/
coapReq.ID.Value/*copy message Id*/);
measuredTemp.Token = coapReq.Token; //Always match the request/response token
//Add the payload
measuredTemp.Payload = new CoAPPayload(tempAsJSON);
//Indicate the content-type of the payload
measuredTemp.AddOption(CoAPHeaderOption.CONTENT_FORMAT,
AbstractByteUtils.GetBytes(CoAPContentFormatOption.APPLICATION_JSON));
//Add remote sender address details
measuredTemp.RemoteSender = coapReq.RemoteSender;
//send response to client
this._coapServer.Send(measuredTemp);
}
}
Error:
error: CS1061 C# does not contain a definition for and no extension method accepting a first argument of type could be found (are you missing a using directive or an assembly reference?)
Simply following the tutorial on CoAPSharp official website.
If you want to run the CoAPSharp library on Raspberry Pi with Windows 10 IoT core, you need to download the experimental release for Windows 10 IoT core. The URL is http://www.coapsharp.com/releases/ . See the last download link.
Also, you may want yo get the source and recompile to get the latest binary to reference in your main project.
Additional information added on 3-Nov-16:
OK, I understood what the problem is. Here is a full and large answer :-)
The CoAPSharp experimental library has a small bug (although unrelated to your problem). I am one of the CoAPSharp developers and work for the company which built the library. The updated library with the fix should be available in a day or two. The issue was with synchronous receive.
The sample you are trying to run, is for NETMF and not for Windows 10 IoT Core and that is why you are getting the errors. There are no samples for the Raspberry Pi experimental release. To help you with the problem, I'm giving below step-by-step solution:
First, download the latest CoAPSharp experimental library to get the fix for synchronous receive bug.
Next, create a solution in which, create one UWA project and add the CoAPSharp library to the solution. Reference the library in the UWA project.
5.1 Create a small server code for Raspberry Pi in this project, as shown below:
/// <summary>
/// We will start a server locally and then connect to it
/// </summary>
private void TestLocalCoAPServer()
{
/*_coapServer variable is a class level variable*/
_coapServer = new CoAPServerChannel();
_coapServer.CoAPRequestReceived += OnCoAPRequestReceived;
_coapServer.Initialize(null, 5683);
}
/// <summary>
/// Gets called everytime a CoAP request is received
/// </summary>
/// <param name="coapReq">The CoAP Request object instance</param>
private async void OnCoAPRequestReceived(CoAPRequest coapReq)
{
//send ACK back
Debug.WriteLine("Received Request::" + coapReq.ToString());
CoAPResponse coapResp = new CoAPResponse(CoAPMessageType.ACK, CoAPMessageCode.CONTENT, coapReq);
coapResp.AddPayload("GOT IT!");
await _coapServer.Send(coapResp);
}
5.2 Next, ensure that port 5683 is not blocked on Raspberry Pi. If yes, then use the powershell to unblock it.
5.3 Next, create a new solution on your desktop(I used Windows 10 and Visual Studio 2015 Community edition) and add another copy of CoAPSharp Raspberry Pi experimental library.
5.3 Now create another UWA project on your desktop . Also, refer the CoAPSharp project in this new project.
5.4 Now write a client in this project that will send/receive CoAP messages from the server hosted on the Raspberry Pi:
private async void TestCoAPAsyncClient()
{
/*_coapAsyncClient is declared at class level*/
this._coapAsyncClient = new CoAPClientChannel();
/*minwinpc was the name of the device running Windows IoT core on Raspberry Pi*/
this._coapAsyncClient.Initialize("minwinpc", 5683);
this._coapAsyncClient.CoAPError += delegate (Exception e, AbstractCoAPMessage associatedMsg) {
Debug.WriteLine("Exception e=" + e.Message);
Debug.WriteLine("Associated Message=" + ((associatedMsg != null) ? associatedMsg.ToString() : "NULL"));
};
this._coapAsyncClient.CoAPRequestReceived += delegate (CoAPRequest coapReq) {
Debug.WriteLine("REQUEST RECEIVED !!!!!!!!!!!!!!" + coapReq.ToString());
};
this._coapAsyncClient.CoAPResponseReceived += delegate (CoAPResponse coapResp) {
Debug.WriteLine("RESPONSE RECEIVED <<<<<<<<<<<<<" + coapResp.ToString());
};
CoAPRequest req = new CoAPRequest(CoAPMessageType.CON, CoAPMessageCode.GET, 100);
//req.SetURL("coap://capi.coapworks.com:5683/v1/time/pcl?mid=CPWK-TESTM");
req.SetURL("coap://localhost:5683/someurl");
await this._coapAsyncClient.Send(req);
}
You can call the method TestCoAPAsyncClient() in a button click or when the page is loaded.
The setup I used was, one desktop with Windows 10 and Visual Studio Community Edition 2015. This was connected to Raspberry Pi running Windows 10 IoT core (OS: 10.0.10240.16384). Both my desktop and the Raspberry Pi were connected to ethernet.
CoAPSharp team added a sample at the link http://www.coapsharp.com/coap-server-windows-10-iot-core-raspberry-pi/ to elaborate this further.
I'm creating an application for Minecraft Classic to send "Heartbeats" to an external website and my application wants to send IPv6 heartbeats rather than IPv4 heartbeats if both IPv6 and IPv4 are present on the system.
Here's what I've tried (through looking through Google search):
Ipv6Element DisableIPv6 = null;
DisableIPv6.enabled = false;
The issue here is that when I add the System.Net.Configuration import, my other portions of code from a .dll won't work anymore because I've attempted to use this method of disabling IPv6.
Here's an example of the .cs file where the heartbeat is sent to the external website (Either Minecraft.net or ClassiCube.net. Since Minecraft.net only supports IPv4 for its Classic servers, the software works fine, but since ClassiCube accepts both 4 and 6, if the machine the server is running has both, it will only take 6, but my software doesn't support IPv6 yet. The .cs file is here. (the Pastebin link expires in 2 weeks)
I've been trying to disable IPv6 if this is the case, but now that I realize that IPv6 will someday replace IPv4, I know I need to support IPv6 now before it is too late
I want to be able to support IPv6 in the application. How can I fix my code to support both IPv4 and 6?
Disclaimer
This code, in fact, is Visual C#, not java. The software has been created in Visual Studio 2013. This program is used to host Minecraft Classic Servers, (Not Premium). Many people don't believe the program was writen in C#, but I'm going to state that now so there is no confusion down the road.
Under the salt initialization:
// Dns lookup, to make sure that IPv4 is preferred for heartbeats
static readonly Dictionary<string, IPAddress> TargetAddresses = new Dictionary<string, IPAddress>();
static DateTime nextDnsLookup = DateTime.MinValue;
static readonly TimeSpan DnsRefreshInterval = TimeSpan.FromMinutes(30);
static IPAddress RefreshTargetAddress([NotNull] Uri requestUri)
{
if (requestUri == null) throw new ArgumentNullException("requestUri");
string hostName = requestUri.Host.ToLowerInvariant();
IPAddress targetAddress;
if (!TargetAddresses.TryGetValue(hostName, out targetAddress) || DateTime.UtcNow >= nextDnsLookup)
{
try
{
// Perform a DNS lookup on given host. Throws SocketException if no host found.
IPAddress[] allAddresses = Dns.GetHostAddresses(requestUri.Host);
// Find a suitable IPv4 address. Throws InvalidOperationException if none found.
targetAddress = allAddresses.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
}
catch (SocketException ex)
{
Logger.Log(LogType.Error,
"Heartbeat.RefreshTargetAddress: Error looking up heartbeat server URLs: {0}",
ex);
}
catch (InvalidOperationException)
{
Logger.Log(LogType.Warning,
"Heartbeat.RefreshTargetAddress: {0} does not have an IPv4 address!", requestUri.Host);
}
TargetAddresses[hostName] = targetAddress;
nextDnsLookup = DateTime.UtcNow + DnsRefreshInterval;
}
return targetAddress;
}
And then, within static HttpWebRequest CreateRequest, under request.UserAgent, insert
if (uri.Scheme == "http")
{
request.Proxy = new WebProxy("http://" + RefreshTargetAddress(uri) + ":" + uri.Port);
}
That should work, I have no way of testing it. Hopefully you or someone else has ipv6 so they can test. All of this code was basically taken from fCraft by the way, all credit to them. http://www.fcraft.net