private bool VerifyPublishResponse(
ResponseHeader responseHeader,
Subscription subscription,
UInt32Collection availableSequenceNumbers,
bool moreNotifications,
NotificationMessage notificationMessage,
StatusCodeCollection results,
DiagnosticInfoCollection diagnosticInfos)
{
/*
Utils.Trace(
"PublishReceived: SubId={0} SeqNo={1}, PublishTime={2:mm:ss.fff}, Time={3:mm:ss.fff}",
subscription.SubscriptionId,
notificationMessage.SequenceNumber,
notificationMessage.PublishTime,
DateTime.UtcNow);
*/
// check if there is an odd delay.
if (responseHeader.Timestamp > notificationMessage.PublishTime.AddMilliseconds(100))
{
Log(
"WARNING. Unexpected delay between PublishTime and ResponseTime. SeqNo={0}, PublishTime={1:hh:mm:ss.fff}, ResponseTime={2:hh:mm:ss.fff}",
notificationMessage.SequenceNumber,
notificationMessage.PublishTime,
responseHeader.Timestamp);
}
// save results.
subscription.AvailableSequenceNumbers = availableSequenceNumbers;
if (notificationMessage.NotificationData.Count == 0)
{
// keep alives do not increment the sequence number.
if (subscription.NextExpectedSequenceNumber != notificationMessage.SequenceNumber)
{
Log(
"Incorrect sequence number for keep alive. SubscriptionId = {0}, Actual = {1}, Expected = {2}",
subscription.SubscriptionId,
notificationMessage.SequenceNumber,
subscription.NextExpectedSequenceNumber);
subscription.Failed = true;
return false;
}
// save the message.
DateTime timestamp = responseHeader.Timestamp;
DateTime start = subscription.States[subscription.States.Count - 1].Start;
// check if this is an old request being processed late.
if (start > timestamp && subscription.States.Count > 1)
{
subscription.States[subscription.States.Count - 2].KeepAlives.Add(timestamp);
}
else
{
subscription.States[subscription.States.Count - 1].KeepAlives.Add(timestamp);
}
}
else
{
// check for replays.
if (subscription.NextExpectedSequenceNumber > notificationMessage.SequenceNumber)
{
// check for out of order responses.
bool found = false;
for (int ii = 0; ii < subscription.MissingSequenceNumbers.Count; ii++)
{
if (subscription.MissingSequenceNumbers[ii] == notificationMessage.SequenceNumber)
{
subscription.MissingSequenceNumbers.RemoveAt(ii);
found = true;
break;
}
}
// oops - duplicate.
if (!found)
{
Log(
"Duplicate sequence number for message. SubscriptionId = {0}, Actual = {1}, Expected = {2}",
subscription.SubscriptionId,
notificationMessage.SequenceNumber,
subscription.NextExpectedSequenceNumber);
subscription.Failed = true;
return false;
}
}
// increment message counter.
if (notificationMessage.SequenceNumber >= subscription.NextExpectedSequenceNumber)
{
for (uint ii = subscription.NextExpectedSequenceNumber; ii < notificationMessage.SequenceNumber; ii++)
{
if (!subscription.MissingSequenceNumbers.Contains(ii))
{
subscription.MissingSequenceNumbers.Add(ii);
}
}
subscription.NextExpectedSequenceNumber = notificationMessage.SequenceNumber+1;
}
// save the largest received message number (gap exist because of client side threading issues).
if (subscription.LastReceivedSequenceNumber < notificationMessage.SequenceNumber)
{
subscription.LastReceivedSequenceNumber = notificationMessage.SequenceNumber;
}
// save the message.
DateTime timestamp = responseHeader.Timestamp;
DateTime start = subscription.States[subscription.States.Count-1].Start;
// check if this is an old request being processed late.
if (start > timestamp && subscription.States.Count > 1)
{
subscription.States[subscription.States.Count - 2].KeepAlives.Add(timestamp);
}
else
{
subscription.States[subscription.States.Count - 1].KeepAlives.Add(timestamp);
}
subscription.NotificationMessages.Add(notificationMessage);
subscription.ReceiveTimes.Add(responseHeader.Timestamp);
// change to keep alive mode.
if (subscription.StaticData)
{
PublishingState state = new PublishingState();
state.KeepAliveCount = subscription.KeepAliveCount;
state.PublishingInterval = subscription.PublishingInterval;
state.Start = timestamp;
state.KeepAliveMode = true;
subscription.States[subscription.States.Count-1].End = state.Start;
subscription.States.Add(state);
}
// save the acknowlegements.
SaveAcknowledgement(subscription.SubscriptionId, notificationMessage.SequenceNumber);
}
return true;
}