| /** @file | |
| * | |
| * A brief file description | |
| * | |
| * @section license License | |
| * | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "proxy/http3/Http09App.h" | |
| #include "tscore/ink_resolver.h" | |
| #include "../../iocore/net/P_Net.h" | |
| #include "iocore/eventsystem/VConnection.h" | |
| #include "iocore/net/quic/QUICStreamManager.h" | |
| #include "iocore/net/quic/QUICDebugNames.h" | |
| #include "iocore/net/quic/QUICStreamVCAdapter.h" | |
| #include "proxy/http3/Http3Session.h" | |
| #include "proxy/http3/Http3Transaction.h" | |
| namespace | |
| { | |
| constexpr char debug_tag[] = "quic_simple_app"; | |
| constexpr char debug_tag_v[] = "v_quic_simple_app"; | |
| DbgCtl dbg_ctl{debug_tag}; | |
| DbgCtl dbg_ctl_v{debug_tag_v}; | |
| } // end anonymous namespace | |
| Http09App::Http09App(NetVConnection *client_vc, QUICConnection *qc, IpAllow::ACL &&session_acl, | |
| HttpSessionAcceptBase const *acceptor) | |
| : QUICApplication(qc) | |
| { | |
| this->_ssn = new Http09Session(client_vc); | |
| this->_ssn->acl = std::move(session_acl); | |
| this->_ssn->acceptor = acceptor; | |
| this->_ssn->new_connection(client_vc, nullptr, nullptr); | |
| this->_qc->stream_manager()->set_default_application(this); | |
| SET_HANDLER(&Http09App::main_event_handler); | |
| } | |
| Http09App::~Http09App() | |
| { | |
| delete this->_ssn; | |
| } | |
| void | |
| Http09App::on_stream_open(QUICStream &stream) | |
| { | |
| auto ret = this->_streams.emplace(stream.id(), stream); | |
| auto &info = ret.first->second; | |
| switch (stream.direction()) { | |
| case QUICStreamDirection::BIDIRECTIONAL: | |
| info.setup_read_vio(this); | |
| info.setup_write_vio(this); | |
| break; | |
| case QUICStreamDirection::SEND: | |
| info.setup_write_vio(this); | |
| break; | |
| case QUICStreamDirection::RECEIVE: | |
| info.setup_read_vio(this); | |
| break; | |
| default: | |
| ink_assert(false); | |
| break; | |
| } | |
| stream.set_io_adapter(&info.adapter); | |
| } | |
| void | |
| Http09App::on_stream_close(QUICStream & /* stream ATS_UNUSED */) | |
| { | |
| } | |
| int | |
| Http09App::main_event_handler(int event, Event *data) | |
| { | |
| Dbg(dbg_ctl_v, "[%s] %s (%d)", this->_qc->cids().data(), get_vc_event_name(event), event); | |
| VIO *vio = reinterpret_cast<VIO *>(data->cookie); | |
| QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server); | |
| if (adapter == nullptr) { | |
| Dbg(dbg_ctl, "[%s] Unknown Stream", this->_qc->cids().data()); | |
| return -1; | |
| } | |
| bool is_bidirectional = adapter->stream().is_bidirectional(); | |
| QUICStreamId stream_id = adapter->stream().id(); | |
| Http09Transaction *txn = static_cast<Http09Transaction *>(this->_ssn->get_transaction(stream_id)); | |
| switch (event) { | |
| case VC_EVENT_READ_READY: | |
| case VC_EVENT_READ_COMPLETE: | |
| if (!is_bidirectional) { | |
| // FIXME Ignore unidirectional streams for now | |
| break; | |
| } | |
| if (txn == nullptr) { | |
| if (auto ret = this->_streams.find(stream_id); ret != this->_streams.end()) { | |
| txn = new Http09Transaction(this->_ssn, ret->second); | |
| SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); | |
| txn->new_transaction(); | |
| } else { | |
| ink_assert(!"Stream info should exist"); | |
| } | |
| } else { | |
| SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); | |
| txn->handleEvent(event); | |
| } | |
| break; | |
| case VC_EVENT_WRITE_READY: | |
| case VC_EVENT_WRITE_COMPLETE: | |
| if (txn != nullptr) { | |
| SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); | |
| txn->handleEvent(event); | |
| } | |
| break; | |
| case VC_EVENT_EOS: | |
| case VC_EVENT_ERROR: | |
| case VC_EVENT_INACTIVITY_TIMEOUT: | |
| case VC_EVENT_ACTIVE_TIMEOUT: | |
| ink_assert(false); | |
| break; | |
| default: | |
| break; | |
| } | |
| return EVENT_CONT; | |
| } |