/// <summary> /// Accepts the connection. /// </summary> /// <param name="clientSocket">The socket.</param> void IAcceptConnectionConsumer.AcceptConnection(Socket clientSocket) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; // GenuineConnectionType genuineConnectionType = GenuineConnectionType.None; string remoteUri = "Unknown."; string remoteAddress = "Address of the remote host."; string connectionName; int remoteHostUniqueIdentifier; TcpSocketInfo tcpSocketInfo = null; HostInformation hostInformation = null; using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) throw OperationException.WrapException(this._disposeReason); } using (new ThreadDataSlotKeeper(OccupiedThreadSlots.SocketDuringEstablishing, clientSocket)) { try { // provide a possibility to decline the connection ConnectionAcceptedCancellableEventParameter connectionAcceptedCancellableEventParameter = new ConnectionAcceptedCancellableEventParameter(); connectionAcceptedCancellableEventParameter.Socket = clientSocket; connectionAcceptedCancellableEventParameter.IPEndPoint = (IPEndPoint) clientSocket.RemoteEndPoint; this.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.GTcpConnectionAccepted, null, null, connectionAcceptedCancellableEventParameter)); if (connectionAcceptedCancellableEventParameter.Cancel) throw GenuineExceptions.Get_Connect_CanNotAcceptIncomingConnection("Connection accepting was cancelled by the event consumer."); // accept the connection Exception reasonOfStateLost = null; tcpSocketInfo = this.LowLevel_AcceptConnection(clientSocket, this.Local.Uri, out remoteUri, out remoteAddress, out connectionName, out remoteHostUniqueIdentifier, out reasonOfStateLost); // get the remote host hostInformation = this.ITransportContext.KnownHosts[remoteUri]; if (remoteAddress != null) hostInformation.UpdateUrl(remoteAddress); tcpSocketInfo.Remote = hostInformation; hostInformation.PhysicalAddress = tcpSocketInfo.Socket.RemoteEndPoint; hostInformation.LocalPhysicalAddress = tcpSocketInfo.Socket.LocalEndPoint; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0 ) { binaryLogWriter.WriteHostInformationEvent("TcpConnectionManager.LowLevel_AcceptConnection", LogMessageType.HostInformationCreated, null, hostInformation, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, "HostInformation is ready for actions."); } using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) throw OperationException.WrapException(this._disposeReason); switch (tcpSocketInfo.GenuineConnectionType) { case GenuineConnectionType.Persistent: lock (hostInformation.PersistentConnectionEstablishingLock) { if (hostInformation.GenuinePersistentConnectionState == GenuinePersistentConnectionState.Opened) throw GenuineExceptions.Get_Processing_LogicError("Remote host tries to open persistent connection while it's a server."); hostInformation.GenuinePersistentConnectionState = GenuinePersistentConnectionState.Accepted; // close existent connection lock (this._persistent.SyncRoot) { TcpSocketInfo existentSocketInfo = this._persistent.Get(remoteUri, connectionName) as TcpSocketInfo; if (existentSocketInfo != null) { lock (existentSocketInfo) tcpSocketInfo.MessageContainer = existentSocketInfo.MessageContainer; this.SocketFailed(GenuineExceptions.Get_Connect_ConnectionReestablished(), existentSocketInfo); this.LowLevel_CloseConnection(existentSocketInfo); } else { tcpSocketInfo.MessageContainer = new MessageContainer(this.ITransportContext); } // register the new connection this._persistent.Set(remoteUri, connectionName, tcpSocketInfo); } } tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.ClosePersistentConnectionAfterInactivity]); tcpSocketInfo.Renew(); tcpSocketInfo.SignalState(GenuineEventType.GeneralConnectionEstablished, null, null); // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.IAcceptConnectionConsumer.AcceptConnection", LogMessageType.ConnectionEstablished, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, (int) tcpSocketInfo.GenuineConnectionType, 0, 0, this.GetType().Name, hostInformation.LocalPhysicalAddress.ToString(), hostInformation.PhysicalAddress.ToString(), null, "The persistent connection is established."); } // to avoid sending previous messages, encrypted by previously used Security Sessions if (reasonOfStateLost != null) { tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages(); tcpSocketInfo.MessageContainer.Dispose(reasonOfStateLost); tcpSocketInfo.MessageContainer = new MessageContainer(this.ITransportContext); } // start processing this.Pool_StartSending(tcpSocketInfo); this.Pool_InitiateReceiving(tcpSocketInfo, this.ITransportContext.IParameterProvider); break; case GenuineConnectionType.Named: // register the new connection string fullConnectionName = remoteUri + "/" + tcpSocketInfo.ConnectionName; tcpSocketInfo.MessageContainer = new MessageContainer(this.ITransportContext); lock (this._named) this._named[fullConnectionName] = tcpSocketInfo; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.IAcceptConnectionConsumer.AcceptConnection", LogMessageType.ConnectionEstablished, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, (int) tcpSocketInfo.GenuineConnectionType, 0, 0, this.GetType().Name, hostInformation.LocalPhysicalAddress.ToString(), hostInformation.PhysicalAddress.ToString(), null, "The named connection is established."); } // start processing this.Pool_StartSending(tcpSocketInfo); this.Pool_InitiateReceiving(tcpSocketInfo, this.ITransportContext.IParameterProvider); tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.CloseNamedConnectionAfterInactivity]); break; case GenuineConnectionType.Invocation: // register the new connection tcpSocketInfo.TcpInvocationFiniteAutomatonState = TcpInvocationFiniteAutomatonState.ServerAwaiting; this._knownInvocationConnections[tcpSocketInfo.ConnectionName] = tcpSocketInfo; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.IAcceptConnectionConsumer.AcceptConnection", LogMessageType.ConnectionEstablished, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, (int) tcpSocketInfo.GenuineConnectionType, 0, 0, this.GetType().Name, hostInformation.LocalPhysicalAddress.ToString(), hostInformation.PhysicalAddress.ToString(), null, "The invocation connection is established."); } // start processing this.Pool_InitiateReceiving(tcpSocketInfo, this.ITransportContext.IParameterProvider); tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.CloseInvocationConnectionAfterInactivity]); break; } } // start the shutdown timer tcpSocketInfo.Renew(); } catch(Exception ex) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "TcpConnectionManager.IAcceptConnectionConsumer.AcceptConnection", LogMessageType.ConnectionAccepting, ex, null, hostInformation, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, tcpSocketInfo == null ? -1 : tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The inbound connection has not been accepted."); SocketUtility.CloseSocket(clientSocket); } } }
/// <summary> /// Continues receiving and processing of the message in half-sync mode. /// </summary> /// <param name="socketAsObject">The connection.</param> private void Pool_Server_ContinueHalfSyncReceiving(object socketAsObject) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; XHttpConnection xHttpConnection = null; XHttpPhysicalConnection xHttpPhysicalConnection = null; Socket socket = (Socket) socketAsObject; byte protocolVersion; string remoteUri = null; int sequenceNo = 0; GenuineConnectionType genuineConnectionType = GenuineConnectionType.None; Guid hostId = Guid.Empty; HttpPacketType httpPacketType = HttpPacketType.Unkown; string connectionName; int remoteHostUniqueIdentifier; try { // server & sender - parse messages, execute them, send confirmation // server & listener - if messages are available, send them all. otherwise set available flag and hold the connection for a while // first, read the header Stream inputStream = this.LowLevel_ParseHttpContent(GenuineUtility.GetTimeout(GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.XHttpReadHttpMessageTimeout])), false, socket, null, out protocolVersion, out remoteUri, out sequenceNo, out genuineConnectionType, out hostId, out httpPacketType, out connectionName, out remoteHostUniqueIdentifier); // who it was HostInformation remote = this.ITransportContext.KnownHosts["_ghttp://" + hostId.ToString("N")]; remote.UpdateUri(remote.Uri, remoteHostUniqueIdentifier); remote.ProtocolVersion = protocolVersion; // get the connection lock (remote.PersistentConnectionEstablishingLock) { xHttpConnection = this._persistent.Get(remote.Uri, connectionName) as XHttpConnection; if (httpPacketType == HttpPacketType.Establishing_ResetConnection && xHttpConnection != null) { xHttpConnection.Dispose(GenuineExceptions.Get_Receive_ConnectionClosed("The connection was closed by HttpPacketType.Establishing_ResetConnection client request.")); xHttpConnection = null; } if (xHttpConnection == null) { using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) throw OperationException.WrapException(this._disposeReason); // provide a possibility to decline the connection ConnectionAcceptedCancellableEventParameter connectionAcceptedCancellableEventParameter = new ConnectionAcceptedCancellableEventParameter(); connectionAcceptedCancellableEventParameter.Socket = socket; connectionAcceptedCancellableEventParameter.IPEndPoint = (IPEndPoint) socket.RemoteEndPoint; this.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.GHttpConnectionAccepted, null, null, connectionAcceptedCancellableEventParameter)); if (connectionAcceptedCancellableEventParameter.Cancel) throw GenuineExceptions.Get_Connect_CanNotAcceptIncomingConnection("Connection accepting was cancelled by the event consumer."); xHttpConnection = this.Pool_CreateConnection(remote, remote.Uri, false, connectionName); } } } bool theSamePacketIsRequested; lock (xHttpConnection.Listener.PhysicalConnectionStateLock) { if (httpPacketType == HttpPacketType.Listening) { // if there is an already registered listener request - release it if (xHttpConnection.Listener.ConnectionAvailable && xHttpConnection.Listener.Socket != socket) { // shut down the previous physical connection this.LowLevel_SendServerError(new PhysicalConnectionAndSocket(xHttpConnection.Listener, socket)); // GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.LowLevel_SendServerError), new PhysicalConnectionAndSocket(xHttpConnection.Listener, socket), true); xHttpConnection.Listener.AcquireIfAvailable(); } xHttpConnection.Listener.Socket = socket; xHttpPhysicalConnection = xHttpConnection.Listener; } else { xHttpConnection.Sender.Socket = socket; xHttpPhysicalConnection = xHttpConnection.Sender; } theSamePacketIsRequested = xHttpPhysicalConnection.SequenceNo == sequenceNo && xHttpPhysicalConnection.SentContent != null; #if DEBUG xHttpPhysicalConnection.TypeOfSocket = "Accepted"; #endif xHttpPhysicalConnection.Remote.PhysicalAddress = socket.RemoteEndPoint; xHttpPhysicalConnection.Remote.LocalPhysicalAddress = socket.LocalEndPoint; } // lock (xHttpConnection.Listener.PhysicalConnectionStateLock) // renew connection lifetime xHttpConnection.Renew(); xHttpPhysicalConnection.XHttpConnection.SignalState(GenuineEventType.GeneralConnectionEstablished, null, null); // if the same packet stream is requested, send the response if (theSamePacketIsRequested) { // skip the current stream inputStream.Close(); // send the stream and initiate receiving this.LowLevel_SendHttpContent(remote.ExpireTime, null, null, null, null, xHttpPhysicalConnection, genuineConnectionType, HttpPacketType.RequestRepeated, true, true, true, true); return ; } lock (xHttpConnection.Listener.PhysicalConnectionStateLock) { // if desynchronization, report and continue if (httpPacketType != HttpPacketType.Establishing_ResetConnection && xHttpPhysicalConnection.SequenceNo > sequenceNo || sequenceNo > xHttpPhysicalConnection.SequenceNo + 1) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "XHttpConnectionManager.Pool_Server_ContinueHalfSyncreceiving", LogMessageType.ConnectionStreamDesynchronization, GenuineExceptions.Get_Debugging_GeneralWarning("Stream desynchronization."), null, xHttpPhysicalConnection.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, xHttpPhysicalConnection.ConnectionLevelSecurity, xHttpPhysicalConnection.ConnectionLevelSecurity == null ? null : xHttpPhysicalConnection.ConnectionLevelSecurity.Name, xHttpConnection.DbgConnectionId, 0, 0, 0, null, null, null, null, "Stream desynchronization error. Received sequence number: {0}. Expected sequence number: {1}.", xHttpPhysicalConnection.SequenceNo, sequenceNo); } // send the stream and initiate receiving this.LowLevel_SendHttpContent(remote.ExpireTime, null, null, null, null, xHttpPhysicalConnection, genuineConnectionType, HttpPacketType.Desynchronization, false, true, true, true); return ; } // the next sequence is requested if (xHttpPhysicalConnection.SentContent != null) { // release the content xHttpPhysicalConnection.SentContent.Close(); xHttpPhysicalConnection.SentContent = null; } // respond with the same seq No xHttpPhysicalConnection.SequenceNo = sequenceNo; xHttpPhysicalConnection.Socket = socket; xHttpPhysicalConnection.MessagesBeingSent.Clear(); } // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "XHttpConnectionManager.Pool_Server_ContinueHalfSyncreceiving", LogMessageType.ReceivingFinished, null, null, xHttpPhysicalConnection.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, xHttpPhysicalConnection.ConnectionLevelSecurity, xHttpPhysicalConnection.ConnectionLevelSecurity == null ? null : xHttpPhysicalConnection.ConnectionLevelSecurity.Name, xHttpConnection.DbgConnectionId, 0, 0, 0, null, null, null, null, "HTTP Stream received. Packet type: {0}.", Enum.Format(typeof(HttpPacketType), httpPacketType, "g")); } // analyze the type of the packet switch(httpPacketType) { case HttpPacketType.Establishing_ResetConnection: case HttpPacketType.Establishing: // mark the remote host as client lock (remote.PersistentConnectionEstablishingLock) remote.GenuinePersistentConnectionState = GenuinePersistentConnectionState.Accepted; // read CLSS streams BinaryReader binaryReader = new BinaryReader(inputStream); Stream clsseStream = null; GenuineChunkedStream outputStream = new GenuineChunkedStream(false); // process the sender info int writtenSize = binaryReader.ReadInt32(); using (new GenuineChunkedStreamSizeLabel(outputStream)) { if (xHttpConnection.Sender.ConnectionLevelSecurity != null && ! xHttpConnection.Sender.ConnectionLevelSecurity.IsEstablished) { using (Stream clssData = new DelimiterStream(inputStream, writtenSize)) { clsseStream = xHttpConnection.Sender.ConnectionLevelSecurity.EstablishSession(clssData, true); } } if (clsseStream != null) GenuineUtility.CopyStreamToStream(clsseStream, outputStream); } // process the listener info writtenSize = binaryReader.ReadInt32(); using (new GenuineChunkedStreamSizeLabel(outputStream)) { if (xHttpConnection.Listener.ConnectionLevelSecurity != null && ! xHttpConnection.Listener.ConnectionLevelSecurity.IsEstablished) { using (Stream clssData = new DelimiterStream(inputStream, writtenSize)) { clsseStream = xHttpConnection.Listener.ConnectionLevelSecurity.EstablishSession(clssData, true); } } if (clsseStream != null) GenuineUtility.CopyStreamToStream(clsseStream, outputStream); } // skip remaining part of the packet inputStream.Close(); this.LowLevel_SendHttpContent(remote.ExpireTime, null, outputStream, null, null, xHttpPhysicalConnection, genuineConnectionType, httpPacketType, false, true, true, false); break; case HttpPacketType.Listening: // if messages are available, send them immediately // otherwise put the connection off for a while // skip the remaining content inputStream.Close(); Pool_Server_ProcessListenerRequest(xHttpConnection, xHttpPhysicalConnection); break; case HttpPacketType.Usual: // apply CLSS if it was established if (xHttpPhysicalConnection.ConnectionLevelSecurity != null) inputStream = xHttpPhysicalConnection.ConnectionLevelSecurity.Decrypt(inputStream); Pool_Server_ProcessSenderRequest(xHttpConnection, xHttpPhysicalConnection, inputStream); break; default: throw GenuineExceptions.Get_Receive_IncorrectData("Unexpected type of the packet."); } } catch(Exception ex) { try { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "XHttpConnectionManager.Pool_Server_ContinueHalfSyncreceiving", LogMessageType.ReceivingFinished, ex, null, xHttpPhysicalConnection.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, xHttpPhysicalConnection.ConnectionLevelSecurity, xHttpPhysicalConnection.ConnectionLevelSecurity == null ? null : xHttpPhysicalConnection.ConnectionLevelSecurity.Name, xHttpConnection.DbgConnectionId, 0, 0, 0, null, null, null, null, "Error occurred while receiving HTTP Stream. Sequence No: {0}. Connection type: {1}. Packet type: {2}.", sequenceNo, genuineConnectionType, httpPacketType); } SocketUtility.CloseSocket(socket); } catch { } } }