1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/quic/quic_chromium_client_session.h"
- #include <memory>
- #include <set>
- #include <utility>
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "base/feature_list.h"
- #include "base/location.h"
- #include "base/memory/ptr_util.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/metrics/sparse_histogram.h"
- #include "base/no_destructor.h"
- #include "base/observer_list.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/stringprintf.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/tick_clock.h"
- #include "base/trace_event/memory_usage_estimator.h"
- #include "base/values.h"
- #include "net/base/features.h"
- #include "net/base/io_buffer.h"
- #include "net/base/net_errors.h"
- #include "net/base/network_activity_monitor.h"
- #include "net/base/network_isolation_key.h"
- #include "net/base/privacy_mode.h"
- #include "net/base/url_util.h"
- #include "net/cert/signed_certificate_timestamp_and_status.h"
- #include "net/http/transport_security_state.h"
- #include "net/log/net_log_event_type.h"
- #include "net/log/net_log_source_type.h"
- #include "net/quic/address_utils.h"
- #include "net/quic/crypto/proof_verifier_chromium.h"
- #include "net/quic/quic_chromium_connection_helper.h"
- #include "net/quic/quic_chromium_packet_writer.h"
- #include "net/quic/quic_crypto_client_stream_factory.h"
- #include "net/quic/quic_server_info.h"
- #include "net/quic/quic_stream_factory.h"
- #include "net/socket/datagram_client_socket.h"
- #include "net/spdy/spdy_http_utils.h"
- #include "net/spdy/spdy_log_util.h"
- #include "net/spdy/spdy_session.h"
- #include "net/ssl/ssl_connection_status_flags.h"
- #include "net/ssl/ssl_info.h"
- #include "net/third_party/quiche/src/quiche/quic/core/http/quic_client_promised_info.h"
- #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_server_push_utils.h"
- #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
- #include "net/third_party/quiche/src/quiche/quic/platform/api/quic_flags.h"
- #include "net/traffic_annotation/network_traffic_annotation.h"
- #include "third_party/boringssl/src/include/openssl/ssl.h"
- #include "url/origin.h"
- #include "url/scheme_host_port.h"
- namespace net {
- namespace {
- // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
- const size_t kAdditionalOverheadForIPv6 = 20;
- // Maximum number of Readers that are created for any session due to
- // connection migration. A new Reader is created every time this endpoint's
- // IP address changes.
- const size_t kMaxReadersPerQuicSession = 5;
- // Time to wait (in seconds) when no networks are available and
- // migrating sessions need to wait for a new network to connect.
- const size_t kWaitTimeForNewNetworkSecs = 10;
- const size_t kMinRetryTimeForDefaultNetworkSecs = 1;
- // These values are persisted to logs. Entries should not be renumbered,
- // and numeric values should never be reused.
- enum class AcceptChEntries {
- kNoEntries = 0,
- kOnlyValidEntries = 1,
- kOnlyInvalidEntries = 2,
- kBothValidAndInvalidEntries = 3,
- kMaxValue = kBothValidAndInvalidEntries,
- };
- void LogAcceptChFrameReceivedHistogram(bool has_valid_entry,
- bool has_invalid_entry) {
- AcceptChEntries value;
- if (has_valid_entry) {
- if (has_invalid_entry) {
- value = AcceptChEntries::kBothValidAndInvalidEntries;
- } else {
- value = AcceptChEntries::kOnlyValidEntries;
- }
- } else {
- if (has_invalid_entry) {
- value = AcceptChEntries::kOnlyInvalidEntries;
- } else {
- value = AcceptChEntries::kNoEntries;
- }
- }
- base::UmaHistogramEnumeration("Net.QuicSession.AcceptChFrameReceivedViaAlps",
- value);
- }
- void LogAcceptChForOriginHistogram(bool value) {
- base::UmaHistogramBoolean("Net.QuicSession.AcceptChForOrigin", value);
- }
- void RecordConnectionCloseErrorCodeImpl(const std::string& histogram,
- uint64_t error,
- bool is_google_host,
- bool handshake_confirmed) {
- base::UmaHistogramSparse(histogram, error);
- if (handshake_confirmed) {
- base::UmaHistogramSparse(histogram + ".HandshakeConfirmed", error);
- } else {
- base::UmaHistogramSparse(histogram + ".HandshakeNotConfirmed", error);
- }
- if (is_google_host) {
- base::UmaHistogramSparse(histogram + "Google", error);
- if (handshake_confirmed) {
- base::UmaHistogramSparse(histogram + "Google.HandshakeConfirmed", error);
- } else {
- base::UmaHistogramSparse(histogram + "Google.HandshakeNotConfirmed",
- error);
- }
- }
- }
- void LogMigrateToSocketStatus(bool success) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.MigrateToSocketSuccess", success);
- }
- void RecordConnectionCloseErrorCode(const quic::QuicConnectionCloseFrame& frame,
- quic::ConnectionCloseSource source,
- const std::string& hostname,
- bool handshake_confirmed) {
- bool is_google_host = IsGoogleHost(hostname);
- std::string histogram = "Net.QuicSession.ConnectionCloseErrorCode";
- if (source == quic::ConnectionCloseSource::FROM_SELF) {
- // When sending a CONNECTION_CLOSE frame, it is sufficient to record
- // |quic_error_code|.
- histogram += "Client";
- RecordConnectionCloseErrorCodeImpl(histogram, frame.quic_error_code,
- is_google_host, handshake_confirmed);
- return;
- }
- histogram += "Server";
- // Record |quic_error_code|. Note that when using IETF QUIC, this is
- // extracted from the CONNECTION_CLOSE frame reason phrase, and might be
- // QUIC_IETF_GQUIC_ERROR_MISSING.
- RecordConnectionCloseErrorCodeImpl(histogram, frame.quic_error_code,
- is_google_host, handshake_confirmed);
- // For IETF QUIC frames, also record the error code received on the wire.
- if (frame.close_type == quic::IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
- histogram += "IetfTransport";
- RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
- is_google_host, handshake_confirmed);
- if (frame.quic_error_code == quic::QUIC_IETF_GQUIC_ERROR_MISSING) {
- histogram += "GQuicErrorMissing";
- RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
- is_google_host, handshake_confirmed);
- }
- } else if (frame.close_type == quic::IETF_QUIC_APPLICATION_CONNECTION_CLOSE) {
- histogram += "IetfApplication";
- RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
- is_google_host, handshake_confirmed);
- if (frame.quic_error_code == quic::QUIC_IETF_GQUIC_ERROR_MISSING) {
- histogram += "GQuicErrorMissing";
- RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
- is_google_host, handshake_confirmed);
- }
- }
- }
- base::Value NetLogQuicMigrationFailureParams(
- quic::QuicConnectionId connection_id,
- base::StringPiece reason) {
- base::Value::Dict dict;
- dict.Set("connection_id", connection_id.ToString());
- dict.Set("reason", reason);
- return base::Value(std::move(dict));
- }
- base::Value NetLogQuicMigrationSuccessParams(
- quic::QuicConnectionId connection_id) {
- base::Value::Dict dict;
- dict.Set("connection_id", connection_id.ToString());
- return base::Value(std::move(dict));
- }
- base::Value NetLogProbingResultParams(
- handles::NetworkHandle network,
- const quic::QuicSocketAddress* peer_address,
- bool is_success) {
- base::Value::Dict dict;
- dict.Set("network", base::NumberToString(network));
- dict.Set("peer address", peer_address->ToString());
- dict.Set("is_success", is_success);
- return base::Value(std::move(dict));
- }
- base::Value NetLogAcceptChFrameReceivedParams(
- spdy::AcceptChOriginValuePair entry) {
- base::Value::Dict dict;
- dict.Set("origin", entry.origin);
- dict.Set("accept_ch", entry.value);
- return base::Value(std::move(dict));
- }
- // Histogram for recording the different reasons that a QUIC session is unable
- // to complete the handshake.
- enum HandshakeFailureReason {
- HANDSHAKE_FAILURE_UNKNOWN = 0,
- HANDSHAKE_FAILURE_BLACK_HOLE = 1,
- HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
- NUM_HANDSHAKE_FAILURE_REASONS = 3,
- };
- void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason", reason,
- NUM_HANDSHAKE_FAILURE_REASONS);
- }
- // Note: these values must be kept in sync with the corresponding values in:
- // tools/metrics/histograms/histograms.xml
- enum HandshakeState {
- STATE_STARTED = 0,
- STATE_ENCRYPTION_ESTABLISHED = 1,
- STATE_HANDSHAKE_CONFIRMED = 2,
- STATE_FAILED = 3,
- NUM_HANDSHAKE_STATES = 4
- };
- enum class ZeroRttState {
- kAttemptedAndSucceeded = 0,
- kAttemptedAndRejected = 1,
- kNotAttempted = 2,
- kMaxValue = kNotAttempted,
- };
- void RecordHandshakeState(HandshakeState state) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
- NUM_HANDSHAKE_STATES);
- }
- std::string MigrationCauseToString(MigrationCause cause) {
- switch (cause) {
- case UNKNOWN_CAUSE:
- return "Unknown";
- case ON_NETWORK_CONNECTED:
- return "OnNetworkConnected";
- case ON_NETWORK_DISCONNECTED:
- return "OnNetworkDisconnected";
- case ON_WRITE_ERROR:
- return "OnWriteError";
- case ON_NETWORK_MADE_DEFAULT:
- return "OnNetworkMadeDefault";
- case ON_MIGRATE_BACK_TO_DEFAULT_NETWORK:
- return "OnMigrateBackToDefaultNetwork";
- case CHANGE_NETWORK_ON_PATH_DEGRADING:
- return "OnPathDegrading";
- case CHANGE_PORT_ON_PATH_DEGRADING:
- return "ChangePortOnPathDegrading";
- case NEW_NETWORK_CONNECTED_POST_PATH_DEGRADING:
- return "NewNetworkConnectedPostPathDegrading";
- default:
- QUICHE_NOTREACHED();
- break;
- }
- return "InvalidCause";
- }
- base::Value NetLogQuicClientSessionParams(
- const QuicSessionKey* session_key,
- const quic::QuicConnectionId& connection_id,
- const quic::QuicConnectionId& client_connection_id,
- const quic::ParsedQuicVersionVector& supported_versions,
- int cert_verify_flags,
- bool require_confirmation) {
- base::Value::Dict dict;
- dict.Set("host", session_key->server_id().host());
- dict.Set("port", session_key->server_id().port());
- dict.Set("privacy_mode",
- PrivacyModeToDebugString(session_key->privacy_mode()));
- dict.Set("network_isolation_key",
- session_key->network_isolation_key().ToDebugString());
- dict.Set("require_confirmation", require_confirmation);
- dict.Set("cert_verify_flags", cert_verify_flags);
- dict.Set("connection_id", connection_id.ToString());
- if (!client_connection_id.IsEmpty()) {
- dict.Set("client_connection_id", client_connection_id.ToString());
- }
- dict.Set("versions", ParsedQuicVersionVectorToString(supported_versions));
- return base::Value(std::move(dict));
- }
- base::Value NetLogQuicPushPromiseReceivedParams(
- const spdy::Http2HeaderBlock* headers,
- spdy::SpdyStreamId stream_id,
- spdy::SpdyStreamId promised_stream_id,
- NetLogCaptureMode capture_mode) {
- base::Value::Dict dict;
- dict.Set("headers", ElideHttp2HeaderBlockForNetLog(*headers, capture_mode));
- dict.Set("id", static_cast<int>(stream_id));
- dict.Set("promised_stream_id", static_cast<int>(promised_stream_id));
- return base::Value(std::move(dict));
- }
- // TODO(fayang): Remove this when necessary data is collected.
- void LogProbeResultToHistogram(MigrationCause cause, bool success) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PathValidationSuccess", success);
- const std::string histogram_name =
- "Net.QuicSession.PathValidationSuccess." + MigrationCauseToString(cause);
- STATIC_HISTOGRAM_POINTER_GROUP(
- histogram_name, cause, MIGRATION_CAUSE_MAX, AddBoolean(success),
- base::BooleanHistogram::FactoryGet(
- histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag));
- }
- class QuicServerPushHelper : public ServerPushDelegate::ServerPushHelper {
- public:
- explicit QuicServerPushHelper(
- base::WeakPtr<QuicChromiumClientSession> session,
- const GURL& url)
- : session_(session), request_url_(url) {}
- void Cancel() override {
- if (session_) {
- session_->CancelPush(request_url_);
- }
- }
- const GURL& GetURL() const override { return request_url_; }
- NetworkIsolationKey GetNetworkIsolationKey() const override {
- if (session_) {
- return session_->quic_session_key().network_isolation_key();
- }
- return NetworkIsolationKey();
- }
- private:
- base::WeakPtr<QuicChromiumClientSession> session_;
- const GURL request_url_;
- };
- } // namespace
- QuicChromiumClientSession::Handle::Handle(
- const base::WeakPtr<QuicChromiumClientSession>& session,
- url::SchemeHostPort destination)
- : MultiplexedSessionHandle(session),
- session_(session),
- destination_(std::move(destination)),
- net_log_(session_->net_log()),
- was_handshake_confirmed_(session->OneRttKeysAvailable()),
- server_id_(session_->server_id()),
- quic_version_(session->connection()->version()) {
- DCHECK(session_);
- session_->AddHandle(this);
- }
- QuicChromiumClientSession::Handle::~Handle() {
- if (push_handle_) {
- auto* push_handle = push_handle_;
- push_handle_ = nullptr;
- push_handle->Cancel();
- }
- if (session_)
- session_->RemoveHandle(this);
- }
- void QuicChromiumClientSession::Handle::OnCryptoHandshakeConfirmed() {
- was_handshake_confirmed_ = true;
- }
- void QuicChromiumClientSession::Handle::OnSessionClosed(
- quic::ParsedQuicVersion quic_version,
- int net_error,
- quic::QuicErrorCode quic_error,
- bool port_migration_detected,
- bool quic_connection_migration_attempted,
- bool quic_connection_migration_successful,
- LoadTimingInfo::ConnectTiming connect_timing,
- bool was_ever_used) {
- session_ = nullptr;
- port_migration_detected_ = port_migration_detected;
- quic_connection_migration_attempted_ = quic_connection_migration_attempted;
- quic_connection_migration_successful_ = quic_connection_migration_successful;
- net_error_ = net_error;
- quic_error_ = quic_error;
- quic_version_ = quic_version;
- connect_timing_ = connect_timing;
- push_handle_ = nullptr;
- was_ever_used_ = was_ever_used;
- }
- bool QuicChromiumClientSession::Handle::IsConnected() const {
- return session_ != nullptr;
- }
- bool QuicChromiumClientSession::Handle::OneRttKeysAvailable() const {
- return was_handshake_confirmed_;
- }
- const LoadTimingInfo::ConnectTiming&
- QuicChromiumClientSession::Handle::GetConnectTiming() {
- if (!session_)
- return connect_timing_;
- return session_->GetConnectTiming();
- }
- void QuicChromiumClientSession::Handle::PopulateNetErrorDetails(
- NetErrorDetails* details) const {
- if (session_) {
- session_->PopulateNetErrorDetails(details);
- } else {
- details->quic_port_migration_detected = port_migration_detected_;
- details->quic_connection_error = quic_error_;
- details->quic_connection_migration_attempted =
- quic_connection_migration_attempted_;
- details->quic_connection_migration_successful =
- quic_connection_migration_successful_;
- }
- }
- quic::ParsedQuicVersion QuicChromiumClientSession::Handle::GetQuicVersion()
- const {
- if (!session_)
- return quic_version_;
- return session_->GetQuicVersion();
- }
- void QuicChromiumClientSession::Handle::ResetPromised(
- quic::QuicStreamId id,
- quic::QuicRstStreamErrorCode error_code) {
- if (session_)
- session_->ResetPromised(id, error_code);
- }
- std::unique_ptr<quic::QuicConnection::ScopedPacketFlusher>
- QuicChromiumClientSession::Handle::CreatePacketBundler() {
- if (!session_)
- return nullptr;
- return std::make_unique<quic::QuicConnection::ScopedPacketFlusher>(
- session_->connection());
- }
- bool QuicChromiumClientSession::Handle::SharesSameSession(
- const Handle& other) const {
- return session_.get() == other.session_.get();
- }
- int QuicChromiumClientSession::Handle::RendezvousWithPromised(
- const spdy::Http2HeaderBlock& headers,
- CompletionOnceCallback callback) {
- if (!session_)
- return ERR_CONNECTION_CLOSED;
- quic::QuicAsyncStatus push_status =
- session_->push_promise_index()->Try(headers, this, &push_handle_);
- switch (push_status) {
- case quic::QUIC_FAILURE:
- return ERR_FAILED;
- case quic::QUIC_SUCCESS:
- return OK;
- case quic::QUIC_PENDING:
- push_callback_ = std::move(callback);
- return ERR_IO_PENDING;
- }
- NOTREACHED();
- return ERR_UNEXPECTED;
- }
- int QuicChromiumClientSession::Handle::RequestStream(
- bool requires_confirmation,
- CompletionOnceCallback callback,
- const NetworkTrafficAnnotationTag& traffic_annotation) {
- DCHECK(!stream_request_);
- if (!session_)
- return ERR_CONNECTION_CLOSED;
- requires_confirmation |= session_->gquic_zero_rtt_disabled();
- // std::make_unique does not work because the StreamRequest constructor
- // is private.
- stream_request_ = base::WrapUnique(
- new StreamRequest(this, requires_confirmation, traffic_annotation));
- return stream_request_->StartRequest(std::move(callback));
- }
- std::unique_ptr<QuicChromiumClientStream::Handle>
- QuicChromiumClientSession::Handle::ReleaseStream() {
- DCHECK(stream_request_);
- auto handle = stream_request_->ReleaseStream();
- stream_request_.reset();
- return handle;
- }
- std::unique_ptr<QuicChromiumClientStream::Handle>
- QuicChromiumClientSession::Handle::ReleasePromisedStream() {
- DCHECK(push_stream_);
- return std::move(push_stream_);
- }
- int QuicChromiumClientSession::Handle::WaitForHandshakeConfirmation(
- CompletionOnceCallback callback) {
- if (!session_)
- return ERR_CONNECTION_CLOSED;
- return session_->WaitForHandshakeConfirmation(std::move(callback));
- }
- void QuicChromiumClientSession::Handle::CancelRequest(StreamRequest* request) {
- if (session_)
- session_->CancelRequest(request);
- }
- int QuicChromiumClientSession::Handle::TryCreateStream(StreamRequest* request) {
- if (!session_)
- return ERR_CONNECTION_CLOSED;
- return session_->TryCreateStream(request);
- }
- quic::QuicClientPushPromiseIndex*
- QuicChromiumClientSession::Handle::GetPushPromiseIndex() {
- if (!session_)
- return push_promise_index_;
- return session_->push_promise_index();
- }
- int QuicChromiumClientSession::Handle::GetPeerAddress(
- IPEndPoint* address) const {
- if (!session_)
- return ERR_CONNECTION_CLOSED;
- *address = ToIPEndPoint(session_->peer_address());
- return OK;
- }
- int QuicChromiumClientSession::Handle::GetSelfAddress(
- IPEndPoint* address) const {
- if (!session_)
- return ERR_CONNECTION_CLOSED;
- *address = ToIPEndPoint(session_->self_address());
- return OK;
- }
- bool QuicChromiumClientSession::Handle::WasEverUsed() const {
- if (!session_)
- return was_ever_used_;
- return session_->WasConnectionEverUsed();
- }
- const std::set<std::string>&
- QuicChromiumClientSession::Handle::GetDnsAliasesForSessionKey(
- const QuicSessionKey& key) const {
- static const base::NoDestructor<std::set<std::string>> emptyset_result;
- return session_ ? session_->GetDnsAliasesForSessionKey(key)
- : *emptyset_result;
- }
- bool QuicChromiumClientSession::Handle::CheckVary(
- const spdy::Http2HeaderBlock& client_request,
- const spdy::Http2HeaderBlock& promise_request,
- const spdy::Http2HeaderBlock& promise_response) {
- HttpRequestInfo promise_request_info;
- ConvertHeaderBlockToHttpRequestHeaders(promise_request,
- &promise_request_info.extra_headers);
- HttpRequestInfo client_request_info;
- ConvertHeaderBlockToHttpRequestHeaders(client_request,
- &client_request_info.extra_headers);
- HttpResponseInfo promise_response_info;
- if (SpdyHeadersToHttpResponse(promise_response, &promise_response_info) !=
- OK) {
- DLOG(WARNING) << "Invalid headers";
- return false;
- }
- HttpVaryData vary_data;
- if (!vary_data.Init(promise_request_info,
- *promise_response_info.headers.get())) {
- // Promise didn't contain valid vary info, so URL match was sufficient.
- return true;
- }
- // Now compare the client request for matching.
- return vary_data.MatchesRequest(client_request_info,
- *promise_response_info.headers.get());
- }
- void QuicChromiumClientSession::Handle::OnRendezvousResult(
- quic::QuicSpdyStream* stream) {
- DCHECK(!push_stream_);
- int rv = ERR_FAILED;
- if (stream) {
- rv = OK;
- push_stream_ =
- static_cast<QuicChromiumClientStream*>(stream)->CreateHandle();
- }
- if (push_callback_) {
- DCHECK(push_handle_);
- push_handle_ = nullptr;
- std::move(push_callback_).Run(rv);
- }
- }
- QuicChromiumClientSession::StreamRequest::StreamRequest(
- QuicChromiumClientSession::Handle* session,
- bool requires_confirmation,
- const NetworkTrafficAnnotationTag& traffic_annotation)
- : session_(session),
- requires_confirmation_(requires_confirmation),
- traffic_annotation_(traffic_annotation) {}
- QuicChromiumClientSession::StreamRequest::~StreamRequest() {
- if (stream_)
- stream_->Reset(quic::QUIC_STREAM_CANCELLED);
- if (session_)
- session_->CancelRequest(this);
- }
- int QuicChromiumClientSession::StreamRequest::StartRequest(
- CompletionOnceCallback callback) {
- if (!session_->IsConnected())
- return ERR_CONNECTION_CLOSED;
- next_state_ = STATE_WAIT_FOR_CONFIRMATION;
- int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
- callback_ = std::move(callback);
- return rv;
- }
- std::unique_ptr<QuicChromiumClientStream::Handle>
- QuicChromiumClientSession::StreamRequest::ReleaseStream() {
- DCHECK(stream_);
- return std::move(stream_);
- }
- void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
- std::unique_ptr<QuicChromiumClientStream::Handle> stream) {
- DCHECK_EQ(STATE_REQUEST_STREAM_COMPLETE, next_state_);
- stream_ = std::move(stream);
- // This method is called even when the request completes synchronously.
- if (callback_)
- DoCallback(OK);
- }
- void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure(
- int rv) {
- DCHECK_EQ(STATE_REQUEST_STREAM_COMPLETE, next_state_);
- // This method is called even when the request completes synchronously.
- if (callback_) {
- // Avoid re-entrancy if the callback calls into the session.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&QuicChromiumClientSession::StreamRequest::DoCallback,
- weak_factory_.GetWeakPtr(), rv));
- }
- }
- void QuicChromiumClientSession::StreamRequest::OnIOComplete(int rv) {
- rv = DoLoop(rv);
- if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- DoCallback(rv);
- }
- }
- void QuicChromiumClientSession::StreamRequest::DoCallback(int rv) {
- CHECK_NE(rv, ERR_IO_PENDING);
- CHECK(!callback_.is_null());
- // The client callback can do anything, including destroying this class,
- // so any pending callback must be issued after everything else is done.
- std::move(callback_).Run(rv);
- }
- int QuicChromiumClientSession::StreamRequest::DoLoop(int rv) {
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_WAIT_FOR_CONFIRMATION:
- CHECK_EQ(OK, rv);
- rv = DoWaitForConfirmation();
- break;
- case STATE_WAIT_FOR_CONFIRMATION_COMPLETE:
- rv = DoWaitForConfirmationComplete(rv);
- break;
- case STATE_REQUEST_STREAM:
- CHECK_EQ(OK, rv);
- rv = DoRequestStream();
- break;
- case STATE_REQUEST_STREAM_COMPLETE:
- rv = DoRequestStreamComplete(rv);
- break;
- default:
- NOTREACHED() << "next_state_: " << next_state_;
- break;
- }
- } while (next_state_ != STATE_NONE && next_state_ && rv != ERR_IO_PENDING);
- return rv;
- }
- int QuicChromiumClientSession::StreamRequest::DoWaitForConfirmation() {
- next_state_ = STATE_WAIT_FOR_CONFIRMATION_COMPLETE;
- if (requires_confirmation_) {
- return session_->WaitForHandshakeConfirmation(
- base::BindOnce(&QuicChromiumClientSession::StreamRequest::OnIOComplete,
- weak_factory_.GetWeakPtr()));
- }
- return OK;
- }
- int QuicChromiumClientSession::StreamRequest::DoWaitForConfirmationComplete(
- int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
- next_state_ = STATE_REQUEST_STREAM;
- return OK;
- }
- int QuicChromiumClientSession::StreamRequest::DoRequestStream() {
- next_state_ = STATE_REQUEST_STREAM_COMPLETE;
- return session_->TryCreateStream(this);
- }
- int QuicChromiumClientSession::StreamRequest::DoRequestStreamComplete(int rv) {
- DCHECK(rv == OK || !stream_);
- return rv;
- }
- QuicChromiumClientSession::QuicChromiumPathValidationContext::
- QuicChromiumPathValidationContext(
- const quic::QuicSocketAddress& self_address,
- const quic::QuicSocketAddress& peer_address,
- handles::NetworkHandle network,
- std::unique_ptr<DatagramClientSocket> socket,
- std::unique_ptr<QuicChromiumPacketWriter> writer,
- std::unique_ptr<QuicChromiumPacketReader> reader)
- : QuicPathValidationContext(self_address, peer_address),
- network_handle_(network),
- socket_(std::move(socket)),
- writer_(std::move(writer)),
- reader_(std::move(reader)) {}
- QuicChromiumClientSession::QuicChromiumPathValidationContext::
- ~QuicChromiumPathValidationContext() = default;
- handles::NetworkHandle
- QuicChromiumClientSession::QuicChromiumPathValidationContext::network() {
- return network_handle_;
- }
- quic::QuicPacketWriter*
- QuicChromiumClientSession::QuicChromiumPathValidationContext::WriterToUse() {
- return writer_.get();
- }
- std::unique_ptr<QuicChromiumPacketWriter>
- QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseWriter() {
- return std::move(writer_);
- }
- std::unique_ptr<DatagramClientSocket>
- QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseSocket() {
- return std::move(socket_);
- }
- std::unique_ptr<QuicChromiumPacketReader>
- QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseReader() {
- return std::move(reader_);
- }
- QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
- ConnectionMigrationValidationResultDelegate(
- QuicChromiumClientSession* session)
- : session_(session) {}
- void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
- OnPathValidationSuccess(
- std::unique_ptr<quic::QuicPathValidationContext> context,
- quic::QuicTime start_time) {
- auto* chrome_context =
- static_cast<QuicChromiumPathValidationContext*>(context.get());
- session_->OnConnectionMigrationProbeSucceeded(
- chrome_context->network(), chrome_context->peer_address(),
- chrome_context->self_address(), chrome_context->ReleaseSocket(),
- chrome_context->ReleaseWriter(), chrome_context->ReleaseReader());
- }
- void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
- OnPathValidationFailure(
- std::unique_ptr<quic::QuicPathValidationContext> context) {
- session_->connection()->OnPathValidationFailureAtClient();
- // Note that socket, packet writer, and packet reader in |context| will be
- // discarded.
- auto* chrome_context =
- static_cast<QuicChromiumPathValidationContext*>(context.get());
- session_->OnProbeFailed(chrome_context->network(),
- chrome_context->peer_address());
- }
- QuicChromiumClientSession::PortMigrationValidationResultDelegate::
- PortMigrationValidationResultDelegate(QuicChromiumClientSession* session)
- : session_(session) {}
- void QuicChromiumClientSession::PortMigrationValidationResultDelegate::
- OnPathValidationSuccess(
- std::unique_ptr<quic::QuicPathValidationContext> context,
- quic::QuicTime start_time) {
- auto* chrome_context =
- static_cast<QuicChromiumPathValidationContext*>(context.get());
- session_->OnPortMigrationProbeSucceeded(
- chrome_context->network(), chrome_context->peer_address(),
- chrome_context->self_address(), chrome_context->ReleaseSocket(),
- chrome_context->ReleaseWriter(), chrome_context->ReleaseReader());
- }
- void QuicChromiumClientSession::PortMigrationValidationResultDelegate::
- OnPathValidationFailure(
- std::unique_ptr<quic::QuicPathValidationContext> context) {
- session_->connection()->OnPathValidationFailureAtClient();
- // Note that socket, packet writer, and packet reader in |context| will be
- // discarded.
- auto* chrome_context =
- static_cast<QuicChromiumPathValidationContext*>(context.get());
- session_->OnProbeFailed(chrome_context->network(),
- chrome_context->peer_address());
- }
- QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- QuicChromiumPathValidationWriterDelegate(
- QuicChromiumClientSession* session,
- base::SequencedTaskRunner* task_runner)
- : session_(session),
- task_runner_(task_runner),
- network_(handles::kInvalidNetworkHandle) {}
- QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- ~QuicChromiumPathValidationWriterDelegate() = default;
- int QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- HandleWriteError(
- int error_code,
- scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> last_packet) {
- // Write error on the probing network is not recoverable.
- DVLOG(1) << "Probing packet encounters write error " << error_code;
- // Post a task to notify |session_| that this probe failed and cancel
- // undergoing probing, which will delete the packet writer.
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- &QuicChromiumPathValidationWriterDelegate::NotifySessionProbeFailed,
- weak_factory_.GetWeakPtr(), network_));
- return error_code;
- }
- void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- OnWriteError(int error_code) {
- NotifySessionProbeFailed(network_);
- }
- void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- OnWriteUnblocked() {}
- void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- NotifySessionProbeFailed(handles::NetworkHandle network) {
- session_->OnProbeFailed(network, peer_address_);
- }
- void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- set_peer_address(const quic::QuicSocketAddress& peer_address) {
- peer_address_ = peer_address;
- }
- void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
- set_network(handles::NetworkHandle network) {
- network_ = network;
- }
- QuicChromiumClientSession::QuicChromiumClientSession(
- quic::QuicConnection* connection,
- std::unique_ptr<DatagramClientSocket> socket,
- QuicStreamFactory* stream_factory,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory,
- const quic::QuicClock* clock,
- TransportSecurityState* transport_security_state,
- SSLConfigService* ssl_config_service,
- std::unique_ptr<QuicServerInfo> server_info,
- const QuicSessionKey& session_key,
- bool require_confirmation,
- bool migrate_session_early_v2,
- bool migrate_sessions_on_network_change_v2,
- handles::NetworkHandle default_network,
- quic::QuicTime::Delta retransmittable_on_wire_timeout,
- bool migrate_idle_session,
- bool allow_port_migration,
- base::TimeDelta idle_migration_period,
- base::TimeDelta max_time_on_non_default_network,
- int max_migrations_to_non_default_network_on_write_error,
- int max_migrations_to_non_default_network_on_path_degrading,
- int yield_after_packets,
- quic::QuicTime::Delta yield_after_duration,
- bool headers_include_h2_stream_dependency,
- int cert_verify_flags,
- const quic::QuicConfig& config,
- std::unique_ptr<QuicCryptoClientConfigHandle> crypto_config,
- const char* const connection_description,
- base::TimeTicks dns_resolution_start_time,
- base::TimeTicks dns_resolution_end_time,
- std::unique_ptr<quic::QuicClientPushPromiseIndex> push_promise_index,
- ServerPushDelegate* push_delegate,
- const base::TickClock* tick_clock,
- base::SequencedTaskRunner* task_runner,
- std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
- NetLog* net_log)
- : quic::QuicSpdyClientSessionBase(connection,
- push_promise_index.get(),
- config,
- connection->supported_versions()),
- session_key_(session_key),
- require_confirmation_(require_confirmation),
- migrate_session_early_v2_(migrate_session_early_v2),
- migrate_session_on_network_change_v2_(
- migrate_sessions_on_network_change_v2),
- migrate_idle_session_(migrate_idle_session),
- allow_port_migration_(allow_port_migration),
- idle_migration_period_(idle_migration_period),
- max_time_on_non_default_network_(max_time_on_non_default_network),
- max_migrations_to_non_default_network_on_write_error_(
- max_migrations_to_non_default_network_on_write_error),
- max_migrations_to_non_default_network_on_path_degrading_(
- max_migrations_to_non_default_network_on_path_degrading),
- clock_(clock),
- yield_after_packets_(yield_after_packets),
- yield_after_duration_(yield_after_duration),
- most_recent_path_degrading_timestamp_(base::TimeTicks()),
- most_recent_network_disconnected_timestamp_(base::TimeTicks()),
- tick_clock_(tick_clock),
- most_recent_stream_close_time_(tick_clock_->NowTicks()),
- most_recent_write_error_timestamp_(base::TimeTicks()),
- crypto_config_(std::move(crypto_config)),
- stream_factory_(stream_factory),
- transport_security_state_(transport_security_state),
- ssl_config_service_(ssl_config_service),
- server_info_(std::move(server_info)),
- task_runner_(task_runner),
- net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::QUIC_SESSION)),
- logger_(std::make_unique<QuicConnectionLogger>(
- this,
- connection_description,
- std::move(socket_performance_watcher),
- net_log_)),
- http3_logger_(VersionUsesHttp3(connection->transport_version())
- ? std::make_unique<QuicHttp3Logger>(net_log_)
- : nullptr),
- push_delegate_(push_delegate),
- headers_include_h2_stream_dependency_(
- headers_include_h2_stream_dependency),
- push_promise_index_(std::move(push_promise_index)),
- path_validation_writer_delegate_(this, task_runner_) {
- default_network_ = default_network;
- auto* socket_raw = socket.get();
- sockets_.push_back(std::move(socket));
- packet_readers_.push_back(std::make_unique<QuicChromiumPacketReader>(
- sockets_.back().get(), clock, this, yield_after_packets,
- yield_after_duration, net_log_));
- CHECK_EQ(packet_readers_.size(), sockets_.size());
- crypto_stream_ = crypto_client_stream_factory->CreateQuicCryptoClientStream(
- session_key.server_id(), this,
- std::make_unique<ProofVerifyContextChromium>(cert_verify_flags, net_log_),
- crypto_config_->GetConfig());
- if (VersionUsesHttp3(transport_version()))
- set_debug_visitor(http3_logger_.get());
- connection->set_debug_visitor(logger_.get());
- connection->set_creator_debug_delegate(logger_.get());
- migrate_back_to_default_timer_.SetTaskRunner(task_runner_.get());
- net_log_.BeginEvent(NetLogEventType::QUIC_SESSION, [&] {
- return NetLogQuicClientSessionParams(
- &session_key, connection_id(), connection->client_connection_id(),
- supported_versions(), cert_verify_flags, require_confirmation_);
- });
- IPEndPoint address;
- if (socket_raw && socket_raw->GetLocalAddress(&address) == OK &&
- address.GetFamily() == ADDRESS_FAMILY_IPV6) {
- connection->SetMaxPacketLength(connection->max_packet_length() -
- kAdditionalOverheadForIPv6);
- }
- connect_timing_.dns_start = dns_resolution_start_time;
- connect_timing_.dns_end = dns_resolution_end_time;
- if (!retransmittable_on_wire_timeout.IsZero()) {
- connection->set_initial_retransmittable_on_wire_timeout(
- retransmittable_on_wire_timeout);
- }
- }
- QuicChromiumClientSession::~QuicChromiumClientSession() {
- // This is referenced by the parent class's destructor, so have to delete it
- // asynchronously, unfortunately. Don't use DeleteSoon, since that leaks if
- // the task is not run, which is often the case in tests.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce([](std::unique_ptr<quic::QuicClientPushPromiseIndex>
- push_promise_index) {},
- std::move(push_promise_index_)));
- DCHECK(callback_.is_null());
- for (auto& observer : connectivity_observer_list_)
- observer.OnSessionRemoved(this);
- net_log_.EndEvent(NetLogEventType::QUIC_SESSION);
- DCHECK(waiting_for_confirmation_callbacks_.empty());
- DCHECK(!HasActiveRequestStreams());
- DCHECK(handles_.empty());
- if (!stream_requests_.empty()) {
- // The session must be closed before it is destroyed.
- CancelAllRequests(ERR_UNEXPECTED);
- }
- connection()->set_debug_visitor(nullptr);
- if (connection()->connected()) {
- // Ensure that the connection is closed by the time the session is
- // destroyed.
- connection()->CloseConnection(quic::QUIC_PEER_GOING_AWAY,
- "session torn down",
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- }
- if (IsEncryptionEstablished())
- RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
- if (OneRttKeysAvailable())
- RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
- else
- RecordHandshakeState(STATE_FAILED);
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.NumTotalStreams",
- num_total_streams_);
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicNumSentClientHellos",
- crypto_stream_->num_sent_client_hellos());
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.Pushed", streams_pushed_count_);
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.PushedAndClaimed",
- streams_pushed_and_claimed_count_);
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.PushedBytes", bytes_pushed_count_);
- DCHECK_LE(bytes_pushed_and_unclaimed_count_, bytes_pushed_count_);
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.PushedAndUnclaimedBytes",
- bytes_pushed_and_unclaimed_count_);
- if (!OneRttKeysAvailable())
- return;
- // Sending one client_hello means we had zero handshake-round-trips.
- int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
- SSLInfo ssl_info;
- // QUIC supports only secure urls.
- if (GetSSLInfo(&ssl_info) && ssl_info.cert.get()) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
- round_trip_handshakes, 1, 3, 4);
- if (require_confirmation_) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
- round_trip_handshakes, 1, 3, 4);
- }
- }
- const quic::QuicConnectionStats stats = connection()->GetStats();
- // The MTU used by QUIC is limited to a fairly small set of predefined values
- // (initial values and MTU discovery values), but does not fare well when
- // bucketed. Because of that, a sparse histogram is used here.
- base::UmaHistogramSparse("Net.QuicSession.ClientSideMtu", stats.egress_mtu);
- base::UmaHistogramSparse("Net.QuicSession.ServerSideMtu", stats.ingress_mtu);
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.MtuProbesSent",
- connection()->mtu_probe_count());
- if (stats.packets_sent >= 100) {
- // Used to monitor for regressions that effect large uploads.
- UMA_HISTOGRAM_COUNTS_1000(
- "Net.QuicSession.PacketRetransmitsPerMille",
- 1000 * stats.packets_retransmitted / stats.packets_sent);
- }
- if (stats.max_sequence_reordering == 0)
- return;
- const base::HistogramBase::Sample kMaxReordering = 100;
- base::HistogramBase::Sample reordering = kMaxReordering;
- if (stats.min_rtt_us > 0) {
- reordering = static_cast<base::HistogramBase::Sample>(
- 100 * stats.max_time_reordering_us / stats.min_rtt_us);
- }
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime", reordering,
- 1, kMaxReordering, 50);
- if (stats.min_rtt_us > 100 * 1000) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
- reordering, 1, kMaxReordering, 50);
- }
- UMA_HISTOGRAM_COUNTS_1M(
- "Net.QuicSession.MaxReordering",
- static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
- }
- void QuicChromiumClientSession::Initialize() {
- set_max_inbound_header_list_size(kQuicMaxHeaderListSize);
- if (config()->HasClientRequestedIndependentOption(
- quic::kQLVE, quic::Perspective::IS_CLIENT)) {
- connection()->EnableLegacyVersionEncapsulation(session_key_.host());
- }
- quic::QuicSpdyClientSessionBase::Initialize();
- }
- size_t QuicChromiumClientSession::WriteHeadersOnHeadersStream(
- quic::QuicStreamId id,
- spdy::Http2HeaderBlock headers,
- bool fin,
- const spdy::SpdyStreamPrecedence& precedence,
- quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
- ack_listener) {
- spdy::SpdyStreamId parent_stream_id = 0;
- int weight = 0;
- bool exclusive = false;
- if (headers_include_h2_stream_dependency_) {
- priority_dependency_state_.OnStreamCreation(id, precedence.spdy3_priority(),
- &parent_stream_id, &weight,
- &exclusive);
- } else {
- weight = spdy::Spdy3PriorityToHttp2Weight(precedence.spdy3_priority());
- }
- return WriteHeadersOnHeadersStreamImpl(id, std::move(headers), fin,
- parent_stream_id, weight, exclusive,
- std::move(ack_listener));
- }
- void QuicChromiumClientSession::UnregisterStreamPriority(quic::QuicStreamId id,
- bool is_static) {
- if (headers_include_h2_stream_dependency_ && !is_static) {
- priority_dependency_state_.OnStreamDestruction(id);
- }
- quic::QuicSpdySession::UnregisterStreamPriority(id, is_static);
- }
- void QuicChromiumClientSession::UpdateStreamPriority(
- quic::QuicStreamId id,
- const spdy::SpdyStreamPrecedence& new_precedence) {
- if (headers_include_h2_stream_dependency_ ||
- VersionUsesHttp3(connection()->transport_version())) {
- auto updates = priority_dependency_state_.OnStreamUpdate(
- id, new_precedence.spdy3_priority());
- for (auto update : updates) {
- if (!VersionUsesHttp3(connection()->transport_version())) {
- WritePriority(update.id, update.parent_stream_id, update.weight,
- update.exclusive);
- }
- }
- }
- quic::QuicSpdySession::UpdateStreamPriority(id, new_precedence);
- }
- void QuicChromiumClientSession::OnHttp3GoAway(uint64_t id) {
- quic::QuicSpdySession::OnHttp3GoAway(id);
- NotifyFactoryOfSessionGoingAway();
- PerformActionOnActiveStreams([id](quic::QuicStream* stream) {
- if (stream->id() >= id) {
- static_cast<QuicChromiumClientStream*>(stream)->OnError(
- ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED);
- }
- return true;
- });
- }
- void QuicChromiumClientSession::OnAcceptChFrameReceivedViaAlps(
- const quic::AcceptChFrame& frame) {
- bool has_valid_entry = false;
- bool has_invalid_entry = false;
- for (const auto& entry : frame.entries) {
- const url::SchemeHostPort scheme_host_port(GURL(entry.origin));
- // |entry.origin| must be a valid SchemeHostPort.
- std::string serialized = scheme_host_port.Serialize();
- if (serialized.empty() || entry.origin != serialized) {
- has_invalid_entry = true;
- continue;
- }
- has_valid_entry = true;
- accept_ch_entries_received_via_alps_.insert(
- std::make_pair(std::move(scheme_host_port), entry.value));
- net_log_.AddEvent(NetLogEventType::QUIC_ACCEPT_CH_FRAME_RECEIVED,
- [&] { return NetLogAcceptChFrameReceivedParams(entry); });
- }
- LogAcceptChFrameReceivedHistogram(has_valid_entry, has_invalid_entry);
- }
- void QuicChromiumClientSession::AddHandle(Handle* handle) {
- if (going_away_) {
- handle->OnSessionClosed(connection()->version(), ERR_UNEXPECTED, error(),
- port_migration_detected_,
- quic_connection_migration_attempted_,
- quic_connection_migration_successful_,
- GetConnectTiming(), WasConnectionEverUsed());
- return;
- }
- DCHECK(!base::Contains(handles_, handle));
- handles_.insert(handle);
- }
- void QuicChromiumClientSession::RemoveHandle(Handle* handle) {
- DCHECK(base::Contains(handles_, handle));
- handles_.erase(handle);
- }
- void QuicChromiumClientSession::AddConnectivityObserver(
- ConnectivityObserver* observer) {
- connectivity_observer_list_.AddObserver(observer);
- observer->OnSessionRegistered(this, GetCurrentNetwork());
- }
- void QuicChromiumClientSession::RemoveConnectivityObserver(
- ConnectivityObserver* observer) {
- connectivity_observer_list_.RemoveObserver(observer);
- }
- // TODO(zhongyi): replace migration_session_* booleans with
- // ConnectionMigrationMode.
- ConnectionMigrationMode QuicChromiumClientSession::connection_migration_mode()
- const {
- if (migrate_session_early_v2_)
- return ConnectionMigrationMode::FULL_MIGRATION_V2;
- if (migrate_session_on_network_change_v2_)
- return ConnectionMigrationMode::NO_MIGRATION_ON_PATH_DEGRADING_V2;
- return ConnectionMigrationMode::NO_MIGRATION;
- }
- int QuicChromiumClientSession::WaitForHandshakeConfirmation(
- CompletionOnceCallback callback) {
- if (!connection()->connected())
- return ERR_CONNECTION_CLOSED;
- if (OneRttKeysAvailable())
- return OK;
- waiting_for_confirmation_callbacks_.push_back(std::move(callback));
- return ERR_IO_PENDING;
- }
- int QuicChromiumClientSession::TryCreateStream(StreamRequest* request) {
- if (goaway_received()) {
- DVLOG(1) << "Going away.";
- return ERR_CONNECTION_CLOSED;
- }
- if (!connection()->connected()) {
- DVLOG(1) << "Already closed.";
- return ERR_CONNECTION_CLOSED;
- }
- if (going_away_) {
- return ERR_CONNECTION_CLOSED;
- }
- bool can_open_next = CanOpenNextOutgoingBidirectionalStream();
- if (can_open_next) {
- request->stream_ =
- CreateOutgoingReliableStreamImpl(request->traffic_annotation())
- ->CreateHandle();
- return OK;
- }
- request->pending_start_time_ = tick_clock_->NowTicks();
- stream_requests_.push_back(request);
- UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumPendingStreamRequests",
- stream_requests_.size());
- return ERR_IO_PENDING;
- }
- void QuicChromiumClientSession::CancelRequest(StreamRequest* request) {
- // Remove |request| from the queue while preserving the order of the
- // other elements.
- auto it =
- std::find(stream_requests_.begin(), stream_requests_.end(), request);
- if (it != stream_requests_.end()) {
- it = stream_requests_.erase(it);
- }
- }
- bool QuicChromiumClientSession::ShouldCreateOutgoingBidirectionalStream() {
- if (!crypto_stream_->encryption_established()) {
- DVLOG(1) << "Encryption not active so no outgoing stream created.";
- return false;
- }
- if (!CanOpenNextOutgoingBidirectionalStream()) {
- DVLOG(1) << "Failed to create a new outgoing stream. "
- << "Already " << GetNumActiveStreams() << " open.";
- return false;
- }
- if (goaway_received()) {
- DVLOG(1) << "Failed to create a new outgoing stream. "
- << "Already received goaway.";
- return false;
- }
- if (going_away_) {
- return false;
- }
- return true;
- }
- bool QuicChromiumClientSession::ShouldCreateOutgoingUnidirectionalStream() {
- NOTREACHED() << "Try to create outgoing unidirectional streams";
- return false;
- }
- bool QuicChromiumClientSession::WasConnectionEverUsed() {
- const quic::QuicConnectionStats& stats = connection()->GetStats();
- return stats.bytes_sent > 0 || stats.bytes_received > 0;
- }
- QuicChromiumClientStream*
- QuicChromiumClientSession::CreateOutgoingBidirectionalStream() {
- NOTREACHED() << "CreateOutgoingReliableStreamImpl should be called directly";
- return nullptr;
- }
- QuicChromiumClientStream*
- QuicChromiumClientSession::CreateOutgoingUnidirectionalStream() {
- NOTREACHED() << "Try to create outgoing unidirectional stream";
- return nullptr;
- }
- QuicChromiumClientStream*
- QuicChromiumClientSession::CreateOutgoingReliableStreamImpl(
- const NetworkTrafficAnnotationTag& traffic_annotation) {
- DCHECK(connection()->connected());
- QuicChromiumClientStream* stream = new QuicChromiumClientStream(
- GetNextOutgoingBidirectionalStreamId(), this, quic::BIDIRECTIONAL,
- net_log_, traffic_annotation);
- ActivateStream(base::WrapUnique(stream));
- ++num_total_streams_;
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.NumOpenStreams",
- GetNumActiveStreams());
- // The previous histogram puts 100 in a bucket betweeen 86-113 which does
- // not shed light on if chrome ever things it has more than 100 streams open.
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
- GetNumActiveStreams() > 100);
- return stream;
- }
- quic::QuicCryptoClientStream*
- QuicChromiumClientSession::GetMutableCryptoStream() {
- return crypto_stream_.get();
- }
- const quic::QuicCryptoClientStream* QuicChromiumClientSession::GetCryptoStream()
- const {
- return crypto_stream_.get();
- }
- int QuicChromiumClientSession::GetRemoteEndpoint(IPEndPoint* endpoint) {
- *endpoint = ToIPEndPoint(peer_address());
- return OK;
- }
- // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
- // we learn about SSL info (sync vs async vs cached).
- bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
- ssl_info->Reset();
- if (!cert_verify_result_) {
- return false;
- }
- ssl_info->cert_status = cert_verify_result_->cert_status;
- ssl_info->cert = cert_verify_result_->verified_cert;
- ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
- ssl_info->is_issued_by_known_root =
- cert_verify_result_->is_issued_by_known_root;
- ssl_info->pkp_bypassed = pkp_bypassed_;
- ssl_info->client_cert_sent = false;
- ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
- ssl_info->pinning_failure_log = pinning_failure_log_;
- ssl_info->is_fatal_cert_error = is_fatal_cert_error_;
- ssl_info->signed_certificate_timestamps = cert_verify_result_->scts;
- ssl_info->ct_policy_compliance = cert_verify_result_->policy_compliance;
- const auto& crypto_params = crypto_stream_->crypto_negotiated_params();
- uint16_t cipher_suite;
- if (connection()->version().UsesTls()) {
- cipher_suite = crypto_params.cipher_suite;
- } else {
- // Map QUIC AEADs to the corresponding TLS 1.3 cipher. OpenSSL's cipher
- // suite numbers begin with a stray 0x03, so mask them off.
- quic::QuicTag aead = crypto_params.aead;
- switch (aead) {
- case quic::kAESG:
- cipher_suite = TLS1_CK_AES_128_GCM_SHA256 & 0xffff;
- break;
- case quic::kCC20:
- cipher_suite = TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff;
- break;
- default:
- NOTREACHED();
- return false;
- }
- }
- int ssl_connection_status = 0;
- SSLConnectionStatusSetCipherSuite(cipher_suite, &ssl_connection_status);
- SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_QUIC,
- &ssl_connection_status);
- ssl_info->connection_status = ssl_connection_status;
- if (connection()->version().UsesTls()) {
- ssl_info->key_exchange_group = crypto_params.key_exchange_group;
- ssl_info->peer_signature_algorithm = crypto_params.peer_signature_algorithm;
- return true;
- }
- // Report the QUIC key exchange as the corresponding TLS curve.
- switch (crypto_stream_->crypto_negotiated_params().key_exchange) {
- case quic::kP256:
- ssl_info->key_exchange_group = SSL_CURVE_SECP256R1;
- break;
- case quic::kC255:
- ssl_info->key_exchange_group = SSL_CURVE_X25519;
- break;
- default:
- NOTREACHED();
- return false;
- }
- // QUIC-Crypto always uses RSA-PSS or ECDSA with SHA-256.
- size_t unused;
- X509Certificate::PublicKeyType key_type;
- X509Certificate::GetPublicKeyInfo(ssl_info->cert->cert_buffer(), &unused,
- &key_type);
- switch (key_type) {
- case X509Certificate::kPublicKeyTypeRSA:
- ssl_info->peer_signature_algorithm = SSL_SIGN_RSA_PSS_RSAE_SHA256;
- break;
- case X509Certificate::kPublicKeyTypeECDSA:
- ssl_info->peer_signature_algorithm = SSL_SIGN_ECDSA_SECP256R1_SHA256;
- break;
- default:
- NOTREACHED();
- return false;
- }
- return true;
- }
- base::StringPiece QuicChromiumClientSession::GetAcceptChViaAlps(
- const url::SchemeHostPort& scheme_host_port) const {
- auto it = accept_ch_entries_received_via_alps_.find(scheme_host_port);
- if (it == accept_ch_entries_received_via_alps_.end()) {
- LogAcceptChForOriginHistogram(false);
- return {};
- } else {
- LogAcceptChForOriginHistogram(true);
- return it->second;
- }
- }
- int QuicChromiumClientSession::CryptoConnect(CompletionOnceCallback callback) {
- connect_timing_.connect_start = tick_clock_->NowTicks();
- RecordHandshakeState(STATE_STARTED);
- DCHECK(flow_controller());
- if (!crypto_stream_->CryptoConnect())
- return ERR_QUIC_HANDSHAKE_FAILED;
- if (OneRttKeysAvailable()) {
- connect_timing_.connect_end = tick_clock_->NowTicks();
- return OK;
- }
- // Unless we require handshake confirmation, activate the session if
- // we have established initial encryption.
- if (!require_confirmation_ && IsEncryptionEstablished())
- return OK;
- callback_ = std::move(callback);
- return ERR_IO_PENDING;
- }
- int QuicChromiumClientSession::GetNumSentClientHellos() const {
- return crypto_stream_->num_sent_client_hellos();
- }
- bool QuicChromiumClientSession::CanPool(
- const std::string& hostname,
- const QuicSessionKey& other_session_key) const {
- DCHECK(connection()->connected());
- if (!session_key_.CanUseForAliasing(other_session_key))
- return false;
- SSLInfo ssl_info;
- if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
- NOTREACHED() << "QUIC should always have certificates.";
- return false;
- }
- return SpdySession::CanPool(transport_security_state_, ssl_info,
- *ssl_config_service_, session_key_.host(),
- hostname, session_key_.network_isolation_key());
- }
- bool QuicChromiumClientSession::ShouldCreateIncomingStream(
- quic::QuicStreamId id) {
- if (!connection()->connected()) {
- LOG(DFATAL) << "ShouldCreateIncomingStream called when disconnected";
- return false;
- }
- if (goaway_received()) {
- DVLOG(1) << "Cannot create a new outgoing stream. "
- << "Already received goaway.";
- return false;
- }
- if (going_away_) {
- return false;
- }
- if (quic::QuicUtils::IsClientInitiatedStreamId(
- connection()->transport_version(), id) ||
- (connection()->version().HasIetfQuicFrames() &&
- quic::QuicUtils::IsBidirectionalStreamId(id, connection()->version()))) {
- LOG(WARNING) << "Received invalid push stream id " << id;
- connection()->CloseConnection(
- quic::QUIC_INVALID_STREAM_ID,
- "Server created non write unidirectional stream",
- quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- return true;
- }
- QuicChromiumClientStream* QuicChromiumClientSession::CreateIncomingStream(
- quic::QuicStreamId id) {
- if (!ShouldCreateIncomingStream(id)) {
- return nullptr;
- }
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("quic_chromium_incoming_session", R"(
- semantics {
- sender: "Quic Chromium Client Session"
- description:
- "When a web server needs to push a response to a client, an incoming "
- "stream is created to reply the client with pushed message instead "
- "of a message from the network."
- trigger:
- "A request by a server to push a response to the client."
- data: "None."
- destination: OTHER
- destination_other:
- "This stream is not used for sending data."
- }
- policy {
- cookies_allowed: NO
- setting: "This feature cannot be disabled in settings."
- policy_exception_justification:
- "Essential for network access."
- }
- )");
- return CreateIncomingReliableStreamImpl(id, traffic_annotation);
- }
- QuicChromiumClientStream* QuicChromiumClientSession::CreateIncomingStream(
- quic::PendingStream* pending) {
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation(
- "quic_chromium_incoming_pending_session", R"(
- semantics {
- sender: "Quic Chromium Client Session Pending Stream"
- description:
- "When a web server needs to push a response to a client, an incoming "
- "stream is created to reply to the client with pushed message instead "
- "of a message from the network."
- trigger:
- "A request by a server to push a response to the client."
- data: "This stream is only used to receive data from the server."
- destination: OTHER
- destination_other:
- "The web server pushing the response."
- }
- policy {
- cookies_allowed: NO
- setting: "This feature cannot be disabled in settings."
- policy_exception_justification:
- "Essential for network access."
- }
- )");
- return CreateIncomingReliableStreamImpl(pending, traffic_annotation);
- }
- QuicChromiumClientStream*
- QuicChromiumClientSession::CreateIncomingReliableStreamImpl(
- quic::QuicStreamId id,
- const NetworkTrafficAnnotationTag& traffic_annotation) {
- DCHECK(connection()->connected());
- QuicChromiumClientStream* stream = new QuicChromiumClientStream(
- id, this, quic::READ_UNIDIRECTIONAL, net_log_, traffic_annotation);
- ActivateStream(base::WrapUnique(stream));
- ++num_total_streams_;
- return stream;
- }
- QuicChromiumClientStream*
- QuicChromiumClientSession::CreateIncomingReliableStreamImpl(
- quic::PendingStream* pending,
- const NetworkTrafficAnnotationTag& traffic_annotation) {
- DCHECK(connection()->connected());
- QuicChromiumClientStream* stream =
- new QuicChromiumClientStream(pending, this, net_log_, traffic_annotation);
- ActivateStream(base::WrapUnique(stream));
- ++num_total_streams_;
- return stream;
- }
- void QuicChromiumClientSession::OnStreamClosed(quic::QuicStreamId stream_id) {
- most_recent_stream_close_time_ = tick_clock_->NowTicks();
- quic::QuicStream* stream = GetActiveStream(stream_id);
- if (stream != nullptr) {
- logger_->UpdateReceivedFrameCounts(stream_id, stream->num_frames_received(),
- stream->num_duplicate_frames_received());
- if (quic::QuicUtils::IsServerInitiatedStreamId(
- connection()->transport_version(), stream_id)) {
- bytes_pushed_count_ += stream->stream_bytes_read();
- }
- }
- quic::QuicSpdyClientSessionBase::OnStreamClosed(stream_id);
- }
- void QuicChromiumClientSession::OnCanCreateNewOutgoingStream(
- bool unidirectional) {
- while (CanOpenNextOutgoingBidirectionalStream() &&
- !stream_requests_.empty() &&
- crypto_stream_->encryption_established() && !goaway_received() &&
- !going_away_ && connection()->connected()) {
- StreamRequest* request = stream_requests_.front();
- // TODO(ckrasic) - analyze data and then add logic to mark QUIC
- // broken if wait times are excessive.
- UMA_HISTOGRAM_TIMES("Net.QuicSession.PendingStreamsWaitTime",
- tick_clock_->NowTicks() - request->pending_start_time_);
- stream_requests_.pop_front();
- request->OnRequestCompleteSuccess(
- CreateOutgoingReliableStreamImpl(request->traffic_annotation())
- ->CreateHandle());
- }
- }
- void QuicChromiumClientSession::OnConfigNegotiated() {
- quic::QuicSpdyClientSessionBase::OnConfigNegotiated();
- if (!stream_factory_ || !stream_factory_->allow_server_migration()) {
- if (connection()->connection_migration_use_new_cid()) {
- if (!config()->HasReceivedPreferredAddressConnectionIdAndToken()) {
- return;
- }
- } else {
- if (!config()->HasReceivedIPv6AlternateServerAddress() &&
- !config()->HasReceivedIPv4AlternateServerAddress()) {
- return;
- }
- }
- }
- // Server has sent an alternate address to connect to.
- IPEndPoint old_address;
- GetDefaultSocket()->GetPeerAddress(&old_address);
- // Migrate only if address families match.
- IPEndPoint new_address;
- if (old_address.GetFamily() == ADDRESS_FAMILY_IPV6) {
- if (!config()->HasReceivedIPv6AlternateServerAddress()) {
- return;
- }
- new_address = ToIPEndPoint(config()->ReceivedIPv6AlternateServerAddress());
- } else if (old_address.GetFamily() == ADDRESS_FAMILY_IPV4) {
- if (!config()->HasReceivedIPv4AlternateServerAddress()) {
- return;
- }
- new_address = ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress());
- }
- DCHECK_EQ(new_address.GetFamily(), old_address.GetFamily());
- // Specifying handles::kInvalidNetworkHandle for the |network| parameter
- // causes the session to use the default network for the new socket.
- Migrate(handles::kInvalidNetworkHandle, new_address,
- /*close_session_on_error=*/true);
- }
- void QuicChromiumClientSession::SetDefaultEncryptionLevel(
- quic::EncryptionLevel level) {
- if (!callback_.is_null() &&
- (!require_confirmation_ || level == quic::ENCRYPTION_FORWARD_SECURE ||
- level == quic::ENCRYPTION_ZERO_RTT)) {
- // Currently for all CryptoHandshakeEvent events, callback_
- // could be called because there are no error events in CryptoHandshakeEvent
- // enum. If error events are added to CryptoHandshakeEvent, then the
- // following code needs to changed.
- std::move(callback_).Run(OK);
- }
- if (level == quic::ENCRYPTION_FORWARD_SECURE) {
- OnCryptoHandshakeComplete();
- LogZeroRttStats();
- }
- if (level == quic::ENCRYPTION_ZERO_RTT)
- attempted_zero_rtt_ = true;
- quic::QuicSpdySession::SetDefaultEncryptionLevel(level);
- }
- void QuicChromiumClientSession::OnTlsHandshakeComplete() {
- if (!callback_.is_null()) {
- // Currently for all CryptoHandshakeEvent events, callback_
- // could be called because there are no error events in CryptoHandshakeEvent
- // enum. If error events are added to CryptoHandshakeEvent, then the
- // following code needs to changed.
- std::move(callback_).Run(OK);
- }
- OnCryptoHandshakeComplete();
- LogZeroRttStats();
- quic::QuicSpdySession::OnTlsHandshakeComplete();
- }
- void QuicChromiumClientSession::OnNewEncryptionKeyAvailable(
- quic::EncryptionLevel level,
- std::unique_ptr<quic::QuicEncrypter> encrypter) {
- if (!attempted_zero_rtt_ && (level == quic::ENCRYPTION_ZERO_RTT ||
- level == quic::ENCRYPTION_FORWARD_SECURE)) {
- base::TimeTicks now = tick_clock_->NowTicks();
- DCHECK_LE(connect_timing_.connect_start, now);
- UMA_HISTOGRAM_TIMES("Net.QuicSession.EncryptionEstablishedTime",
- now - connect_timing_.connect_start);
- }
- if (level == quic::ENCRYPTION_ZERO_RTT)
- attempted_zero_rtt_ = true;
- QuicSpdySession::OnNewEncryptionKeyAvailable(level, std::move(encrypter));
- if (!callback_.is_null() &&
- (!require_confirmation_ && level == quic::ENCRYPTION_ZERO_RTT)) {
- // Currently for all CryptoHandshakeEvent events, callback_
- // could be called because there are no error events in CryptoHandshakeEvent
- // enum. If error events are added to CryptoHandshakeEvent, then the
- // following code needs to changed.
- std::move(callback_).Run(OK);
- }
- }
- void QuicChromiumClientSession::LogZeroRttStats() {
- DCHECK(OneRttKeysAvailable());
- ZeroRttState state;
- ssl_early_data_reason_t early_data_reason = crypto_stream_->EarlyDataReason();
- if (early_data_reason == ssl_early_data_accepted) {
- state = ZeroRttState::kAttemptedAndSucceeded;
- } else if (early_data_reason == ssl_early_data_peer_declined ||
- early_data_reason == ssl_early_data_session_not_resumed ||
- early_data_reason == ssl_early_data_hello_retry_request) {
- state = ZeroRttState::kAttemptedAndRejected;
- } else {
- state = ZeroRttState::kNotAttempted;
- }
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttState", state);
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttReason", early_data_reason,
- ssl_early_data_reason_max_value + 1);
- if (IsGoogleHost(session_key_.host())) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttReasonGoogle",
- early_data_reason,
- ssl_early_data_reason_max_value + 1);
- } else {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttReasonNonGoogle",
- early_data_reason,
- ssl_early_data_reason_max_value + 1);
- }
- }
- void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
- const quic::CryptoHandshakeMessage& message) {
- logger_->OnCryptoHandshakeMessageSent(message);
- }
- void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
- const quic::CryptoHandshakeMessage& message) {
- logger_->OnCryptoHandshakeMessageReceived(message);
- if (message.tag() == quic::kREJ) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
- message.GetSerialized().length(), 1000, 10000,
- 50);
- absl::string_view proof;
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.RejectHasProof",
- message.GetStringPiece(quic::kPROF, &proof));
- }
- }
- void QuicChromiumClientSession::OnGoAway(const quic::QuicGoAwayFrame& frame) {
- quic::QuicSession::OnGoAway(frame);
- NotifyFactoryOfSessionGoingAway();
- port_migration_detected_ =
- frame.error_code == quic::QUIC_ERROR_MIGRATING_PORT;
- }
- void QuicChromiumClientSession::OnConnectionClosed(
- const quic::QuicConnectionCloseFrame& frame,
- quic::ConnectionCloseSource source) {
- DCHECK(!connection()->connected());
- logger_->OnConnectionClosed(frame, source);
- RecordConnectionCloseErrorCode(frame, source, session_key_.host(),
- OneRttKeysAvailable());
- if (OneRttKeysAvailable()) {
- handles::NetworkHandle current_network = GetCurrentNetwork();
- for (auto& observer : connectivity_observer_list_)
- observer.OnSessionClosedAfterHandshake(this, current_network, source,
- frame.quic_error_code);
- }
- const quic::QuicErrorCode error = frame.quic_error_code;
- const std::string& error_details = frame.error_details;
- if (source == quic::ConnectionCloseSource::FROM_SELF &&
- error == quic::QUIC_NETWORK_IDLE_TIMEOUT && ShouldKeepConnectionAlive()) {
- quic::QuicStreamCount streams_waiting_to_write = 0;
- PerformActionOnActiveStreams(
- [&streams_waiting_to_write](quic::QuicStream* stream) {
- if (stream->HasBufferedData())
- ++streams_waiting_to_write;
- return true;
- });
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicSession.NumStreamsWaitingToWriteOnIdleTimeout",
- streams_waiting_to_write);
- UMA_HISTOGRAM_COUNTS_100("Net.QuicSession.NumActiveStreamsOnIdleTimeout",
- GetNumActiveStreams());
- }
- if (source == quic::ConnectionCloseSource::FROM_PEER) {
- if (error == quic::QUIC_PUBLIC_RESET) {
- // is_from_google_server will be true if the received EPID is
- // kEPIDGoogleFrontEnd or kEPIDGoogleFrontEnd0.
- const bool is_from_google_server =
- error_details.find(base::StringPrintf(
- "From %s", quic::kEPIDGoogleFrontEnd)) != std::string::npos;
- if (OneRttKeysAvailable()) {
- UMA_HISTOGRAM_BOOLEAN(
- "Net.QuicSession.ClosedByPublicReset.HandshakeConfirmed",
- is_from_google_server);
- } else {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedByPublicReset",
- is_from_google_server);
- }
- if (is_from_google_server) {
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicSession.NumMigrationsExercisedBeforePublicReset",
- sockets_.size() - 1);
- }
- base::UmaHistogramSparse(
- "Net.QuicSession.LastSentPacketContentBeforePublicReset",
- connection()
- ->sent_packet_manager()
- .unacked_packets()
- .GetLastPacketContent());
- const quic::QuicTime last_in_flight_packet_sent_time =
- connection()
- ->sent_packet_manager()
- .unacked_packets()
- .GetLastInFlightPacketSentTime();
- const quic::QuicTime handshake_completion_time =
- connection()->GetStats().handshake_completion_time;
- if (last_in_flight_packet_sent_time.IsInitialized() &&
- handshake_completion_time.IsInitialized() &&
- last_in_flight_packet_sent_time >= handshake_completion_time) {
- const quic::QuicTime::Delta delay =
- last_in_flight_packet_sent_time - handshake_completion_time;
- UMA_HISTOGRAM_LONG_TIMES_100(
- "Net.QuicSession."
- "LastInFlightPacketSentTimeFromHandshakeCompletionWithPublicReset",
- base::Milliseconds(delay.ToMilliseconds()));
- }
- UMA_HISTOGRAM_LONG_TIMES_100(
- "Net.QuicSession.ConnectionDurationWithPublicReset",
- tick_clock_->NowTicks() - connect_timing_.connect_end);
- }
- if (OneRttKeysAvailable()) {
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- "Net.QuicSession.StreamCloseErrorCodeServer.HandshakeConfirmed",
- base::HistogramBase::kUmaTargetedHistogramFlag);
- size_t num_streams = GetNumActiveStreams();
- if (num_streams > 0)
- histogram->AddCount(error, num_streams);
- }
- } else {
- if (OneRttKeysAvailable()) {
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- "Net.QuicSession.StreamCloseErrorCodeClient.HandshakeConfirmed",
- base::HistogramBase::kUmaTargetedHistogramFlag);
- size_t num_streams = GetNumActiveStreams();
- if (num_streams > 0)
- histogram->AddCount(error, num_streams);
- } else {
- if (error == quic::QUIC_HANDSHAKE_TIMEOUT) {
- UMA_HISTOGRAM_BOOLEAN(
- "Net.QuicSession.HandshakeTimeout.PathDegradingDetected",
- connection()->IsPathDegrading());
- }
- }
- if (error == quic::QUIC_TOO_MANY_RTOS) {
- UMA_HISTOGRAM_COUNTS_1000(
- "Net.QuicSession.ClosedByRtoAtClient.ReceivedPacketCount",
- connection()->GetStats().packets_received);
- UMA_HISTOGRAM_COUNTS_1000(
- "Net.QuicSession.ClosedByRtoAtClient.SentPacketCount",
- connection()->GetStats().packets_sent);
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicSession."
- "MaxConsecutiveRtoWithForwardProgressAndBlackholeDetected",
- connection()->GetStats().max_consecutive_rto_with_forward_progress);
- }
- }
- if (error == quic::QUIC_NETWORK_IDLE_TIMEOUT) {
- UMA_HISTOGRAM_COUNTS_1M(
- "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
- GetNumActiveStreams());
- if (OneRttKeysAvailable()) {
- if (GetNumActiveStreams() > 0) {
- UMA_HISTOGRAM_BOOLEAN(
- "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
- connection()->sent_packet_manager().HasInFlightPackets());
- UMA_HISTOGRAM_COUNTS_1M(
- "Net.QuicSession.TimedOutWithOpenStreams.ConsecutivePTOCount",
- connection()->sent_packet_manager().GetConsecutivePtoCount());
- base::UmaHistogramSparse(
- "Net.QuicSession.TimedOutWithOpenStreams.LocalPort",
- connection()->self_address().port());
- }
- } else {
- UMA_HISTOGRAM_COUNTS_1M(
- "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
- GetNumActiveStreams());
- UMA_HISTOGRAM_COUNTS_1M(
- "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
- num_total_streams_);
- }
- }
- if (OneRttKeysAvailable()) {
- // QUIC connections should not timeout while there are open streams,
- // since PING frames are sent to prevent timeouts. If, however, the
- // connection timed out with open streams then QUIC traffic has become
- // blackholed. Alternatively, if too many retransmission timeouts occur
- // then QUIC traffic has become blackholed.
- if (stream_factory_ && (error == quic::QUIC_TOO_MANY_RTOS ||
- (error == quic::QUIC_NETWORK_IDLE_TIMEOUT &&
- GetNumActiveStreams() > 0))) {
- stream_factory_->OnBlackholeAfterHandshakeConfirmed(this);
- }
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicSession.CryptoRetransmitCount.HandshakeConfirmed",
- connection()->GetStats().crypto_retransmit_count);
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicSession.MaxConsecutiveRtoWithForwardProgress",
- connection()->GetStats().max_consecutive_rto_with_forward_progress);
- UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumPingsSent",
- connection()->GetStats().ping_frames_sent);
- UMA_HISTOGRAM_LONG_TIMES_100(
- "Net.QuicSession.ConnectionDuration",
- tick_clock_->NowTicks() - connect_timing_.connect_end);
- UMA_HISTOGRAM_COUNTS_100("Net.QuicSession.NumMigrations", num_migrations_);
- if (connection()->version().UsesTls()) {
- base::UmaHistogramCounts100("Net.QuicSession.KeyUpdate.PerConnection2",
- connection()->GetStats().key_update_count);
- base::UmaHistogramCounts100(
- "Net.QuicSession.KeyUpdate.PotentialPeerKeyUpdateAttemptCount",
- connection()->PotentialPeerKeyUpdateAttemptCount());
- if (last_key_update_reason_ != quic::KeyUpdateReason::kInvalid) {
- std::string suffix =
- last_key_update_reason_ == quic::KeyUpdateReason::kRemote ? "Remote"
- : "Local";
- // These values are persisted to logs. Entries should not be renumbered
- // and numeric values should never be reused.
- enum class KeyUpdateSuccess {
- kInvalid = 0,
- kSuccess = 1,
- kFailedInitial = 2,
- kFailedNonInitial = 3,
- kMaxValue = kFailedNonInitial,
- };
- KeyUpdateSuccess value = KeyUpdateSuccess::kInvalid;
- if (connection()->HaveSentPacketsInCurrentKeyPhaseButNoneAcked()) {
- if (connection()->GetStats().key_update_count >= 2) {
- value = KeyUpdateSuccess::kFailedNonInitial;
- } else {
- value = KeyUpdateSuccess::kFailedInitial;
- }
- } else {
- value = KeyUpdateSuccess::kSuccess;
- }
- base::UmaHistogramEnumeration(
- "Net.QuicSession.KeyUpdate.Success." + suffix, value);
- }
- }
- } else {
- if (error == quic::QUIC_PUBLIC_RESET) {
- RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
- } else if (connection()->GetStats().packets_received == 0) {
- RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
- base::UmaHistogramSparse(
- "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
- error);
- } else {
- RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
- base::UmaHistogramSparse(
- "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
- error);
- }
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicSession.CryptoRetransmitCount.HandshakeNotConfirmed",
- connection()->GetStats().crypto_retransmit_count);
- }
- base::UmaHistogramCounts1M(
- "Net.QuicSession.UndecryptablePacketsReceivedWithDecrypter",
- connection()->GetStats().num_failed_authentication_packets_received);
- base::UmaHistogramSparse("Net.QuicSession.QuicVersion",
- connection()->transport_version());
- NotifyFactoryOfSessionGoingAway();
- quic::QuicSession::OnConnectionClosed(frame, source);
- if (!callback_.is_null()) {
- std::move(callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
- }
- CHECK_EQ(sockets_.size(), packet_readers_.size());
- for (auto& socket : sockets_) {
- socket->Close();
- }
- DCHECK(!HasActiveRequestStreams());
- CloseAllHandles(ERR_UNEXPECTED);
- CancelAllRequests(ERR_CONNECTION_CLOSED);
- NotifyRequestsOfConfirmation(ERR_CONNECTION_CLOSED);
- NotifyFactoryOfSessionClosedLater();
- }
- void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
- const quic::ParsedQuicVersion& version) {
- logger_->OnSuccessfulVersionNegotiation(version);
- quic::QuicSpdySession::OnSuccessfulVersionNegotiation(version);
- }
- int QuicChromiumClientSession::HandleWriteError(
- int error_code,
- scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet) {
- current_migration_cause_ = ON_WRITE_ERROR;
- LogHandshakeStatusOnMigrationSignal();
- base::UmaHistogramSparse("Net.QuicSession.WriteError", -error_code);
- if (OneRttKeysAvailable()) {
- base::UmaHistogramSparse("Net.QuicSession.WriteError.HandshakeConfirmed",
- -error_code);
- }
- // For now, skip reporting if there are multiple packet writers and
- // connection migration is enabled.
- if (sockets_.size() == 1u || !migrate_session_early_v2_) {
- handles::NetworkHandle current_network = GetCurrentNetwork();
- for (auto& observer : connectivity_observer_list_) {
- observer.OnSessionEncounteringWriteError(this, current_network,
- error_code);
- }
- }
- if (error_code == ERR_MSG_TOO_BIG || stream_factory_ == nullptr ||
- !migrate_session_on_network_change_v2_ || !OneRttKeysAvailable() ||
- !version().UsesHttp3()) {
- return error_code;
- }
- handles::NetworkHandle current_network = GetCurrentNetwork();
- net_log_.AddEventWithInt64Params(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_WRITE_ERROR, "network",
- current_network);
- DCHECK(packet != nullptr);
- DCHECK_NE(ERR_IO_PENDING, error_code);
- DCHECK_GT(0, error_code);
- DCHECK(packet_ == nullptr);
- // Post a task to migrate the session onto a new network.
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&QuicChromiumClientSession::MigrateSessionOnWriteError,
- weak_factory_.GetWeakPtr(), error_code,
- connection()->writer()));
- // Only save packet from the old path for retransmission on the new path when
- // the connection ID does not change.
- if (!connection()->connection_migration_use_new_cid()) {
- // Store packet in the session since the actual migration and packet rewrite
- // can happen via this posted task or via an async network notification.
- packet_ = std::move(packet);
- }
- ignore_read_error_ = true;
- // Cause the packet writer to return ERR_IO_PENDING and block so
- // that the actual migration happens from the message loop instead
- // of under the call stack of quic::QuicConnection::WritePacket.
- return ERR_IO_PENDING;
- }
- void QuicChromiumClientSession::MigrateSessionOnWriteError(
- int error_code,
- quic::QuicPacketWriter* writer) {
- DCHECK(migrate_session_on_network_change_v2_);
- // If |writer| is no longer actively in use, abort this migration attempt.
- if (writer != connection()->writer())
- return;
- most_recent_write_error_timestamp_ = tick_clock_->NowTicks();
- most_recent_write_error_ = error_code;
- if (stream_factory_ == nullptr) {
- // Close the connection if migration failed. Do not cause a
- // connection close packet to be sent since socket may be borked.
- connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
- "Write error with nulled stream factory",
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- current_migration_cause_ = ON_WRITE_ERROR;
- if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod())
- return;
- if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
- // connection close packet to be sent since socket may be borked.
- connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
- "Write error for non-migratable session",
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- // Do not migrate if connection migration is disabled.
- if (config()->DisableConnectionMigration()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
- connection_id(),
- "Migration disabled by config");
- // Close the connection since migration was disabled. Do not cause a
- // connection close packet to be sent since socket may be borked.
- connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
- "Write error for non-migratable session",
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- handles::NetworkHandle new_network =
- stream_factory_->FindAlternateNetwork(GetCurrentNetwork());
- if (new_network == handles::kInvalidNetworkHandle) {
- // No alternate network found.
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
- connection_id(),
- "No alternate network found");
- OnNoNewNetwork();
- return;
- }
- if (GetCurrentNetwork() == default_network_ &&
- current_migrations_to_non_default_network_on_write_error_ >=
- max_migrations_to_non_default_network_on_write_error_) {
- HistogramAndLogMigrationFailure(
- MIGRATION_STATUS_ON_WRITE_ERROR_DISABLED, connection_id(),
- "Exceeds maximum number of migrations on write error");
- connection()->CloseConnection(
- quic::QUIC_PACKET_WRITE_ERROR,
- "Too many migrations for write error for the same network",
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- current_migrations_to_non_default_network_on_write_error_++;
- net_log_.BeginEventWithStringParams(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger",
- "WriteError");
- MigrationResult result =
- Migrate(new_network, ToIPEndPoint(connection()->peer_address()),
- /*close_session_on_error=*/false);
- net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED);
- if (result == MigrationResult::FAILURE) {
- // Close the connection if migration failed. Do not cause a
- // connection close packet to be sent since socket may be borked.
- connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
- "Write and subsequent migration failed",
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- if (new_network != default_network_) {
- StartMigrateBackToDefaultNetworkTimer(
- base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
- } else {
- CancelMigrateBackToDefaultNetworkTimer();
- }
- }
- void QuicChromiumClientSession::OnNoNewNetwork() {
- DCHECK(OneRttKeysAvailable());
- wait_for_new_network_ = true;
- DVLOG(1) << "Force blocking the packet writer";
- // Force blocking the packet writer to avoid any writes since there is no
- // alternate network available.
- static_cast<QuicChromiumPacketWriter*>(connection()->writer())
- ->set_force_write_blocked(true);
- // Post a task to maybe close the session if the alarm fires.
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&QuicChromiumClientSession::OnMigrationTimeout,
- weak_factory_.GetWeakPtr(), sockets_.size()),
- base::Seconds(kWaitTimeForNewNetworkSecs));
- }
- void QuicChromiumClientSession::WriteToNewSocket() {
- // Set |send_packet_after_migration_| to true so that a packet will be
- // sent when the writer becomes unblocked.
- send_packet_after_migration_ = true;
- DVLOG(1) << "Cancel force blocking the packet writer";
- // Notify writer that it is no longer forced blocked, which may call
- // OnWriteUnblocked() if the writer has no write in progress.
- static_cast<QuicChromiumPacketWriter*>(connection()->writer())
- ->set_force_write_blocked(false);
- }
- void QuicChromiumClientSession::OnMigrationTimeout(size_t num_sockets) {
- // If number of sockets has changed, this migration task is stale.
- if (num_sockets != sockets_.size())
- return;
- int net_error = current_migration_cause_ == ON_NETWORK_DISCONNECTED
- ? ERR_INTERNET_DISCONNECTED
- : ERR_NETWORK_CHANGED;
- // |current_migration_cause_| will be reset after logging.
- LogMigrationResultToHistogram(MIGRATION_STATUS_TIMEOUT);
- CloseSessionOnError(net_error, quic::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- }
- void QuicChromiumClientSession::OnPortMigrationProbeSucceeded(
- handles::NetworkHandle network,
- const quic::QuicSocketAddress& peer_address,
- const quic::QuicSocketAddress& self_address,
- std::unique_ptr<DatagramClientSocket> socket,
- std::unique_ptr<QuicChromiumPacketWriter> writer,
- std::unique_ptr<QuicChromiumPacketReader> reader) {
- DCHECK(socket);
- DCHECK(writer);
- DCHECK(reader);
- net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
- [&] {
- return NetLogProbingResultParams(network, &peer_address,
- /*is_success=*/true);
- });
- LogProbeResultToHistogram(current_migration_cause_, true);
- // Remove |this| as the old packet writer's delegate. Write error on old
- // writers will be ignored.
- // Set |this| to listen on socket write events on the packet writer
- // that was used for probing.
- static_cast<QuicChromiumPacketWriter*>(connection()->writer())
- ->set_delegate(nullptr);
- writer->set_delegate(this);
- if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
- // If idle sessions won't be migrated, close the connection.
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
- quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod())
- return;
- // Migrate to the probed socket immediately: socket, writer and reader will
- // be acquired by connection and used as default on success.
- if (!MigrateToSocket(self_address, peer_address, std::move(socket),
- std::move(reader), std::move(writer))) {
- LogMigrateToSocketStatus(false);
- net_log_.AddEvent(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
- return;
- }
- LogMigrateToSocketStatus(true);
- num_migrations_++;
- HistogramAndLogMigrationSuccess(connection_id());
- }
- void QuicChromiumClientSession::OnConnectionMigrationProbeSucceeded(
- handles::NetworkHandle network,
- const quic::QuicSocketAddress& peer_address,
- const quic::QuicSocketAddress& self_address,
- std::unique_ptr<DatagramClientSocket> socket,
- std::unique_ptr<QuicChromiumPacketWriter> writer,
- std::unique_ptr<QuicChromiumPacketReader> reader) {
- DCHECK(socket);
- DCHECK(writer);
- DCHECK(reader);
- net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
- [&] {
- return NetLogProbingResultParams(network, &peer_address,
- /*is_success=*/true);
- });
- if (network == handles::kInvalidNetworkHandle)
- return;
- LogProbeResultToHistogram(current_migration_cause_, true);
- // Remove |this| as the old packet writer's delegate. Write error on old
- // writers will be ignored.
- // Set |this| to listen on socket write events on the packet writer
- // that was used for probing.
- static_cast<QuicChromiumPacketWriter*>(connection()->writer())
- ->set_delegate(nullptr);
- writer->set_delegate(this);
- // Close streams that are not migratable to the probed |network|.
- ResetNonMigratableStreams();
- if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
- // If idle sessions won't be migrated, close the connection.
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
- quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod())
- return;
- // Migrate to the probed socket immediately: socket, writer and reader will
- // be acquired by connection and used as default on success.
- if (!MigrateToSocket(self_address, peer_address, std::move(socket),
- std::move(reader), std::move(writer))) {
- LogMigrateToSocketStatus(false);
- net_log_.AddEvent(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
- return;
- }
- LogMigrateToSocketStatus(true);
- net_log_.AddEventWithInt64Params(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING,
- "migrate_to_network", network);
- num_migrations_++;
- HistogramAndLogMigrationSuccess(connection_id());
- if (network == default_network_) {
- DVLOG(1) << "Client successfully migrated to default network: "
- << default_network_;
- CancelMigrateBackToDefaultNetworkTimer();
- return;
- }
- DVLOG(1) << "Client successfully got off default network after "
- << "successful probing network: " << network << ".";
- current_migrations_to_non_default_network_on_path_degrading_++;
- if (!migrate_back_to_default_timer_.IsRunning()) {
- current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK;
- // Session gets off the |default_network|, stay on |network| for now but
- // try to migrate back to default network after 1 second.
- StartMigrateBackToDefaultNetworkTimer(
- base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
- }
- }
- void QuicChromiumClientSession::OnProbeFailed(
- handles::NetworkHandle network,
- const quic::QuicSocketAddress& peer_address) {
- DCHECK(connection()->connection_migration_use_new_cid());
- net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
- [&] {
- return NetLogProbingResultParams(network, &peer_address,
- /*is_success=*/false);
- });
- LogProbeResultToHistogram(current_migration_cause_, false);
- auto* context = static_cast<QuicChromiumPathValidationContext*>(
- connection()->GetPathValidationContext());
- if (!context)
- return;
- if (context->network() == network &&
- context->peer_address() == peer_address) {
- connection()->CancelPathValidation();
- }
- if (network != handles::kInvalidNetworkHandle) {
- // Probing failure can be ignored.
- DVLOG(1) << "Connectivity probing failed on <network: " << network
- << ", peer_address: " << peer_address.ToString() << ">.";
- DVLOG_IF(1, network == default_network_ &&
- GetCurrentNetwork() != default_network_)
- << "Client probing failed on the default network, still using "
- "non-default network.";
- }
- }
- void QuicChromiumClientSession::OnNetworkConnected(
- handles::NetworkHandle network) {
- if (connection()->IsPathDegrading()) {
- base::TimeDelta duration =
- tick_clock_->NowTicks() - most_recent_path_degrading_timestamp_;
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.QuicNetworkDegradingDurationTillConnected",
- duration, base::Milliseconds(1),
- base::Minutes(10), 50);
- }
- if (!migrate_session_on_network_change_v2_ || !version().UsesHttp3())
- return;
- net_log_.AddEventWithInt64Params(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_CONNECTED,
- "connected_network", network);
- // If there was no migration waiting for new network and the path is not
- // degrading, ignore this signal.
- if (!wait_for_new_network_ && !connection()->IsPathDegrading())
- return;
- if (connection()->IsPathDegrading())
- current_migration_cause_ = NEW_NETWORK_CONNECTED_POST_PATH_DEGRADING;
- if (wait_for_new_network_) {
- wait_for_new_network_ = false;
- if (current_migration_cause_ == ON_WRITE_ERROR)
- current_migrations_to_non_default_network_on_write_error_++;
- // |wait_for_new_network_| is true, there was no working network previously.
- // |network| is now the only possible candidate, migrate immediately.
- MigrateNetworkImmediately(network);
- } else {
- // The connection is path degrading.
- DCHECK(connection()->IsPathDegrading());
- MaybeMigrateToAlternateNetworkOnPathDegrading();
- }
- }
- void QuicChromiumClientSession::OnNetworkDisconnectedV2(
- handles::NetworkHandle disconnected_network) {
- LogMetricsOnNetworkDisconnected();
- if (!migrate_session_on_network_change_v2_ || !version().UsesHttp3())
- return;
- net_log_.AddEventWithInt64Params(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_DISCONNECTED,
- "disconnected_network", disconnected_network);
- // Stop probing the disconnected network if there is one.
- if (connection()->connection_migration_use_new_cid()) {
- auto* context = static_cast<QuicChromiumPathValidationContext*>(
- connection()->GetPathValidationContext());
- if (context && context->network() == disconnected_network &&
- context->peer_address() == peer_address()) {
- connection()->CancelPathValidation();
- }
- }
- if (disconnected_network == default_network_) {
- DVLOG(1) << "Default network: " << default_network_ << " is disconnected.";
- default_network_ = handles::kInvalidNetworkHandle;
- current_migrations_to_non_default_network_on_write_error_ = 0;
- }
- // Ignore the signal if the current active network is not affected.
- if (GetCurrentNetwork() != disconnected_network) {
- DVLOG(1) << "Client's current default network is not affected by the "
- << "disconnected one.";
- return;
- }
- current_migration_cause_ = ON_NETWORK_DISCONNECTED;
- LogHandshakeStatusOnMigrationSignal();
- if (!OneRttKeysAvailable()) {
- // Close the connection if handshake is not confirmed. Migration before
- // handshake is not allowed.
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- // Attempt to find alternative network.
- handles::NetworkHandle new_network =
- stream_factory_->FindAlternateNetwork(disconnected_network);
- if (new_network == handles::kInvalidNetworkHandle) {
- OnNoNewNetwork();
- return;
- }
- // Current network is being disconnected, migrate immediately to the
- // alternative network.
- MigrateNetworkImmediately(new_network);
- }
- void QuicChromiumClientSession::OnNetworkMadeDefault(
- handles::NetworkHandle new_network) {
- LogMetricsOnNetworkMadeDefault();
- if (!migrate_session_on_network_change_v2_ || !version().UsesHttp3())
- return;
- DCHECK_NE(handles::kInvalidNetworkHandle, new_network);
- net_log_.AddEventWithInt64Params(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_MADE_DEFAULT,
- "new_default_network", new_network);
- default_network_ = new_network;
- DVLOG(1) << "Network: " << new_network
- << " becomes default, old default: " << default_network_;
- current_migration_cause_ = ON_NETWORK_MADE_DEFAULT;
- current_migrations_to_non_default_network_on_write_error_ = 0;
- current_migrations_to_non_default_network_on_path_degrading_ = 0;
- // Simply cancel the timer to migrate back to the default network if session
- // is already on the default network.
- if (GetCurrentNetwork() == new_network) {
- CancelMigrateBackToDefaultNetworkTimer();
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_ALREADY_MIGRATED,
- connection_id(),
- "Already migrated on the new network");
- return;
- }
- LogHandshakeStatusOnMigrationSignal();
- // Stay on the current network. Try to migrate back to default network
- // without any delay, which will start probing the new default network and
- // migrate to the new network immediately on success.
- StartMigrateBackToDefaultNetworkTimer(base::TimeDelta());
- }
- void QuicChromiumClientSession::MigrateNetworkImmediately(
- handles::NetworkHandle network) {
- // There is no choice but to migrate to |network|. If any error encountered,
- // close the session. When migration succeeds:
- // - if no longer on the default network, start timer to migrate back;
- // - otherwise, it's brought to default network, cancel the running timer to
- // migrate back.
- DCHECK(migrate_session_on_network_change_v2_ && version().UsesHttp3());
- if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
- connection_id(), "No active streams");
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod())
- return;
- // Do not migrate if connection migration is disabled.
- if (config()->DisableConnectionMigration()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
- connection_id(),
- "Migration disabled by config");
- CloseSessionOnErrorLater(ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- if (network == GetCurrentNetwork()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_ALREADY_MIGRATED,
- connection_id(),
- "Already bound to new network");
- return;
- }
- // Cancel probing on |network| if there is any.
- if (connection()->connection_migration_use_new_cid()) {
- auto* context = static_cast<QuicChromiumPathValidationContext*>(
- connection()->GetPathValidationContext());
- if (context && context->network() == network &&
- context->peer_address() == peer_address()) {
- connection()->CancelPathValidation();
- }
- }
- MigrationResult result =
- Migrate(network, ToIPEndPoint(connection()->peer_address()),
- /*close_session_on_error=*/true);
- if (result == MigrationResult::FAILURE)
- return;
- if (network == default_network_) {
- CancelMigrateBackToDefaultNetworkTimer();
- return;
- }
- // TODO(zhongyi): reconsider this, maybe we just want to hear back
- // We are forced to migrate to |network|, probably |default_network_| is
- // not working, start to migrate back to default network after 1 secs.
- StartMigrateBackToDefaultNetworkTimer(
- base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
- }
- void QuicChromiumClientSession::OnWriteError(int error_code) {
- DCHECK_NE(ERR_IO_PENDING, error_code);
- DCHECK_GT(0, error_code);
- connection()->OnWriteError(error_code);
- }
- void QuicChromiumClientSession::OnWriteUnblocked() {
- DCHECK(!connection()->writer()->IsWriteBlocked());
- // A new packet will be written after migration completes, unignore read
- // errors.
- if (ignore_read_error_)
- ignore_read_error_ = false;
- if (packet_) {
- DCHECK(send_packet_after_migration_);
- send_packet_after_migration_ = false;
- static_cast<QuicChromiumPacketWriter*>(connection()->writer())
- ->WritePacketToSocket(std::move(packet_));
- return;
- }
- // Unblock the connection, which may send queued packets.
- connection()->OnCanWrite();
- if (send_packet_after_migration_) {
- send_packet_after_migration_ = false;
- if (!connection()->writer()->IsWriteBlocked()) {
- connection()->SendPing();
- }
- }
- }
- void QuicChromiumClientSession::OnPathDegrading() {
- if (most_recent_path_degrading_timestamp_ == base::TimeTicks())
- most_recent_path_degrading_timestamp_ = tick_clock_->NowTicks();
- handles::NetworkHandle current_network = GetCurrentNetwork();
- for (auto& observer : connectivity_observer_list_)
- observer.OnSessionPathDegrading(this, current_network);
- if (!stream_factory_)
- return;
- if (allow_port_migration_ && !migrate_session_early_v2_) {
- MaybeMigrateToDifferentPortOnPathDegrading();
- return;
- }
- MaybeMigrateToAlternateNetworkOnPathDegrading();
- }
- void QuicChromiumClientSession::OnForwardProgressMadeAfterPathDegrading() {
- handles::NetworkHandle current_network = GetCurrentNetwork();
- for (auto& observer : connectivity_observer_list_)
- observer.OnSessionResumedPostPathDegrading(this, current_network);
- }
- void QuicChromiumClientSession::OnKeyUpdate(quic::KeyUpdateReason reason) {
- net_log_.AddEventWithStringParams(NetLogEventType::QUIC_SESSION_KEY_UPDATE,
- "reason",
- quic::KeyUpdateReasonString(reason));
- base::UmaHistogramEnumeration("Net.QuicSession.KeyUpdate.Reason", reason);
- last_key_update_reason_ = reason;
- }
- void QuicChromiumClientSession::OnProofValid(
- const quic::QuicCryptoClientConfig::CachedState& cached) {
- DCHECK(cached.proof_valid());
- if (!server_info_) {
- return;
- }
- QuicServerInfo::State* state = server_info_->mutable_state();
- state->server_config = cached.server_config();
- state->source_address_token = cached.source_address_token();
- state->cert_sct = cached.cert_sct();
- state->chlo_hash = cached.chlo_hash();
- state->server_config_sig = cached.signature();
- state->certs = cached.certs();
- server_info_->Persist();
- }
- void QuicChromiumClientSession::OnProofVerifyDetailsAvailable(
- const quic::ProofVerifyDetails& verify_details) {
- const ProofVerifyDetailsChromium* verify_details_chromium =
- reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
- cert_verify_result_ = std::make_unique<CertVerifyResult>(
- verify_details_chromium->cert_verify_result);
- pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
- logger_->OnCertificateVerified(*cert_verify_result_);
- pkp_bypassed_ = verify_details_chromium->pkp_bypassed;
- is_fatal_cert_error_ = verify_details_chromium->is_fatal_cert_error;
- }
- void QuicChromiumClientSession::StartReading() {
- for (auto& packet_reader : packet_readers_) {
- packet_reader->StartReading();
- }
- }
- void QuicChromiumClientSession::CloseSessionOnError(
- int net_error,
- quic::QuicErrorCode quic_error,
- quic::ConnectionCloseBehavior behavior) {
- base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error);
- if (!callback_.is_null()) {
- std::move(callback_).Run(net_error);
- }
- NotifyAllStreamsOfError(net_error);
- net_log_.AddEventWithIntParams(NetLogEventType::QUIC_SESSION_CLOSE_ON_ERROR,
- "net_error", net_error);
- if (connection()->connected())
- connection()->CloseConnection(quic_error, "net error", behavior);
- DCHECK(!connection()->connected());
- CloseAllHandles(net_error);
- NotifyFactoryOfSessionClosed();
- }
- void QuicChromiumClientSession::CloseSessionOnErrorLater(
- int net_error,
- quic::QuicErrorCode quic_error,
- quic::ConnectionCloseBehavior behavior) {
- base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error);
- if (!callback_.is_null()) {
- std::move(callback_).Run(net_error);
- }
- NotifyAllStreamsOfError(net_error);
- CloseAllHandles(net_error);
- net_log_.AddEventWithIntParams(NetLogEventType::QUIC_SESSION_CLOSE_ON_ERROR,
- "net_error", net_error);
- if (connection()->connected())
- connection()->CloseConnection(quic_error, "net error", behavior);
- DCHECK(!connection()->connected());
- NotifyFactoryOfSessionClosedLater();
- }
- void QuicChromiumClientSession::NotifyAllStreamsOfError(int net_error) {
- PerformActionOnActiveStreams([net_error](quic::QuicStream* stream) {
- static_cast<QuicChromiumClientStream*>(stream)->OnError(net_error);
- return true;
- });
- }
- void QuicChromiumClientSession::CloseAllHandles(int net_error) {
- while (!handles_.empty()) {
- Handle* handle = *handles_.begin();
- handles_.erase(handle);
- handle->OnSessionClosed(connection()->version(), net_error, error(),
- port_migration_detected_,
- quic_connection_migration_attempted_,
- quic_connection_migration_successful_,
- GetConnectTiming(), WasConnectionEverUsed());
- }
- }
- void QuicChromiumClientSession::CancelAllRequests(int net_error) {
- UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.AbortedPendingStreamRequests",
- stream_requests_.size());
- while (!stream_requests_.empty()) {
- StreamRequest* request = stream_requests_.front();
- stream_requests_.pop_front();
- request->OnRequestCompleteFailure(net_error);
- }
- }
- void QuicChromiumClientSession::NotifyRequestsOfConfirmation(int net_error) {
- // Post tasks to avoid reentrancy.
- for (auto& callback : waiting_for_confirmation_callbacks_)
- task_runner_->PostTask(FROM_HERE,
- base::BindOnce(std::move(callback), net_error));
- waiting_for_confirmation_callbacks_.clear();
- }
- void QuicChromiumClientSession::MaybeMigrateToDifferentPortOnPathDegrading() {
- DCHECK(allow_port_migration_ && !migrate_session_early_v2_);
- current_migration_cause_ = CHANGE_PORT_ON_PATH_DEGRADING;
- if (!version().UsesHttp3())
- return;
- // Migration before handshake confirmed is not allowed.
- if (!connection()->IsHandshakeConfirmed()) {
- HistogramAndLogMigrationFailure(
- MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED,
- connection_id(), "Path degrading before handshake confirmed");
- return;
- }
- if (config()->DisableConnectionMigration()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
- connection_id(),
- "Migration disabled by config");
- return;
- }
- net_log_.BeginEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED);
- if (!stream_factory_)
- return;
- // Probe a different port, session will migrate to the probed port on success.
- StartProbing(default_network_, peer_address());
- net_log_.EndEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED);
- }
- void QuicChromiumClientSession::
- MaybeMigrateToAlternateNetworkOnPathDegrading() {
- net_log_.AddEvent(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_PATH_DEGRADING);
- current_migration_cause_ = CHANGE_NETWORK_ON_PATH_DEGRADING;
- if (!migrate_session_early_v2_ || !version().UsesHttp3()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED,
- connection_id(),
- "Migration on path degrading not enabled");
- return;
- }
- if (GetCurrentNetwork() == default_network_ &&
- current_migrations_to_non_default_network_on_path_degrading_ >=
- max_migrations_to_non_default_network_on_path_degrading_) {
- HistogramAndLogMigrationFailure(
- MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, connection_id(),
- "Exceeds maximum number of migrations on path degrading");
- return;
- }
- handles::NetworkHandle alternate_network =
- stream_factory_->FindAlternateNetwork(GetCurrentNetwork());
- if (alternate_network == handles::kInvalidNetworkHandle) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
- connection_id(),
- "No alternative network on path degrading");
- return;
- }
- LogHandshakeStatusOnMigrationSignal();
- if (!connection()->IsHandshakeConfirmed()) {
- HistogramAndLogMigrationFailure(
- MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED,
- connection_id(), "Path degrading before handshake confirmed");
- return;
- }
- net_log_.BeginEventWithStringParams(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger",
- "PathDegrading");
- // Probe the alternative network, session will migrate to the probed
- // network and decide whether it wants to migrate back to the default
- // network on success.
- MaybeStartProbing(alternate_network, peer_address());
- net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED);
- }
- ProbingResult QuicChromiumClientSession::MaybeStartProbing(
- handles::NetworkHandle network,
- const quic::QuicSocketAddress& peer_address) {
- if (!stream_factory_)
- return ProbingResult::FAILURE;
- CHECK_NE(handles::kInvalidNetworkHandle, network);
- if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
- connection_id(), "No active streams");
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
- quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return ProbingResult::DISABLED_WITH_IDLE_SESSION;
- }
- if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod())
- return ProbingResult::DISABLED_WITH_IDLE_SESSION;
- // Abort probing if connection migration is disabled by config.
- if (!connection()->connection_migration_use_new_cid()) {
- DVLOG(1) << "Client IETF connection migration is not enabled.";
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_NOT_ENABLED,
- connection_id(),
- "IETF migration flag is false");
- return ProbingResult::DISABLED_BY_CONFIG;
- }
- if (config()->DisableConnectionMigration()) {
- DVLOG(1) << "Client disables probing network with connection migration "
- << "disabled by config";
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
- connection_id(),
- "Migration disabled by config");
- return ProbingResult::DISABLED_BY_CONFIG;
- }
- return StartProbing(network, peer_address);
- }
- ProbingResult QuicChromiumClientSession::StartProbing(
- handles::NetworkHandle network,
- const quic::QuicSocketAddress& peer_address) {
- if (!connection()->connection_migration_use_new_cid()) {
- return ProbingResult::DISABLED_BY_CONFIG;
- }
- // Check if probing manager is probing the same path.
- auto* existing_context = static_cast<QuicChromiumPathValidationContext*>(
- connection()->GetPathValidationContext());
- if (existing_context && existing_context->network() == network &&
- existing_context->peer_address() == peer_address) {
- return ProbingResult::PENDING;
- }
- // Create and configure socket on |network|.
- std::unique_ptr<DatagramClientSocket> probing_socket =
- stream_factory_->CreateSocket(net_log_.net_log(), net_log_.source());
- if (stream_factory_->ConfigureSocket(probing_socket.get(),
- ToIPEndPoint(peer_address), network,
- session_key_.socket_tag()) != OK) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_INTERNAL_ERROR,
- connection_id(),
- "Socket configuration failed");
- return ProbingResult::INTERNAL_ERROR;
- }
- // Create new packet writer and reader on the probing socket.
- auto probing_writer = std::make_unique<QuicChromiumPacketWriter>(
- probing_socket.get(), task_runner_);
- auto probing_reader = std::make_unique<QuicChromiumPacketReader>(
- probing_socket.get(), clock_, this, yield_after_packets_,
- yield_after_duration_, net_log_);
- probing_reader->StartReading();
- path_validation_writer_delegate_.set_network(network);
- path_validation_writer_delegate_.set_peer_address(peer_address);
- probing_writer->set_delegate(&path_validation_writer_delegate_);
- IPEndPoint local_address;
- probing_socket->GetLocalAddress(&local_address);
- auto context = std::make_unique<QuicChromiumPathValidationContext>(
- ToQuicSocketAddress(local_address), peer_address, network,
- std::move(probing_socket), std::move(probing_writer),
- std::move(probing_reader));
- if (current_migration_cause_ != CHANGE_PORT_ON_PATH_DEGRADING) {
- ValidatePath(
- std::move(context),
- std::make_unique<ConnectionMigrationValidationResultDelegate>(this));
- return ProbingResult::PENDING;
- }
- ValidatePath(std::move(context),
- std::make_unique<PortMigrationValidationResultDelegate>(this));
- return ProbingResult::PENDING;
- }
- void QuicChromiumClientSession::StartMigrateBackToDefaultNetworkTimer(
- base::TimeDelta delay) {
- if (current_migration_cause_ != ON_NETWORK_MADE_DEFAULT)
- current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK;
- CancelMigrateBackToDefaultNetworkTimer();
- // Post a task to try migrate back to default network after |delay|.
- migrate_back_to_default_timer_.Start(
- FROM_HERE, delay,
- base::BindOnce(
- &QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork,
- weak_factory_.GetWeakPtr()));
- }
- void QuicChromiumClientSession::CancelMigrateBackToDefaultNetworkTimer() {
- retry_migrate_back_count_ = 0;
- migrate_back_to_default_timer_.Stop();
- }
- void QuicChromiumClientSession::TryMigrateBackToDefaultNetwork(
- base::TimeDelta timeout) {
- if (default_network_ == handles::kInvalidNetworkHandle) {
- DVLOG(1) << "Default network is not connected";
- return;
- }
- net_log_.AddEventWithInt64Params(
- NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_MIGRATE_BACK, "retry_count",
- retry_migrate_back_count_);
- // Start probe default network immediately, if manager is probing
- // the same network, this will be a no-op. Otherwise, previous probe
- // will be cancelled and manager starts to probe |default_network_|
- // immediately.
- ProbingResult result = MaybeStartProbing(default_network_, peer_address());
- if (result == ProbingResult::DISABLED_WITH_IDLE_SESSION)
- return;
- if (result != ProbingResult::PENDING) {
- // Session is not allowed to migrate, mark session as going away, cancel
- // migrate back to default timer.
- NotifyFactoryOfSessionGoingAway();
- CancelMigrateBackToDefaultNetworkTimer();
- return;
- }
- retry_migrate_back_count_++;
- migrate_back_to_default_timer_.Start(
- FROM_HERE, timeout,
- base::BindOnce(
- &QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork,
- weak_factory_.GetWeakPtr()));
- }
- void QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork() {
- base::TimeDelta retry_migrate_back_timeout =
- base::Seconds(UINT64_C(1) << retry_migrate_back_count_);
- if (default_network_ == GetCurrentNetwork()) {
- // If session has been back on the default already by other direct
- // migration attempt, cancel migrate back now.
- CancelMigrateBackToDefaultNetworkTimer();
- return;
- }
- if (retry_migrate_back_timeout > max_time_on_non_default_network_) {
- // Mark session as going away to accept no more streams.
- NotifyFactoryOfSessionGoingAway();
- return;
- }
- TryMigrateBackToDefaultNetwork(retry_migrate_back_timeout);
- }
- bool QuicChromiumClientSession::CheckIdleTimeExceedsIdleMigrationPeriod() {
- if (!migrate_idle_session_)
- return false;
- if (HasActiveRequestStreams()) {
- return false;
- }
- // There are no active/drainning streams, check the last stream's finish time.
- if (tick_clock_->NowTicks() - most_recent_stream_close_time_ <
- idle_migration_period_) {
- // Still within the idle migration period.
- return false;
- }
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_IDLE_MIGRATION_TIMEOUT,
- connection_id(),
- "Ilde migration period exceeded");
- CloseSessionOnErrorLater(ERR_NETWORK_CHANGED, quic::QUIC_NETWORK_IDLE_TIMEOUT,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return true;
- }
- void QuicChromiumClientSession::ResetNonMigratableStreams() {
- // TODO(zhongyi): may close non-migratable draining streams as well to avoid
- // sending additional data on alternate networks.
- PerformActionOnActiveStreams([](quic::QuicStream* stream) {
- QuicChromiumClientStream* chrome_stream =
- static_cast<QuicChromiumClientStream*>(stream);
- if (!chrome_stream->can_migrate_to_cellular_network()) {
- // Close the stream in both direction by resetting the stream.
- // TODO(zhongyi): use a different error code to reset streams for
- // connection migration.
- chrome_stream->Reset(quic::QUIC_STREAM_CANCELLED);
- }
- return true;
- });
- }
- void QuicChromiumClientSession::LogMetricsOnNetworkDisconnected() {
- if (most_recent_path_degrading_timestamp_ != base::TimeTicks()) {
- most_recent_network_disconnected_timestamp_ = tick_clock_->NowTicks();
- base::TimeDelta degrading_duration =
- most_recent_network_disconnected_timestamp_ -
- most_recent_path_degrading_timestamp_;
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.QuicNetworkDegradingDurationTillDisconnected", degrading_duration,
- base::Milliseconds(1), base::Minutes(10), 100);
- }
- if (most_recent_write_error_timestamp_ != base::TimeTicks()) {
- base::TimeDelta write_error_to_disconnection_gap =
- most_recent_network_disconnected_timestamp_ -
- most_recent_write_error_timestamp_;
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.QuicNetworkGapBetweenWriteErrorAndDisconnection",
- write_error_to_disconnection_gap, base::Milliseconds(1),
- base::Minutes(10), 100);
- base::UmaHistogramSparse("Net.QuicSession.WriteError.NetworkDisconnected",
- -most_recent_write_error_);
- most_recent_write_error_ = 0;
- most_recent_write_error_timestamp_ = base::TimeTicks();
- }
- }
- void QuicChromiumClientSession::LogMetricsOnNetworkMadeDefault() {
- if (most_recent_path_degrading_timestamp_ != base::TimeTicks()) {
- if (most_recent_network_disconnected_timestamp_ != base::TimeTicks()) {
- // NetworkDiscconected happens before NetworkMadeDefault, the platform
- // is dropping WiFi.
- base::TimeTicks now = tick_clock_->NowTicks();
- base::TimeDelta disconnection_duration =
- now - most_recent_network_disconnected_timestamp_;
- base::TimeDelta degrading_duration =
- now - most_recent_path_degrading_timestamp_;
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.QuicNetworkDisconnectionDuration",
- disconnection_duration, base::Milliseconds(1),
- base::Minutes(10), 100);
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.QuicNetworkDegradingDurationTillNewNetworkMadeDefault",
- degrading_duration, base::Milliseconds(1), base::Minutes(10), 100);
- most_recent_network_disconnected_timestamp_ = base::TimeTicks();
- }
- most_recent_path_degrading_timestamp_ = base::TimeTicks();
- }
- }
- void QuicChromiumClientSession::LogMigrationResultToHistogram(
- QuicConnectionMigrationStatus status) {
- if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PortMigration", status,
- MIGRATION_STATUS_MAX);
- current_migration_cause_ = UNKNOWN_CAUSE;
- return;
- }
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status,
- MIGRATION_STATUS_MAX);
- // Log the connection migraiton result to different histograms based on the
- // cause of the connection migration.
- std::string histogram_name = "Net.QuicSession.ConnectionMigration." +
- MigrationCauseToString(current_migration_cause_);
- base::UmaHistogramEnumeration(histogram_name, status, MIGRATION_STATUS_MAX);
- current_migration_cause_ = UNKNOWN_CAUSE;
- }
- void QuicChromiumClientSession::LogHandshakeStatusOnMigrationSignal() const {
- if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.HandshakeStatusOnPortMigration",
- OneRttKeysAvailable());
- return;
- }
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.HandshakeStatusOnConnectionMigration",
- OneRttKeysAvailable());
- const std::string histogram_name =
- "Net.QuicSession.HandshakeStatusOnConnectionMigration." +
- MigrationCauseToString(current_migration_cause_);
- STATIC_HISTOGRAM_POINTER_GROUP(
- histogram_name, current_migration_cause_, MIGRATION_CAUSE_MAX,
- AddBoolean(OneRttKeysAvailable()),
- base::BooleanHistogram::FactoryGet(
- histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag));
- }
- void QuicChromiumClientSession::HistogramAndLogMigrationFailure(
- QuicConnectionMigrationStatus status,
- quic::QuicConnectionId connection_id,
- const char* reason) {
- NetLogEventType event_type =
- current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING
- ? NetLogEventType::QUIC_PORT_MIGRATION_FAILURE
- : NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE;
- net_log_.AddEvent(event_type, [&] {
- return NetLogQuicMigrationFailureParams(connection_id, reason);
- });
- // |current_migration_cause_| will be reset afterwards.
- LogMigrationResultToHistogram(status);
- }
- void QuicChromiumClientSession::HistogramAndLogMigrationSuccess(
- quic::QuicConnectionId connection_id) {
- NetLogEventType event_type =
- current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING
- ? NetLogEventType::QUIC_PORT_MIGRATION_SUCCESS
- : NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS;
- net_log_.AddEvent(event_type, [&] {
- return NetLogQuicMigrationSuccessParams(connection_id);
- });
- // |current_migration_cause_| will be reset afterwards.
- LogMigrationResultToHistogram(MIGRATION_STATUS_SUCCESS);
- }
- base::Value QuicChromiumClientSession::GetInfoAsValue(
- const std::set<HostPortPair>& aliases) {
- base::Value::Dict dict;
- dict.Set("version", ParsedQuicVersionToString(connection()->version()));
- dict.Set("open_streams", static_cast<int>(GetNumActiveStreams()));
- base::Value::List stream_list;
- auto* stream_list_ptr = &stream_list;
- PerformActionOnActiveStreams([stream_list_ptr](quic::QuicStream* stream) {
- stream_list_ptr->Append(base::NumberToString(stream->id()));
- return true;
- });
- dict.Set("active_streams", std::move(stream_list));
- dict.Set("total_streams", static_cast<int>(num_total_streams_));
- dict.Set("peer_address", peer_address().ToString());
- dict.Set("network_isolation_key",
- session_key_.network_isolation_key().ToDebugString());
- dict.Set("connection_id", connection_id().ToString());
- if (!connection()->client_connection_id().IsEmpty()) {
- dict.Set("client_connection_id",
- connection()->client_connection_id().ToString());
- }
- dict.Set("connected", connection()->connected());
- const quic::QuicConnectionStats& stats = connection()->GetStats();
- dict.Set("packets_sent", static_cast<int>(stats.packets_sent));
- dict.Set("packets_received", static_cast<int>(stats.packets_received));
- dict.Set("packets_lost", static_cast<int>(stats.packets_lost));
- SSLInfo ssl_info;
- base::Value::List alias_list;
- for (const auto& alias : aliases) {
- alias_list.Append(alias.ToString());
- }
- dict.Set("aliases", std::move(alias_list));
- return base::Value(std::move(dict));
- }
- bool QuicChromiumClientSession::gquic_zero_rtt_disabled() const {
- if (!stream_factory_)
- return false;
- return stream_factory_->gquic_zero_rtt_disabled();
- }
- std::unique_ptr<QuicChromiumClientSession::Handle>
- QuicChromiumClientSession::CreateHandle(url::SchemeHostPort destination) {
- return std::make_unique<QuicChromiumClientSession::Handle>(
- weak_factory_.GetWeakPtr(), std::move(destination));
- }
- bool QuicChromiumClientSession::OnReadError(
- int result,
- const DatagramClientSocket* socket) {
- DCHECK(socket != nullptr);
- base::UmaHistogramSparse("Net.QuicSession.ReadError.AnyNetwork", -result);
- if (socket != GetDefaultSocket()) {
- DVLOG(1) << "Ignoring read error " << ErrorToString(result)
- << " on old socket";
- base::UmaHistogramSparse("Net.QuicSession.ReadError.OtherNetworks",
- -result);
- // Ignore read errors from sockets that are not affecting the current
- // network, i.e., sockets that are no longer active and probing socket.
- // TODO(jri): Maybe clean up old sockets on error.
- return false;
- }
- if (ignore_read_error_) {
- DVLOG(1) << "Ignoring read error " << ErrorToString(result)
- << " during pending migration";
- // Ignore read errors during pending migration. Connection will be closed if
- // pending migration failed or timed out.
- base::UmaHistogramSparse("Net.QuicSession.ReadError.PendingMigration",
- -result);
- return false;
- }
- base::UmaHistogramSparse("Net.QuicSession.ReadError.CurrentNetwork", -result);
- if (OneRttKeysAvailable()) {
- base::UmaHistogramSparse(
- "Net.QuicSession.ReadError.CurrentNetwork.HandshakeConfirmed", -result);
- }
- DVLOG(1) << "Closing session on read error " << ErrorToString(result);
- connection()->CloseConnection(quic::QUIC_PACKET_READ_ERROR,
- ErrorToString(result),
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- return false;
- }
- bool QuicChromiumClientSession::OnPacket(
- const quic::QuicReceivedPacket& packet,
- const quic::QuicSocketAddress& local_address,
- const quic::QuicSocketAddress& peer_address) {
- ProcessUdpPacket(local_address, peer_address, packet);
- if (!connection()->connected()) {
- NotifyFactoryOfSessionClosedLater();
- return false;
- }
- return true;
- }
- void QuicChromiumClientSession::NotifyFactoryOfSessionGoingAway() {
- going_away_ = true;
- if (stream_factory_)
- stream_factory_->OnSessionGoingAway(this);
- }
- void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
- going_away_ = true;
- DCHECK_EQ(0u, GetNumActiveStreams());
- DCHECK(!connection()->connected());
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&QuicChromiumClientSession::NotifyFactoryOfSessionClosed,
- weak_factory_.GetWeakPtr()));
- }
- void QuicChromiumClientSession::NotifyFactoryOfSessionClosed() {
- going_away_ = true;
- DCHECK_EQ(0u, GetNumActiveStreams());
- // Will delete |this|.
- if (stream_factory_)
- stream_factory_->OnSessionClosed(this);
- }
- void QuicChromiumClientSession::OnCryptoHandshakeComplete() {
- if (stream_factory_)
- stream_factory_->set_is_quic_known_to_work_on_current_network(true);
- // Update |connect_end| only when handshake is confirmed. This should also
- // take care of any failed 0-RTT request.
- connect_timing_.connect_end = tick_clock_->NowTicks();
- DCHECK_LE(connect_timing_.connect_start, connect_timing_.connect_end);
- UMA_HISTOGRAM_TIMES(
- "Net.QuicSession.HandshakeConfirmedTime",
- connect_timing_.connect_end - connect_timing_.connect_start);
- // Track how long it has taken to finish handshake after we have finished
- // DNS host resolution.
- if (!connect_timing_.dns_end.is_null()) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolution.HandshakeConfirmedTime",
- tick_clock_->NowTicks() - connect_timing_.dns_end);
- }
- auto it = handles_.begin();
- while (it != handles_.end()) {
- Handle* handle = *it;
- ++it;
- handle->OnCryptoHandshakeConfirmed();
- }
- NotifyRequestsOfConfirmation(OK);
- // Attempt to migrate back to the default network after handshake has been
- // confirmed if the session is not created on the default network.
- if (migrate_session_on_network_change_v2_ &&
- default_network_ != handles::kInvalidNetworkHandle &&
- GetCurrentNetwork() != default_network_ && version().UsesHttp3()) {
- current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK;
- StartMigrateBackToDefaultNetworkTimer(
- base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
- }
- }
- MigrationResult QuicChromiumClientSession::Migrate(
- handles::NetworkHandle network,
- IPEndPoint peer_address,
- bool close_session_on_error) {
- quic_connection_migration_attempted_ = true;
- quic_connection_migration_successful_ = false;
- if (!stream_factory_)
- return MigrationResult::FAILURE;
- if (network != handles::kInvalidNetworkHandle) {
- // This is a migration attempt from connection migration.
- ResetNonMigratableStreams();
- if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
- // If idle sessions can not be migrated, close the session if needed.
- if (close_session_on_error) {
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- }
- return MigrationResult::FAILURE;
- }
- }
- // Create and configure socket on |network|.
- std::unique_ptr<DatagramClientSocket> socket(
- stream_factory_->CreateSocket(net_log_.net_log(), net_log_.source()));
- if (stream_factory_->ConfigureSocket(socket.get(), peer_address, network,
- session_key_.socket_tag()) != OK) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_INTERNAL_ERROR,
- connection_id(),
- "Socket configuration failed");
- if (close_session_on_error) {
- if (migrate_session_on_network_change_v2_) {
- CloseSessionOnErrorLater(ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- } else {
- CloseSessionOnError(ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- }
- }
- return MigrationResult::FAILURE;
- }
- // Create new packet reader and writer on the new socket.
- auto new_reader = std::make_unique<QuicChromiumPacketReader>(
- socket.get(), clock_, this, yield_after_packets_, yield_after_duration_,
- net_log_);
- new_reader->StartReading();
- auto new_writer =
- std::make_unique<QuicChromiumPacketWriter>(socket.get(), task_runner_);
- static_cast<QuicChromiumPacketWriter*>(connection()->writer())
- ->set_delegate(nullptr);
- new_writer->set_delegate(this);
- IPEndPoint self_address;
- socket->GetLocalAddress(&self_address);
- // Migrate to the new socket.
- if (!MigrateToSocket(ToQuicSocketAddress(self_address),
- ToQuicSocketAddress(peer_address), std::move(socket),
- std::move(new_reader), std::move(new_writer))) {
- if (close_session_on_error) {
- if (migrate_session_on_network_change_v2_) {
- CloseSessionOnErrorLater(
- ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- } else {
- CloseSessionOnError(ERR_NETWORK_CHANGED,
- quic::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
- quic::ConnectionCloseBehavior::SILENT_CLOSE);
- }
- }
- return MigrationResult::FAILURE;
- }
- quic_connection_migration_successful_ = true;
- HistogramAndLogMigrationSuccess(connection_id());
- return MigrationResult::SUCCESS;
- }
- bool QuicChromiumClientSession::MigrateToSocket(
- const quic::QuicSocketAddress& self_address,
- const quic::QuicSocketAddress& peer_address,
- std::unique_ptr<DatagramClientSocket> socket,
- std::unique_ptr<QuicChromiumPacketReader> reader,
- std::unique_ptr<QuicChromiumPacketWriter> writer) {
- CHECK_EQ(sockets_.size(), packet_readers_.size());
- // TODO(zhongyi): figure out whether we want to limit the number of
- // connection migrations for v2, which includes migration on platform signals,
- // write error events, and path degrading on original network.
- if (!migrate_session_on_network_change_v2_ &&
- sockets_.size() >= kMaxReadersPerQuicSession) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_TOO_MANY_CHANGES,
- connection_id(), "Too many changes");
- return false;
- }
- packet_readers_.push_back(std::move(reader));
- sockets_.push_back(std::move(socket));
- // Froce the writer to be blocked to prevent it being used until
- // WriteToNewSocket completes.
- DVLOG(1) << "Force blocking the packet writer";
- writer->set_force_write_blocked(true);
- if (!MigratePath(self_address, peer_address, writer.release(),
- /*owns_writer=*/true)) {
- HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_UNUSED_CONNECTION_ID,
- connection_id(),
- "No unused server connection ID");
- DVLOG(1) << "MigratePath fails as there is no CID available";
- return false;
- }
- // Post task to write the pending packet or a PING packet to the new
- // socket. This avoids reentrancy issues if there is a write error
- // on the write to the new socket.
- task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&QuicChromiumClientSession::WriteToNewSocket,
- weak_factory_.GetWeakPtr()));
- return true;
- }
- void QuicChromiumClientSession::PopulateNetErrorDetails(
- NetErrorDetails* details) const {
- details->quic_port_migration_detected = port_migration_detected_;
- details->quic_connection_error = error();
- details->quic_connection_migration_attempted =
- quic_connection_migration_attempted_;
- details->quic_connection_migration_successful =
- quic_connection_migration_successful_;
- }
- const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
- const {
- DCHECK(sockets_.back().get() != nullptr);
- // The most recently added socket is the currently active one.
- return sockets_.back().get();
- }
- handles::NetworkHandle QuicChromiumClientSession::GetCurrentNetwork() const {
- // If connection migration is enabled, alternate network interface may be
- // used to send packet, it is identified as the bound network of the default
- // socket. Otherwise, always use |default_network_|.
- return migrate_session_on_network_change_v2_
- ? GetDefaultSocket()->GetBoundNetwork()
- : default_network_;
- }
- bool QuicChromiumClientSession::IsAuthorized(const std::string& hostname) {
- bool result = CanPool(hostname, session_key_);
- if (result)
- streams_pushed_count_++;
- return result;
- }
- bool QuicChromiumClientSession::HandlePromised(
- quic::QuicStreamId id,
- quic::QuicStreamId promised_id,
- const spdy::Http2HeaderBlock& headers) {
- bool result =
- quic::QuicSpdyClientSessionBase::HandlePromised(id, promised_id, headers);
- if (result) {
- // The push promise is accepted, notify the push_delegate that a push
- // promise has been received.
- if (push_delegate_) {
- std::string pushed_url =
- quic::SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers);
- push_delegate_->OnPush(std::make_unique<QuicServerPushHelper>(
- weak_factory_.GetWeakPtr(), GURL(pushed_url)),
- net_log_);
- }
- if (headers_include_h2_stream_dependency_ ||
- VersionUsesHttp3(connection()->transport_version())) {
- // Even though the promised stream will not be created until after the
- // push promise headers are received, send a PRIORITY frame for the
- // promised stream ID. Send |kDefaultPriority| since that will be the
- // initial spdy::SpdyPriority of the push promise stream when created.
- const spdy::SpdyPriority priority = quic::QuicStream::kDefaultPriority;
- spdy::SpdyStreamId parent_stream_id = 0;
- int weight = 0;
- bool exclusive = false;
- priority_dependency_state_.OnStreamCreation(
- promised_id, priority, &parent_stream_id, &weight, &exclusive);
- if (!VersionUsesHttp3(connection()->transport_version())) {
- WritePriority(promised_id, parent_stream_id, weight, exclusive);
- }
- }
- }
- net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PUSH_PROMISE_RECEIVED,
- [&](NetLogCaptureMode capture_mode) {
- return NetLogQuicPushPromiseReceivedParams(
- &headers, id, promised_id, capture_mode);
- });
- return result;
- }
- void QuicChromiumClientSession::DeletePromised(
- quic::QuicClientPromisedInfo* promised) {
- if (IsOpenStream(promised->id()))
- streams_pushed_and_claimed_count_++;
- quic::QuicSpdyClientSessionBase::DeletePromised(promised);
- }
- void QuicChromiumClientSession::OnPushStreamTimedOut(
- quic::QuicStreamId stream_id) {
- quic::QuicSpdyStream* stream = GetPromisedStream(stream_id);
- if (stream != nullptr)
- bytes_pushed_and_unclaimed_count_ += stream->stream_bytes_read();
- }
- void QuicChromiumClientSession::CancelPush(const GURL& url) {
- quic::QuicClientPromisedInfo* promised_info =
- quic::QuicSpdyClientSessionBase::GetPromisedByUrl(url.spec());
- if (!promised_info || promised_info->is_validating()) {
- // Push stream has already been claimed or is pending matched to a request.
- return;
- }
- quic::QuicStreamId stream_id = promised_info->id();
- // Collect data on the cancelled push stream.
- quic::QuicSpdyStream* stream = GetPromisedStream(stream_id);
- if (stream != nullptr)
- bytes_pushed_and_unclaimed_count_ += stream->stream_bytes_read();
- // Send the reset and remove the promised info from the promise index.
- quic::QuicSpdyClientSessionBase::ResetPromised(stream_id,
- quic::QUIC_STREAM_CANCELLED);
- DeletePromised(promised_info);
- }
- const LoadTimingInfo::ConnectTiming&
- QuicChromiumClientSession::GetConnectTiming() {
- connect_timing_.ssl_start = connect_timing_.connect_start;
- connect_timing_.ssl_end = connect_timing_.connect_end;
- return connect_timing_;
- }
- quic::ParsedQuicVersion QuicChromiumClientSession::GetQuicVersion() const {
- return connection()->version();
- }
- quic::QuicClientPromisedInfo* QuicChromiumClientSession::GetPromised(
- const GURL& url,
- const QuicSessionKey& session_key) {
- if (!session_key_.CanUseForAliasing(session_key)) {
- return nullptr;
- }
- return push_promise_index_->GetPromised(url.spec());
- }
- const std::set<std::string>&
- QuicChromiumClientSession::GetDnsAliasesForSessionKey(
- const QuicSessionKey& key) const {
- static const base::NoDestructor<std::set<std::string>> emptyset_result;
- return stream_factory_ ? stream_factory_->GetDnsAliasesForSessionKey(key)
- : *emptyset_result;
- }
- } // namespace net
|