Commit Graph

66 Commits

Author SHA1 Message Date
Cory Benfield be4ea8ac74 Add SocketOptionChannel for wider socket options. (#589)
Motivation:

A small number of socket options have values that do not fit into a C
int type. Our current ChannelOption based approach for setting these
simply does not work, and cannot be extended to support the truly arbitrary
types that the setsockopt/getsockopt functions allow here.

This makes it impossible to use some socket options, which is hardly a
good place to be.

There were a number of ways we could have addressed this: we could have
special-cased all socket options with non-integer types in ChannelOption,
but I believe that would be too manual, and risk limiting users that need
to set other socket options. We could also have added a ChannelOption
that simply allows users to pass a buffer to write into or read from,
but that is a very un-Swift-like API that feels pretty gross to hold.

Ultimately, the nicest seemed to be a new protocol users could check
for, and that would provide APIs that let users hold the correct concrete
type. As with setsockopt/getsockopt, while this API is typed it is
not type-safe: ultimately, the struct we have here is treated just as a
buffer by setsockopt/getsockopt. We do not attempt to prevent users from
shooting themselves in the foot here.

This PR does not include an example use case in any server, as I will
provide such an example in a subsequent multicast PR.

Modifications:

- Added a SocketOptionChannel protocol.
- Conformed BaseSocketChannel to SocketOptionChannel.
- Wrote some tests for this.

Result:

Users can set and get sockopts with data that is larger than a C int.
2018-09-18 13:40:38 +02:00
Johannes Weiss 501af860f5
allow two distinct ChannelOptions of one type (#597)
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
2018-08-29 15:24:58 +01:00
fadi-botros 78729bd4ad Solving issue #410 (#414)
match all values in HTTPHeaders.isKeepAlive(...)

HTTPHeaders.isKeepAlive(...) does only match the first value.

### Motivation:

Keep-alive and Close may be something on comma separated arrays

### Modifications:

 - Made an extension function to `ByteBuffer` that could separate the strings at low level, without Swift string API, so that it could split the values
 - Another extension functions that compares the comma separated array with a given array to tell the caller which exists and which no
 - Added unit tests for them
 - Used them in the HTTPHeader

### Result:

- Now, if a request is sent using Keep-alive or Close where it was in an array, it will be handled
- fixes #410
2018-08-07 18:49:30 +01:00
Johannes Weiß 80363d9d8c fix EventLoops that Bootstrap channel initialiser's call out on (#424)
Motivation:

Previously we were not running the (child/server)channelInitializers on the
event loop associated to the `Channel` we're initialising. Almost all
operations in there are pipeline modifications which are thread safe so
it presumably wasn't a massive correctness issue. However it's very
expensive to hop threads that often and it is also very unexpected. This
addresses this issue.

Modifications:

made all (child/server)channelInitializers run on the event loop that is
associated to their `Channel`

Result:

- more correctness
- less unexpected behaviour
2018-05-22 15:58:43 +01:00
Johannes Weiß cea84765de Channel quiescing support (#399)
Motivation:

In certain cases it's useful to quiesce a channel instead of just
closing them immediately for example when receiving a signal.
This lays the groundwork by introducing the
`ChannelShouldQuiesceUserEvent` user event that when received can be
interpreted by a ChannelHandler in a protocol & application specific
way. Some protocols support tear down and that would be a good place to
initiate the tear down.

Modifications:

- introduce `ChannelShouldQuiesceUserEvent`
- handle `ChannelShouldQuiesceUserEvent` in the `AcceptHandler` with
  closing the server socket
- handle `ChannelShouldQuiesceUserEvent` in the
  `HTTPServerPipelineHandler` by only handling a already in-flight
  request and then no longer accepting input
- added `CircularBuffer.removeAll` (& tests)
- added tests for `nextPowerOf2()`

Result:

- handlers can now support quiescing
2018-05-18 10:48:18 +02:00
Cory Benfield 9326f749aa
Allow ChannelCore implementors to unwrap NIOAny. (#321)
Motivation:

When implementing a custom ChannelCore, you will probably need access
to the data inside a NIOAny. It should be possible to unwrap that.

Modifications:

Added an extension to ChannelCore to allow unwrapping a NIOAny.
Added @_versioned to almost all of NIOAny.

Result:

ChannelCore is implementable outside NIO
2018-04-18 10:04:12 +01:00
Cory Benfield bc6e3db537
Fix up HTTP message framing edge cases. (#298)
Motivation:

HTTP message framing has a number of edge cases that NIO currently does
not tolerate. We should decide what our position is on each of these edge
cases and handle it appropriately.

Modifications:

Provide an extensive test suite that codifies our expected handling of
these edge cases. Fix divergences from this behaviour.

Result:

Better tolerance for the weird corners of HTTP.
2018-04-12 15:12:39 +01:00
Cory Benfield 5b2ad2d921 Add support for automatic HTTP error reporting. (#268)
Motivation:

Currently the HTTP decoders can throw errors, but they will be ignored
and lead to a simple EOF. That's not ideal: in most cases we should make
a best-effort attempt to send a 4XX error code before we shut the client
down.

Modifications:

Provided a new ChannelHandler that generates 400 errors when the HTTP
decoder fails.
Added a flag to automatically add that handler to the channel pipeline.
Added the handler to the HTTP sample server.
Enabled integration test 12.

Result:

Easier error handling for HTTP servers.
2018-04-07 10:13:31 +02:00
Cory Benfield d6ade1424e
Forbid HTTP protocols other than 1. (#283)
Motivation:

Our HTTP code handles only HTTP/1.X. There is no reason to support
HTTP/0.9, and we cannot safely handle a major protocol higher than 1 in
this code, so we should simply treat requests/responses claiming to be
of those protocols as errors.

Modifications:

HTTPDecoder now checks the major version is equal to 1 before it
continues with parsing. If it hits an error, that error will be propagated
out to the user.

Result:

Better resilience against bad HTTP messages.
2018-04-06 11:26:32 +01:00
Norman Maurer b1f948a115
Set hints for getaddrinfo to restrict results (#221)
Motivation:

We only use our GetaddrinfoResolver for SocketChannels (TCP stream channels), so we should set some hints for getaddrinfo.

Modifications:

Set proto and socktype hints.

Result:

More correct usage of getaddrinfo. Fixes https://github.com/apple/swift-nio/issues/201.
2018-03-28 10:49:05 +02:00
Johannes Weiß c9c3974276 bring PriorityQueue/Heap implementations inline (#245)
Motivation:

We triggered extra allocations for the generics on PriorityQueue/Heap.
They unfortunately can't be solved using `@_specialize` as the element
type is `ScheduledTask`.
Fortunately we never exposed those types externally so we can just
inline without breaking the public API.

Modifications:

Moved everything from the `NIOPriorityQueue` module into the `NIO`
module.

Result:

Less allocations, more happiness.
2018-03-27 19:04:33 +02:00
Norman Maurer b8055f7467
Guard against the case when a Selectable is deregistered during Selector.whenReady(...) processing. (#210)
Motivation:

It's possible someone deregistered a Selectable while Selector.whenReady(...) is processed and an even for the now deregistered Selectable is ready. In this case we crashed (due a force-unwrap) on linux.

Modifications:

- Skip the processing of the Selectable if deregistered (by replacing force-unwrap with an if let).
- Add unit test.

Result:

No more crashes caused by this on Linux
2018-03-21 15:32:15 +01:00
Norman Maurer edfbe50fc8 Ensure we always update the promise before calling fire* methods and also udate channel state before. (#181)
Motivation:

We not always ensure correct ordering which made it quite hard to reason about things. We should always first notify the promise before we call the fire* method that belongs to the event. Beside this we sometimes fired events or notified promised before correctly update the active state / addresses of a Channel which could result in unexpected results when query the Channel during execution of callbacks and handlers.

Modifications:

- Ensure we always notify promise first
- Always correctly update channel state before notify promise
- Add test to verify notification order.

Result:

Correct ordering of events which makes things easier to reason about and which follows what netty is doing.
2018-03-19 20:52:31 +09:00
Norman Maurer 22d3439c4b
Add handler that provides some backoff for accepts if these failed because of an IOError. (#126)
Motivation:

Often accept errors are recoverable over time as for example you may just run out of file descriptors. Because of this it may be useful to just "delay" accepts a bit to recover.

Modifications:

Add ChannelHandler which will backoff accepts.

Result:

Be able to recover from accept errors gracefully.
2018-03-15 21:23:19 +01:00
Cory Benfield b542775605 Add initial websocket codec. (#109)
Motivation:

Websockets is a major protocol in use on the web today, and is
particularly valuable in applications that use asynchronous I/O
as it allows servers to keep connections open for long periods of
time for fully-duplex communication.

Users of NIO should be able to build websocket clients and servers
without too much difficulty.

Modifications:

Provided a WebsocketFrameEncoder and Decoder that can serialize and
deserialize Websocket frames.

Result:

Easier use of websockets.
2018-03-13 17:24:54 +01:00
Cory Benfield 860a7d40a3 Add channel handler for server side pipelining. (#62)
Motivation:

HTTP pipelining can be tricky to handle properly on the server side.
In particular, it's very easy to write out of order or inconsistently
mutate state. Users often need help to handle this appropriately.

Modifications:

Added a HTTPServerPipelineHandler that only lets one request through
at a time.

Result:

Better servers that are more able to handle HTTP pipelining
2018-03-13 15:21:12 +00:00
adamnemecek 0bbed6d72f * removed trailing whitespace (#52) 2018-03-02 15:40:52 +09:00
Cory Benfield 088c09ece5 Improve Linux test gen script to match current format. (#3)
Motivation:

Right now the test gen script will rewrite every file. Not ideal!

Modifications:

Added the license header, and made the follow-on comment match that
style.

Result:

Test files will look the same when running this script as they do
now.
2018-02-21 20:16:28 +01:00
Norman Maurer 55e99b603d Expose BlockingIOThreadPool
* Expose BlockingIOThreadPool

Motivation:

Sometimes we need to execute some blocking IO. For this we should expose the BlockingIOThreadPool that can be used.

Modifications:

- Factor out BlockingIOThreadPool
- Added tests
- Correctly start threadpool before execute NonBlockingIO tests.

Result:

Possible to do blocking IO.

* Corrys comment

* Correctly start pool before using it
2018-02-16 14:53:19 +01:00
Cory Benfield ab9427bdd4 Initial UDP support 2018-01-16 17:00:09 +00:00
Cory Benfield 67bb71e44b Add a pending datagram writes manager
This change adds support for doing datagram-style writes. It's not currently
hooked up to anything, but it will be sometime soon.
2018-02-14 15:32:31 +00:00
Johannes Weiß ebf351abda implement thread specific values 2018-02-08 17:37:01 +00:00
Daniel Dunbar 41bf7278f8 [NIO] Fix setOption() to be async.
- This fixes Bootstrap's ChannelOptionStore.applyAll to return a future rather
   than synchronously iterating through all the options.

 - This is particular important because when a server accepts a child, if the
   child channel is on a different event loop then it is possible the
   synchronous calls may deadlock (if the child's eventloop happens to be
   scheduled with a similar accept sequence).

 - I did not tackle also making getOption() async, which means the Channel API
   is asymmetric at the moment. That should probably be addressed, potentialy
   with synchronous wrappers for API compatibility.

 - Fixes: <rdar://problem/37191923> [Omega] Worker tasks fail to close subtasks (many connections in CLOSE_WAIT state)
2018-02-08 09:21:40 -08:00
Cory Benfield ce7b0c52ce Add a CompositeError type 2018-02-08 13:12:30 +00:00
Johannes Weiss 755ea5aedc non-blocking file IO 2018-02-07 17:25:45 +00:00
Cory Benfield 2630d583cd Happy Eyeballs! 2018-02-02 17:26:51 +00:00
Johannes Weiss b3799b9403 take OpenSSL support out of tree 2018-01-26 09:50:38 +00:00
Cory Benfield 92634a68fb Add utility for detecting core count. 2018-01-22 12:05:43 +00:00
Cory Benfield 8ee527ac52 Simplify running code 2018-01-08 16:39:54 +00:00
Cory Benfield f3e72c13f3 Add HTTP streaming compressor 2017-12-15 09:50:12 +00:00
Johannes Weiss 8335b6c3a0 replace priority queue 2017-11-28 16:13:26 +00:00
Johannes Weiß 06f9b1d63b merge ConcurrencyHelpers 2017-11-21 18:32:33 +00:00
Johannes Weiß 33fe401322 rename Future/Promise to EventLoopFuture/EventLoopPromise 2017-11-21 17:41:36 +00:00
Cory Benfield 229c23a63b Support X.509 hostname validation 2017-11-20 14:26:22 +00:00
Johannes Weiß 936e812b32 make system call wrapper fast & test it 2017-11-16 15:42:03 +00:00
Cory Benfield 8ff2d5bb92 OpenSSL ALPN support 2017-11-13 12:45:57 +00:00
Cory Benfield e72569e329 Add client-side SNI support 2017-10-25 15:04:46 +01:00
Cory Benfield 8efedf33fa Add ALPN handler 2017-11-01 16:14:11 +00:00
Norman Maurer 976f4752df Add HTTPRequestEncoder / HTTPResponseDecoder implementation and tests 2017-11-02 13:50:46 +01:00
Cory Benfield 8b860d3009 Add SNI handler 2017-10-30 10:58:26 +00:00
Norman Maurer 9c7829a065 Port IdleStateHandler from Netty 2017-10-29 09:46:48 +01:00
Johannes Weiß 6173bee782 Split IOData into NIOAny & IOData (ByteBuffer | FileRegion) 2017-10-25 19:31:27 +01:00
Cory Benfield 25d57e8fab Add Channel.isActive 2017-10-19 16:44:42 -07:00
Cory Benfield b2cbe766f0 Add support for HTTP Upgrade 2017-10-12 17:24:00 -07:00
Cory Benfield 7dddd67608 Add TLS configuration object 2017-09-29 14:25:46 +01:00
Tom Doron f76a2bfa66 sort linux tests
motivation: generated linux tests dont have consitent sorting in different OSs

changes:

* change test generator to sort tests and imports in memory before writing to file
* update LinuxMain to the sorted version
2017-10-17 09:51:59 -07:00
Cory Benfield 6f17b320d5 Ensure no transfer-encoding when body is forbidden 2017-10-13 13:44:51 -07:00
Cory Benfield 55ae8a8606 Make MarkedCircularBuffer public 2017-10-02 11:36:29 +01:00
Cory Benfield 8a6d9c825c OpenSSL-based TLS support
Add initial OpenSSL support to NIO.
2017-09-26 14:47:41 +01:00
Johannes Weiss a73d46f218 HTTP/1.1 Chunked Encoding
* HTTP/1.1 Chunked Encoding

* fix MarkedCircularBuffer: if not marked do not try to move mark when removing first

* fix HTTPRequestDecoder: dispatch callouts after parsing is complete

* fix HTTPTest: feed pipeline the inbound data correctly
2017-09-25 15:33:02 +01:00