Fixed false assumption that all data instances are 0-indexed

This commit is contained in:
Ben Davis
2017-11-04 18:11:23 +08:00
parent dffbaa6cf3
commit 6c868a9692
16 changed files with 116 additions and 56 deletions
+4
View File
@@ -79,6 +79,7 @@
B5AF7AAA1F252A79003FD66F /* MultFileHandleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AF7AA81F252A70003FD66F /* MultFileHandleTests.swift */; };
B5AF7AAD1F253055003FD66F /* FileHandleFake.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AF7AAC1F253055003FD66F /* FileHandleFake.swift */; };
B5BD7FD61F03032400621BC2 /* TorrentHTTPTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BD7FD51F03032400621BC2 /* TorrentHTTPTrackerTests.swift */; };
B5BF03EC1FADC54900DF13D5 /* IndexCorrectedDataSlice.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BF03EB1FADC54900DF13D5 /* IndexCorrectedDataSlice.swift */; };
B5BFD9CC1F3FAF9A00CE0186 /* TorrentTrackerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BFD9CB1F3FAF9A00CE0186 /* TorrentTrackerManager.swift */; };
B5BFD9CE1F3FAFA500CE0186 /* TorrentTrackerManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BFD9CD1F3FAFA500CE0186 /* TorrentTrackerManagerTests.swift */; };
B5BFD9D01F3FB13E00CE0186 /* TorrentTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BFD9CF1F3FB13E00CE0186 /* TorrentTracker.swift */; };
@@ -245,6 +246,7 @@
B5AF7AA81F252A70003FD66F /* MultFileHandleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultFileHandleTests.swift; sourceTree = "<group>"; };
B5AF7AAC1F253055003FD66F /* FileHandleFake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileHandleFake.swift; sourceTree = "<group>"; };
B5BD7FD51F03032400621BC2 /* TorrentHTTPTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentHTTPTrackerTests.swift; sourceTree = "<group>"; };
B5BF03EB1FADC54900DF13D5 /* IndexCorrectedDataSlice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndexCorrectedDataSlice.swift; sourceTree = "<group>"; };
B5BFD9CB1F3FAF9A00CE0186 /* TorrentTrackerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentTrackerManager.swift; sourceTree = "<group>"; };
B5BFD9CD1F3FAFA500CE0186 /* TorrentTrackerManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentTrackerManagerTests.swift; sourceTree = "<group>"; };
B5BFD9CF1F3FB13E00CE0186 /* TorrentTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentTracker.swift; sourceTree = "<group>"; };
@@ -435,6 +437,7 @@
B514DD8E1F40C53C00C932F8 /* NetworkSpeedTrackerTests.swift */,
B514DD9B1F40DD1B00C932F8 /* URL.swift */,
B501A5571F557E9E00B87911 /* RandomEnumeration.swift */,
B5BF03EB1FADC54900DF13D5 /* IndexCorrectedDataSlice.swift */,
);
path = Utilities;
sourceTree = "<group>";
@@ -1019,6 +1022,7 @@
B5C06F131F12CDD8005730B3 /* TorrentPeer.swift in Sources */,
B5F81E4B1F04399800B25C70 /* TorrentTrackerResponse.swift in Sources */,
B501A5661F55B24B00B87911 /* TorrentServer.swift in Sources */,
B5BF03EC1FADC54900DF13D5 /* IndexCorrectedDataSlice.swift in Sources */,
B5AF7AA61F252A66003FD66F /* MultiFileHandle.swift in Sources */,
B54D0C7B1CA69FD8004343BD /* Data+sha1.swift in Sources */,
B5F27C5D1F3F7BDD0040589C /* TorrentPeerManager.swift in Sources */,
+1 -1
View File
@@ -24,7 +24,7 @@ class FileHandleFake: FileHandleProtocol {
func readData(ofLength length: Int) -> Data {
let beginOffset = currentOffset
currentOffset += length
return data[beginOffset ..< currentOffset]
return data.correctingIndicies[beginOffset ..< currentOffset]
}
func write(_ data: Data) {
@@ -87,8 +87,8 @@ class MultiFileHandle: FileHandleProtocol {
private func writeDataToEndOfCurrentFile(_ data: Data) -> Data? {
guard remainingInCurrentFile >= data.count else {
let dataToWrite = data[0 ..< Int(remainingInCurrentFile)]
let remaining = data[Int(remainingInCurrentFile) ..< data.count]
let dataToWrite = data.correctingIndicies[0 ..< Int(remainingInCurrentFile)]
let remaining = data.correctingIndicies[Int(remainingInCurrentFile) ..< data.count]
currentFile.handle.write(dataToWrite)
incrementCurrentFile()
return remaining
@@ -42,7 +42,7 @@ class TorrentFileManagerTests: XCTestCase {
sut.setPiece(at: 1, data: piece1)
// Then
XCTAssertEqualData(fileHandle.data[pieceLength..<pieceLength*2], piece1)
XCTAssertEqualData(fileHandle.data.correctingIndicies[pieceLength..<pieceLength*2], piece1)
}
func test_canGetPiece() {
@@ -24,7 +24,7 @@ extension String {
for i in 0..<data.count {
let byte = data[i]
let byte = data.correctingIndicies[i]
if byte == asciiSpace {
result.append("%20")
+1 -1
View File
@@ -23,7 +23,7 @@ public struct BitField: Equatable {
init(data: Data) {
self.init(size: data.count*8)
for byteIndex in 0 ..< data.count {
let byte = data[byteIndex]
let byte = data.correctingIndicies[byteIndex]
for i in 0 ..< 8 {
if isNthBitSet(byte, n: i) {
set(at: byteIndex*8 + i)
+5 -5
View File
@@ -36,11 +36,11 @@ struct TorrentPeerInfo {
let numberOfPeers = data.count / 6
var result: [TorrentPeerInfo] = []
for i in 0..<numberOfPeers {
let ip1 = Int(data[i*6])
let ip2 = Int(data[i*6 + 1])
let ip3 = Int(data[i*6 + 2])
let ip4 = Int(data[i*6 + 3])
let portBytes = [data[i*6 + 5], data[i*6 + 4]]
let ip1 = Int(data.correctingIndicies[i*6])
let ip2 = Int(data.correctingIndicies[i*6 + 1])
let ip3 = Int(data.correctingIndicies[i*6 + 2])
let ip4 = Int(data.correctingIndicies[i*6 + 3])
let portBytes = [data.correctingIndicies[i*6 + 5], data.correctingIndicies[i*6 + 4]]
let port = UnsafePointer(portBytes).withMemoryRebound(to: UInt16.self, capacity: 1) {
$0.pointee
@@ -44,7 +44,7 @@ class TorrentPeerHandshakeMessageBuffer {
return
}
let pstrLen = buffer[0]
let pstrLen = buffer.correctingIndicies[0]
guard pstrLen == 19 else {
delegate?.peerHandshakeMessageBuffer(self, gotBadHandshake: .protocolMismatch)
@@ -55,7 +55,7 @@ class TorrentPeerHandshakeMessageBuffer {
return
}
let protocolStringBytes = Data(buffer[1..<20])
let protocolStringBytes = buffer.correctingIndicies[1..<20]
let protocolString = String(data: protocolStringBytes, encoding: .ascii)
guard protocolString == "BitTorrent protocol" else {
delegate?.peerHandshakeMessageBuffer(self, gotBadHandshake: .protocolMismatch)
@@ -66,7 +66,7 @@ class TorrentPeerHandshakeMessageBuffer {
return
}
let infoHash = Data(buffer[28..<48])
let infoHash = buffer.correctingIndicies[28..<48]
guard infoHash == expectedInfoHash else {
delegate?.peerHandshakeMessageBuffer(self, gotBadHandshake: .infoHashMismatch)
@@ -77,16 +77,16 @@ class TorrentPeerHandshakeMessageBuffer {
return
}
let peerId = Data(buffer[48..<68])
let peerId = Data(buffer.correctingIndicies[48..<68])
guard expectedPeerId == nil || peerId == expectedPeerId else {
delegate?.peerHandshakeMessageBuffer(self, gotBadHandshake: .peerIdMismatch)
return
}
let reservedBytes = buffer[20..<28]
let onDHT = (reservedBytes[7] & UInt8(1)) == 1
let remainingBytes = Data(buffer[68..<buffer.count])
let reservedBytes = Data(buffer.correctingIndicies[20..<28])
let onDHT = (reservedBytes.correctingIndicies[7] & UInt8(1)) == 1
let remainingBytes = Data(buffer.correctingIndicies[68..<buffer.count])
delegate?.peerHandshakeMessageBuffer(self,
gotHandshakeWithPeerId: peerId,
@@ -69,8 +69,8 @@ class TorrentPeerHandshakeMessageBufferTests: XCTestCase {
data = data + infoHash // info_hash
data = data + peerId // peer_id
let data1 = data[0..<30]
let data2 = data[30..<data.count]
let data1 = data.correctingIndicies[0..<30]
let data2 = data.correctingIndicies[30..<data.count]
sut.appendData(data1)
XCTAssertFalse(delegate.gotHandshakeCalled)
@@ -29,13 +29,13 @@ class TorrentPeerMessageBuffer {
return
}
let lengthPrefix = buffer[0..<4]
let lengthPrefix = buffer.correctingIndicies[0..<4]
let expectedLength = Int(UInt32(data: lengthPrefix)) + 4
if buffer.count >= expectedLength {
let message = buffer[0..<expectedLength]
let message = buffer.correctingIndicies[0..<expectedLength]
delegate?.peerMessageBuffer(self, gotMessage: message)
buffer = Data(buffer[expectedLength..<buffer.count])
buffer = buffer.correctingIndicies[expectedLength..<buffer.count]
testIfBufferContainsCompletedMessage()
}
}
@@ -285,7 +285,7 @@ extension TorrentPeerCommunicator: TorrentPeerMessageBufferDelegate {
return
}
guard let message = Message(rawValue: data[4]) else {
guard let message = Message(rawValue: data.correctingIndicies[4]) else {
if enableLogging { print("Peer sent malformed message") }
delegate?.peerSentMalformedMessage(self)
return
@@ -329,34 +329,34 @@ extension TorrentPeerCommunicator: TorrentPeerMessageBufferDelegate {
}
private func processHasPieceMessage(_ message: Data) {
let pieceIndex = Int(UInt32(data: message[5 ..< 9]))
let pieceIndex = Int(UInt32(data: message.correctingIndicies[5 ..< 9]))
delegate?.peer(self, hasPiece: pieceIndex)
}
private func processBitFieldMessage(_ message: Data) {
let bitFieldData = message[5 ..< message.count]
let bitFieldData = message.correctingIndicies[5 ..< message.count]
let bitField = BitField(data: bitFieldData)
delegate?.peer(self, hasBitField: bitField)
}
private func processRequestMessage(_ message: Data) {
let pieceIndex = Int(UInt32(data: message[5 ..< 9]))
let begin = Int(UInt32(data: message[9 ..< 13]))
let length = Int(UInt32(data: message[13 ..< 17]))
let pieceIndex = Int(UInt32(data: message.correctingIndicies[5 ..< 9]))
let begin = Int(UInt32(data: message.correctingIndicies[9 ..< 13]))
let length = Int(UInt32(data: message.correctingIndicies[13 ..< 17]))
delegate?.peer(self, requestedPiece: pieceIndex, begin: begin, length: length)
}
private func processSentPieceMessage(_ message: Data) {
let pieceIndex = Int(UInt32(data: message[5 ..< 9]))
let begin = Int(UInt32(data: message[9 ..< 13]))
let block = message[13 ..< message.count]
let pieceIndex = Int(UInt32(data: message.correctingIndicies[5 ..< 9]))
let begin = Int(UInt32(data: message.correctingIndicies[9 ..< 13]))
let block = message.correctingIndicies[13 ..< message.count]
delegate?.peer(self, sentPiece: pieceIndex, begin: begin, block: block)
}
private func processCancelRequestMessage(_ message: Data) {
let pieceIndex = Int(UInt32(data: message[5 ..< 9]))
let begin = Int(UInt32(data: message[9 ..< 13]))
let length = Int(UInt32(data: message[13 ..< 17]))
let pieceIndex = Int(UInt32(data: message.correctingIndicies[5 ..< 9]))
let begin = Int(UInt32(data: message.correctingIndicies[9 ..< 13]))
let length = Int(UInt32(data: message.correctingIndicies[13 ..< 17]))
delegate?.peer(self, cancelledRequestedPiece: pieceIndex, begin: begin, length: length)
}
}
@@ -45,7 +45,7 @@ class TorrentUploadPieceRequest {
let begin = request.begin
let end = begin + request.length
let blockData = data[begin..<end]
let blockData = data.correctingIndicies[begin..<end]
return TorrentBlock(piece: request.piece,
begin: request.begin,
length: request.length,
+9 -9
View File
@@ -107,7 +107,7 @@ extension TorrentUDPTracker: UDPConnectionDelegate {
func udpConnection(_ sender: UDPConnectionProtocol, receivedData data: Data, fromHost host: String) {
let action = Data(data[0..<4])
let action = data.correctingIndicies[0..<4]
log("Got response from UDP tracker \(host)")
@@ -125,8 +125,8 @@ extension TorrentUDPTracker: UDPConnectionDelegate {
func parseConnectionResponse(_ response: Data) {
let transactionId = Data(response[4..<8])
let connectionId = Data(response[8..<16])
let transactionId = response.correctingIndicies[4..<8]
let connectionId = response.correctingIndicies[8..<16]
pendingAnnounce?(transactionId, connectionId)
pendingAnnounce = nil
@@ -134,13 +134,13 @@ extension TorrentUDPTracker: UDPConnectionDelegate {
private func parseAnnounceResponse(_ response: Data) {
let transactionId = Data(response[4..<8])
let transactionId = response.correctingIndicies[4..<8]
guard pendingTransactionId == transactionId else { return }
let interval = response[8..<12].toUInt32()
let leechers = response[12..<16].toUInt32()
let seeders = response[16..<20].toUInt32()
let peers = TorrentPeerInfo.peersInfoFromBinaryModel(response[20..<response.count])
let interval = response.correctingIndicies[8..<12].toUInt32()
let leechers = response.correctingIndicies[12..<16].toUInt32()
let seeders = response.correctingIndicies[16..<20].toUInt32()
let peers = TorrentPeerInfo.peersInfoFromBinaryModel(response.correctingIndicies[20..<response.count])
let response = TorrentTrackerResponse(peers: peers,
numberOfPeersComplete: Int(seeders),
@@ -152,7 +152,7 @@ extension TorrentUDPTracker: UDPConnectionDelegate {
private func parseErrorResponse(_ response: Data) {
if let errorMessage = String(data: response[8..<response.count], encoding: .utf8) {
if let errorMessage = String(data: response.correctingIndicies[8..<response.count], encoding: .utf8) {
delegate?.torrentTracker(self, receivedErrorMessage: errorMessage)
}
}
+10 -10
View File
@@ -89,10 +89,10 @@ class TorrentUDPTrackerTests: XCTestCase {
XCTAssertEqual(parameters.data.count, 16)
let protocolId = Data(parameters.data[0..<8])
let protocolId = Data(parameters.data.correctingIndicies[0..<8])
XCTAssertEqual(protocolId, expectedProtocolId)
let action = Data(parameters.data[8..<12])
let action = Data(parameters.data.correctingIndicies[8..<12])
XCTAssertEqual(action, expectedAction)
XCTAssertEqual(parameters.host, "127.0.0.1")
@@ -113,10 +113,10 @@ class TorrentUDPTrackerTests: XCTestCase {
XCTAssertEqual(udpConnection.sendCallCount, 2)
if let parameters = udpConnection.sendDataParameters {
let connectionId = Data(parameters.data[0..<8])
let connectionId = parameters.data.correctingIndicies[0..<8]
XCTAssertEqual(connectionId, expectedConnectionId)
let action = Data(parameters.data[8..<12])
let action = parameters.data.correctingIndicies[8..<12]
XCTAssertEqual(action, expectedAction)
}
}
@@ -155,7 +155,7 @@ class TorrentUDPTrackerTests: XCTestCase {
// Then
XCTAssertEqual(udpConnection.sendCallCount, 2)
if let data = udpConnection.sendDataParameters?.data {
if let data = udpConnection.sendDataParameters?.data.correctingIndicies {
XCTAssertEqual(data.count, 98)
@@ -260,7 +260,7 @@ class TorrentUDPTrackerTests: XCTestCase {
performAnnounce(withEvent: .started)
_ = simulateAcceptConnection()
guard let connectionParameters = udpConnection.sendDataParameters else { return }
let oldTransactionId = connectionParameters.data[4..<8]
let oldTransactionId = connectionParameters.data.correctingIndicies[4..<8]
// When
performAnnounce(withEvent: .started)
@@ -276,7 +276,7 @@ class TorrentUDPTrackerTests: XCTestCase {
// Given
performAnnounce(withEvent: .started)
guard let connectionParameters = udpConnection.sendDataParameters else { return }
let oldTransactionId = connectionParameters.data[4..<8]
let oldTransactionId = connectionParameters.data.correctingIndicies[4..<8]
// When
performAnnounce(withEvent: .started)
@@ -301,7 +301,7 @@ class TorrentUDPTrackerTests: XCTestCase {
peers: Data) {
guard let announceParameters = udpConnection.sendDataParameters else { return }
let transactionId = announceParameters.data[12..<16]
let transactionId = announceParameters.data.correctingIndicies[12..<16]
simulateAnnounceResponse(interval: interval,
leechers: leechers,
@@ -336,7 +336,7 @@ class TorrentUDPTrackerTests: XCTestCase {
return connectionId
}
let transactionId = connectionParameters.data[12..<16]
let transactionId = connectionParameters.data.correctingIndicies[12..<16]
let actionData = UInt32(0).toData() // Action 0 = connection
let connectionResponse = actionData + transactionId + connectionId
@@ -359,7 +359,7 @@ class TorrentUDPTrackerTests: XCTestCase {
func simulateErrorResponse(withError errorString: String) {
guard let connectionParameters = udpConnection.sendDataParameters else { return }
let transactionId = connectionParameters.data[4..<8]
let transactionId = connectionParameters.data.correctingIndicies[4..<8]
let connectionResponse = UInt32(3).toData() + // Action 3 = error
transactionId + // Responding to transaction
@@ -0,0 +1,56 @@
//
// Data+subscript.swift
// BitTorrent
//
// Created by Ben Davis on 03/11/2017.
// Copyright © 2017 Ben Davis. All rights reserved.
//
import Foundation
/// This class wraps a Data instance to guarantee that the byte at index 0
/// is the first byte in the represented data, regardless of whether the instance
/// represents a slice of a different Data instance.
///
/// For example:
/// ```
/// let data = Data(bytes: [1,2,3])
/// let slice = data[1..<3] // represents data with bytes [2,3]
/// print(slice[1]) // prints '2'
/// print(slice.correctingIndicies[1]) // prints '3'
/// ```
struct IndexCorrectedDataSlice: Collection {
private let originalData: Data
let startIndex = 0
let endIndex: Int
fileprivate init(originalData: Data) {
self.originalData = originalData
self.endIndex = originalData.distance(from: originalData.startIndex,
to: originalData.endIndex)
}
/// Note: The resulting data shares indicies with the original Data instance.
subscript(_ range: Range<Int>) -> Data {
let actualLowerBound = originalData.startIndex + range.lowerBound
let actualUpperBound = originalData.startIndex + range.upperBound
return originalData[actualLowerBound ..< actualUpperBound]
}
subscript(_ index: Int) -> UInt8 {
let correctedIndex = originalData.startIndex + index
return originalData[correctedIndex]
}
func index(after i: Int) -> Int {
return i + 1
}
}
extension Data {
var correctingIndicies: IndexCorrectedDataSlice {
return IndexCorrectedDataSlice(originalData: self)
}
}