Repository: apple/swift-nio
File: Sources/NIOPosix/ControlMessage.swift (Swift)

Code before:

    // Guess that 4 Int32 payload messages is enough for anyone.
    static var bytesPerMessage: Int { NIOBSDSocketControlMessage.space(payloadSize: MemoryLayout<Int32>.stride) * 4 }

    /// Allocate new memory - Caller must call `deallocate` when no longer required.
    /// parameter:
    ///   - msghdrCount: How many `msghdr` structures will be fed from this buffer - we assume 4 Int32 cmsgs for each.
    static func allocate(msghdrCount: Int) -> UnsafeControlMessageStorage {
        let bytesPerMessage = Self.bytesPerMessage
        let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: bytesPerMessage * msghdrCount,
                                                             alignment: MemoryLayout<cmsghdr>.alignment)
        return UnsafeControlMessageStorage(bytesPerMessage: bytesPerMessage, deallocateBuffer: true, buffer: buffer)
    }

    mutating func deallocate() {
        if self.deallocateBuffer {
            self.buffer.deallocate()
            self.buffer = UnsafeMutableRawBufferPointer(start: UnsafeMutableRawPointer(bitPattern: 0x7eadbeef), count: 0)
        }
    }

    /// Get the part of the buffer for use with a message.
    public subscript(position: Int) -> UnsafeMutableRawBufferPointer {
        return UnsafeMutableRawBufferPointer(
            fastRebase: self.buffer[(position * self.bytesPerMessage)..<((position+1) * self.bytesPerMessage)])
    }

    var startIndex: Int { return 0 }

    var endIndex: Int { return self.buffer.count / self.bytesPerMessage }

    func index(after: Int) -> Int {
        return after + 1
    }
}

/// Representation of a `cmsghdr` and associated data.
/// Unsafe as captures pointers and must not escape the scope where those pointers are valid.
struct UnsafeControlMessage {
    var level: CInt
    var type: CInt
    var data: UnsafeRawBufferPointer?
}

/// Collection representation of `cmsghdr` structures and associated data from `recvmsg`
/// Unsafe as captures pointers held in msghdr structure which must not escape scope of validity.
struct UnsafeControlMessageCollection {
    private var messageHeader: msghdr

    init(messageHeader: msghdr) {
        self.messageHeader = messageHeader

Review comment (suggestion):
For this PR I think this is fine, but it'd be really valuable (I think) to add support for using the pool on the `DatagramVectorReadManager` side as well, so that we can drop the need to use this type in two different ways.

Code after:
    }

    // Guess that 4 Int32 payload messages is enough for anyone.
    static var bytesPerMessage: Int { NIOBSDSocketControlMessage.space(payloadSize: MemoryLayout<Int32>.stride) * 4 }

    /// Allocate new memory - Caller must call `deallocate` when no longer required.
    /// parameter:
    ///   - msghdrCount: How many `msghdr` structures will be fed from this buffer - we assume 4 Int32 cmsgs for each.
    static func allocate(msghdrCount: Int) -> UnsafeControlMessageStorage {
        let bytesPerMessage = Self.bytesPerMessage
        let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: bytesPerMessage * msghdrCount,
                                                            alignment: MemoryLayout<cmsghdr>.alignment)
        return UnsafeControlMessageStorage(bytesPerMessage: bytesPerMessage, buffer: buffer, deallocateBuffer: true)
    }

    /// Create an instance not owning the buffer
    /// parameter:
    /// - bytesPerMessage: How many bytes have been allocated for each supported message.
    /// - buffer: The memory allocated to use for control messages.
    static func makeNotOwning(bytesPerMessage: Int, buffer: UnsafeMutableRawBufferPointer) -> UnsafeControlMessageStorage {
        precondition(buffer.count >= bytesPerMessage)
        return UnsafeControlMessageStorage(bytesPerMessage: bytesPerMessage, buffer: buffer, deallocateBuffer: false)
    }

    mutating func deallocate() {
        if self.deallocateBuffer {
            self.buffer.deallocate()
            self.buffer = UnsafeMutableRawBufferPointer(start: UnsafeMutableRawPointer(bitPattern: 0x7eadbeef), count: 0)
        }
    }

    /// Get the part of the buffer for use with a message.
    public subscript(position: Int) -> UnsafeMutableRawBufferPointer {
        return UnsafeMutableRawBufferPointer(
            fastRebase: self.buffer[(position * self.bytesPerMessage)..<((position+1) * self.bytesPerMessage)])
    }

    var startIndex: Int { return 0 }

    var endIndex: Int { return self.buffer.count / self.bytesPerMessage }

    func index(after: Int) -> Int {
        return after + 1
    }
}

/// Representation of a `cmsghdr` and associated data.
/// Unsafe as captures pointers and must not escape the scope where those pointers are valid.
struct UnsafeControlMessage {
    var level: CInt
    var type: CInt