Tag the initial code used for a 1.3.0 vote
diff --git a/nant.build b/nant.build
index b70d6f1..0079624 100644
--- a/nant.build
+++ b/nant.build
@@ -22,7 +22,7 @@
<property name="basedir" value="${project::get-base-directory()}" />
<property name="project.name" value="Apache.NMS.ActiveMQ" />
<property name="project.group" value="org.apache.activemq" />
- <property name="project.version" value="1.3.x" unless="${property::exists('project.version')}" />
+ <property name="project.version" value="1.3.0" unless="${property::exists('project.version')}" />
<property name="project.release.type" value="GA" unless="${property::exists('project.release.type')}" />
<property name="project.short_description" value="Apache NMS for ActiveMQ Class Library" />
<property name="project.description" value="Apache NMS for ActiveMQ Class Library (.Net Messaging Library Implementation): An implementation of the NMS API for ActiveMQ" />
diff --git a/src/main/csharp/Transport/Tcp/TcpTransportFactory.cs b/src/main/csharp/Transport/Tcp/TcpTransportFactory.cs
index 121b725..6ddc56a 100644
--- a/src/main/csharp/Transport/Tcp/TcpTransportFactory.cs
+++ b/src/main/csharp/Transport/Tcp/TcpTransportFactory.cs
@@ -116,9 +116,28 @@
// Set transport. properties on this (the factory)
URISupport.SetProperties(this, map, "transport.");
- Tracer.Debug("Opening socket to: " + location.Host + " on port: " + location.Port);
- Socket socket = Connect(location.Host, location.Port);
-
+ // See if there is a local address and port specified
+ string localAddress = null;
+ int localPort = -1;
+
+ if(!String.IsNullOrEmpty(location.AbsolutePath) && !location.AbsolutePath.Equals("/"))
+ {
+ int index = location.AbsolutePath.IndexOf(':');
+ try
+ {
+ localPort = Int16.Parse(location.AbsolutePath.Substring(index + 1));
+ localAddress = location.AbsolutePath.Substring(1, index - 1);
+ Tracer.DebugFormat("Binding Socket to {0} on port: {1}", localAddress, localPort);
+ }
+ catch
+ {
+ Tracer.Warn("Invalid Port value on URI for local bind option, ignoring.");
+ }
+ }
+
+ Tracer.Debug("Opening socket to: " + location.Host + " on port: " + location.Port);
+ Socket socket = DoConnect(location.Host, location.Port, localAddress, localPort );
+
#if !NETCF
socket.ReceiveBufferSize = ReceiveBufferSize;
socket.SendBufferSize = SendBufferSize;
@@ -220,7 +239,7 @@
return ipEntry;
}
- private Socket ConnectSocket(IPAddress address, int port)
+ private Socket TryConnectSocket(IPAddress address, int port, string localAddress, int localPort)
{
if(null != address)
{
@@ -230,6 +249,11 @@
if(null != socket)
{
+ if(!String.IsNullOrEmpty(localAddress))
+ {
+ DoBind(socket, localAddress, localPort);
+ }
+
socket.Connect(new IPEndPoint(address, port));
if(socket.Connected)
{
@@ -292,7 +316,7 @@
return null;
}
- protected Socket Connect(string host, int port)
+ protected Socket DoConnect(string host, int port, string localAddress, int localPort)
{
Socket socket = null;
IPAddress ipaddress;
@@ -301,7 +325,7 @@
{
if(TryParseIPAddress(host, out ipaddress))
{
- socket = ConnectSocket(ipaddress, port);
+ socket = TryConnectSocket(ipaddress, port, localAddress, localPort);
}
else
{
@@ -313,12 +337,12 @@
{
// Prefer IPv6 first.
ipaddress = GetIPAddress(hostEntry, AddressFamily.InterNetworkV6);
- socket = ConnectSocket(ipaddress, port);
+ socket = TryConnectSocket(ipaddress, port, localAddress, localPort);
if(null == socket)
{
// Try IPv4 next.
ipaddress = GetIPAddress(hostEntry, AddressFamily.InterNetwork);
- socket = ConnectSocket(ipaddress, port);
+ socket = TryConnectSocket(ipaddress, port, localAddress, localPort);
if(null == socket)
{
// Try whatever else there is.
@@ -331,7 +355,7 @@
continue;
}
- socket = ConnectSocket(address, port);
+ socket = TryConnectSocket(ipaddress, port, localAddress, localPort);
if(null != socket)
{
ipaddress = address;
@@ -356,5 +380,86 @@
Tracer.DebugFormat("Connected to {0}:{1} using {2} protocol.", host, port, ipaddress.AddressFamily.ToString());
return socket;
}
+
+ protected void DoBind(Socket socket, string host, int port)
+ {
+ IPAddress ipaddress;
+
+ try
+ {
+ if(TryParseIPAddress(host, out ipaddress))
+ {
+ TryBindSocket(socket, ipaddress, port);
+ }
+ else
+ {
+ // Looping through the AddressList allows different type of connections to be tried
+ // (IPv6, IPv4 and whatever else may be available).
+ IPHostEntry hostEntry = GetIPHostEntry(host);
+
+ if(null != hostEntry)
+ {
+ // Prefer IPv6 first.
+ ipaddress = GetIPAddress(hostEntry, AddressFamily.InterNetworkV6);
+ if(!TryBindSocket(socket, ipaddress, port))
+ {
+ // Try IPv4 next.
+ ipaddress = GetIPAddress(hostEntry, AddressFamily.InterNetwork);
+ if(!TryBindSocket(socket, ipaddress, port))
+ {
+ // Try whatever else there is.
+ foreach(IPAddress address in hostEntry.AddressList)
+ {
+ if(AddressFamily.InterNetworkV6 == address.AddressFamily
+ || AddressFamily.InterNetwork == address.AddressFamily)
+ {
+ // Already tried these protocols.
+ continue;
+ }
+
+ if(TryBindSocket(socket, ipaddress, port))
+ {
+ ipaddress = address;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(!socket.IsBound)
+ {
+ throw new SocketException();
+ }
+ }
+ catch(Exception ex)
+ {
+ throw new NMSConnectionException(String.Format("Error binding to {0}:{1}.", host, port), ex);
+ }
+
+ Tracer.DebugFormat("Bound to {0}:{1} using.", host, port);
+ }
+
+ private bool TryBindSocket(Socket socket, IPAddress address, int port)
+ {
+ if(null != socket && null != address)
+ {
+ try
+ {
+ socket.Bind(new IPEndPoint(address, port));
+ if(socket.IsBound)
+ {
+ return true;
+ }
+ }
+ catch
+ {
+ }
+ }
+
+ return false;
+ }
+
}
}
diff --git a/src/test/csharp/NMSConnectionFactoryTest.cs b/src/test/csharp/NMSConnectionFactoryTest.cs
index 45053c2..4c8c731 100644
--- a/src/test/csharp/NMSConnectionFactoryTest.cs
+++ b/src/test/csharp/NMSConnectionFactoryTest.cs
@@ -36,6 +36,7 @@
[RowTest]
[Row("tcp://${activemqhost}:61616")]
[Row("activemq:tcp://${activemqhost}:61616")]
+ [Row("activemq:tcp://${activemqhost}:61616/0.0.0.0:0")]
[Row("activemq:tcp://${activemqhost}:61616?connection.asyncclose=false")]
[Row("activemq:failover:tcp://${activemqhost}:61616")]
[Row("activemq:failover:(tcp://${activemqhost}:61616)")]
@@ -48,6 +49,8 @@
[Row("activemq:failover:(discovery:(multicast://default))")]
#endif
+ [Row("activemq:tcp://${activemqhost}:61616/InvalidHost:0", ExpectedException = typeof(NMSConnectionException))]
+ [Row("activemq:tcp://${activemqhost}:61616/0.0.0.0:-1", ExpectedException = typeof(NMSConnectionException))]
[Row("tcp://InvalidHost:61616", ExpectedException = typeof(NMSConnectionException))]
[Row("activemq:tcp://InvalidHost:61616", ExpectedException = typeof(NMSConnectionException))]
[Row("activemq:tcp://InvalidHost:61616?connection.asyncclose=false", ExpectedException = typeof(NMSConnectionException))]