-
Notifications
You must be signed in to change notification settings - Fork 656
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
channelActive needs to happen before channelRead #204
channelActive needs to happen before channelRead #204
Conversation
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.
LGTM in general but needs a test
2b09023
to
4ca8ae4
Compare
Tests/NIOTests/ChannelTests.swift
Outdated
} | ||
|
||
func channelActive(ctx: ChannelHandlerContext) { | ||
var buffer = ctx.channel.allocator.buffer(capacity: 100) |
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.
nit: just allocate 4 as this is big enough for "foo" ;)
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.
but what if it's in UTF-264 encoding that I'll announce tomorrow? :p
fixing :)
Tests/NIOTests/ChannelTests.swift
Outdated
// this will fail as the socket is already pre-connected ;) | ||
sc.connect(to: bootstrap.localAddress!).map { | ||
XCTFail("should've failed") | ||
}.mapIfError { error 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.
the indention doesn't look right...
Tests/NIOTests/ChannelTests.swift
Outdated
} | ||
} | ||
|
||
let elg = MultiThreadedEventLoopGroup(numThreads: 1) |
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 shut this down in a defer block
4ca8ae4
to
c72bac4
Compare
|
||
private let writeDonePromise: EventLoopPromise<()> | ||
|
||
init(writeDonePromise: EventLoopPromise<()>) { |
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.
@weissi we usually use EventLoopPromise<Void>
I think... Not sure what is the "more swifty way tho". Thoughts ?
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.
@normanmaurer for functions that have 'no return value' (sure you could return ()
but you don't have to) I tend to use -> Void
but the promises we succeed with the value ()
. Therefore I mostly use EventLoopPromise<()>
as there is a value 'sent'. Our codebase has both:
$ git grep 'EventLoopPromise<Void>' | wc -l
220
$ git grep 'EventLoopPromise<()>' | wc -l
57
$ git grep 'EventLoopFuture<()>' | wc -l
31
$ git grep 'EventLoopFuture<Void>' | wc -l
69
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.
@weissi maybe a follow-up but I think w should make it consistent ;) I am not sure what is the "preferred" way tho.
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.
@normanmaurer ok, I'll file an issue.
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.
see #211
Tests/NIOTests/ChannelTests.swift
Outdated
defer { | ||
XCTAssertNoThrow(try elg.syncShutdownGracefully()) | ||
} | ||
let sc = try SocketChannel(eventLoop: elg.next() as! SelectableEventLoop, protocolFamily: AF_INET) |
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.
IMHO we use PF_INET
usually, so maybe change this as well ?
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.
AF_INET
is newer, more standard and overall more preferred. https://stackoverflow.com/questions/6729366/what-is-the-difference-between-af-inet-and-pf-inet-in-socket-programming
Tests/NIOTests/ChannelTests.swift
Outdated
|
||
let serverWriteHappenedPromise: EventLoopPromise<()> = elg.next().newPromise() | ||
let clientHasRegistered: EventLoopPromise<()> = elg.next().newPromise() | ||
let clientHasUnregistered: EventLoopPromise<()> = elg.next().newPromise() |
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 comment about using Void
here.
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.
Tests/NIOTests/ChannelTests.swift
Outdated
let clientHasRegistered: EventLoopPromise<()> = elg.next().newPromise() | ||
let clientHasUnregistered: EventLoopPromise<()> = elg.next().newPromise() | ||
|
||
let bootstrap = try! ServerBootstrap(group: elg) |
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.
I think you can remove !
here.
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.
A few more comments
4c2ff85
to
0d001f6
Compare
Tests/NIOTests/ChannelTests.swift
Outdated
} | ||
}.wait() | ||
try clientHasRegistered.futureResult.wait() | ||
try sc.close().wait() |
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.
I think this is very slightly probabilistic, as the close can technically race with the return to the selector such that it occurs before the selector is next polled. I think the only way you can avoid this is to connect-and-read-from another channel, which kinda sucks, but may be necessary.
3339426
to
3993ca3
Compare
} | ||
let serverEL = group.next() | ||
let clientEL = group.next() | ||
precondition(serverEL !== clientEL) |
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.
@weissi just make this an XCTAssertTrue
?
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.
the problem is that if I do this, the test would just hang forever if something goes wrong (as XCTAssert
s trigger after the test has finished)
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.
I see... ok
Tests/NIOTests/ChannelTests.swift
Outdated
sc.register() | ||
}.then { | ||
// this should fail (and will on Darwin but _not_ Linux) as the socket is already pre-connected ;) | ||
// on Linux a subsequent connect will just silently succeed, go figure... |
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 really makes me sad :( I wonder if there is no other way to test this in a more "consistent" way
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.
@normanmaurer after @Lukasa 's patch is in I can create a Socket
subclass which lets a subsequent 'special' connect succeed on all platforms. That way we can test even more as the channel does become active.
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.
@weissi which patch you are talking about ? :)
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.
@normanmaurer I must have dreamt ;)
Tests/NIOTests/ChannelTests.swift
Outdated
let serverEL = group.next() | ||
let clientEL = group.next() | ||
precondition(serverEL !== clientEL) | ||
let sc = try SocketChannel(eventLoop: clientEL as! SelectableEventLoop, protocolFamily: PF_INET) |
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.
I'd prefer AF_INET
. 2c.
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.
isn't AF address family and PF protocol family?
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.
They're the same. There's no meaningful distinction here: the idea that these constants are different is a legacy from a bygone era.
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.
@Lukasa so should I use PF_INET | AF_INET
:P
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.
@normanmaurer wanted PF_INET
#204 (comment) . I don't care :)
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.
3993ca3
to
577dc76
Compare
Tests/NIOTests/ChannelTests.swift
Outdated
// available to be read immediately | ||
sc.register() | ||
}.then { | ||
// this should fail (and will on Darwin but _not_ Linux) as the socket is already pre-connected ;) |
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 comment is out of date.
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.
thanks, fixed
Motivation: `readIfNeeded` was triggered straight after the channel was registered but _before_ `channelActive` was called which is wrong. Modifications: Moved the calls to `readIfNeeded` into `becomeActive0` and removed them everywhere else (except some error path). Result: handle ChannelHandler lifecycle more correctly.
577dc76
to
a495ac0
Compare
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.
LGTM if it passes the CI :)
Motivation: As Chrome has started GREASEing HTTP/2 settings and frames, we should ensure that we have tests that explicitly validate that we tolerate GREASEing these parameters. A future version of swift-nio-http2 should start emitting GREASE as well, but for now we'll satisfy ourselves with this. Two relevant citations: https://tools.ietf.org/html/draft-bishop-httpbis-grease-00 https://bugs.chromium.org/p/chromium/issues/detail?id=1083706 Modifications: - Added a frame parser test - Added a end-to-end settings test. Result: Validated that GREASE is tolerated.
Many thanks for @vlm for the repro! Fixes #196
Motivation:
readIfNeeded
was triggered straight after the channel was registeredbut before
channelActive
was called which is wrong.Modifications:
Moved the calls to
readIfNeeded
intobecomeActive0
and removed themeverywhere else (except some error path).
Result:
handle ChannelHandler lifecycle more correctly.