diff --git a/iocore/net/QUICPacketHandler_quiche.cc b/iocore/net/QUICPacketHandler_quiche.cc index d256445c1f0..bad50d651d2 100644 --- a/iocore/net/QUICPacketHandler_quiche.cc +++ b/iocore/net/QUICPacketHandler_quiche.cc @@ -32,6 +32,8 @@ #include "QUICMultiCertConfigLoader.h" #include +#include "swoc/BufferWriter.h" + static constexpr char debug_tag[] = "quic_sec"; static constexpr char v_debug_tag[] = "v_quic_sec"; @@ -285,14 +287,15 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) udp_packet->from.isIp4() ? sizeof(udp_packet->from.sin) : sizeof(udp_packet->from.sin6), &this->_quiche_config, ssl, true); if (params->get_qlog_file_base_name() != nullptr) { - char qlog_filepath[PATH_MAX]; + swoc::LocalBufferWriter w; const uint8_t *quic_trace_id; - size_t quic_trace_id_len = 0; + size_t quic_trace_id_len{0}; quiche_conn_trace_id(quiche_con, &quic_trace_id, &quic_trace_id_len); - snprintf(qlog_filepath, PATH_MAX, "%s-%.*s.sqlog", Layout::get()->relative(params->get_qlog_file_base_name()).c_str(), - static_cast(quic_trace_id_len), quic_trace_id); - if (auto success = quiche_conn_set_qlog_path(quiche_con, qlog_filepath, "Apache Traffic Server", "qlog"); !success) { - QUICDebug("quiche_conn_set_qlog_path failed to use %s", qlog_filepath); + + w.print("{}-{}.sqlog\0", Layout::get()->relative(params->get_qlog_file_base_name()), + std::string_view{reinterpret_cast(quic_trace_id), quic_trace_id_len}); + if (auto success = quiche_conn_set_qlog_path(quiche_con, w.data(), "Apache Traffic Server", "qlog"); !success) { + QUICDebug("quiche_conn_set_qlog_path failed to use %s", w.data()); } } diff --git a/tests/gold_tests/logging/qlog_quiche.test.py b/tests/gold_tests/logging/qlog_quiche.test.py new file mode 100644 index 00000000000..e6265f4e20e --- /dev/null +++ b/tests/gold_tests/logging/qlog_quiche.test.py @@ -0,0 +1,130 @@ +''' +''' +# 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. + +import os + +Test.Summary = ''' +Basic test for qlog using quiche library. +''' + +Test.SkipUnless( + Condition.HasATSFeature('TS_HAS_QUICHE') +) + +Generate_Qlog = True +No_Qlog = False + + +class quiche_qlog_Test: + replay_file = "replay/basic1.replay.yaml" + client_counter: int = 0 + ts_counter: int = 0 + server_counter: int = 0 + + def __init__(self, name: str): + """Initialize the test. + :param name: The name of the test. + """ + self._name = name + self._generate_qlog = False + + def with_qlogs(self): + self._generate_qlog = True + return self + + def without_qlogs(self): + self._generate_qlog = False + return self + + def _configure_server(self, tr: 'TestRun'): + """Configure the server. + + :param tr: The TestRun object to associate the server process with. + """ + server = tr.AddVerifierServerProcess(f"server_{quiche_qlog_Test.server_counter}", self.replay_file) + quiche_qlog_Test.server_counter += 1 + self._server = server + + def _configure_traffic_server(self, tr: 'TestRun'): + """Configure Traffic Server. + + :param tr: The TestRun object to associate the ts process with. + """ + ts = Test.MakeATSProcess(f"ts-{quiche_qlog_Test.ts_counter}", enable_quic=True, enable_tls=True) + self._ts = ts + quiche_qlog_Test.ts_counter += 1 + self._ts.addDefaultSSLFiles() + self._ts.Disk.records_config.update( + ''' + diags: + debug: + enabled: 1 + tags: vv_quic|v_quic + quic: + no_activity_timeout_in: 3000 + ''') + if self._generate_qlog: + self._ts.Disk.records_config.update( + ''' + quic: + qlog: + file_base: log/test_qlog # we expect to have log/test_qlog-.sqlog + ''' + ) + self._ts.Disk.ssl_multicert_config.AddLine( + f'dest_ip=* ssl_cert_name={ts.Variables.SSLDir}/server.pem ssl_key_name={ts.Variables.SSLDir}/server.key' + ) + + self._ts.Disk.remap_config.AddLine(f'map / http://127.0.0.1:{self._server.Variables.http_port}') + + def test(self): + """Run the test.""" + tr = Test.AddTestRun(self._name) + self._configure_server(tr) + self._configure_traffic_server(tr) + + tr.Processes.Default.StartBefore(self._server) + tr.Processes.Default.StartBefore(self._ts) + tr.AddVerifierClientProcess( + f"client-{quiche_qlog_Test.client_counter}", + self.replay_file, + http3_ports=[ + self._ts.Variables.ssl_port]) + quiche_qlog_Test.client_counter += 1 + tr.Processes.Default.ReturnCode = 0 + + # If requested we will copy the file to a known name as the runtime name is not know + # by the test. So we will rename them all and grab the first one for validation. + test_run = Test.AddTestRun(f"{self._name} : check qlog files") + qlog_base_name = "test_qlog" + rename_script = os.path.join(Test.TestDirectory, 'rename_qlog.sh') + test_run.Processes.Default.Command = f'sleep 5; bash {rename_script} {self._ts.Variables.LOGDIR} {qlog_base_name}' + test_run.Processes.Default.ReturnCode = 0 if self._generate_qlog else 2 # exit 2 is what we want if no qlog was generated. + + # Basic valdation + if self._generate_qlog: + tr = Test.AddTestRun("Check qlog content") + file = os.path.join(self._ts.Variables.LOGDIR, "1.sqlog") + f = tr.Disk.File(file) + tr.Processes.Default.Command = "echo 0" + tr.Processes.Default.ReturnCode = 0 + f.Content = Testers.IncludesExpression('"title":"Apache Traffic Server"', 'Should include this basic text') + + +quiche_qlog_Test("Generate qlog test").with_qlogs().test() +quiche_qlog_Test("Do not generate qlog").without_qlogs().test() diff --git a/tests/gold_tests/logging/rename_qlog.sh b/tests/gold_tests/logging/rename_qlog.sh new file mode 100755 index 00000000000..4fcb8b2738c --- /dev/null +++ b/tests/gold_tests/logging/rename_qlog.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# 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. + +# Rename qlog files base on a folder and a file name basename + +x=0 + +for i in `find $1 -name $2*`; do + ((x+=1)) + mv -- "$i" "$1/$x.sqlog" + echo "renamed $i with $1/$x.sqlog" +done + +if [ $x -gt 0 ]; then + echo "exit with 0" + exit 0 +else + echo "exit with 2" + exit 2 +fi diff --git a/tests/gold_tests/logging/replay/basic1.replay.yaml b/tests/gold_tests/logging/replay/basic1.replay.yaml new file mode 100644 index 00000000000..4de3719c2fa --- /dev/null +++ b/tests/gold_tests/logging/replay/basic1.replay.yaml @@ -0,0 +1,50 @@ +# 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. + +meta: + version: "1.0" + +sessions: +- protocol: + - name: http + version: 3 + - name: tls + sni: test_sni + transactions: + + - client-request: + version: "3" + headers: + fields: + - [ Content-Length, 0 ] + - [:method, GET] + - [:scheme, https] + - [:authority, example.com] + - [:path, /path/test1] + - [ uuid, generate_qlog1 ] + server-response: + status: 200 + reason: "OK" + headers: + fields: + - [ Content-Length, 20 ] + + proxy-response: + status: 200 + + + +