Skip to content

Commit

Permalink
Better sequence index handling, new true sequence index
Browse files Browse the repository at this point in the history
  • Loading branch information
samiyrj committed Jun 9, 2021
1 parent 25c2112 commit 05591bc
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 34 deletions.
58 changes: 42 additions & 16 deletions Sources/SwiftyPing/SwiftyPing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public enum PingError: Error, Equatable {
/// Response `identifier` doesn't match what was sent.
case identifierMismatch(received: UInt16, expected: UInt16)
/// Response `sequenceNumber` doesn't match.
case invalidSequenceIndex(received: Int, expected: Int)
case invalidSequenceIndex(received: UInt16, expected: UInt16)

// Host resolve errors
/// Unknown error occured within host lookup.
Expand Down Expand Up @@ -158,8 +158,8 @@ public class SwiftyPing: NSObject {
public var targetCount: Int?

/// The current ping count, starting from 0.
public var currentCount: Int {
return sequenceIndex
public var currentCount: UInt64 {
return trueSequenceIndex
}
/// Array of all ping responses sent to the `observer`.
public private(set) var responses: [PingResponse] = []
Expand All @@ -180,15 +180,25 @@ public class SwiftyPing: NSObject {
/// When the current request was sent.
private var sequenceStart = Date()
/// The current sequence number.
private var _sequenceIndex = 0
private var sequenceIndex: Int {
private var _sequenceIndex: UInt16 = 0
private var sequenceIndex: UInt16 {
get {
_serial_property.sync { self._sequenceIndex }
}
set {
_serial_property.sync { self._sequenceIndex = newValue }
}
}
/// The true sequence number.
private var _trueSequenceIndex: UInt64 = 0
private var trueSequenceIndex: UInt64 {
get {
_serial_property.sync { self._trueSequenceIndex }
}
set {
_serial_property.sync { self._trueSequenceIndex = newValue }
}
}

private var erroredIndices = [Int]()
/// Initializes a pinger.
Expand Down Expand Up @@ -375,12 +385,13 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: self.identifier,
ipAddress: self.destination.ip,
sequenceNumber: self.sequenceIndex,
trueSequenceNumber: self.trueSequenceIndex,
duration: self.timeIntervalSinceStart,
error: error,
byteCount: nil,
ipHeader: nil)

self.erroredIndices.append(self.sequenceIndex)
self.erroredIndices.append(Int(self.sequenceIndex))
self.isPinging = false
self.informObserver(of: response)

Expand All @@ -396,11 +407,12 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: self.identifier,
ipAddress: self.destination.ip,
sequenceNumber: self.sequenceIndex,
trueSequenceNumber: self.trueSequenceIndex,
duration: self.timeIntervalSinceStart,
error: pingError,
byteCount: nil,
ipHeader: nil)
self.erroredIndices.append(self.sequenceIndex)
self.erroredIndices.append(Int(self.sequenceIndex))
self.isPinging = false
self.informObserver(of: response)

Expand All @@ -418,12 +430,13 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: self.identifier,
ipAddress: self.destination.ip,
sequenceNumber: self.sequenceIndex,
trueSequenceNumber: self.trueSequenceIndex,
duration: timeIntervalSinceStart,
error: error,
byteCount: nil,
ipHeader: nil)

erroredIndices.append(sequenceIndex)
erroredIndices.append(Int(sequenceIndex))
self.isPinging = false
informObserver(of: response)

Expand Down Expand Up @@ -461,7 +474,7 @@ public class SwiftyPing: NSObject {
if configuration.haltAfterTarget {
haltPinging()
} else {
informFinishedStatus(sequenceIndex)
informFinishedStatus(trueSequenceIndex)
}
}
if shouldSchedulePing() {
Expand All @@ -470,7 +483,7 @@ public class SwiftyPing: NSObject {
}
}
}
private func informFinishedStatus(_ sequenceIndex: Int) {
private func informFinishedStatus(_ sequenceIndex: UInt64) {
if let callback = finished {
var roundtrip: PingResult.Roundtrip? = nil
let roundtripTimes = responses.filter { $0.error == nil }.map { $0.duration }
Expand All @@ -484,7 +497,7 @@ public class SwiftyPing: NSObject {
roundtrip = PingResult.Roundtrip(minimum: min, maximum: max, average: avg, standardDeviation: stddev)
}

let result = PingResult(responses: responses, packetsTransmitted: sequenceIndex, packetsReceived: roundtripTimes.count, roundtrip: roundtrip)
let result = PingResult(responses: responses, packetsTransmitted: sequenceIndex, packetsReceived: UInt64(roundtripTimes.count), roundtrip: roundtrip)
callback(result)
}
}
Expand Down Expand Up @@ -516,9 +529,10 @@ public class SwiftyPing: NSObject {
public func stopPinging(resetSequence: Bool = true) {
killswitch = true
isPinging = false
let count = sequenceIndex
let count = trueSequenceIndex
if resetSequence {
sequenceIndex = 0
trueSequenceIndex = 0
erroredIndices.removeAll()
}
informFinishedStatus(count)
Expand All @@ -537,6 +551,12 @@ public class SwiftyPing: NSObject {
} else {
sequenceIndex += 1
}

if trueSequenceIndex >= UInt64.max {
trueSequenceIndex = 0
} else {
trueSequenceIndex += 1
}
}

// MARK: - Socket callback
Expand All @@ -563,6 +583,7 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: identifier,
ipAddress: destination.ip,
sequenceNumber: sequenceIndex,
trueSequenceNumber: trueSequenceIndex,
duration: timeIntervalSinceStart,
error: validationError,
byteCount: data.count,
Expand Down Expand Up @@ -675,7 +696,7 @@ public class SwiftyPing: NSObject {
// This response either errorred or timed out, ignore it
return false
}
throw PingError.invalidSequenceIndex(received: Int(receivedSequenceIndex), expected: sequenceIndex)
throw PingError.invalidSequenceIndex(received: receivedSequenceIndex, expected: sequenceIndex)
}
return true
}
Expand Down Expand Up @@ -729,7 +750,12 @@ public struct PingResponse {
/// The IP address of the host.
public let ipAddress: String?
/// Running sequence number, starting from 0.
public let sequenceNumber: Int
/// This number will wrap to zero when it exceeds `UInt16.max`,
/// which is usually just 65535, and is the one used in the ping
/// protocol. See `trueSequenceNumber` for the actual count.
public let sequenceNumber: UInt16
/// The true sequence number.
public let trueSequenceNumber: UInt64
/// Roundtrip time.
public let duration: TimeInterval
/// An error associated with the response.
Expand All @@ -756,9 +782,9 @@ public struct PingResult {
/// Collection of all responses, including errored or timed out.
public let responses: [PingResponse]
/// Number of packets sent.
public let packetsTransmitted: Int
public let packetsTransmitted: UInt64
/// Number of packets received.
public let packetsReceived: Int
public let packetsReceived: UInt64
/// The packet loss. If the number of packets transmitted (`packetsTransmitted`) is zero, returns `nil`.
public var packetLoss: Double? {
if packetsTransmitted == 0 { return nil }
Expand Down
60 changes: 43 additions & 17 deletions SwiftyPingTest/SwiftyPing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public enum PingError: Error, Equatable {
/// Response `identifier` doesn't match what was sent.
case identifierMismatch(received: UInt16, expected: UInt16)
/// Response `sequenceNumber` doesn't match.
case invalidSequenceIndex(received: Int, expected: Int)
case invalidSequenceIndex(received: UInt16, expected: UInt16)

// Host resolve errors
/// Unknown error occured within host lookup.
Expand Down Expand Up @@ -158,8 +158,8 @@ public class SwiftyPing: NSObject {
public var targetCount: Int?

/// The current ping count, starting from 0.
public var currentCount: Int {
return sequenceIndex
public var currentCount: UInt64 {
return trueSequenceIndex
}
/// Array of all ping responses sent to the `observer`.
public private(set) var responses: [PingResponse] = []
Expand All @@ -180,15 +180,25 @@ public class SwiftyPing: NSObject {
/// When the current request was sent.
private var sequenceStart = Date()
/// The current sequence number.
private var _sequenceIndex = 0
private var sequenceIndex: Int {
private var _sequenceIndex: UInt16 = 0
private var sequenceIndex: UInt16 {
get {
_serial_property.sync { self._sequenceIndex }
}
set {
_serial_property.sync { self._sequenceIndex = newValue }
}
}
/// The true sequence number.
private var _trueSequenceIndex: UInt64 = 0
private var trueSequenceIndex: UInt64 {
get {
_serial_property.sync { self._trueSequenceIndex }
}
set {
_serial_property.sync { self._trueSequenceIndex = newValue }
}
}

private var erroredIndices = [Int]()
/// Initializes a pinger.
Expand Down Expand Up @@ -375,12 +385,13 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: self.identifier,
ipAddress: self.destination.ip,
sequenceNumber: self.sequenceIndex,
trueSequenceNumber: self.trueSequenceIndex,
duration: self.timeIntervalSinceStart,
error: error,
byteCount: nil,
ipHeader: nil)

self.erroredIndices.append(self.sequenceIndex)
self.erroredIndices.append(Int(self.sequenceIndex))
self.isPinging = false
self.informObserver(of: response)

Expand All @@ -396,11 +407,12 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: self.identifier,
ipAddress: self.destination.ip,
sequenceNumber: self.sequenceIndex,
trueSequenceNumber: self.trueSequenceIndex,
duration: self.timeIntervalSinceStart,
error: pingError,
byteCount: nil,
ipHeader: nil)
self.erroredIndices.append(self.sequenceIndex)
self.erroredIndices.append(Int(self.sequenceIndex))
self.isPinging = false
self.informObserver(of: response)

Expand All @@ -418,12 +430,13 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: self.identifier,
ipAddress: self.destination.ip,
sequenceNumber: self.sequenceIndex,
trueSequenceNumber: self.trueSequenceIndex,
duration: timeIntervalSinceStart,
error: error,
byteCount: nil,
ipHeader: nil)

erroredIndices.append(sequenceIndex)
erroredIndices.append(Int(sequenceIndex))
self.isPinging = false
informObserver(of: response)

Expand Down Expand Up @@ -461,7 +474,7 @@ public class SwiftyPing: NSObject {
if configuration.haltAfterTarget {
haltPinging()
} else {
informFinishedStatus(sequenceIndex)
informFinishedStatus(trueSequenceIndex)
}
}
if shouldSchedulePing() {
Expand All @@ -470,7 +483,7 @@ public class SwiftyPing: NSObject {
}
}
}
private func informFinishedStatus(_ sequenceIndex: Int) {
private func informFinishedStatus(_ sequenceIndex: UInt64) {
if let callback = finished {
var roundtrip: PingResult.Roundtrip? = nil
let roundtripTimes = responses.filter { $0.error == nil }.map { $0.duration }
Expand All @@ -484,7 +497,7 @@ public class SwiftyPing: NSObject {
roundtrip = PingResult.Roundtrip(minimum: min, maximum: max, average: avg, standardDeviation: stddev)
}

let result = PingResult(responses: responses, packetsTransmitted: sequenceIndex, packetsReceived: roundtripTimes.count, roundtrip: roundtrip)
let result = PingResult(responses: responses, packetsTransmitted: sequenceIndex, packetsReceived: UInt64(roundtripTimes.count), roundtrip: roundtrip)
callback(result)
}
}
Expand Down Expand Up @@ -516,9 +529,10 @@ public class SwiftyPing: NSObject {
public func stopPinging(resetSequence: Bool = true) {
killswitch = true
isPinging = false
let count = sequenceIndex
let count = trueSequenceIndex
if resetSequence {
sequenceIndex = 0
trueSequenceIndex = 0
erroredIndices.removeAll()
}
informFinishedStatus(count)
Expand All @@ -532,11 +546,17 @@ public class SwiftyPing: NSObject {

private func incrementSequenceIndex() {
// Handle overflow gracefully
if sequenceIndex >= Int.max {
if sequenceIndex >= UInt16.max {
sequenceIndex = 0
} else {
sequenceIndex += 1
}

if trueSequenceIndex >= UInt64.max {
trueSequenceIndex = 0
} else {
trueSequenceIndex += 1
}
}

// MARK: - Socket callback
Expand All @@ -563,6 +583,7 @@ public class SwiftyPing: NSObject {
let response = PingResponse(identifier: identifier,
ipAddress: destination.ip,
sequenceNumber: sequenceIndex,
trueSequenceNumber: trueSequenceIndex,
duration: timeIntervalSinceStart,
error: validationError,
byteCount: data.count,
Expand Down Expand Up @@ -675,7 +696,7 @@ public class SwiftyPing: NSObject {
// This response either errorred or timed out, ignore it
return false
}
throw PingError.invalidSequenceIndex(received: Int(receivedSequenceIndex), expected: sequenceIndex)
throw PingError.invalidSequenceIndex(received: receivedSequenceIndex, expected: sequenceIndex)
}
return true
}
Expand Down Expand Up @@ -729,7 +750,12 @@ public struct PingResponse {
/// The IP address of the host.
public let ipAddress: String?
/// Running sequence number, starting from 0.
public let sequenceNumber: Int
/// This number will wrap to zero when it exceeds `UInt16.max`,
/// which is usually just 65535, and is the one used in the ping
/// protocol. See `trueSequenceNumber` for the actual count.
public let sequenceNumber: UInt16
/// The true sequence number.
public let trueSequenceNumber: UInt64
/// Roundtrip time.
public let duration: TimeInterval
/// An error associated with the response.
Expand All @@ -756,9 +782,9 @@ public struct PingResult {
/// Collection of all responses, including errored or timed out.
public let responses: [PingResponse]
/// Number of packets sent.
public let packetsTransmitted: Int
public let packetsTransmitted: UInt64
/// Number of packets received.
public let packetsReceived: Int
public let packetsReceived: UInt64
/// The packet loss. If the number of packets transmitted (`packetsTransmitted`) is zero, returns `nil`.
public var packetLoss: Double? {
if packetsTransmitted == 0 { return nil }
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion SwiftyPingTest/SwiftyPingTest/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ViewController: UIViewController {
message = error.localizedDescription
}
}
self.textView.text.append(contentsOf: "\nPing #\(response.sequenceNumber): \(message)")
self.textView.text.append(contentsOf: "\nPing #\(response.trueSequenceNumber): \(message)")
self.textView.scrollRangeToVisible(NSRange(location: self.textView.text.count - 1, length: 1))
}
}
Expand Down

0 comments on commit 05591bc

Please sign in to comment.