Implemented a UDPConnection class as a wrapper around a UDP implementation
This commit is contained in:
@@ -10,6 +10,8 @@
|
|||||||
0434EAB818A3C318E433338A /* Pods_BitTorrentTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8680B0EA21B5A20E03DEE6D /* Pods_BitTorrentTests.framework */; };
|
0434EAB818A3C318E433338A /* Pods_BitTorrentTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8680B0EA21B5A20E03DEE6D /* Pods_BitTorrentTests.framework */; };
|
||||||
34D4082D0E0A2C899857DC89 /* Pods_BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B47AE52A67ECE61259FCDAD /* Pods_BitTorrent.framework */; };
|
34D4082D0E0A2C899857DC89 /* Pods_BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B47AE52A67ECE61259FCDAD /* Pods_BitTorrent.framework */; };
|
||||||
867491B4C409A91D4D72CCE7 /* Pods_BitTorrent_BitTorrentExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D97F9FB9F74204574FF6840B /* Pods_BitTorrent_BitTorrentExample.framework */; };
|
867491B4C409A91D4D72CCE7 /* Pods_BitTorrent_BitTorrentExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D97F9FB9F74204574FF6840B /* Pods_BitTorrent_BitTorrentExample.framework */; };
|
||||||
|
B50B24F71F0A553F00C23E7C /* UDPConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50B24F61F0A553B00C23E7C /* UDPConnectionTests.swift */; };
|
||||||
|
B50B24F91F0A554A00C23E7C /* UDPConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50B24F81F0A554A00C23E7C /* UDPConnection.swift */; };
|
||||||
B537CF061F03148B0084089B /* HTTPConnectionStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = B537CF051F03148B0084089B /* HTTPConnectionStub.swift */; };
|
B537CF061F03148B0084089B /* HTTPConnectionStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = B537CF051F03148B0084089B /* HTTPConnectionStub.swift */; };
|
||||||
B537CF461F031AD20084089B /* TestText.torrent in Resources */ = {isa = PBXBuildFile; fileRef = B5E9B0E31F02F9E700EF58E3 /* TestText.torrent */; };
|
B537CF461F031AD20084089B /* TestText.torrent in Resources */ = {isa = PBXBuildFile; fileRef = B5E9B0E31F02F9E700EF58E3 /* TestText.torrent */; };
|
||||||
B537CF491F031C3D0084089B /* BEncode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B54D0C1A1CA53983004343BD /* BEncode.framework */; };
|
B537CF491F031C3D0084089B /* BEncode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B54D0C1A1CA53983004343BD /* BEncode.framework */; };
|
||||||
@@ -25,6 +27,9 @@
|
|||||||
B5530DB51F03063E00F71CCD /* HTTPConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */; };
|
B5530DB51F03063E00F71CCD /* HTTPConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */; };
|
||||||
B55317DC1F02FC4D00909ADF /* TorrentHTTPTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */; };
|
B55317DC1F02FC4D00909ADF /* TorrentHTTPTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */; };
|
||||||
B55317E01F02FE1500909ADF /* URLEncodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */; };
|
B55317E01F02FE1500909ADF /* URLEncodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */; };
|
||||||
|
B556D5AE1F0BA1FD00277B8D /* GCDAsyncUdpSocketStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = B551C9541F0B9D3D004115CB /* GCDAsyncUdpSocketStub.swift */; };
|
||||||
|
B558F4831F0A647D00438BB4 /* InternetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B558F4821F0A647D00438BB4 /* InternetProtocol.swift */; };
|
||||||
|
B558F4851F0A73D000438BB4 /* InternetProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B558F4841F0A73D000438BB4 /* InternetProtocolTests.swift */; };
|
||||||
B56A8A071C83539300426AC8 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56A8A061C83539300426AC8 /* TestHelpers.swift */; };
|
B56A8A071C83539300426AC8 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56A8A061C83539300426AC8 /* TestHelpers.swift */; };
|
||||||
B585AB781C3833450093FA41 /* BitTorrent.h in Headers */ = {isa = PBXBuildFile; fileRef = B585AB771C3833450093FA41 /* BitTorrent.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
B585AB781C3833450093FA41 /* BitTorrent.h in Headers */ = {isa = PBXBuildFile; fileRef = B585AB771C3833450093FA41 /* BitTorrent.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
B585AB7F1C3833450093FA41 /* BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B585AB741C3833450093FA41 /* BitTorrent.framework */; };
|
B585AB7F1C3833450093FA41 /* BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B585AB741C3833450093FA41 /* BitTorrent.framework */; };
|
||||||
@@ -112,6 +117,8 @@
|
|||||||
8B47AE52A67ECE61259FCDAD /* Pods_BitTorrent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
8B47AE52A67ECE61259FCDAD /* Pods_BitTorrent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
99A91AD4708288B297A8B700 /* Pods-BitTorrentTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrentTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrentTests/Pods-BitTorrentTests.debug.xcconfig"; sourceTree = "<group>"; };
|
99A91AD4708288B297A8B700 /* Pods-BitTorrentTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrentTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrentTests/Pods-BitTorrentTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
A8680B0EA21B5A20E03DEE6D /* Pods_BitTorrentTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrentTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
A8680B0EA21B5A20E03DEE6D /* Pods_BitTorrentTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrentTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
B50B24F61F0A553B00C23E7C /* UDPConnectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDPConnectionTests.swift; sourceTree = "<group>"; };
|
||||||
|
B50B24F81F0A554A00C23E7C /* UDPConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDPConnection.swift; sourceTree = "<group>"; };
|
||||||
B537CF051F03148B0084089B /* HTTPConnectionStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnectionStub.swift; path = "HTTP Networking/HTTPConnectionStub.swift"; sourceTree = "<group>"; };
|
B537CF051F03148B0084089B /* HTTPConnectionStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnectionStub.swift; path = "HTTP Networking/HTTPConnectionStub.swift"; sourceTree = "<group>"; };
|
||||||
B54D0C141CA53983004343BD /* BEncode.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = BEncode.xcodeproj; path = Submodules/BEncodeSwift/BEncode.xcodeproj; sourceTree = "<group>"; };
|
B54D0C141CA53983004343BD /* BEncode.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = BEncode.xcodeproj; path = Submodules/BEncodeSwift/BEncode.xcodeproj; sourceTree = "<group>"; };
|
||||||
B54D0C231CA56A22004343BD /* TorrentMetaInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TorrentMetaInfo.swift; path = Models/TorrentMetaInfo.swift; sourceTree = "<group>"; };
|
B54D0C231CA56A22004343BD /* TorrentMetaInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TorrentMetaInfo.swift; path = Models/TorrentMetaInfo.swift; sourceTree = "<group>"; };
|
||||||
@@ -123,10 +130,13 @@
|
|||||||
B54D0C721CA5879E004343BD /* iphoneos.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = iphoneos.modulemap; sourceTree = "<group>"; };
|
B54D0C721CA5879E004343BD /* iphoneos.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = iphoneos.modulemap; sourceTree = "<group>"; };
|
||||||
B54D0C731CA587A9004343BD /* iphonesimulator.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = iphonesimulator.modulemap; sourceTree = "<group>"; };
|
B54D0C731CA587A9004343BD /* iphonesimulator.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = iphonesimulator.modulemap; sourceTree = "<group>"; };
|
||||||
B54D0C741CA587B5004343BD /* macosx.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = macosx.modulemap; sourceTree = "<group>"; };
|
B54D0C741CA587B5004343BD /* macosx.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = macosx.modulemap; sourceTree = "<group>"; };
|
||||||
|
B551C9541F0B9D3D004115CB /* GCDAsyncUdpSocketStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GCDAsyncUdpSocketStub.swift; sourceTree = "<group>"; };
|
||||||
B5530DB11F03063300F71CCD /* HTTPConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnection.swift; path = "HTTP Networking/HTTPConnection.swift"; sourceTree = "<group>"; };
|
B5530DB11F03063300F71CCD /* HTTPConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnection.swift; path = "HTTP Networking/HTTPConnection.swift"; sourceTree = "<group>"; };
|
||||||
B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnectionTests.swift; path = "HTTP Networking/HTTPConnectionTests.swift"; sourceTree = "<group>"; };
|
B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnectionTests.swift; path = "HTTP Networking/HTTPConnectionTests.swift"; sourceTree = "<group>"; };
|
||||||
B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TorrentHTTPTracker.swift; path = Tracker/TorrentHTTPTracker.swift; sourceTree = "<group>"; };
|
B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TorrentHTTPTracker.swift; path = Tracker/TorrentHTTPTracker.swift; sourceTree = "<group>"; };
|
||||||
B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = URLEncodeTests.swift; path = "HTTP Networking/URLEncodeTests.swift"; sourceTree = "<group>"; };
|
B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = URLEncodeTests.swift; path = "HTTP Networking/URLEncodeTests.swift"; sourceTree = "<group>"; };
|
||||||
|
B558F4821F0A647D00438BB4 /* InternetProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
B558F4841F0A73D000438BB4 /* InternetProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetProtocolTests.swift; sourceTree = "<group>"; };
|
||||||
B56A8A061C83539300426AC8 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestHelpers.swift; path = Utilities/TestHelpers.swift; sourceTree = "<group>"; };
|
B56A8A061C83539300426AC8 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestHelpers.swift; path = Utilities/TestHelpers.swift; sourceTree = "<group>"; };
|
||||||
B585AB741C3833450093FA41 /* BitTorrent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BitTorrent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
B585AB741C3833450093FA41 /* BitTorrent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BitTorrent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B585AB771C3833450093FA41 /* BitTorrent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitTorrent.h; sourceTree = "<group>"; };
|
B585AB771C3833450093FA41 /* BitTorrent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitTorrent.h; sourceTree = "<group>"; };
|
||||||
@@ -204,6 +214,18 @@
|
|||||||
name = Pods;
|
name = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B50B24F01F0A54C100C23E7C /* UDP Networking */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B558F4821F0A647D00438BB4 /* InternetProtocol.swift */,
|
||||||
|
B558F4841F0A73D000438BB4 /* InternetProtocolTests.swift */,
|
||||||
|
B50B24F81F0A554A00C23E7C /* UDPConnection.swift */,
|
||||||
|
B551C9541F0B9D3D004115CB /* GCDAsyncUdpSocketStub.swift */,
|
||||||
|
B50B24F61F0A553B00C23E7C /* UDPConnectionTests.swift */,
|
||||||
|
);
|
||||||
|
path = "UDP Networking";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
B54D0C131CA53979004343BD /* Frameworks */ = {
|
B54D0C131CA53979004343BD /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -306,6 +328,7 @@
|
|||||||
B54D0C251CA56A25004343BD /* Models */,
|
B54D0C251CA56A25004343BD /* Models */,
|
||||||
B54D0C291CA5785F004343BD /* Utilities */,
|
B54D0C291CA5785F004343BD /* Utilities */,
|
||||||
B5E9778F1CAFB2090038EBE7 /* HTTP Networking */,
|
B5E9778F1CAFB2090038EBE7 /* HTTP Networking */,
|
||||||
|
B50B24F01F0A54C100C23E7C /* UDP Networking */,
|
||||||
B585AB791C3833450093FA41 /* Info.plist */,
|
B585AB791C3833450093FA41 /* Info.plist */,
|
||||||
);
|
);
|
||||||
path = BitTorrent;
|
path = BitTorrent;
|
||||||
@@ -712,10 +735,12 @@
|
|||||||
B5F81E491F0436D600B25C70 /* TorrentPeer.swift in Sources */,
|
B5F81E491F0436D600B25C70 /* TorrentPeer.swift in Sources */,
|
||||||
B55317DC1F02FC4D00909ADF /* TorrentHTTPTracker.swift in Sources */,
|
B55317DC1F02FC4D00909ADF /* TorrentHTTPTracker.swift in Sources */,
|
||||||
B5E977961CAFB46B0038EBE7 /* String+URLEncode.swift in Sources */,
|
B5E977961CAFB46B0038EBE7 /* String+URLEncode.swift in Sources */,
|
||||||
|
B558F4831F0A647D00438BB4 /* InternetProtocol.swift in Sources */,
|
||||||
B54D0C7A1CA69FAD004343BD /* TorrentMetaInfo.swift in Sources */,
|
B54D0C7A1CA69FAD004343BD /* TorrentMetaInfo.swift in Sources */,
|
||||||
B5F81E4B1F04399800B25C70 /* TorrentTrackerResponse.swift in Sources */,
|
B5F81E4B1F04399800B25C70 /* TorrentTrackerResponse.swift in Sources */,
|
||||||
B54D0C7B1CA69FD8004343BD /* Data+sha1.swift in Sources */,
|
B54D0C7B1CA69FD8004343BD /* Data+sha1.swift in Sources */,
|
||||||
B5530DB21F03063300F71CCD /* HTTPConnection.swift in Sources */,
|
B5530DB21F03063300F71CCD /* HTTPConnection.swift in Sources */,
|
||||||
|
B50B24F91F0A554A00C23E7C /* UDPConnection.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -725,11 +750,14 @@
|
|||||||
files = (
|
files = (
|
||||||
B537CF061F03148B0084089B /* HTTPConnectionStub.swift in Sources */,
|
B537CF061F03148B0084089B /* HTTPConnectionStub.swift in Sources */,
|
||||||
B5BD7FD61F03032400621BC2 /* TorrentHTTPTrackerTests.swift in Sources */,
|
B5BD7FD61F03032400621BC2 /* TorrentHTTPTrackerTests.swift in Sources */,
|
||||||
|
B556D5AE1F0BA1FD00277B8D /* GCDAsyncUdpSocketStub.swift in Sources */,
|
||||||
B5530DB51F03063E00F71CCD /* HTTPConnectionTests.swift in Sources */,
|
B5530DB51F03063E00F71CCD /* HTTPConnectionTests.swift in Sources */,
|
||||||
B56A8A071C83539300426AC8 /* TestHelpers.swift in Sources */,
|
B56A8A071C83539300426AC8 /* TestHelpers.swift in Sources */,
|
||||||
B585AB841C3833450093FA41 /* BitTorrentTests.swift in Sources */,
|
B585AB841C3833450093FA41 /* BitTorrentTests.swift in Sources */,
|
||||||
B54D0C271CA56ADB004343BD /* TorrentMetaInfoTests.swift in Sources */,
|
B54D0C271CA56ADB004343BD /* TorrentMetaInfoTests.swift in Sources */,
|
||||||
B55317E01F02FE1500909ADF /* URLEncodeTests.swift in Sources */,
|
B55317E01F02FE1500909ADF /* URLEncodeTests.swift in Sources */,
|
||||||
|
B558F4851F0A73D000438BB4 /* InternetProtocolTests.swift in Sources */,
|
||||||
|
B50B24F71F0A553F00C23E7C /* UDPConnectionTests.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <CommonCrypto/CommonCrypto.h>
|
||||||
|
#import "GCDAsyncSocket.h"
|
||||||
|
#import "GCDAsyncUdpSocket.h"
|
||||||
|
#import "InternetProtocol.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// GCDAsyncUdpSocketProtocol.swift
|
||||||
|
// BitTorrent
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 04/07/2017.
|
||||||
|
// Copyright © 2017 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CocoaAsyncSocket
|
||||||
|
|
||||||
|
class GCDAsyncUdpSocketStub: GCDAsyncUdpSocket {
|
||||||
|
|
||||||
|
weak var _delegate: GCDAsyncUdpSocketDelegate?
|
||||||
|
|
||||||
|
override func delegate() -> GCDAsyncUdpSocketDelegate? {
|
||||||
|
return _delegate
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setDelegate(_ delegate: GCDAsyncUdpSocketDelegate?) {
|
||||||
|
_delegate = delegate
|
||||||
|
}
|
||||||
|
|
||||||
|
var bindToPortCalled = false
|
||||||
|
var bindToPortParameter: UInt16?
|
||||||
|
override func bind(toPort port: UInt16) throws {
|
||||||
|
bindToPortCalled = true
|
||||||
|
bindToPortParameter = port
|
||||||
|
}
|
||||||
|
|
||||||
|
var beginReceivingCalled = false
|
||||||
|
override func beginReceiving() throws {
|
||||||
|
beginReceivingCalled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var _delegateQueue: DispatchQueue?
|
||||||
|
|
||||||
|
override func delegateQueue() -> DispatchQueue? {
|
||||||
|
return _delegateQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
override func synchronouslySetDelegateQueue(_ delegateQueue: DispatchQueue?) {
|
||||||
|
_delegateQueue = delegateQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
var closeCalled = false
|
||||||
|
override func close() {
|
||||||
|
closeCalled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendCalled = false
|
||||||
|
var sendParameters: (data: Data, host: String, port: UInt16, timeout: TimeInterval, tag: Int)?
|
||||||
|
override func send(_ data: Data, toHost host: String, port: UInt16, withTimeout timeout: TimeInterval, tag: Int) {
|
||||||
|
sendCalled = true
|
||||||
|
sendParameters = (data, host, port, timeout, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// InternetProtocol.h
|
||||||
|
// BitTorrent
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 16/11/2014.
|
||||||
|
// Copyright (c) 2014 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface InternetProtocol : NSObject
|
||||||
|
|
||||||
|
+ (NSString *)getIPAddress:(BOOL)preferIPv4;
|
||||||
|
+ (NSDictionary *)getIPAddresses;
|
||||||
|
|
||||||
|
+ (NSString*)ipAddressOfHostname:(NSString*)hostName;
|
||||||
|
|
||||||
|
+ (NSString*)ipAddressFromSockAddrData:(NSData*)data;
|
||||||
|
+ (uint16_t)portFromSockAddrData:(NSData*)data;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
//
|
||||||
|
// InternetProtocol.m
|
||||||
|
// BitTorrent
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 16/11/2014.
|
||||||
|
// Copyright (c) 2014 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "InternetProtocol.h"
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#define IOS_CELLULAR @"pdp_ip0"
|
||||||
|
#define IOS_WIFI @"en0"
|
||||||
|
#define IP_ADDR_IPv4 @"ipv4"
|
||||||
|
#define IP_ADDR_IPv6 @"ipv6"
|
||||||
|
|
||||||
|
@implementation InternetProtocol
|
||||||
|
|
||||||
|
+ (NSString *)getIPAddress:(BOOL)preferIPv4 {
|
||||||
|
NSArray *searchArray = preferIPv4 ?
|
||||||
|
@[ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :
|
||||||
|
@[ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
|
||||||
|
|
||||||
|
NSDictionary *addresses = [self getIPAddresses];
|
||||||
|
NSLog(@"addresses: %@", addresses);
|
||||||
|
|
||||||
|
__block NSString *address;
|
||||||
|
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
|
||||||
|
{
|
||||||
|
address = addresses[key];
|
||||||
|
if(address) *stop = YES;
|
||||||
|
} ];
|
||||||
|
return address ? address : @"0.0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary *)getIPAddresses {
|
||||||
|
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
|
||||||
|
|
||||||
|
// retrieve the current interfaces - returns 0 on success
|
||||||
|
struct ifaddrs *interfaces;
|
||||||
|
if(!getifaddrs(&interfaces)) {
|
||||||
|
// Loop through linked list of interfaces
|
||||||
|
struct ifaddrs *interface;
|
||||||
|
for(interface=interfaces; interface; interface=interface->ifa_next) {
|
||||||
|
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
|
||||||
|
continue; // deeply nested code harder to read
|
||||||
|
}
|
||||||
|
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
|
||||||
|
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
|
||||||
|
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
|
||||||
|
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
|
||||||
|
NSString *type;
|
||||||
|
if(addr->sin_family == AF_INET) {
|
||||||
|
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
|
||||||
|
type = IP_ADDR_IPv4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
|
||||||
|
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
|
||||||
|
type = IP_ADDR_IPv6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(type) {
|
||||||
|
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
|
||||||
|
addresses[key] = [NSString stringWithUTF8String:addrBuf];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Free memory
|
||||||
|
freeifaddrs(interfaces);
|
||||||
|
}
|
||||||
|
return [addresses count] ? addresses : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(NSString *)ipAddressOfHostname:(NSString *)hostName {
|
||||||
|
struct hostent *host_entry = gethostbyname([hostName cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||||
|
char *buff;
|
||||||
|
if (host_entry != NULL) {
|
||||||
|
buff = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
|
||||||
|
NSString *ip = [NSString stringWithUTF8String:buff];
|
||||||
|
return ip;
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*)ipAddressFromSockAddrData:(NSData*)data {
|
||||||
|
struct sockaddr_in * socketAddress = (struct sockaddr_in *)data.bytes;
|
||||||
|
struct in_addr ipAsStruct = ((struct sockaddr_in)*(socketAddress)).sin_addr;
|
||||||
|
char *buff;
|
||||||
|
buff = inet_ntoa(ipAsStruct);
|
||||||
|
NSString *ip = [NSString stringWithUTF8String:buff];
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (uint16_t)portFromSockAddrData:(NSData*)data {
|
||||||
|
struct sockaddr_in * socketAddressPtr = (struct sockaddr_in *)data.bytes;
|
||||||
|
struct sockaddr_in socketAddress = ((struct sockaddr_in)*(socketAddressPtr));
|
||||||
|
return socketAddress.sin_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
//
|
||||||
|
// InternetProtocol.swift
|
||||||
|
// BitTorrent
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 03/07/2017.
|
||||||
|
// Copyright © 2017 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
let IOS_CELLULAR_INTERFACE_NAME = "pdp_ip0"
|
||||||
|
let IOS_WIFI_INTERFACE_NAME = "en0"
|
||||||
|
let IP_ADDR_IPv4_INTERFACE_NAME = "ipv4"
|
||||||
|
let IP_ADDR_IPv6_INTERFACE_NAME = "ipv6"
|
||||||
|
|
||||||
|
func ipAddress(fromSockAddrData data: Data) -> String? {
|
||||||
|
let socketAddress = data.withUnsafeBytes() { (pointer: UnsafePointer<sockaddr_in>) in
|
||||||
|
return pointer.pointee
|
||||||
|
}
|
||||||
|
guard let resultCString = inet_ntoa(socketAddress.sin_addr) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return String(cString: resultCString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func port(fromSockAddrData data: Data) -> UInt16 {
|
||||||
|
let socketAddress = data.withUnsafeBytes() { (pointer: UnsafePointer<sockaddr_in>) in
|
||||||
|
return pointer.pointee
|
||||||
|
}
|
||||||
|
return socketAddress.sin_port
|
||||||
|
}
|
||||||
|
|
||||||
|
// + (NSString*)ipAddressFromSockAddrData:(NSData*)data {
|
||||||
|
// struct sockaddr_in * socketAddress = (struct sockaddr_in *)data.bytes;
|
||||||
|
// struct in_addr ipAsStruct = ((struct sockaddr_in)*(socketAddress)).sin_addr;
|
||||||
|
// char *buff;
|
||||||
|
// buff = inet_ntoa(ipAsStruct);
|
||||||
|
// NSString *ip = [NSString stringWithUTF8String:buff];
|
||||||
|
// return ip;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// + (uint16_t)portFromSockAddrData:(NSData*)data {
|
||||||
|
// struct sockaddr_in * socketAddressPtr = (struct sockaddr_in *)data.bytes;
|
||||||
|
// struct sockaddr_in socketAddress = ((struct sockaddr_in)*(socketAddressPtr));
|
||||||
|
// return socketAddress.sin_port;
|
||||||
|
//}
|
||||||
|
|
||||||
|
func getIPAddress(of hostname: String) -> String? {
|
||||||
|
|
||||||
|
guard let hostnameCString = hostname.cString(using: .ascii),
|
||||||
|
let hostEntry = gethostbyname(hostnameCString)?.pointee,
|
||||||
|
let hostAddressList = hostEntry.h_addr_list?.pointee else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let firstHostAddress = hostAddressList.withMemoryRebound(to: in_addr.self, capacity: 1) { $0.pointee }
|
||||||
|
let firstHostAddressCString = inet_ntoa(firstHostAddress)!
|
||||||
|
return String(cString: firstHostAddressCString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocalIPAddress(preferIPv4: Bool = true) -> String? {
|
||||||
|
|
||||||
|
// Prefer wifi over cellular
|
||||||
|
let searchArray = preferIPv4 ?
|
||||||
|
[
|
||||||
|
IOS_WIFI_INTERFACE_NAME + "/" + IP_ADDR_IPv4_INTERFACE_NAME,
|
||||||
|
IOS_WIFI_INTERFACE_NAME + "/" + IP_ADDR_IPv6_INTERFACE_NAME,
|
||||||
|
IOS_CELLULAR_INTERFACE_NAME + "/" + IP_ADDR_IPv4_INTERFACE_NAME,
|
||||||
|
IOS_CELLULAR_INTERFACE_NAME + "/" + IP_ADDR_IPv6_INTERFACE_NAME,
|
||||||
|
] :
|
||||||
|
[
|
||||||
|
IOS_WIFI_INTERFACE_NAME + "/" + IP_ADDR_IPv6_INTERFACE_NAME,
|
||||||
|
IOS_WIFI_INTERFACE_NAME + "/" + IP_ADDR_IPv4_INTERFACE_NAME,
|
||||||
|
IOS_CELLULAR_INTERFACE_NAME + "/" + IP_ADDR_IPv6_INTERFACE_NAME,
|
||||||
|
IOS_CELLULAR_INTERFACE_NAME + "/" + IP_ADDR_IPv4_INTERFACE_NAME,
|
||||||
|
]
|
||||||
|
|
||||||
|
let addresses = getLocalIPAddresses()
|
||||||
|
|
||||||
|
for searchItem in searchArray {
|
||||||
|
if let result = addresses[searchItem] {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocalIPAddresses() -> [String: String] {
|
||||||
|
|
||||||
|
var addresses: [String: String] = [:]
|
||||||
|
|
||||||
|
// Get list of all network interfaces on the local machine:
|
||||||
|
var ifaddrsPointer : UnsafeMutablePointer<ifaddrs>?
|
||||||
|
guard getifaddrs(&ifaddrsPointer) == 0, let ifaddrsList = ifaddrsPointer?.pointee else {
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each network interface ...
|
||||||
|
for ifaddrs in ifaddrsList {
|
||||||
|
if !ifaddrs.isUpAndRunning || ifaddrs.isLoopbackNet {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ifaddrs.isIpv4 || ifaddrs.isIpv6 {
|
||||||
|
if let addressString = ifaddrs.convertToIPString(), let name = ifaddrs.nameAndTypeString() {
|
||||||
|
addresses[name] = addressString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddrsPointer)
|
||||||
|
|
||||||
|
return addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ifaddrsIterator: IteratorProtocol {
|
||||||
|
public typealias Element = ifaddrs
|
||||||
|
|
||||||
|
var nextElement: ifaddrs?
|
||||||
|
|
||||||
|
init(first: ifaddrs) {
|
||||||
|
nextElement = first
|
||||||
|
}
|
||||||
|
|
||||||
|
public func next() -> ifaddrs? {
|
||||||
|
let result = nextElement
|
||||||
|
nextElement = result?.ifa_next?.pointee
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ifaddrs: Sequence {
|
||||||
|
public func makeIterator() -> ifaddrsIterator {
|
||||||
|
return ifaddrsIterator(first: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ifaddrs {
|
||||||
|
|
||||||
|
var name: String {
|
||||||
|
return String(cString: ifa_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isIpv4: Bool {
|
||||||
|
let addr = ifa_addr.pointee
|
||||||
|
return addr.sa_family == UInt8(AF_INET)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isIpv6: Bool {
|
||||||
|
let addr = ifa_addr.pointee
|
||||||
|
return addr.sa_family == UInt8(AF_INET6)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isUpAndRunning: Bool {
|
||||||
|
let flags = Int32(ifa_flags)
|
||||||
|
let upAndRunningFlags = (IFF_UP|IFF_RUNNING)
|
||||||
|
return (flags & upAndRunningFlags) == upAndRunningFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
var isLoopbackNet: Bool {
|
||||||
|
let flags = Int32(ifa_flags)
|
||||||
|
return (flags & IFF_LOOPBACK) == IFF_LOOPBACK
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertToIPString() -> String? {
|
||||||
|
return ifa_addr.pointee.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameAndTypeString() -> String? {
|
||||||
|
|
||||||
|
guard isIpv4 || isIpv6 else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "\(name) - " + (isIpv4 ? IP_ADDR_IPv4_INTERFACE_NAME : IP_ADDR_IPv6_INTERFACE_NAME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension sockaddr {
|
||||||
|
|
||||||
|
func toString() -> String? {
|
||||||
|
|
||||||
|
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
||||||
|
var addr = self
|
||||||
|
|
||||||
|
guard getnameinfo(&addr,
|
||||||
|
socklen_t(addr.sa_len),
|
||||||
|
&hostname,
|
||||||
|
socklen_t(hostname.count),
|
||||||
|
nil,
|
||||||
|
socklen_t(0),
|
||||||
|
NI_NUMERICHOST) == 0 else { return nil }
|
||||||
|
|
||||||
|
return String(validatingUTF8: hostname)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// InternetProtocolTests.swift
|
||||||
|
// BitTorrentTests
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 03/07/2017.
|
||||||
|
// Copyright © 2017 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import BitTorrent
|
||||||
|
|
||||||
|
class InternetProtocolTests: XCTestCase {
|
||||||
|
|
||||||
|
func test_canDecodeLocalhost() {
|
||||||
|
let result = getIPAddress(of: "localhost")
|
||||||
|
XCTAssertNotNil(result)
|
||||||
|
XCTAssertEqual(result!, "127.0.0.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_invalidHostnameReturnsNil() {
|
||||||
|
let result = getIPAddress(of: "asldfjhablskhdbj")
|
||||||
|
XCTAssertNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_nonAsciiHostnameReturnsNil() {
|
||||||
|
let result = getIPAddress(of: "🙁")
|
||||||
|
XCTAssertNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_canDecodeGoogle() {
|
||||||
|
let result = getIPAddress(of: "google.com")
|
||||||
|
XCTAssertNotNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_canDecodeIPv4AddressFromData() {
|
||||||
|
let data = Data(bytes: [16,2,122,105,127,0,0,1,0,0,0,0,0,0,0,0])
|
||||||
|
let result = ipAddress(fromSockAddrData: data)
|
||||||
|
XCTAssertNotNil(result)
|
||||||
|
XCTAssertEqual(result, "127.0.0.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_canDecodeSocketPortFromData() {
|
||||||
|
let data = Data(bytes: [16,2,122,105,127,0,0,1,0,0,0,0,0,0,0,0])
|
||||||
|
let result = port(fromSockAddrData: data)
|
||||||
|
XCTAssertNotNil(result)
|
||||||
|
XCTAssertEqual(result, 27002)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// UDPConnection.swift
|
||||||
|
// BitTorrent
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 03/07/2017.
|
||||||
|
// Copyright © 2017 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CocoaAsyncSocket
|
||||||
|
|
||||||
|
protocol UDPConnectionDelegate: class {
|
||||||
|
func udpConnection(_ sender: UDPConnection, receivedData data: Data, fromHost host: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This class is a thin wrapper around the socket library to protect against changes
|
||||||
|
/// in its interface, and to allow me to replace CocoaAsyncSocket with a swift framework
|
||||||
|
/// one day.
|
||||||
|
class UDPConnection: NSObject {
|
||||||
|
|
||||||
|
weak var delegate: UDPConnectionDelegate?
|
||||||
|
|
||||||
|
private let socket: GCDAsyncUdpSocket
|
||||||
|
|
||||||
|
// Designated init for testing
|
||||||
|
init(socket: GCDAsyncUdpSocket) {
|
||||||
|
self.socket = socket
|
||||||
|
super.init()
|
||||||
|
socket.setDelegate(self)
|
||||||
|
socket.synchronouslySetDelegateQueue(.main)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Useful init which should be used
|
||||||
|
override convenience init() {
|
||||||
|
self.init(socket: GCDAsyncUdpSocket())
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
socket.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func startListening(on port: UInt16) {
|
||||||
|
try? socket.bind(toPort: port)
|
||||||
|
try? socket.beginReceiving()
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(_ data: Data, toHost host: String, port: UInt16, timeout: TimeInterval) {
|
||||||
|
socket.send(data, toHost: host, port: port, withTimeout: timeout, tag: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UDPConnection: GCDAsyncUdpSocketDelegate {
|
||||||
|
|
||||||
|
func udpSocket(_ sock: GCDAsyncUdpSocket,
|
||||||
|
didReceive data: Data,
|
||||||
|
fromAddress address: Data,
|
||||||
|
withFilterContext filterContext: Any?) {
|
||||||
|
|
||||||
|
let hostString = ipAddress(fromSockAddrData: address)!
|
||||||
|
delegate?.udpConnection(self, receivedData: data, fromHost: hostString)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
//
|
||||||
|
// UDPConnectionTests.swift
|
||||||
|
// BitTorrentTests
|
||||||
|
//
|
||||||
|
// Created by Ben Davis on 03/07/2017.
|
||||||
|
// Copyright © 2017 Ben Davis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
import CocoaAsyncSocket
|
||||||
|
@testable import BitTorrent
|
||||||
|
|
||||||
|
class UDPConnectionDelegateTestingStub: UDPConnectionDelegate {
|
||||||
|
|
||||||
|
var receivedDataCalled = false
|
||||||
|
var receivedDataParameters: (sender: UDPConnection, data: Data, host: String)?
|
||||||
|
func udpConnection(_ sender: UDPConnection, receivedData data: Data, fromHost host: String) {
|
||||||
|
receivedDataCalled = true
|
||||||
|
receivedDataParameters = (sender, data, host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UDPConnectionTests: XCTestCase {
|
||||||
|
|
||||||
|
var socket: GCDAsyncUdpSocketStub!
|
||||||
|
var delegate: UDPConnectionDelegateTestingStub!
|
||||||
|
var sut: UDPConnection!
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
|
||||||
|
socket = GCDAsyncUdpSocketStub()
|
||||||
|
delegate = UDPConnectionDelegateTestingStub()
|
||||||
|
sut = UDPConnection(socket: socket)
|
||||||
|
sut.delegate = delegate
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_isSocketDelegate() {
|
||||||
|
XCTAssert(socket._delegate === sut)
|
||||||
|
XCTAssert(socket._delegateQueue === DispatchQueue.main)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_canStartListeningOnPort() {
|
||||||
|
|
||||||
|
let port: UInt16 = 123
|
||||||
|
sut.startListening(on: port)
|
||||||
|
|
||||||
|
XCTAssert(socket.bindToPortCalled)
|
||||||
|
XCTAssertEqual(socket.bindToPortParameter, port)
|
||||||
|
XCTAssert(socket.beginReceivingCalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_socketClosedOnDeinit() {
|
||||||
|
sut = nil
|
||||||
|
XCTAssert(socket.closeCalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Receiving data
|
||||||
|
|
||||||
|
func test_canRecieveData() {
|
||||||
|
|
||||||
|
// 127.0.0.1:27002
|
||||||
|
let addressData = Data(bytes: [16,2,122,105,127,0,0,1,0,0,0,0,0,0,0,0])
|
||||||
|
let packetData = Data(bytes: [1,2,3])
|
||||||
|
|
||||||
|
sut.udpSocket(socket, didReceive: packetData, fromAddress: addressData, withFilterContext: nil)
|
||||||
|
|
||||||
|
XCTAssert(delegate.receivedDataCalled)
|
||||||
|
XCTAssertEqual(delegate.receivedDataParameters?.sender, sut)
|
||||||
|
XCTAssertEqual(delegate.receivedDataParameters?.data, packetData)
|
||||||
|
XCTAssertEqual(delegate.receivedDataParameters?.host, "127.0.0.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Sending data
|
||||||
|
|
||||||
|
func test_canSendData() {
|
||||||
|
|
||||||
|
let data = Data(bytes: [1,2,3])
|
||||||
|
let host = "127.0.0.1"
|
||||||
|
let port: UInt16 = 3475
|
||||||
|
let timeout: TimeInterval = 10
|
||||||
|
|
||||||
|
sut.send(data, toHost: host, port: port, timeout: timeout)
|
||||||
|
|
||||||
|
XCTAssert(socket.sendCalled)
|
||||||
|
XCTAssertEqual(socket.sendParameters!.data, data)
|
||||||
|
XCTAssertEqual(socket.sendParameters!.host, host)
|
||||||
|
XCTAssertEqual(socket.sendParameters!.port, port)
|
||||||
|
XCTAssertEqual(socket.sendParameters!.timeout, timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
@testable import BitTorrent
|
@testable import BitTorrent
|
||||||
import BlueSocket
|
|
||||||
|
|
||||||
@UIApplicationMain
|
@UIApplicationMain
|
||||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
class AppDelegate: UIResponder, UIApplicationDelegate, UDPConnectionDelegate {
|
||||||
|
|
||||||
var window: UIWindow?
|
var window: UIWindow?
|
||||||
|
|
||||||
var tracker: TorrentHTTPTracker!
|
var tracker: TorrentHTTPTracker!
|
||||||
|
var udpConnection: UDPConnection!
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||||
window = UIWindow(frame: UIScreen.main.bounds)
|
window = UIWindow(frame: UIScreen.main.bounds)
|
||||||
@@ -39,10 +39,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
// numberOfBytesDownloaded: 0,
|
// numberOfBytesDownloaded: 0,
|
||||||
// numberOfPeersToFetch: 50)
|
// numberOfPeersToFetch: 50)
|
||||||
|
|
||||||
let mySocket = try! Socket.create()
|
// let mySocket = try! Socket.create()
|
||||||
print(mySocket)
|
// print(mySocket)
|
||||||
|
|
||||||
|
udpConnection = UDPConnection()
|
||||||
|
udpConnection.delegate = self
|
||||||
|
|
||||||
|
udpConnection.startListening(on: 59740)
|
||||||
|
|
||||||
|
let data = "Hello, world!".data(using: .utf8)!
|
||||||
|
udpConnection.send(data, toHost: "127.0.0.1", port: 31337, timeout: 10000)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension UDPConnectionDelegate {
|
||||||
|
|
||||||
|
func udpConnection(_ sender: UDPConnection, receivedData data: Data, fromHost host: String) {
|
||||||
|
print(sender, data, host)
|
||||||
|
print(data == "Hello, world!".data(using: .utf8)! ? "Success" : "Fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ target 'BitTorrent' do
|
|||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
pod 'Alamofire', '4.5.0'
|
pod 'Alamofire', '4.5.0'
|
||||||
pod 'BlueSocket'
|
pod 'CocoaAsyncSocket'
|
||||||
|
|
||||||
target 'BitTorrentTests' do
|
target 'BitTorrentTests' do
|
||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- Alamofire (4.5.0)
|
- Alamofire (4.5.0)
|
||||||
- BlueSocket (0.12.16)
|
- CocoaAsyncSocket (7.6.1)
|
||||||
- OHHTTPStubs (6.0.0):
|
- OHHTTPStubs (6.0.0):
|
||||||
- OHHTTPStubs/Default (= 6.0.0)
|
- OHHTTPStubs/Default (= 6.0.0)
|
||||||
- OHHTTPStubs/Core (6.0.0)
|
- OHHTTPStubs/Core (6.0.0)
|
||||||
@@ -17,14 +17,14 @@ PODS:
|
|||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Alamofire (= 4.5.0)
|
- Alamofire (= 4.5.0)
|
||||||
- BlueSocket
|
- CocoaAsyncSocket
|
||||||
- OHHTTPStubs
|
- OHHTTPStubs
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||||
BlueSocket: 13bf1daf94a316e9efe93aa125cc33b8c3dd6c35
|
CocoaAsyncSocket: 7eadd3f59e1a6c84e2aefc93e9ff7b55156fe174
|
||||||
OHHTTPStubs: 752f9b11fd810a15162d50f11c06ff94f8e012eb
|
OHHTTPStubs: 752f9b11fd810a15162d50f11c06ff94f8e012eb
|
||||||
|
|
||||||
PODFILE CHECKSUM: 0d38beb67a05d0be9e85d2555a9fbc44ecf5e80c
|
PODFILE CHECKSUM: 0357d6a70a8533160f506a62590771b1f36ca2cc
|
||||||
|
|
||||||
COCOAPODS: 1.2.0
|
COCOAPODS: 1.2.0
|
||||||
|
|||||||
Reference in New Issue
Block a user