public void Reconnect()
{
try
{
lock (SyncRoot)
{
// check if already connecting.
if (m_reconnecting)
{
Utils.Trace("Session is already attempting to reconnect.");
throw ServiceResultException.Create(
StatusCodes.BadInvalidState,
"Session is already attempting to reconnect.");
}
Utils.Trace("Session RECONNECT starting.");
m_reconnecting = true;
// stop keep alives.
if (m_keepAliveTimer != null)
{
m_keepAliveTimer.Dispose();
m_keepAliveTimer = null;
}
}
EndpointDescription endpoint = m_endpoint.Description;
// create the client signature.
byte[] dataToSign = Utils.Append(endpoint.ServerCertificate, m_serverNonce);
SignatureData clientSignature = SecurityPolicies.Sign(m_instanceCertificate, endpoint.SecurityPolicyUri, dataToSign);
// check that the user identity is supported by the endpoint.
UserTokenPolicy identityPolicy = endpoint.FindUserTokenPolicy(m_identity.TokenType, m_identity.IssuedTokenType);
if (identityPolicy == null)
{
Utils.Trace("Endpoint does not supported the user identity type provided.");
throw ServiceResultException.Create(
StatusCodes.BadUserAccessDenied,
"Endpoint does not supported the user identity type provided.");
}
// select the security policy for the user token.
string securityPolicyUri = identityPolicy.SecurityPolicyUri;
if (String.IsNullOrEmpty(securityPolicyUri))
{
securityPolicyUri = endpoint.SecurityPolicyUri;
}
// need to refresh the identity (reprompt for password, refresh token).
if (m_RenewUserIdentity != null)
{
m_identity = m_RenewUserIdentity(this, m_identity);
}
// sign data with user token.
UserIdentityToken identityToken = m_identity.GetIdentityToken();
identityToken.PolicyId = identityPolicy.PolicyId;
SignatureData userTokenSignature = identityToken.Sign(dataToSign, securityPolicyUri);
// encrypt token.
identityToken.Encrypt(m_serverCertificate, m_serverNonce, securityPolicyUri);
// send the software certificates assigned to the client.
SignedSoftwareCertificateCollection clientSoftwareCertificates = GetSoftwareCertificates();
Utils.Trace("Session REPLACING channel.");
// check if the channel supports reconnect.
if ((TransportChannel.SupportedFeatures & TransportChannelFeatures.Reconnect) != 0)
{
TransportChannel.Reconnect();
}
else
{
// initialize the channel which will be created with the server.
ITransportChannel channel = SessionChannel.Create(
m_configuration,
m_endpoint.Description,
m_endpoint.Configuration,
m_instanceCertificate,
MessageContext);
// disposes the existing channel.
TransportChannel = channel;
}
// reactivate session.
byte[] serverNonce = null;
StatusCodeCollection certificateResults = null;
DiagnosticInfoCollection certificateDiagnosticInfos = null;
Utils.Trace("Session RE-ACTIVATING session.");
IAsyncResult result = BeginActivateSession(
null,
clientSignature,
null,
m_preferredLocales,
new ExtensionObject(identityToken),
userTokenSignature,
null,
null);
if (!result.AsyncWaitHandle.WaitOne(5000, false))
{
Utils.Trace("WARNING: ACTIVATE SESSION timed out. {1}/{0}", OutstandingRequestCount, GoodPublishRequestCount);
}
EndActivateSession(
result,
out serverNonce,
out certificateResults,
out certificateDiagnosticInfos);
int publishCount = 0;
lock (SyncRoot)
{
Utils.Trace("Session RECONNECT completed successfully.");
m_serverNonce = serverNonce;
m_reconnecting = false;
publishCount = m_subscriptions.Count;
}
// refill pipeline.
for (int ii = 0; ii < publishCount; ii++)
{
BeginPublish(OperationTimeout);
}
StartKeepAliveTimer();
}
finally
{
m_reconnecting = false;
}
}