Skip to content

Commit

Permalink
Merge branch 'mqtt_test_app' of https://github.com/awslabs/aws-crt-swift
Browse files Browse the repository at this point in the history
 into device_farm
  • Loading branch information
xiazhvera committed Jul 19, 2024
2 parents bd3ae01 + c0e4aa6 commit 77b0dcd
Show file tree
Hide file tree
Showing 18 changed files with 166 additions and 93 deletions.
6 changes: 5 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ awsCCommonPlatformExcludes.append("source/arch/arm")
#if !os(Windows)
awsCCommonPlatformExcludes.append("source/windows")
#endif
let cSettingsCommon: [CSetting] = [
.headerSearchPath("source/external/libcbor"),
.define("DEBUG_BUILD", .when(configuration: .debug))
]

//////////////////////////////////////////////////////////////////////
/// aws-c-cal
Expand Down Expand Up @@ -207,7 +211,7 @@ packageTargets.append(contentsOf: [
dependencies: ["AwsCPlatformConfig"],
path: "aws-common-runtime/aws-c-common",
exclude: awsCCommonPlatformExcludes,
cSettings: cSettings
cSettings: cSettingsCommon
),
.target(
name: "AwsCSdkUtils",
Expand Down
53 changes: 42 additions & 11 deletions Source/AwsCommonRuntimeKit/auth/signing/SigningConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public struct SigningConfig: CStructWithUserData {
return withByteCursorFromStrings(
region,
service,
signedBodyValue.rawValue) { regionCursor, serviceCursor, signedBodyValueCursor in
signedBodyValue.description) { regionCursor, serviceCursor, signedBodyValueCursor in

cConfig.region = regionCursor
cConfig.service = serviceCursor
Expand Down Expand Up @@ -174,25 +174,56 @@ public enum SignedBodyHeaderType {
/// Optional string to use as the canonical request's body value.
/// Typically, this is the SHA-256 of the (request/chunk/event) payload, written as lowercase hex.
/// If this has been precalculated, it can be set here. Special values used by certain services can also be set.
public enum SignedBodyValue: String {
public enum SignedBodyValue: CustomStringConvertible, Equatable {
/// if empty, a public value will be calculated from the payload during signing
case empty = ""
case empty
/// For empty sha256
case emptySha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
case emptySha256
/// Use this to provide a precalculated sha256 value
case precomputedSha256(String)
/// Use this in the case of needing to not use the payload for signing
case unsignedPayload = "UNSIGNED-PAYLOAD"
case unsignedPayload
/// For streaming sha256 payload
case streamingSha256Payload = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
case streamingSha256Payload
/// For streaming sha256 payload trailer
case streamingSha256PayloadTrailer = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER"
case streamingSha256PayloadTrailer
/// For streaming sigv4a sha256 payload
case streamingECDSA_P256Sha256Payload = "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD"
case streamingECDSA_P256Sha256Payload
/// For streaming sigv4a sha256 payload trailer
case streamingECDSA_P256Sha256PayloadTrailer = "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD-TRAILER"
case streamingECDSA_P256Sha256PayloadTrailer
/// For streaming sigv4a sha256 events
case streamingSha256Events = "STREAMING-AWS4-HMAC-SHA256-EVENTS"
case streamingSha256Events
/// For streaming unsigned payload trailer
case streamingUnSignedPayloadTrailer = "STREAMING-UNSIGNED-PAYLOAD-TRAILER"
case streamingUnSignedPayloadTrailer

public var description: String {
switch self {
case .empty:
return ""
case .emptySha256:
return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
case .precomputedSha256(let value):
return value
case .unsignedPayload:
return "UNSIGNED-PAYLOAD"
case .streamingSha256Payload:
return "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
case .streamingSha256PayloadTrailer:
return "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER"
case .streamingECDSA_P256Sha256Payload:
return "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD"
case .streamingECDSA_P256Sha256PayloadTrailer:
return "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD-TRAILER"
case .streamingSha256Events:
return "STREAMING-AWS4-HMAC-SHA256-EVENTS"
case .streamingUnSignedPayloadTrailer:
return "STREAMING-UNSIGNED-PAYLOAD-TRAILER"
}
}

public static func == (lhs: SignedBodyValue, rhs: SignedBodyValue) -> Bool {
return lhs.description == rhs.description
}
}

public enum SigningAlgorithmType {
Expand Down
14 changes: 2 additions & 12 deletions Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,8 @@ public struct CRTError: Equatable {
public let message: String
public let name: String

public init<T: BinaryInteger>(code: T) {
if code > INT32_MAX || code < 0 {
self.code = Int32(AWS_ERROR_UNKNOWN.rawValue)
} else {
self.code = Int32(code)
}
self.message = String(cString: aws_error_str(self.code))
self.name = String(cString: aws_error_name(self.code))
}

public init<T: BinaryInteger>(code: T, context: String?) {
if code > INT32_MAX || code < 0 {
public init<T: BinaryInteger>(code: T, context: String? = nil) {
if code > INT32_MAX || code <= 0 {
self.code = Int32(AWS_ERROR_UNKNOWN.rawValue)
} else {
self.code = Int32(code)
Expand Down
18 changes: 4 additions & 14 deletions Source/AwsCommonRuntimeKit/crt/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ extension TimeInterval {
let _millisecond = (self * 1_000).rounded()
guard _millisecond >= 0 && _millisecond <= Double(UInt32.max) else {
// todo convert the millisecond conversion errors into aws-crt-swift errors
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue))
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue))
}
return UInt32(_millisecond)
}
Expand All @@ -157,23 +157,23 @@ extension TimeInterval {
let _millisecond = (self * 1_000).rounded()
guard _millisecond >= 0 && _millisecond <= Double(UInt64.max) else {
// todo convert the millisecond conversion errors into aws-crt-swift errors
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue))
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue))
}
return UInt64(_millisecond)
}

func secondUInt16() throws -> UInt16 {
guard self >= 0 && self <= Double(UInt16.max) else {
// todo convert the millisecond conversion errors into aws-crt-swift errors
throw CommonRunTimeError.crtError( CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue))
throw CommonRunTimeError.crtError( CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue))
}
return UInt16(self)
}

func secondUInt32() throws -> UInt32 {
guard self >= 0 && self <= Double(UInt32.max) else {
// todo convert the millisecond conversion errors into aws-crt-swift errors
throw CommonRunTimeError.crtError( CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue))
throw CommonRunTimeError.crtError( CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue))
}
return UInt32(self)
}
Expand Down Expand Up @@ -224,16 +224,6 @@ extension aws_array_list {
}
}

extension Optional {
/// unwrap an optional unsafepointer to its underlying type
func unwrap<T>() -> T? where Wrapped == (UnsafePointer<T>) {
guard let validPointer = self else {
return nil
}
return validPointer.pointee
}
}

extension Bool {
var uintValue: UInt32 {
return self ? 1 : 0
Expand Down
11 changes: 11 additions & 0 deletions Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ public class HTTP2StreamManager {
})
}

/// Fetch the current manager metrics from connection manager.
public func fetchMetrics() -> HTTPClientConnectionManagerMetrics {
var cManagerMetrics = aws_http_manager_metrics()
aws_http2_stream_manager_fetch_metrics(rawValue, &cManagerMetrics)
return HTTPClientConnectionManagerMetrics(
availableConcurrency: cManagerMetrics.available_concurrency,
pendingConcurrencyAcquires: cManagerMetrics.pending_concurrency_acquires,
leasedConcurrency: cManagerMetrics.leased_concurrency
)
}

deinit {
aws_http2_stream_manager_release(rawValue)
}
Expand Down
11 changes: 11 additions & 0 deletions Source/AwsCommonRuntimeKit/http/HTTPClientConnectionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ public class HTTPClientConnectionManager {
}
}

/// Fetch the current manager metrics from connection manager.
public func fetchMetrics() -> HTTPClientConnectionManagerMetrics {
var cManagerMetrics = aws_http_manager_metrics()
aws_http_connection_manager_fetch_metrics(rawValue, &cManagerMetrics)
return HTTPClientConnectionManagerMetrics(
availableConcurrency: cManagerMetrics.available_concurrency,
pendingConcurrencyAcquires: cManagerMetrics.pending_concurrency_acquires,
leasedConcurrency: cManagerMetrics.leased_concurrency
)
}

deinit {
aws_http_connection_manager_release(rawValue)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0.

public struct HTTPClientConnectionManagerMetrics {
/// The number of additional concurrent requests that can be supported by the HTTP manager without needing to
/// establish additional connections to the target server.
///
/// For connection manager, it equals to connections that's idle.
/// For stream manager, it equals to the number of streams that are possible to be made without creating new
/// connection, although the implementation can create new connection without fully filling it.
public var availableConcurrency: Int
/// The number of requests that are awaiting concurrency to be made available from the HTTP manager.
public var pendingConcurrencyAcquires: Int
/// The number of connections (HTTP/1.1) or streams (for HTTP/2 via. stream manager) currently vended to user.
public var leasedConcurrency: Int

public init(
availableConcurrency: Int,
pendingConcurrencyAcquires: Int,
leasedConcurrency: Int
) {
self.availableConcurrency = availableConcurrency
self.pendingConcurrencyAcquires = pendingConcurrencyAcquires
self.leasedConcurrency = leasedConcurrency
}
}
4 changes: 2 additions & 2 deletions Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ public class Mqtt5ClientCore {
guard let rawValue = self.rawValue else {
continuationCore.release()
return continuation.resume(throwing: CommonRunTimeError.crtError(
CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue, context: "Mqtt client is closed.")))
CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, context: "Mqtt client is closed.")))
}

let result = aws_mqtt5_client_publish(rawValue, publishPacketPointer, &callbackOptions)
Expand Down Expand Up @@ -401,7 +401,7 @@ public class Mqtt5ClientCore {
guard let rawValue = self.rawValue else {
continuationCore.release()
return continuation.resume(throwing: CommonRunTimeError.crtError(
CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue, context: "Mqtt client is closed.")))
CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, context: "Mqtt client is closed.")))
}
let result = aws_mqtt5_client_unsubscribe(rawValue, unsubscribePacketPointer, &callbackOptions)
guard result == AWS_OP_SUCCESS else {
Expand Down
31 changes: 16 additions & 15 deletions Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public class MqttConnectOptions: CStruct {
public let username: String?

/// Opaque binary data that the server may use for client authentication and authorization.
public let password: String?
public let password: Data?

/// A time interval, in whole seconds, that the client requests the server to persist this connection's MQTT session state for. Has no meaning if the client has not been configured to rejoin sessions. Must be non-zero in order to successfully rejoin a session. If the responding CONNACK contains a session expiry property value, then that is the negotiated session expiry value. Otherwise, the session expiry sent by the client is the negotiated value.
public let sessionExpiryInterval: TimeInterval?
Expand Down Expand Up @@ -85,7 +85,7 @@ public class MqttConnectOptions: CStruct {
public init (keepAliveInterval: TimeInterval? = nil,
clientId: String? = nil,
username: String? = nil,
password: String? = nil,
password: Data? = nil,
sessionExpiryInterval: TimeInterval? = nil,
requestResponseInformation: Bool? = nil,
requestProblemInformation: Bool? = nil,
Expand All @@ -111,22 +111,22 @@ public class MqttConnectOptions: CStruct {
func validateConversionToNative() throws {
if let keepAliveInterval {
if keepAliveInterval < 0 || keepAliveInterval > Double(UInt16.max) {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid keepAliveInterval value"))
}
}

do {
_ = try sessionExpiryInterval?.secondUInt32()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid sessionExpiryInterval value"))
}

do {
_ = try willDelayInterval?.secondUInt32()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid willDelayInterval value"))
}
}
Expand Down Expand Up @@ -177,11 +177,12 @@ public class MqttConnectOptions: CStruct {
raw_connect_options.user_property_count = userProperties!.count
raw_connect_options.user_properties = UnsafePointer<aws_mqtt5_user_property>(cUserProperties)
}
return withOptionalByteCursorPointerFromStrings(
username, password) { cUsernamePointer, cPasswordPointer in
return withOptionalByteCursorPointerFromString(username) { cUsernamePointer in
raw_connect_options.username = cUsernamePointer
raw_connect_options.password = cPasswordPointer
return body(raw_connect_options)
return withAWSByteCursorPointerFromOptionalData(to: password) { cPasswordPointer in
raw_connect_options.password = cPasswordPointer
return body(raw_connect_options)
}
}
}
}
Expand Down Expand Up @@ -343,41 +344,41 @@ public class MqttClientOptions: CStructWithUserData {
do {
_ = try minReconnectDelay?.millisecondUInt64()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid minReconnectDelay value"))
}

do {
_ = try maxReconnectDelay?.millisecondUInt64()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid maxReconnectDelay value"))
}

do {
_ = try minConnectedTimeToResetReconnectDelay?.millisecondUInt64()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid minConnectedTimeToResetReconnectDelay value"))
}

do {
_ = try pingTimeout?.millisecondUInt32()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid pingTimeout value"))
}

do {
_ = try connackTimeout?.millisecondUInt32()
} catch {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid connackTimeout value"))
}

if let ackTimeout {
if ackTimeout < 0 || ackTimeout > Double(UInt32.max) {
throw CommonRunTimeError.crtError(CRTError(code: AWS_CRT_SWIFT_INVALID_ARGUMENT.rawValue,
throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue,
context: "Invalid ackTimeout value"))
}
}
Expand Down
Loading

0 comments on commit 77b0dcd

Please sign in to comment.