internal void SendRequestMessageOneWay(Stream requestStream, uint requestId, GiopClientConnection connection) { SendMessage(requestStream); // no answer expected. connection.NotifyRequestSentCompleted(); }
internal void SendRequestMessageAsync(Stream requestStream, uint requestId, AsyncResponseAvailableCallBack callback, IClientChannelSinkStack clientSinkStack, GiopClientConnection connection) { // interested in a response -> register to receive response. // this must be done before sending the message, because otherwise, // it would be possible, that a response arrives before being registered IResponseWaiter waiter; lock (m_waitingForResponse.SyncRoot) { // create and register wait handle waiter = new AsynchronousResponseWaiter(this, requestId, callback, clientSinkStack, connection, m_timeout); if (!m_waitingForResponse.Contains(requestId)) { m_waitingForResponse[requestId] = waiter; } else { throw new omg.org.CORBA.INTERNAL(40, CompletionStatus.Completed_No); } } SendMessage(requestStream); connection.NotifyRequestSentCompleted(); // wait for completion or timeout waiter.StartWaiting(); // notify the waiter, that the time for the request starts; is non-blocking }
/// <summary>checks, if availabe connections contain one, which is usable. If yes, removes the connection /// from the available and returns it. </summary> /// <remarks>If unusable connections are found, closes and removes them from available and all connections.</remarks> /// <returns>the connection, if found, otherwise null.</returns> protected virtual GiopClientConnection GetFromAvailable(string connectionKey) { GiopClientConnection result = null; IList available = (IList)m_availableConnections[connectionKey]; while ((available != null) && (available.Count > 0)) { GiopClientConnection con = (GiopClientConnection)available[available.Count - 1]; available.RemoveAt(available.Count - 1); if (con.CanBeUsedForNextRequest()) { result = con; break; } else { try { if (con.CanCloseConnection()) { con.CloseConnection(); } } catch (Exception) { } finally { UnregisterConnection(connectionKey, con); } } } return(result); }
/// <summary>call back to call, when the async response has arrived.</summary> private void AsyncResponseArrived(IClientChannelSinkStack sinkStack, GiopClientConnection con, Stream responseStream, Exception resultException) { ITransportHeaders responseHeaders = new TransportHeaders(); responseHeaders[GiopClientConnectionDesc.CLIENT_TR_HEADER_KEY] = con.Desc; // add to response headers // forward the response if ((resultException == null) && (responseStream != null)) { #if DEBUG OutputHelper.LogStream(responseStream); #endif responseStream.Seek(0, SeekOrigin.Begin); // assure stream is read from beginning in formatter sinkStack.AsyncProcessResponse(responseHeaders, responseStream); } else { Exception toThrow = resultException; if (toThrow == null) { toThrow = new omg.org.CORBA.INTERNAL(79, omg.org.CORBA.CompletionStatus.Completed_MayBe); } sinkStack.DispatchException(toThrow); } }
private void DestroyUnusedConnections(Object state) { lock (this) { bool hasDestroyedConnections = false; foreach (DictionaryEntry de in m_availableConnections) { IList list = (IList)de.Value; GiopClientConnection toDestroy = GetConToDestroy(list); if (toDestroy != null) { list.Remove(toDestroy); UnregisterConnection((string)de.Key, toDestroy); try { toDestroy.CloseConnection(); } catch (ThreadAbortException) { throw; } catch (Exception) { // ignore } hasDestroyedConnections = true; } } if (hasDestroyedConnections) { Monitor.PulseAll(this); // inform all threads waiting on changes in connections } } }
internal GiopClientConnectionDesc(GiopClientConnectionManager conManager, GiopClientConnection connection, GiopRequestNumberGenerator reqNumberGen, GiopTransportMessageHandler transportHandler) : base(conManager, transportHandler) { m_reqNumGen = reqNumberGen; m_connection = connection; }
/// <summary> /// Allocate a connection for the message to the given target. /// </summary> private GiopClientConnection AllocateConnectionForTarget(IMessage msg, IIorProfile target, string targetKey, out uint requestNr) { GiopClientConnection result = null; GiopClientInitiatedConnection newConnection = null; // contains the new connection, if one is created lock (this) { while (result == null) { result = GetFromAvailable(targetKey); if (result != null) { break; } else { // if no usable connection, create new one (if possible) if (CanInitiateNewConnection(targetKey)) { IClientTransport transport = m_transportFactory.CreateTransport(target); newConnection = CreateClientConnection(targetKey, transport, m_requestTimeOut); result = newConnection; } else { // wait for connections to become available Monitor.Wait(this); // wait for a new connection to become available. } } } result.IncrementNumberOfRequests(); requestNr = result.Desc.ReqNumberGen.GenerateRequestId(); m_allocatedConnections[msg] = result; if (newConnection != null) { // Register the new connection, if everything went ok RegisterConnection(targetKey, result); } } if (newConnection != null) { // open the connection now outside the locked session, // to allow other threads to access connection manager during // this lenghty operation. try { newConnection.OpenConnection(); } catch (Exception) { lock (this) { // clean up dead connection UnregisterConnection(targetKey, newConnection); } throw; } } return(result); }
/// <summary> /// unregister a connections among the list of all connections. Must be called only, when having /// the lock on the connection manager instance. /// </summary> protected virtual void UnregisterConnection(string targetKey, GiopClientConnection con) { IList connections = (IList)m_allClientConnections[targetKey]; if (connections != null) { connections.Remove(con); } }
/// <summary> /// removes the connection from the available connections. /// </summary> protected void RemoveConnectionAvailable(string targetKey, GiopClientConnection con) { IList available = (IList)m_availableConnections[targetKey]; if (available != null) { available.Remove(con); } }
internal AsynchronousResponseWaiter(GiopTransportMessageHandler transportHandler, uint requestId, AsyncResponseAvailableCallBack callback, IClientChannelSinkStack clientSinkStack, GiopClientConnection connection, MessageTimeout timeOut) { Initalize(transportHandler, requestId, callback, clientSinkStack, connection, timeOut); }
protected override void UnregisterConnection(string targetKey, GiopClientConnection con) { base.UnregisterConnection(targetKey, con); IList known = (IList)m_bidirConnections[targetKey]; if (known != null) { known.Remove(con); // remove connection, if it's among bidir. } }
/// <summary> /// register a connections among the list of all connections. Must be called only, when having /// the lock on the connection manager instance. /// </summary> protected void RegisterConnection(string targetKey, GiopClientConnection con) { IList connections = (IList)m_allClientConnections[targetKey]; if (connections == null) { connections = new ArrayList(); m_allClientConnections[targetKey] = connections; } connections.Add(con); }
/// <summary> /// Notifies the connection manager, that a request has been completely sent on the connection. /// For non oneway messages, a reply is required before RequestOnConnectionCompleted is called. /// </summary> /// <remarks>if multiplexing is allowed, the connection can now be reused for a next request. This /// guarantuees, that the session based services like codeset work correctly.</remarks> internal void RequestOnConnectionSent(GiopClientConnection con) { if (m_allowMultiplex) { lock (this) { if (con.NumberOfRequestsOnConnection < m_maxNumberOfMultiplexedRequests) { // if currently not too many requests on the same connection, register already // as available. SetConnectionAvailable(con.ConnectionKey, con); } } } // else: nothing to do, wait for request completion. }
/// <summary> /// sends the request and blocks the thread until the response message /// has arravied or a timeout has occured. /// </summary> /// <returns>the response stream</returns> internal Stream SendRequestSynchronous(Stream requestStream, uint requestId, GiopClientConnection connection) { // interested in a response -> register to receive response. // this must be done before sending the message, because otherwise, // it would be possible, that a response arrives before being registered IResponseWaiter waiter; lock (m_waitingForResponse.SyncRoot) { // create and register wait handle waiter = new SynchronousResponseWaiter(this); if (!m_waitingForResponse.Contains(requestId)) { m_waitingForResponse[requestId] = waiter; } else { throw new omg.org.CORBA.INTERNAL(40, CompletionStatus.Completed_No); } } SendMessage(requestStream); connection.NotifyRequestSentCompleted(); // wait for completion or timeout bool received = waiter.StartWaiting(); waiter.Completed(); if (received) { // get and return the message if (waiter.Problem != null) { throw waiter.Problem; } else if (waiter.Response != null) { return(waiter.Response); } else { throw new INTERNAL(41, CompletionStatus.Completed_MayBe); } } else { CancelWaitForResponseMessage(requestId); CloseConnectionAfterTimeout(); throw new omg.org.CORBA.TIMEOUT(31, CompletionStatus.Completed_MayBe); } }
private void Initalize(GiopTransportMessageHandler transportHandler, uint requestId, AsyncResponseAvailableCallBack callback, IClientChannelSinkStack clientSinkStack, GiopClientConnection connection, MessageTimeout timeOutMillis) { m_alreadyNotified = false; m_transportHandler = transportHandler; m_requestId = requestId; m_callback = callback; m_clientConnection = connection; m_clientSinkStack = clientSinkStack; m_timeOut = timeOutMillis; }
/// <summary> /// register the connection as available for a new request. Must be called only, when having /// the lock on the connection manager instance, i.e. in a block lock(this). /// </summary> protected void SetConnectionAvailable(string targetKey, GiopClientConnection con) { IList available = (IList)m_availableConnections[targetKey]; if (available == null) { available = new ArrayList(); m_availableConnections[targetKey] = available; } if (!available.Contains(con)) // possible, that this is called also if the connection is already available { available.Add(con); Monitor.Pulse(this); // inform the next object waiting on connections becoming available. } }
private GiopClientConnection GetClientConnection(IMessage msg) { GiopClientConnection con = m_conManager.GetConnectionFor(msg); if (con == null) { // should not occur, because AllocateConnectionFor has been previouse called throw new omg.org.CORBA.INTERNAL(998, omg.org.CORBA.CompletionStatus.Completed_No); } if (!con.CheckConnected()) { // a new connection must not be opened, because this would require a remarshal // of the message (service-contexts) -> Therefore connection must already be open throw new omg.org.CORBA.TRANSIENT(CorbaSystemExceptionCodes.TRANSIENT_CONNECTION_DROPPED, omg.org.CORBA.CompletionStatus.Completed_No, "Connection to target lost"); } return(con); }
/// <summary> /// Notifies the connection manager, that the connection is no longer needed by the request, because /// the reply has been successfully received or an exception has occured. /// </summary> /// <remarks>if multiplexing is not allowed, the connection can now be reused for a next request.</remarks> internal void RequestOnConnectionCompleted(IMessage msg) { lock (this) { GiopClientConnection connection = (GiopClientConnection)m_allocatedConnections[msg]; if (connection != null) { connection.UpdateLastUsedTime(); connection.DecrementNumberOfRequests(); // remove from allocated connections m_allocatedConnections.Remove(msg); // make sure, that connection is available again (must be called here in every case, because // RequestOnConnectionSent has not set it for sure also for mutex allowed). SetConnectionAvailable(connection.ConnectionKey, connection); } // else: nothing to do, because failed to register connection correctly // -> for simpler error handling, call this also, if something during allocation went wrong } }
public void ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, out ITransportHeaders responseHeaders, out Stream responseStream) { #if DEBUG OutputHelper.LogStream(requestStream); #endif // called by the chain, chain expect response-stream and headers back GiopClientConnection clientCon = GetClientConnection(msg); GiopTransportMessageHandler handler = clientCon.TransportHandler; // send request and wait for response responseHeaders = new TransportHeaders(); responseHeaders[GiopClientConnectionDesc.CLIENT_TR_HEADER_KEY] = clientCon.Desc; // add to response headers uint reqNr = (uint)msg.Properties[SimpleGiopMsg.REQUEST_ID_KEY]; responseStream = handler.SendRequestSynchronous(requestStream, reqNr, clientCon); #if DEBUG OutputHelper.LogStream(responseStream); #endif responseStream.Seek(0, SeekOrigin.Begin); // assure stream is read from beginning in formatter // the previous sink in the chain does further process this response ... }
public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, Stream requestStream) { #if DEBUG OutputHelper.LogStream(requestStream); #endif // this is the last sink in the chain, therefore the call is not forwarded, instead the request is sent GiopClientConnection clientCon = GetClientConnection(msg); GiopTransportMessageHandler handler = clientCon.TransportHandler; uint reqNr = (uint)msg.Properties[SimpleGiopMsg.REQUEST_ID_KEY]; if (!GiopMessageHandler.IsOneWayCall((IMethodCallMessage)msg)) { handler.SendRequestMessageAsync(requestStream, reqNr, new AsyncResponseAvailableCallBack(this.AsyncResponseArrived), sinkStack, clientCon); } else { handler.SendRequestMessageOneWay(requestStream, reqNr, clientCon); } }
/// <summary> /// register the connection as available for a new request. Must be called only, when having /// the lock on the connection manager instance, i.e. in a block lock(this). /// </summary> protected void SetConnectionAvailable(string targetKey, GiopClientConnection con) { IList available = (IList)m_availableConnections[targetKey]; if (available == null) { available = new ArrayList(); m_availableConnections[targetKey] = available; } if (!available.Contains(con)) { // possible, that this is called also if the connection is already available available.Add(con); Monitor.Pulse(this); // inform the next object waiting on connections becoming available. } }
/// <summary>call back to call, when the async response has arrived.</summary> private void AsyncResponseArrived(IClientChannelSinkStack sinkStack, GiopClientConnection con, Stream responseStream, Exception resultException) { ITransportHeaders responseHeaders = new TransportHeaders(); responseHeaders[GiopClientConnectionDesc.CLIENT_TR_HEADER_KEY]= con.Desc; // add to response headers // forward the response if ((resultException == null) && (responseStream != null)) { #if DEBUG OutputHelper.LogStream(responseStream); #endif responseStream.Seek(0, SeekOrigin.Begin); // assure stream is read from beginning in formatter sinkStack.AsyncProcessResponse(responseHeaders, responseStream); } else { Exception toThrow = resultException; if (toThrow == null) { toThrow = new omg.org.CORBA.INTERNAL(79, omg.org.CORBA.CompletionStatus.Completed_MayBe); } sinkStack.DispatchException(toThrow); } }
/// <summary> /// sends the request and blocks the thread until the response message /// has arravied or a timeout has occured. /// </summary> /// <returns>the response stream</returns> internal Stream SendRequestSynchronous(Stream requestStream, uint requestId, GiopClientConnection connection) { // interested in a response -> register to receive response. // this must be done before sending the message, because otherwise, // it would be possible, that a response arrives before being registered IResponseWaiter waiter; lock (m_waitingForResponse.SyncRoot) { // create and register wait handle waiter = new SynchronousResponseWaiter(this); if (!m_waitingForResponse.Contains(requestId)) { m_waitingForResponse[requestId] = waiter; } else { throw new omg.org.CORBA.INTERNAL(40, CompletionStatus.Completed_No); } } SendMessage(requestStream); connection.NotifyRequestSentCompleted(); // wait for completion or timeout bool received = waiter.StartWaiting(); waiter.Completed(); if (received) { // get and return the message if (waiter.Problem != null) { throw waiter.Problem; } else if (waiter.Response != null) { return waiter.Response; } else { throw new INTERNAL(41, CompletionStatus.Completed_MayBe); } } else { CancelWaitForResponseMessage(requestId); CloseConnectionAfterTimeout(); throw new omg.org.CORBA.TIMEOUT(31, CompletionStatus.Completed_MayBe); } }
/// <summary> /// Notifies the connection manager, that a request has been completely sent on the connection. /// For non oneway messages, a reply is required before RequestOnConnectionCompleted is called. /// </summary> /// <remarks>if multiplexing is allowed, the connection can now be reused for a next request. This /// guarantuees, that the session based services like codeset work correctly.</remarks> internal void RequestOnConnectionSent(GiopClientConnection con) { if (m_allowMultiplex) { lock(this) { if (con.NumberOfRequestsOnConnection < m_maxNumberOfMultiplexedRequests) { // if currently not too many requests on the same connection, register already // as available. SetConnectionAvailable(con.ConnectionKey, con); } } } // else: nothing to do, wait for request completion. }