diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/jaegertracing/thrift/lib/swift/Sources | |
parent | Initial commit. (diff) | |
download | ceph-upstream/16.2.11+ds.tar.xz ceph-upstream/16.2.11+ds.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
31 files changed, 4208 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/swift/Sources/LinuxHelper.swift b/src/jaegertracing/thrift/lib/swift/Sources/LinuxHelper.swift new file mode 100644 index 000000000..66d92bb4d --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/LinuxHelper.swift @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import Foundation +import CoreFoundation + +#if os(Linux) +/// Extensions for Linux for incomplete Foundation API's. +/// swift-corelibs-foundation is not yet 1:1 with OSX/iOS Foundation + +extension CFSocketError { + public static let success = kCFSocketSuccess +} + +extension UInt { + public static func &(lhs: UInt, rhs: Int) -> UInt { + let cast = unsafeBitCast(rhs, to: UInt.self) + return lhs & cast + } +} + +#else +extension CFStreamPropertyKey { + static let shouldCloseNativeSocket = CFStreamPropertyKey(kCFStreamPropertyShouldCloseNativeSocket) + // Exists as Stream.PropertyKey.socketSecuritylevelKey but doesn't work with CFReadStreamSetProperty + static let socketSecurityLevel = CFStreamPropertyKey(kCFStreamPropertySocketSecurityLevel) + static let SSLSettings = CFStreamPropertyKey(kCFStreamPropertySSLSettings) +} +#endif diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TApplicationError.swift b/src/jaegertracing/thrift/lib/swift/Sources/TApplicationError.swift new file mode 100644 index 000000000..bc3939680 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TApplicationError.swift @@ -0,0 +1,157 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + + +public struct TApplicationError : TError { + public enum Code : TErrorCode { + case unknown + case unknownMethod(methodName: String?) + case invalidMessageType + case wrongMethodName(methodName: String?) + case badSequenceId + case missingResult(methodName: String?) + case internalError + case protocolError + case invalidTransform + case invalidProtocol + case unsupportedClientType + + + /// Initialize a TApplicationError with a Thrift error code + /// Normally this would be achieved with RawRepresentable however + /// by doing this we can allow for associated properties on enum cases for + /// case specific context data in a Swifty, type-safe manner. + /// + /// - parameter thriftErrorCode: Integer TApplicationError(exception) error code. + /// Default to 0 (.unknown) + public init(thriftErrorCode: Int) { + switch thriftErrorCode { + case 1: self = .unknownMethod(methodName: nil) + case 2: self = .invalidMessageType + case 3: self = .wrongMethodName(methodName: nil) + case 4: self = .badSequenceId + case 5: self = .missingResult(methodName: nil) + case 6: self = .internalError + case 7: self = .protocolError + case 8: self = .invalidProtocol + case 9: self = .invalidTransform + case 10: self = .unsupportedClientType + default: self = .unknown + } + } + public var thriftErrorCode: Int { + switch self { + case .unknown: return 0 + case .unknownMethod: return 1 + case .invalidMessageType: return 2 + case .wrongMethodName: return 3 + case .badSequenceId: return 4 + case .missingResult: return 5 + case .internalError: return 6 + case .protocolError: return 7 + case .invalidProtocol: return 8 + case .invalidTransform: return 9 + case .unsupportedClientType: return 10 + } + } + + public var description: String { + /// Output "for #methodName" if method is not nil else empty + let methodUnwrap: (String?) -> String = { method in + return "\(method == nil ? "" : " for \(method ?? "")")" + } + switch self { + case .unknown: return "Unknown TApplicationError" + case .unknownMethod(let method): return "Unknown Method\(methodUnwrap(method))" + case .invalidMessageType: return "Invalid Message Type" + case .wrongMethodName(let method): return "Wrong Method Name\(methodUnwrap(method))" + case .badSequenceId: return "Bad Sequence ID" + case .missingResult(let method): return "Missing Result\(methodUnwrap(method))" + case .internalError: return "Internal Error" + case .protocolError: return "Protocol Error" + case .invalidProtocol: return "Invalid Protocol" + case .invalidTransform: return "Invalid Transform" + case .unsupportedClientType: return "Unsupported Client Type" + } + } + } + + public init() { } + + public init(thriftErrorCode code: Int, message: String? = nil) { + self.error = Code(thriftErrorCode: code) + self.message = message + } + + public var error: Code = .unknown + public var message: String? = nil + public static var defaultCase: Code { return .unknown } +} + +extension TApplicationError : TSerializable { + public static var thriftType: TType { return .struct } + + public static func read(from proto: TProtocol) throws -> TApplicationError { + var errorCode: Int = 0 + var message: String? = nil + _ = try proto.readStructBegin() + fields: while true { + let (_, fieldType, fieldID) = try proto.readFieldBegin() + + switch (fieldID, fieldType) { + case (_, .stop): + break fields + case (1, .string): + message = try proto.read() + case (2, .i32): + errorCode = Int(try proto.read() as Int32) + + case let (_, unknownType): + try proto.skip(type: unknownType) + } + + try proto.readFieldEnd() + } + try proto.readStructEnd() + return TApplicationError(thriftErrorCode: errorCode, message: message) + } + + public func write(to proto: TProtocol) throws { + try proto.writeStructBegin(name: "TApplicationException") + + try proto.writeFieldBegin(name: "message", type: .string, fieldID: 1) + try proto.write(message ?? "") + try proto.writeFieldEnd() + + try proto.writeFieldBegin(name: "type", type: .i32, fieldID: 2) + let val = Int32(error.thriftErrorCode) + try proto.write(val) + try proto.writeFieldEnd() + try proto.writeFieldStop() + try proto.writeStructEnd() + } + + public var hashValue: Int { + return error.thriftErrorCode &+ (message?.hashValue ?? 0) + } +} + +public func ==(lhs: TApplicationError, rhs: TApplicationError) -> Bool { + return lhs.error.thriftErrorCode == rhs.error.thriftErrorCode && lhs.message == rhs.message +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TBinary.swift b/src/jaegertracing/thrift/lib/swift/Sources/TBinary.swift new file mode 100644 index 000000000..4be56441a --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TBinary.swift @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Foundation + +extension Data : TSerializable { + public static var thriftType: TType { return .string } + + public static func read(from proto: TProtocol) throws -> Data { + return try proto.read() as Data + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TBinaryProtocol.swift b/src/jaegertracing/thrift/lib/swift/Sources/TBinaryProtocol.swift new file mode 100644 index 000000000..85acce045 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TBinaryProtocol.swift @@ -0,0 +1,384 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Foundation + +public struct TBinaryProtocolVersion { + static let version1 = Int32(bitPattern: 0x80010000) + static let versionMask = Int32(bitPattern: 0xffff0000) +} + +public class TBinaryProtocol: TProtocol { + public var messageSizeLimit: UInt32 = 0 + + public var transport: TTransport + + // class level properties for setting global config (useful for server in lieu of Factory design) + public static var strictRead: Bool = false + public static var strictWrite: Bool = true + + private var strictRead: Bool + private var strictWrite: Bool + + var currentMessageName: String? + var currentFieldName: String? + + + public convenience init(transport: TTransport, strictRead: Bool, strictWrite: Bool) { + self.init(on: transport) + self.strictRead = strictRead + self.strictWrite = strictWrite + } + + public required init(on transport: TTransport) { + self.transport = transport + self.strictWrite = TBinaryProtocol.strictWrite + self.strictRead = TBinaryProtocol.strictRead + } + + func readStringBody(_ size: Int) throws -> String { + + var data = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport read failed")) { + data = try self.transport.readAll(size: size) + } + + return String(data: data, encoding: String.Encoding.utf8) ?? "" + } + + /// Mark: - TProtocol + + public func readMessageBegin() throws -> (String, TMessageType, Int32) { + let size: Int32 = try read() + var messageName = "" + var type = TMessageType.exception + + if size < 0 { + let version = size & TBinaryProtocolVersion.versionMask + if version != TBinaryProtocolVersion.version1 { + throw TProtocolError(error: .badVersion(expected: "\(TBinaryProtocolVersion.version1)", + got: "\(version)")) + } + type = TMessageType(rawValue: Int32(size) & 0x00FF) ?? type + messageName = try read() + } else { + if strictRead { + let errorMessage = "Missing message version, old client? Message Name: \(currentMessageName ?? "")" + throw TProtocolError(error: .invalidData, + message: errorMessage) + } + if messageSizeLimit > 0 && size > Int32(messageSizeLimit) { + throw TProtocolError(error: .sizeLimit(limit: Int(messageSizeLimit), got: Int(size))) + } + + messageName = try readStringBody(Int(size)) + type = TMessageType(rawValue: Int32(try read() as UInt8)) ?? type + } + + let seqID: Int32 = try read() + return (messageName, type, seqID) + } + + public func readMessageEnd() throws { + return + } + + public func readStructBegin() throws -> String { + return "" + } + + public func readStructEnd() throws { + return + } + + public func readFieldBegin() throws -> (String, TType, Int32) { + + let fieldType = TType(rawValue: Int32(try read() as UInt8)) ?? TType.stop + var fieldID: Int32 = 0 + + if fieldType != .stop { + fieldID = Int32(try read() as Int16) + } + + return ("", fieldType, fieldID) + } + + public func readFieldEnd() throws { + return + } + + public func readMapBegin() throws -> (TType, TType, Int32) { + var raw = Int32(try read() as UInt8) + guard let keyType = TType(rawValue: raw) else { + throw TProtocolError(message: "Unknown value for keyType TType: \(raw)") + } + + raw = Int32(try read() as UInt8) + guard let valueType = TType(rawValue: raw) else { + throw TProtocolError(message: "Unknown value for valueType TType: \(raw)") + } + let size: Int32 = try read() + + return (keyType, valueType, size) + } + + public func readMapEnd() throws { + return + } + + public func readSetBegin() throws -> (TType, Int32) { + let raw = Int32(try read() as UInt8) + guard let elementType = TType(rawValue: raw) else { + throw TProtocolError(message: "Unknown value for elementType TType: \(raw)") + } + + let size: Int32 = try read() + + return (elementType, size) + } + + public func readSetEnd() throws { + return + } + + public func readListBegin() throws -> (TType, Int32) { + let raw = Int32(try read() as UInt8) + guard let elementType = TType(rawValue: raw) else { + throw TProtocolError(message: "Unknown value for elementType TType: \(raw)") + } + let size: Int32 = try read() + + return (elementType, size) + } + + public func readListEnd() throws { + return + } + + public func read() throws -> String { + let data: Data = try read() + guard let str = String.init(data: data, encoding: .utf8) else { + throw TProtocolError(error: .invalidData, message: "Couldn't encode UTF-8 from data read") + } + return str + } + + public func read() throws -> Bool { + return (try read() as UInt8) == 1 + } + + public func read() throws -> UInt8 { + var buff = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + buff = try self.transport.readAll(size: 1) + } + return buff[0] + } + + public func read() throws -> Int16 { + var buff = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + buff = try self.transport.readAll(size: 2) + } + var ret = Int16(buff[0] & 0xff) << 8 + ret |= Int16(buff[1] & 0xff) + return ret + } + + public func read() throws -> Int32 { + var buff = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + buff = try self.transport.readAll(size: 4) + } + var ret = Int32(buff[0] & 0xff) << 24 + ret |= Int32(buff[1] & 0xff) << 16 + ret |= Int32(buff[2] & 0xff) << 8 + ret |= Int32(buff[3] & 0xff) + + return ret + } + + public func read() throws -> Int64 { + var buff = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + buff = try self.transport.readAll(size: 8) + } + var ret = Int64(buff[0] & 0xff) << 56 + ret |= Int64(buff[1] & 0xff) << 48 + ret |= Int64(buff[2] & 0xff) << 40 + ret |= Int64(buff[3] & 0xff) << 32 + ret |= Int64(buff[4] & 0xff) << 24 + ret |= Int64(buff[5] & 0xff) << 16 + ret |= Int64(buff[6] & 0xff) << 8 + ret |= Int64(buff[7] & 0xff) + + return ret + } + + public func read() throws -> Double { + let val = try read() as Int64 + return Double(bitPattern: UInt64(bitPattern: val)) + } + + public func read() throws -> Data { + let size = Int(try read() as Int32) + var data = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + data = try self.transport.readAll(size: size) + } + + return data + } + + // Write methods + + public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { + if strictWrite { + let version = TBinaryProtocolVersion.version1 | Int32(messageType.rawValue) + try write(version) + try write(name) + try write(sequenceID) + } else { + try write(name) + try write(UInt8(messageType.rawValue)) + try write(sequenceID) + } + currentMessageName = name + } + + public func writeMessageEnd() throws { + currentMessageName = nil + } + + public func writeStructBegin(name: String) throws { + return + } + + public func writeStructEnd() throws { + return + } + + public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { + try write(UInt8(fieldType.rawValue)) + try write(Int16(fieldID)) + } + + public func writeFieldStop() throws { + try write(UInt8(TType.stop.rawValue)) + } + + public func writeFieldEnd() throws { + return + } + + public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { + try write(UInt8(keyType.rawValue)) + try write(UInt8(valueType.rawValue)) + try write(size) + } + + public func writeMapEnd() throws { + return + } + + public func writeSetBegin(elementType: TType, size: Int32) throws { + try write(UInt8(elementType.rawValue)) + try write(size) + } + + public func writeSetEnd() throws { + return + } + + public func writeListBegin(elementType: TType, size: Int32) throws { + try write(UInt8(elementType.rawValue)) + try write(size) + } + + public func writeListEnd() throws { + return + } + + public func write(_ value: String) throws { + try write(value.data(using: .utf8)!) + } + + public func write(_ value: Bool) throws { + let byteVal: UInt8 = value ? 1 : 0 + try write(byteVal) + } + + public func write(_ value: UInt8) throws { + let buff = Data([value]) + + try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { + try self.transport.write(data: buff) + } + } + + public func write(_ value: Int16) throws { + var buff = Data() + buff.append(Data([UInt8(0xff & (value >> 8))])) + buff.append(Data([UInt8(0xff & (value))])) + try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { + try self.transport.write(data: buff) + } + } + + public func write(_ value: Int32) throws { + var buff = Data() + buff.append(Data([UInt8(0xff & (value >> 24))])) + buff.append(Data([UInt8(0xff & (value >> 16))])) + buff.append(Data([UInt8(0xff & (value >> 8))])) + buff.append(Data([UInt8(0xff & (value))])) + + try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { + try self.transport.write(data: buff) + } + } + + public func write(_ value: Int64) throws { + var buff = Data() + buff.append(Data([UInt8(0xff & (value >> 56))])) + buff.append(Data([UInt8(0xff & (value >> 48))])) + buff.append(Data([UInt8(0xff & (value >> 40))])) + buff.append(Data([UInt8(0xff & (value >> 32))])) + buff.append(Data([UInt8(0xff & (value >> 24))])) + buff.append(Data([UInt8(0xff & (value >> 16))])) + buff.append(Data([UInt8(0xff & (value >> 8))])) + buff.append(Data([UInt8(0xff & (value))])) + + try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { + try self.transport.write(data: buff) + } + } + + public func write(_ value: Double) throws { + // Notably unsafe, since Double and Int64 are the same size, this should work fine + try self.write(Int64(bitPattern: value.bitPattern)) + } + + public func write(_ data: Data) throws { + try write(Int32(data.count)) + + try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { + try self.transport.write(data: data) + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TClient.swift b/src/jaegertracing/thrift/lib/swift/Sources/TClient.swift new file mode 100644 index 000000000..cc3288a8c --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TClient.swift @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +open class TClient { + public let inProtocol: TProtocol + public let outProtocol: TProtocol + + required public init(inoutProtocol: TProtocol) { + self.inProtocol = inoutProtocol + self.outProtocol = inoutProtocol + } + + required public init(inProtocol: TProtocol, outProtocol: TProtocol) { + self.inProtocol = inProtocol + self.outProtocol = outProtocol + } +} + + +open class TAsyncClient<Protocol: TProtocol, Factory: TAsyncTransportFactory> { + public var factory: Factory + public init(with protocol: Protocol.Type, factory: Factory) { + self.factory = factory + } +} + + +public enum TAsyncResult<T> { + case success(T) + case error(Swift.Error) + + public func value() throws -> T { + switch self { + case .success(let t): return t + case .error(let e): throw e + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift b/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift new file mode 100644 index 000000000..5b302d38f --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift @@ -0,0 +1,571 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation +import CoreFoundation + +public enum TCType: UInt8 { + case stop = 0x00 + case boolean_TRUE = 0x01 + case boolean_FALSE = 0x02 + case i8 = 0x03 + case i16 = 0x04 + case i32 = 0x05 + case i64 = 0x06 + case double = 0x07 + case binary = 0x08 + case list = 0x09 + case set = 0x0A + case map = 0x0B + case `struct` = 0x0C + + public static let typeMask: UInt8 = 0xE0 // 1110 0000 + public static let typeBits: UInt8 = 0x07 // 0000 0111 + public static let typeShiftAmount = 5 + +} + + +public class TCompactProtocol: TProtocol { + public static let protocolID: UInt8 = 0x82 + public static let version: UInt8 = 1 + public static let versionMask: UInt8 = 0x1F // 0001 1111 + + public var transport: TTransport + + var lastField: [UInt8] = [] + var lastFieldId: UInt8 = 0 + + var boolFieldName: String? + var boolFieldType: TType? + var boolFieldId: Int32? + var booleanValue: Bool? + + var currentMessageName: String? + + public required init(on transport: TTransport) { + self.transport = transport + } + + + /// Mark: - TCompactProtocol helpers + + func writebyteDirect(_ byte: UInt8) throws { + let byte = Data([byte]) + try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { + try self.transport.write(data: byte) + } + } + + func writeVarint32(_ val: UInt32) throws { + var val = val + var i32buf = [UInt8](repeating: 0, count: 5) + var idx = 0 + while true { + if (val & ~0x7F) == 0 { + i32buf[idx] = UInt8(val) + idx += 1 + break + } else { + i32buf[idx] = UInt8((val & 0x7F) | 0x80) + idx += 1 + val >>= 7 + } + } + + try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { + try self.transport.write(data: Data(i32buf[0..<idx])) + } + } + + func writeVarint64(_ val: UInt64) throws { + var val = val + var varint64out = [UInt8](repeating: 0, count: 10) + var idx = 0 + while true { + if (val & ~0x7F) == 0{ + varint64out[idx] = UInt8(val) + idx += 1 + break + } else { + varint64out[idx] = UInt8(val & 0x7F) | 0x80 + idx += 1 + val >>= 7 + } + } + + try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { + try self.transport.write(data: Data(varint64out[0..<idx])) + } + } + + func writeCollectionBegin(_ elementType: TType, size: Int32) throws { + let ctype = compactType(elementType).rawValue + if size <= 14 { + try writebyteDirect(UInt8(size << 4) | ctype) + } else { + try writebyteDirect(0xF0 | ctype) + try writeVarint32(UInt32(size)) + } + } + + func readBinary(_ size: Int) throws -> Data { + var result = Data() + if size != 0 { + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + result = try self.transport.readAll(size: size) + } + } + return result + } + + func readVarint32() throws -> UInt32 { + var result: UInt32 = 0 + var shift: UInt32 = 0 + while true { + let byte: UInt8 = try read() + + result |= UInt32(byte & 0x7F) << shift + if (byte & 0x80) == 0 { + break + } + + shift += 7 + } + + return result + } + + func readVarint64() throws -> UInt64 { + var result: UInt64 = 0 + var shift: UInt64 = 0 + + while true { + let byte: UInt8 = try read() + + result |= UInt64(byte & 0x7F) << shift + if (byte & 0x80) == 0 { + break + } + + shift += 7 + } + return result + } + + + func ttype(_ compactTypeVal: UInt8) throws -> TType { + guard let compactType = TCType(rawValue: compactTypeVal) else { + throw TProtocolError(message: "Unknown TCType value: \(compactTypeVal)") + } + + switch compactType { + case .stop: return .stop; + case .boolean_FALSE, .boolean_TRUE: return .bool; + case .i8: return .i8; + case .i16: return .i16; + case .i32: return .i32; + case .i64: return .i64; + case .double: return .double; + case .binary: return .string; + case .list: return .list; + case .set: return .set; + case .map: return .map; + case .struct: return .struct; + } + } + + func compactType(_ ttype: TType) -> TCType { + switch ttype { + case .stop: return .stop + case .void: return .i8 + case .bool: return .boolean_FALSE + case .i8: return .i8 + case .double: return .double + case .i16: return .i16 + case .i32: return .i32 + case .i64: return .i64 + case .string: return .binary + case .struct: return .struct + case .map: return .map + case .set: return .set + case .list: return .list + case .utf8: return .binary + case .utf16: return .binary + } + } + + /// ZigZag encoding maps signed integers to unsigned integers so that + /// numbers with a small absolute value (for instance, -1) have + /// a small varint encoded value too. It does this in a way that + /// "zig-zags" back and forth through the positive and negative integers, + /// so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so + /// + /// - parameter n: number to zigzag + /// + /// - returns: zigzaged UInt32 + func i32ToZigZag(_ n : Int32) -> UInt32 { + return UInt32(bitPattern: Int32(n << 1) ^ Int32(n >> 31)) + } + + func i64ToZigZag(_ n : Int64) -> UInt64 { + return UInt64(bitPattern: Int64(n << 1) ^ Int64(n >> 63)) + } + + func zigZagToi32(_ n: UInt32) -> Int32 { + return Int32(n >> 1) ^ (-Int32(n & 1)) + } + + func zigZagToi64(_ n: UInt64) -> Int64 { + return Int64(n >> 1) ^ (-Int64(n & 1)) + } + + + + /// Mark: - TProtocol + + public func readMessageBegin() throws -> (String, TMessageType, Int32) { + let protocolId: UInt8 = try read() + + if protocolId != TCompactProtocol.protocolID { + let expected = String(format:"%2X", TCompactProtocol.protocolID) + let got = String(format:"%2X", protocolId) + throw TProtocolError(message: "Wrong Protocol ID \(got)", + extendedError: .mismatchedProtocol(expected: expected, got: got)) + } + + let versionAndType: UInt8 = try read() + let version: UInt8 = versionAndType & TCompactProtocol.versionMask + if version != TCompactProtocol.version { + throw TProtocolError(error: .badVersion(expected: "\(TCompactProtocol.version)", + got:"\(version)")) + } + + let type = (versionAndType >> UInt8(TCType.typeShiftAmount)) & TCType.typeBits + guard let mtype = TMessageType(rawValue: Int32(type)) else { + throw TProtocolError(message: "Unknown TMessageType value: \(type)") + } + let sequenceId = try readVarint32() + let name: String = try read() + + return (name, mtype, Int32(sequenceId)) + } + + public func readMessageEnd() throws { } + + public func readStructBegin() throws -> String { + lastField.append(lastFieldId) + lastFieldId = 0 + return "" + } + + public func readStructEnd() throws { + lastFieldId = lastField.last ?? 0 + lastField.removeLast() + } + + public func readFieldBegin() throws -> (String, TType, Int32) { + let byte: UInt8 = try read() + guard let type = TCType(rawValue: byte & 0x0F) else { + throw TProtocolError(message: "Unknown TCType \(byte & 0x0F)") + } + + // if it's a stop, then we can return immediately, as the struct is over + if type == .stop { + return ("", .stop, 0) + } + + var fieldId: Int16 = 0 + + // mask off the 4MSB of the type header. it could contain a field id delta + let modifier = (byte & 0xF0) >> 4 + if modifier == 0 { + // not a delta. look ahead for the zigzag varint field id + fieldId = try read() + } else { + // has a delta. add the delta to the last Read field id. + fieldId = Int16(lastFieldId + modifier) + } + + let fieldType = try ttype(type.rawValue) + + // if this happens to be a boolean field, the value is encoded in the type + if type == .boolean_TRUE || type == .boolean_FALSE { + // save the boolean value in a special instance variable + booleanValue = type == .boolean_TRUE + } + + // push the new field onto the field stack so we can keep the deltas going + lastFieldId = UInt8(fieldId) + return ("", fieldType, Int32(fieldId)) + } + + public func readFieldEnd() throws { } + + public func read() throws -> String { + let length = try readVarint32() + + var result: String + + if length != 0 { + let data = try readBinary(Int(length)) + result = String(data: data, encoding: String.Encoding.utf8) ?? "" + } else { + result = "" + } + + return result + } + + public func read() throws -> Bool { + if let val = booleanValue { + self.booleanValue = nil + return val + } else { + let result = try read() as UInt8 + return TCType(rawValue: result) == .boolean_TRUE + } + } + + public func read() throws -> UInt8 { + var buff: UInt8 = 0 + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + buff = try self.transport.readAll(size: 1)[0] + } + return buff + } + + public func read() throws -> Int16 { + let v = try readVarint32() + return Int16(zigZagToi32(v)) + } + + public func read() throws -> Int32 { + let v = try readVarint32() + return zigZagToi32(v) + } + + public func read() throws -> Int64 { + let v = try readVarint64() + return zigZagToi64(v) + } + + public func read() throws -> Double { + var buff = Data() + try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { + buff = try self.transport.readAll(size: 8) + } + + let i64: UInt64 = buff.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> UInt64 in + return UnsafePointer<UInt64>(OpaquePointer(ptr)).pointee + } + let bits = CFSwapInt64LittleToHost(i64) + return Double(bitPattern: bits) + } + + public func read() throws -> Data { + let length = try readVarint32() + return try readBinary(Int(length)) + } + + public func readMapBegin() throws -> (TType, TType, Int32) { + var keyAndValueType: UInt8 = 8 + let size = try readVarint32() + if size != 0 { + keyAndValueType = try read() + } + + let keyType = try ttype(keyAndValueType >> 4) + let valueType = try ttype(keyAndValueType & 0xF) + + return (keyType, valueType, Int32(size)) + } + + public func readMapEnd() throws { } + + public func readSetBegin() throws -> (TType, Int32) { + return try readListBegin() + } + + public func readSetEnd() throws { } + + public func readListBegin() throws -> (TType, Int32) { + let sizeAndType: UInt8 = try read() + var size: UInt32 = UInt32(sizeAndType >> 4) & 0x0f + if size == 15 { + size = try readVarint32() + } + let elementType = try ttype(sizeAndType & 0x0F) + + return (elementType, Int32(size)) + } + + public func readListEnd() throws { } + + public func writeMessageBegin(name: String, + type messageType: TMessageType, + sequenceID: Int32) throws { + try writebyteDirect(TCompactProtocol.protocolID) + let nextByte: UInt8 = (TCompactProtocol.version & TCompactProtocol.versionMask) | + (UInt8((UInt32(messageType.rawValue) << UInt32(TCType.typeShiftAmount))) & + TCType.typeMask) + try writebyteDirect(nextByte) + try writeVarint32(UInt32(sequenceID)) + try write(name) + + currentMessageName = name + } + + public func writeMessageEnd() throws { + currentMessageName = nil + } + + public func writeStructBegin(name: String) throws { + lastField.append(lastFieldId) + lastFieldId = 0 + } + + public func writeStructEnd() throws { + lastFieldId = lastField.last ?? 0 + lastField.removeLast() + } + + public func writeFieldBegin(name: String, + type fieldType: TType, + fieldID: Int32) throws { + if fieldType == .bool { + boolFieldName = name + boolFieldType = fieldType + boolFieldId = fieldID + return + } else { + try writeFieldBeginInternal(name: name, + type: fieldType, + fieldID: fieldID, + typeOverride: 0xFF) + } + } + + func writeFieldBeginInternal(name: String, + type fieldType: TType, + fieldID: Int32, + typeOverride: UInt8) throws { + + let typeToWrite = typeOverride == 0xFF ? compactType(fieldType).rawValue : typeOverride + + // check if we can use delta encoding for the field id + let diff = UInt8(fieldID) - lastFieldId + if (UInt8(fieldID) > lastFieldId) && (diff <= 15) { + // Write them together + try writebyteDirect((UInt8(fieldID) - lastFieldId) << 4 | typeToWrite) + + } else { + // Write them separate + try writebyteDirect(typeToWrite) + try write(Int16(fieldID)) + } + + lastFieldId = UInt8(fieldID) + } + + public func writeFieldStop() throws { + try writebyteDirect(TCType.stop.rawValue) + } + + public func writeFieldEnd() throws { } + + public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { + if size == 0 { + try writebyteDirect(0) + } else { + try writeVarint32(UInt32(size)) + + let compactedTypes = compactType(keyType).rawValue << 4 | compactType(valueType).rawValue + try writebyteDirect(compactedTypes) + } + } + + public func writeMapEnd() throws { } + + public func writeSetBegin(elementType: TType, size: Int32) throws { + try writeCollectionBegin(elementType, size: size) + } + + public func writeSetEnd() throws { } + + public func writeListBegin(elementType: TType, size: Int32) throws { + try writeCollectionBegin(elementType, size: size) + } + + public func writeListEnd() throws { } + + public func write(_ value: String) throws { + try write(value.data(using: String.Encoding.utf8)!) + } + + public func write(_ value: Bool) throws { + if let boolFieldId = boolFieldId, let boolFieldType = boolFieldType, + let boolFieldName = boolFieldName { + + // we haven't written the field header yet + let compactType: TCType = value ? .boolean_TRUE : .boolean_FALSE + try writeFieldBeginInternal(name: boolFieldName, type: boolFieldType, fieldID: boolFieldId, + typeOverride: compactType.rawValue) + self.boolFieldId = nil + self.boolFieldType = nil + self.boolFieldName = nil + } else { + // we're not part of a field, so just write the value. + try writebyteDirect(value ? TCType.boolean_TRUE.rawValue : TCType.boolean_FALSE.rawValue) + } + } + + public func write(_ value: UInt8) throws { + try writebyteDirect(value) + } + + public func write(_ value: Int16) throws { + try writeVarint32(i32ToZigZag(Int32(value))) + } + + public func write(_ value: Int32) throws { + try writeVarint32(i32ToZigZag(value)) + } + + public func write(_ value: Int64) throws { + try writeVarint64(i64ToZigZag(value)) + } + + public func write(_ value: Double) throws { + var bits = CFSwapInt64HostToLittle(value.bitPattern) + let data = withUnsafePointer(to: &bits) { + return Data(bytes: UnsafePointer<UInt8>(OpaquePointer($0)), count: MemoryLayout<UInt64>.size) + } + try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { + try self.transport.write(data: data) + } + } + + public func write(_ data: Data) throws { + try writeVarint32(UInt32(data.count)) + try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { + try self.transport.write(data: data) + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TEnum.swift b/src/jaegertracing/thrift/lib/swift/Sources/TEnum.swift new file mode 100644 index 000000000..fedfdb124 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TEnum.swift @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +public protocol TEnum : TSerializable, Hashable { + var rawValue: Int32 { get } +} + +extension TEnum { + public static var thriftType: TType { return .i32 } + public var hashValue: Int { return rawValue.hashValue } + + public func write(to proto: TProtocol) throws { + try proto.write(rawValue) + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TError.swift b/src/jaegertracing/thrift/lib/swift/Sources/TError.swift new file mode 100644 index 000000000..79edba602 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TError.swift @@ -0,0 +1,77 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + + +/// TErrorCode +/// +/// Protocol for TError conformers' enum's to conform to. +/// Generic Int Thrift error code to allow error cases to have +/// associated values. +public protocol TErrorCode : CustomStringConvertible { + var thriftErrorCode: Int { get } +} + +/// TError +/// +/// Base protocol for all Thrift Error(Exception) types to conform to +public protocol TError : Error, CustomStringConvertible { + + /// Enum for error cases. Can be typealiased to any conforming enum + /// or defined nested. + associatedtype Code: TErrorCode + + /// Error Case, value from internal enum + var error: Code { get set } + + /// Optional additional message + var message: String? { get set } + + /// Default error case for the error type, used for generic init() + static var defaultCase: Code { get } + + init() +} + +extension TError { + /// Human readable description of error. Default provided for you in the + /// format \(Self.self): \(error.errorDescription) \n message + /// eg: + /// + /// TApplicationError (1): Invalid Message Type + /// An unknown Error has occured. + public var description: String { + var out = "\(Self.self) (\(error.thriftErrorCode)): " + error.description + "\n" + if let message = message { + out += "Message: \(message)" + } + return out + } + + /// Simple default Initializer for TError's + /// + /// - parameter error: ErrorCode value. Default: defaultCase + /// - parameter message: Custom message with error. Optional + /// + /// - returns: <#return value description#> + public init(error: Code, message: String? = nil) { + self.init() + self.error = error + self.message = message + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TFileHandleTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TFileHandleTransport.swift new file mode 100644 index 000000000..f315fefda --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TFileHandleTransport.swift @@ -0,0 +1,56 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation + +public class TFileHandleTransport: TTransport { + var inputFileHandle: FileHandle + var outputFileHandle: FileHandle + + public init(inputFileHandle: FileHandle, outputFileHandle: FileHandle) { + self.inputFileHandle = inputFileHandle + self.outputFileHandle = outputFileHandle + } + + public convenience init(fileHandle: FileHandle) { + self.init(inputFileHandle: fileHandle, outputFileHandle: fileHandle) + } + + public func read(size: Int) throws -> Data { + var data = Data() + while data.count < size { + let read = inputFileHandle.readData(ofLength: size - data.count) + data.append(read) + if read.count == 0 { + break + } + } + return data + } + + public func write(data: Data) throws { + outputFileHandle.write(data) + } + + public func flush() throws { + return + } +} + + diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TFileTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TFileTransport.swift new file mode 100644 index 000000000..fe2253da4 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TFileTransport.swift @@ -0,0 +1,101 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation + +#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) + import Darwin +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) + import Glibc +#endif + +/// TFileTransport +/// Foundation-less Swift File transport. +/// Uses C fopen/fread/fwrite, +/// provided by Glibc in linux and Darwin on OSX/iOS +public class TFileTransport: TTransport { + var fileHandle: UnsafeMutablePointer<FILE>? = nil + + public init (fileHandle: UnsafeMutablePointer<FILE>) { + self.fileHandle = fileHandle + } + + public convenience init(filename: String) throws { + var fileHandle: UnsafeMutablePointer<FILE>? + filename.withCString({ cFilename in + "rw".withCString({ cMode in + fileHandle = fopen(cFilename, cMode) + }) + }) + if let fileHandle = fileHandle { + self.init(fileHandle: fileHandle) + } else { + throw TTransportError(error: .notOpen) + } + } + + deinit { + fclose(self.fileHandle) + } + + public func readAll(size: Int) throws -> Data { + let read = try self.read(size: size) + + if read.count != size { + throw TTransportError(error: .endOfFile) + } + return read + } + + public func read(size: Int) throws -> Data { + // set up read buffer, position 0 + var read = Data(capacity: size) + var position = 0 + + // read character buffer + var nextChar: UInt8 = 0 + + // continue until we've read size bytes + while read.count < size { + if fread(&nextChar, 1, 1, self.fileHandle) == 1 { + read[position] = nextChar + + // Increment output byte pointer + position += 1 + + } else { + throw TTransportError(error: .endOfFile) + } + } + return read + } + + public func write(data: Data) throws { + let bytesWritten = data.withUnsafeBytes { + fwrite($0, 1, data.count, self.fileHandle) + } + if bytesWritten != data.count { + throw TTransportError(error: .unknown) + } + } + + public func flush() throws { + return + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TFramedTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TFramedTransport.swift new file mode 100644 index 000000000..59855eb9c --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TFramedTransport.swift @@ -0,0 +1,123 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation + +public class TFramedTransport: TTransport { + public static let headerSize = 4 + public static let initFrameSize = 1024 + private static let defaultMaxLength = 16384000 + + public var transport: TTransport + private var writeBuffer = Data() + + private var maxSize = TFramedTransport.defaultMaxLength + private var remainingBytes = 0 + + + public init(transport: TTransport, maxSize: Int) { + self.transport = transport + self.maxSize = maxSize + } + + public convenience init(transport: TTransport) { + self.init(transport: transport, maxSize: TFramedTransport.defaultMaxLength) + } + + func readHeader() throws { + let read = try transport.readAll(size: TFramedTransport.headerSize) + remainingBytes = Int(decodeFrameSize(data: read)) + } + + /// Mark: - TTransport + + public func read(size: Int) throws -> Data { + while (remainingBytes <= 0) { + try readHeader() + } + + let toRead = min(size, remainingBytes) + + if toRead < 0 { + try close() + throw TTransportError(error: .negativeSize, + message: "Read a negative frame size (\(toRead))!") + } + + if toRead > maxSize { + try close() + throw TTransportError(error: .sizeLimit(limit: maxSize, got: toRead)) + } + + return try transport.readAll(size: toRead) + } + + public func flush() throws { + // copy buffer and reset + let buff = writeBuffer + writeBuffer = Data() + + if buff.count - TFramedTransport.headerSize < 0 { + throw TTransportError(error: .unknown) + } + + let frameSize = encodeFrameSize(size: UInt32(buff.count)) + + try transport.write(data: frameSize) + try transport.write(data: buff) + try transport.flush() + } + + public func write(data: Data) throws { + writeBuffer.append(data) + } + + + + private func encodeFrameSize(size: UInt32) -> Data { + var data = Data() + data.append(Data([UInt8(0xff & (size >> 24))])) + data.append(Data([UInt8(0xff & (size >> 16))])) + data.append(Data([UInt8(0xff & (size >> 8))])) + data.append(Data([UInt8(0xff & (size))])) + + return data + } + + private func decodeFrameSize(data: Data) -> UInt32 { + var size: UInt32 + size = (UInt32(data[0] & 0xff) << 24) + size |= (UInt32(data[1] & 0xff) << 16) + size |= (UInt32(data[2] & 0xff) << 8) + size |= (UInt32(data[3] & 0xff)) + return size + } + + public func close() throws { + try transport.close() + } + + public func open() throws { + try transport.open() + } + + public func isOpen() throws -> Bool { + return try transport.isOpen() + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift new file mode 100644 index 000000000..3c0af8eb8 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift @@ -0,0 +1,184 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation +import Dispatch + + +public class THTTPSessionTransport: TAsyncTransport { + public class Factory : TAsyncTransportFactory { + public var responseValidate: ((HTTPURLResponse?, Data?) throws -> Void)? + + var session: URLSession + var url: URL + + public class func setupDefaultsForSessionConfiguration(_ config: URLSessionConfiguration, withProtocolName protocolName: String?) { + var thriftContentType = "application/x-thrift" + + if let protocolName = protocolName { + thriftContentType += "; p=\(protocolName)" + } + + config.requestCachePolicy = .reloadIgnoringLocalCacheData + config.urlCache = nil + + config.httpShouldUsePipelining = true + config.httpShouldSetCookies = true + config.httpAdditionalHeaders = ["Content-Type": thriftContentType, + "Accept": thriftContentType, + "User-Agent": "Thrift/Swift (Session)"] + + + } + + public init(session: URLSession, url: URL) { + self.session = session + self.url = url + } + + public func newTransport() -> THTTPSessionTransport { + return THTTPSessionTransport(factory: self) + } + + func validateResponse(_ response: HTTPURLResponse?, data: Data?) throws { + try responseValidate?(response, data) + } + + func taskWithRequest(_ request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) throws -> URLSessionTask { + + let newTask: URLSessionTask? = session.dataTask(with: request, completionHandler: completionHandler) + if let newTask = newTask { + return newTask + } else { + throw TTransportError(error: .unknown, message: "Failed to create session data task") + } + } + } + + var factory: Factory + var requestData = Data() + var responseData = Data() + var responseDataOffset: Int = 0 + + init(factory: Factory) { + self.factory = factory + } + + public func readAll(size: Int) throws -> Data { + let read = try self.read(size: size) + if read.count != size { + throw TTransportError(error: .endOfFile) + } + return read + } + + public func read(size: Int) throws -> Data { + let avail = responseData.count - responseDataOffset + let (start, stop) = (responseDataOffset, responseDataOffset + min(size, avail)) + let read = responseData.subdata(in: start..<stop) + responseDataOffset += read.count + return read + } + + public func write(data: Data) throws { + requestData.append(data) + } + + public func flush(_ completed: @escaping (TAsyncTransport, Error?) -> Void) { + var error: Error? + var task: URLSessionTask? + + var request = URLRequest(url: factory.url) + request.httpMethod = "POST" + request.httpBody = requestData + + requestData = Data() + + do { + task = try factory.taskWithRequest(request, completionHandler: { (data, response, taskError) in + + // Check if there was an error with the network + if taskError != nil { + error = TTransportError(error: .timedOut) + completed(self, error) + return + } + + // Check response type + if taskError == nil && !(response is HTTPURLResponse) { + error = THTTPTransportError(error: .invalidResponse) + completed(self, error) + return + } + + // Check status code + if let httpResponse = response as? HTTPURLResponse { + if taskError == nil && httpResponse.statusCode != 200 { + if httpResponse.statusCode == 401 { + error = THTTPTransportError(error: .authentication) + } else { + error = THTTPTransportError(error: .invalidStatus(statusCode: httpResponse.statusCode)) + } + } + + // Allow factory to check + if error != nil { + do { + try self.factory.validateResponse(httpResponse, data: data) + } catch let validateError { + error = validateError + } + } + + self.responseDataOffset = 0 + if error != nil { + self.responseData = Data() + } else { + self.responseData = data ?? Data() + } + completed(self, error) + } + }) + + } catch let taskError { + error = taskError + } + + if let error = error, task == nil { + completed(self, error) + } + task?.resume() + } + + public func flush() throws { + let completed = DispatchSemaphore(value: 0) + var internalError: Error? + + flush() { _, error in + internalError = error + completed.signal() + } + + _ = completed.wait(timeout: DispatchTime.distantFuture) + + if let error = internalError { + throw error + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TList.swift b/src/jaegertracing/thrift/lib/swift/Sources/TList.swift new file mode 100644 index 000000000..c239d10c5 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TList.swift @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +public struct TList<Element : TSerializable> : RandomAccessCollection, MutableCollection, ExpressibleByArrayLiteral, TSerializable, Hashable { + public typealias Storage = Array<Element> + public typealias Indices = Storage.Indices + + internal var storage = Storage() + public init() { } + public init(arrayLiteral elements: Element...) { + self.storage = Storage(elements) + } + public init<Source : Sequence>(_ sequence: Source) where Source.Iterator.Element == Element { + storage = Storage(sequence) + } + + /// Mark: Hashable + public var hashValue : Int { + let prime = 31 + var result = 1 + for element in storage { + result = prime &* result &+ element.hashValue + } + return result + } + + /// Mark: TSerializable + public static var thriftType : TType { return .list } + + public static func read(from proto: TProtocol) throws -> TList { + let (elementType, size) = try proto.readListBegin() + if elementType != Element.thriftType { + throw TProtocolError(error: .invalidData, + extendedError: .unexpectedType(type: elementType)) + } + var list = TList() + for _ in 0..<size { + let element = try Element.read(from: proto) + list.storage.append(element) + } + try proto.readListEnd() + return list + } + + public func write(to proto: TProtocol) throws { + try proto.writeListBegin(elementType: Element.thriftType, size: Int32(self.count)) + for element in self.storage { + try Element.write(element, to: proto) + } + try proto.writeListEnd() + } + + /// Mark: MutableCollection + + public typealias SubSequence = Storage.SubSequence + public typealias Index = Storage.Index + + public subscript(position: Storage.Index) -> Element { + get { + return storage[position] + } + set { + storage[position] = newValue + } + } + + public subscript(range: Range<Index>) -> SubSequence { + get { + return storage[range] + } + set { + storage[range] = newValue + } + } + + public var startIndex: Index { + return storage.startIndex + } + public var endIndex: Index { + return storage.endIndex + } + + public func formIndex(after i: inout Index) { + storage.formIndex(after: &i) + } + + public func formIndex(before i: inout Int) { + storage.formIndex(before: &i) + } + + public func index(after i: Index) -> Index { + return storage.index(after: i) + } + + public func index(before i: Int) -> Int { + return storage.index(before: i) + } + +} + +extension TList : RangeReplaceableCollection { + public mutating func replaceSubrange<C: Collection>(_ subrange: Range<Index>, with newElements: C) + where C.Iterator.Element == Element { + storage.replaceSubrange(subrange, with: newElements) + } +} + +extension TList : CustomStringConvertible, CustomDebugStringConvertible { + + public var description : String { + return storage.description + } + + public var debugDescription : String { + return storage.debugDescription + } + +} + +public func ==<Element>(lhs: TList<Element>, rhs: TList<Element>) -> Bool { + return lhs.storage.elementsEqual(rhs.storage) { $0 == $1 } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TMap.swift b/src/jaegertracing/thrift/lib/swift/Sources/TMap.swift new file mode 100644 index 000000000..dcf1481c6 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TMap.swift @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +public struct TMap<Key : TSerializable & Hashable, Value : TSerializable>: Collection, ExpressibleByDictionaryLiteral, Hashable, TSerializable { + public typealias Storage = Dictionary<Key, Value> + public typealias Element = Storage.Element + public typealias Index = Storage.Index + public typealias IndexDistance = Int + public typealias Indices = Storage.Indices + public typealias SubSequence = Storage.SubSequence + internal var storage = Storage() + + /// Mark: Be Like Dictionary + + public func indexForKey(_ key: Key) -> Index? { + return storage.index(forKey: key) + } + + public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { + return storage.updateValue(value, forKey: key) + } + + public mutating func removeValueForKey(_ key: Key) -> Value? { + return storage.removeValue(forKey: key) + } + + public init(minimumCapacity: Int) { + storage = Storage(minimumCapacity: minimumCapacity) + } + + /// init from Dictionary<K,V> + public init(_ dict: [Key: Value]) { + storage = dict + } + + /// read only access to storage if needed as Dictionary<K,V> + public var dictionary: [Key: Value] { + return storage + } + + public subscript (key: Key) -> Value? { + get { + return storage[key] + } + set { + storage[key] = newValue + } + } + + /// Mark: Collection + + public var indices: Indices { + return storage.indices + } + + public func distance(from start: Index, to end: Index) -> IndexDistance { + return storage.distance(from: start, to: end) + } + + public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { + return storage.index(i, offsetBy: n) + } + + public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? { + return storage.index(i, offsetBy: n, limitedBy: limit) + } + + public subscript(position: Index) -> Element { + return storage[position] + } + + /// Mark: IndexableBase + + public var startIndex: Index { return storage.startIndex } + public var endIndex: Index { return storage.endIndex } + public func index(after i: Index) -> Index { + return storage.index(after: i) + } + + public func formIndex(after i: inout Index) { + storage.formIndex(after: &i) + } + + public subscript(bounds: Range<Index>) -> SubSequence { + return storage[bounds] + } + + /// Mark: DictionaryLiteralConvertible + + public init(dictionaryLiteral elements: (Key, Value)...) { + storage = Storage() + for (key, value) in elements { + storage[key] = value + } + } + + /// Mark: Hashable + + public var hashValue: Int { + let prime = 31 + var result = 1 + for (key, value) in storage { + result = prime &* result &+ key.hashValue + result = prime &* result &+ value.hashValue + } + return result + } + + /// Mark: TSerializable + + public static var thriftType : TType { return .map } + public init() { + storage = Storage() + } + + public static func read(from proto: TProtocol) throws -> TMap { + + let (keyType, valueType, size) = try proto.readMapBegin() + if size > 0 { + if keyType != Key.thriftType { + throw TProtocolError(error: .invalidData, + message: "Unexpected TMap Key Type", + extendedError: .unexpectedType(type: keyType)) + } + if valueType != Value.thriftType { + throw TProtocolError(error: .invalidData, + message: "Unexpected TMap Value Type", + extendedError: .unexpectedType(type: valueType)) + } + } + + var map = TMap() + for _ in 0..<size { + let key = try Key.read(from: proto) + let value = try Value.read(from: proto) + map.storage[key] = value + } + try proto.readMapEnd() + return map + } + + public func write(to proto: TProtocol) throws { + try proto.writeMapBegin(keyType: Key.thriftType, + valueType: Value.thriftType, size: Int32(self.count)) + for (key, value) in self.storage { + try Key.write(key, to: proto) + try Value.write(value, to: proto) + } + try proto.writeMapEnd() + } +} + +/// Mark: CustomStringConvertible, CustomDebugStringConvertible + +extension TMap : CustomStringConvertible, CustomDebugStringConvertible { + + public var description : String { + return storage.description + } + + public var debugDescription : String { + return storage.debugDescription + } + +} + +/// Mark: Equatable + +public func ==<Key, Value>(lhs: TMap<Key,Value>, rhs: TMap<Key, Value>) -> Bool { + if lhs.count != rhs.count { + return false + } + return lhs.storage.elementsEqual(rhs.storage) { $0.key == $1.key && $0.value == $1.value } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TMemoryBufferTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TMemoryBufferTransport.swift new file mode 100644 index 000000000..bd58b6ef7 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TMemoryBufferTransport.swift @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Foundation + +public class TMemoryBufferTransport : TTransport { + public private(set) var readBuffer = Data() + public private(set) var writeBuffer = Data() + + public private(set) var position = 0 + + public var bytesRemainingInBuffer: Int { + return readBuffer.count - position + } + + public func consumeBuffer(size: Int) { + position += size + } + public func clear() { + readBuffer = Data() + writeBuffer = Data() + } + + + private var flushHandler: ((TMemoryBufferTransport, Data) -> ())? + + public init(flushHandler: ((TMemoryBufferTransport, Data) -> ())? = nil) { + self.flushHandler = flushHandler + } + + public convenience init(readBuffer: Data, flushHandler: ((TMemoryBufferTransport, Data) -> ())? = nil) { + self.init() + self.readBuffer = readBuffer + } + + public func reset(readBuffer: Data = Data(), writeBuffer: Data = Data()) { + self.readBuffer = readBuffer + self.writeBuffer = writeBuffer + } + + public func read(size: Int) throws -> Data { + let amountToRead = min(bytesRemainingInBuffer, size) + if amountToRead > 0 { + let ret = readBuffer.subdata(in: Range(uncheckedBounds: (lower: position, upper: position + amountToRead))) + position += ret.count + return ret + } + return Data() + } + + public func write(data: Data) throws { + writeBuffer.append(data) + } + + public func flush() throws { + flushHandler?(self, writeBuffer) + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TMultiplexedProtocol.swift b/src/jaegertracing/thrift/lib/swift/Sources/TMultiplexedProtocol.swift new file mode 100644 index 000000000..73a8d51ab --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TMultiplexedProtocol.swift @@ -0,0 +1,47 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +public class TMultiplexedProtocol<Protocol: TProtocol>: TWrappedProtocol<Protocol> { + public let separator = ":" + + public var serviceName = "" + + public convenience init(on transport: TTransport, serviceName: String) { + self.init(on: transport) + self.serviceName = serviceName + } + + override public func writeMessageBegin(name: String, + type messageType: TMessageType, + sequenceID: Int32) throws { + switch messageType { + case .call, .oneway: + var serviceFunction = serviceName + serviceFunction += serviceName == "" ? "" : separator + serviceFunction += name + return try super.writeMessageBegin(name: serviceFunction, + type: messageType, + sequenceID: sequenceID) + default: + return try super.writeMessageBegin(name: name, + type: messageType, + sequenceID: sequenceID) + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TProcessor.swift b/src/jaegertracing/thrift/lib/swift/Sources/TProcessor.swift new file mode 100644 index 000000000..7ff222e41 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TProcessor.swift @@ -0,0 +1,29 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + + +public typealias TProcessorMessageHandler<T> = (Int, TProtocol, TProtocol, T) -> Void + +public protocol TProcessor { + associatedtype Service + var service: Service { get set } + func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws + init(service: Service) +} + diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TProtocol.swift b/src/jaegertracing/thrift/lib/swift/Sources/TProtocol.swift new file mode 100644 index 000000000..b4e5dbe73 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TProtocol.swift @@ -0,0 +1,182 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation + +public enum TMessageType: Int32 { + case call = 1 + case reply = 2 + case exception = 3 + case oneway = 4 +} + +public enum TType: Int32 { + case stop = 0 + case void = 1 + case bool = 2 + case i8 = 3 + case double = 4 + case i16 = 6 + case i32 = 8 + case i64 = 10 + case string = 11 + case `struct` = 12 + case map = 13 + case set = 14 + case list = 15 + case utf8 = 16 + case utf16 = 17 +} + +public protocol TProtocol { + var transport: TTransport { get set } + init(on transport: TTransport) + // Reading Methods + + func readMessageBegin() throws -> (String, TMessageType, Int32) + func readMessageEnd() throws + func readStructBegin() throws -> String + func readStructEnd() throws + func readFieldBegin() throws -> (String, TType, Int32) + func readFieldEnd() throws + func readMapBegin() throws -> (TType, TType, Int32) + func readMapEnd() throws + func readSetBegin() throws -> (TType, Int32) + func readSetEnd() throws + func readListBegin() throws -> (TType, Int32) + func readListEnd() throws + + func read() throws -> String + func read() throws -> Bool + func read() throws -> UInt8 + func read() throws -> Int16 + func read() throws -> Int32 + func read() throws -> Int64 + func read() throws -> Double + func read() throws -> Data + + // Writing methods + + func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws + func writeMessageEnd() throws + func writeStructBegin(name: String) throws + func writeStructEnd() throws + func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws + func writeFieldStop() throws + func writeFieldEnd() throws + func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws + func writeMapEnd() throws + func writeSetBegin(elementType: TType, size: Int32) throws + func writeSetEnd() throws + func writeListBegin(elementType: TType, size: Int32) throws + func writeListEnd() throws + + func write(_ value: String) throws + func write(_ value: Bool) throws + func write(_ value: UInt8) throws + func write(_ value: Int16) throws + func write(_ value: Int32) throws + func write(_ value: Int64) throws + func write(_ value: Double) throws + func write(_ value: Data) throws +} + +public extension TProtocol { + func writeFieldValue(_ value: TSerializable, name: String, type: TType, id: Int32) throws { + try writeFieldBegin(name: name, type: type, fieldID: id) + try value.write(to: self) + try writeFieldEnd() + } + + func validateValue(_ value: Any?, named name: String) throws { + if value == nil { + throw TProtocolError(error: .unknown, message: "Missing required value for field: \(name)") + } + } + + func readResultMessageBegin() throws { + let (_, type, _) = try readMessageBegin(); + if type == .exception { + let x = try readException() + throw x + } + return + } + + func readException() throws -> TApplicationError { + return try TApplicationError.read(from: self) + } + + func writeException(messageName name: String, sequenceID: Int32, ex: TApplicationError) throws { + try writeMessageBegin(name: name, type: .exception, sequenceID: sequenceID) + try ex.write(to: self) + try writeMessageEnd() + } + + func skip(type: TType) throws { + switch type { + case .bool: _ = try read() as Bool + case .i8: _ = try read() as UInt8 + case .i16: _ = try read() as Int16 + case .i32: _ = try read() as Int32 + case .i64: _ = try read() as Int64 + case .double: _ = try read() as Double + case .string: _ = try read() as String + + case .struct: + _ = try readStructBegin() + while true { + let (_, fieldType, _) = try readFieldBegin() + if fieldType == .stop { + break + } + try skip(type: fieldType) + try readFieldEnd() + } + try readStructEnd() + + + case .map: + let (keyType, valueType, size) = try readMapBegin() + for _ in 0..<size { + try skip(type: keyType) + try skip(type: valueType) + } + try readMapEnd() + + + case .set: + let (elemType, size) = try readSetBegin() + for _ in 0..<size { + try skip(type: elemType) + } + try readSetEnd() + + case .list: + let (elemType, size) = try readListBegin() + for _ in 0..<size { + try skip(type: elemType) + } + try readListEnd() + + default: + throw TProtocolError(error: .invalidData, message: "Invalid data") + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TProtocolError.swift b/src/jaegertracing/thrift/lib/swift/Sources/TProtocolError.swift new file mode 100644 index 000000000..a5d14f9ea --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TProtocolError.swift @@ -0,0 +1,146 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation + +public struct TProtocolError : TError { + public init() { } + + public enum Code : TErrorCode { + case unknown + case invalidData + case negativeSize + case sizeLimit(limit: Int, got: Int) + case badVersion(expected: String, got: String) + case notImplemented + case depthLimit + + public var thriftErrorCode: Int { + switch self { + case .unknown: return 0 + case .invalidData: return 1 + case .negativeSize: return 2 + case .sizeLimit: return 3 + case .badVersion: return 4 + case .notImplemented: return 5 + case .depthLimit: return 6 + } + + } + public var description: String { + switch self { + case .unknown: return "Unknown TProtocolError" + case .invalidData: return "Invalid Data" + case .negativeSize: return "Negative Size" + case .sizeLimit(let limit, let got): + return "Message exceeds size limit of \(limit) (received: \(got)" + case .badVersion(let expected, let got): + return "Bad Version. (Expected: \(expected), Got: \(got)" + case .notImplemented: return "Not Implemented" + case .depthLimit: return "Depth Limit" + } + } + } + + public enum ExtendedErrorCode : TErrorCode { + case unknown + case missingRequiredField(fieldName: String) + case unexpectedType(type: TType) + case mismatchedProtocol(expected: String, got: String) + public var thriftErrorCode: Int { + switch self { + case .unknown: return 1000 + case .missingRequiredField: return 1001 + case .unexpectedType: return 1002 + case .mismatchedProtocol: return 1003 + } + } + public var description: String { + switch self { + case .unknown: return "Unknown TProtocolExtendedError" + case .missingRequiredField(let fieldName): return "Missing Required Field: \(fieldName)" + case .unexpectedType(let type): return "Unexpected Type \(type.self)" + case .mismatchedProtocol(let expected, let got): return "Mismatched Protocol. (Expected: \(expected), got \(got))" + } + } + } + + public var extendedError: ExtendedErrorCode? = nil + + public init(error: Code = .unknown, + message: String? = nil, + extendedError: ExtendedErrorCode? = nil) { + self.error = error + self.message = message + self.extendedError = extendedError + } + + /// Mark: TError + public var error: Code = .unknown + public var message: String? = nil + public static var defaultCase: Code { return .unknown } + + public var description: String { + var out = "\(TProtocolError.self): (\(error.thriftErrorCode) \(error.description)\n" + if let extendedError = extendedError { + out += "TProtocolExtendedError (\(extendedError.thriftErrorCode)): \(extendedError.description)" + } + if let message = message { + out += "Message: \(message)" + } + return out + } +} + + +/// Wrapper for Transport errors in Protocols. Inspired by Thrift-Cocoa PROTOCOL_TRANSPORT_ERROR +/// macro. Modified to be more Swift-y. Catches any TError thrown within the block and +/// rethrows a given TProtocolError, the original error's description is appended to the new +/// TProtocolError's message. sourceFile, sourceLine, sourceMethod are auto-populated and should +/// be ignored when calling. +/// +/// - parameter error: TProtocolError to throw if the block throws +/// - parameter sourceFile: throwing file, autopopulated +/// - parameter sourceLine: throwing line, autopopulated +/// - parameter sourceMethod: throwing method, autopopulated +/// - parameter block: throwing block +/// +/// - throws: TProtocolError Default is TProtocolError.ErrorCode.unknown. Underlying +/// error's description appended to TProtocolError.message +func ProtocolTransportTry(error: TProtocolError = TProtocolError(), + sourceFile: String = #file, + sourceLine: Int = #line, + sourceMethod: String = #function, + block: () throws -> ()) throws { + // Need mutable copy + var error = error + do { + try block() + } catch let err as TError { + var message = error.message ?? "" + message += "\nFile: \(sourceFile)\n" + message += "Line: \(sourceLine)\n" + message += "Method: \(sourceMethod)" + message += "\nOriginal Error:\n" + err.description + error.message = message + throw error + } +} + + diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift new file mode 100644 index 000000000..d350f821e --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransport.swift @@ -0,0 +1,236 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation +import CoreFoundation + +#if !swift(>=4.2) +// Swift 3/4 compatibility +fileprivate extension RunLoopMode { + static let `default` = defaultRunLoopMode +} +#endif + +#if os(Linux) +public class TSSLSocketTransport { + init(hostname: String, port: UInt16) { + // FIXME! + assert(false, "Security not available in Linux, TSSLSocketTransport Unavilable for now") + } +} +#else +let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian +let htons = isLittleEndian ? _OSSwapInt16 : { $0 } +let htonl = isLittleEndian ? _OSSwapInt32 : { $0 } + +public class TSSLSocketTransport: TStreamTransport { + var sslHostname: String + var sd: Int32 = 0 + + public init(hostname: String, port: UInt16) throws { + sslHostname = hostname + var readStream: Unmanaged<CFReadStream>? + var writeStream: Unmanaged<CFWriteStream>? + + /* create a socket structure */ + var pin: sockaddr_in = sockaddr_in() + var hp: UnsafeMutablePointer<hostent>? = nil + for i in 0..<10 { + + hp = gethostbyname(hostname.cString(using: String.Encoding.utf8)!) + if hp == nil { + print("failed to resolve hostname \(hostname)") + herror("resolv") + if i == 9 { + super.init(inputStream: nil, outputStream: nil) // have to init before throwing + throw TSSLSocketTransportError(error: .hostanameResolution(hostname: hostname)) + } + Thread.sleep(forTimeInterval: 0.2) + } else { + break + } + } + pin.sin_family = UInt8(AF_INET) + pin.sin_addr = in_addr(s_addr: UInt32((hp?.pointee.h_addr_list.pointee?.pointee)!)) // Is there a better way to get this??? + pin.sin_port = htons(port) + + /* create the socket */ + sd = socket(Int32(AF_INET), Int32(SOCK_STREAM), Int32(IPPROTO_TCP)) + if sd == -1 { + super.init(inputStream: nil, outputStream: nil) // have to init before throwing + throw TSSLSocketTransportError(error: .socketCreate(port: Int(port))) + } + + /* open a connection */ + // need a non-self ref to sd, otherwise the j complains + let sd_local = sd + let connectResult = withUnsafePointer(to: &pin) { + connect(sd_local, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in>.size)) + } + if connectResult == -1 { + super.init(inputStream: nil, outputStream: nil) // have to init before throwing + throw TSSLSocketTransportError(error: .connect) + } + + CFStreamCreatePairWithSocket(kCFAllocatorDefault, sd, &readStream, &writeStream) + + CFReadStreamSetProperty(readStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue) + CFWriteStreamSetProperty(writeStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue) + + var inputStream: InputStream? = nil + var outputStream: OutputStream? = nil + if readStream != nil && writeStream != nil { + + CFReadStreamSetProperty(readStream?.takeRetainedValue(), + .socketSecurityLevel, + kCFStreamSocketSecurityLevelTLSv1) + + let settings: [String: Bool] = [kCFStreamSSLValidatesCertificateChain as String: true] + + CFReadStreamSetProperty(readStream?.takeRetainedValue(), + .SSLSettings, + settings as CFTypeRef) + + CFWriteStreamSetProperty(writeStream?.takeRetainedValue(), + .SSLSettings, + settings as CFTypeRef) + + inputStream = readStream!.takeRetainedValue() + inputStream?.schedule(in: .current, forMode: .default) + inputStream?.open() + + outputStream = writeStream!.takeRetainedValue() + outputStream?.schedule(in: .current, forMode: .default) + outputStream?.open() + + readStream?.release() + writeStream?.release() + } + + + super.init(inputStream: inputStream, outputStream: outputStream) + self.input?.delegate = self + self.output?.delegate = self + } + + func recoverFromTrustFailure(_ myTrust: SecTrust, lastTrustResult: SecTrustResultType) -> Bool { + let trustTime = SecTrustGetVerifyTime(myTrust) + let currentTime = CFAbsoluteTimeGetCurrent() + + let timeIncrement = 31536000 // from TSSLSocketTransport.m + let newTime = currentTime - Double(timeIncrement) + + if trustTime - newTime != 0 { + let newDate = CFDateCreate(nil, newTime) + SecTrustSetVerifyDate(myTrust, newDate!) + + var tr = lastTrustResult + let success = withUnsafeMutablePointer(to: &tr) { trPtr -> Bool in + if SecTrustEvaluate(myTrust, trPtr) != errSecSuccess { + return false + } + return true + } + if !success { return false } + } + if lastTrustResult == .proceed || lastTrustResult == .unspecified { + return false + } + + print("TSSLSocketTransport: Unable to recover certificate trust failure") + return true + } + + public func isOpen() -> Bool { + return sd > 0 + } +} + +extension TSSLSocketTransport: StreamDelegate { + public func stream(_ aStream: Stream, handle eventCode: Stream.Event) { + + switch eventCode { + case Stream.Event(): break + case Stream.Event.hasBytesAvailable: break + case Stream.Event.openCompleted: break + case Stream.Event.hasSpaceAvailable: + var proceed = false + var trustResult: SecTrustResultType = .invalid + + var newPolicies: CFMutableArray? + + repeat { + let trust: SecTrust = aStream.property(forKey: .SSLPeerTrust) as! SecTrust + + // Add new policy to current list of policies + let policy = SecPolicyCreateSSL(false, sslHostname as CFString?) + var ppolicy = policy // mutable for pointer + let policies: UnsafeMutablePointer<CFArray?>? = nil + if SecTrustCopyPolicies(trust, policies!) != errSecSuccess { + break + } + withUnsafeMutablePointer(to: &ppolicy) { ptr in + newPolicies = CFArrayCreateMutableCopy(nil, 0, policies?.pointee) + CFArrayAppendValue(newPolicies, ptr) + } + + // update trust policies + if SecTrustSetPolicies(trust, newPolicies!) != errSecSuccess { + break + } + + // Evaluate the trust chain + let success = withUnsafeMutablePointer(to: &trustResult) { trustPtr -> Bool in + if SecTrustEvaluate(trust, trustPtr) != errSecSuccess { + return false + } + return true + } + + if !success { + break + } + + + switch trustResult { + case .proceed: proceed = true + case .unspecified: proceed = true + case .recoverableTrustFailure: + proceed = self.recoverFromTrustFailure(trust, lastTrustResult: trustResult) + + case .deny: break + case .fatalTrustFailure: break + case .otherError: break + case .invalid: break + default: break + } + } while false + + if !proceed { + print("TSSLSocketTransport: Cannot trust certificate. Result: \(trustResult)") + aStream.close() + } + + case Stream.Event.errorOccurred: break + case Stream.Event.endEncountered: break + default: break + } + } +} +#endif diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransportError.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransportError.swift new file mode 100644 index 000000000..fda162bd5 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TSSLSocketTransportError.swift @@ -0,0 +1,48 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +public struct TSSLSocketTransportError: TError { + public enum ErrorCode: TErrorCode { + case hostanameResolution(hostname: String) + case socketCreate(port: Int) + case connect + + public var thriftErrorCode: Int { + switch self { + case .hostanameResolution: return -10000 + case .socketCreate: return -10001 + case .connect: return -10002 + } + } + + public var description: String { + switch self { + case .hostanameResolution(let hostname): return "Failed to resolve hostname: \(hostname)" + case .socketCreate(let port): return "Could not create socket on port: \(port)" + case .connect: return "Connect error" + } + } + + } + public var error: ErrorCode = .connect + public var message: String? + public static var defaultCase: ErrorCode { return .connect } + + public init() { } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSerializable.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSerializable.swift new file mode 100644 index 000000000..b45096b69 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TSerializable.swift @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Foundation + + +public protocol TSerializable { + var hashValue: Int { get } + + /// TType for instance + static var thriftType: TType { get } + + /// Read TSerializable instance from Protocol + static func read(from proto: TProtocol) throws -> Self + + /// Write TSerializable instance to Protocol + func write(to proto: TProtocol) throws + +} + +extension TSerializable { + public static func write(_ value: Self, to proto: TProtocol) throws { + try value.write(to: proto) + } + + /// convenience for member access + public var thriftType: TType { return Self.thriftType } +} + +public func ==<T>(lhs: T, rhs: T) -> Bool where T : TSerializable { + return lhs.hashValue == rhs.hashValue +} + +/// Default read/write for primitave Thrift types: +/// Bool, Int8 (byte), Int16, Int32, Int64, Double, String + +extension Bool : TSerializable { + public static var thriftType: TType { return .bool } + + public static func read(from proto: TProtocol) throws -> Bool { + return try proto.read() + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} + +extension Int8 : TSerializable { + public static var thriftType: TType { return .i8 } + + public static func read(from proto: TProtocol) throws -> Int8 { + return Int8(try proto.read() as UInt8) + } + + public func write(to proto: TProtocol) throws { + try proto.write(UInt8(self)) + } +} + +extension Int16 : TSerializable { + public static var thriftType: TType { return .i16 } + + public static func read(from proto: TProtocol) throws -> Int16 { + return try proto.read() + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} + +extension Int32 : TSerializable { + public static var thriftType: TType { return .i32 } + + public static func read(from proto: TProtocol) throws -> Int32 { + return try proto.read() + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} + + +extension Int64 : TSerializable { + public static var thriftType: TType { return .i64 } + + public static func read(from proto: TProtocol) throws -> Int64 { + return try proto.read() + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} + +extension Double : TSerializable { + public static var thriftType: TType { return .double } + + public static func read(from proto: TProtocol) throws -> Double { + return try proto.read() + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} + +extension String : TSerializable { + public static var thriftType: TType { return .string } + + public static func read(from proto: TProtocol) throws -> String { + return try proto.read() + } + + public func write(to proto: TProtocol) throws { + try proto.write(self) + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSet.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSet.swift new file mode 100644 index 000000000..6891c11e6 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TSet.swift @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Foundation + +public struct TSet<Element : TSerializable & Hashable> : SetAlgebra, Hashable, Collection, ExpressibleByArrayLiteral, TSerializable { + /// Typealias for Storage type + public typealias Storage = Set<Element> + + + /// Internal Storage used for TSet (Set\<Element\>) + internal var storage : Storage + + + /// Mark: Collection + + public typealias Indices = Storage.Indices + public typealias Index = Storage.Index + public typealias IndexDistance = Int + public typealias SubSequence = Storage.SubSequence + + + public var indices: Indices { return storage.indices } + + // Must implement isEmpty even though both SetAlgebra and Collection provide it due to their conflciting default implementations + public var isEmpty: Bool { return storage.isEmpty } + + public func distance(from start: Index, to end: Index) -> IndexDistance { + return storage.distance(from: start, to: end) + } + + public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { + return storage.index(i, offsetBy: n) + } + + public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? { + return storage.index(i, offsetBy: n, limitedBy: limit) + } + + #if swift(>=3.2) + public subscript (position: Storage.Index) -> Element { + return storage[position] + } + #else + public subscript (position: Storage.Index) -> Element? { + return storage[position] + } + #endif + + /// Mark: SetAlgebra + internal init(storage: Set<Element>) { + self.storage = storage + } + + public func contains(_ member: Element) -> Bool { + return storage.contains(member) + } + + public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) { + return storage.insert(newMember) + } + + public mutating func remove(_ member: Element) -> Element? { + return storage.remove(member) + } + + public func union(_ other: TSet<Element>) -> TSet { + return TSet(storage: storage.union(other.storage)) + } + + public mutating func formIntersection(_ other: TSet<Element>) { + return storage.formIntersection(other.storage) + } + + public mutating func formSymmetricDifference(_ other: TSet<Element>) { + return storage.formSymmetricDifference(other.storage) + } + + public mutating func formUnion(_ other: TSet<Element>) { + return storage.formUnion(other.storage) + } + + public func intersection(_ other: TSet<Element>) -> TSet { + return TSet(storage: storage.intersection(other.storage)) + } + + public func symmetricDifference(_ other: TSet<Element>) -> TSet { + return TSet(storage: storage.symmetricDifference(other.storage)) + } + + public mutating func update(with newMember: Element) -> Element? { + return storage.update(with: newMember) + } + + /// Mark: IndexableBase + + public var startIndex: Index { return storage.startIndex } + public var endIndex: Index { return storage.endIndex } + public func index(after i: Index) -> Index { + return storage.index(after: i) + } + + public func formIndex(after i: inout Storage.Index) { + storage.formIndex(after: &i) + } + + public subscript(bounds: Range<Index>) -> SubSequence { + return storage[bounds] + } + + + /// Mark: Hashable + public var hashValue : Int { + let prime = 31 + var result = 1 + for element in storage { + result = prime &* result &+ element.hashValue + } + return result + } + + /// Mark: TSerializable + public static var thriftType : TType { return .set } + + public init() { + storage = Storage() + } + + public init(arrayLiteral elements: Element...) { + self.storage = Storage(elements) + } + + public init<Source : Sequence>(_ sequence: Source) where Source.Iterator.Element == Element { + storage = Storage(sequence) + } + + public static func read(from proto: TProtocol) throws -> TSet { + let (elementType, size) = try proto.readSetBegin() + if elementType != Element.thriftType { + throw TProtocolError(error: .invalidData, + extendedError: .unexpectedType(type: elementType)) + } + var set = TSet() + for _ in 0..<size { + let element = try Element.read(from: proto) + set.storage.insert(element) + } + try proto.readSetEnd() + return set + } + + public func write(to proto: TProtocol) throws { + try proto.writeSetBegin(elementType: Element.thriftType, size: Int32(self.count)) + for element in self.storage { + try Element.write(element, to: proto) + } + try proto.writeSetEnd() + } +} + +extension TSet: CustomStringConvertible, CustomDebugStringConvertible { + public var description : String { + return storage.description + } + public var debugDescription : String { + return storage.debugDescription + } + +} + +public func ==<Element>(lhs: TSet<Element>, rhs: TSet<Element>) -> Bool { + return lhs.storage == rhs.storage +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSocketServer.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSocketServer.swift new file mode 100644 index 000000000..7367c7edc --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TSocketServer.swift @@ -0,0 +1,148 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) + import Darwin +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) + import Glibc + import Dispatch +#endif + +import Foundation +import CoreFoundation + +public let TSocketServerClientConnectionFinished = "TSocketServerClientConnectionFinished" +public let TSocketServerProcessorKey = "TSocketServerProcessor" +public let TSocketServerTransportKey = "TSocketServerTransport" + +class TSocketServer<InProtocol: TProtocol, OutProtocol: TProtocol, Processor: TProcessor, Service> where Processor.Service == Service { + var socketFileHandle: FileHandle + var processingQueue = DispatchQueue(label: "TSocketServer.processing", + qos: .background, + attributes: .concurrent) + var serviceHandler: Service + + public init(port: Int, + service: Service, + inProtocol: InProtocol.Type, + outProtocol: OutProtocol.Type, + processor: Processor.Type) throws { + // set service handler + self.serviceHandler = service + + // create a socket + var fd: Int32 = -1 + #if os(Linux) + let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, Int32(SOCK_STREAM.rawValue), Int32(IPPROTO_TCP), 0, nil, nil) + #else + let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, nil, nil) + #endif + if sock != nil { + CFSocketSetSocketFlags(sock, CFSocketGetSocketFlags(sock) & ~kCFSocketCloseOnInvalidate) + + fd = CFSocketGetNative(sock) + var yes = 1 + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, UInt32(MemoryLayout<Int>.size)) + + #if os(Linux) + var addr = sockaddr_in(sin_family: sa_family_t(AF_INET), + sin_port: in_port_t(port.bigEndian), + sin_addr: in_addr(s_addr: in_addr_t(0)), + sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) + #else + var addr = sockaddr_in(sin_len: UInt8(MemoryLayout<sockaddr_in>.size), + sin_family: sa_family_t(AF_INET), + sin_port: in_port_t(port.bigEndian), + sin_addr: in_addr(s_addr: in_addr_t(0)), + sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) + #endif + + let ptr = withUnsafePointer(to: &addr) { + return UnsafePointer<UInt8>(OpaquePointer($0)) + } + + let address = Data(bytes: ptr, count: MemoryLayout<sockaddr_in>.size) + + let cfaddr = address.withUnsafeBytes { + CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, $0, address.count, nil) + } + if CFSocketSetAddress(sock, cfaddr) != CFSocketError.success { //kCFSocketSuccess { + CFSocketInvalidate(sock) + print("TSocketServer: Could not bind to address") + throw TTransportError(error: .notOpen, message: "Could not bind to address") + } + + } else { + print("TSocketServer: No server socket") + throw TTransportError(error: .notOpen, message: "Could not create socket") + } + + // wrap it in a file handle so we can get messages from it + socketFileHandle = FileHandle(fileDescriptor: fd, closeOnDealloc: true) + + // throw away our socket + CFSocketInvalidate(sock) + + // register for notifications of accepted incoming connections + _ = NotificationCenter.default.addObserver(forName: .NSFileHandleConnectionAccepted, + object: nil, queue: nil) { + [weak self] notification in + guard let strongSelf = self else { return } + strongSelf.connectionAccepted(strongSelf.socketFileHandle) + } + + // tell socket to listen + socketFileHandle.acceptConnectionInBackgroundAndNotify() + + print("TSocketServer: Listening on TCP port \(port)") + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + func connectionAccepted(_ socket: FileHandle) { + // Now that we have a client connected, handle the request on queue + processingQueue.async { + self.handleClientConnection(socket) + } + } + + func handleClientConnection(_ clientSocket: FileHandle) { + + let transport = TFileHandleTransport(fileHandle: clientSocket) + let processor = Processor(service: serviceHandler) + + let inProtocol = InProtocol(on: transport) + let outProtocol = OutProtocol(on: transport) + + do { + try processor.process(on: inProtocol, outProtocol: outProtocol) + } catch let error { + print("Error processign request: \(error)") + } + DispatchQueue.main.async { + NotificationCenter.default + .post(name: Notification.Name(rawValue: TSocketServerClientConnectionFinished), + object: self, + userInfo: [TSocketServerProcessorKey: processor, + TSocketServerTransportKey: transport]) + } + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TSocketTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TSocketTransport.swift new file mode 100644 index 000000000..21325033b --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TSocketTransport.swift @@ -0,0 +1,216 @@ + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) + import Darwin +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) + import Glibc + import Dispatch +#endif + +import Foundation +import CoreFoundation + +#if !swift(>=4.2) +// Swift 3/4 compatibility +fileprivate extension RunLoopMode { + static let `default` = defaultRunLoopMode +} +#endif + +private struct Sys { + #if os(Linux) + static let read = Glibc.read + static let write = Glibc.write + static let close = Glibc.close + #else + static let read = Darwin.read + static let write = Darwin.write + static let close = Darwin.close + #endif +} + +extension in_addr { + public init?(hostent: hostent?) { + guard let host = hostent, host.h_addr_list != nil, host.h_addr_list.pointee != nil else { + return nil + } + self.init() + memcpy(&self, host.h_addr_list.pointee!, Int(host.h_length)) + + } +} + + +#if os(Linux) + /// TCFSocketTransport currently unavailable + /// remove comments and build to see why/fix + /// currently CF[Read|Write]Stream's can't cast to [Input|Output]Streams which breaks thigns +#else +extension Stream.PropertyKey { + static let SSLPeerTrust = Stream.PropertyKey(kCFStreamPropertySSLPeerTrust as String) +} + +/// TCFSocketTransport, uses CFSockets and (NS)Stream's +public class TCFSocketTransport: TStreamTransport { + public init?(hostname: String, port: Int, secure: Bool = false) { + + var inputStream: InputStream + var outputStream: OutputStream + + var readStream: Unmanaged<CFReadStream>? + var writeStream: Unmanaged<CFWriteStream>? + CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, + hostname as CFString, + UInt32(port), + &readStream, + &writeStream) + + if let readStream = readStream?.takeRetainedValue(), + let writeStream = writeStream?.takeRetainedValue() { + CFReadStreamSetProperty(readStream, .shouldCloseNativeSocket, kCFBooleanTrue) + CFWriteStreamSetProperty(writeStream, .shouldCloseNativeSocket, kCFBooleanTrue) + + if secure { + CFReadStreamSetProperty(readStream, .socketSecurityLevel, StreamSocketSecurityLevel.negotiatedSSL.rawValue as CFString) + CFWriteStreamSetProperty(writeStream, .socketSecurityLevel, StreamSocketSecurityLevel.negotiatedSSL.rawValue as CFString) + } + + inputStream = readStream as InputStream + inputStream.schedule(in: .current, forMode: .default) + inputStream.open() + + outputStream = writeStream as OutputStream + outputStream.schedule(in: .current, forMode: .default) + outputStream.open() + + } else { + + if readStream != nil { + readStream?.release() + } + if writeStream != nil { + writeStream?.release() + } + super.init(inputStream: nil, outputStream: nil) + return nil + } + + super.init(inputStream: inputStream, outputStream: outputStream) + + self.input?.delegate = self + self.output?.delegate = self + } +} + +extension TCFSocketTransport: StreamDelegate { } +#endif + + +/// TSocketTransport, posix sockets. Supports IPv4 only for now +public class TSocketTransport : TTransport { + public var socketDescriptor: Int32 + + + + /// Initialize from an already set up socketDescriptor. + /// Expects socket thats already bound/connected (i.e. from listening) + /// + /// - parameter socketDescriptor: posix socket descriptor (Int32) + public init(socketDescriptor: Int32) { + self.socketDescriptor = socketDescriptor + } + + + public convenience init(hostname: String, port: Int) throws { + guard let hp = gethostbyname(hostname.cString(using: .utf8)!)?.pointee, + let hostAddr = in_addr(hostent: hp) else { + throw TTransportError(error: .unknown, message: "Invalid address: \(hostname)") + } + + + #if os(Linux) + let sock = socket(AF_INET, Int32(SOCK_STREAM.rawValue), 0) + var addr = sockaddr_in(sin_family: sa_family_t(AF_INET), + sin_port: in_port_t(htons(UInt16(port))), + sin_addr: hostAddr, + sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) + #else + let sock = socket(AF_INET, SOCK_STREAM, 0) + + var addr = sockaddr_in(sin_len: UInt8(MemoryLayout<sockaddr_in>.size), + sin_family: sa_family_t(AF_INET), + sin_port: in_port_t(htons(UInt16(port))), + sin_addr: in_addr(s_addr: in_addr_t(0)), + sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) + + #endif + + let addrPtr = withUnsafePointer(to: &addr){ UnsafePointer<sockaddr>(OpaquePointer($0)) } + + let connected = connect(sock, addrPtr, UInt32(MemoryLayout<sockaddr_in>.size)) + if connected != 0 { + throw TTransportError(error: .notOpen, message: "Error binding to host: \(hostname) \(port)") + } + + self.init(socketDescriptor: sock) + } + + deinit { + close() + } + + public func readAll(size: Int) throws -> Data { + var out = Data() + while out.count < size { + out.append(try self.read(size: size)) + } + return out + } + + public func read(size: Int) throws -> Data { + var buff = Array<UInt8>.init(repeating: 0, count: size) + let readBytes = Sys.read(socketDescriptor, &buff, size) + + return Data(buff[0..<readBytes]) + } + + public func write(data: Data) { + var bytesToWrite = data.count + var writeBuffer = data + while bytesToWrite > 0 { + let written = writeBuffer.withUnsafeBytes { + Sys.write(socketDescriptor, $0, writeBuffer.count) + } + writeBuffer = writeBuffer.subdata(in: written ..< writeBuffer.count) + bytesToWrite -= written + } + } + + public func flush() throws { + // nothing to do + } + + public func close() { + shutdown(socketDescriptor, Int32(SHUT_RDWR)) + _ = Sys.close(socketDescriptor) + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TStreamTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TStreamTransport.swift new file mode 100644 index 000000000..d9c957422 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TStreamTransport.swift @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Foundation +import CoreFoundation + +#if !swift(>=4.2) +// Swift 3/4 compatibility +fileprivate extension RunLoopMode { + static let `default` = defaultRunLoopMode +} +#endif + +#if os(Linux) + /// Currently unavailable in Linux + /// Remove comments and build to fix + /// Currently kConstants for CFSockets don't exist in linux and not all have been moved + /// to property structs yet +#else + // Must inherit NSObject for NSStreamDelegate conformance + public class TStreamTransport : NSObject, TTransport { + public var input: InputStream? = nil + public var output: OutputStream? = nil + + public init(inputStream: InputStream?, outputStream: OutputStream?) { + input = inputStream + output = outputStream + } + + public convenience init(inputStream: InputStream?) { + self.init(inputStream: inputStream, outputStream: nil) + } + + public convenience init(outputStream: OutputStream?) { + self.init(inputStream: nil, outputStream: outputStream) + } + + deinit { + close() + } + + public func readAll(size: Int) throws -> Data { + guard let input = input else { + throw TTransportError(error: .unknown) + } + + var read = Data() + while read.count < size { + var buffer = Array<UInt8>(repeating: 0, count: size - read.count) + + let bytesRead = buffer.withUnsafeMutableBufferPointer { bufferPtr in + return input.read(bufferPtr.baseAddress!, maxLength: size - read.count) + } + + if bytesRead <= 0 { + throw TTransportError(error: .notOpen) + } + read.append(Data(buffer)) + } + return read + } + + public func read(size: Int) throws -> Data { + guard let input = input else { + throw TTransportError(error: .unknown) + } + + var read = Data() + while read.count < size { + var buffer = Array<UInt8>(repeating: 0, count: size - read.count) + let bytesRead = buffer.withUnsafeMutableBufferPointer { + input.read($0.baseAddress!, maxLength: size - read.count) + } + + if bytesRead <= 0 { + break + } + + read.append(Data(buffer)) + } + return read + } + + public func write(data: Data) throws { + guard let output = output else { + throw TTransportError(error: .unknown) + } + + var bytesWritten = 0 + while bytesWritten < data.count { + bytesWritten = data.withUnsafeBytes { + return output.write($0, maxLength: data.count) + } + + if bytesWritten == -1 { + throw TTransportError(error: .notOpen) + } else if bytesWritten == 0 { + throw TTransportError(error: .endOfFile) + } + } + } + + + public func flush() throws { + return + } + + public func close() { + + if input != nil { + // Close and reset inputstream + if let cf: CFReadStream = input { + CFReadStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue) + } + + input?.delegate = nil + input?.close() + input?.remove(from: .current, forMode: .default) + input = nil + } + + if output != nil { + // Close and reset output stream + if let cf: CFWriteStream = output { + CFWriteStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue) + } + output?.delegate = nil + output?.close() + output?.remove(from: .current, forMode: .default) + output = nil + } + } + } +#endif diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TStruct.swift b/src/jaegertracing/thrift/lib/swift/Sources/TStruct.swift new file mode 100644 index 000000000..38e51e702 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TStruct.swift @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +/// Protocol for Generated Structs to conform to +/// Dictionary maps field names to internal IDs and uses Reflection +/// to iterate through all fields. +/// `writeFieldValue(_:name:type:id:)` calls `TSerializable.write(to:)` internally +/// giving a nice recursive behavior for nested TStructs, TLists, TMaps, and TSets +public protocol TStruct : TSerializable { + static var fieldIds: [String: Int32] { get } + static var structName: String { get } +} + +public extension TStruct { + static var fieldIds: [String: (id: Int32, type: TType)] { return [:] } + static var thriftType: TType { return .struct } + + func write(to proto: TProtocol) throws { + // Write struct name first + try proto.writeStructBegin(name: Self.structName) + + try self.forEach { name, value, id in + // Write to protocol + try proto.writeFieldValue(value, name: name, + type: value.thriftType, id: id) + } + try proto.writeFieldStop() + try proto.writeStructEnd() + } + + var hashValue: Int { + let prime = 31 + var result = 1 + self.forEach { _, value, _ in + result = prime &* result &+ (value.hashValue) + } + return result + } + + /// Provides a block for handling each (available) thrift property using reflection + /// Caveat: Skips over optional values + + + /// Provides a block for handling each (available) thrift property using reflection + /// + /// - parameter block: block for handling property + /// + /// - throws: rethrows any Error thrown in block + private func forEach(_ block: (_ name: String, _ value: TSerializable, _ id: Int32) throws -> Void) rethrows { + // Mirror the object, getting (name: String?, value: Any) for every property + let mirror = Mirror(reflecting: self) + + // Iterate through all children, ignore empty property names + for (propName, propValue) in mirror.children { + guard let propName = propName else { continue } + + if let tval = unwrap(any: propValue) as? TSerializable, let id = Self.fieldIds[propName] { + try block(propName, tval, id) + } + } + } + + + /// Any can mysteriously be an Optional<Any> at the same time, + /// this checks and always returns Optional<Any> without double wrapping + /// we then try to bind value as TSerializable to ignore any extension properties + /// and the like and verify the property exists and grab the Thrift + /// property ID at the same time + /// + /// - parameter any: Any instance to attempt to unwrap + /// + /// - returns: Unwrapped Any as Optional<Any> + private func unwrap(any: Any) -> Any? { + let mi = Mirror(reflecting: any) + + if mi.displayStyle != .optional { return any } + if mi.children.count == 0 { return nil } + + let (_, some) = mi.children.first! + return some + } +} + diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/TTransport.swift new file mode 100644 index 000000000..e82bbe140 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TTransport.swift @@ -0,0 +1,64 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation + +public protocol TTransport { + + // Required + func read(size: Int) throws -> Data + func write(data: Data) throws + func flush() throws + + // Optional (default provided) + func readAll(size: Int) throws -> Data + func isOpen() throws -> Bool + func open() throws + func close() throws +} + +public extension TTransport { + func isOpen() throws -> Bool { return true } + func open() throws { } + func close() throws { } + + func readAll(size: Int) throws -> Data { + var buff = Data() + var have = 0 + while have < size { + let chunk = try self.read(size: size - have) + have += chunk.count + buff.append(chunk) + if chunk.count == 0 { + throw TTransportError(error: .endOfFile) + } + } + return buff + } +} + +public protocol TAsyncTransport : TTransport { + // Factory + func flush(_ completion: @escaping (TAsyncTransport, Error?) ->()) +} + +public protocol TAsyncTransportFactory { + associatedtype Transport : TAsyncTransport + func newTransport() -> Transport +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TTransportError.swift b/src/jaegertracing/thrift/lib/swift/Sources/TTransportError.swift new file mode 100644 index 000000000..3fd005937 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TTransportError.swift @@ -0,0 +1,86 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +public struct TTransportError: TError { + public enum ErrorCode: TErrorCode { + case unknown + case notOpen + case alreadyOpen + case timedOut + case endOfFile + case negativeSize + case sizeLimit(limit: Int, got: Int) + + public var thriftErrorCode: Int { + switch self { + case .unknown: return 0 + case .notOpen: return 1 + case .alreadyOpen: return 2 + case .timedOut: return 3 + case .endOfFile: return 4 + case .negativeSize: return 5 + case .sizeLimit: return 6 + } + } + public var description: String { + switch self { + case .unknown: return "Unknown TTransportError" + case .notOpen: return "Not Open" + case .alreadyOpen: return "Already Open" + case .timedOut: return "Timed Out" + case .endOfFile: return "End Of File" + case .negativeSize: return "Negative Size" + case .sizeLimit(let limit, let got): + return "Message exceeds size limit of \(limit) (received: \(got)" + } + } + } + public var error: ErrorCode = .unknown + public var message: String? = nil + public static var defaultCase: ErrorCode { return .unknown } + + public init() { } + +} + +/// THTTPTransportError +/// +/// Error's thrown on HTTP Transport +public struct THTTPTransportError: TError { + public enum ErrorCode: TErrorCode { + case invalidResponse + case invalidStatus(statusCode: Int) + case authentication + + public var description: String { + switch self { + case .invalidResponse: return "Invalid HTTP Response" + case .invalidStatus(let statusCode): return "Invalid HTTP Status Code (\(statusCode))" + case .authentication: return "Authentication Error" + } + } + public var thriftErrorCode: Int { return 0 } + } + public var error: ErrorCode = .invalidResponse + public var message: String? = nil + public static var defaultCase: ErrorCode { return .invalidResponse } + + public init() { } +} + diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TWrappedProtocol.swift b/src/jaegertracing/thrift/lib/swift/Sources/TWrappedProtocol.swift new file mode 100644 index 000000000..8e8577bb5 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/TWrappedProtocol.swift @@ -0,0 +1,208 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation // For (NS)Data + + +/// Generic protocol, implementes TProtocol and wraps a concrete protocol. +/// Useful for generically subclassing protocols to override specific methods +/// (i.e. TMultiplexedProtocol) +open class TWrappedProtocol<Protocol: TProtocol> : TProtocol { + var concreteProtocol: Protocol + + public var transport: TTransport { + get { + return concreteProtocol.transport + } + set { + concreteProtocol.transport = newValue + } + } + + public required init(on transport: TTransport) { + self.concreteProtocol = Protocol(on: transport) + } + + // Read methods + + public func readMessageBegin() throws -> (String, TMessageType, Int32) { + return try concreteProtocol.readMessageBegin() + } + + public func readMessageEnd() throws { + try concreteProtocol.readMessageEnd() + } + + public func readStructBegin() throws -> String { + return try concreteProtocol.readStructBegin() + } + + public func readStructEnd() throws { + try concreteProtocol.readStructEnd() + } + + public func readFieldBegin() throws -> (String, TType, Int32) { + return try concreteProtocol.readFieldBegin() + } + + public func readFieldEnd() throws { + try concreteProtocol.readFieldEnd() + } + + public func readMapBegin() throws -> (TType, TType, Int32) { + return try concreteProtocol.readMapBegin() + } + + public func readMapEnd() throws { + try concreteProtocol.readMapEnd() + } + + public func readSetBegin() throws -> (TType, Int32) { + return try concreteProtocol.readSetBegin() + } + + public func readSetEnd() throws { + try concreteProtocol.readSetEnd() + } + + public func readListBegin() throws -> (TType, Int32) { + return try concreteProtocol.readListBegin() + } + + public func readListEnd() throws { + try concreteProtocol.readListEnd() + } + + public func read() throws -> String { + return try concreteProtocol.read() + } + + public func read() throws -> Bool { + return try concreteProtocol.read() + } + + public func read() throws -> UInt8 { + return try concreteProtocol.read() + } + + public func read() throws -> Int16 { + return try concreteProtocol.read() + } + + public func read() throws -> Int32 { + return try concreteProtocol.read() + } + + public func read() throws -> Int64 { + return try concreteProtocol.read() + } + + public func read() throws -> Double { + return try concreteProtocol.read() + } + + public func read() throws -> Data { + return try concreteProtocol.read() + } + + // Write methods + + public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { + return try concreteProtocol.writeMessageBegin(name: name, type: messageType, sequenceID: sequenceID) + } + + public func writeMessageEnd() throws { + try concreteProtocol.writeMessageEnd() + } + + public func writeStructBegin(name: String) throws { + try concreteProtocol.writeStructBegin(name: name) + } + + public func writeStructEnd() throws { + try concreteProtocol.writeStructEnd() + } + + public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { + try concreteProtocol.writeFieldBegin(name: name, type: fieldType, fieldID: fieldID) + } + + public func writeFieldStop() throws { + try concreteProtocol.writeFieldStop() + } + + public func writeFieldEnd() throws { + try concreteProtocol.writeFieldEnd() + } + + public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { + try concreteProtocol.writeMapBegin(keyType: keyType, valueType: valueType, size: size) + } + + public func writeMapEnd() throws { + try concreteProtocol.writeMapEnd() + } + + public func writeSetBegin(elementType: TType, size: Int32) throws { + try concreteProtocol.writeSetBegin(elementType: elementType, size: size) + } + + public func writeSetEnd() throws { + try concreteProtocol.writeSetEnd() + } + + public func writeListBegin(elementType: TType, size: Int32) throws { + try concreteProtocol.writeListBegin(elementType: elementType, size: size) + } + + public func writeListEnd() throws { + try concreteProtocol.writeListEnd() + } + public func write(_ value: String) throws { + try concreteProtocol.write(value) + } + + public func write(_ value: Bool) throws { + try concreteProtocol.write(value) + } + + public func write(_ value: UInt8) throws { + try concreteProtocol.write(value) + } + + public func write(_ value: Int16) throws { + try concreteProtocol.write(value) + } + + public func write(_ value: Int32) throws { + try concreteProtocol.write(value) + } + + public func write(_ value: Int64) throws { + try concreteProtocol.write(value) + } + + public func write(_ value: Double) throws { + try concreteProtocol.write(value) + } + + public func write(_ data: Data) throws { + try concreteProtocol.write(data) + } +} diff --git a/src/jaegertracing/thrift/lib/swift/Sources/Thrift.swift b/src/jaegertracing/thrift/lib/swift/Sources/Thrift.swift new file mode 100644 index 000000000..45c68f2e5 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/Thrift.swift @@ -0,0 +1,3 @@ +class Thrift { + let version = "0.13.0" +} |