Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NIOBSDSocket.ProtocolSubtype #2317

Merged
merged 9 commits into from
Nov 22, 2022
Merged

Conversation

dnadoba
Copy link
Member

@dnadoba dnadoba commented Nov 16, 2022

Motivation:

We want to support custom IP protocols through POSIX Raw Socket API. To allow this, users will need to specify the IP sub protocol type they want to use.

Modifications:

  • Add NIOBSDSocket.ProtocolSubtype with a lot of well known protocols
  • Plumb NIOBSDSocket.ProtocolSubtype through DatagramChannel which we will reuse for the Raw Socket API

Result:

DatagramChannel is prepared to be used in a RawSocketBootstrap

@dnadoba dnadoba added the semver/minor Adds new public API. label Nov 16, 2022
@dnadoba dnadoba requested a review from Lukasa November 16, 2022 11:27
Sources/NIOPosix/BSDSocketAPICommon.swift Outdated Show resolved Hide resolved
// }
extension NIOBSDSocket.ProtocolSubtype {
/// internet protocol, pseudo protocol number
public static let ip = Self(rawValue: 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These protocol subtypes are not necessarily stable from OS release to OS release. As much as possible, can we use the symbolic names?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I find the symbolic names?

Copy link
Member Author

@dnadoba dnadoba Nov 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that they can change? I thought that these are the numbers used in the IP header protocol field and therefore should be and need to be OS independent.
258 (Divert pseudo-protocol [non IANA]) and 262 (MTCP) are outliers and I'm not quite sure how they fit into this picture as they exceed the 8-bit available in the IPv4 protocol (IPv6 nextHeader) field.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these have that effect, but some do not. The protocol subtype field has uses outside of raw sockets.

In this case, these all match IPPROTO_* constants in the various libcs. I suspect netinet/in.h has most of them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made NIOBSDSocket.ProtocolSubtype internal and moved all known protocol types to a new type called NIOIPProtocol which is public. Should I still use the IPPROTO_* constants for those as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we can point to the IANA registry that's sufficient.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I can follow. What do you mean by pointing to the IANA registry?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IANA (the Internet Assigned Numbers Authority) holds registries for most extension points in IETF protocols. In the case of the IPv4 next-level protocol field or IPv6 next header field, that registry is this one. You can skip most of that registry: I'd limit myself to assignments with a reference to an RFC or IANA. But that's the authoritative reference for the numbers, so we should reference it as the source for the numbers we choose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 30e96bb

/// called "Protocol" to identify the next level protocol. This is an 8
/// bit field. In Internet Protocol version 6 (IPv6) [RFC8200], this field
/// is called the "Next Header" field.
public struct NIOIPProtocol: RawRepresentable, Hashable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of convenience it might be nice to add a CustomStringConvertible implementation that switches over the named static lets and prints those names as well as the raw number.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 904c5fd

public var rawValue: RawValue

@inlinable
public init(rawValue: RawValue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add an init(_ rawValue: Int) as well? It's useful to be able to construct this from a general Int.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really that useful? I can't think of an instance where I would want to use that and NIOIPProtocol(rawValue: .init(someInt)) isn't too bad. This would also crash at runtime unless we make it an optional init.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. It remains helpful for cases where you can easily get hold of an Int, and represents good practice in the Swift ecosystem (where Int is the currency numerical type). The crash at runtime is a red herring: if the user has an Int, we just force them to write the crash in their code instead of ours. The type very clearly communicates that it can only hold a UInt8, so there's no ambiguity, and we can safely save the user the hassle of writing that code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 35cb11f

}

extension NIOBSDSocket.ProtocolSubtype {
static let ip = Self(rawValue: 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add an MPTCP static let here to avoid using the raw value elsewhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fadd5c1

@@ -212,10 +212,10 @@ extension NIOBSDSocket {

// The protocol subtype for MPTCP.
// Returns nil if mptcp is not supported.
static var mptcpProtocolSubtype: Int? {
static var mptcpProtocolSubtype: NIOBSDSocket.ProtocolSubtype? {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this in favour of NIOBSDSocket.ProtocolSubtype.mptcp?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fadd5c1

// Use for experimentation and testing (253) - [RFC3692]
public static let useForExperimentationAndTesting1 = Self(rawValue: 253)
// Use for experimentation and testing (254) - [RFC3692]
public static let useForExperimentationAndTesting2 = Self(rawValue: 254)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd skip these bottom two names: we can just leave them undefined.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 904c5fd

}

extension NIOBSDSocket.ProtocolSubtype {
static let ip = Self(rawValue: 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think 0 implies IP: I think it just implies "default".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dddf452

@Lukasa Lukasa enabled auto-merge (squash) November 22, 2022 11:08
@Lukasa
Copy link
Contributor

Lukasa commented Nov 22, 2022

@swift-server-bot test this please

@Lukasa
Copy link
Contributor

Lukasa commented Nov 22, 2022

Looks like the syscall wrapper test has broken. Probably this is the result of another dependency getting added to actually building that project (listed in IntegrationTests/tests_02_syscall_wrappers/defines.sh). You probably need to add IPProtocol.swift to that list.

@Lukasa Lukasa merged commit 0b4edd8 into apple:main Nov 22, 2022
@dnadoba dnadoba deleted the dn-protocol-subtype branch November 22, 2022 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants