diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 3e088ef..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: lsquic.cr CI - -on: - schedule: - - cron: "0 0 * * *" # Every day at 00:00 - push: - branches: - - "master" - - "api-only" - pull_request: - branches: "*" - -jobs: - build: - - runs-on: ubuntu-latest - - name: "build - crystal: ${{ matrix.crystal }}, stable: ${{ matrix.stable }}" - - continue-on-error: ${{ !matrix.stable }} - - strategy: - fail-fast: false - matrix: - stable: [true] - crystal: - - 1.0.0 - - 1.1.1 - - 1.2.0 - include: - - crystal: nightly - stable: false - - steps: - - uses: actions/checkout@v2 - - - name: Install Crystal - uses: crystal-lang/install-crystal@v1.5.3 - with: - crystal: ${{ matrix.crystal }} - - - name: Cache Shards - uses: actions/cache@v2 - with: - path: ./lib - key: shards-${{ hashFiles('shard.lock') }} - - - name: Install Shards - run: | - if ! shards check; then - shards install - fi - - - name: Run tests - run: crystal spec --warnings all --error-on-warnings --error-trace - - - name: Run lint - run: | - if ! crystal tool format --check; then - crystal tool format - git diff - exit 1 - fi - - - name: Build - run: crystal build --warnings all --error-on-warnings --error-trace src/lsquic.cr diff --git a/.github/workflows/container-release.yml b/.github/workflows/container-release.yml deleted file mode 100644 index 63f5936..0000000 --- a/.github/workflows/container-release.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Build and release container - -on: - push: - branches: - - "master" - -jobs: - release: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - with: - platforms: arm64 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to registry - uses: docker/login-action@v1 - with: - registry: quay.io - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_PASSWORD }} - - - name: Build and push Docker image for Push Event - if: github.ref == 'refs/heads/master' - uses: docker/build-push-action@v2 - with: - context: . - file: docker/Dockerfile - platforms: linux/amd64,linux/arm64/v8 - push: true - tags: quay.io/invidious/lsquic-compiled:${{ github.sha }},quay.io/invidious/lsquic-compiled:latest \ No newline at end of file diff --git a/README.md b/README.md index c4f01d2..2829305 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,10 @@ Crystal bindings to the excellent [LSQUIC](https://github.com/litespeedtech/lsquic) library. -Releases track lsquic's versioning starting with `v2.18.1`. +`libssl.a`, `libcrypto.a` are both licensed under `LICENSE.boringssl`. `liblsquic.a` is licensed under `LICENSE.lsquic` and `LICENSE.chrome`. -Lsquic uses [boringssl](https://github.com/google/boringssl), which is licensed under `LICENSE.boringssl`. - This library is available under the MIT license. ## Installation @@ -17,7 +15,7 @@ This library is available under the MIT license. ```yaml dependencies: lsquic: - github: iv-org/lsquic.cr + github: omarroth/lsquic.cr ``` 2. Run `shards install` @@ -39,7 +37,7 @@ client.get("/", headers: HTTP::Headers{ ## Contributing -1. Fork it () +1. Fork it () 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) @@ -48,3 +46,7 @@ client.get("/", headers: HTTP::Headers{ ## Contributors - [Omar Roth](https://github.com/omarroth) - creator and maintainer + +``` + +``` diff --git a/docker/APKBUILD-boringssl b/docker/APKBUILD-boringssl deleted file mode 100644 index a162119..0000000 --- a/docker/APKBUILD-boringssl +++ /dev/null @@ -1,46 +0,0 @@ -# Based on https://aur.archlinux.org/packages/boringssl-git/ -# Maintainer: Omar Roth -pkgname=boringssl -pkgver=1.1.0 -pkgrel=0 -pkgdesc="BoringSSL is a fork of OpenSSL that is designed to meet Google's needs" -url="https://boringssl.googlesource.com/boringssl" -arch="all" -license="MIT" -replaces="openssl libressl" -depends="!openssl-libs-static" -makedepends_host="linux-headers" -makedepends="cmake git go perl" -subpackages="$pkgname-static $pkgname-dev $pkgname-doc" -source="251b516.tar.gz::https://github.com/google/boringssl/tarball/251b516" -builddir="$srcdir/google-boringssl-251b516" - -prepare() { - : -} - -build() { - cmake -DCMAKE_BUILD_TYPE=Debug . - make ssl crypto -} - -check() { - make all_tests -} - -package() { - for i in *.md ; do - install -Dm644 $i "$pkgdir/usr/share/doc/$pkgname/$i" - done - install -d "$pkgdir/usr/lib" - install -d "$pkgdir/usr/include" - cp -R include/openssl "$pkgdir/usr/include" - - install -Dm755 crypto/libcrypto.a "$pkgdir/usr/lib/libcrypto.a" - install -Dm755 ssl/libssl.a "$pkgdir/usr/lib/libssl.a" -# install -Dm755 decrepit/libdecrepit.a "$pkgdir/usr/lib/libdecrepit.a" -# install -Dm755 libboringssl_gtest.a "$pkgdir/usr/lib/libboringssl_gtest.a" -} -sha512sums=" -b1d42ed188cf0cce89d40061fa05de85b387ee4244f1236ea488a431536a2c6b657b4f03daed0ac9328c7f5c4c9330499283b8a67f1444dcf9ba5e97e1199c4e 251b516.tar.gz -" diff --git a/docker/APKBUILD-lsquic b/docker/APKBUILD-lsquic deleted file mode 100644 index 2e2f982..0000000 --- a/docker/APKBUILD-lsquic +++ /dev/null @@ -1,43 +0,0 @@ -# Maintainer: Omar Roth -pkgname=lsquic -pkgver=2.18.1 -pkgrel=0 -pkgdesc="LiteSpeed QUIC and HTTP/3 Library" -url="https://github.com/litespeedtech/lsquic" -arch="all" -license="MIT" -depends="boringssl-dev boringssl-static zlib-static libevent-static" -makedepends="cmake git go perl bsd-compat-headers linux-headers" -subpackages="$pkgname-static" -source="v$pkgver.tar.gz::https://github.com/litespeedtech/lsquic/tarball/v2.18.1 -ls-qpack-$pkgver.tar.gz::https://github.com/litespeedtech/ls-qpack/tarball/a8ae6ef -ls-hpack-$pkgver.tar.gz::https://github.com/litespeedtech/ls-hpack/tarball/bd5d589" -builddir="$srcdir/litespeedtech-$pkgname-692a910" - -prepare() { - cp -r -T "$srcdir/litespeedtech-ls-qpack-a8ae6ef" "$builddir/src/liblsquic/ls-qpack" - cp -r -T "$srcdir/litespeedtech-ls-hpack-bd5d589" "$builddir/src/lshpack" -} - -build() { - cmake \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DBORINGSSL_INCLUDE=/usr/include/openssl \ - -DBORINGSSL_LIB_crypto=/usr/lib \ - -DBORINGSSL_LIB_ssl=/usr/lib . - make lsquic -} - -check() { - make tests -} - -package() { - install -d "$pkgdir/usr/lib" - install -Dm755 src/liblsquic/liblsquic.a "$pkgdir/usr/lib/liblsquic.a" -} -sha512sums=" -d015a72f1e88750ecb364768a40f532678f11ded09c6447a2e698b20f43fa499ef143a53f4c92a5938dfece0e39e687dc9df4aea97c618faee0c63da771561c3 v2.18.1.tar.gz -c5629085a3881815fb0b72a321eeba8de093eff9417b8ac7bde1ee1264971be0dca6d61d74799b02ae03a4c629b2a9cf21387deeb814935339a8a2503ea33fee ls-qpack-2.18.1.tar.gz -1b9f7ce4c82dadfca8154229a415b0335a61761eba698f814d4b94195c708003deb5cb89318a1ab78ac8fa88b141bc9df283fb1c6e40b3ba399660feaae353a0 ls-hpack-2.18.1.tar.gz -" diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 02f269a..0000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM alpine:edge AS liblsquic-builder -WORKDIR /src - -RUN apk add --no-cache build-base git apk-tools abuild cmake go perl linux-headers - -RUN abuild-keygen -a -n && \ - cp /root/.abuild/-*.rsa.pub /etc/apk/keys/ - -COPY docker/APKBUILD-boringssl boringssl/APKBUILD -RUN cd boringssl && abuild -F -r && cd .. - -RUN apk add --repository /root/packages/src boringssl boringssl-dev boringssl-static - -RUN apk add --no-cache zlib-dev zlib-static libevent-dev libevent-static - -COPY docker/APKBUILD-lsquic lsquic/APKBUILD -RUN cd lsquic && abuild -F -r && cd .. - -RUN apk add --repository /root/packages/src lsquic-static - -RUN mkdir tmp && cd tmp && \ - ar -x /usr/lib/libssl.a && \ - ar -x /usr/lib/libcrypto.a && \ - ar -x /usr/lib/liblsquic.a && \ - ar rc liblsquic.a *.o && \ - ranlib liblsquic.a && \ - cp liblsquic.a /root/liblsquic.a && \ - cd .. && rm -rf tmp \ No newline at end of file diff --git a/shard.yml b/shard.yml index 231c9d3..3ae6ddc 100644 --- a/shard.yml +++ b/shard.yml @@ -1,9 +1,9 @@ name: lsquic -version: 2.18.1-2 +version: 0.1.9 authors: - Omar Roth -crystal: ">= 0.35.0, < 2.0.0" +crystal: 0.33.0 license: MIT diff --git a/src/lsquic/client.cr b/src/lsquic/client.cr index b99f3db..b7cd4e3 100644 --- a/src/lsquic/client.cr +++ b/src/lsquic/client.cr @@ -11,8 +11,6 @@ module QUIC end class Client - REQUIRED_HEADERS = {":method", ":scheme", ":path", ":authority"} - def self.stream_readf(stream_if_ctx : Void*, buf : UInt8*, buf_len : LibC::SizeT, fin : LibC::Int) stream_ctx = Box(StreamCtx).unbox(stream_if_ctx) stream_ctx.io.write Slice.new(buf, buf_len) @@ -32,7 +30,9 @@ module QUIC .try { |c| LibLsquic.conn_get_ctx(c) } .try { |c| Box(StreamCtx).unbox(c) } - return Box.box(stream_ctx) if LibLsquic.stream_is_pushed(s) != 0 + if LibLsquic.stream_is_pushed(s) != 0 + return Box.box(stream_ctx) + end LibLsquic.stream_wantwrite(s, 1) Box.box(stream_ctx) @@ -40,33 +40,32 @@ module QUIC def self.on_write(s : LibLsquic::StreamT, stream_if_ctx : Void*) stream_ctx = Box(StreamCtx).unbox(stream_if_ctx) - request_headers = stream_ctx.request.headers - headers = [] of LibLsquic::LsxpackHeader - REQUIRED_HEADERS.each do |name| - value = stream_ctx.request.headers[name] - headers << LibLsquic::LsxpackHeader.new( - buf: "#{name}#{value}", - name_len: name.bytesize, - name_offset: 0, - val_len: value.bytesize, - val_offset: name.bytesize - ) - end - - request_headers.each do |name, values| + headers = [] of LibLsquic::HttpHeader + (stream_ctx.request.headers.to_a.sort_by { |k, v| {":authority", ":path", ":scheme", ":method"}.index(k) || -1 }).reverse.each do |tuple| + name, values = tuple name = name.downcase - next if REQUIRED_HEADERS.includes? name - headers << LibLsquic::LsxpackHeader.new( - buf: "#{name}#{values[0]}", - name_len: name.bytesize, - name_offset: 0, - val_len: values[0].bytesize, - val_offset: name.bytesize - ) + + values.each do |value| + name_vec = LibLsquic::Iovec.new + name_vec.iov_base = name.to_slice + name_vec.iov_len = name.bytesize + + value_vec = LibLsquic::Iovec.new + value_vec.iov_base = value.to_slice + value_vec.iov_len = value.bytesize + + header = LibLsquic::HttpHeader.new + header.name = name_vec + header.value = value_vec + + headers << header + end end - http_headers = LibLsquic::HttpHeaders.new(count: headers.size, headers: headers.to_unsafe) + http_headers = LibLsquic::HttpHeaders.new + http_headers.count = headers.size + http_headers.headers = headers.to_unsafe raise "Could not send headers" if LibLsquic.stream_send_headers(s, pointerof(http_headers), stream_ctx.request.body ? 0 : 1) != 0 @@ -166,7 +165,7 @@ module QUIC def run_engine LibLsquic.engine_init_settings(out engine_settings, ENGINE_FLAGS) - engine_settings.es_ua = "Chrome/83.0.4103.61 Linux x86_64" + engine_settings.es_ua = "Chrome/78.0.3904.97 Linux x86_64" engine_settings.es_ecn = 0 err_buf = Bytes.new(0x100) @@ -195,16 +194,7 @@ module QUIC hostname = host.starts_with?('[') && host.ends_with?(']') ? host[1..-2] : host @engine_open = true - conn = LibLsquic.engine_connect( - engine, - LibLsquic::Version::Lsqver050, - socket.local_address, - socket.remote_address, - Box.box(socket), nil, - hostname, 0, - nil, 0, - nil, 0 - ) + conn = LibLsquic.engine_connect(engine, LibLsquic::Version::Lsqver046, socket.local_address, socket.remote_address, Box.box(socket), nil, hostname, 0, nil, 0, nil, 0) spawn do while stream_ctx = @stream_channel.receive LibLsquic.conn_set_ctx(conn, Box.box(stream_ctx)) @@ -213,29 +203,25 @@ module QUIC end @engine_open = false LibLsquic.engine_destroy(engine) - @socket.try &.close - @socket = nil end - begin - buffer = Bytes.new(0x600) - loop do + buffer = Bytes.new(0x600) + loop do + begin bytes_read = socket.read buffer - break if !@engine_open - LibLsquic.engine_packet_in(engine, buffer[0, bytes_read], bytes_read, socket.local_address, socket.remote_address, Box.box(socket), 0) if bytes_read != 0 - LibLsquic.engine_process_conns(engine) + rescue ex + break end - rescue IO::Error - # may have already been closed - ensure - @socket.try &.close - @socket = nil + break if !@engine_open + LibLsquic.engine_packet_in(engine, buffer[0, bytes_read], bytes_read, socket.local_address, socket.remote_address, Box.box(socket), 0) if bytes_read != 0 + LibLsquic.engine_process_conns(engine) end + @socket.try &.close + @socket = nil end def socket : UDPSocket - socket = @socket - return socket.not_nil! if @socket + return @socket.as(UDPSocket) if @socket socket = UDPSocket.new @family case @family @@ -511,6 +497,8 @@ module QUIC def close @stream_channel.send nil Fiber.yield + @socket.try &.close + @socket = nil end private def new_request(method, path, headers, body : BodyType) diff --git a/src/lsquic/ext/libcrypto.a b/src/lsquic/ext/libcrypto.a new file mode 100644 index 0000000..755fa5f Binary files /dev/null and b/src/lsquic/ext/libcrypto.a differ diff --git a/src/lsquic/ext/liblsquic.a b/src/lsquic/ext/liblsquic.a index a9c7ade..ad85a26 100644 Binary files a/src/lsquic/ext/liblsquic.a and b/src/lsquic/ext/liblsquic.a differ diff --git a/src/lsquic/ext/libssl.a b/src/lsquic/ext/libssl.a new file mode 100644 index 0000000..1b1974b Binary files /dev/null and b/src/lsquic/ext/libssl.a differ diff --git a/src/lsquic/liblsquic.cr b/src/lsquic/liblsquic.cr index 9d193d4..fbee2d0 100644 --- a/src/lsquic/liblsquic.cr +++ b/src/lsquic/liblsquic.cr @@ -1,64 +1,74 @@ -@[Link(ldflags: "#{__DIR__}/ext/liblsquic.a")] +@[Link(ldflags: "#{__DIR__}/ext/liblsquic.a -lz")] lib LibLsquic - LSENG_SERVER = 1 - LSENG_HTTP = 2 + MAX_CID_LEN = 20 + QQUIC_CID_LEN = 8 + LSENG_SERVER = 1 + LSENG_HTTP = 2 LSENG_HTTP_SERVER = LSENG_SERVER | LSENG_HTTP - GLOBAL_CLIENT = 1 - GLOBAL_SERVER = 2 - MAJOR_VERSION = 2 - MINOR_VERSION = 18 - PATCH_VERSION = 1 - EXPERIMENTAL_Q098 = 0 - DEPRECATED_VERSIONS = 0 + GLOBAL_CLIENT = 1 + GLOBAL_SERVER = 2 + MAJOR_VERSION = 2 + MINOR_VERSION = 6 + PATCH_VERSION = 1 + EXPERIMENTAL_Q098 = 0 + DEPRECATED_VERSIONS = 0 + MIN_CFW = 16 * 1024 + DF_CFCW_SERVER = 3 * 1024 * 1024 / 2 + DF_CFCW_CLIENT = 15 * 1024 * 1024 + DF_SFCW_SERVER = 1 * 1024 * 1024 + DF_SFCW_CLIENT = 6 * 1024 * 1024 DF_MAX_STREAMS_IN = 100 DF_INIT_MAX_STREAM_DATA_BIDI_LOCAL_SERVER = 0 DF_INIT_MAX_STREAM_DATA_BIDI_REMOTE_CLIENT = 0 DF_INIT_MAX_STREAMS_UNI_CLIENT = 100 DF_INIT_MAX_STREAMS_UNI_SERVER = 3 - DF_IDLE_TIMEOUT = 30 - DF_PING_PERIOD = 15 - DF_SILENT_CLOSE = 1 - DF_MAX_HEADER_LIST_SIZE = 0 + DF_INIT_MAX_STREAM_DATA_UNI_CLIENT = 32 * 1024 + DF_INIT_MAX_STREAM_DATA_UNI_SERVER = 12 * 1024 + DF_IDLE_TIMEOUT = 30 + DF_PING_PERIOD = 15 + DF_HANDSHAKE_TO = 10 * 1000 * 1000 + DF_IDLE_CONN_TO = DF_IDLE_TIMEOUT * 1000 * 1000 + DF_SILENT_CLOSE = 1 + DF_MAX_HEADER_LIST_SIZE = 0 DF_UA = "LSQUIC" DF_STTL = 86400 - DF_SUPPORT_NSTP = 0 - DF_SUPPORT_PUSH = 1 - DF_SUPPORT_TCID0 = 1 - DF_HONOR_PRST = 0 - DF_SEND_PRST = 0 - DF_PROGRESS_CHECK = 1000 - DF_RW_ONCE = 0 - DF_PROC_TIME_THRESH = 0 - DF_PACE_PACKETS = 1 - DF_CLOCK_GRANULARITY = 1000 - DF_SCID_LEN = 8 - DF_SCID_ISS_RATE = 60 - DF_QPACK_DEC_MAX_BLOCKED = 100 - DF_QPACK_DEC_MAX_SIZE = 4096 - DF_QPACK_ENC_MAX_BLOCKED = 100 - DF_QPACK_ENC_MAX_SIZE = 4096 - DF_ECN = 0 - DF_ALLOW_MIGRATION = 1 - DF_QL_BITS = 2 - DF_SPIN = 1 - DF_DELAYED_ACKS = 0 - DF_TIMESTAMPS = 1 - DF_CC_ALGO = 1 - DF_MAX_UDP_PAYLOAD_SIZE_RX = 0 - DF_GREASE_QUIC_BIT = 1 - DF_NOPROGRESS_TIMEOUT_SERVER = 60 - DF_NOPROGRESS_TIMEOUT_CLIENT = 0 + DF_MAX_INCHOATE = 1 * 1000 * 1000 + DF_SUPPORT_SREJ_SERVER = 1 + DF_SUPPORT_SREJ_CLIENT = 0 + DF_SUPPORT_NSTP = 0 + DF_SUPPORT_PUSH = 1 + DF_SUPPORT_TCID0 = 1 + DF_HONOR_PRST = 0 + DF_SEND_PRST = 0 + DF_PROGRESS_CHECK = 1000 + DF_RW_ONCE = 0 + DF_PROC_TIME_THRESH = 0 + DF_PACE_PACKETS = 1 + DF_CLOCK_GRANULARITY = 1000 + DF_SCID_LEN = 8 + DF_SCID_ISS_RATE = 60 + DF_QPACK_DEC_MAX_BLOCKED = 100 + DF_QPACK_DEC_MAX_SIZE = 4096 + DF_QPACK_ENC_MAX_BLOCKED = 100 + DF_QPACK_ENC_MAX_SIZE = 4096 + DF_ECN = 0 + DF_ALLOW_MIGRATION = 1 + DF_CC_ALGO = 2 struct Cid - len : UInt8 + len : UintFast8T u_cid : CidUCid end + alias UintFast8T = UInt8 + union CidUCid - buf : LibC::UInt8T[20] - id : LibC::UInt64T + buf : Uint8T[20] + id : Uint64T end + alias Uint8T = UInt8 + alias Uint64T = LibC::ULong alias Engine = Void alias Conn = Void alias ConnCtx = Void @@ -67,26 +77,16 @@ lib LibLsquic struct HttpHeaders count : LibC::Int - headers : LsxpackHeader* + headers : HttpHeader* end - struct LsxpackHeader - buf : LibC::Char* - name_hash : LibC::UInt32T - nameval_hash : LibC::UInt32T - name_offset : LibC::UInt16T - name_len : LibC::UInt16T - val_offset : LibC::UInt16T - val_len : LibC::UInt16T - chain_next_idx : LibC::UInt16T - hpack_index : LibC::UInt8T - qpack_index : LibC::UInt8T - app_index : LibC::UInt8T - flags : LibC::UInt8T - indexed_type : LibC::UInt8T - dec_overhead : LibC::UInt8T + struct HttpHeader + name : Iovec + value : Iovec end + type HttpHeaderT = HttpHeader + struct Iovec iov_base : UInt8* iov_len : LibC::SizeT @@ -126,11 +126,12 @@ lib LibLsquic es_silent_close : LibC::Int es_max_header_list_size : LibC::UInt es_ua : LibC::Char* - es_sttl : LibC::UInt64T - es_pdmd : LibC::UInt32T - es_aead : LibC::UInt32T - es_kexs : LibC::UInt32T + es_sttl : Uint64T + es_pdmd : Uint32T + es_aead : Uint32T + es_kexs : Uint32T es_max_inchoate : LibC::UInt + es_support_srej : LibC::Int es_support_push : LibC::Int es_support_tcid0 : LibC::Int es_support_nstp : LibC::Int @@ -158,13 +159,9 @@ lib LibLsquic es_ecn : LibC::Int es_allow_migration : LibC::Int es_cc_algo : LibC::UInt - es_ql_bits : LibC::Int - es_spin : LibC::Int - es_delayed_acks : LibC::Int - es_timestamps : LibC::Int - es_max_packet_size_rx : LibC::UInt16T end + alias Uint32T = LibC::UInt fun engine_init_settings = lsquic_engine_init_settings(x0 : EngineSettings*, engine_flags : LibC::UInt) fun engine_check_settings = lsquic_engine_check_settings(settings : EngineSettings*, engine_flags : LibC::UInt, err_buf : LibC::Char*, err_buf_sz : LibC::SizeT) : LibC::Int @@ -192,17 +189,25 @@ lib LibLsquic end struct HsetIf - hsi_create_header_set : (Void*, StreamT, LibC::Int -> Void*) - hsi_prepare_decode : (Void*, LsxpackHeader*, LibC::SizeT -> LsxpackHeader*) - hsi_process_header : (Void*, LsxpackHeader* -> LibC::Int) + hsi_create_header_set : (Void*, LibC::Int -> Void*) + hsi_process_header : (Void*, LibC::UInt, LibC::Char*, LibC::UInt, LibC::Char*, LibC::UInt -> HeaderStatus) hsi_discard_header_set : (Void* -> Void) - hsi_flags : HsiFlag end - enum HsiFlag - HsiHttp1X = 2 - HsiHashName = 4 - HsiHashNameval = 8 + enum HeaderStatus + HdrOk = 0 + HdrErrDuplicatePsdoHdr = 1 + HdrErrIncomplReqPsdoHdr = 2 + HdrErrUnnecReqPsdoHdr = 3 + HdrErrBadReqHeader = 4 + HdrErrIncomplRespPsdoHdr = 5 + HdrErrUnnecRespPsdoHdr = 6 + HdrErrUnknownPsdoHdr = 7 + HdrErrUppercaseHeader = 8 + HdrErrMisplacedPsdoHdr = 9 + HdrErrMissingPsdoHdr = 10 + HdrErrHeadersTooLarge = 11 + HdrErrNomem = 12 end struct KeylogIf @@ -234,32 +239,27 @@ lib LibLsquic ea_hsi_ctx : Void* ea_keylog_if : KeylogIf* ea_keylog_ctx : Void* - ea_alpn : LibC::Char* end alias PacketsOutF = (Void*, OutSpec*, LibC::UInt -> LibC::Int) alias SslCtxSt = Void - alias Sockaddr = LibC::Sockaddr - alias LookupCertF = (Void*, Sockaddr*, LibC::Char* -> SslCtxSt*) + alias LookupCertF = (Void*, LibC::Sockaddr*, LibC::Char* -> SslCtxSt*) type CidT = Cid alias CidsUpdateF = (Void*, Void**, CidT*, LibC::UInt -> Void) alias StackStX509 = Void - fun engine_new = lsquic_engine_new(engine_flags : LibC::UInt, api : EngineApi*) : EngineT + fun engine_new = lsquic_engine_new(engine_flags : LibC::UInt, x1 : EngineApi*) : EngineT type EngineT = Void* - fun engine_connect = lsquic_engine_connect(x0 : EngineT, x1 : Version, local_sa : Sockaddr*, peer_sa : Sockaddr*, peer_ctx : Void*, conn_ctx : Void*, hostname : LibC::Char*, max_packet_size : LibC::UShort, zero_rtt : UInt8*, zero_rtt_len : LibC::SizeT, token : UInt8*, token_sz : LibC::SizeT) : ConnT - + fun engine_connect = lsquic_engine_connect(x0 : EngineT, x1 : Version, local_sa : LibC::Sockaddr*, peer_sa : LibC::Sockaddr*, peer_ctx : Void*, conn_ctx : Void*, hostname : LibC::Char*, max_packet_size : LibC::UShort, zero_rtt : UInt8*, zero_rtt_len : LibC::SizeT, token : UInt8*, token_sz : LibC::SizeT) : ConnT enum Version - Lsqver043 = 0 - Lsqver046 = 1 - Lsqver050 = 2 - LsqverId27 = 3 - LsqverId28 = 4 - LsqverId29 = 5 - LsqverVerneg = 6 - NLsqver = 7 + Lsqver039 = 0 + Lsqver043 = 1 + Lsqver046 = 2 + LsqverId23 = 3 + LsqverId24 = 4 + LsqverVerneg = 5 + NLsqver = 6 end - - fun engine_packet_in = lsquic_engine_packet_in(x0 : EngineT, packet_in_data : UInt8*, packet_in_size : LibC::SizeT, sa_local : Sockaddr*, sa_peer : Sockaddr*, peer_ctx : Void*, ecn : LibC::Int) : LibC::Int + fun engine_packet_in = lsquic_engine_packet_in(x0 : EngineT, packet_in_data : UInt8*, packet_in_size : LibC::SizeT, sa_local : LibC::Sockaddr*, sa_peer : LibC::Sockaddr*, peer_ctx : Void*, ecn : LibC::Int) : LibC::Int fun engine_process_conns = lsquic_engine_process_conns(engine : EngineT) fun engine_has_unsent_packets = lsquic_engine_has_unsent_packets(engine : EngineT) : LibC::Int fun engine_send_unsent_packets = lsquic_engine_send_unsent_packets(engine : EngineT) @@ -271,12 +271,13 @@ lib LibLsquic fun conn_going_away = lsquic_conn_going_away(x0 : ConnT) fun conn_close = lsquic_conn_close(x0 : ConnT) fun stream_wantread = lsquic_stream_wantread(s : StreamT, is_want : LibC::Int) : LibC::Int - fun stream_read = lsquic_stream_read(s : StreamT, buf : Void*, len : LibC::SizeT) : LibC::SizeT - fun stream_readv = lsquic_stream_readv(s : StreamT, vec : Iovec*, iovcnt : LibC::Int) : LibC::SizeT - fun stream_readf = lsquic_stream_readf(s : StreamT, readf : (Void*, UInt8*, LibC::SizeT, LibC::Int -> LibC::SizeT), ctx : Void*) : LibC::SizeT + fun stream_read = lsquic_stream_read(s : StreamT, buf : Void*, len : LibC::SizeT) : SsizeT + alias SsizeT = LibC::Long + fun stream_readv = lsquic_stream_readv(s : StreamT, x1 : Iovec*, iovcnt : LibC::Int) : SsizeT + fun stream_readf = lsquic_stream_readf(s : StreamT, readf : (Void*, UInt8*, LibC::SizeT, LibC::Int -> LibC::SizeT), ctx : Void*) : SsizeT fun stream_wantwrite = lsquic_stream_wantwrite(s : StreamT, is_want : LibC::Int) : LibC::Int - fun stream_write = lsquic_stream_write(s : StreamT, buf : Void*, len : LibC::SizeT) : LibC::SizeT - fun stream_writev = lsquic_stream_writev(s : StreamT, vec : Iovec*, count : LibC::Int) : LibC::SizeT + fun stream_write = lsquic_stream_write(s : StreamT, buf : Void*, len : LibC::SizeT) : SsizeT + fun stream_writev = lsquic_stream_writev(s : StreamT, vec : Iovec*, count : LibC::Int) : SsizeT struct Reader lsqr_read : (Void*, Void*, LibC::SizeT -> LibC::SizeT) @@ -284,17 +285,18 @@ lib LibLsquic lsqr_ctx : Void* end - fun stream_writef = lsquic_stream_writef(x0 : StreamT, x1 : Reader*) : LibC::SizeT + fun stream_writef = lsquic_stream_writef(x0 : StreamT, x1 : Reader*) : SsizeT fun stream_flush = lsquic_stream_flush(s : StreamT) : LibC::Int - fun stream_send_headers = lsquic_stream_send_headers(s : StreamT, headers : HttpHeaders*, eos : LibC::Int) : LibC::Int + fun stream_send_headers = lsquic_stream_send_headers(s : StreamT, h : HttpHeaders*, eos : LibC::Int) : LibC::Int + type HttpHeadersT = HttpHeaders fun stream_get_hset = lsquic_stream_get_hset(x0 : StreamT) : Void* - fun conn_push_stream = lsquic_conn_push_stream(c : ConnT, hdr_set : Void*, s : StreamT, headers : HttpHeaders*) : LibC::Int + fun conn_push_stream = lsquic_conn_push_stream(c : ConnT, hdr_set : Void*, s : StreamT, url : Iovec*, authority : Iovec*, headers : HttpHeaders*) : LibC::Int fun conn_is_push_enabled = lsquic_conn_is_push_enabled(x0 : ConnT) : LibC::Int fun stream_shutdown = lsquic_stream_shutdown(s : StreamT, how : LibC::Int) : LibC::Int fun stream_close = lsquic_stream_close(s : StreamT) : LibC::Int fun conn_get_server_cert_chain = lsquic_conn_get_server_cert_chain(x0 : ConnT) : StackStX509* fun stream_id = lsquic_stream_id(s : StreamT) : StreamIdT - alias StreamIdT = LibC::UInt64T + alias StreamIdT = Uint64T fun stream_get_ctx = lsquic_stream_get_ctx(s : StreamT) : Void* fun stream_is_pushed = lsquic_stream_is_pushed(s : StreamT) : LibC::Int fun stream_is_rejected = lsquic_stream_is_rejected(s : StreamT) : LibC::Int @@ -303,16 +305,16 @@ lib LibLsquic fun stream_priority = lsquic_stream_priority(s : StreamT) : LibC::UInt fun stream_set_priority = lsquic_stream_set_priority(s : StreamT, priority : LibC::UInt) : LibC::Int fun stream_conn = lsquic_stream_conn(s : StreamT) : ConnT + fun conn_get_stream_by_id = lsquic_conn_get_stream_by_id(c : ConnT, stream_id : StreamIdT) : StreamT fun conn_id = lsquic_conn_id(c : ConnT) : CidT* fun conn_get_engine = lsquic_conn_get_engine(c : ConnT) : EngineT - fun conn_get_sockaddr = lsquic_conn_get_sockaddr(c : ConnT, local : Sockaddr**, peer : Sockaddr**) : LibC::Int + fun conn_get_sockaddr = lsquic_conn_get_sockaddr(c : ConnT, local : LibC::Sockaddr**, peer : LibC::Sockaddr**) : LibC::Int struct LoggerIf log_buf : (Void*, LibC::Char*, LibC::SizeT -> LibC::Int) end fun logger_init = lsquic_logger_init(x0 : LoggerIf*, logger_ctx : Void*, x2 : LoggerTimestampStyle) - enum LoggerTimestampStyle LltsNone = 0 LltsHhmmssms = 1 @@ -322,7 +324,6 @@ lib LibLsquic LltsYyyymmddHhmmssus = 5 NLlts = 6 end - fun set_log_level = lsquic_set_log_level(log_level : LibC::Char*) : LibC::Int fun logger_lopt = lsquic_logger_lopt(optarg : LibC::Char*) : LibC::Int fun engine_quic_versions = lsquic_engine_quic_versions(x0 : EngineT) : LibC::UInt @@ -336,14 +337,15 @@ lib LibLsquic LsqCryQuic = 0 LsqCryTlSv13 = 1 end - fun conn_crypto_cipher = lsquic_conn_crypto_cipher(c : ConnT) : LibC::Char* fun str2ver = lsquic_str2ver(str : LibC::Char*, len : LibC::SizeT) : Version fun alpn2ver = lsquic_alpn2ver(alpn : LibC::Char*, len : LibC::SizeT) : Version fun engine_cooldown = lsquic_engine_cooldown(x0 : EngineT) + fun hsk_getssl = lsquic_hsk_getssl(conn : ConnT) : SslSt* + alias SslSt = Void fun conn_get_ctx = lsquic_conn_get_ctx(x0 : ConnT) : Void* fun conn_set_ctx = lsquic_conn_set_ctx(x0 : ConnT, x1 : Void*) - fun conn_get_peer_ctx = lsquic_conn_get_peer_ctx(x0 : ConnT, local_sa : Sockaddr*) : Void* + fun conn_get_peer_ctx = lsquic_conn_get_peer_ctx(x0 : ConnT, local_sa : LibC::Sockaddr*) : Void* fun conn_abort = lsquic_conn_abort(x0 : ConnT) fun get_alt_svc_versions = lsquic_get_alt_svc_versions(versions : LibC::UInt) : LibC::Char* fun get_h3_alpns = lsquic_get_h3_alpns(versions : LibC::UInt) : LibC::Char** @@ -352,7 +354,6 @@ lib LibLsquic fun engine_earliest_adv_tick = lsquic_engine_earliest_adv_tick(engine : EngineT, diff : LibC::Int*) : LibC::Int fun engine_count_attq = lsquic_engine_count_attq(engine : EngineT, from_now : LibC::Int) : LibC::UInt fun conn_status = lsquic_conn_status(x0 : ConnT, errbuf : LibC::Char*, bufsz : LibC::SizeT) : ConnStatus - enum ConnStatus LsconnStHskInProgress = 0 LsconnStConnected = 1 @@ -365,6 +366,5 @@ lib LibLsquic LsconnStClosed = 8 LsconnStPeerGoingAway = 9 end - - $lsquic_ver2str : LibC::Char*[7] + $ver2str : LibC::Char*[6] end diff --git a/src/lsquic/patch.cr b/src/lsquic/patch.cr index a3889ec..11b407e 100644 --- a/src/lsquic/patch.cr +++ b/src/lsquic/patch.cr @@ -1,5 +1,6 @@ require "openssl" +@[Link(ldflags: "#{__DIR__}/ext/liblsquic.a #{__DIR__}/ext/libcrypto.a")] lib LibCrypto fun evp_ripemd160 = EVP_sha1 : EVP_MD fun sk_free = sk_free(st : Void*) @@ -11,9 +12,8 @@ lib LibCrypto fun err_load_crypto_strings = rand : LibC::Int end +@[Link(ldflags: "#{__DIR__}/ext/libssl.a")] lib LibSSL - {% ssl_version = "1.1.0" %} - fun ssl_set_tlsext_host_name = SSL_set_tlsext_host_name(handle : SSL, name : Char*) : Long fun ssl_ctx_set_tmp_ecdh = SSL_CTX_set_tmp_ecdh(ctx : SSLContext, parg : Void*) : ULong fun ssl_ctx_get_mode = SSL_CTX_get_mode(ctx : SSLContext) : ULong @@ -27,6 +27,43 @@ lib LibSSL fun ssl_load_error_strings = rand : LibC::Int end +abstract class OpenSSL::SSL::Context + def set_tmp_ecdh_key(curve = LibCrypto::NID_X9_62_prime256v1) + key = LibCrypto.ec_key_new_by_curve_name(curve) + raise OpenSSL::Error.new("ec_key_new_by_curve_name") if key.null? + LibSSL.ssl_ctx_set_tmp_ecdh(@handle, key) + LibCrypto.ec_key_free(key) + end + + # Returns the current modes set on the TLS context. + def modes + OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_get_mode(@handle) + end + + # Adds modes to the TLS context. + def add_modes(mode : OpenSSL::SSL::Modes) + OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_set_mode(@handle, mode) + end + + # Removes modes from the TLS context. + def remove_modes(mode : OpenSSL::SSL::Modes) + OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_clear_mode(@handle, mode) + end + + # Returns the current options set on the TLS context. + def options + OpenSSL::SSL::Options.new LibSSL.ssl_ctx_get_options(@handle) + end + + def add_options(options : OpenSSL::SSL::Options) + OpenSSL::SSL::Options.new LibSSL.ssl_ctx_set_options(@handle, options) + end + + def remove_options(options : OpenSSL::SSL::Options) + OpenSSL::SSL::Options.new LibSSL.ssl_ctx_clear_options(@handle, options) + end +end + struct OpenSSL::BIO CRYSTAL_BIO_BORING = begin bwrite = LibCrypto::BioMethodWriteOld.new do |bio, data, len| @@ -126,43 +163,6 @@ struct OpenSSL::BIO end end -abstract class OpenSSL::SSL::Context - def set_tmp_ecdh_key(curve = LibCrypto::NID_X9_62_prime256v1) - key = LibCrypto.ec_key_new_by_curve_name(curve) - raise OpenSSL::Error.new("ec_key_new_by_curve_name") if key.null? - LibSSL.ssl_ctx_set_tmp_ecdh(@handle, key) - LibCrypto.ec_key_free(key) - end - - # Returns the current modes set on the TLS context. - def modes - OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_get_mode(@handle) - end - - # Adds modes to the TLS context. - def add_modes(mode : OpenSSL::SSL::Modes) - OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_set_mode(@handle, mode) - end - - # Removes modes from the TLS context. - def remove_modes(mode : OpenSSL::SSL::Modes) - OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_clear_mode(@handle, mode) - end - - # Returns the current options set on the TLS context. - def options - OpenSSL::SSL::Options.new LibSSL.ssl_ctx_get_options(@handle) - end - - def add_options(options : OpenSSL::SSL::Options) - OpenSSL::SSL::Options.new LibSSL.ssl_ctx_set_options(@handle, options) - end - - def remove_options(options : OpenSSL::SSL::Options) - OpenSSL::SSL::Options.new LibSSL.ssl_ctx_clear_options(@handle, options) - end -end - abstract class OpenSSL::SSL::Socket < IO class Client < Socket def initialize(io, context : Context::Client = Context::Client.new, sync_close : Bool = false, hostname : String? = nil)