From ee9e474e43e1cc585d12adee8e6bd144990bcfe3 Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Tue, 5 Mar 2024 13:48:30 -0700 Subject: [PATCH] Lots of work --- .codecov.yml | 1 - .github/workflows/CompatHelper.yml | 45 --- .github/workflows/ci.yml | 16 +- .github/workflows/invalidations.yml | 40 --- .github/workflows/previews-cleanup.yml | 28 -- LICENSE.md | 4 +- README.md | 15 +- src/AwsIO.jl | 305 ++++++++++++++++++- src/LibAwsIO.jl | 391 +++++++++++++++++++++++++ src/io_errors.jl | 152 ++++++++++ test/runtests.jl | 32 +- 11 files changed, 879 insertions(+), 150 deletions(-) delete mode 100644 .codecov.yml delete mode 100644 .github/workflows/CompatHelper.yml delete mode 100644 .github/workflows/invalidations.yml delete mode 100644 .github/workflows/previews-cleanup.yml create mode 100644 src/LibAwsIO.jl create mode 100644 src/io_errors.jl diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index 69cb760..0000000 --- a/.codecov.yml +++ /dev/null @@ -1 +0,0 @@ -comment: false diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml deleted file mode 100644 index 7ddad2a..0000000 --- a/.github/workflows/CompatHelper.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: CompatHelper -on: - schedule: - - cron: 0 0 * * * - workflow_dispatch: -permissions: - contents: write - pull-requests: write -jobs: - CompatHelper: - runs-on: ubuntu-latest - steps: - - name: Check if Julia is already available in the PATH - id: julia_in_path - run: which julia - continue-on-error: true - - name: Install Julia, but only if it is not already available in the PATH - uses: julia-actions/setup-julia@v1 - with: - version: '1' - # arch: ${{ runner.arch }} - if: steps.julia_in_path.outcome != 'success' - - name: "Add the General registry via Git" - run: | - import Pkg - ENV["JULIA_PKG_SERVER"] = "" - Pkg.Registry.add("General") - shell: julia --color=yes {0} - - name: "Install CompatHelper" - run: | - import Pkg - name = "CompatHelper" - uuid = "aa819f21-2bde-4658-8897-bab36330d9b7" - version = "3" - Pkg.add(; name, uuid, version) - shell: julia --color=yes {0} - - name: "Run CompatHelper" - run: | - import CompatHelper - CompatHelper.main() - shell: julia --color=yes {0} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} - # COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e978134..3a97b24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: fail-fast: false matrix: version: - - '1.6' + - '1.9' - '1' # automatically expands to the latest stable 1.x release of Julia - nightly os: @@ -24,10 +24,6 @@ jobs: - windows-latest arch: - x64 - include: - - os: windows-latest - version: '1' - arch: x86 steps: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 @@ -50,13 +46,3 @@ jobs: - uses: codecov/codecov-action@v1 with: file: lcov.info - docs: - name: Documentation - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/julia-buildpkg@latest - - uses: julia-actions/julia-docdeploy@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/invalidations.yml b/.github/workflows/invalidations.yml deleted file mode 100644 index af4c158..0000000 --- a/.github/workflows/invalidations.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Invalidations - -on: - pull_request: - -concurrency: - # Skip intermediate builds: always. - # Cancel intermediate builds: always. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - evaluate: - # Only run on PRs to the default branch. - # In the PR trigger above branches can be specified only explicitly whereas this check should work for master, main, or any other default branch - if: github.base_ref == github.event.repository.default_branch - runs-on: ubuntu-latest - steps: - - uses: julia-actions/setup-julia@v1 - with: - version: '1' - - uses: actions/checkout@v3 - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-invalidations@v1 - id: invs_pr - - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.repository.default_branch }} - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-invalidations@v1 - id: invs_default - - - name: Report invalidation counts - run: | - echo "Invalidations on default branch: ${{ steps.invs_default.outputs.total }} (${{ steps.invs_default.outputs.deps }} via deps)" >> $GITHUB_STEP_SUMMARY - echo "This branch: ${{ steps.invs_pr.outputs.total }} (${{ steps.invs_pr.outputs.deps }} via deps)" >> $GITHUB_STEP_SUMMARY - - name: Check if the PR does increase number of invalidations - if: steps.invs_pr.outputs.total > steps.invs_default.outputs.total - run: exit 1 \ No newline at end of file diff --git a/.github/workflows/previews-cleanup.yml b/.github/workflows/previews-cleanup.yml deleted file mode 100644 index 1568024..0000000 --- a/.github/workflows/previews-cleanup.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Doc Preview Cleanup - -on: - pull_request: - types: [closed] - -jobs: - doc-preview-cleanup: - runs-on: ubuntu-latest - steps: - - name: Checkout gh-pages branch - uses: actions/checkout@v2 - with: - ref: gh-pages - - - name: Delete preview and history - run: | - git config user.name "Documenter.jl" - git config user.email "documenter@juliadocs.github.io" - git rm -rf "previews/PR$PRNUM" - git commit -m "delete preview" - git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree}) - env: - PRNUM: ${{ github.event.number }} - - - name: Push changes - run: | - git push --force origin gh-pages-new:gh-pages diff --git a/LICENSE.md b/LICENSE.md index 295bef4..f2aa1bc 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ -The Example.jl package is licensed under the MIT "Expat" License: +The AwsIO.jl package is licensed under the MIT "Expat" License: -> Copyright (c) 2022: Jacob Quinn +> Copyright (c) 2024: Jacob Quinn > > Permission is hereby granted, free of charge, to any person obtaining > a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 9a441d9..f8bf6ab 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,13 @@ -Example Julia package repo. +# AwsIO.jl -[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaLang.github.io/Example.jl/stable) -[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaLang.github.io/Example.jl/dev) +Wrapper library for the https://github.com/awslabs/aws-c-io library. -GitHub Actions : [![Build Status](https://github.com/JuliaLang/Example.jl/workflows/CI/badge.svg)](https://github.com/JuliaLang/Example.jl/actions?query=workflow%3ACI+branch%3Amaster) +The `LibAwsIO` module (exported) aims to directly wrap and expose aws-c-io functionality (matching +data structures and api functions exactly). -[![codecov.io](http://codecov.io/github/JuliaLang/Example.jl/coverage.svg?branch=master)](http://codecov.io/github/JuliaLang/Example.jl?branch=master) +The functions and structures in `AwsIO` are more Julia-like and are intended to be more user-friendly, +while using `LibAwsIO` under the hood. + +GitHub Actions : [![Build Status](https://github.com/JuliaServices/AwsIO.jl/workflows/CI/badge.svg)](https://github.com/JuliaServices/AwsIO.jl/actions?query=workflow%3ACI+branch%3Amaster) + +[![codecov.io](http://codecov.io/github/JuliaServices/AwsIO.jl/coverage.svg?branch=master)](http://codecov.io/github/JuliaServices/AwsIO.jl?branch=master) diff --git a/src/AwsIO.jl b/src/AwsIO.jl index 2cf379e..9bcf4d8 100644 --- a/src/AwsIO.jl +++ b/src/AwsIO.jl @@ -1,18 +1,301 @@ module AwsIO -export hello, domath -""" - hello(who::String) +using Logging -Return "Hello, `who`". -""" -hello(who::String) = "Hello, $who" +import AwsC: AwsC, SUCCESS, ERROR, mem_acquire, mem_release, error_str, byte_cursor, byte_buf, append -""" - domath(x::Number) +include("LibAwsIO.jl") +import .LibAwsIO: LibAwsIO, get_allocator, get_message_data, set_message_data!, aws_channel_slot_increment_read_window, + aws_channel_slot_on_handler_shutdown_complete, aws_channel_handler_vtable, aws_channel_slot_new, + aws_channel_slot_insert_end, aws_channel_slot_set_handler, aws_channel_handler, aws_channel, + aws_channel_slot, AWS_TASK_STATUS_RUN_READY, AWS_CHANNEL_DIR_WRITE, aws_channel_acquire_message_from_pool, + aws_channel_slot_send_message, aws_client_bootstrap, aws_socket_channel_bootstrap_options, aws_channel_task, + aws_io_message, aws_client_bootstrap_new_socket_channel, aws_channel_task_init, aws_channel_schedule_task_now, + tlsoptions, aws_tls_client_handler_new, aws_tls_client_handler_start_negotiation, + aws_channel_slot_insert_left, aws_channel_shutdown, aws_tls_connection_options_clean_up -Return `x + 5`. -""" -domath(x::Number) = x + 5 +struct SocketError <: Exception + msg::String +end + +function c_process_read_message(handler, slot, messageptr)::Cint + data = get_message_data(messageptr) + handler.impl.debug && @info "c_process_read_message: $(data.len) bytes" + if isopen(handler.impl.readbuf) + unsafe_write(handler.impl.readbuf, data.buffer, data.len) + ret = SUCCESS + else + ret = ERROR + end + mem_release(get_allocator(messageptr), messageptr) + return ret +end + +function c_process_write_message(handler, slot, messageptr)::Cint + handler.impl.debug && @info "c_process_write_message" + # this should never be called since we only want to be the last slot in the channel + return ERROR +end + +function c_increment_read_window(handler, slot, size)::Cint + handler.impl.debug && @info "c_increment_read_window" + aws_channel_slot_increment_read_window(slot, size) + return SUCCESS +end + +function c_shutdown(handler, slot, dir, error_code, free_scarce_resources_immediately)::Cint + Core.println("c_shutdown: $slot") + handler.impl.debug && @warn "c_shutdown: dir = $dir" + close(handler.impl.ch, SocketError(error_str(error_code))) + return aws_channel_slot_on_handler_shutdown_complete(slot, dir, error_code, free_scarce_resources_immediately) +end + +function c_initial_window_size(channel_handler)::Csize_t + return typemax(Int64) +end + +function c_message_overhead(channel_handler)::Csize_t + return 0 +end + +function c_destroy(channel_handler) + return +end + +function c_reset_statistics(channel_handler)::Cvoid + return SUCCESS +end + +function c_gather_statistics(channel_handler, stats#=::Ptr{aws_array_list}=#)::Cvoid + return SUCCESS +end + +function c_trigger_read(channel_handler)::Cvoid + return SUCCESS +end + +const RW_HANDLER_VTABLE = Ref{aws_channel_handler_vtable}() + +function c_setup_callback(bootstrap, error_code, channel, socket) + if error_code != 0 + socket.debug && @error "c_setup_callback: error = '$(error_str(error_code))'" + close(socket.ch, SocketError(error_str(error_code))) + else + slot = aws_channel_slot_new(channel) + if slot == C_NULL + socket.debug && @error "c_setup_callback: failed to create channel slot" + close(socket.ch, SocketError("failed to create channel slot")) + end + if aws_channel_slot_insert_end(channel, slot) != 0 + socket.debug && @error "c_setup_callback: failed to insert channel slot" + close(socket.ch, SocketError("failed to insert channel slot")) + end + handler = aws_channel_handler(RW_HANDLER_VTABLE[], AwsC.allocator(), C_NULL, socket) + if aws_channel_slot_set_handler(slot, handler) != 0 + socket.debug && @error "c_setup_callback: failed to set channel slot handler" + close(socket.ch, SocketError("failed to set channel slot handler")) + end + socket.channel = channel + socket.slot = slot + socket.handler = handler + put!(socket.ch, :setup) + end + return +end + +const SETUP_CALLBACK = Ref{Ptr{Cvoid}}(C_NULL) +function c_shutdown_callback(bootstrap, error_code, channel, socket) + socket.debug && @warn "c_shutdown_callback" + close(socket.ch) + close(socket.readbuf) + close(socket.writebuf) + socket.channel = C_NULL + socket.slot = C_NULL + socket.handler = nothing + return end + +const SHUTDOWN_CALLBACK = Ref{Ptr{Cvoid}}(C_NULL) + +mutable struct Socket + debug::Bool + tls::Bool + channel::Ptr{aws_channel} + slot::Ptr{aws_channel_slot} + handler::Union{aws_channel_handler, Nothing} + ch::Channel{Symbol} + readbuf::Base.BufferStream + writelock::ReentrantLock + writebuf::IOBuffer + options::aws_socket_channel_bootstrap_options + + function Socket(host, port; tls::Bool=false, debug::Bool=false, kw...) + x = new(debug, tls, C_NULL, C_NULL, nothing, Channel{Symbol}(0), Base.BufferStream(), ReentrantLock(), PipeBuffer()) + x.options = aws_socket_channel_bootstrap_options( + host, + port; + tls, + user_data=x, + setup_callback=SETUP_CALLBACK[], + shutdown_callback=SHUTDOWN_CALLBACK[], + kw...) + aws_client_bootstrap_new_socket_channel(x.options) != 0 && throw(SocketError("failed to create socket")) + take!(x.ch) # wait for connection + return x + end +end + +function schedule_channel_task(channel, task_fn, arg, type_tag) + task = aws_channel_task_init(task_fn, arg, type_tag) + aws_channel_schedule_task_now(channel, task) +end + +function c_scheduled_write(channel_task, (socket, n), status) + if status == Int(AWS_TASK_STATUS_RUN_READY) + socket.debug && @info "c_scheduled_write: writing $n bytes" + buf = byte_buf(n, pointer(socket.writebuf.data)) + bytes_written = 0 + while bytes_written < n + msgptr = aws_channel_acquire_message_from_pool(socket.channel, n - bytes_written) + if msgptr == C_NULL + socket.debug && @error "c_scheduled_write: failed to acquire message from pool" + close(socket.ch, SocketError("failed to acquire message from pool")) + @goto done + end + data = get_message_data(msgptr) + cap = data.capacity + cursor = byte_cursor(cap, buf.buffer + bytes_written) + data = append(data, cursor) + set_message_data!(msgptr, data) + socket.debug && @info "c_scheduled_write: sending $(data.len) bytes in message" + if aws_channel_slot_send_message(socket.slot, msgptr, AWS_CHANNEL_DIR_WRITE) != 0 + mem_release(AwsC.allocator(), msgptr) + socket.debug && @error "c_scheduled_write: failed to send message" + close(socket.ch, SocketError("failed to send message")) + @goto done + end + bytes_written += cap + end + else + socket.debug && @warn "c_scheduled_write: task cancelled" + close(socket.ch, SocketError("task cancelled")) + @goto done + end + put!(socket.ch, :write_completed) +@label done + mem_release(AwsC.allocator(), channel_task) + socket.debug && @info "c_scheduled_write: write completed" + return +end + +const SCHEDULED_WRITE = Ref{Ptr{Cvoid}}(C_NULL) + +function Base.write(sock::Socket, data) + @lock sock.writelock begin + n = write(sock.writebuf, data) + schedule_channel_task(sock.channel, SCHEDULED_WRITE[], (sock, n), "socket channel write") + take!(sock.ch) # wait for write completion + skip(sock.writebuf, n) # "consume" the bytes we wrote to our writebuf to reset it for furture writes + return n + end +end + +Base.flush(sock::Socket) = flush(sock.writebuf) + +Base.read(sock::Socket) = read(sock.readbuf) +Base.read!(sock::Socket, buf::Vector{UInt8}) = read!(sock.readbuf, buf) +Base.read(sock::Socket, ::Type{T}) where {T} = read(sock.readbuf, T) +Base.read(sock::Socket, n::Integer) = read(sock.readbuf, n) +Base.unsafe_read(sock::Socket, ptr::Ptr{UInt8}, n::Integer) = unsafe_read(sock.readbuf, ptr, n) + +Base.skip(sock::Socket, n) = skip(sock.readbuf, n) + +Base.isopen(sock::Socket) = isopen(sock.ch) + +function Base.close(sock::Socket) + close(sock.ch) + close(sock.readbuf) + close(sock.writebuf) + if sock.channel != C_NULL + aws_channel_shutdown(sock.channel, 0) + sock.channel = C_NULL + end + sock.slot = C_NULL + sock.handler = nothing + return +end + +function c_on_negotiation_result(handler, slot, error_code, sock) + if error_code != 0 + sock.debug && @error "c_on_negotiation_result: error = '$(error_str(error_code))'" + close(sock.ch, SocketError(error_str(error_code))) + else + put!(sock.ch, :negotiated) + end + return +end + +const ON_NEGOTIATION_RESULT = Ref{Ptr{Cvoid}}(C_NULL) + +function tlsupgrade!(sock::Socket; + ssl_cert::Union{String, Nothing}=nothing, + ssl_key::Union{String, Nothing}=nothing, + ssl_capath::Union{String, Nothing}=nothing, + ssl_cacert::Union{String, Nothing}=nothing, + ssl_insecure::Bool=false, + ssl_alpn_list::Union{String, Nothing}=nothing + ) + tls_options = tlsoptions( + sock.options.host; + ssl_cert=ssl_cert, + ssl_key=ssl_key, + ssl_capath=ssl_capath, + ssl_cacert=ssl_cacert, + ssl_insecure=ssl_insecure, + ssl_alpn_list=ssl_alpn_list, + on_negotiation_result=ON_NEGOTIATION_RESULT[], + user_data=sock + ) + slot = aws_channel_slot_new(sock.channel) + if slot == C_NULL + throw(SocketError("failed to create channel slot for tlsupgrade")) + end + channel_handler = aws_tls_client_handler_new(AwsC.allocator(), tls_options, slot) + if channel_handler == C_NULL + throw(SocketError("failed to create tls client handler")) + end + # options are copied in aws_tls_client_handler_new, so we can free them now + aws_tls_connection_options_clean_up(tls_options) + mem_release(AwsC.allocator(), tls_options) + if aws_channel_slot_insert_left(sock.slot, slot) != 0 + throw(SocketError("failed to insert channel slot for tlsupgrade")) + end + if aws_channel_slot_set_handler(slot, channel_handler) != 0 + throw(SocketError("failed to set tls client handler")) + end + if aws_tls_client_handler_start_negotiation(channel_handler) != 0 + throw(SocketError("failed to start tls negotiation")) + end + take!(sock.ch) # wait for tls negotiation + return +end + +function __init__() + SETUP_CALLBACK[] = @cfunction(c_setup_callback, Cvoid, (Ptr{aws_client_bootstrap}, Cint, Ptr{aws_channel}, Any)) + SHUTDOWN_CALLBACK[] = @cfunction(c_shutdown_callback, Cvoid, (Ptr{aws_client_bootstrap}, Cint, Ptr{aws_channel}, Any)) + SCHEDULED_WRITE[] = @cfunction(c_scheduled_write, Cvoid, (Ptr{aws_channel_task}, Any, Cint)) + RW_HANDLER_VTABLE[] = aws_channel_handler_vtable( + @cfunction(c_process_read_message, Cint, (Ref{aws_channel_handler}, Ptr{aws_channel_slot}, Ptr{aws_io_message})), + @cfunction(c_process_write_message, Cint, (Ref{aws_channel_handler}, Ptr{aws_channel_slot}, Ptr{aws_io_message})), + @cfunction(c_increment_read_window, Cint, (Ref{aws_channel_handler}, Ptr{aws_channel_slot}, Csize_t)), + @cfunction(c_shutdown, Cint, (Ref{aws_channel_handler}, Ptr{aws_channel_slot}, Cint, Cint, Bool)), + @cfunction(c_initial_window_size, Csize_t, (Ref{aws_channel_handler},)), + @cfunction(c_message_overhead, Csize_t, (Ref{aws_channel_handler},)), + @cfunction(c_destroy, Cvoid, (Ref{aws_channel_handler},)) + ) + ON_NEGOTIATION_RESULT[] = @cfunction(c_on_negotiation_result, Cvoid, (Ptr{Cvoid}, Ptr{aws_channel_slot}, Cint, Any)) + return +end + +end \ No newline at end of file diff --git a/src/LibAwsIO.jl b/src/LibAwsIO.jl new file mode 100644 index 0000000..e86d00f --- /dev/null +++ b/src/LibAwsIO.jl @@ -0,0 +1,391 @@ +module LibAwsIO + +import AwsC.LibAwsC: aws_allocator, aws_default_allocator, aws_byte_buf, aws_byte_cursor, aws_mem_acquire, aws_mem_release, aws_throw_error + +using aws_c_io_jll +# const libaws_c_io = "/Users/jacob.quinn/aws-crt/lib/libaws-c-io.1.0.0.dylib" + +include("io_errors.jl") + +function aws_io_library_init(allocator) + @ccall libaws_c_io.aws_io_library_init(allocator::Ptr{aws_allocator})::Cint +end + +const aws_event_loop_group = Cvoid + +function aws_event_loop_group_new_default(alloc, max_threads, shutdown_options) + @ccall libaws_c_io.aws_event_loop_group_new_default(alloc::Ptr{aws_allocator}, max_threads::UInt16, shutdown_options::Ptr{Cvoid})::Ptr{aws_event_loop_group} +end + +const EVENT_LOOP_GROUP = Ref{Ptr{Cvoid}}(C_NULL) + +const aws_event_loop = Cvoid + +function aws_event_loop_group_get_next_loop(el_group) + @ccall libaws_c_io.aws_event_loop_group_get_next_loop(el_group::Ptr{aws_event_loop_group})::Ptr{aws_event_loop} +end + +const aws_shutdown_callback_options = Cvoid + +mutable struct aws_host_resolver_default_options + max_entries::Csize_t + el_group::Ptr{aws_event_loop_group} + shutdown_options::Ptr{aws_shutdown_callback_options} + system_clock_override_fn::Ptr{Cvoid} +end + +const aws_host_resolver = Cvoid + +const HOST_RESOLVER = Ref{Ptr{Cvoid}}(C_NULL) + +function aws_host_resolver_new_default(allocator, options) + @ccall libaws_c_io.aws_host_resolver_new_default(allocator::Ptr{aws_allocator}, options::Ref{aws_host_resolver_default_options})::Ptr{aws_host_resolver} +end + +struct aws_client_bootstrap_options + event_loop_group::Ptr{aws_event_loop_group} + host_resolver::Ptr{aws_host_resolver} + host_resolution_config::Ptr{Cvoid} # Ptr{aws_host_resolution_config} + on_shutdown_complete::Ptr{Cvoid} + user_data::Ptr{Cvoid} +end + +const aws_client_bootstrap = Cvoid + +const CLIENT_BOOTSTRAP = Ref{Ptr{Cvoid}}(C_NULL) + +function aws_client_bootstrap_new(allocator, options) + @ccall libaws_c_io.aws_client_bootstrap_new(allocator::Ptr{aws_allocator}, options::Ref{aws_client_bootstrap_options})::Ptr{aws_client_bootstrap} +end + +const aws_tls_ctx_options = Cvoid +const aws_tls_ctx = Cvoid +const aws_channel = Cvoid +const aws_channel_slot = Cvoid + +@enum aws_task_status::Cint begin + AWS_TASK_STATUS_RUN_READY = 0 + AWS_TASK_STATUS_CANCELLED = 1 +end + +@enum aws_channel_direction::Cint begin + AWS_CHANNEL_DIR_READ = 0 + AWS_CHANNEL_DIR_WRITE = 1 +end + +mutable struct aws_channel_handler_vtable + process_read_message::Ptr{Cvoid} + process_write_message::Ptr{Cvoid} + increment_read_window::Ptr{Cvoid} + shutdown::Ptr{Cvoid} + initial_window_size::Ptr{Cvoid} + message_overhead::Ptr{Cvoid} + destroy::Ptr{Cvoid} +end + +mutable struct aws_channel_handler + vtable::aws_channel_handler_vtable + allocator::Ptr{aws_allocator} + slot::Ptr{aws_channel_slot} + impl::Any +end + +const aws_io_message = Cvoid + +get_message_data(msg::Ptr{aws_io_message}) = unsafe_load(Ptr{aws_byte_buf}(Ptr{UInt8}(msg) + sizeof(Ptr))) +set_message_data!(msg::Ptr{aws_io_message}, data::aws_byte_buf) = unsafe_store!(Ptr{aws_byte_buf}(Ptr{UInt8}(msg) + sizeof(Ptr)), data) +get_allocator(msg::Ptr{aws_io_message}) = unsafe_load(Ptr{Ptr{aws_allocator}}(msg)) + +function aws_channel_slot_increment_read_window(slot, size) + @ccall libaws_c_io.aws_channel_slot_increment_read_window(slot::Ptr{aws_channel_slot}, size::Csize_t)::Cint +end + +function aws_channel_slot_on_handler_shutdown_complete(slot, dir, error_code, abort_immediately) + @ccall libaws_c_io.aws_channel_slot_on_handler_shutdown_complete(slot::Ptr{aws_channel_slot}, dir::Cint, error_code::Cint, abort_immediately::Bool)::Cint +end + +function aws_channel_acquire_message_from_pool(channel, size_hint) + @ccall libaws_c_io.aws_channel_acquire_message_from_pool(channel::Ptr{aws_channel}, 0::Cint, size_hint::Int32)::Ptr{aws_io_message} +end + +function aws_channel_slot_send_message(slot, message, dir) + @ccall libaws_c_io.aws_channel_slot_send_message(slot::Ptr{aws_channel_slot}, message::Ptr{Cvoid}, dir::Cint)::Cint +end + +function aws_channel_slot_new(channel) + @ccall libaws_c_io.aws_channel_slot_new(channel::Ptr{aws_channel})::Ptr{aws_channel_slot} +end + +function aws_channel_slot_insert_end(channel, slot) + @ccall libaws_c_io.aws_channel_slot_insert_end(channel::Ptr{aws_channel}, slot::Ptr{aws_channel_slot})::Cint +end + +function aws_channel_slot_insert_right(slot, to_add) + @ccall libaws_c_io.aws_channel_slot_insert_right(slot::Ptr{aws_channel_slot}, to_add::Ptr{aws_channel_slot})::Cint +end + +function aws_channel_slot_insert_left(slot, to_add) + @ccall libaws_c_io.aws_channel_slot_insert_left(slot::Ptr{aws_channel_slot}, to_add::Ptr{aws_channel_slot})::Cint +end + +function aws_channel_get_first_slot(channel) + @ccall libaws_c_io.aws_channel_get_first_slot(channel::Ptr{aws_channel})::Ptr{aws_channel_slot} +end + +function aws_channel_slot_set_handler(slot, handler) + @ccall libaws_c_io.aws_channel_slot_set_handler(slot::Ptr{Cvoid}, handler::Any)::Cint +end + +function aws_channel_slot_set_handler(slot, handler::Ptr{Cvoid}) + @ccall libaws_c_io.aws_channel_slot_set_handler(slot::Ptr{aws_channel_slot}, handler::Ptr{Cvoid})::Cint +end + +function aws_tls_client_ctx_new(alloc, options) + @ccall libaws_c_io.aws_tls_client_ctx_new(alloc::Ptr{aws_allocator}, options::Ptr{aws_tls_ctx_options})::Ptr{aws_tls_ctx} +end + +const aws_tls_connection_options = Cvoid + +function aws_tls_connection_options_init_from_ctx(conn_options, ctx) + @ccall libaws_c_io.aws_tls_connection_options_init_from_ctx(conn_options::Ref{aws_tls_connection_options}, ctx::Ptr{aws_tls_ctx})::Cvoid +end + +function aws_tls_ctx_options_init_client_mtls_from_path(options, allocator, cert_path, pkey_path) + @ccall libaws_c_io.aws_tls_ctx_options_init_client_mtls_from_path(options::Ptr{aws_tls_ctx_options}, allocator::Ptr{aws_allocator}, cert_path::Ptr{Cchar}, pkey_path::Ptr{Cchar})::Cint +end + +function aws_tls_ctx_options_init_client_mtls_from_system_path(options, allocator, cert_reg_path) + @ccall libaws_c_io.aws_tls_ctx_options_init_client_mtls_from_system_path(options::Ptr{aws_tls_ctx_options}, allocator::Ptr{aws_allocator}, cert_reg_path::Ptr{Cchar})::Cint +end + +function aws_tls_ctx_options_override_default_trust_store_from_path(options, ca_path, ca_file) + @ccall libaws_c_io.aws_tls_ctx_options_override_default_trust_store_from_path(options::Ptr{aws_tls_ctx_options}, ca_path::Ptr{Cchar}, ca_file::Ptr{Cchar})::Cint +end + +function aws_tls_ctx_options_init_default_client(options, allocator) + @ccall libaws_c_io.aws_tls_ctx_options_init_default_client(options::Ptr{aws_tls_ctx_options}, allocator::Ptr{aws_allocator})::Cvoid +end + +function aws_tls_ctx_options_set_alpn_list(options, alpn_list) + @ccall libaws_c_io.aws_tls_ctx_options_set_alpn_list(options::Ptr{aws_tls_ctx_options}, alpn_list::Ptr{Cchar})::Cint +end + +function aws_tls_ctx_options_set_verify_peer(options, verify_peer) + @ccall libaws_c_io.aws_tls_ctx_options_set_verify_peer(options::Ptr{aws_tls_ctx_options}, verify_peer::Bool)::Cvoid +end + +function aws_tls_connection_options_set_server_name(conn_options, allocator, server_name) + @ccall libaws_c_io.aws_tls_connection_options_set_server_name(conn_options::Ptr{aws_tls_connection_options}, allocator::Ptr{aws_allocator}, server_name::Ref{aws_byte_cursor})::Cint +end + +function aws_tls_connection_options_clean_up(connection_options) + @ccall libaws_c_io.aws_tls_connection_options_clean_up(connection_options::Ref{aws_tls_connection_options})::Cvoid +end + +function aws_tls_ctx_release(ctx) + @ccall libaws_c_io.aws_tls_ctx_release(ctx::Ptr{aws_tls_ctx})::Cvoid +end + +function aws_tls_ctx_options_clean_up(options) + @ccall libaws_c_io.aws_tls_ctx_options_clean_up(options::Ptr{aws_tls_ctx_options})::Cvoid +end + +const aws_channel_task = Cvoid + +#NOTE: task_fn needs to release channel_task memory +function aws_channel_task_init(task_fn, arg, type_tag) + channel_task = aws_mem_acquire(aws_default_allocator(), 512) + @ccall libaws_c_io.aws_channel_task_init(channel_task::Ptr{aws_channel_task}, task_fn::Ptr{Cvoid}, arg::Any, type_tag::Ptr{Cchar})::Cvoid + return channel_task +end + +function aws_channel_schedule_task_now(channel, task) + @ccall libaws_c_io.aws_channel_schedule_task_now(channel::Ptr{aws_channel}, task::Ptr{aws_channel_task})::Cint +end + +@enum aws_socket_type::UInt32 begin + AWS_SOCKET_STREAM = 0 + AWS_SOCKET_DGRAM = 1 +end + +@enum aws_socket_domain::UInt32 begin + AWS_SOCKET_IPV4 = 0 + AWS_SOCKET_IPV6 = 1 + AWS_SOCKET_LOCAL = 2 + AWS_SOCKET_VSOCK = 3 +end + +mutable struct aws_socket_options + type::aws_socket_type + domain::aws_socket_domain + connect_timeout_ms::UInt32 + keep_alive_interval_sec::UInt16 + keep_alive_timeout_sec::UInt16 + keep_alive_max_failed_probes::UInt16 + keepalive::Bool +end + +aws_socket_options() = aws_socket_options(AWS_SOCKET_STREAM, AWS_SOCKET_IPV4, 3000, 0, 0, 0, false) + +mutable struct aws_socket_channel_bootstrap_options + bootstrap::Ptr{aws_client_bootstrap} + host_name::Cstring + port::UInt32 + socket_options::aws_socket_options + tls_options::Ptr{aws_tls_connection_options} + creation_callback::Ptr{Cvoid} + setup_callback::Ptr{Cvoid} + shutdown_callback::Ptr{Cvoid} + enable_read_back_pressure::Bool + user_data::Any + requested_event_loop::Ptr{aws_event_loop} + host_resolution_override_config::Ptr{Cvoid} # Ptr{aws_host_resolution_config} + host::String # to hold the reference to our host_name Cstring +end + +function aws_client_bootstrap_new_socket_channel(options) + @ccall libaws_c_io.aws_client_bootstrap_new_socket_channel(options::Ref{aws_socket_channel_bootstrap_options})::Cint +end + +function aws_tls_connection_options_set_callbacks(options, on_negotiation_result, user_data) + @ccall libaws_c_io.aws_tls_connection_options_set_callbacks(options::Ptr{aws_tls_connection_options}, on_negotiation_result::Ptr{Cvoid}, C_NULL::Ptr{Cvoid}, C_NULL::Ptr{Cvoid}, user_data::Any)::Cvoid +end + +# NOTE: caller is responsible for cleaning up tls_options +function tlsoptions(host_str::String; + allocator=aws_default_allocator(), + # tls options + ssl_cert=nothing, + ssl_key=nothing, + ssl_capath=nothing, + ssl_cacert=nothing, + ssl_insecure=false, + ssl_alpn_list=nothing, + on_negotiation_result=C_NULL, + user_data=C_NULL +) + tls_options = aws_mem_acquire(allocator, 64) + tls_ctx_options = aws_mem_acquire(allocator, 512) + tls_ctx = C_NULL + try + if ssl_cert !== nothing && ssl_key !== nothing + aws_tls_ctx_options_init_client_mtls_from_path(tls_ctx_options, allocator, ssl_cert, ssl_key) != 0 && aws_throw_error() + elseif Sys.iswindows() && ssl_cert !== nothing && ssl_key === nothing + aws_tls_ctx_options_init_client_mtls_from_system_path(tls_ctx_options, allocator, ssl_cert) != 0 && aws_throw_error() + else + aws_tls_ctx_options_init_default_client(tls_ctx_options, allocator) + end + if ssl_capath !== nothing && ssl_cacert !== nothing + aws_tls_ctx_options_override_default_trust_store_from_path(tls_ctx_options, ssl_capath, ssl_cacert) != 0 && aws_throw_error() + end + if ssl_insecure + aws_tls_ctx_options_set_verify_peer(tls_ctx_options, false) + end + if ssl_alpn_list !== nothing + aws_tls_ctx_options_set_alpn_list(tls_ctx_options, ssl_alpn_list) != 0 && aws_throw_error() + end + tls_ctx = aws_tls_client_ctx_new(allocator, tls_ctx_options) + tls_ctx == C_NULL && aws_throw_error() + aws_tls_connection_options_init_from_ctx(tls_options, tls_ctx) + aws_tls_connection_options_set_server_name(tls_options, allocator, aws_byte_cursor(host_str)) != 0 && aws_throw_error() + if on_negotiation_result !== C_NULL + aws_tls_connection_options_set_callbacks(tls_options, on_negotiation_result, user_data) + end + finally + aws_tls_ctx_options_clean_up(tls_ctx_options) + aws_tls_ctx_release(tls_ctx) + aws_mem_release(allocator, tls_ctx_options) + end + return tls_options +end + +function aws_socket_channel_bootstrap_options(host::AbstractString, port::Integer; + tls::Bool=false, + allocator=aws_default_allocator(), + bootstrap=CLIENT_BOOTSTRAP[], + socket_options=aws_socket_options(), + # tls options + ssl_cert=nothing, + ssl_key=nothing, + ssl_capath=nothing, + ssl_cacert=nothing, + ssl_insecure=false, + ssl_alpn_list="h2;http/1.1", + # callbacks + creation_callback=C_NULL, + setup_callback=C_NULL, + shutdown_callback=C_NULL, + user_data=C_NULL, + enabled_read_back_pressure=false, + ) + host_str = String(host) + tls_options = C_NULL + if tls + tls_options = tlsoptions( + host_str; + allocator=allocator, + ssl_cert=ssl_cert, + ssl_key=ssl_key, + ssl_capath=ssl_capath, + ssl_cacert=ssl_cacert, + ssl_insecure=ssl_insecure, + ssl_alpn_list=ssl_alpn_list + ) + end + x = aws_socket_channel_bootstrap_options( + bootstrap, + Base.unsafe_convert(Cstring, host_str), + UInt32(port), + socket_options, + tls_options, + creation_callback, + setup_callback, + shutdown_callback, + enabled_read_back_pressure, + user_data, + C_NULL, + C_NULL, + host_str + ) + finalizer(x) do x + if x.tls_options !== C_NULL + aws_tls_connection_options_clean_up(x.tls_options) + aws_mem_release(allocator, x.tls_options) + end + end + return x +end + +function aws_tls_client_handler_new(allocator, options, slot) + @ccall libaws_c_io.aws_tls_client_handler_new(allocator::Ptr{aws_allocator}, options::Ptr{aws_tls_connection_options}, slot::Ptr{aws_channel_slot})::Ptr{Cvoid} +end + +function aws_tls_client_handler_start_negotiation(handler) + @ccall libaws_c_io.aws_tls_client_handler_start_negotiation(handler::Ptr{Cvoid})::Cint +end + +function aws_channel_shutdown(channel, error_code) + @ccall libaws_c_io.aws_channel_shutdown(channel::Ptr{aws_channel}, error_code::Cint)::Cint +end + +precompiling() = ccall(:jl_generating_output, Cint, ()) == 1 + +function __init__() + if !precompiling() + allocator = aws_default_allocator() + aws_io_library_init(allocator) + el_group = aws_event_loop_group_new_default(allocator, 0, C_NULL) + EVENT_LOOP_GROUP[] = el_group + # populate default host resolver + resolver_options = aws_host_resolver_default_options(8, el_group, C_NULL, C_NULL) + host_resolver = aws_host_resolver_new_default(allocator, resolver_options) + @assert host_resolver != C_NULL + HOST_RESOLVER[] = host_resolver + # populate default client bootstrap w/ event loop, host resolver, and allocator + bootstrap_options = aws_client_bootstrap_options(el_group, host_resolver, C_NULL, C_NULL, C_NULL) + CLIENT_BOOTSTRAP[] = aws_client_bootstrap_new(allocator, bootstrap_options) + @assert CLIENT_BOOTSTRAP[] != C_NULL + end +end + +end \ No newline at end of file diff --git a/src/io_errors.jl b/src/io_errors.jl new file mode 100644 index 0000000..df59d5c --- /dev/null +++ b/src/io_errors.jl @@ -0,0 +1,152 @@ +@enum aws_io_errors::UInt32 begin + AWS_IO_CHANNEL_ERROR_ERROR_CANT_ACCEPT_INPUT = 1024 + AWS_IO_CHANNEL_UNKNOWN_MESSAGE_TYPE = 1025 + AWS_IO_CHANNEL_READ_WOULD_EXCEED_WINDOW = 1026 + AWS_IO_EVENT_LOOP_ALREADY_ASSIGNED = 1027 + AWS_IO_EVENT_LOOP_SHUTDOWN = 1028 + AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE = 1029 + AWS_IO_TLS_ERROR_NOT_NEGOTIATED = 1030 + AWS_IO_TLS_ERROR_WRITE_FAILURE = 1031 + AWS_IO_TLS_ERROR_ALERT_RECEIVED = 1032 + AWS_IO_TLS_CTX_ERROR = 1033 + AWS_IO_TLS_VERSION_UNSUPPORTED = 1034 + AWS_IO_TLS_CIPHER_PREF_UNSUPPORTED = 1035 + AWS_IO_MISSING_ALPN_MESSAGE = 1036 + AWS_IO_UNHANDLED_ALPN_PROTOCOL_MESSAGE = 1037 + AWS_IO_FILE_VALIDATION_FAILURE = 1038 + AWS_ERROR_IO_EVENT_LOOP_THREAD_ONLY = 1039 + AWS_ERROR_IO_ALREADY_SUBSCRIBED = 1040 + AWS_ERROR_IO_NOT_SUBSCRIBED = 1041 + AWS_ERROR_IO_OPERATION_CANCELLED = 1042 + AWS_IO_READ_WOULD_BLOCK = 1043 + AWS_IO_BROKEN_PIPE = 1044 + AWS_IO_SOCKET_UNSUPPORTED_ADDRESS_FAMILY = 1045 + AWS_IO_SOCKET_INVALID_OPERATION_FOR_TYPE = 1046 + AWS_IO_SOCKET_CONNECTION_REFUSED = 1047 + AWS_IO_SOCKET_TIMEOUT = 1048 + AWS_IO_SOCKET_NO_ROUTE_TO_HOST = 1049 + AWS_IO_SOCKET_NETWORK_DOWN = 1050 + AWS_IO_SOCKET_CLOSED = 1051 + AWS_IO_SOCKET_NOT_CONNECTED = 1052 + AWS_IO_SOCKET_INVALID_OPTIONS = 1053 + AWS_IO_SOCKET_ADDRESS_IN_USE = 1054 + AWS_IO_SOCKET_INVALID_ADDRESS = 1055 + AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE = 1056 + AWS_IO_SOCKET_CONNECT_ABORTED = 1057 + AWS_IO_DNS_QUERY_FAILED = 1058 + AWS_IO_DNS_INVALID_NAME = 1059 + AWS_IO_DNS_NO_ADDRESS_FOR_HOST = 1060 + AWS_IO_DNS_HOST_REMOVED_FROM_CACHE = 1061 + AWS_IO_STREAM_INVALID_SEEK_POSITION = 1062 + AWS_IO_STREAM_READ_FAILED = 1063 + DEPRECATED_AWS_IO_INVALID_FILE_HANDLE = 1064 + AWS_IO_SHARED_LIBRARY_LOAD_FAILURE = 1065 + AWS_IO_SHARED_LIBRARY_FIND_SYMBOL_FAILURE = 1066 + AWS_IO_TLS_NEGOTIATION_TIMEOUT = 1067 + AWS_IO_TLS_ALERT_NOT_GRACEFUL = 1068 + AWS_IO_MAX_RETRIES_EXCEEDED = 1069 + AWS_IO_RETRY_PERMISSION_DENIED = 1070 + AWS_IO_TLS_DIGEST_ALGORITHM_UNSUPPORTED = 1071 + AWS_IO_TLS_SIGNATURE_ALGORITHM_UNSUPPORTED = 1072 + AWS_ERROR_PKCS11_VERSION_UNSUPPORTED = 1073 + AWS_ERROR_PKCS11_TOKEN_NOT_FOUND = 1074 + AWS_ERROR_PKCS11_KEY_NOT_FOUND = 1075 + AWS_ERROR_PKCS11_KEY_TYPE_UNSUPPORTED = 1076 + AWS_ERROR_PKCS11_UNKNOWN_CRYPTOKI_RETURN_VALUE = 1077 + AWS_ERROR_PKCS11_CKR_CANCEL = 1078 + AWS_ERROR_PKCS11_CKR_HOST_MEMORY = 1079 + AWS_ERROR_PKCS11_CKR_SLOT_ID_INVALID = 1080 + AWS_ERROR_PKCS11_CKR_GENERAL_ERROR = 1081 + AWS_ERROR_PKCS11_CKR_FUNCTION_FAILED = 1082 + AWS_ERROR_PKCS11_CKR_ARGUMENTS_BAD = 1083 + AWS_ERROR_PKCS11_CKR_NO_EVENT = 1084 + AWS_ERROR_PKCS11_CKR_NEED_TO_CREATE_THREADS = 1085 + AWS_ERROR_PKCS11_CKR_CANT_LOCK = 1086 + AWS_ERROR_PKCS11_CKR_ATTRIBUTE_READ_ONLY = 1087 + AWS_ERROR_PKCS11_CKR_ATTRIBUTE_SENSITIVE = 1088 + AWS_ERROR_PKCS11_CKR_ATTRIBUTE_TYPE_INVALID = 1089 + AWS_ERROR_PKCS11_CKR_ATTRIBUTE_VALUE_INVALID = 1090 + AWS_ERROR_PKCS11_CKR_ACTION_PROHIBITED = 1091 + AWS_ERROR_PKCS11_CKR_DATA_INVALID = 1092 + AWS_ERROR_PKCS11_CKR_DATA_LEN_RANGE = 1093 + AWS_ERROR_PKCS11_CKR_DEVICE_ERROR = 1094 + AWS_ERROR_PKCS11_CKR_DEVICE_MEMORY = 1095 + AWS_ERROR_PKCS11_CKR_DEVICE_REMOVED = 1096 + AWS_ERROR_PKCS11_CKR_ENCRYPTED_DATA_INVALID = 1097 + AWS_ERROR_PKCS11_CKR_ENCRYPTED_DATA_LEN_RANGE = 1098 + AWS_ERROR_PKCS11_CKR_FUNCTION_CANCELED = 1099 + AWS_ERROR_PKCS11_CKR_FUNCTION_NOT_PARALLEL = 1100 + AWS_ERROR_PKCS11_CKR_FUNCTION_NOT_SUPPORTED = 1101 + AWS_ERROR_PKCS11_CKR_KEY_HANDLE_INVALID = 1102 + AWS_ERROR_PKCS11_CKR_KEY_SIZE_RANGE = 1103 + AWS_ERROR_PKCS11_CKR_KEY_TYPE_INCONSISTENT = 1104 + AWS_ERROR_PKCS11_CKR_KEY_NOT_NEEDED = 1105 + AWS_ERROR_PKCS11_CKR_KEY_CHANGED = 1106 + AWS_ERROR_PKCS11_CKR_KEY_NEEDED = 1107 + AWS_ERROR_PKCS11_CKR_KEY_INDIGESTIBLE = 1108 + AWS_ERROR_PKCS11_CKR_KEY_FUNCTION_NOT_PERMITTED = 1109 + AWS_ERROR_PKCS11_CKR_KEY_NOT_WRAPPABLE = 1110 + AWS_ERROR_PKCS11_CKR_KEY_UNEXTRACTABLE = 1111 + AWS_ERROR_PKCS11_CKR_MECHANISM_INVALID = 1112 + AWS_ERROR_PKCS11_CKR_MECHANISM_PARAM_INVALID = 1113 + AWS_ERROR_PKCS11_CKR_OBJECT_HANDLE_INVALID = 1114 + AWS_ERROR_PKCS11_CKR_OPERATION_ACTIVE = 1115 + AWS_ERROR_PKCS11_CKR_OPERATION_NOT_INITIALIZED = 1116 + AWS_ERROR_PKCS11_CKR_PIN_INCORRECT = 1117 + AWS_ERROR_PKCS11_CKR_PIN_INVALID = 1118 + AWS_ERROR_PKCS11_CKR_PIN_LEN_RANGE = 1119 + AWS_ERROR_PKCS11_CKR_PIN_EXPIRED = 1120 + AWS_ERROR_PKCS11_CKR_PIN_LOCKED = 1121 + AWS_ERROR_PKCS11_CKR_SESSION_CLOSED = 1122 + AWS_ERROR_PKCS11_CKR_SESSION_COUNT = 1123 + AWS_ERROR_PKCS11_CKR_SESSION_HANDLE_INVALID = 1124 + AWS_ERROR_PKCS11_CKR_SESSION_PARALLEL_NOT_SUPPORTED = 1125 + AWS_ERROR_PKCS11_CKR_SESSION_READ_ONLY = 1126 + AWS_ERROR_PKCS11_CKR_SESSION_EXISTS = 1127 + AWS_ERROR_PKCS11_CKR_SESSION_READ_ONLY_EXISTS = 1128 + AWS_ERROR_PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS = 1129 + AWS_ERROR_PKCS11_CKR_SIGNATURE_INVALID = 1130 + AWS_ERROR_PKCS11_CKR_SIGNATURE_LEN_RANGE = 1131 + AWS_ERROR_PKCS11_CKR_TEMPLATE_INCOMPLETE = 1132 + AWS_ERROR_PKCS11_CKR_TEMPLATE_INCONSISTENT = 1133 + AWS_ERROR_PKCS11_CKR_TOKEN_NOT_PRESENT = 1134 + AWS_ERROR_PKCS11_CKR_TOKEN_NOT_RECOGNIZED = 1135 + AWS_ERROR_PKCS11_CKR_TOKEN_WRITE_PROTECTED = 1136 + AWS_ERROR_PKCS11_CKR_UNWRAPPING_KEY_HANDLE_INVALID = 1137 + AWS_ERROR_PKCS11_CKR_UNWRAPPING_KEY_SIZE_RANGE = 1138 + AWS_ERROR_PKCS11_CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT = 1139 + AWS_ERROR_PKCS11_CKR_USER_ALREADY_LOGGED_IN = 1140 + AWS_ERROR_PKCS11_CKR_USER_NOT_LOGGED_IN = 1141 + AWS_ERROR_PKCS11_CKR_USER_PIN_NOT_INITIALIZED = 1142 + AWS_ERROR_PKCS11_CKR_USER_TYPE_INVALID = 1143 + AWS_ERROR_PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN = 1144 + AWS_ERROR_PKCS11_CKR_USER_TOO_MANY_TYPES = 1145 + AWS_ERROR_PKCS11_CKR_WRAPPED_KEY_INVALID = 1146 + AWS_ERROR_PKCS11_CKR_WRAPPED_KEY_LEN_RANGE = 1147 + AWS_ERROR_PKCS11_CKR_WRAPPING_KEY_HANDLE_INVALID = 1148 + AWS_ERROR_PKCS11_CKR_WRAPPING_KEY_SIZE_RANGE = 1149 + AWS_ERROR_PKCS11_CKR_WRAPPING_KEY_TYPE_INCONSISTENT = 1150 + AWS_ERROR_PKCS11_CKR_RANDOM_SEED_NOT_SUPPORTED = 1151 + AWS_ERROR_PKCS11_CKR_RANDOM_NO_RNG = 1152 + AWS_ERROR_PKCS11_CKR_DOMAIN_PARAMS_INVALID = 1153 + AWS_ERROR_PKCS11_CKR_CURVE_NOT_SUPPORTED = 1154 + AWS_ERROR_PKCS11_CKR_BUFFER_TOO_SMALL = 1155 + AWS_ERROR_PKCS11_CKR_SAVED_STATE_INVALID = 1156 + AWS_ERROR_PKCS11_CKR_INFORMATION_SENSITIVE = 1157 + AWS_ERROR_PKCS11_CKR_STATE_UNSAVEABLE = 1158 + AWS_ERROR_PKCS11_CKR_CRYPTOKI_NOT_INITIALIZED = 1159 + AWS_ERROR_PKCS11_CKR_CRYPTOKI_ALREADY_INITIALIZED = 1160 + AWS_ERROR_PKCS11_CKR_MUTEX_BAD = 1161 + AWS_ERROR_PKCS11_CKR_MUTEX_NOT_LOCKED = 1162 + AWS_ERROR_PKCS11_CKR_NEW_PIN_MODE = 1163 + AWS_ERROR_PKCS11_CKR_NEXT_OTP = 1164 + AWS_ERROR_PKCS11_CKR_EXCEEDED_MAX_ITERATIONS = 1165 + AWS_ERROR_PKCS11_CKR_FIPS_SELF_TEST_FAILED = 1166 + AWS_ERROR_PKCS11_CKR_LIBRARY_LOAD_FAILED = 1167 + AWS_ERROR_PKCS11_CKR_PIN_TOO_WEAK = 1168 + AWS_ERROR_PKCS11_CKR_PUBLIC_KEY_INVALID = 1169 + AWS_ERROR_PKCS11_CKR_FUNCTION_REJECTED = 1170 + AWS_ERROR_IO_PINNED_EVENT_LOOP_MISMATCH = 1171 + AWS_IO_ERROR_END_RANGE = 2047 + AWS_IO_INVALID_FILE_HANDLE = 50 +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 35f99ea..c8046ba 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,30 @@ -using Test, Example +using Test, AwsIO -@test hello("Julia") == "Hello, Julia" -@test domath(2.0) ≈ 7.0 +@testset "AwsIO" begin + +println("testing non-tls") +sock = AwsIO.Socket("www.google.com", 80) +write(sock, "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") +sleep(0.1) +data = String(read(sock, 100)) +@test startswith(data, "HTTP/1.1 200 OK") +close(sock) + +println("testing tls") +sock = AwsIO.Socket("www.google.com", 443; tls=true, ssl_alpn_list="http/1.1") +write(sock, "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") +sleep(0.1) +data = String(read(sock, 100)) +@test startswith(data, "HTTP/1.1 200 OK") +close(sock) + +println("testing tls upgrade") +sock = AwsIO.Socket("www.google.com", 443; tls=false, debug=true) +AwsIO.tlsupgrade!(sock; ssl_alpn_list="http/1.1") +write(sock, "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") +sleep(0.1) +data = String(read(sock, 100)) +@test startswith(data, "HTTP/1.1 200 OK") +close(sock) + +end