From 1d3b7cbbc359223be0d7b3faf0b0aec25eb56b35 Mon Sep 17 00:00:00 2001 From: Zach Rausnitz Date: Thu, 12 Oct 2023 10:05:17 -0700 Subject: [PATCH 1/2] add support for inet --- .../Data/SocketAddress+PostgresCodable.swift | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift diff --git a/Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift b/Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift new file mode 100644 index 00000000..194247b5 --- /dev/null +++ b/Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift @@ -0,0 +1,86 @@ +import NIOCore + +extension SocketAddress: PostgresDecodable { + public init(from byteBuffer: inout NIOCore.ByteBuffer, type: PostgresDataType, format: PostgresFormat, context: PostgresDecodingContext) throws { + // IP family + byteBuffer.moveReaderIndex(forwardBy: MemoryLayout.size) + + // netmask length in bits + guard let netmaskLength: UInt8 = byteBuffer.readInteger(as: UInt8.self) else { + throw PostgresDecodingError.Code.failure + } + + // ensure it is not a CIDR + guard byteBuffer.readInteger(as: UInt8.self) == 0 else { + throw PostgresDecodingError.Code.failure + } + + // address length in bytes + guard let addressLength: UInt8 = byteBuffer.readInteger(as: UInt8.self), + addressLength * 8 == netmaskLength, + let packedIPAddress: ByteBuffer = byteBuffer.readSlice(length: Int(addressLength)) + else { + throw PostgresDecodingError.Code.failure + } + + try self.init(packedIPAddress: packedIPAddress, port: 0) + } +} + +extension SocketAddress: PostgresEncodable & PostgresNonThrowingEncodable { + public static var psqlType: PostgresDataType { return .inet } + public static var psqlFormat: PostgresFormat { .binary } + public func encode(into byteBuffer: inout ByteBuffer, context: PostgresEncodingContext) { + switch self { + case .v4(let address): + // IP family + byteBuffer.writeInteger(UInt8(2)) + // netmask length in bits + byteBuffer.writeInteger(UInt8(32)) + // indicate it is not a CIDR + byteBuffer.writeInteger(UInt8(0)) + // address length in bytes + byteBuffer.writeInteger(UInt8(4)) + // address values + let addressBytes = withUnsafeBytes(of: address.address.sin_addr.s_addr) { Array($0) } + byteBuffer.writeBytes(addressBytes) + + case .v6(let address): + // IP family + byteBuffer.writeInteger(UInt8(3)) + // netmask length in bits + byteBuffer.writeInteger(UInt8(128)) + // indicate it is not a CIDR + byteBuffer.writeInteger(UInt8(0)) + // address length in bytes + byteBuffer.writeInteger(UInt8(16)) + // address values + let addressBytes = withUnsafeBytes(of: address.address.sin6_addr) { Array($0) } + byteBuffer.writeBytes(addressBytes) + + case .unixDomainSocket: + fatalError("Cannot encode a UNIX socket address using the Postgres inet type") + } + } +} + +extension SocketAddress: PostgresArrayDecodable {} + +extension SocketAddress: PostgresArrayEncodable { + public static var psqlArrayType: PostgresDataType { return .inetArray } +} + +extension SocketAddress: Decodable { + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let ipAddress = try container.decode(String.self) + try self.init(ipAddress: ipAddress, port: 0) + } +} + +extension SocketAddress: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self.description) + } +} From f972b921dd843f123600d115bceb5c2139ae076e Mon Sep 17 00:00:00 2001 From: Zach Rausnitz Date: Fri, 13 Oct 2023 08:34:29 -0700 Subject: [PATCH 2/2] add PostgresINET type --- .../Data/PostgresINET+PostgresCodable.swift | 66 ++++++++++++++ .../Data/SocketAddress+PostgresCodable.swift | 86 ------------------- 2 files changed, 66 insertions(+), 86 deletions(-) create mode 100644 Sources/PostgresNIO/New/Data/PostgresINET+PostgresCodable.swift delete mode 100644 Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift diff --git a/Sources/PostgresNIO/New/Data/PostgresINET+PostgresCodable.swift b/Sources/PostgresNIO/New/Data/PostgresINET+PostgresCodable.swift new file mode 100644 index 00000000..2dd85c1e --- /dev/null +++ b/Sources/PostgresNIO/New/Data/PostgresINET+PostgresCodable.swift @@ -0,0 +1,66 @@ +public struct PostgresINET { + public let ipFamily: UInt8 + public let netmaskLength: UInt8 + public let isCIDR: Bool + public let addressLength: UInt8 + public let ipAddress: [UInt8] +} + +extension PostgresINET: PostgresDecodable { + public init(from byteBuffer: inout ByteBuffer, type: PostgresDataType, format: PostgresFormat, context: PostgresDecodingContext) throws { + // IP family + guard let ipFamily: UInt8 = byteBuffer.readInteger(as: UInt8.self) else { + throw PostgresDecodingError.Code.failure + } + + // netmask length in bits + guard let netmaskLength: UInt8 = byteBuffer.readInteger(as: UInt8.self) else { + throw PostgresDecodingError.Code.failure + } + + // whether it is a CIDR + let isCIDR: Bool + switch byteBuffer.readInteger(as: UInt8.self) { + case .some(0): + isCIDR = false + case .some(1): + isCIDR = true + default: + throw PostgresDecodingError.Code.failure + } + + // address length in bytes + guard let addressLength: UInt8 = byteBuffer.readInteger(as: UInt8.self), + addressLength * 8 == netmaskLength, + let ipAddress: [UInt8] = byteBuffer.readBytes(length: Int(addressLength)) + else { + throw PostgresDecodingError.Code.failure + } + + self.init( + ipFamily: ipFamily, + netmaskLength: netmaskLength, + isCIDR: isCIDR, + addressLength: addressLength, + ipAddress: ipAddress + ) + } +} + +extension PostgresINET: PostgresEncodable & PostgresNonThrowingEncodable { + public static var psqlType: PostgresDataType { return .inet } + public static var psqlFormat: PostgresFormat { .binary } + public func encode(into byteBuffer: inout ByteBuffer, context: PostgresEncodingContext) { + byteBuffer.writeInteger(self.ipFamily, as: UInt8.self) + byteBuffer.writeInteger(self.netmaskLength, as: UInt8.self) + byteBuffer.writeInteger(self.isCIDR ? 1 : 0, as: UInt8.self) + byteBuffer.writeInteger(self.addressLength, as: UInt8.self) + byteBuffer.writeBytes(self.ipAddress) + } +} + +extension PostgresINET: PostgresArrayDecodable {} + +extension PostgresINET: PostgresArrayEncodable { + public static var psqlArrayType: PostgresDataType { return .inetArray } +} \ No newline at end of file diff --git a/Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift b/Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift deleted file mode 100644 index 194247b5..00000000 --- a/Sources/PostgresNIO/New/Data/SocketAddress+PostgresCodable.swift +++ /dev/null @@ -1,86 +0,0 @@ -import NIOCore - -extension SocketAddress: PostgresDecodable { - public init(from byteBuffer: inout NIOCore.ByteBuffer, type: PostgresDataType, format: PostgresFormat, context: PostgresDecodingContext) throws { - // IP family - byteBuffer.moveReaderIndex(forwardBy: MemoryLayout.size) - - // netmask length in bits - guard let netmaskLength: UInt8 = byteBuffer.readInteger(as: UInt8.self) else { - throw PostgresDecodingError.Code.failure - } - - // ensure it is not a CIDR - guard byteBuffer.readInteger(as: UInt8.self) == 0 else { - throw PostgresDecodingError.Code.failure - } - - // address length in bytes - guard let addressLength: UInt8 = byteBuffer.readInteger(as: UInt8.self), - addressLength * 8 == netmaskLength, - let packedIPAddress: ByteBuffer = byteBuffer.readSlice(length: Int(addressLength)) - else { - throw PostgresDecodingError.Code.failure - } - - try self.init(packedIPAddress: packedIPAddress, port: 0) - } -} - -extension SocketAddress: PostgresEncodable & PostgresNonThrowingEncodable { - public static var psqlType: PostgresDataType { return .inet } - public static var psqlFormat: PostgresFormat { .binary } - public func encode(into byteBuffer: inout ByteBuffer, context: PostgresEncodingContext) { - switch self { - case .v4(let address): - // IP family - byteBuffer.writeInteger(UInt8(2)) - // netmask length in bits - byteBuffer.writeInteger(UInt8(32)) - // indicate it is not a CIDR - byteBuffer.writeInteger(UInt8(0)) - // address length in bytes - byteBuffer.writeInteger(UInt8(4)) - // address values - let addressBytes = withUnsafeBytes(of: address.address.sin_addr.s_addr) { Array($0) } - byteBuffer.writeBytes(addressBytes) - - case .v6(let address): - // IP family - byteBuffer.writeInteger(UInt8(3)) - // netmask length in bits - byteBuffer.writeInteger(UInt8(128)) - // indicate it is not a CIDR - byteBuffer.writeInteger(UInt8(0)) - // address length in bytes - byteBuffer.writeInteger(UInt8(16)) - // address values - let addressBytes = withUnsafeBytes(of: address.address.sin6_addr) { Array($0) } - byteBuffer.writeBytes(addressBytes) - - case .unixDomainSocket: - fatalError("Cannot encode a UNIX socket address using the Postgres inet type") - } - } -} - -extension SocketAddress: PostgresArrayDecodable {} - -extension SocketAddress: PostgresArrayEncodable { - public static var psqlArrayType: PostgresDataType { return .inetArray } -} - -extension SocketAddress: Decodable { - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let ipAddress = try container.decode(String.self) - try self.init(ipAddress: ipAddress, port: 0) - } -} - -extension SocketAddress: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(self.description) - } -}