/// <summary>Removes from the connection table any outdated connection information.</summary>
        /// <remarks>
        /// When the table is sweeped, the table is locked to prevent it from being modified during the
        /// sweep which could cause exceptions to be thrown.  The downside to this is that while the
        /// table is locked, incoming requests will be blocked!  As such, either this should be rewritten
        /// or the frequency of the sleep should be limited.  Idle checks could also be implemented to
        /// ensure that the process runs only when a long idle period has been observed.
        /// </remarks>
        private void SweepConnections(object sender, ElapsedEventArgs e)
        {
            // We lock it because we want all checks and deletions to be atomic.
            // If anyone tries to access the hashtable during the sweep, they'll
            // have to wait.
            lock (_connections.SyncRoot)
            {
                ArrayList toDelete = new ArrayList(_connections.Count);

                // Find all entries that need to be deleted
                foreach (DictionaryEntry entry in _connections)
                {
                    ClientConnectionInfo cci = (ClientConnectionInfo)entry.Value;
                    if (cci.LastUsed.AddSeconds(_connectionAgeLimit).CompareTo(DateTime.UtcNow) < 0)
                    {
                        toDelete.Add(entry.Key);
                        ((IDisposable)cci).Dispose();                         // Dispose of the connection
                        System.Diagnostics.Debug.WriteLine("Removing connection: " + cci.TransactID);
                    }
                }

                // Delete the out-of-date entries found above
                foreach (Object obj in toDelete)
                {
                    _connections.Remove(obj);
                }
                toDelete = null;
            }
        }
        /// <summary>Generates the output parameters necessary to send a new shared key to the client.</summary>
        /// <param name="transactID">The transaction ID for the client to whom we're communicating.</param>
        /// <param name="requestHeaders">Headers retrieved from the client.</param>
        /// <param name="responseMsg">Upon return, contains an empty message to be sent to the client.</param>
        /// <param name="responseHeaders">Upon return, contains the transport headers to be sent to the client.</param>
        /// <param name="responseStream">Upon return, contains an empty stream to be sent to the client.</param>
        /// <returns>Status of the server message processing (always returns Complete).</returns>
        /// <remarks>Caches the generated client information for later use.</remarks>
        private ServerProcessing MakeSharedKey(
            Guid transactID, ITransportHeaders requestHeaders,
            out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
        {
            // Generate a new shared key and iv (done as part of the constructor of the algorithm)
            SymmetricAlgorithm symmetricProvider = CryptoHelper.GetNewSymmetricProvider(_algorithm);

            // Add the transaction id and related information to the connections table.
            // We cache the entire provider object for use later on.
            ClientConnectionInfo cci = new ClientConnectionInfo(transactID, symmetricProvider);

            lock (_connections.SyncRoot) _connections[transactID.ToString()] = cci;

            // Encrypt the shared key with the sent RSA public key.  We need to make sure
            // the client actually sent us one.
            RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
            string publicKey = (string)requestHeaders[CommonHeaders.PublicKey];

            if (publicKey == null || publicKey == string.Empty)
            {
                throw new SecureRemotingException("No public key found with which to encrypt the shared key.");
            }

            rsaProvider.FromXmlString(publicKey);             // load the public key
            byte [] encryptedKey = rsaProvider.Encrypt(symmetricProvider.Key, _oaep);
            byte [] encryptedIV  = rsaProvider.Encrypt(symmetricProvider.IV, _oaep);

            // Setup the output headers and messages
            responseHeaders = new TransportHeaders();
            responseHeaders[CommonHeaders.Transaction] = ((int)SecureTransaction.SendingSharedKey).ToString();
            responseHeaders[CommonHeaders.SharedKey]   = Convert.ToBase64String(encryptedKey);
            responseHeaders[CommonHeaders.SharedIV]    = Convert.ToBase64String(encryptedIV);

            // There is no message to send back, but need to initialize them none-the-less.
            responseMsg    = null;
            responseStream = new MemoryStream();

            // We're done; don't forward this on to the next sink!  Just return.
            return(ServerProcessing.Complete);
        }
        /// <summary>Generates the output parameters necessary to send a new shared key to the client.</summary>
        /// <param name="transactID">The transaction ID for the client to whom we're communicating.</param>
        /// <param name="requestHeaders">Headers retrieved from the client.</param>
        /// <param name="responseMsg">Upon return, contains an empty message to be sent to the client.</param>
        /// <param name="responseHeaders">Upon return, contains the transport headers to be sent to the client.</param>
        /// <param name="responseStream">Upon return, contains an empty stream to be sent to the client.</param>
        /// <returns>Status of the server message processing (always returns Complete).</returns>
        /// <remarks>Caches the generated client information for later use.</remarks>
        private ServerProcessing MakeSharedKey(
			Guid transactID, ITransportHeaders requestHeaders,
			out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
        {
            // Generate a new shared key and iv (done as part of the constructor of the algorithm)
            SymmetricAlgorithm symmetricProvider = CryptoHelper.GetNewSymmetricProvider(_algorithm);

            // Add the transaction id and related information to the connections table.
            // We cache the entire provider object for use later on.
            ClientConnectionInfo cci = new ClientConnectionInfo(transactID, symmetricProvider);
            lock(_connections.SyncRoot) _connections[transactID.ToString()] = cci;

            // Encrypt the shared key with the sent RSA public key.  We need to make sure
            // the client actually sent us one.
            RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
            string publicKey = (string)requestHeaders[CommonHeaders.PublicKey];
            if (publicKey == null || publicKey == string.Empty) throw new SecureRemotingException("No public key found with which to encrypt the shared key.");

            rsaProvider.FromXmlString(publicKey); // load the public key
            byte [] encryptedKey = rsaProvider.Encrypt(symmetricProvider.Key, _oaep);
            byte [] encryptedIV = rsaProvider.Encrypt(symmetricProvider.IV, _oaep);

            // Setup the output headers and messages
            responseHeaders = new TransportHeaders();
            responseHeaders[CommonHeaders.Transaction] = ((int)SecureTransaction.SendingSharedKey).ToString();
            responseHeaders[CommonHeaders.SharedKey] = Convert.ToBase64String(encryptedKey);
            responseHeaders[CommonHeaders.SharedIV] = Convert.ToBase64String(encryptedIV);

            // There is no message to send back, but need to initialize them none-the-less.
            responseMsg = null;
            responseStream = new MemoryStream();

            // We're done; don't forward this on to the next sink!  Just return.
            return ServerProcessing.Complete;
        }