private void CloseConnection(HttpResponseSender clientContext) { using (EneterTrace.Entering()) { if (!clientContext.IsDisposed) { try { // Send close connection message. object anEncodedMessage = myProtocolFormatter.EncodeCloseConnectionMessage(clientContext.ResponseReceiverId); clientContext.SendResponseMessage(anEncodedMessage); } catch (Exception err) { EneterTrace.Warning("failed to send the close message.", err); } // Note: the client context will be removed by the timer. // The reason is the client can still poll for messages which are stored in the HttpResponseSender. clientContext.Dispose(); } } }
private void HandleConnection(HttpListenerContext httpRequestContext) { using (EneterTrace.Entering()) { // If polling. (when client polls to get response messages) if (httpRequestContext.Request.HttpMethod.ToUpperInvariant() == "GET") { // Get responseReceiverId. string[] aQueryItems = httpRequestContext.Request.Url.Query.Split('&'); if (aQueryItems.Length > 0) { string aResponseReceiverId = aQueryItems[0].Substring(4); // Find the client. HttpResponseSender aClientContext; using (ThreadLock.Lock(myConnectedClients)) { aClientContext = myConnectedClients.FirstOrDefault(x => x.ResponseReceiverId == aResponseReceiverId); } if (aClientContext != null) { // Response collected messages. byte[] aMessages = aClientContext.DequeueCollectedMessages(); if (aMessages != null) { httpRequestContext.SendResponseMessage(aMessages); } } else { // Note: This happens when the polling runs and the connection is not open yet. // It is a normal situation because the polling thread on the client starts // slightly before the connection is open. } } else { EneterTrace.Warning("Incorrect query format detected for HTTP GET request."); // The request was not processed. httpRequestContext.Response.StatusCode = 404; } } else // Client sends a request message. { byte[] aMessage = httpRequestContext.GetRequestMessage(); IPEndPoint anEndPoint = httpRequestContext.Request.RemoteEndPoint; string aClientIp = (anEndPoint != null) ? anEndPoint.Address.ToString() : ""; ProtocolMessage aProtocolMessage = myProtocolFormatter.DecodeMessage(aMessage); bool anIsProcessingOk = true; if (aProtocolMessage != null && !string.IsNullOrEmpty(aProtocolMessage.ResponseReceiverId)) { MessageContext aMessageContext = new MessageContext(aProtocolMessage, aClientIp); if (aProtocolMessage.MessageType == EProtocolMessageType.OpenConnectionRequest) { using (ThreadLock.Lock(myConnectedClients)) { HttpResponseSender aClientContext = myConnectedClients.FirstOrDefault(x => x.ResponseReceiverId == aProtocolMessage.ResponseReceiverId); if (aClientContext != null && aClientContext.IsDisposed) { // The client with the same id exists but was closed and disposed. // It is just that the timer did not remove it. So delete it now. myConnectedClients.Remove(aClientContext); // Indicate the new client context shall be created. aClientContext = null; } if (aClientContext == null) { aClientContext = new HttpResponseSender(aProtocolMessage.ResponseReceiverId, aClientIp); myConnectedClients.Add(aClientContext); // If this is the only sender then start the timer measuring the inactivity to detect if the client is disconnected. // If it is not the only sender, then the timer is already running. if (myConnectedClients.Count == 1) { myResponseReceiverInactivityTimer.Change(myResponseReceiverInactivityTimeout, -1); } } else { EneterTrace.Warning(TracedObject + "could not open connection for client '" + aProtocolMessage.ResponseReceiverId + "' because the client with same id is already connected."); anIsProcessingOk = false; } } } else if (aProtocolMessage.MessageType == EProtocolMessageType.CloseConnectionRequest) { using (ThreadLock.Lock(myConnectedClients)) { HttpResponseSender aClientContext = myConnectedClients.FirstOrDefault(x => x.ResponseReceiverId == aProtocolMessage.ResponseReceiverId); if (aClientContext != null) { // Note: the disconnection comes from the client. // It means the client closed the connection and will not poll anymore. // Therefore the client context can be removed. myConnectedClients.Remove(aClientContext); aClientContext.Dispose(); } } } if (anIsProcessingOk) { NotifyMessageContext(aMessageContext); } } if (!anIsProcessingOk) { // The request was not processed. httpRequestContext.Response.StatusCode = 404; } } } }