### Description CosmoSQLClient-Swift fails to establish connections to Azure SQL Database, throwing an `IOError: Connection reset by peer (errno: 54)` during the TLS handshake phase. ### Environment - **Package Version**: v1.6.4 - **Platform**: macOS (also likely affects Linux) - **Target Database**: Azure SQL Database - **Swift Version**: 5.9+ ### Reproduction ```swift import CosmoMSSQL let config = MSSQLConnection.Configuration( host: "your-server.database.windows.net", port: 1433, database: "your_database", username: "username", password: "password", tls: .require, trustServerCertificate: true ) let pool = MSSQLConnectionPool(configuration: config) let rows = try await pool.withConnection { conn in try await conn.query("SELECT 1") } // ❌ Fails with: IOError: Connection reset by peer ``` ### Expected Behavior Successfully connects to Azure SQL Database and executes queries. ### Actual Behavior Connection fails during TLS handshake with error: ``` IOError: read(descriptor:pointer:size:): Connection reset by peer (errno: 54) ``` ### Root Cause The `TDSTLSFramer` class in `Sources/CosmoMSSQL/TDS/TDSTLSFramer.swift` does not properly accumulate fragmented TCP packets. When Azure SQL Database sends a TLS ServerHello response that exceeds the TCP segment size (typically ~4KB TDS packet in ~1.5KB TCP segments), SwiftNIO delivers the data across multiple `channelRead` callbacks. The current implementation does not maintain state between these calls, causing incomplete packet parsing. **Debug trace showing the issue:** ``` [TDSTLSFramer] Inbound: 2048 bytes // First fragment [TDSTLSFramer] Incomplete packet - lengthBE=4096, available=2048 [TDSTLSFramer] Inbound: 2700 bytes // Second fragment (not accumulated!) [TDSTLSFramer] Incomplete packet - lengthBE=8390891566170136948 // Corrupt length ❌ Connection reset ``` ### Proposed Fix Add buffer accumulation to `TDSTLSFramer`: ```swift final class TDSTLSFramer: ChannelDuplexHandler, @unchecked Sendable { // ... existing code ... // ADD: Buffer to accumulate fragmented packets private var accumulatedBuffer: ByteBuffer? func channelRead(context: ChannelHandlerContext, data: NIOAny) { guard active else { context.fireChannelRead(data) return } var incoming = unwrapInboundIn(data) // Accumulate with previous data if var accumulated = accumulatedBuffer { accumulated.writeBuffer(&incoming) accumulatedBuffer = accumulated } else { accumulatedBuffer = incoming } guard var buf = accumulatedBuffer else { return } // Process complete TDS packets while buf.readableBytes >= 8 { guard let lengthBE: UInt16 = buf.getInteger(at: buf.readerIndex + 2, endianness: .big), Int(lengthBE) <= buf.readableBytes, Int(lengthBE) >= 8 else { accumulatedBuffer = buf // Save for next read return } let packetLen = Int(lengthBE) var packet = buf.readSlice(length: packetLen)! packet.moveReaderIndex(forwardBy: 8) context.fireChannelRead(wrapInboundOut(packet)) } // Clear if fully processed accumulatedBuffer = buf.readableBytes == 0 ? nil : buf } } ``` ### Additional Issue (Minor) The Pre-Login packet advertises TDS 8.0, but TDS 7.4 is more widely compatible: **File**: `Sources/CosmoMSSQL/TDS/TDSPreLogin.swift` line 24 ```swift // Change from: var clientVersion: (UInt8, UInt8, UInt8, UInt8) = (8, 0, 0, 0) // To: var clientVersion: (UInt8, UInt8, UInt8, UInt8) = (7, 4, 0, 0) ``` ### Verification After applying the fix, the connection succeeds: ``` ✅ Connected successfully! ✅ Query executed successfully! ``` Tested against Azure SQL Database with successful SELECT queries on production databases. ### Impact **High**: Affects all users connecting to Azure SQL Database and potentially on-premises SQL Server instances with large TLS certificates. This is a critical bug for production use with Azure. ### Files Affected - `Sources/CosmoMSSQL/TDS/TDSTLSFramer.swift` (**critical**) - `Sources/CosmoMSSQL/TDS/TDSPreLogin.swift` (compatibility improvement) I'm happy to submit a PR with these fixes if helpful. Full technical analysis available upon request.