mirror of
https://github.com/HaishinKit/HaishinKit.swift.git
synced 2026-05-07 20:12:28 +00:00
Merge pull request #1842 from HaishinKit/feature/ipv6-srt
Added IPv6 support in the SRT protocol.
This commit is contained in:
@@ -1,30 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
|
|
||||||
extension sockaddr_in {
|
|
||||||
var size: Int {
|
|
||||||
return MemoryLayout.size(ofValue: self)
|
|
||||||
}
|
|
||||||
|
|
||||||
init?(_ host: String, port: Int) {
|
|
||||||
self.init()
|
|
||||||
self.sin_family = sa_family_t(AF_INET)
|
|
||||||
self.sin_port = CFSwapInt16BigToHost(UInt16(port))
|
|
||||||
if inet_pton(AF_INET, host, &sin_addr) == 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let hostent = gethostbyname(host), hostent.pointee.h_addrtype == AF_INET else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if let h_addr_list = hostent.pointee.h_addr_list[0] {
|
|
||||||
self.sin_addr = UnsafeRawPointer(h_addr_list).assumingMemoryBound(to: in_addr.self).pointee
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutating func makeSockaddr() -> sockaddr {
|
|
||||||
var address = sockaddr()
|
|
||||||
memcpy(&address, &self, size)
|
|
||||||
return address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,7 @@ final actor SRTSocket {
|
|||||||
|
|
||||||
enum Error: Swift.Error {
|
enum Error: Swift.Error {
|
||||||
case notConnected
|
case notConnected
|
||||||
|
case invalidArgument(_ message: String)
|
||||||
case rejected(_ reason: SRTRejectReason)
|
case rejected(_ reason: SRTRejectReason)
|
||||||
case illegalState(_ message: String)
|
case illegalState(_ message: String)
|
||||||
}
|
}
|
||||||
@@ -128,28 +129,42 @@ final actor SRTSocket {
|
|||||||
let status: Int32 = try {
|
let status: Int32 = try {
|
||||||
switch url.mode {
|
switch url.mode {
|
||||||
case .caller:
|
case .caller:
|
||||||
guard var remote = url.remote else {
|
guard let remote = url.remote else {
|
||||||
return SRT_ERROR
|
throw Error.invalidArgument("missing remote url")
|
||||||
|
}
|
||||||
|
return try remote.resolve(AI_ADDRCONFIG) { name, length in
|
||||||
|
srt_connect(socket, name, length)
|
||||||
}
|
}
|
||||||
var remoteaddr = remote.makeSockaddr()
|
|
||||||
return srt_connect(socket, &remoteaddr, Int32(remote.size))
|
|
||||||
case .listener:
|
case .listener:
|
||||||
guard var local = url.local else {
|
guard let local = url.local else {
|
||||||
return SRT_ERROR
|
throw Error.invalidArgument("missing local url")
|
||||||
}
|
}
|
||||||
var localaddr = local.makeSockaddr()
|
let _: Int32 = try local.resolve(AI_PASSIVE) { name, length in
|
||||||
let status = srt_bind(socket, &localaddr, Int32(local.size))
|
let status = srt_bind(socket, name, length)
|
||||||
guard status != SRT_ERROR else {
|
if status == SRT_ERROR {
|
||||||
throw makeSocketError()
|
return nil
|
||||||
|
} else {
|
||||||
|
return status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return srt_listen(socket, 1)
|
return srt_listen(socket, 1)
|
||||||
case .rendezvous:
|
case .rendezvous:
|
||||||
guard var remote = url.remote, var local = url.local else {
|
guard let remote = url.remote else {
|
||||||
return SRT_ERROR
|
throw Error.invalidArgument("missing remote url")
|
||||||
|
}
|
||||||
|
guard let local = url.local else {
|
||||||
|
throw Error.invalidArgument("missing local url")
|
||||||
|
}
|
||||||
|
return try remote.resolve(AI_PASSIVE | AI_ADDRCONFIG) { remotename, remotelen in
|
||||||
|
return try local.resolve(AI_PASSIVE | AI_ADDRCONFIG) { localname, locallen in
|
||||||
|
let status = srt_rendezvous(socket, localname, locallen, remotename, remotelen)
|
||||||
|
if status == SRT_ERROR {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var remoteaddr = remote.makeSockaddr()
|
|
||||||
var localaddr = local.makeSockaddr()
|
|
||||||
return srt_rendezvous(socket, &remoteaddr, Int32(remote.size), &localaddr, Int32(local.size))
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
guard status != SRT_ERROR else {
|
guard status != SRT_ERROR else {
|
||||||
|
|||||||
@@ -27,20 +27,20 @@ struct SRTSocketURL {
|
|||||||
let mode: SRTMode
|
let mode: SRTMode
|
||||||
let options: [SRTSocketOption]
|
let options: [SRTSocketOption]
|
||||||
|
|
||||||
var remote: sockaddr_in? {
|
var remote: AddrInfo? {
|
||||||
guard let host = url.host else {
|
guard let host = url.host else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return .init(host, port: url.port ?? Self.defaultPort)
|
return AddrInfo(host: host, port: url.port ?? Self.defaultPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
var local: sockaddr_in? {
|
var local: AddrInfo? {
|
||||||
let queryItems = Self.getQueryItems(url)
|
let queryItems = Self.getQueryItems(url)
|
||||||
let adapter = queryItems["adapter"] ?? "0.0.0.0"
|
let adapter = queryItems["adapter"] ?? "0.0.0.0"
|
||||||
if let port = queryItems["port"] {
|
if let port = queryItems["port"] {
|
||||||
return .init(adapter, port: Int(port) ?? url.port ?? Self.defaultPort)
|
return AddrInfo(host: adapter, port: Int(port) ?? url.port ?? Self.defaultPort)
|
||||||
}
|
}
|
||||||
return .init(adapter, port: url.port ?? Self.defaultPort)
|
return AddrInfo(host: adapter, port: url.port ?? Self.defaultPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
init?(_ url: URL?) {
|
init?(_ url: URL?) {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import Foundation
|
||||||
|
import libsrt
|
||||||
|
|
||||||
|
struct AddrInfo {
|
||||||
|
enum Error: Swift.Error {
|
||||||
|
case failedToGetaddrinfo(_ code: Int)
|
||||||
|
case failedToResolve
|
||||||
|
}
|
||||||
|
|
||||||
|
let host: String
|
||||||
|
let port: Int
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func resolve<R>(_ flags: Int32, lambda: (UnsafePointer<sockaddr>, Int32) throws -> R?) throws -> R {
|
||||||
|
var hints = addrinfo(
|
||||||
|
ai_flags: flags,
|
||||||
|
ai_family: AF_UNSPEC,
|
||||||
|
ai_socktype: SOCK_DGRAM,
|
||||||
|
ai_protocol: 0,
|
||||||
|
ai_addrlen: 0,
|
||||||
|
ai_canonname: nil,
|
||||||
|
ai_addr: nil,
|
||||||
|
ai_next: nil
|
||||||
|
)
|
||||||
|
var result: UnsafeMutablePointer<addrinfo>?
|
||||||
|
let rv = getaddrinfo(host, String(port), &hints, &result)
|
||||||
|
guard rv == 0 else {
|
||||||
|
throw Error.failedToGetaddrinfo(Int(rv))
|
||||||
|
}
|
||||||
|
defer {
|
||||||
|
freeaddrinfo(result)
|
||||||
|
}
|
||||||
|
var addr = sockaddr_storage()
|
||||||
|
var rp = result
|
||||||
|
while rp != nil {
|
||||||
|
if let ai = rp?.pointee {
|
||||||
|
memcpy(&addr, ai.ai_addr, Int(ai.ai_addrlen))
|
||||||
|
let result = withUnsafePointer(to: &addr) {
|
||||||
|
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||||
|
do {
|
||||||
|
return try lambda($0, Int32(ai.ai_addrlen))
|
||||||
|
} catch {
|
||||||
|
print("AddrInfo.resolve: lambda threw error for address \(host):\(port): \(error)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let result {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rp = rp?.pointee.ai_next
|
||||||
|
}
|
||||||
|
throw Error.failedToResolve
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user