private void CloseConnection(string outputConnectorAddress, TClientContext clientContext) { using (EneterTrace.Entering()) { try { object anEncodedMessage = myProtocolFormatter.EncodeCloseConnectionMessage(outputConnectorAddress); if (anEncodedMessage != null) { clientContext.SendResponseMessage(anEncodedMessage); } } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.FailedToCloseConnection, err); } clientContext.CloseConnection(); } }
private void ForwardMessageToService(string clientResponseReceiverId, MessageBusMessage messageFromClient) { using (EneterTrace.Entering()) { TClientContext aClientContext = null; using (ThreadLock.Lock(myConnectionLock)) { aClientContext = myConnectedClients.FirstOrDefault(x => x.ClientResponseReceiverId == clientResponseReceiverId); } if (aClientContext != null) { // Forward the incoming message to the service. IDuplexInputChannel anInputChannel = myServiceConnector.AttachedDuplexInputChannel; if (anInputChannel != null) { aClientContext.ForwardToServiceThreadDispatcher.Invoke( () => { using (EneterTrace.Entering()) { try { // Add the client id into the message. // Note: Because of security reasons we do not expect Ids from the client but using Ids associated with the connection session. // Otherwise it would be possible that some client could use id of another client to pretend a different client. messageFromClient.Id = clientResponseReceiverId; object aSerializedMessage = mySerializer.Serialize <MessageBusMessage>(messageFromClient); anInputChannel.SendResponseMessage(aClientContext.ServiceResponseReceiverId, aSerializedMessage); if (MessageToServiceSent != null) { MessageBusMessageEventArgs anEventArgs = new MessageBusMessageEventArgs(aClientContext.ServiceId, aClientContext.ServiceResponseReceiverId, clientResponseReceiverId, messageFromClient.MessageData); try { MessageToServiceSent(this, anEventArgs); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } } catch (Exception err) { string anErrorMessage = TracedObject + "failed to send message to the service '" + aClientContext.ServiceId + "'."; EneterTrace.Error(anErrorMessage, err); UnregisterService(aClientContext.ServiceResponseReceiverId); } } }); } } else { string anErrorMessage = TracedObject + "failed to send message to the service because the client was not found."; EneterTrace.Warning(anErrorMessage); } } }
private void UnregisterClient(string clientResponseReceiverId, bool sendCloseConnectionToServiceFlag, bool disconnectClientFlag) { using (EneterTrace.Entering()) { // Unregistering client. TClientContext aClientContext = null; using (ThreadLock.Lock(myConnectionLock)) { myConnectedClients.RemoveWhere(x => { if (x.ClientResponseReceiverId == clientResponseReceiverId) { aClientContext = x; return(true); } return(false); }); } if (aClientContext != null) { if (sendCloseConnectionToServiceFlag) { try { // Send close connection message to the service. MessageBusMessage aMessage = new MessageBusMessage(EMessageBusRequest.DisconnectClient, aClientContext.ClientResponseReceiverId, null); object aSerializedMessage = mySerializer.Serialize <MessageBusMessage>(aMessage); IDuplexInputChannel anInputChannel = myServiceConnector.AttachedDuplexInputChannel; if (anInputChannel != null) { anInputChannel.SendResponseMessage(aClientContext.ServiceResponseReceiverId, aSerializedMessage); } } catch (Exception err) { string anErrorMessage = TracedObject + ErrorHandler.FailedToCloseConnection; EneterTrace.Warning(anErrorMessage, err); } } // Disconnecting the client. if (disconnectClientFlag) { IDuplexInputChannel anInputChannel1 = myClientConnector.AttachedDuplexInputChannel; if (anInputChannel1 != null) { anInputChannel1.DisconnectResponseReceiver(aClientContext.ClientResponseReceiverId); } } if (ClientDisconnected != null) { MessageBusClientEventArgs anEventArgs = new MessageBusClientEventArgs(aClientContext.ServiceId, aClientContext.ServiceResponseReceiverId, clientResponseReceiverId); try { ClientDisconnected(this, anEventArgs); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } } } }
private void RegisterClient(string clientResponseReceiverId, string serviceId) { using (EneterTrace.Entering()) { bool anIsNewClientConnected = false; TClientContext aClientContext = null; using (ThreadLock.Lock(myConnectionLock)) { aClientContext = myConnectedClients.FirstOrDefault(x => x.ClientResponseReceiverId == clientResponseReceiverId); // If such client does not exist yet then create it. if (aClientContext == null) { TServiceContext aServiceContext = myConnectedServices.FirstOrDefault(x => x.ServiceId == serviceId); // If requested service exists. if (aServiceContext != null) { aClientContext = new TClientContext(clientResponseReceiverId, serviceId, aServiceContext.ServiceResponseReceiverId); myConnectedClients.Add(aClientContext); anIsNewClientConnected = true; } } } if (anIsNewClientConnected) { // Send open connection message to the service. try { MessageBusMessage aMessage = new MessageBusMessage(EMessageBusRequest.ConnectClient, clientResponseReceiverId, null); object aSerializedMessage = mySerializer.Serialize <MessageBusMessage>(aMessage); IDuplexInputChannel anInputChannel = myServiceConnector.AttachedDuplexInputChannel; if (anInputChannel != null) { anInputChannel.SendResponseMessage(aClientContext.ServiceResponseReceiverId, aSerializedMessage); } } catch (Exception err) { EneterTrace.Warning(TracedObject + "failed to send open connection message to the service '" + aClientContext.ServiceId + "'.", err); // Note: The service should not be disconnected from the message bus when not available. // Because it can be "just" overloaded. So only this new client will be disconnected from the message bus. UnregisterClient(clientResponseReceiverId, false, true); } } else { if (aClientContext != null) { EneterTrace.Warning(TracedObject + "failed to connect the client already exists. The connection will be closed."); UnregisterClient(clientResponseReceiverId, false, true); } else { EneterTrace.Warning(TracedObject + "failed to connec the client because the service '" + serviceId + "' does not exist. The connection will be closed."); UnregisterClient(clientResponseReceiverId, false, true); } } } }
private void HandleConnection(TcpClient tcpClient) { using (EneterTrace.Entering()) { IPEndPoint anEndPoint = tcpClient.Client.RemoteEndPoint as IPEndPoint; string aClientIp = (anEndPoint != null) ? anEndPoint.ToString() : ""; Stream anInputOutputStream = null; TClientContext aClientContext = null; string aClientId = null; try { tcpClient.SendTimeout = mySendTimeout; tcpClient.ReceiveTimeout = myReceiveTimeout; tcpClient.SendBufferSize = mySendBuffer; tcpClient.ReceiveBufferSize = myReceiveBuffer; // If the security communication is required, then wrap the network stream into the security stream. anInputOutputStream = mySecurityStreamFactory.CreateSecurityStreamAndAuthenticate(tcpClient.GetStream()); aClientContext = new TClientContext(anInputOutputStream, aClientIp); // If current protocol formatter does not support OpenConnection message // then open the connection now. if (!myProtocolUsesOpenConnectionMessage) { // Generate client id. aClientId = Guid.NewGuid().ToString(); using (ThreadLock.Lock(myConnectedClients)) { myConnectedClients[aClientId] = aClientContext; } ProtocolMessage anOpenConnectionProtocolMessage = new ProtocolMessage(EProtocolMessageType.OpenConnectionRequest, aClientId, null); MessageContext aMessageContext = new MessageContext(anOpenConnectionProtocolMessage, aClientIp); NotifyMessageContext(aMessageContext); } // While the stop of listening is not requested and the connection is not closed. while (true) { ProtocolMessage aProtocolMessage = myProtocolFormatter.DecodeMessage((Stream)anInputOutputStream); // If the stream was not closed. if (aProtocolMessage != null) { // Note: Due to security reasons ignore close connection message in TCP. // So that it is not possible that somebody will just send a close message which will have id of somebody else. // The TCP connection will be closed when the client closes the socket. if (aProtocolMessage.MessageType != EProtocolMessageType.CloseConnectionRequest) { MessageContext aMessageContext = new MessageContext(aProtocolMessage, aClientIp); // If open connection message is received and the current protocol formatter uses open connection message // then create the connection now. if (aProtocolMessage.MessageType == EProtocolMessageType.OpenConnectionRequest && myProtocolUsesOpenConnectionMessage) { // Note: if client id is already set then it means this client has already open connection. if (string.IsNullOrEmpty(aClientId)) { aClientId = !string.IsNullOrEmpty(aProtocolMessage.ResponseReceiverId) ? aProtocolMessage.ResponseReceiverId : Guid.NewGuid().ToString(); using (ThreadLock.Lock(myConnectedClients)) { if (!myConnectedClients.ContainsKey(aClientId)) { myConnectedClients[aClientId] = aClientContext; } else { // Note: if the client id already exists then the connection cannot be open // and the connection with this client will be closed. EneterTrace.Warning(TracedObject + "could not open connection for client '" + aClientId + "' because the client with same id is already connected."); break; } } } else { EneterTrace.Warning(TracedObject + "the client '" + aClientId + "' has already open connection."); } } // Ensure that nobody will try to use id of somebody else. aMessageContext.ProtocolMessage.ResponseReceiverId = aClientId; NotifyMessageContext(aMessageContext); } } else { break; } } } finally { // Remove client from connected clients. if (aClientId != null) { using (ThreadLock.Lock(myConnectedClients)) { myConnectedClients.Remove(aClientId); } } // If the disconnection comes from the client (and not from the service). if (aClientContext != null && !aClientContext.IsClosedByService) { ProtocolMessage aCloseProtocolMessage = new ProtocolMessage(EProtocolMessageType.CloseConnectionRequest, aClientId, null); MessageContext aMessageContext = new MessageContext(aCloseProtocolMessage, aClientIp); // Notify duplex input channel about the disconnection. NotifyMessageContext(aMessageContext); } if (anInputOutputStream != null) { anInputOutputStream.Close(); } } } }
private void OnRequestMessageReceived(byte[] datagram, EndPoint clientAddress) { using (EneterTrace.Entering()) { if (datagram == null && clientAddress == null) { // The listening got interrupted so nothing to do. return; } // Get the sender IP address. string aClientIp = (clientAddress != null) ? ((IPEndPoint)clientAddress).ToString() : ""; ProtocolMessage aProtocolMessage = myProtocolFormatter.DecodeMessage(datagram); if (aProtocolMessage != null) { if (aProtocolMessage.MessageType == EProtocolMessageType.OpenConnectionRequest) { if (!string.IsNullOrEmpty(aProtocolMessage.ResponseReceiverId)) { using (ThreadLock.Lock(myConnectedClients)) { if (myMaxAmountOfConnections > -1 && myConnectedClients.Count >= myMaxAmountOfConnections) { TClientContext aClientContext = new TClientContext(myReceiver, (IPEndPoint)clientAddress); CloseConnection(aProtocolMessage.ResponseReceiverId, aClientContext); EneterTrace.Warning(TracedObject + "could not open connection for client '" + aProtocolMessage.ResponseReceiverId + "' because the maximum number of connections = '" + myMaxAmountOfConnections + "' was exceeded."); return; } if (!myConnectedClients.ContainsKey(aProtocolMessage.ResponseReceiverId)) { TClientContext aClientContext = new TClientContext(myReceiver, (IPEndPoint)clientAddress); myConnectedClients[aProtocolMessage.ResponseReceiverId] = aClientContext; } else { EneterTrace.Warning(TracedObject + "could not open connection for client '" + aProtocolMessage.ResponseReceiverId + "' because the client with same id is already connected."); } } } else { EneterTrace.Warning(TracedObject + "could not connect a client because response recevier id was not available in open connection message."); } } else if (aProtocolMessage.MessageType == EProtocolMessageType.CloseConnectionRequest) { if (!string.IsNullOrEmpty(aProtocolMessage.ResponseReceiverId)) { using (ThreadLock.Lock(myConnectedClients)) { myConnectedClients.Remove(aProtocolMessage.ResponseReceiverId); } } } MessageContext aMessageContext = new MessageContext(aProtocolMessage, aClientIp); NotifyMessageContext(aMessageContext); } } }
private void HandleConnection(IWebSocketClientContext client) { using (EneterTrace.Entering()) { string aClientIp = (client.ClientEndPoint != null) ? client.ClientEndPoint.ToString() : ""; TClientContext aClientContext = new TClientContext(client); string aClientId = null; try { client.SendTimeout = mySendTimeout; client.ReceiveTimeout = myReceiveTimeout; // If protocol formatter does not use OpenConnection message. if (!myProtocolUsesOpenConnectionMessage) { aClientId = Guid.NewGuid().ToString(); using (ThreadLock.Lock(myConnectedClients)) { myConnectedClients[aClientId] = aClientContext; } ProtocolMessage anOpenConnectionProtocolMessage = new ProtocolMessage(EProtocolMessageType.OpenConnectionRequest, aClientId, null); MessageContext aMessageContext = new MessageContext(anOpenConnectionProtocolMessage, aClientIp); NotifyMessageContext(aMessageContext); } while (true) { // Block until a message is received or the connection is closed. WebSocketMessage aWebSocketMessage = client.ReceiveMessage(); if (aWebSocketMessage != null && myMessageHandler != null) { ProtocolMessage aProtocolMessage = myProtocolFormatter.DecodeMessage((Stream)aWebSocketMessage.InputStream); // Note: security reasons ignore close connection message in WebSockets. // So that it is not possible that somebody will just send a close message which will have id of somebody else. // The connection will be closed when the client closes the socket. if (aProtocolMessage != null && aProtocolMessage.MessageType != EProtocolMessageType.CloseConnectionRequest) { MessageContext aMessageContext = new MessageContext(aProtocolMessage, aClientIp); // If protocol formatter uses open connection message to create the connection. if (aProtocolMessage.MessageType == EProtocolMessageType.OpenConnectionRequest && myProtocolUsesOpenConnectionMessage) { // Note: if client id is already set then it means this client has already open connection. if (string.IsNullOrEmpty(aClientId)) { aClientId = !string.IsNullOrEmpty(aProtocolMessage.ResponseReceiverId) ? aProtocolMessage.ResponseReceiverId : Guid.NewGuid().ToString(); using (ThreadLock.Lock(myConnectedClients)) { if (!myConnectedClients.ContainsKey(aClientId)) { myConnectedClients[aClientId] = aClientContext; } else { // Note: if the client id already exists then the connection cannot be open // and the connection with this client will be closed. EneterTrace.Warning(TracedObject + "could not open connection for client '" + aClientId + "' because the client with same id is already connected."); break; } } } else { EneterTrace.Warning(TracedObject + "the client '" + aClientId + "' has already open connection."); } } // Notify message. // Ensure that nobody will try to use id of somebody else. aMessageContext.ProtocolMessage.ResponseReceiverId = aClientId; NotifyMessageContext(aMessageContext); } else if (aProtocolMessage == null) { // Client disconnected. Or the client shall be disconnected because of incorrect message format. break; } } else { break; } } } finally { // Remove client from connected clients. if (aClientId != null) { using (ThreadLock.Lock(myConnectedClients)) { myConnectedClients.Remove(aClientId); } } // If the disconnection does not come from the service // and the client was successfuly connected then notify about the disconnection. if (!aClientContext.IsClosedFromService && aClientId != null) { ProtocolMessage aCloseProtocolMessage = new ProtocolMessage(EProtocolMessageType.CloseConnectionRequest, aClientId, null); MessageContext aMessageContext = new MessageContext(aCloseProtocolMessage, aClientIp); // Notify duplex input channel about the disconnection. NotifyMessageContext(aMessageContext); } client.CloseConnection(); } } }