History

GSF.ServiceProcess: In ClientHelper, fixed invalid authentication failures due to a short client-side timeout.

StephenCWills committed 8 years ago

Commit 276a58a1 parent 4a4c6ef6 files · +144 −129Browse files

Unified · Split

6 files
  1. Source/Libraries/GSF.Communication/Payload.cs +8 −4
  2. Source/Libraries/GSF.Communication/TcpClient.cs +14 −0
  3. Source/Libraries/GSF.Communication/TcpServer.cs +12 −17
  4. Source/Libraries/GSF.Communication/TlsClient.cs +28 −0
  5. Source/Libraries/GSF.Communication/TlsServer.cs +73 −94
  6. Source/Libraries/GSF.ServiceProcess/ClientHelper.cs +9 −14
Source/Libraries/GSF.Communication/Payload.cs+8−4
@@ -109,11 +109,15 @@ namespace GSF.Communication · 108 unmodified lines
109 /// <returns>Length of the payload.</returns>109 /// <returns>Length of the payload.</returns>
110 public static int ExtractLength(byte[] buffer, int length, byte[] marker)110 public static int ExtractLength(byte[] buffer, int length, byte[] marker)
111 {111 {
112 // Check to see if buffer is at least as big as the payload header and has the payload marker112 // Check to see if buffer is at least as big as the payload header
113 if (length >= (marker.Length + LengthSegment) && HasHeader(buffer, marker))113 if (length < (marker.Length + LengthSegment))
114 return BitConverter.ToInt32(buffer, marker.Length);114 return -1;
115 115
116 return -1;116 // Check to see if buffer has the payload marker
117 if (!HasHeader(buffer, marker))
118 return 0;
119
120 return BitConverter.ToInt32(buffer, marker.Length);
117 }121 }
118 }122 }
119}123}
Source/Libraries/GSF.Communication/TcpClient.cs+14−0
@@ -167,6 +167,7 @@ namespace GSF.Communication · 166 unmodified lines
167 public int ConnectionAttempts;167 public int ConnectionAttempts;
168 168
169 public CancellationToken Token = new CancellationToken();169 public CancellationToken Token = new CancellationToken();
170 public ICancellationToken TimeoutToken;
170 171
171 public void Dispose()172 public void Dispose()
172 {173 {
@@ -744,6 +745,15 @@ namespace GSF.Communication · 571 unmodified lines
744 // send and receive operations on the socket745 // send and receive operations on the socket
745 connectState.NetworkStream = new NetworkStream(connectState.Socket, false);746 connectState.NetworkStream = new NetworkStream(connectState.Socket, false);
746 connectState.NegotiateStream = new NegotiateStream(connectState.NetworkStream, true);747 connectState.NegotiateStream = new NegotiateStream(connectState.NetworkStream, true);
748
749 connectState.TimeoutToken = new Action(() =>
750 {
751 SocketException ex = new SocketException((int)SocketError.TimedOut);
752 OnConnectionException(ex);
753 TerminateConnection(connectState.Token);
754 connectState.Dispose();
755 }).DelayAndExecute(15000);
756
747 connectState.NegotiateStream.BeginAuthenticateAsClient(m_networkCredential ?? (NetworkCredential)CredentialCache.DefaultCredentials, string.Empty, ProcessIntegratedSecurityAuthentication, connectState);757 connectState.NegotiateStream.BeginAuthenticateAsClient(m_networkCredential ?? (NetworkCredential)CredentialCache.DefaultCredentials, string.Empty, ProcessIntegratedSecurityAuthentication, connectState);
748#endif758#endif
749 }759 }
@@ -875,6 +885,10 @@ namespace GSF.Communication · 125 unmodified lines
875 // Get the connect state from the async result885 // Get the connect state from the async result
876 connectState = (ConnectState)asyncResult.AsyncState;886 connectState = (ConnectState)asyncResult.AsyncState;
877 887
888 // Attempt to cancel the timeout operation
889 if (!connectState.TimeoutToken.Cancel())
890 return;
891
878 // Quit if this connection loop has been cancelled892 // Quit if this connection loop has been cancelled
879 if (connectState.Token.Cancelled)893 if (connectState.Token.Cancelled)
880 return;894 return;
Source/Libraries/GSF.Communication/TcpServer.cs+12−17
@@ -803,6 +803,7 @@ namespace GSF.Communication · 802 unmodified lines
803 TransportProvider<Socket> client = new TransportProvider<Socket>();803 TransportProvider<Socket> client = new TransportProvider<Socket>();
804 SocketAsyncEventArgs receiveArgs = null;804 SocketAsyncEventArgs receiveArgs = null;
805 WindowsPrincipal clientPrincipal = null;805 WindowsPrincipal clientPrincipal = null;
806 IPEndPoint remoteEndPoint = null;
806 TcpClientInfo clientInfo;807 TcpClientInfo clientInfo;
807 808
808 try809 try
@@ -829,6 +830,7 @@ namespace GSF.Communication · 20 unmodified lines
829 // Process the newly connected client.830 // Process the newly connected client.
830 client.Provider = acceptArgs.AcceptSocket;831 client.Provider = acceptArgs.AcceptSocket;
831 client.Provider.ReceiveBufferSize = ReceiveBufferSize;832 client.Provider.ReceiveBufferSize = ReceiveBufferSize;
833 remoteEndPoint = client.Provider.RemoteEndPoint as IPEndPoint;
832 834
833 // Set up SocketAsyncEventArgs for receive operations.835 // Set up SocketAsyncEventArgs for receive operations.
834 receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction();836 receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction();
@@ -838,9 +840,7 @@ namespace GSF.Communication · 3 unmodified lines
838 acceptArgs.AcceptSocket = null;840 acceptArgs.AcceptSocket = null;
839 841
840 if (!m_tcpServer.AcceptAsync(acceptArgs))842 if (!m_tcpServer.AcceptAsync(acceptArgs))
841 {
842 ThreadPool.QueueUserWorkItem(state => ProcessAccept(acceptArgs));843 ThreadPool.QueueUserWorkItem(state => ProcessAccept(acceptArgs));
843 }
844 844
845#if !MONO845#if !MONO
846 // Authenticate the connected client Windows credentials.846 // Authenticate the connected client Windows credentials.
@@ -851,10 +851,15 @@ namespace GSF.Communication · 4 unmodified lines
851 851
852 try852 try
853 {853 {
854 socketStream = new NetworkStream(client.Provider);854 socketStream = new NetworkStream(client.Provider, false);
855 authenticationStream = new NegotiateStream(socketStream);855 authenticationStream = new NegotiateStream(socketStream, true);
856
857 ICancellationToken timeoutToken = new Action(() => client.Provider.Dispose()).DelayAndExecute(15000);
856 authenticationStream.AuthenticateAsServer();858 authenticationStream.AuthenticateAsServer();
857 859
860 if (!timeoutToken.Cancel())
861 throw new SocketException((int)SocketError.TimedOut);
862
858 if (authenticationStream.RemoteIdentity is WindowsIdentity)863 if (authenticationStream.RemoteIdentity is WindowsIdentity)
859 clientPrincipal = new WindowsPrincipal((WindowsIdentity)authenticationStream.RemoteIdentity);864 clientPrincipal = new WindowsPrincipal((WindowsIdentity)authenticationStream.RemoteIdentity);
860 }865 }
@@ -940,22 +945,12 @@ namespace GSF.Communication · 79 unmodified lines
940 catch (Exception ex)945 catch (Exception ex)
941 {946 {
942 // Notify of the exception.947 // Notify of the exception.
943 if ((object)client.Provider != null && (object)client.Provider.RemoteEndPoint != null)948 string clientAddress = remoteEndPoint?.Address.ToString() ?? "UNKNOWN";
944 {949 string errorMessage = $"Unable to accept connection to client [{clientAddress}]: {ex.Message}";
945 string clientAddress = ((IPEndPoint)client.Provider.RemoteEndPoint).Address.ToString();950 OnClientConnectingException(new Exception(errorMessage, ex));
946 string errorMessage = $"Unable to accept connection to client [{clientAddress}]: {ex.Message}";
947 OnClientConnectingException(new Exception(errorMessage, ex));
948 }
949 else
950 {
951 string errorMessage = $"Unable to accept connection to client [unknown]: {ex.Message}";
952 OnClientConnectingException(new Exception(errorMessage, ex));
953 }
954 951
955 if ((object)receiveArgs != null)952 if ((object)receiveArgs != null)
956 {
957 TerminateConnection(client, receiveArgs, false);953 TerminateConnection(client, receiveArgs, false);
958 }
959 }954 }
960 }955 }
961 956
Source/Libraries/GSF.Communication/TlsClient.cs+28−0
@@ -64,6 +64,7 @@ namespace GSF.Communication · 63 unmodified lines
64 public int ConnectionAttempts;64 public int ConnectionAttempts;
65 65
66 public CancellationToken Token = new CancellationToken();66 public CancellationToken Token = new CancellationToken();
67 public ICancellationToken TimeoutToken;
67 68
68 public void Dispose()69 public void Dispose()
69 {70 {
@@ -909,7 +910,17 @@ namespace GSF.Communication · 839 unmodified lines
909 endpoint = Regex.Match(m_connectData["server"], Transport.EndpointFormatRegex);910 endpoint = Regex.Match(m_connectData["server"], Transport.EndpointFormatRegex);
910 911
911 if (!connectState.Token.Cancelled)912 if (!connectState.Token.Cancelled)
913 {
914 connectState.TimeoutToken = new Action(() =>
915 {
916 SocketException ex = new SocketException((int)SocketError.TimedOut);
917 OnConnectionException(ex);
918 TerminateConnection(connectState.Token);
919 connectState.Dispose();
920 }).DelayAndExecute(15000);
921
912 connectState.SslStream.BeginAuthenticateAsClient(endpoint.Groups["host"].Value, m_clientCertificates, m_enabledSslProtocols, m_checkCertificateRevocation, ProcessTlsAuthentication, connectState);922 connectState.SslStream.BeginAuthenticateAsClient(endpoint.Groups["host"].Value, m_clientCertificates, m_enabledSslProtocols, m_checkCertificateRevocation, ProcessTlsAuthentication, connectState);
923 }
913 }924 }
914 catch (SocketException ex)925 catch (SocketException ex)
915 {926 {
@@ -968,6 +979,10 @@ namespace GSF.Communication · 52 unmodified lines
968 // Get the connect state from the async result979 // Get the connect state from the async result
969 connectState = (ConnectState)asyncResult.AsyncState;980 connectState = (ConnectState)asyncResult.AsyncState;
970 981
982 // Attempt to cancel the timeout operation
983 if (!connectState.TimeoutToken.Cancel())
984 return;
985
971 // Quit if this connection loop has been cancelled986 // Quit if this connection loop has been cancelled
972 if (connectState.Token.Cancelled)987 if (connectState.Token.Cancelled)
973 return;988 return;
@@ -995,6 +1010,15 @@ namespace GSF.Communication · 21 unmodified lines
995 1010
996 // Create the NegotiateStream to begin authentication of the user's Windows credentials1011 // Create the NegotiateStream to begin authentication of the user's Windows credentials
997 connectState.NegotiateStream = new NegotiateStream(connectState.SslStream, true);1012 connectState.NegotiateStream = new NegotiateStream(connectState.SslStream, true);
1013
1014 connectState.TimeoutToken = new Action(() =>
1015 {
1016 SocketException ex = new SocketException((int)SocketError.TimedOut);
1017 OnConnectionException(ex);
1018 TerminateConnection(connectState.Token);
1019 connectState.Dispose();
1020 }).DelayAndExecute(15000);
1021
998 connectState.NegotiateStream.BeginAuthenticateAsClient(m_networkCredential ?? (NetworkCredential)CredentialCache.DefaultCredentials, string.Empty, ProcessIntegratedSecurityAuthentication, connectState);1022 connectState.NegotiateStream.BeginAuthenticateAsClient(m_networkCredential ?? (NetworkCredential)CredentialCache.DefaultCredentials, string.Empty, ProcessIntegratedSecurityAuthentication, connectState);
999#endif1023#endif
1000 }1024 }
@@ -1112,6 +1136,10 @@ namespace GSF.Communication · 111 unmodified lines
1112 // Get the connect state from the async result1136 // Get the connect state from the async result
1113 connectState = (ConnectState)asyncResult.AsyncState;1137 connectState = (ConnectState)asyncResult.AsyncState;
1114 1138
1139 // Attempt to cancel the timeout operation
1140 if (!connectState.TimeoutToken.Cancel())
1141 return;
1142
1115 // Quit if this connection loop has been cancelled1143 // Quit if this connection loop has been cancelled
1116 if (connectState.Token.Cancelled)1144 if (connectState.Token.Cancelled)
1117 return;1145 return;
Source/Libraries/GSF.Communication/TlsServer.cs+73−94
@@ -76,6 +76,11 @@ namespace GSF.Communication · 75 unmodified lines
76 /// </summary>76 /// </summary>
77 public SslStream SslStream;77 public SslStream SslStream;
78 78
79 /// <summary>
80 /// The end point of the remote client connecting to this server.
81 /// </summary>
82 public IPEndPoint RemoteEndPoint;
83
79 /// <summary>84 /// <summary>
80 /// Performs application-defined tasks associated with85 /// Performs application-defined tasks associated with
81 /// freeing, releasing, or resetting unmanaged resources.86 /// freeing, releasing, or resetting unmanaged resources.
@@ -93,11 +98,14 @@ namespace GSF.Communication · 11 unmodified lines
93 private class TlsClientInfo98 private class TlsClientInfo
94 {99 {
95 public TransportProvider<TlsSocket> Client;100 public TransportProvider<TlsSocket> Client;
101 public ICancellationToken TimeoutToken;
102
103 public int Sending;
96 public object SendLock;104 public object SendLock;
97 public ConcurrentQueue<TlsServerPayload> SendQueue;105 public ConcurrentQueue<TlsServerPayload> SendQueue;
98 public ShortSynchronizedOperation DumpPayloadsOperation;106 public ShortSynchronizedOperation DumpPayloadsOperation;
99 public int Sending;
100 107
108 public NegotiateStream NegotiateStream;
101 public WindowsPrincipal ClientPrincipal;109 public WindowsPrincipal ClientPrincipal;
102 }110 }
103 111
@@ -995,7 +1003,6 @@ namespace GSF.Communication · 891 unmodified lines
995 private void ProcessAccept(SocketAsyncEventArgs acceptArgs)1003 private void ProcessAccept(SocketAsyncEventArgs acceptArgs)
996 {1004 {
997 TransportProvider<TlsSocket> client = new TransportProvider<TlsSocket>();1005 TransportProvider<TlsSocket> client = new TransportProvider<TlsSocket>();
998 IPEndPoint remoteEndPoint = null;
999 NetworkStream netStream;1006 NetworkStream netStream;
1000 1007
1001 try1008 try
@@ -1025,9 +1032,6 @@ namespace GSF.Communication · 23 unmodified lines
1025 1032
1026 try1033 try
1027 {1034 {
1028 // Get the remote end point in case we need to display useful error messages
1029 remoteEndPoint = acceptArgs.AcceptSocket.RemoteEndPoint as IPEndPoint;
1030
1031 if (MaxClientConnections != -1 && ClientIDs.Length >= MaxClientConnections)1035 if (MaxClientConnections != -1 && ClientIDs.Length >= MaxClientConnections)
1032 {1036 {
1033 // Reject client connection since limit has been reached.1037 // Reject client connection since limit has been reached.
@@ -1042,11 +1046,43 @@ namespace GSF.Communication · 8 unmodified lines
1042 client.Provider = new TlsSocket1046 client.Provider = new TlsSocket
1043 {1047 {
1044 Socket = acceptArgs.AcceptSocket,1048 Socket = acceptArgs.AcceptSocket,
1045 SslStream = new SslStream(netStream, false, m_remoteCertificateValidationCallback ?? CertificateChecker.ValidateRemoteCertificate, m_localCertificateSelectionCallback)1049 SslStream = new SslStream(netStream, false, m_remoteCertificateValidationCallback ?? CertificateChecker.ValidateRemoteCertificate, m_localCertificateSelectionCallback),
1050 RemoteEndPoint = acceptArgs.AcceptSocket.RemoteEndPoint as IPEndPoint
1046 };1051 };
1047 1052
1048 client.Provider.Socket.ReceiveBufferSize = ReceiveBufferSize;1053 client.Provider.Socket.ReceiveBufferSize = ReceiveBufferSize;
1049 client.Provider.SslStream.BeginAuthenticateAsServer(m_certificate, m_requireClientCertificate, m_enabledSslProtocols, m_checkCertificateRevocation, ProcessTlsAuthentication, client);1054
1055 TlsClientInfo clientInfo = new TlsClientInfo
1056 {
1057 Client = client,
1058 SendLock = new object(),
1059 SendQueue = new ConcurrentQueue<TlsServerPayload>()
1060 };
1061
1062 // Create operation to dump send queue payloads when the queue grows too large.
1063 clientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() =>
1064 {
1065 TlsServerPayload payload;
1066
1067 // Check to see if the client has reached the maximum send queue size.
1068 if (m_maxSendQueueSize > 0 && clientInfo.SendQueue.Count >= m_maxSendQueueSize)
1069 {
1070 for (int i = 0; i < m_maxSendQueueSize; i++)
1071 {
1072 if (clientInfo.SendQueue.TryDequeue(out payload))
1073 {
1074 payload.WaitHandle.Set();
1075 payload.WaitHandle.Dispose();
1076 payload.WaitHandle = null;
1077 }
1078 }
1079
1080 throw new InvalidOperationException($"Client {clientInfo.Client.ID} connected to TCP server reached maximum send queue size. {m_maxSendQueueSize} payloads dumped from the queue.");
1081 }
1082 }, ex => OnSendClientDataException(clientInfo.Client.ID, ex));
1083
1084 clientInfo.TimeoutToken = new Action(() => client.Provider.Socket.Dispose()).DelayAndExecute(15000);
1085 client.Provider.SslStream.BeginAuthenticateAsServer(m_certificate, m_requireClientCertificate, m_enabledSslProtocols, m_checkCertificateRevocation, ProcessTlsAuthentication, clientInfo);
1050 }1086 }
1051 }1087 }
1052 finally1088 finally
@@ -1067,13 +1103,10 @@ namespace GSF.Communication · 14 unmodified lines
1067 catch (Exception ex)1103 catch (Exception ex)
1068 {1104 {
1069 // Notify of the exception.1105 // Notify of the exception.
1070 if ((object)remoteEndPoint != null)1106 IPEndPoint remoteEndPoint = client.Provider?.RemoteEndPoint;
1071 {1107 string clientAddress = remoteEndPoint?.Address.ToString() ?? "UNKNOWN";
1072 string clientAddress = remoteEndPoint.Address.ToString();1108 string errorMessage = $"Unable to accept connection to client [{clientAddress}]: {ex.Message}";
1073 string errorMessage = $"Unable to accept connection to client [{clientAddress}]: {ex.Message}";1109 OnClientConnectingException(new Exception(errorMessage, ex));
1074 OnClientConnectingException(new Exception(errorMessage, ex));
1075 }
1076
1077 TerminateConnection(client, false);1110 TerminateConnection(client, false);
1078 }1111 }
1079 }1112 }
@@ -1083,12 +1116,15 @@ namespace GSF.Communication · 3 unmodified lines
1083 /// </summary>1116 /// </summary>
1084 private void ProcessTlsAuthentication(IAsyncResult asyncResult)1117 private void ProcessTlsAuthentication(IAsyncResult asyncResult)
1085 {1118 {
1086 TransportProvider<TlsSocket> client = (TransportProvider<TlsSocket>)asyncResult.AsyncState;1119 TlsClientInfo clientInfo = (TlsClientInfo)asyncResult.AsyncState;
1087 IPEndPoint remoteEndPoint = client.Provider.Socket.RemoteEndPoint as IPEndPoint;1120 TransportProvider<TlsSocket> client = clientInfo.Client;
1088 SslStream stream = client.Provider.SslStream;1121 SslStream stream = client.Provider.SslStream;
1089 1122
1090 try1123 try
1091 {1124 {
1125 if (!clientInfo.TimeoutToken.Cancel())
1126 throw new SocketException((int)SocketError.TimedOut);
1127
1092 stream.EndAuthenticateAsServer(asyncResult);1128 stream.EndAuthenticateAsServer(asyncResult);
1093 1129
1094 if (EnabledSslProtocols != SslProtocols.None)1130 if (EnabledSslProtocols != SslProtocols.None)
@@ -1103,41 +1139,13 @@ namespace GSF.Communication · 8 unmodified lines
1103 if (m_integratedSecurity)1139 if (m_integratedSecurity)
1104 {1140 {
1105#if !MONO1141#if !MONO
1106 NegotiateStream negotiateStream = new NegotiateStream(stream, true);1142 clientInfo.NegotiateStream = new NegotiateStream(stream, true);
1107 negotiateStream.BeginAuthenticateAsServer(ProcessIntegratedSecurityAuthentication, Tuple.Create(client, negotiateStream));1143 clientInfo.TimeoutToken = new Action(() => client.Provider.Socket.Dispose()).DelayAndExecute(15000);
1144 clientInfo.NegotiateStream.BeginAuthenticateAsServer(ProcessIntegratedSecurityAuthentication, clientInfo);
1108#endif1145#endif
1109 }1146 }
1110 else1147 else
1111 {1148 {
1112 TlsClientInfo clientInfo = new TlsClientInfo
1113 {
1114 Client = client,
1115 SendLock = new object(),
1116 SendQueue = new ConcurrentQueue<TlsServerPayload>()
1117 };
1118
1119 // Create operation to dump send queue payloads when the queue grows too large.
1120 clientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() =>
1121 {
1122 TlsServerPayload payload;
1123
1124 // Check to see if the client has reached the maximum send queue size.
1125 if (m_maxSendQueueSize > 0 && clientInfo.SendQueue.Count >= m_maxSendQueueSize)
1126 {
1127 for (int i = 0; i < m_maxSendQueueSize; i++)
1128 {
1129 if (clientInfo.SendQueue.TryDequeue(out payload))
1130 {
1131 payload.WaitHandle.Set();
1132 payload.WaitHandle.Dispose();
1133 payload.WaitHandle = null;
1134 }
1135 }
1136
1137 throw new InvalidOperationException($"Client {clientInfo.Client.ID} connected to TCP server reached maximum send queue size. {m_maxSendQueueSize} payloads dumped from the queue.");
1138 }
1139 }, ex => OnSendClientDataException(clientInfo.Client.ID, ex));
1140
1141 // We can proceed further with receiving data from the client.1149 // We can proceed further with receiving data from the client.
1142 m_clientInfoLookup.TryAdd(client.ID, clientInfo);1150 m_clientInfoLookup.TryAdd(client.ID, clientInfo);
1143 1151
@@ -1148,12 +1156,10 @@ namespace GSF.Communication · 4 unmodified lines
1148 catch (Exception ex)1156 catch (Exception ex)
1149 {1157 {
1150 // Notify of the exception.1158 // Notify of the exception.
1151 if ((object)remoteEndPoint != null)1159 IPEndPoint remoteEndPoint = client.Provider.RemoteEndPoint;
1152 {1160 string clientAddress = remoteEndPoint.Address.ToString();
1153 string clientAddress = remoteEndPoint.Address.ToString();1161 string errorMessage = $"Unable to authenticate connection to client [{clientAddress}]: {CertificateChecker.ReasonForFailure ?? ex.Message}";
1154 string errorMessage = $"Unable to authenticate connection to client [{clientAddress}]: {CertificateChecker.ReasonForFailure ?? ex.Message}";1162 OnClientConnectingException(new Exception(errorMessage, ex));
1155 OnClientConnectingException(new Exception(errorMessage, ex));
1156 }
1157 TerminateConnection(client, false);1163 TerminateConnection(client, false);
1158 }1164 }
1159 }1165 }
@@ -1161,20 +1167,26 @@ namespace GSF.Communication · 1 unmodified line
1161#if !MONO1167#if !MONO
1162 private void ProcessIntegratedSecurityAuthentication(IAsyncResult asyncResult)1168 private void ProcessIntegratedSecurityAuthentication(IAsyncResult asyncResult)
1163 {1169 {
1164 Tuple<TransportProvider<TlsSocket>, NegotiateStream> state = (Tuple<TransportProvider<TlsSocket>, NegotiateStream>)asyncResult.AsyncState;1170 TlsClientInfo clientInfo = (TlsClientInfo)asyncResult.AsyncState;
1165 TransportProvider<TlsSocket> client = state.Item1;1171 TransportProvider<TlsSocket> client = clientInfo.Client;
1166 IPEndPoint remoteEndPoint = client.Provider.Socket.RemoteEndPoint as IPEndPoint;1172 NegotiateStream negotiateStream = clientInfo.NegotiateStream;
1167 NegotiateStream negotiateStream = state.Item2;1173 IPEndPoint remoteEndPoint = client.Provider.RemoteEndPoint;
1168 WindowsPrincipal clientPrincipal = null;1174 WindowsPrincipal clientPrincipal;
1169 1175
1170 try1176 try
1171 {1177 {
1178 if (!clientInfo.TimeoutToken.Cancel())
1179 throw new SocketException((int)SocketError.TimedOut);
1180
1172 try1181 try
1173 {1182 {
1174 negotiateStream.EndAuthenticateAsServer(asyncResult);1183 negotiateStream.EndAuthenticateAsServer(asyncResult);
1175 1184
1176 if (negotiateStream.RemoteIdentity is WindowsIdentity)1185 if (negotiateStream.RemoteIdentity is WindowsIdentity)
1186 {
1177 clientPrincipal = new WindowsPrincipal((WindowsIdentity)negotiateStream.RemoteIdentity);1187 clientPrincipal = new WindowsPrincipal((WindowsIdentity)negotiateStream.RemoteIdentity);
1188 clientInfo.ClientPrincipal = clientPrincipal;
1189 }
1178 }1190 }
1179 catch (InvalidCredentialException)1191 catch (InvalidCredentialException)
1180 {1192 {
@@ -1182,36 +1194,6 @@ namespace GSF.Communication · 1 unmodified line
1182 throw;1194 throw;
1183 }1195 }
1184 1196
1185 TlsClientInfo clientInfo = new TlsClientInfo
1186 {
1187 Client = client,
1188 SendLock = new object(),
1189 SendQueue = new ConcurrentQueue<TlsServerPayload>(),
1190 ClientPrincipal = clientPrincipal
1191 };
1192
1193 // Create operation to dump send queue payloads when the queue grows too large.
1194 clientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() =>
1195 {
1196 TlsServerPayload payload;
1197
1198 // Check to see if the client has reached the maximum send queue size.
1199 if (m_maxSendQueueSize > 0 && clientInfo.SendQueue.Count >= m_maxSendQueueSize)
1200 {
1201 for (int i = 0; i < m_maxSendQueueSize; i++)
1202 {
1203 if (clientInfo.SendQueue.TryDequeue(out payload))
1204 {
1205 payload.WaitHandle.Set();
1206 payload.WaitHandle.Dispose();
1207 payload.WaitHandle = null;
1208 }
1209 }
1210
1211 throw new InvalidOperationException($"Client {clientInfo.Client.ID} connected to TCP server reached maximum send queue size. {m_maxSendQueueSize} payloads dumped from the queue.");
1212 }
1213 }, ex => OnSendClientDataException(clientInfo.Client.ID, ex));
1214
1215 // We can proceed further with receiving data from the client.1197 // We can proceed further with receiving data from the client.
1216 m_clientInfoLookup.TryAdd(client.ID, clientInfo);1198 m_clientInfoLookup.TryAdd(client.ID, clientInfo);
1217 1199
@@ -1221,12 +1203,9 @@ namespace GSF.Communication · 3 unmodified lines
1221 catch (Exception ex)1203 catch (Exception ex)
1222 {1204 {
1223 // Notify of the exception.1205 // Notify of the exception.
1224 if ((object)remoteEndPoint != null)1206 string clientAddress = remoteEndPoint.Address.ToString();
1225 {1207 string errorMessage = $"Unable to authenticate connection to client [{clientAddress}]: {ex.Message}";
1226 string clientAddress = remoteEndPoint.Address.ToString();1208 OnClientConnectingException(new Exception(errorMessage, ex));
1227 string errorMessage = $"Unable to authenticate connection to client [{clientAddress}]: {ex.Message}";
1228 OnClientConnectingException(new Exception(errorMessage, ex));
1229 }
1230 TerminateConnection(client, false);1209 TerminateConnection(client, false);
1231 }1210 }
1232 finally1211 finally
Source/Libraries/GSF.ServiceProcess/ClientHelper.cs+9−14
@@ -540,18 +540,17 @@ namespace GSF.ServiceProcess · 539 unmodified lines
540 /// </summary>540 /// </summary>
541 public void Connect()541 public void Connect()
542 {542 {
543 if ((object)m_remotingClient == null)543 ClientBase remotingClient = m_remotingClient;
544
545 if ((object)remotingClient == null)
544 throw new InvalidOperationException("RemotingClient property of ClientHelper component is not set");546 throw new InvalidOperationException("RemotingClient property of ClientHelper component is not set");
545 547
546 m_authenticationComplete = false;548 m_authenticationComplete = false;
547 549
548 // Wait for connection.550 // Wait for connection.
549 m_remotingClient.Connect();551 remotingClient.Connect();
550
551 const int MaxWaitPeriods = 50; // Will wait a maximum of 5 seconds before assuming failure
552 int attempts = 0;
553 552
554 while (!m_authenticationComplete && m_remotingClient.Enabled && attempts++ < MaxWaitPeriods)553 while (remotingClient.Enabled && !m_authenticationComplete)
555 {554 {
556 // Wait for authentication.555 // Wait for authentication.
557 Thread.Sleep(100);556 Thread.Sleep(100);
@@ -561,14 +560,10 @@ namespace GSF.ServiceProcess · 3 unmodified lines
561 return;560 return;
562 }561 }
563 562
564 // It is possible that local domain account will not be accepted and/or recognized by remote563 if (!m_authenticationComplete)
565 // server when attempting to use integrated security - in these cases the sent client info564 UpdateStatus(UpdateType.Alarm, "Connection was terminated before completing authentication.\r\n\r\n");
566 // message can be rejected so the ServiceHelper will neither respond with success or failure.
567 // We treat this as an authentication failure so that credentials can be requested.
568 if (attempts >= MaxWaitPeriods)
569 OnAuthenticationFailure();
570 565
571 if (m_remotingClient.Enabled)566 if (remotingClient.Enabled)
572 m_attemptReconnection = true;567 m_attemptReconnection = true;
573 }568 }
574 569
@@ -777,7 +772,6 @@ namespace GSF.ServiceProcess · 202 unmodified lines
777 status.Append(m_remotingClient.Status);772 status.Append(m_remotingClient.Status);
778 status.AppendLine();773 status.AppendLine();
779 UpdateStatus(UpdateType.Information, "{0}", status.ToString());774 UpdateStatus(UpdateType.Information, "{0}", status.ToString());
780 SendRequest(StatusMessageFilter);
781 }775 }
782 776
783 private void RemotingClient_ConnectionException(object sender, EventArgs<Exception> e)777 private void RemotingClient_ConnectionException(object sender, EventArgs<Exception> e)
@@ -848,6 +842,7 @@ namespace GSF.ServiceProcess · 64 unmodified lines
848 UpdateStatus(UpdateType.Alarm, "{0}", response.Message);842 UpdateStatus(UpdateType.Alarm, "{0}", response.Message);
849 break;843 break;
850 case "AUTHENTICATIONSUCCESS":844 case "AUTHENTICATIONSUCCESS":
845 SendRequest(StatusMessageFilter);
851 OnAuthenticationSuccess();846 OnAuthenticationSuccess();
852 break;847 break;
853 case "AUTHENTICATIONFAILURE":848 case "AUTHENTICATIONFAILURE":

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t