-
Notifications
You must be signed in to change notification settings - Fork 656
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Add methods to create and parse cmsghdr structured data. #1590
Conversation
Motivation: cmsghdrs can be used to send an receive extra data on UDP packets. For example ECN data. Modifications: Map in Linux and Darwin versions of cmsghdr macros as functions. Create strctures for holding a received collection; parsing ecn data from a received collection and building a collection suitable for sending. Result: Functions to manipulate cmsghdr and data exist.
@Lukasa The obvious points for discussion are
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, looks like a good first start. Notes in the diff.
Sources/NIO/ControlMessage.swift
Outdated
/// Unsafe as captures pointers and must not escape the scope where those pointers are valid. | ||
struct UnsafeControlMessage { | ||
var level: Int32 | ||
var type: Int32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should probably be CInt
, not Int32
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
Sources/NIO/ControlMessage.swift
Outdated
/// 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: Collection { | ||
typealias Index = ControlMessageIndex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can elide this typealias by renaming ControlMessageIndex
to Index
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree.
Sources/NIO/ControlMessage.swift
Outdated
data: Posix.cmsgData(for: cmsg)) | ||
} | ||
|
||
private var messageHeader: msghdr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's quite confusing to have stored properties, computed properties, and functions scattered around this type definition. Can we refactor it? Something like:
struct UnsafeControlMessageCollection {
private var messageHeader: msghdr
init(messageHeader: msghdr)
}
extension UnsafeControlMessageCollection: Collection {
var startIndex: Index
var endIndex: Index // This should not be a stored property as it's a global static, let the compiler handle it
func index(after:)
subscript
}
This would much more clearly separate concerns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
Tests/NIOTests/SystemTest.swift
Outdated
|
||
func testCMsgNextHeader() { | ||
var exampleCmsgHrd = SystemTest.cmsghdrExample | ||
exampleCmsgHrd.withUnsafeMutableBytes { pCmsgHdr in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same mutable note here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same reason.
Tests/NIOTests/SystemTest.swift
Outdated
let second = Posix.cmsgNextHeader(inside: pMsgHdr, from: first) | ||
let expectedSecondSlice = UnsafeMutableRawBufferPointer( | ||
rebasing: pCmsgHdr[SystemTest.cmsghdr_secondStartPosition...]) | ||
XCTAssertEqual(expectedSecondSlice.baseAddress, second) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not bother creating a slice if we don't need one, let's just use pCmsgHdr.baseAddress! + SystemTest.cmsghdr_secondStartPosition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
@Lukasa I have taken most of your suggested changes. There are a few where I have not done but have replied to your comment. |
There are no visible comment replies @PeterAdams-A: did you submit them? |
Sources/NIO/ControlMessage.swift
Outdated
private static let ipv4TosType = IP_TOS // Linux | ||
#endif | ||
|
||
static func readCInt(data: UnsafeRawBufferPointer) -> CInt { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefix with an underscore to indicate this is not supposed to be part of the public API of this type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
Sources/NIO/ControlMessage.swift
Outdated
|
||
extension CInt { | ||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) | ||
fileprivate static let notCapableValue = IPTOS_ECN_NOTECT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be private
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Sources/NIO/ControlMessage.swift
Outdated
|
||
struct UnsafeOutboundControlBytes { | ||
private var controlBytes: UnsafeMutableRawBufferPointer | ||
private var writePosition: UnsafeMutableRawBufferPointer.Index = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the sake of keeping this as correct as possible, let's initialise this in init
with self.controlBytes.startIndex
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good thinking.
Sources/NIO/ControlMessage.swift
Outdated
cmsghdrPtr.pointee.cmsg_type = type | ||
cmsghdrPtr.pointee.cmsg_len = .init(Posix.cmsgLen(payloadSize: MemoryLayout.size(ofValue: payload))) | ||
|
||
let dataPointer = Posix.cmsgData(for: cmsghdrPtr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can bring the force-unwrap to here and save ourselves two more below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Sources/NIO/ControlMessage.swift
Outdated
/// It's assumed the caller has checked that congestion information is required before calling. | ||
internal init(from controlMessagesReceived: UnsafeControlMessageCollection) { | ||
var controlMessageReceiver = ControlMessageParser() | ||
controlMessagesReceived.forEach { controlMessage in controlMessageReceiver.receiveMessage(controlMessage) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for message in controlMessagesReceived {
controlMessageReceiver.receiveMessage(message)
}
In general forEach
is not really worth using: it's kinda needless sugar over the more straightforward looping operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, should this loop move into an init
on ControlMessageParser
? That object can really only be used with one thing anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One note, otherwise good.
Sources/NIO/ControlMessage.swift
Outdated
var endIndex: Index { return Index(cmsgPointer: nil) } | ||
|
||
func index(after: Index) -> Index { | ||
precondition(after.cmsgPointer != nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This precondition is unnecessary: we force-unwrap this pointer before its first use anyway, so the correctness of the code isn't enforced here. If you wanted to match the message below you can move the force-unwrap to this line instead, if that helps.
Motivation: cmsghdrs can be used to send an receive extra data on UDP packets. For example ECN data. Modifications: Map in Linux and Darwin versions of cmsghdr macros as functions. Create strctures for holding a received collection; parsing ecn data from a received collection and building a collection suitable for sending. Result: Functions to manipulate cmsghdr and data exist.
Motivation:
cmsghdrs can be used to send an receive extra data on UDP packets.
For example ECN data.
Modifications:
Map in Linux and Darwin versions of cmsghdr macros as functions.
Create strctures for holding a received collection; parsing ecn
data from a received collection and building a collection suitable
for sending.
Result:
Functions to manipulate cmsghdr and data exist.