diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs
index de6e31b7da..53cd8f6d17 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs
@@ -11,6 +11,7 @@
*/
using System;
+using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
@@ -171,8 +172,6 @@ namespace Opc.Ua.Bindings
m_sink = sink;
m_socket = null;
- m_socketV4 = null;
- m_socketV6 = null;
m_bufferManager = bufferManager;
m_receiveBufferSize = receiveBufferSize;
m_incomingMessageSize = -1;
@@ -242,7 +241,7 @@ namespace Opc.Ua.Bindings
///
/// Connects to an endpoint.
///
- public async Task BeginConnect(Uri endpointUrl, EventHandler callback, object state)
+ public async Task BeginConnect(Uri endpointUrl, EventHandler callback, object state)
{
if (endpointUrl == null) throw new ArgumentNullException("endpointUrl");
@@ -251,155 +250,89 @@ namespace Opc.Ua.Bindings
throw new InvalidOperationException("The socket is already connected.");
}
- // Get DNS host information.
+ // Get DNS host information
IPAddress[] hostAdresses = await Dns.GetHostAddressesAsync(endpointUrl.DnsSafeHost);
- // try IPv4 and IPv6 address
- IPAddress addressV4 = null;
- IPAddress addressV6 = null;
+ // Get IPv4 and IPv6 address
+ IPAddress addressV4 = hostAdresses.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork);
+ IPAddress addressV6 = hostAdresses.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetworkV6);
- foreach (IPAddress address in hostAdresses)
+ // Get port
+ int port = endpointUrl.Port;
+ if (port <= 0 || port > UInt16.MaxValue)
{
- if (address.AddressFamily == AddressFamily.InterNetworkV6)
- {
- if (addressV6 == null)
- {
- addressV6 = address;
- }
- }
- if (address.AddressFamily == AddressFamily.InterNetwork)
- {
- if (addressV4 == null)
- {
- addressV4 = address;
- }
- }
- if ((addressV4 != null) && (addressV6 != null))
- {
- break;
- }
+ port = Utils.UaTcpDefaultPort;
}
- SocketError error = SocketError.NotInitialized;
- TaskCompletionSource tcs = new TaskCompletionSource();
- TcpMessageSocketAsyncEventArgs argsV4 = null;
- TcpMessageSocketAsyncEventArgs argsV6 = null;
- m_socketResponses = 0;
+ Action doCallback = () => callback(this, new TcpMessageSocketAsyncEventArgs { UserToken = state });
+ if (addressV6 != null)
+ {
+ BeginConnect(addressV6, AddressFamily.InterNetworkV6, port, doCallback);
+ }
+
+ if (addressV4 != null && m_socket == null)
+ {
+ BeginConnect(addressV4, AddressFamily.InterNetwork, port, doCallback);
+ }
+ }
+
+ ///
+ /// Try to connect to endpoint and do callback if connected successfully
+ ///
+ /// Endpoint address
+ /// Endpoint address family
+ /// Endpoint port
+ /// Callback that must be executed if the connection would be established
+ private void BeginConnect(IPAddress address, AddressFamily addressFamily, int port, Action callback)
+ {
+ var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
+ var args = new SocketAsyncEventArgs()
+ {
+ UserToken = callback,
+ RemoteEndPoint = new IPEndPoint(address, port),
+ };
+ args.Completed += new EventHandler(OnSocketConnected);
+
+ var result = !socket.ConnectAsync(args);
+ if (result)
+ {
+ // I/O completed synchronously
+ OnSocketConnected(socket, args);
+ }
+ }
+
+ ///
+ /// Handle socket connection event
+ ///
+ ///
+ ///
+ private void OnSocketConnected(object sender, SocketAsyncEventArgs args)
+ {
lock (m_socketLock)
{
- // ensure a valid port.
- int port = endpointUrl.Port;
-
- if (port <= 0 || port > UInt16.MaxValue)
+ var socket = sender as Socket;
+ if (!m_closed && m_socket == null && args.SocketError == SocketError.Success)
{
- port = Utils.UaTcpDefaultPort;
+ m_socket = socket;
+ ((Action)args.UserToken)();
}
-
- // create sockets if IP address was provided
- if (addressV6 != null)
+ else
{
- argsV6 = new TcpMessageSocketAsyncEventArgs();
- argsV6.UserToken = state;
- m_socketV6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
- argsV6.m_args.RemoteEndPoint = new IPEndPoint(addressV6, port);
- m_socketResponses++;
- argsV6.m_args.Completed += (o, e) =>
+ try
{
- lock (m_socketLock)
+ if (socket.Connected)
{
- m_socketResponses--;
- if (m_socketV6 != null)
- {
- if (m_socket == null &&
- (m_socketResponses == 0 || e.SocketError == SocketError.Success))
- {
- m_socket = m_socketV6;
- tcs.SetResult(e.SocketError);
- }
- else
- {
- m_socketV6.Dispose();
- e.UserToken = null;
- }
- m_socketV6 = null;
- }
- else
- {
- e.UserToken = null;
- }
+ socket.Shutdown(SocketShutdown.Both);
}
- };
- argsV6.Completed += callback;
- }
- if (addressV4 != null)
- {
- argsV4 = new TcpMessageSocketAsyncEventArgs();
- argsV4.UserToken = state;
- m_socketV4 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- argsV4.m_args.RemoteEndPoint = new IPEndPoint(addressV4, port);
- m_socketResponses++;
- argsV4.m_args.Completed += (o, e) =>
- {
- lock (m_socketLock)
- {
- m_socketResponses--;
- if (m_socketV4 != null)
- {
- if (m_socket == null &&
- (m_socketResponses == 0 || e.SocketError == SocketError.Success))
- {
- m_socket = m_socketV4;
- tcs.SetResult(e.SocketError);
- }
- else
- {
- m_socketV4.Dispose();
- e.UserToken = null;
- }
- m_socketV4 = null;
- }
- else
- {
- e.UserToken = null;
- }
- }
- };
- argsV4.Completed += callback;
- }
-
- bool connectV6Sync = true;
- bool connectV4Sync = true;
- if (m_socketV6 != null)
- {
- connectV6Sync = !m_socketV6.ConnectAsync(argsV6.m_args);
- if (connectV6Sync)
- {
- // I/O completed synchronously
- callback(this, argsV6);
- error = argsV6.m_args.SocketError;
}
- }
- if (m_socketV4 != null && error != SocketError.Success)
- {
- connectV4Sync = !m_socketV4.ConnectAsync(argsV4.m_args);
- if (connectV4Sync)
+ finally
{
- // I/O completed synchronously
- callback(this, argsV4);
- error = argsV4.m_args.SocketError;
+ socket.Dispose();
}
}
-
- if (connectV4Sync && connectV6Sync)
- {
- return (error == SocketError.Success) ? true : false;
- }
}
-
- error = await tcs.Task;
-
- return (error == SocketError.Success) ? true : false;
+ args.Dispose();
}
///
@@ -407,48 +340,29 @@ namespace Opc.Ua.Bindings
///
public void Close()
{
- // get the socket.
- Socket socket = null;
- Socket socketV4 = null;
- Socket socketV6 = null;
-
lock (m_socketLock)
{
- socket = m_socket;
- socketV4 = m_socketV4;
- socketV6 = m_socketV6;
- m_socket = null;
- m_socketV6 = null;
- m_socketV4 = null;
- }
+ m_closed = true;
- // shutdown sockets which may still be active
- // due to a timeout during ConnectAsync
- if (socketV4 != null)
- {
- socketV4.Dispose();
- }
-
- if (socketV6 != null)
- {
- socketV6.Dispose();
- }
-
- // shutdown the socket.
- if (socket != null)
- {
- try
+ // Shutdown the socket.
+ if (m_socket != null)
{
- if (socket.Connected)
+ try
{
- socket.Shutdown(SocketShutdown.Both);
+ if (m_socket.Connected)
+ {
+ m_socket.Shutdown(SocketShutdown.Both);
+ }
+ }
+ catch (Exception e)
+ {
+ Utils.Trace(e, "Unexpected error closing socket.");
+ }
+ finally
+ {
+ m_socket.Dispose();
+ m_socket = null;
}
-
- socket.Dispose();
- }
- catch (Exception e)
- {
- Utils.Trace(e, "Unexpected error closing socket.");
}
}
}
@@ -724,15 +638,13 @@ namespace Opc.Ua.Bindings
private object m_socketLock = new object();
private Socket m_socket;
+ private bool m_closed = false;
private object m_readLock = new object();
private byte[] m_receiveBuffer;
private int m_bytesReceived;
private int m_bytesToReceive;
private int m_incomingMessageSize;
- private Socket m_socketV4;
- private Socket m_socketV6;
- private int m_socketResponses;
#endregion
}
}
diff --git a/Stack/Opc.Ua.Core/Stack/Transport/IMessageSocket.cs b/Stack/Opc.Ua.Core/Stack/Transport/IMessageSocket.cs
index 4de9131bff..829c3d61e4 100644
--- a/Stack/Opc.Ua.Core/Stack/Transport/IMessageSocket.cs
+++ b/Stack/Opc.Ua.Core/Stack/Transport/IMessageSocket.cs
@@ -137,7 +137,7 @@ namespace Opc.Ua.Bindings
///
/// Connects to an endpoint.
///
- Task BeginConnect(Uri endpointUrl, EventHandler callback, object state);
+ Task BeginConnect(Uri endpointUrl, EventHandler callback, object state);
///
/// Forcefully closes the socket.