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

[WIP] KQueue and Unix domain socket support #480

Open
wants to merge 45 commits into
base: master
from

Conversation

@kachayev
Copy link
Collaborator

kachayev commented Feb 8, 2019

Quick note. Marked as WIP. Relies on #477 to be merged beforehand, so I can implement proper support for KQueue settings for DNS resolvers.

There're still a few things I want to discuss.

KQueue

Overall it works the same way :epoll? works for TCP, HTTP, WebSockets, UDP and DNS by specifying :kqueue? option. false by default, to be consistent with epoll?. At first glance it feels a bit weird to carry two arguments epoll? and kqueue? here and there, but on the hand that gives me the ability to switch ON both native transports whenever possible (both will not be available on the same host).

io.netty/netty-transport-native-epoll dependency should also be specified with appropriate classifier ("osx-x86_64"). This is the same problem we have in #475. With the recent commits, I updated project.clj to include classifiers right away, both for epoll and kqueue JARs. Generally, this should work, apart from the fact, your JAR would be 180kb larger. It also may lead to some problems with transitive dependencies from other libraries, but I don't have a lot of experience with classpath resolution order when using classifiers. So, let's discuss it. The obvious advantage here: less confusion for users when working with native transports.

Netty 4.1.33.Final has a weird issue with KQueue selector which I'm still struggling to catch. Hope the next version of Netty will fix this, so we can ship w/o concerns. Updated: seems to be fixed already.

Unix Domain Socket

Unix domain socket support added for TCP & HTTP both for client and server. Unix socket works only with native transports (epoll or kqueue), Netty does not support it with NIO (yet?).

TCP API

user=> (def s1 (tcp/start-server (fn [s _] (s/connect s s)) {:unix-socket "/tmp/tcp-server.sock"}))
#'user/s1
user=> (def c1 @(tcp/client {:unix-socket "/tmp/tcp-server.sock"}))
#'user/c1
user=> (s/put! c1 "hello")
<< … >>
user=> @(s/take! c1)
#object["[B" 0x2eb44ff0 "[B@2eb44ff0"]
user=> (.close s1)
nil

HTTP API

user=> (require '[aleph.http :as http])
nil
user=> (def s1 (http/start-server (fn [_] {:status 200 :body "OK"}) {:unix-socket "/tmp/server1.sock"}))
#'user/s1
user=> (def p (http/connection-pool {:connection-options {:unix-socket "/tmp/server1.sock"}}))
#'user/p
user=> (-> (http/get "http://domain/info" {:pool p}) deref :status)
200

There are a few points to mention here. When connecting to unix domain socket, we still require a valid parsable URL (host + scheme). We still need hostname to acquire a connection from the pool, setup SSL handler (improved, not trying to set SNI hostname if no InetSocketAddress available) and render "Host" header (this might be required by the server). curl has the same problem, so I think that's a reasonable trade-off. Quite a few tools use http+unix://<socket-file>/<path> to convey both unix socket filepath and "fake" domain, if that's interesting for users we can always implement this on top of the existing functionality.

From an implementation point of view, there're still some rough edges I'm not sure about. Notably, netty/create-client accepts remote-address option in the form of InetSocketAddress, we can relax that to SocketAddress and pass DomainSocketAddress right away... but that doesn't work in case we need to pass both inet (with host, port) and domain address (to connect to). create-client now takes both params, dynamically choose what address to connect to and rejects SSL handler setup if no InetSocketAddress provided (throwing exception in case ssl-context given with no host/port information). Overall, the number of positional arguments for netty/create-client looks awful right now, I'll probably reimplement that to accept a map of params (done).

Proxy options are rejected when connecting to unix domain socket, DNS resolver is set to :noop to bypass any attempts to resolve host before sending the request (we do just the same when sending requests through proxies).

@ztellman Waiting for your review!

kachayev added 30 commits Feb 1, 2019
@kachayev kachayev changed the title KQueue and Unix domain socket support [WIP] KQueue and Unix domain socket support Feb 9, 2019
;; not expect it work at the first place. The only thing...
;; I don't know the connection pool configuration here, meaning
;; I have no idea if it's allowed to pass URI with no additional
;; information

This comment has been minimized.

Copy link
@ztellman

ztellman Mar 25, 2019

Owner

Whatever is here will get passed through to aleph.http.client/http-connection by way of aleph.http/create-connection, which does assume the object is a URI, but does not assume any of the fields are populated. I think it's okay to populate everything with dummy values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.