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

allow two distinct ChannelOptions of one type #597

Merged
merged 1 commit into from
Aug 29, 2018

Conversation

weissi
Copy link
Member

@weissi weissi commented Aug 28, 2018

Motivation:

Quite embarrasingly, we previously would only store one ChannelOption
per ChannelOption type. Most channel option types are distinct and
that's probably why it took so long to find this issue. Thanks
@pushkarnk for reporting. Unfortunately though, the most important
ChannelOption is .socket which crucially also holds a level and a
name. That means if you set two ChannelOptions.socket options with
distinct name/level, one would still override the other.

Example:

.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1)
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)

would only actually set the latter.

Modifications:

  • made all common ChannelOption types equatable (for 2.0 this will
    be a protocol requirement)
  • deprecated non-Equatable ChannelOption types

Result:

you can now set two distinct ChannelOptions for one type

Copy link
Member

@normanmaurer normanmaurer left a comment

Choose a reason for hiding this comment

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

generally LGTM... a few things

public func serverChannelOption<T: ChannelOption>(_ option: T, value: T.OptionType) -> Self {
serverChannelOptions.put(key: option, value: value)
print(serverChannelOptions)
Copy link
Member

Choose a reason for hiding this comment

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

remove

/// - value: The value for the option.
public func serverChannelOption<T: ChannelOption & Equatable>(_ option: T, value: T.OptionType) -> Self {
serverChannelOptions.put(key: option, value: value)
print(serverChannelOptions)
Copy link
Member

Choose a reason for hiding this comment

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

remove

@@ -672,11 +720,34 @@ public final class DatagramBootstrap {
}
}

fileprivate struct ChannelOptionStorage {
internal struct ChannelOptionStorage {
Copy link
Member

Choose a reason for hiding this comment

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

Add comment that its internal for testing only

}
XCTAssertNoThrow(XCTAssertGreaterThan(try channel.getOption(option: ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET),
SO_REUSEADDR)).wait(),
0))
Copy link
Member

Choose a reason for hiding this comment

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

formatting looks really odd... maybe merge with previous line ?

0))
XCTAssertNoThrow(XCTAssertGreaterThan(try channel.getOption(option: ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET),
SO_DEBUG)).wait(),
0))
Copy link
Member

Choose a reason for hiding this comment

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

formatting looks really odd... maybe merge with previous line ?

0))
XCTAssertNoThrow(XCTAssertGreaterThan(try server3.getOption(option: ChannelOptions.socket(IPPROTO_TCP,
TCP_NODELAY)).wait(),
0))
Copy link
Member

Choose a reason for hiding this comment

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

formatting looks really odd... maybe merge with previous line ? (same comment for others)

Copy link
Member Author

Choose a reason for hiding this comment

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

@normanmaurer then the line would be too long. And in github you couldn't see any of the important bits as they were hidden off screen. Still want me to merge?

Copy link
Member

Choose a reason for hiding this comment

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

maybe use this formatting then ?:

let value = XCTAssertNoThrow(try server3.getOption(option: ChannelOptions.socket(IPPROTO_TCP,TCP_NODELAY)).wait())
XCTAssertGreaterThan(value,  0))

Copy link
Member Author

Choose a reason for hiding this comment

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

just put the shared code in a function actually

}
XCTAssertNoThrow(XCTAssertGreaterThan(try server.getOption(option: ChannelOptions.socket(SOL_SOCKET,
SO_REUSEADDR)).wait(),
0))
Copy link
Member

Choose a reason for hiding this comment

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

can you also do the same refactoring here ?

@weissi weissi force-pushed the jw-two-opts-one-type branch 3 times, most recently from e1d77cf to 51532c1 Compare August 28, 2018 16:39
@weissi weissi added this to the 1.9.3 milestone Aug 28, 2018
@weissi weissi added the semver/patch No public API change. label Aug 28, 2018
}

// HACK: this function should go for NIO 2.0, all ChannelOptions should be equatable
mutating func put<K: ChannelOption>(key: K, value: K.OptionType) {
Copy link
Member

Choose a reason for hiding this comment

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

Please remember to open an issue once we merge this one

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 #598

@weissi weissi force-pushed the jw-two-opts-one-type branch 2 times, most recently from 0244764 to 2938130 Compare August 28, 2018 17:47
@@ -332,7 +332,10 @@ class BaseSocket: Selectable {
/// - value: The value for the option.
/// - throws: An `IOError` if the operation failed.
final func setOption<T>(level: Int32, name: Int32, value: T) throws {
try withUnsafeFileDescriptor { fd in
if level == SocketOptionValue(IPPROTO_TCP) && name == TCP_NODELAY && (try? self.localAddress().protocolFamily) == Optional<Int32>.some(Int32(Posix.AF_UNIX)) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain why we need to ignore these ? Maybe adding a comment would be good.

Copy link
Member Author

Choose a reason for hiding this comment

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

@normanmaurer done that, also #599

Motivation:

Quite embarrasingly, we previously would only store one `ChannelOption`
per `ChannelOption` type. Most channel option types are distinct and
that's probably why it took so long to find this issue. Thanks
@pushkarnk for reporting. Unfortunately though, the most important
`ChannelOption` is `.socket` which crucially also holds a level and a
name. That means if you set two `ChannelOptions.socket` options with
distinct name/level, one would still override the other.

Example:

    .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1)
    .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)

would only actually set the latter.

Modifications:

- made all common `ChannelOption` types equatable (for 2.0 this will
  be a protocol requirement)
- deprecated non-Equatable `ChannelOption` types
- zero out buffer before calling getsockopt as Linux doesn't do that

Result:

you can now set two distinct `ChannelOptions` for one type
Copy link
Member

@normanmaurer normanmaurer left a comment

Choose a reason for hiding this comment

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

LGTM

@weissi weissi merged commit 501af86 into apple:master Aug 29, 2018
@weissi weissi deleted the jw-two-opts-one-type branch August 29, 2018 14:26
weissi added a commit that referenced this pull request Aug 29, 2018
Motivation:

Quite embarrasingly, we previously would only store one `ChannelOption`
per `ChannelOption` type. Most channel option types are distinct and
that's probably why it took so long to find this issue. Thanks
@pushkarnk for reporting. Unfortunately though, the most important
`ChannelOption` is `.socket` which crucially also holds a level and a
name. That means if you set two `ChannelOptions.socket` options with
distinct name/level, one would still override the other.

Example:

    .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1)
    .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)

would only actually set the latter.

Modifications:

- made all common `ChannelOption` types equatable (for 2.0 this will
  be a protocol requirement)
- deprecated non-Equatable `ChannelOption` types
- zero out buffer before calling getsockopt as Linux doesn't do that

Result:

you can now set two distinct `ChannelOptions` for one type
Motivation:

Explain here the context, and why you're making that change.
What is the problem you're trying to solve.

Modifications:

Describe the modifications you've done.

Result:

After your change, what will change.
Lukasa added a commit to Lukasa/swift-nio-transport-services that referenced this pull request May 1, 2019
Motivation:

While we fixed a bug in SwiftNIO about setting multiple options of the same type in
apple/swift-nio#597, we never brought a fix for that issue forward. We did aim to resolve
this in SwiftNIO 2.0 by providing ChannelOptions.Storage, but unfortunately we forgot to
make the initializer for that type public (see apple/swift-nio#988). While SwiftNIO core
has to get its ducks in a row, users of this library should still be able to set more than
one socket option, in my humble opinion.

Modifications:

- Ported over ChannelOptions.Storage until apple/swift-nio#988 is fixed.
- Transitioned our code to use it.
- Tested it works.

Result:

Users can set multiple channel options.
Lukasa added a commit to Lukasa/swift-nio-transport-services that referenced this pull request May 1, 2019
Motivation:

We never brought across the fix to apple/swift-nio#597 into swift-nio-transport-services. This
has caused some users a few hard-to-track-down surprises. We fixed this in the mainline by way
of apple#40, but users running the old codebase probably want this fix too.

Modifications:

- Side-ported the fix from apple/swift-nio#597.
- Back-ported the test from apple#40.

Result:

Users can set multiple socket options.
Lukasa added a commit to apple/swift-nio-transport-services that referenced this pull request May 1, 2019
Motivation:

While we fixed a bug in SwiftNIO about setting multiple options of the same type in
apple/swift-nio#597, we never brought a fix for that issue forward. We did aim to resolve
this in SwiftNIO 2.0 by providing ChannelOptions.Storage, but unfortunately we forgot to
make the initializer for that type public (see apple/swift-nio#988). While SwiftNIO core
has to get its ducks in a row, users of this library should still be able to set more than
one socket option, in my humble opinion.

Modifications:

- Ported over ChannelOptions.Storage until apple/swift-nio#988 is fixed.
- Transitioned our code to use it.
- Tested it works.

Result:

Users can set multiple channel options.
weissi pushed a commit to apple/swift-nio-transport-services that referenced this pull request May 1, 2019
Motivation:

We never brought across the fix to apple/swift-nio#597 into swift-nio-transport-services. This
has caused some users a few hard-to-track-down surprises. We fixed this in the mainline by way
of #40, but users running the old codebase probably want this fix too.

Modifications:

- Side-ported the fix from apple/swift-nio#597.
- Back-ported the test from #40.

Result:

Users can set multiple socket options.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/patch No public API change.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants