1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805 |
- /*
- * ngtcp2
- *
- * Copyright (c) 2017 ngtcp2 contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include "ngtcp2_conn.h"
- #include <string.h>
- #include <assert.h>
- #include "ngtcp2_macro.h"
- #include "ngtcp2_log.h"
- #include "ngtcp2_cid.h"
- #include "ngtcp2_conv.h"
- #include "ngtcp2_vec.h"
- #include "ngtcp2_addr.h"
- #include "ngtcp2_path.h"
- #include "ngtcp2_rcvry.h"
- #include "ngtcp2_unreachable.h"
- #include "ngtcp2_net.h"
- #include "ngtcp2_transport_params.h"
- #include "ngtcp2_settings.h"
- #include "ngtcp2_tstamp.h"
- #include "ngtcp2_frame_chain.h"
- /* NGTCP2_FLOW_WINDOW_RTT_FACTOR is the factor of RTT when flow
- control window auto-tuning is triggered. */
- #define NGTCP2_FLOW_WINDOW_RTT_FACTOR 2
- /* NGTCP2_FLOW_WINDOW_SCALING_FACTOR is the growth factor of flow
- control window. */
- #define NGTCP2_FLOW_WINDOW_SCALING_FACTOR 2
- /* NGTCP2_MIN_COALESCED_PAYLOADLEN is the minimum length of QUIC
- packet payload that should be coalesced to a long packet. */
- #define NGTCP2_MIN_COALESCED_PAYLOADLEN 128
- /* NGTCP2_MAX_ACK_PER_PKT is the maximum number of ACK frame per an
- incoming QUIC packet to process. ACK frames that exceed this limit
- are not processed. */
- #define NGTCP2_MAX_ACK_PER_PKT 1
- ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent)
- /*
- * conn_local_stream returns nonzero if |stream_id| indicates that it
- * is the stream initiated by local endpoint.
- */
- static int conn_local_stream(ngtcp2_conn *conn, int64_t stream_id) {
- return (uint8_t)(stream_id & 1) == conn->server;
- }
- /*
- * bidi_stream returns nonzero if |stream_id| is a bidirectional
- * stream ID.
- */
- static int bidi_stream(int64_t stream_id) { return (stream_id & 0x2) == 0; }
- static void conn_update_timestamp(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- assert(conn->log.last_ts <= ts);
- assert(conn->qlog.last_ts <= ts);
- conn->log.last_ts = ts;
- conn->qlog.last_ts = ts;
- }
- /*
- * conn_is_tls_handshake_completed returns nonzero if TLS handshake
- * has completed and 1 RTT keys are available.
- */
- static int conn_is_tls_handshake_completed(ngtcp2_conn *conn) {
- return (conn->flags & NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED) &&
- conn->pktns.crypto.rx.ckm && conn->pktns.crypto.tx.ckm;
- }
- static int conn_call_recv_client_initial(ngtcp2_conn *conn,
- const ngtcp2_cid *dcid) {
- int rv;
- assert(conn->callbacks.recv_client_initial);
- rv = conn->callbacks.recv_client_initial(conn, dcid, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_handshake_completed(ngtcp2_conn *conn) {
- int rv;
- if (!conn->callbacks.handshake_completed) {
- return 0;
- }
- rv = conn->callbacks.handshake_completed(conn, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint32_t flags, uint64_t offset,
- const uint8_t *data, size_t datalen) {
- int rv;
- if (!conn->callbacks.recv_stream_data) {
- return 0;
- }
- rv = conn->callbacks.recv_stream_data(conn, flags, strm->stream_id, offset,
- data, datalen, conn->user_data,
- strm->stream_user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_crypto_data(ngtcp2_conn *conn,
- ngtcp2_encryption_level encryption_level,
- uint64_t offset, const uint8_t *data,
- size_t datalen) {
- int rv;
- assert(conn->callbacks.recv_crypto_data);
- rv = conn->callbacks.recv_crypto_data(conn, encryption_level, offset, data,
- datalen, conn->user_data);
- switch (rv) {
- case 0:
- case NGTCP2_ERR_CRYPTO:
- case NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM:
- case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
- case NGTCP2_ERR_TRANSPORT_PARAM:
- case NGTCP2_ERR_PROTO:
- case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
- case NGTCP2_ERR_NOMEM:
- case NGTCP2_ERR_CALLBACK_FAILURE:
- return rv;
- default:
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- }
- static int conn_call_stream_open(ngtcp2_conn *conn, ngtcp2_strm *strm) {
- int rv;
- if (!conn->callbacks.stream_open) {
- return 0;
- }
- rv = conn->callbacks.stream_open(conn, strm->stream_id, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_stream_close(ngtcp2_conn *conn, ngtcp2_strm *strm) {
- int rv;
- uint32_t flags = NGTCP2_STREAM_CLOSE_FLAG_NONE;
- if (!conn->callbacks.stream_close) {
- return 0;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET) {
- flags |= NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET;
- }
- rv = conn->callbacks.stream_close(conn, flags, strm->stream_id,
- strm->app_error_code, conn->user_data,
- strm->stream_user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_stream_reset(ngtcp2_conn *conn, int64_t stream_id,
- uint64_t final_size, uint64_t app_error_code,
- void *stream_user_data) {
- int rv;
- if (!conn->callbacks.stream_reset) {
- return 0;
- }
- rv = conn->callbacks.stream_reset(conn, stream_id, final_size, app_error_code,
- conn->user_data, stream_user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_extend_max_local_streams_bidi(ngtcp2_conn *conn,
- uint64_t max_streams) {
- int rv;
- if (!conn->callbacks.extend_max_local_streams_bidi) {
- return 0;
- }
- rv = conn->callbacks.extend_max_local_streams_bidi(conn, max_streams,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_extend_max_local_streams_uni(ngtcp2_conn *conn,
- uint64_t max_streams) {
- int rv;
- if (!conn->callbacks.extend_max_local_streams_uni) {
- return 0;
- }
- rv = conn->callbacks.extend_max_local_streams_uni(conn, max_streams,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid,
- uint8_t *token, size_t cidlen) {
- int rv;
- assert(conn->callbacks.get_new_connection_id);
- rv = conn->callbacks.get_new_connection_id(conn, cid, token, cidlen,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_remove_connection_id(ngtcp2_conn *conn,
- const ngtcp2_cid *cid) {
- int rv;
- if (!conn->callbacks.remove_connection_id) {
- return 0;
- }
- rv = conn->callbacks.remove_connection_id(conn, cid, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv,
- ngtcp2_path_validation_result res) {
- int rv;
- uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE;
- const ngtcp2_path *old_path = NULL;
- if (!conn->callbacks.path_validation) {
- return 0;
- }
- if (pv->flags & NGTCP2_PV_FLAG_PREFERRED_ADDR) {
- flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR;
- }
- if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) {
- old_path = &pv->fallback_dcid.ps.path;
- }
- if (conn->server && old_path &&
- (ngtcp2_addr_compare(&pv->dcid.ps.path.remote, &old_path->remote) &
- (NGTCP2_ADDR_COMPARE_FLAG_ADDR | NGTCP2_ADDR_COMPARE_FLAG_FAMILY))) {
- flags |= NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN;
- }
- rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, old_path,
- res, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_select_preferred_addr(ngtcp2_conn *conn,
- ngtcp2_path *dest) {
- int rv;
- if (!conn->callbacks.select_preferred_addr) {
- return 0;
- }
- assert(conn->remote.transport_params);
- assert(conn->remote.transport_params->preferred_addr_present);
- rv = conn->callbacks.select_preferred_addr(
- conn, dest, &conn->remote.transport_params->preferred_addr,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_extend_max_remote_streams_bidi(ngtcp2_conn *conn,
- uint64_t max_streams) {
- int rv;
- if (!conn->callbacks.extend_max_remote_streams_bidi) {
- return 0;
- }
- rv = conn->callbacks.extend_max_remote_streams_bidi(conn, max_streams,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_extend_max_remote_streams_uni(ngtcp2_conn *conn,
- uint64_t max_streams) {
- int rv;
- if (!conn->callbacks.extend_max_remote_streams_uni) {
- return 0;
- }
- rv = conn->callbacks.extend_max_remote_streams_uni(conn, max_streams,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_extend_max_stream_data(ngtcp2_conn *conn,
- ngtcp2_strm *strm,
- int64_t stream_id,
- uint64_t datalen) {
- int rv;
- if (!conn->callbacks.extend_max_stream_data) {
- return 0;
- }
- rv = conn->callbacks.extend_max_stream_data(
- conn, stream_id, datalen, conn->user_data, strm->stream_user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_dcid_status(ngtcp2_conn *conn,
- ngtcp2_connection_id_status_type type,
- const ngtcp2_dcid *dcid) {
- int rv;
- if (!conn->callbacks.dcid_status) {
- return 0;
- }
- rv = conn->callbacks.dcid_status(
- conn, type, dcid->seq, &dcid->cid,
- (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token : NULL,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_activate_dcid(ngtcp2_conn *conn, const ngtcp2_dcid *dcid) {
- return conn_call_dcid_status(conn, NGTCP2_CONNECTION_ID_STATUS_TYPE_ACTIVATE,
- dcid);
- }
- static int conn_call_deactivate_dcid(ngtcp2_conn *conn,
- const ngtcp2_dcid *dcid) {
- return conn_call_dcid_status(
- conn, NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE, dcid);
- }
- static int conn_call_stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id,
- uint64_t app_error_code,
- void *stream_user_data) {
- int rv;
- if (!conn->callbacks.stream_stop_sending) {
- return 0;
- }
- rv = conn->callbacks.stream_stop_sending(conn, stream_id, app_error_code,
- conn->user_data, stream_user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static void conn_call_delete_crypto_aead_ctx(ngtcp2_conn *conn,
- ngtcp2_crypto_aead_ctx *aead_ctx) {
- if (!aead_ctx->native_handle) {
- return;
- }
- assert(conn->callbacks.delete_crypto_aead_ctx);
- conn->callbacks.delete_crypto_aead_ctx(conn, aead_ctx, conn->user_data);
- }
- static void
- conn_call_delete_crypto_cipher_ctx(ngtcp2_conn *conn,
- ngtcp2_crypto_cipher_ctx *cipher_ctx) {
- if (!cipher_ctx->native_handle) {
- return;
- }
- assert(conn->callbacks.delete_crypto_cipher_ctx);
- conn->callbacks.delete_crypto_cipher_ctx(conn, cipher_ctx, conn->user_data);
- }
- static int conn_call_client_initial(ngtcp2_conn *conn) {
- int rv;
- assert(conn->callbacks.client_initial);
- rv = conn->callbacks.client_initial(conn, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_get_path_challenge_data(ngtcp2_conn *conn, uint8_t *data) {
- int rv;
- assert(conn->callbacks.get_path_challenge_data);
- rv = conn->callbacks.get_path_challenge_data(conn, data, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_version_negotiation(ngtcp2_conn *conn,
- const ngtcp2_pkt_hd *hd,
- const uint32_t *sv, size_t nsv) {
- int rv;
- if (!conn->callbacks.recv_version_negotiation) {
- return 0;
- }
- rv = conn->callbacks.recv_version_negotiation(conn, hd, sv, nsv,
- conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) {
- int rv;
- assert(conn->callbacks.recv_retry);
- rv = conn->callbacks.recv_retry(conn, hd, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int
- conn_call_recv_stateless_reset(ngtcp2_conn *conn,
- const ngtcp2_pkt_stateless_reset *sr) {
- int rv;
- if (!conn->callbacks.recv_stateless_reset) {
- return 0;
- }
- rv = conn->callbacks.recv_stateless_reset(conn, sr, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_new_token(ngtcp2_conn *conn, const uint8_t *token,
- size_t tokenlen) {
- int rv;
- if (!conn->callbacks.recv_new_token) {
- return 0;
- }
- rv = conn->callbacks.recv_new_token(conn, token, tokenlen, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_handshake_confirmed(ngtcp2_conn *conn) {
- int rv;
- if (!conn->callbacks.handshake_confirmed) {
- return 0;
- }
- rv = conn->callbacks.handshake_confirmed(conn, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_datagram(ngtcp2_conn *conn,
- const ngtcp2_datagram *fr) {
- const uint8_t *data;
- size_t datalen;
- int rv;
- uint32_t flags = NGTCP2_DATAGRAM_FLAG_NONE;
- if (!conn->callbacks.recv_datagram) {
- return 0;
- }
- if (fr->datacnt) {
- assert(fr->datacnt == 1);
- data = fr->data->base;
- datalen = fr->data->len;
- } else {
- data = NULL;
- datalen = 0;
- }
- if (!conn_is_tls_handshake_completed(conn)) {
- flags |= NGTCP2_DATAGRAM_FLAG_0RTT;
- }
- rv =
- conn->callbacks.recv_datagram(conn, flags, data, datalen, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int
- conn_call_update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
- ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
- ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
- const uint8_t *current_rx_secret,
- const uint8_t *current_tx_secret, size_t secretlen) {
- int rv;
- assert(conn->callbacks.update_key);
- rv = conn->callbacks.update_key(
- conn, rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, tx_iv,
- current_rx_secret, current_tx_secret, secretlen, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_version_negotiation(ngtcp2_conn *conn, uint32_t version,
- const ngtcp2_cid *dcid) {
- int rv;
- assert(conn->callbacks.version_negotiation);
- rv =
- conn->callbacks.version_negotiation(conn, version, dcid, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_rx_key(ngtcp2_conn *conn,
- ngtcp2_encryption_level level) {
- int rv;
- if (!conn->callbacks.recv_rx_key) {
- return 0;
- }
- rv = conn->callbacks.recv_rx_key(conn, level, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static int conn_call_recv_tx_key(ngtcp2_conn *conn,
- ngtcp2_encryption_level level) {
- int rv;
- if (!conn->callbacks.recv_tx_key) {
- return 0;
- }
- rv = conn->callbacks.recv_tx_key(conn, level, conn->user_data);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- return 0;
- }
- static void pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id,
- ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num,
- ngtcp2_log *log, ngtcp2_qlog *qlog,
- ngtcp2_objalloc *rtb_entry_objalloc,
- ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
- memset(pktns, 0, sizeof(*pktns));
- ngtcp2_gaptr_init(&pktns->rx.pngap, mem);
- pktns->tx.last_pkt_num = initial_pkt_num - 1;
- pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
- pktns->rx.max_pkt_num = -1;
- pktns->rx.max_ack_eliciting_pkt_num = -1;
- pktns->id = pktns_id;
- ngtcp2_acktr_init(&pktns->acktr, log, mem);
- ngtcp2_strm_init(&pktns->crypto.strm, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL,
- frc_objalloc, mem);
- ngtcp2_rtb_init(&pktns->rtb, rst, cc, initial_pkt_num, log, qlog,
- rtb_entry_objalloc, frc_objalloc, mem);
- }
- static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id,
- ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num,
- ngtcp2_log *log, ngtcp2_qlog *qlog,
- ngtcp2_objalloc *rtb_entry_objalloc,
- ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
- *ppktns = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pktns));
- if (*ppktns == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- pktns_init(*ppktns, pktns_id, rst, cc, initial_pkt_num, log, qlog,
- rtb_entry_objalloc, frc_objalloc, mem);
- return 0;
- }
- static int cycle_less(const ngtcp2_pq_entry *lhs, const ngtcp2_pq_entry *rhs) {
- ngtcp2_strm *ls = ngtcp2_struct_of(lhs, ngtcp2_strm, pe);
- ngtcp2_strm *rs = ngtcp2_struct_of(rhs, ngtcp2_strm, pe);
- if (ls->cycle == rs->cycle) {
- return ls->stream_id < rs->stream_id;
- }
- return rs->cycle - ls->cycle <= 1;
- }
- static void delete_buffed_pkts(ngtcp2_pkt_chain *pc, const ngtcp2_mem *mem) {
- ngtcp2_pkt_chain *next;
- for (; pc;) {
- next = pc->next;
- ngtcp2_pkt_chain_del(pc, mem);
- pc = next;
- }
- }
- static void delete_buf_chain(ngtcp2_buf_chain *bufchain,
- const ngtcp2_mem *mem) {
- ngtcp2_buf_chain *next;
- for (; bufchain;) {
- next = bufchain->next;
- ngtcp2_buf_chain_del(bufchain, mem);
- bufchain = next;
- }
- }
- static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) {
- delete_buf_chain(pktns->crypto.tx.data, mem);
- delete_buffed_pkts(pktns->rx.buffed_pkts, mem);
- ngtcp2_frame_chain_list_objalloc_del(pktns->tx.frq, pktns->rtb.frc_objalloc,
- mem);
- ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, mem);
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, mem);
- ngtcp2_rtb_free(&pktns->rtb);
- ngtcp2_strm_free(&pktns->crypto.strm);
- ngtcp2_acktr_free(&pktns->acktr);
- ngtcp2_gaptr_free(&pktns->rx.pngap);
- }
- static void pktns_del(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) {
- if (pktns == NULL) {
- return;
- }
- pktns_free(pktns, mem);
- ngtcp2_mem_free(mem, pktns);
- }
- static int cid_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
- return ngtcp2_cid_less(lhs, rhs);
- }
- ngtcp2_ksl_search_def(cid_less, cid_less)
- static int retired_ts_less(const ngtcp2_pq_entry *lhs,
- const ngtcp2_pq_entry *rhs) {
- const ngtcp2_scid *a = ngtcp2_struct_of(lhs, ngtcp2_scid, pe);
- const ngtcp2_scid *b = ngtcp2_struct_of(rhs, ngtcp2_scid, pe);
- return a->retired_ts < b->retired_ts;
- }
- /*
- * conn_reset_conn_stat_cc resets congestion state in |cstat|.
- */
- static void conn_reset_conn_stat_cc(ngtcp2_conn *conn,
- ngtcp2_conn_stat *cstat) {
- cstat->latest_rtt = 0;
- cstat->min_rtt = UINT64_MAX;
- cstat->smoothed_rtt = conn->local.settings.initial_rtt;
- cstat->rttvar = conn->local.settings.initial_rtt / 2;
- cstat->first_rtt_sample_ts = UINT64_MAX;
- cstat->pto_count = 0;
- cstat->loss_detection_timer = UINT64_MAX;
- cstat->max_tx_udp_payload_size =
- ngtcp2_conn_get_path_max_tx_udp_payload_size(conn);
- cstat->cwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size);
- cstat->ssthresh = UINT64_MAX;
- cstat->congestion_recovery_start_ts = UINT64_MAX;
- cstat->bytes_in_flight = 0;
- cstat->delivery_rate_sec = 0;
- cstat->pacing_interval = 0;
- cstat->send_quantum = 64 * 1024;
- }
- /*
- * reset_conn_stat_recovery resets the fields related to the recovery
- * function
- */
- static void reset_conn_stat_recovery(ngtcp2_conn_stat *cstat) {
- /* Initializes them with UINT64_MAX. */
- memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time));
- memset(cstat->last_tx_pkt_ts, 0xff, sizeof(cstat->last_tx_pkt_ts));
- }
- /*
- * conn_reset_conn_stat resets |cstat|. The following fields are not
- * reset: initial_rtt and max_udp_payload_size.
- */
- static void conn_reset_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) {
- conn_reset_conn_stat_cc(conn, cstat);
- reset_conn_stat_recovery(cstat);
- }
- static void delete_scid(ngtcp2_ksl *scids, const ngtcp2_mem *mem) {
- ngtcp2_ksl_it it;
- for (it = ngtcp2_ksl_begin(scids); !ngtcp2_ksl_it_end(&it);
- ngtcp2_ksl_it_next(&it)) {
- ngtcp2_mem_free(mem, ngtcp2_ksl_it_get(&it));
- }
- }
- /*
- * compute_pto computes PTO.
- */
- static ngtcp2_duration compute_pto(ngtcp2_duration smoothed_rtt,
- ngtcp2_duration rttvar,
- ngtcp2_duration max_ack_delay) {
- ngtcp2_duration var = ngtcp2_max_uint64(4 * rttvar, NGTCP2_GRANULARITY);
- return smoothed_rtt + var + max_ack_delay;
- }
- /*
- * conn_compute_initial_pto computes PTO using the initial RTT.
- */
- static ngtcp2_duration conn_compute_initial_pto(ngtcp2_conn *conn,
- ngtcp2_pktns *pktns) {
- ngtcp2_duration initial_rtt = conn->local.settings.initial_rtt;
- ngtcp2_duration max_ack_delay;
- if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION &&
- conn->remote.transport_params) {
- max_ack_delay = conn->remote.transport_params->max_ack_delay;
- } else {
- max_ack_delay = 0;
- }
- return compute_pto(initial_rtt, initial_rtt / 2, max_ack_delay);
- }
- /*
- * conn_compute_pto computes the current PTO.
- */
- static ngtcp2_duration conn_compute_pto(ngtcp2_conn *conn,
- ngtcp2_pktns *pktns) {
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_duration max_ack_delay;
- if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION &&
- conn->remote.transport_params) {
- max_ack_delay = conn->remote.transport_params->max_ack_delay;
- } else {
- max_ack_delay = 0;
- }
- return compute_pto(cstat->smoothed_rtt, cstat->rttvar, max_ack_delay);
- }
- ngtcp2_duration ngtcp2_conn_compute_pto(ngtcp2_conn *conn,
- ngtcp2_pktns *pktns) {
- return conn_compute_pto(conn, pktns);
- }
- /*
- * conn_compute_pv_timeout_pto returns path validation timeout using
- * the given |pto|.
- */
- static ngtcp2_duration conn_compute_pv_timeout_pto(ngtcp2_conn *conn,
- ngtcp2_duration pto) {
- ngtcp2_duration initial_pto = conn_compute_initial_pto(conn, &conn->pktns);
- return 3 * ngtcp2_max_uint64(pto, initial_pto);
- }
- /*
- * conn_compute_pv_timeout returns path validation timeout.
- */
- static ngtcp2_duration conn_compute_pv_timeout(ngtcp2_conn *conn) {
- return conn_compute_pv_timeout_pto(conn,
- conn_compute_pto(conn, &conn->pktns));
- }
- static void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
- uint16_t *prtb_entry_flags, ngtcp2_pktns *pktns,
- const ngtcp2_pkt_hd *hd, ngtcp2_tstamp ts) {
- assert(pi);
- if (pi->ecn != NGTCP2_ECN_NOT_ECT) {
- /* We have already made a transition of validation state and
- deceided to send UDP datagram with ECN bit set. Coalesced QUIC
- packets also bear ECN bits set. */
- if (pktns->tx.ecn.start_pkt_num == INT64_MAX) {
- pktns->tx.ecn.start_pkt_num = hd->pkt_num;
- }
- ++pktns->tx.ecn.validation_pkt_sent;
- if (prtb_entry_flags) {
- *prtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ECN;
- }
- ++pktns->tx.ecn.ect0;
- return;
- }
- switch (conn->tx.ecn.state) {
- case NGTCP2_ECN_STATE_TESTING:
- if (conn->tx.ecn.validation_start_ts == UINT64_MAX) {
- assert(0 == pktns->tx.ecn.validation_pkt_sent);
- assert(0 == pktns->tx.ecn.validation_pkt_lost);
- conn->tx.ecn.validation_start_ts = ts;
- } else if (ts - conn->tx.ecn.validation_start_ts >=
- 3 * conn_compute_pto(conn, pktns)) {
- conn->tx.ecn.state = NGTCP2_ECN_STATE_UNKNOWN;
- break;
- }
- if (pktns->tx.ecn.start_pkt_num == INT64_MAX) {
- pktns->tx.ecn.start_pkt_num = hd->pkt_num;
- }
- ++pktns->tx.ecn.validation_pkt_sent;
- if (++conn->tx.ecn.dgram_sent == NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS) {
- conn->tx.ecn.state = NGTCP2_ECN_STATE_UNKNOWN;
- }
- /* fall through */
- case NGTCP2_ECN_STATE_CAPABLE:
- /* pi is provided per UDP datagram. */
- assert(NGTCP2_ECN_NOT_ECT == pi->ecn);
- pi->ecn = NGTCP2_ECN_ECT_0;
- if (prtb_entry_flags) {
- *prtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ECN;
- }
- ++pktns->tx.ecn.ect0;
- break;
- case NGTCP2_ECN_STATE_UNKNOWN:
- case NGTCP2_ECN_STATE_FAILED:
- break;
- default:
- ngtcp2_unreachable();
- }
- }
- static void conn_reset_ecn_validation_state(ngtcp2_conn *conn) {
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- ngtcp2_pktns *pktns = &conn->pktns;
- conn->tx.ecn.state = NGTCP2_ECN_STATE_TESTING;
- conn->tx.ecn.validation_start_ts = UINT64_MAX;
- conn->tx.ecn.dgram_sent = 0;
- if (in_pktns) {
- in_pktns->tx.ecn.start_pkt_num = INT64_MAX;
- in_pktns->tx.ecn.validation_pkt_sent = 0;
- in_pktns->tx.ecn.validation_pkt_lost = 0;
- }
- if (hs_pktns) {
- hs_pktns->tx.ecn.start_pkt_num = INT64_MAX;
- hs_pktns->tx.ecn.validation_pkt_sent = 0;
- hs_pktns->tx.ecn.validation_pkt_lost = 0;
- }
- pktns->tx.ecn.start_pkt_num = INT64_MAX;
- pktns->tx.ecn.validation_pkt_sent = 0;
- pktns->tx.ecn.validation_pkt_lost = 0;
- }
- /* server_default_available_versions is the default available_versions
- field sent by server. */
- static uint8_t server_default_available_versions[] = {0, 0, 0, 1};
- /*
- * available_versions_init writes |versions| of length |versionslen|
- * in network byte order to the buffer pointed by |buf|, suitable for
- * sending in available_versions field of version_information QUIC
- * transport parameter. This function returns the pointer to the one
- * beyond the last byte written.
- */
- static void *available_versions_init(void *buf, const uint32_t *versions,
- size_t versionslen) {
- size_t i;
- for (i = 0; i < versionslen; ++i) {
- buf = ngtcp2_put_uint32be(buf, versions[i]);
- }
- return 0;
- }
- static void
- conn_set_local_transport_params(ngtcp2_conn *conn,
- const ngtcp2_transport_params *params) {
- ngtcp2_transport_params *p = &conn->local.transport_params;
- uint32_t chosen_version = p->version_info.chosen_version;
- *p = *params;
- if (conn->server) {
- p->version_info.chosen_version = chosen_version;
- } else {
- p->version_info.chosen_version = conn->client_chosen_version;
- }
- p->version_info.available_versions = conn->vneg.available_versions;
- p->version_info.available_versionslen = conn->vneg.available_versionslen;
- p->version_info_present = 1;
- }
- static size_t buflen_align(size_t buflen) {
- return (buflen + 0x7) & (size_t)~0x7;
- }
- static void *buf_align(void *buf) {
- return (void *)((uintptr_t)((uint8_t *)buf + 0x7) & (uintptr_t)~0x7);
- }
- static void *buf_advance(void *buf, size_t n) { return (uint8_t *)buf + n; }
- static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
- const ngtcp2_cid *scid, const ngtcp2_path *path,
- uint32_t client_chosen_version, int callbacks_version,
- const ngtcp2_callbacks *callbacks, int settings_version,
- const ngtcp2_settings *settings,
- int transport_params_version,
- const ngtcp2_transport_params *params,
- const ngtcp2_mem *mem, void *user_data, int server) {
- int rv;
- ngtcp2_scid *scident;
- void *buf, *tokenbuf;
- size_t buflen;
- uint8_t fixed_bit_byte;
- size_t i;
- uint32_t *preferred_versions;
- ngtcp2_settings settingsbuf;
- ngtcp2_transport_params paramsbuf;
- (void)callbacks_version;
- (void)settings_version;
- settings =
- ngtcp2_settings_convert_to_latest(&settingsbuf, settings_version, settings);
- params = ngtcp2_transport_params_convert_to_latest(
- ¶msbuf, transport_params_version, params);
- assert(settings->max_window <= NGTCP2_MAX_VARINT);
- assert(settings->max_stream_window <= NGTCP2_MAX_VARINT);
- assert(settings->max_tx_udp_payload_size);
- assert(settings->max_tx_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE);
- assert(settings->initial_pkt_num <= INT32_MAX);
- assert(params->active_connection_id_limit >=
- NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT);
- assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE);
- assert(params->initial_max_data <= NGTCP2_MAX_VARINT);
- assert(params->initial_max_stream_data_bidi_local <= NGTCP2_MAX_VARINT);
- assert(params->initial_max_stream_data_bidi_remote <= NGTCP2_MAX_VARINT);
- assert(params->initial_max_stream_data_uni <= NGTCP2_MAX_VARINT);
- assert((server && params->original_dcid_present) ||
- (!server && !params->original_dcid_present));
- assert(!params->initial_scid_present);
- assert(server || !params->stateless_reset_token_present);
- assert(server || !params->preferred_addr_present);
- assert(server || !params->retry_scid_present);
- assert(params->max_idle_timeout != UINT64_MAX);
- assert(params->max_ack_delay < (1 << 14) * NGTCP2_MILLISECONDS);
- assert(server || callbacks->client_initial);
- assert(!server || callbacks->recv_client_initial);
- assert(callbacks->recv_crypto_data);
- assert(callbacks->encrypt);
- assert(callbacks->decrypt);
- assert(callbacks->hp_mask);
- assert(server || callbacks->recv_retry);
- assert(callbacks->rand);
- assert(callbacks->get_new_connection_id);
- assert(callbacks->update_key);
- assert(callbacks->delete_crypto_aead_ctx);
- assert(callbacks->delete_crypto_cipher_ctx);
- assert(callbacks->get_path_challenge_data);
- assert(!server || !ngtcp2_is_reserved_version(client_chosen_version));
- for (i = 0; i < settings->pmtud_probeslen; ++i) {
- assert(settings->pmtud_probes[i] > NGTCP2_MAX_UDP_PAYLOAD_SIZE);
- }
- if (mem == NULL) {
- mem = ngtcp2_mem_default();
- }
- buflen = sizeof(ngtcp2_conn);
- if (settings->qlog_write) {
- buflen = buflen_align(buflen);
- buflen += NGTCP2_QLOG_BUFLEN;
- }
- if (settings->pmtud_probeslen) {
- buflen = buflen_align(buflen);
- buflen += sizeof(settings->pmtud_probes[0]) * settings->pmtud_probeslen;
- }
- if (settings->preferred_versionslen) {
- buflen = buflen_align(buflen);
- buflen +=
- sizeof(settings->preferred_versions[0]) * settings->preferred_versionslen;
- }
- if (settings->available_versionslen) {
- buflen = buflen_align(buflen);
- buflen +=
- sizeof(settings->available_versions[0]) * settings->available_versionslen;
- } else if (server) {
- if (settings->preferred_versionslen) {
- buflen = buflen_align(buflen);
- buflen += sizeof(settings->preferred_versions[0]) *
- settings->preferred_versionslen;
- }
- } else if (!ngtcp2_is_reserved_version(client_chosen_version)) {
- buflen = buflen_align(buflen);
- buflen += sizeof(client_chosen_version);
- }
- buf = ngtcp2_mem_calloc(mem, 1, buflen);
- if (buf == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- *pconn = buf;
- buf = buf_advance(buf, sizeof(ngtcp2_conn));
- (*pconn)->server = server;
- ngtcp2_objalloc_frame_chain_init(&(*pconn)->frc_objalloc, 16, mem);
- ngtcp2_objalloc_rtb_entry_init(&(*pconn)->rtb_entry_objalloc, 16, mem);
- ngtcp2_objalloc_strm_init(&(*pconn)->strm_objalloc, 16, mem);
- ngtcp2_static_ringbuf_dcid_bound_init(&(*pconn)->dcid.bound);
- ngtcp2_static_ringbuf_dcid_unused_init(&(*pconn)->dcid.unused);
- ngtcp2_static_ringbuf_dcid_retired_init(&(*pconn)->dcid.retired);
- ngtcp2_gaptr_init(&(*pconn)->dcid.seqgap, mem);
- ngtcp2_ksl_init(&(*pconn)->scid.set, cid_less, ksl_cid_less_search,
- sizeof(ngtcp2_cid), mem);
- ngtcp2_pq_init(&(*pconn)->scid.used, retired_ts_less, mem);
- ngtcp2_map_init(&(*pconn)->strms, mem);
- ngtcp2_pq_init(&(*pconn)->tx.strmq, cycle_less, mem);
- ngtcp2_idtr_init(&(*pconn)->remote.bidi.idtr, mem);
- ngtcp2_idtr_init(&(*pconn)->remote.uni.idtr, mem);
- ngtcp2_static_ringbuf_path_challenge_init(&(*pconn)->rx.path_challenge);
- ngtcp2_log_init(&(*pconn)->log, scid, settings->log_printf,
- settings->initial_ts, user_data);
- ngtcp2_qlog_init(&(*pconn)->qlog, settings->qlog_write, settings->initial_ts,
- user_data);
- if ((*pconn)->qlog.write) {
- buf = buf_align(buf);
- ngtcp2_buf_init(&(*pconn)->qlog.buf, buf, NGTCP2_QLOG_BUFLEN);
- buf = buf_advance(buf, NGTCP2_QLOG_BUFLEN);
- }
- (*pconn)->local.settings = *settings;
- if (settings->tokenlen) {
- tokenbuf = ngtcp2_mem_malloc(mem, settings->tokenlen);
- if (tokenbuf == NULL) {
- rv = NGTCP2_ERR_NOMEM;
- goto fail_token;
- }
- memcpy(tokenbuf, settings->token, settings->tokenlen);
- (*pconn)->local.settings.token = tokenbuf;
- } else {
- (*pconn)->local.settings.token = NULL;
- }
- if (settings->pmtud_probeslen) {
- (*pconn)->local.settings.pmtud_probes = buf_align(buf);
- buf = ngtcp2_cpymem(
- (uint16_t *)(*pconn)->local.settings.pmtud_probes, settings->pmtud_probes,
- sizeof(settings->pmtud_probes[0]) * settings->pmtud_probeslen);
- }
- if (!(*pconn)->local.settings.original_version) {
- (*pconn)->local.settings.original_version = client_chosen_version;
- }
- ngtcp2_dcid_init(&(*pconn)->dcid.current, 0, dcid, NULL);
- ngtcp2_dcid_set_path(&(*pconn)->dcid.current, path);
- rv = ngtcp2_gaptr_push(&(*pconn)->dcid.seqgap, 0, 1);
- if (rv != 0) {
- goto fail_seqgap_push;
- }
- conn_reset_conn_stat(*pconn, &(*pconn)->cstat);
- (*pconn)->cstat.initial_rtt = settings->initial_rtt;
- ngtcp2_rst_init(&(*pconn)->rst);
- (*pconn)->cc_algo = settings->cc_algo;
- switch (settings->cc_algo) {
- case NGTCP2_CC_ALGO_RENO:
- ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log);
- break;
- case NGTCP2_CC_ALGO_CUBIC:
- ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log, &(*pconn)->rst);
- break;
- case NGTCP2_CC_ALGO_BBR:
- ngtcp2_cc_bbr_init(&(*pconn)->bbr, &(*pconn)->log, &(*pconn)->cstat,
- &(*pconn)->rst, settings->initial_ts, callbacks->rand,
- &settings->rand_ctx);
- break;
- default:
- ngtcp2_unreachable();
- }
- rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst,
- &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log,
- &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc,
- &(*pconn)->frc_objalloc, mem);
- if (rv != 0) {
- goto fail_in_pktns_init;
- }
- rv = pktns_new(&(*pconn)->hs_pktns, NGTCP2_PKTNS_ID_HANDSHAKE, &(*pconn)->rst,
- &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log,
- &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc,
- &(*pconn)->frc_objalloc, mem);
- if (rv != 0) {
- goto fail_hs_pktns_init;
- }
- pktns_init(&(*pconn)->pktns, NGTCP2_PKTNS_ID_APPLICATION, &(*pconn)->rst,
- &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log,
- &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc,
- &(*pconn)->frc_objalloc, mem);
- scident = ngtcp2_mem_malloc(mem, sizeof(*scident));
- if (scident == NULL) {
- rv = NGTCP2_ERR_NOMEM;
- goto fail_scident;
- }
- /* Set stateless reset token later if it is available in the local
- transport parameters */
- ngtcp2_scid_init(scident, 0, scid);
- rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident);
- if (rv != 0) {
- goto fail_scid_set_insert;
- }
- scident = NULL;
- if (settings->preferred_versionslen) {
- if (!server && !ngtcp2_is_reserved_version(client_chosen_version)) {
- for (i = 0; i < settings->preferred_versionslen; ++i) {
- if (settings->preferred_versions[i] == client_chosen_version) {
- break;
- }
- }
- assert(i < settings->preferred_versionslen);
- }
- preferred_versions = buf_align(buf);
- buf = buf_advance(preferred_versions, sizeof(preferred_versions[0]) *
- settings->preferred_versionslen);
- for (i = 0; i < settings->preferred_versionslen; ++i) {
- assert(ngtcp2_is_supported_version(settings->preferred_versions[i]));
- preferred_versions[i] = settings->preferred_versions[i];
- }
- (*pconn)->vneg.preferred_versions = preferred_versions;
- (*pconn)->vneg.preferred_versionslen = settings->preferred_versionslen;
- }
- (*pconn)->local.settings.preferred_versions = NULL;
- (*pconn)->local.settings.preferred_versionslen = 0;
- if (settings->available_versionslen) {
- if (!server && !ngtcp2_is_reserved_version(client_chosen_version)) {
- for (i = 0; i < settings->available_versionslen; ++i) {
- if (settings->available_versions[i] == client_chosen_version) {
- break;
- }
- }
- assert(i < settings->available_versionslen);
- }
- for (i = 0; i < settings->available_versionslen; ++i) {
- assert(ngtcp2_is_reserved_version(settings->available_versions[i]) ||
- ngtcp2_is_supported_version(settings->available_versions[i]));
- }
- (*pconn)->vneg.available_versions = buf_align(buf);
- (*pconn)->vneg.available_versionslen =
- sizeof(uint32_t) * settings->available_versionslen;
- buf = available_versions_init((*pconn)->vneg.available_versions,
- settings->available_versions,
- settings->available_versionslen);
- } else if (server) {
- if (settings->preferred_versionslen) {
- (*pconn)->vneg.available_versions = buf_align(buf);
- (*pconn)->vneg.available_versionslen =
- sizeof(uint32_t) * settings->preferred_versionslen;
- buf = available_versions_init((*pconn)->vneg.available_versions,
- settings->preferred_versions,
- settings->preferred_versionslen);
- } else {
- (*pconn)->vneg.available_versions = server_default_available_versions;
- (*pconn)->vneg.available_versionslen =
- sizeof(server_default_available_versions);
- }
- } else if (!ngtcp2_is_reserved_version(client_chosen_version)) {
- (*pconn)->vneg.available_versions = buf_align(buf);
- (*pconn)->vneg.available_versionslen = sizeof(uint32_t);
- buf = available_versions_init((*pconn)->vneg.available_versions,
- &client_chosen_version, 1);
- }
- (*pconn)->local.settings.available_versions = NULL;
- (*pconn)->local.settings.available_versionslen = 0;
- (*pconn)->client_chosen_version = client_chosen_version;
- conn_set_local_transport_params(*pconn, params);
- callbacks->rand(&fixed_bit_byte, 1, &settings->rand_ctx);
- if (fixed_bit_byte & 1) {
- (*pconn)->flags |= NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT;
- }
- (*pconn)->keep_alive.last_ts = UINT64_MAX;
- (*pconn)->keep_alive.timeout = UINT64_MAX;
- (*pconn)->oscid = *scid;
- (*pconn)->callbacks = *callbacks;
- (*pconn)->mem = mem;
- (*pconn)->user_data = user_data;
- (*pconn)->idle_ts = settings->initial_ts;
- (*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX;
- (*pconn)->tx.last_max_data_ts = UINT64_MAX;
- (*pconn)->tx.pacing.next_ts = UINT64_MAX;
- (*pconn)->tx.last_blocked_offset = UINT64_MAX;
- (*pconn)->early.discard_started_ts = UINT64_MAX;
- conn_reset_ecn_validation_state(*pconn);
- ngtcp2_qlog_start(&(*pconn)->qlog,
- server
- ? ((*pconn)->local.transport_params.retry_scid_present
- ? &(*pconn)->local.transport_params.retry_scid
- : &(*pconn)->local.transport_params.original_dcid)
- : dcid,
- server);
- return 0;
- fail_scid_set_insert:
- ngtcp2_mem_free(mem, scident);
- fail_scident:
- pktns_del((*pconn)->hs_pktns, mem);
- fail_hs_pktns_init:
- pktns_del((*pconn)->in_pktns, mem);
- fail_in_pktns_init:
- ngtcp2_gaptr_free(&(*pconn)->dcid.seqgap);
- fail_seqgap_push:
- ngtcp2_mem_free(mem, (uint8_t *)(*pconn)->local.settings.token);
- fail_token:
- ngtcp2_mem_free(mem, *pconn);
- return rv;
- }
- int ngtcp2_conn_client_new_versioned(
- ngtcp2_conn **pconn, const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
- const ngtcp2_path *path, uint32_t client_chosen_version,
- int callbacks_version, const ngtcp2_callbacks *callbacks,
- int settings_version, const ngtcp2_settings *settings,
- int transport_params_version, const ngtcp2_transport_params *params,
- const ngtcp2_mem *mem, void *user_data) {
- int rv;
- rv = conn_new(pconn, dcid, scid, path, client_chosen_version,
- callbacks_version, callbacks, settings_version, settings,
- transport_params_version, params, mem, user_data, 0);
- if (rv != 0) {
- return rv;
- }
- (*pconn)->rcid = *dcid;
- (*pconn)->state = NGTCP2_CS_CLIENT_INITIAL;
- (*pconn)->local.bidi.next_stream_id = 0;
- (*pconn)->local.uni.next_stream_id = 2;
- rv = ngtcp2_conn_commit_local_transport_params(*pconn);
- if (rv != 0) {
- ngtcp2_conn_del(*pconn);
- return rv;
- }
- return 0;
- }
- int ngtcp2_conn_server_new_versioned(
- ngtcp2_conn **pconn, const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
- const ngtcp2_path *path, uint32_t client_chosen_version,
- int callbacks_version, const ngtcp2_callbacks *callbacks,
- int settings_version, const ngtcp2_settings *settings,
- int transport_params_version, const ngtcp2_transport_params *params,
- const ngtcp2_mem *mem, void *user_data) {
- int rv;
- rv = conn_new(pconn, dcid, scid, path, client_chosen_version,
- callbacks_version, callbacks, settings_version, settings,
- transport_params_version, params, mem, user_data, 1);
- if (rv != 0) {
- return rv;
- }
- (*pconn)->state = NGTCP2_CS_SERVER_INITIAL;
- (*pconn)->local.bidi.next_stream_id = 1;
- (*pconn)->local.uni.next_stream_id = 3;
- if ((*pconn)->local.settings.tokenlen) {
- /* Usage of token lifts amplification limit */
- (*pconn)->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED;
- }
- return 0;
- }
- /*
- * conn_fc_credits returns the number of bytes allowed to be sent to
- * the given stream. Both connection and stream level flow control
- * credits are considered.
- */
- static uint64_t conn_fc_credits(ngtcp2_conn *conn, ngtcp2_strm *strm) {
- return ngtcp2_min_uint64(strm->tx.max_offset - strm->tx.offset,
- conn->tx.max_offset - conn->tx.offset);
- }
- /*
- * conn_enforce_flow_control returns the number of bytes allowed to be
- * sent to the given stream. |len| might be shorted because of
- * available flow control credits.
- */
- static uint64_t conn_enforce_flow_control(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t len) {
- uint64_t fc_credits = conn_fc_credits(conn, strm);
- return ngtcp2_min_uint64(len, fc_credits);
- }
- static int delete_strms_each(void *data, void *ptr) {
- ngtcp2_conn *conn = ptr;
- ngtcp2_strm *s = data;
- ngtcp2_strm_free(s);
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, s);
- return 0;
- }
- static void conn_vneg_crypto_free(ngtcp2_conn *conn) {
- if (conn->vneg.rx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &conn->vneg.rx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->vneg.rx.hp_ctx);
- if (conn->vneg.tx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &conn->vneg.tx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->vneg.tx.hp_ctx);
- ngtcp2_crypto_km_del(conn->vneg.rx.ckm, conn->mem);
- ngtcp2_crypto_km_del(conn->vneg.tx.ckm, conn->mem);
- }
- void ngtcp2_conn_del(ngtcp2_conn *conn) {
- if (conn == NULL) {
- return;
- }
- ngtcp2_qlog_end(&conn->qlog);
- if (conn->early.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx);
- if (conn->crypto.key_update.old_rx_ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx);
- }
- if (conn->crypto.key_update.new_rx_ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->crypto.key_update.new_rx_ckm->aead_ctx);
- }
- if (conn->crypto.key_update.new_tx_ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->crypto.key_update.new_tx_ckm->aead_ctx);
- }
- if (conn->pktns.crypto.rx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn,
- &conn->pktns.crypto.rx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.rx.hp_ctx);
- if (conn->pktns.crypto.tx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn,
- &conn->pktns.crypto.tx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.tx.hp_ctx);
- if (conn->hs_pktns) {
- if (conn->hs_pktns->crypto.rx.ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->hs_pktns->crypto.rx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.rx.hp_ctx);
- if (conn->hs_pktns->crypto.tx.ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->hs_pktns->crypto.tx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.tx.hp_ctx);
- }
- if (conn->in_pktns) {
- if (conn->in_pktns->crypto.rx.ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->in_pktns->crypto.rx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.rx.hp_ctx);
- if (conn->in_pktns->crypto.tx.ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->in_pktns->crypto.tx.ckm->aead_ctx);
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.tx.hp_ctx);
- }
- conn_call_delete_crypto_aead_ctx(conn, &conn->crypto.retry_aead_ctx);
- ngtcp2_transport_params_del(conn->remote.transport_params, conn->mem);
- ngtcp2_transport_params_del(conn->remote.pending_transport_params, conn->mem);
- conn_vneg_crypto_free(conn);
- ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base);
- ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_hp_buf.base);
- ngtcp2_mem_free(conn->mem, (uint8_t *)conn->local.settings.token);
- ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem);
- ngtcp2_crypto_km_del(conn->crypto.key_update.new_rx_ckm, conn->mem);
- ngtcp2_crypto_km_del(conn->crypto.key_update.new_tx_ckm, conn->mem);
- ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
- pktns_free(&conn->pktns, conn->mem);
- pktns_del(conn->hs_pktns, conn->mem);
- pktns_del(conn->in_pktns, conn->mem);
- ngtcp2_pmtud_del(conn->pmtud);
- ngtcp2_pv_del(conn->pv);
- ngtcp2_mem_free(conn->mem, (uint8_t *)conn->rx.ccerr.reason);
- ngtcp2_idtr_free(&conn->remote.uni.idtr);
- ngtcp2_idtr_free(&conn->remote.bidi.idtr);
- ngtcp2_mem_free(conn->mem, conn->tx.ack);
- ngtcp2_pq_free(&conn->tx.strmq);
- ngtcp2_map_each(&conn->strms, delete_strms_each, (void *)conn);
- ngtcp2_map_free(&conn->strms);
- ngtcp2_pq_free(&conn->scid.used);
- delete_scid(&conn->scid.set, conn->mem);
- ngtcp2_ksl_free(&conn->scid.set);
- ngtcp2_gaptr_free(&conn->dcid.seqgap);
- ngtcp2_objalloc_free(&conn->strm_objalloc);
- ngtcp2_objalloc_free(&conn->rtb_entry_objalloc);
- ngtcp2_objalloc_free(&conn->frc_objalloc);
- ngtcp2_mem_free(conn->mem, conn);
- }
- /*
- * conn_ensure_ack_ranges makes sure that conn->tx.ack->ack.ranges can
- * contain at least |n| additional ngtcp2_ack_range.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_ensure_ack_ranges(ngtcp2_conn *conn, size_t n) {
- ngtcp2_frame *fr;
- size_t max = conn->tx.max_ack_ranges;
- if (n <= max) {
- return 0;
- }
- max *= 2;
- assert(max >= n);
- fr = ngtcp2_mem_realloc(conn->mem, conn->tx.ack,
- sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_range) * max);
- if (fr == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- conn->tx.ack = fr;
- conn->tx.max_ack_ranges = max;
- return 0;
- }
- /*
- * conn_compute_ack_delay computes ACK delay for outgoing protected
- * ACK.
- */
- static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) {
- return ngtcp2_min_uint64(
- conn->local.transport_params.max_ack_delay,
- ngtcp2_max_uint64(conn->cstat.smoothed_rtt / 8, NGTCP2_NANOSECONDS));
- }
- int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
- ngtcp2_pktns *pktns, uint8_t type,
- ngtcp2_tstamp ts, ngtcp2_duration ack_delay,
- uint64_t ack_delay_exponent) {
- /* TODO Measure an actual size of ACK blocks to find the best
- default value. */
- const size_t initial_max_ack_ranges = 8;
- int64_t last_pkt_num;
- ngtcp2_acktr *acktr = &pktns->acktr;
- ngtcp2_ack_range *range;
- ngtcp2_ksl_it it;
- ngtcp2_acktr_entry *rpkt;
- ngtcp2_ack *ack;
- size_t range_idx;
- ngtcp2_tstamp largest_ack_ts;
- int rv;
- if (acktr->flags & NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK) {
- ack_delay = 0;
- }
- if (!ngtcp2_acktr_require_active_ack(acktr, ack_delay, ts)) {
- return 0;
- }
- it = ngtcp2_acktr_get(acktr);
- if (ngtcp2_ksl_it_end(&it)) {
- ngtcp2_acktr_commit_ack(acktr);
- return 0;
- }
- if (conn->tx.ack == NULL) {
- conn->tx.ack = ngtcp2_mem_malloc(
- conn->mem,
- sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_range) * initial_max_ack_ranges);
- if (conn->tx.ack == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- conn->tx.max_ack_ranges = initial_max_ack_ranges;
- }
- ack = &conn->tx.ack->ack;
- if (pktns->rx.ecn.ect0 || pktns->rx.ecn.ect1 || pktns->rx.ecn.ce) {
- ack->type = NGTCP2_FRAME_ACK_ECN;
- ack->ecn.ect0 = pktns->rx.ecn.ect0;
- ack->ecn.ect1 = pktns->rx.ecn.ect1;
- ack->ecn.ce = pktns->rx.ecn.ce;
- } else {
- ack->type = NGTCP2_FRAME_ACK;
- }
- ack->rangecnt = 0;
- rpkt = ngtcp2_ksl_it_get(&it);
- if (rpkt->pkt_num == pktns->rx.max_pkt_num) {
- last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
- largest_ack_ts = rpkt->tstamp;
- ack->largest_ack = rpkt->pkt_num;
- ack->first_ack_range = rpkt->len - 1;
- ngtcp2_ksl_it_next(&it);
- } else if (rpkt->pkt_num + 1 == pktns->rx.max_pkt_num) {
- last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
- largest_ack_ts = pktns->rx.max_pkt_ts;
- ack->largest_ack = pktns->rx.max_pkt_num;
- ack->first_ack_range = rpkt->len;
- ngtcp2_ksl_it_next(&it);
- } else {
- assert(rpkt->pkt_num < pktns->rx.max_pkt_num);
- last_pkt_num = pktns->rx.max_pkt_num;
- largest_ack_ts = pktns->rx.max_pkt_ts;
- ack->largest_ack = pktns->rx.max_pkt_num;
- ack->first_ack_range = 0;
- }
- if (type == NGTCP2_PKT_1RTT) {
- ack->ack_delay_unscaled = ts - largest_ack_ts;
- ack->ack_delay = ack->ack_delay_unscaled / NGTCP2_MICROSECONDS /
- (1ULL << ack_delay_exponent);
- } else {
- ack->ack_delay_unscaled = 0;
- ack->ack_delay = 0;
- }
- for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
- if (ack->rangecnt == NGTCP2_MAX_ACK_RANGES) {
- break;
- }
- rpkt = ngtcp2_ksl_it_get(&it);
- range_idx = ack->rangecnt++;
- rv = conn_ensure_ack_ranges(conn, ack->rangecnt);
- if (rv != 0) {
- return rv;
- }
- ack = &conn->tx.ack->ack;
- range = &ack->ranges[range_idx];
- range->gap = (uint64_t)(last_pkt_num - rpkt->pkt_num - 2);
- range->len = rpkt->len - 1;
- last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
- }
- /* TODO Just remove entries which cannot fit into a single ACK frame
- for now. */
- if (!ngtcp2_ksl_it_end(&it)) {
- ngtcp2_acktr_forget(acktr, ngtcp2_ksl_it_get(&it));
- }
- *pfr = conn->tx.ack;
- return 0;
- }
- /*
- * conn_ppe_write_frame writes |fr| to |ppe|. If |hd_logged| is not
- * NULL and |*hd_logged| is zero, packet header is logged, and 1 is
- * assigned to |*hd_logged|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOBUF
- * Buffer is too small.
- */
- static int conn_ppe_write_frame_hd_log(ngtcp2_conn *conn, ngtcp2_ppe *ppe,
- int *hd_logged, const ngtcp2_pkt_hd *hd,
- ngtcp2_frame *fr) {
- int rv;
- rv = ngtcp2_ppe_encode_frame(ppe, fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return rv;
- }
- if (hd_logged && !*hd_logged) {
- *hd_logged = 1;
- ngtcp2_log_tx_pkt_hd(&conn->log, hd);
- ngtcp2_qlog_pkt_sent_start(&conn->qlog);
- }
- ngtcp2_log_tx_fr(&conn->log, hd, fr);
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
- return 0;
- }
- /*
- * conn_ppe_write_frame writes |fr| to |ppe|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOBUF
- * Buffer is too small.
- */
- static int conn_ppe_write_frame(ngtcp2_conn *conn, ngtcp2_ppe *ppe,
- const ngtcp2_pkt_hd *hd, ngtcp2_frame *fr) {
- return conn_ppe_write_frame_hd_log(conn, ppe, NULL, hd, fr);
- }
- /*
- * conn_on_pkt_sent is called when new non-ACK-only packet is sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- */
- static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
- ngtcp2_rtb_entry *ent) {
- ngtcp2_rtb *rtb = &pktns->rtb;
- int rv;
- /* This function implements OnPacketSent, but it handles only
- non-ACK-only packet. */
- rv = ngtcp2_rtb_add(rtb, ent, &conn->cstat);
- if (rv != 0) {
- return rv;
- }
- if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
- conn->cstat.last_tx_pkt_ts[pktns->id] = ent->ts;
- }
- ngtcp2_conn_set_loss_detection_timer(conn, ent->ts);
- return 0;
- }
- /*
- * pktns_select_pkt_numlen selects shortest packet number encoding for
- * the next packet number based on the largest acknowledged packet
- * number. It returns the number of bytes to encode the packet
- * number.
- */
- static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) {
- int64_t pkt_num = pktns->tx.last_pkt_num + 1;
- ngtcp2_rtb *rtb = &pktns->rtb;
- int64_t n = pkt_num - rtb->largest_acked_tx_pkt_num;
- if (NGTCP2_MAX_PKT_NUM / 2 < n) {
- return 4;
- }
- n = n * 2 - 1;
- if (n > 0xffffff) {
- return 4;
- }
- if (n > 0xffff) {
- return 3;
- }
- if (n > 0xff) {
- return 2;
- }
- return 1;
- }
- /*
- * conn_get_cwnd returns cwnd for the current path.
- */
- static uint64_t conn_get_cwnd(ngtcp2_conn *conn) {
- return conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE)
- ? ngtcp2_cc_compute_initcwnd(conn->cstat.max_tx_udp_payload_size)
- : conn->cstat.cwnd;
- }
- /*
- * conn_cwnd_is_zero returns nonzero if the number of bytes the local
- * endpoint can sent at this time is zero.
- */
- static int conn_cwnd_is_zero(ngtcp2_conn *conn) {
- uint64_t bytes_in_flight = conn->cstat.bytes_in_flight;
- uint64_t cwnd = conn_get_cwnd(conn);
- if (bytes_in_flight >= cwnd) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
- "cwnd limited bytes_in_flight=%lu cwnd=%lu",
- bytes_in_flight, cwnd);
- }
- return bytes_in_flight >= cwnd;
- }
- /*
- * conn_retry_early_payloadlen returns the estimated wire length of
- * the first STREAM frame of 0-RTT packet which should be
- * retransmitted due to Retry packet.
- */
- static uint64_t conn_retry_early_payloadlen(ngtcp2_conn *conn) {
- ngtcp2_frame_chain *frc;
- ngtcp2_strm *strm;
- uint64_t len;
- if (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) {
- return 0;
- }
- for (; !ngtcp2_pq_empty(&conn->tx.strmq);) {
- strm = ngtcp2_conn_tx_strmq_top(conn);
- if (ngtcp2_strm_streamfrq_empty(strm)) {
- ngtcp2_conn_tx_strmq_pop(conn);
- continue;
- }
- frc = ngtcp2_strm_streamfrq_top(strm);
- len = ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt) +
- NGTCP2_STREAM_OVERHEAD;
- /* Take the min because in conn_should_pad_pkt we take max in
- order to deal with unbreakable DATAGRAM. */
- return ngtcp2_min_uint64(len, NGTCP2_MIN_COALESCED_PAYLOADLEN);
- }
- return 0;
- }
- /*
- * conn_verify_dcid verifies that destination connection ID in |hd| is
- * valid for the connection. If it is successfully verified and the
- * remote endpoint uses new DCID in the packet, nonzero value is
- * assigned to |*pnew_cid_used| if it is not NULL. Otherwise 0 is
- * assigned to it.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_INVALID_ARGUMENT
- * |dcid| is not known to the local endpoint.
- */
- static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used,
- const ngtcp2_pkt_hd *hd) {
- ngtcp2_ksl_it it;
- ngtcp2_scid *scid;
- int rv;
- it = ngtcp2_ksl_lower_bound(&conn->scid.set, &hd->dcid);
- if (ngtcp2_ksl_it_end(&it)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- scid = ngtcp2_ksl_it_get(&it);
- if (!ngtcp2_cid_eq(&scid->cid, &hd->dcid)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- if (!(scid->flags & NGTCP2_SCID_FLAG_USED)) {
- scid->flags |= NGTCP2_SCID_FLAG_USED;
- if (scid->pe.index == NGTCP2_PQ_BAD_INDEX) {
- rv = ngtcp2_pq_push(&conn->scid.used, &scid->pe);
- if (rv != 0) {
- return rv;
- }
- }
- if (pnew_cid_used) {
- *pnew_cid_used = 1;
- }
- } else if (pnew_cid_used) {
- *pnew_cid_used = 0;
- }
- return 0;
- }
- /*
- * conn_should_pad_pkt returns nonzero if the packet should be padded.
- * |type| is the type of packet. |left| is the space left in packet
- * buffer. |write_datalen| is the number of bytes which will be sent
- * in the next, coalesced 0-RTT packet.
- */
- static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left,
- uint64_t write_datalen, int ack_eliciting,
- int require_padding) {
- uint64_t min_payloadlen;
- if (type == NGTCP2_PKT_INITIAL) {
- if (conn->server) {
- if (!ack_eliciting) {
- return 0;
- }
- if ((conn->hs_pktns->crypto.tx.ckm &&
- (conn->hs_pktns->rtb.probe_pkt_left ||
- !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm) ||
- !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) ||
- conn->pktns.crypto.tx.ckm) {
- /* If we have something to send in Handshake or 1RTT packet,
- then add PADDING in that packet. */
- min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN;
- } else {
- return 1;
- }
- } else {
- if (conn->hs_pktns->crypto.tx.ckm &&
- (conn->hs_pktns->rtb.probe_pkt_left ||
- !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm) ||
- !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) {
- /* If we have something to send in Handshake packet, then add
- PADDING in Handshake packet. */
- min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN;
- } else if (conn->early.ckm && write_datalen > 0) {
- /* If we have something to send in 0RTT packet, then add
- PADDING in that packet. Take maximum in case that
- write_datalen includes DATAGRAM which cannot be split. */
- min_payloadlen =
- ngtcp2_max_uint64(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN);
- } else {
- return 1;
- }
- }
- } else {
- assert(type == NGTCP2_PKT_HANDSHAKE);
- if (!require_padding) {
- return 0;
- }
- if (!conn->pktns.crypto.tx.ckm) {
- return 1;
- }
- min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN;
- }
- /* TODO the next packet type should be taken into account */
- return left <
- /* TODO Assuming that pkt_num is encoded in 1 byte. */
- NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen +
- conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen +
- NGTCP2_MAX_AEAD_OVERHEAD;
- }
- static void conn_restart_timer_on_write(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- conn->idle_ts = ts;
- conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE;
- }
- static void conn_restart_timer_on_read(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- conn->idle_ts = ts;
- conn->flags |= NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE;
- }
- /*
- * conn_keep_alive_enabled returns nonzero if keep-alive is enabled.
- */
- static int conn_keep_alive_enabled(ngtcp2_conn *conn) {
- return conn->keep_alive.last_ts != UINT64_MAX &&
- conn->keep_alive.timeout != UINT64_MAX;
- }
- /*
- * conn_keep_alive_expired returns nonzero if keep-alive timer has
- * expired.
- */
- static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- return ngtcp2_tstamp_elapsed(conn->keep_alive.last_ts,
- conn->keep_alive.timeout, ts);
- }
- /*
- * conn_keep_alive_expiry returns the expiry time of keep-alive timer.
- */
- static ngtcp2_tstamp conn_keep_alive_expiry(ngtcp2_conn *conn) {
- if ((conn->flags & NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED) ||
- !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) ||
- !conn_keep_alive_enabled(conn) ||
- conn->keep_alive.last_ts >= UINT64_MAX - conn->keep_alive.timeout) {
- return UINT64_MAX;
- }
- return conn->keep_alive.last_ts + conn->keep_alive.timeout;
- }
- /*
- * conn_cancel_expired_keep_alive_timer cancels the expired keep-alive
- * timer.
- */
- static void conn_cancel_expired_keep_alive_timer(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- if (!(conn->flags & NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED) &&
- conn_keep_alive_expired(conn, ts)) {
- conn->flags |= NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED;
- }
- }
- /*
- * conn_update_keep_alive_last_ts updates the base time point of
- * keep-alive timer.
- */
- static void conn_update_keep_alive_last_ts(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- conn->keep_alive.last_ts = ts;
- conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED;
- }
- void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn,
- ngtcp2_duration timeout) {
- if (timeout == 0) {
- timeout = UINT64_MAX;
- }
- conn->keep_alive.timeout = timeout;
- }
- /*
- * NGTCP2_PKT_PACING_OVERHEAD defines overhead of userspace event
- * loop. Packet pacing might require sub milliseconds packet spacing,
- * but userspace event loop might not offer such precision.
- * Typically, if delay is 0.5 microseconds, the actual delay after
- * which we can send packet is well over 1 millisecond when event loop
- * is involved (which includes other stuff, like reading packets etc
- * in a typical single threaded use case).
- */
- #define NGTCP2_PKT_PACING_OVERHEAD NGTCP2_MILLISECONDS
- static void conn_cancel_expired_pkt_tx_timer(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- if (conn->tx.pacing.next_ts == UINT64_MAX) {
- return;
- }
- if (conn->tx.pacing.next_ts > ts + NGTCP2_PKT_PACING_OVERHEAD) {
- return;
- }
- conn->tx.pacing.next_ts = UINT64_MAX;
- }
- static int conn_pacing_pkt_tx_allowed(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- return conn->tx.pacing.next_ts == UINT64_MAX ||
- conn->tx.pacing.next_ts <= ts + NGTCP2_PKT_PACING_OVERHEAD;
- }
- static uint8_t conn_pkt_flags(ngtcp2_conn *conn) {
- if (conn->remote.transport_params &&
- conn->remote.transport_params->grease_quic_bit &&
- (conn->flags & NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT)) {
- return NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR;
- }
- return NGTCP2_PKT_FLAG_NONE;
- }
- static uint8_t conn_pkt_flags_long(ngtcp2_conn *conn) {
- return NGTCP2_PKT_FLAG_LONG_FORM | conn_pkt_flags(conn);
- }
- static uint8_t conn_pkt_flags_short(ngtcp2_conn *conn) {
- return (uint8_t)(conn_pkt_flags(conn) | ((conn->pktns.crypto.tx.ckm->flags &
- NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE)
- ? NGTCP2_PKT_FLAG_KEY_PHASE
- : NGTCP2_PKT_FLAG_NONE));
- }
- static size_t conn_min_pktlen(ngtcp2_conn *conn);
- /*
- * conn_write_handshake_pkt writes handshake packet in the buffer
- * pointed by |dest| whose length is |destlen|. |dgram_offset| is the
- * offset in UDP datagram payload where this QUIC packet is positioned
- * at. |type| specifies long packet type. It should be either
- * NGTCP2_PKT_INITIAL or NGTCP2_PKT_HANDSHAKE_PKT.
- *
- * |write_datalen| is the minimum length of application data ready to
- * send in subsequent 0RTT packet.
- *
- * This function returns the number of bytes written in |dest| if it
- * succeeds, or one of the following negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static ngtcp2_ssize
- conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, size_t dgram_offset, uint8_t type,
- uint8_t flags, uint64_t write_datalen,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_ppe ppe;
- ngtcp2_pkt_hd hd;
- ngtcp2_frame_chain *frq = NULL, **pfrc = &frq;
- ngtcp2_frame_chain *nfrc;
- ngtcp2_frame *ackfr = NULL, lfr;
- ngtcp2_ssize spktlen;
- ngtcp2_crypto_cc cc;
- ngtcp2_rtb_entry *rtbent;
- ngtcp2_pktns *pktns;
- size_t left;
- uint16_t rtb_entry_flags = NGTCP2_RTB_ENTRY_FLAG_NONE;
- int require_padding = (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) != 0;
- int pkt_empty = 1;
- int min_padded = 0;
- int padded = 0;
- int hd_logged = 0;
- uint64_t crypto_offset;
- ngtcp2_ssize num_reclaimed;
- uint32_t version;
- switch (type) {
- case NGTCP2_PKT_INITIAL:
- if (!conn->in_pktns) {
- return 0;
- }
- assert(conn->in_pktns->crypto.tx.ckm);
- pktns = conn->in_pktns;
- version = conn->negotiated_version ? conn->negotiated_version
- : conn->client_chosen_version;
- if (version == conn->client_chosen_version) {
- cc.ckm = pktns->crypto.tx.ckm;
- cc.hp_ctx = pktns->crypto.tx.hp_ctx;
- } else {
- assert(conn->vneg.version == version);
- cc.ckm = conn->vneg.tx.ckm;
- cc.hp_ctx = conn->vneg.tx.hp_ctx;
- }
- break;
- case NGTCP2_PKT_HANDSHAKE:
- if (!conn->hs_pktns || !conn->hs_pktns->crypto.tx.ckm) {
- return 0;
- }
- pktns = conn->hs_pktns;
- version = conn->negotiated_version;
- cc.ckm = pktns->crypto.tx.ckm;
- cc.hp_ctx = pktns->crypto.tx.hp_ctx;
- break;
- default:
- ngtcp2_unreachable();
- }
- cc.aead = pktns->crypto.ctx.aead;
- cc.hp = pktns->crypto.ctx.hp;
- cc.encrypt = conn->callbacks.encrypt;
- cc.hp_mask = conn->callbacks.hp_mask;
- ngtcp2_pkt_hd_init(
- &hd, conn_pkt_flags_long(conn), type, &conn->dcid.current.cid, &conn->oscid,
- pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns), version, 0);
- if (!conn->server && type == NGTCP2_PKT_INITIAL &&
- conn->local.settings.tokenlen) {
- hd.token = conn->local.settings.token;
- hd.tokenlen = conn->local.settings.tokenlen;
- }
- ngtcp2_ppe_init(&ppe, dest, destlen, dgram_offset, &cc);
- rv = ngtcp2_ppe_encode_hd(&ppe, &hd);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return 0;
- }
- if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) {
- return 0;
- }
- rv = ngtcp2_conn_create_ack_frame(conn, &ackfr, pktns, type, ts,
- /* ack_delay = */ 0,
- NGTCP2_DEFAULT_ACK_DELAY_EXPONENT);
- if (rv != 0) {
- ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, conn->mem);
- return rv;
- }
- if (ackfr) {
- rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, ackfr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- } else {
- ngtcp2_acktr_commit_ack(&pktns->acktr);
- ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, ackfr->ack.largest_ack);
- pkt_empty = 0;
- }
- }
- /* Server requires at least NGTCP2_MAX_UDP_PAYLOAD_SIZE bytes in
- order to send ack-eliciting Initial packet. */
- if (!conn->server || type != NGTCP2_PKT_INITIAL ||
- destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- build_pkt:
- for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) {
- left = ngtcp2_ppe_left(&ppe);
- crypto_offset = ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm);
- if (crypto_offset == (uint64_t)-1) {
- ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm);
- break;
- }
- left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
- if (left == (size_t)-1) {
- break;
- }
- rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
- conn->mem);
- return rv;
- }
- if (nfrc == NULL) {
- break;
- }
- rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr);
- if (rv != 0) {
- ngtcp2_unreachable();
- }
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- }
- if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
- pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) {
- num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1);
- if (num_reclaimed < 0) {
- ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
- conn->mem);
- return rv;
- }
- if (num_reclaimed) {
- goto build_pkt;
- }
- /* We had pktns->rtb.num_retransmittable > 0 but the contents of
- those packets have been acknowledged (i.e., retransmission in
- another packet). For server, in this case, we don't have to
- send any probe packet. Client needs to send probe packets
- until it knows that server has completed address validation or
- handshake has been confirmed. */
- if (pktns->rtb.num_pto_eliciting == 0 &&
- (conn->server ||
- (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED |
- NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) {
- pktns->rtb.probe_pkt_left = 0;
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- /* TODO If packet is empty, we should return now if cwnd is
- zero. */
- }
- }
- if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
- pktns->rtb.probe_pkt_left) {
- lfr.type = NGTCP2_FRAME_PING;
- rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
- if (rv != 0) {
- assert(rv == NGTCP2_ERR_NOBUF);
- } else {
- rtb_entry_flags |=
- NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_PROBE;
- pkt_empty = 0;
- }
- }
- if (!pkt_empty) {
- if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts,
- conn->cstat.smoothed_rtt, ts)) {
- lfr.type = NGTCP2_FRAME_PING;
- rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
- if (rv != 0) {
- assert(rv == NGTCP2_ERR_NOBUF);
- } else {
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING;
- pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
- pkt_empty = 0;
- }
- } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) {
- pktns->tx.non_ack_pkt_start_ts = ts;
- }
- } else {
- pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
- }
- }
- }
- if (pkt_empty && !require_padding) {
- return 0;
- }
- /* If we cannot write another packet, then we need to add padding to
- Initial here. */
- if (conn_should_pad_pkt(
- conn, type, ngtcp2_ppe_left(&ppe), write_datalen,
- (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) != 0,
- require_padding)) {
- lfr.type = NGTCP2_FRAME_PADDING;
- lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
- } else if (pkt_empty) {
- return 0;
- } else {
- lfr.type = NGTCP2_FRAME_PADDING;
- lfr.padding.len = ngtcp2_ppe_padding_size(&ppe, conn_min_pktlen(conn));
- min_padded = 1;
- }
- if (lfr.padding.len) {
- if (!min_padded ||
- (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- padded = 1;
- }
- ngtcp2_log_tx_fr(&conn->log, &hd, &lfr);
- ngtcp2_qlog_write_frame(&conn->qlog, &lfr);
- }
- spktlen = ngtcp2_ppe_final(&ppe, NULL);
- if (spktlen < 0) {
- assert(ngtcp2_err_is_fatal((int)spktlen));
- ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, conn->mem);
- return spktlen;
- }
- ngtcp2_qlog_pkt_sent_end(&conn->qlog, &hd, (size_t)spktlen);
- if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) {
- if (pi) {
- conn_handle_tx_ecn(conn, pi, &rtb_entry_flags, pktns, &hd, ts);
- }
- rv =
- ngtcp2_rtb_entry_objalloc_new(&rtbent, &hd, frq, ts, (size_t)spktlen,
- rtb_entry_flags, &conn->rtb_entry_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, conn->mem);
- return rv;
- }
- rv = conn_on_pkt_sent(conn, pktns, rtbent);
- if (rv != 0) {
- ngtcp2_rtb_entry_objalloc_del(rtbent, &conn->rtb_entry_objalloc,
- &conn->frc_objalloc, conn->mem);
- return rv;
- }
- if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
- (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE)) {
- conn_restart_timer_on_write(conn, ts);
- }
- } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
- conn_handle_tx_ecn(conn, pi, NULL, pktns, &hd, ts);
- }
- if (pktns->rtb.probe_pkt_left &&
- (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- --pktns->rtb.probe_pkt_left;
- }
- conn_update_keep_alive_last_ts(conn, ts);
- conn->dcid.current.bytes_sent += (uint64_t)spktlen;
- conn->tx.pacing.pktlen += (size_t)spktlen;
- ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
- ++pktns->tx.last_pkt_num;
- return spktlen;
- }
- /*
- * conn_write_ack_pkt writes QUIC packet for type |type| which only
- * includes ACK frame in the buffer pointed by |dest| whose length is
- * |destlen|.
- *
- * This function returns the number of bytes written in |dest| if it
- * succeeds, or one of the following negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- uint8_t type, ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_frame *ackfr;
- ngtcp2_pktns *pktns;
- ngtcp2_duration ack_delay;
- uint64_t ack_delay_exponent;
- ngtcp2_ssize spktlen;
- assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING));
- switch (type) {
- case NGTCP2_PKT_INITIAL:
- assert(conn->server);
- pktns = conn->in_pktns;
- ack_delay = 0;
- ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
- break;
- case NGTCP2_PKT_HANDSHAKE:
- pktns = conn->hs_pktns;
- ack_delay = 0;
- ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
- break;
- case NGTCP2_PKT_1RTT:
- pktns = &conn->pktns;
- ack_delay = conn_compute_ack_delay(conn);
- ack_delay_exponent = conn->local.transport_params.ack_delay_exponent;
- break;
- default:
- ngtcp2_unreachable();
- }
- if (!pktns->crypto.tx.ckm) {
- return 0;
- }
- ackfr = NULL;
- rv = ngtcp2_conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay,
- ack_delay_exponent);
- if (rv != 0) {
- return rv;
- }
- if (!ackfr) {
- return 0;
- }
- spktlen = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, type, NGTCP2_WRITE_PKT_FLAG_NONE,
- &conn->dcid.current.cid, ackfr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
- if (spktlen <= 0) {
- return spktlen;
- }
- conn->dcid.current.bytes_sent += (uint64_t)spktlen;
- return spktlen;
- }
- static void conn_discard_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns,
- ngtcp2_tstamp ts) {
- ngtcp2_pktns *pktns = *ppktns;
- uint64_t bytes_in_flight;
- bytes_in_flight = pktns->rtb.cc_bytes_in_flight;
- assert(conn->cstat.bytes_in_flight >= bytes_in_flight);
- conn->cstat.bytes_in_flight -= bytes_in_flight;
- conn->cstat.pto_count = 0;
- conn->cstat.last_tx_pkt_ts[pktns->id] = UINT64_MAX;
- conn->cstat.loss_time[pktns->id] = UINT64_MAX;
- conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx);
- conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx);
- conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx);
- conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx);
- pktns_del(pktns, conn->mem);
- *ppktns = NULL;
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- }
- void ngtcp2_conn_discard_initial_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- if (!conn->in_pktns) {
- return;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "discarding Initial packet number space");
- conn_discard_pktns(conn, &conn->in_pktns, ts);
- conn_vneg_crypto_free(conn);
- memset(&conn->vneg.rx, 0, sizeof(conn->vneg.rx));
- memset(&conn->vneg.tx, 0, sizeof(conn->vneg.tx));
- }
- void ngtcp2_conn_discard_handshake_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- if (!conn->hs_pktns) {
- return;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "discarding Handshake packet number space");
- conn_discard_pktns(conn, &conn->hs_pktns, ts);
- }
- /*
- * conn_discard_early_key discards early key.
- */
- static void conn_discard_early_key(ngtcp2_conn *conn) {
- assert(conn->early.ckm);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "discarding early key");
- conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx);
- conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx);
- memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx));
- ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
- conn->early.ckm = NULL;
- }
- /*
- * conn_write_handshake_ack_pkts writes packets which contain ACK
- * frame only. This function writes at most 2 packets for each
- * Initial and Handshake packet.
- */
- static ngtcp2_ssize conn_write_handshake_ack_pkts(ngtcp2_conn *conn,
- ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- ngtcp2_tstamp ts) {
- ngtcp2_ssize res = 0, nwrite = 0;
- /* In the most cases, client sends ACK in conn_write_handshake_pkt.
- This function is only called when it is CWND limited or pacing
- limited. It is not required for client to send ACK for server
- Initial. This is because once it gets server Initial, it gets
- Handshake tx key and discards Initial key. The only good reason
- to send ACK is give server RTT measurement early. */
- if (conn->server && conn->in_pktns) {
- nwrite =
- conn_write_ack_pkt(conn, pi, dest, destlen, NGTCP2_PKT_INITIAL, ts);
- if (nwrite < 0) {
- assert(nwrite != NGTCP2_ERR_NOBUF);
- return nwrite;
- }
- res += nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- }
- if (conn->hs_pktns->crypto.tx.ckm) {
- nwrite =
- conn_write_ack_pkt(conn, pi, dest, destlen, NGTCP2_PKT_HANDSHAKE, ts);
- if (nwrite < 0) {
- assert(nwrite != NGTCP2_ERR_NOBUF);
- return nwrite;
- }
- res += nwrite;
- if (!conn->server && nwrite) {
- ngtcp2_conn_discard_initial_state(conn, ts);
- }
- }
- return res;
- }
- /*
- * conn_write_client_initial writes Initial packet in the buffer
- * pointed by |dest| whose length is |destlen|.
- *
- * This function returns the number of bytes written in |dest| if it
- * succeeds, or one of the following negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static ngtcp2_ssize conn_write_client_initial(ngtcp2_conn *conn,
- ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- uint64_t early_datalen,
- ngtcp2_tstamp ts) {
- int rv;
- rv = conn_call_client_initial(conn);
- if (rv != 0) {
- return rv;
- }
- return conn_write_handshake_pkt(
- conn, pi, dest, destlen, 0, NGTCP2_PKT_INITIAL, NGTCP2_WRITE_PKT_FLAG_NONE,
- early_datalen, ts);
- }
- /*
- * dcid_tx_left returns the maximum number of bytes that server is
- * allowed to send to an unvalidated path associated to |dcid|.
- */
- static uint64_t dcid_tx_left(ngtcp2_dcid *dcid) {
- if (dcid->flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) {
- return SIZE_MAX;
- }
- /* From QUIC spec: Prior to validating the client address, servers
- MUST NOT send more than three times as many bytes as the number
- of bytes they have received. */
- assert(dcid->bytes_recv * 3 >= dcid->bytes_sent);
- return dcid->bytes_recv * 3 - dcid->bytes_sent;
- }
- /*
- * conn_server_tx_left returns the maximum number of bytes that server
- * is allowed to send to an unvalidated path.
- */
- static uint64_t conn_server_tx_left(ngtcp2_conn *conn, ngtcp2_dcid *dcid) {
- assert(conn->server);
- /* If pv->dcid has the current path, use conn->dcid.current. This
- is because conn->dcid.current gets update for bytes_recv and
- bytes_sent. */
- if (ngtcp2_path_eq(&dcid->ps.path, &conn->dcid.current.ps.path)) {
- return dcid_tx_left(&conn->dcid.current);
- }
- return dcid_tx_left(dcid);
- }
- /*
- * conn_write_handshake_pkts writes Initial and Handshake packets in
- * the buffer pointed by |dest| whose length is |destlen|.
- *
- * This function returns the number of bytes written in |dest| if it
- * succeeds, or one of the following negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static ngtcp2_ssize conn_write_handshake_pkts(ngtcp2_conn *conn,
- ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- uint64_t write_datalen,
- ngtcp2_tstamp ts) {
- ngtcp2_ssize nwrite;
- ngtcp2_ssize res = 0;
- ngtcp2_rtb_entry *rtbent;
- uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE;
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_ksl_it it;
- /* As a client, we would like to discard Initial packet number space
- when sending the first Handshake packet. When sending Handshake
- packet, it should be one of 1) sending ACK, 2) sending PTO probe
- packet, or 3) sending CRYPTO. If we have pending acknowledgement
- for Initial, then do not discard Initial packet number space.
- Otherwise, if either 1) or 2) is satisfied, discard Initial
- packet number space. When sending Handshake CRYPTO, it indicates
- that client has received Handshake CRYPTO from server. Initial
- packet number space is discarded because 1) is met. If there is
- pending Initial ACK, Initial packet number space is discarded
- after writing the first Handshake packet.
- */
- if (!conn->server && conn->hs_pktns->crypto.tx.ckm && conn->in_pktns &&
- !ngtcp2_acktr_require_active_ack(&conn->in_pktns->acktr,
- /* max_ack_delay = */ 0, ts) &&
- (ngtcp2_acktr_require_active_ack(&conn->hs_pktns->acktr,
- /* max_ack_delay = */ 0, ts) ||
- conn->hs_pktns->rtb.probe_pkt_left)) {
- /* Discard Initial state here so that Handshake packet is not
- padded. */
- ngtcp2_conn_discard_initial_state(conn, ts);
- } else if (conn->in_pktns) {
- nwrite =
- conn_write_handshake_pkt(conn, pi, dest, destlen, 0, NGTCP2_PKT_INITIAL,
- NGTCP2_WRITE_PKT_FLAG_NONE, write_datalen, ts);
- if (nwrite < 0) {
- assert(nwrite != NGTCP2_ERR_NOBUF);
- return nwrite;
- }
- if (nwrite == 0) {
- if (conn->server &&
- (conn->in_pktns->rtb.probe_pkt_left ||
- !ngtcp2_strm_streamfrq_empty(&conn->in_pktns->crypto.strm))) {
- if (cstat->loss_detection_timer != UINT64_MAX &&
- conn_server_tx_left(conn, &conn->dcid.current) <
- NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss detection timer canceled due to amplification limit");
- ngtcp2_conn_cancel_loss_detection_timer(conn);
- }
- return 0;
- }
- } else {
- res += nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- /* If initial packet size is at least
- NGTCP2_MAX_UDP_PAYLOAD_SIZE, no extra padding is needed in a
- subsequent packet. */
- if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- if (conn->server) {
- it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
- if (!ngtcp2_ksl_it_end(&it)) {
- rtbent = ngtcp2_ksl_it_get(&it);
- if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- }
- } else {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- }
- }
- }
- nwrite =
- conn_write_handshake_pkt(conn, pi, dest, destlen, (size_t)res,
- NGTCP2_PKT_HANDSHAKE, wflags, write_datalen, ts);
- if (nwrite < 0) {
- assert(nwrite != NGTCP2_ERR_NOBUF);
- return nwrite;
- }
- res += nwrite;
- if (!conn->server && conn->hs_pktns->crypto.tx.ckm && nwrite) {
- /* We don't need to send further Initial packet if we have
- Handshake key and sent something with it. So discard initial
- state here. */
- ngtcp2_conn_discard_initial_state(conn, ts);
- }
- return res;
- }
- /*
- * conn_initial_stream_rx_offset returns the initial maximum offset of
- * data for a stream denoted by |stream_id|.
- */
- static uint64_t conn_initial_stream_rx_offset(ngtcp2_conn *conn,
- int64_t stream_id) {
- int local_stream = conn_local_stream(conn, stream_id);
- if (bidi_stream(stream_id)) {
- if (local_stream) {
- return conn->local.transport_params.initial_max_stream_data_bidi_local;
- }
- return conn->local.transport_params.initial_max_stream_data_bidi_remote;
- }
- if (local_stream) {
- return 0;
- }
- return conn->local.transport_params.initial_max_stream_data_uni;
- }
- /*
- * conn_should_send_max_stream_data returns nonzero if MAX_STREAM_DATA
- * frame should be send for |strm|.
- */
- static int conn_should_send_max_stream_data(ngtcp2_conn *conn,
- ngtcp2_strm *strm) {
- uint64_t inc = strm->rx.unsent_max_offset - strm->rx.max_offset;
- (void)conn;
- return strm->rx.window < 4 * inc;
- }
- /*
- * conn_should_send_max_data returns nonzero if MAX_DATA frame should
- * be sent.
- */
- static int conn_should_send_max_data(ngtcp2_conn *conn) {
- uint64_t inc = conn->rx.unsent_max_offset - conn->rx.max_offset;
- return conn->rx.window < 4 * inc;
- }
- /*
- * conn_required_num_new_connection_id returns the number of
- * additional connection ID the local endpoint has to provide to the
- * remote endpoint.
- */
- static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) {
- uint64_t n;
- size_t len = ngtcp2_ksl_len(&conn->scid.set);
- size_t lim;
- if (len >= NGTCP2_MAX_SCID_POOL_SIZE) {
- return 0;
- }
- assert(NGTCP2_MAX_SCID_POOL_SIZE >= conn->scid.num_in_flight);
- lim = NGTCP2_MAX_SCID_POOL_SIZE - conn->scid.num_in_flight;
- if (lim == 0) {
- return 0;
- }
- assert(conn->remote.transport_params);
- assert(conn->remote.transport_params->active_connection_id_limit);
- /* len includes retired CID. We don't provide extra CID if doing so
- exceeds NGTCP2_MAX_SCID_POOL_SIZE. */
- n = conn->remote.transport_params->active_connection_id_limit +
- conn->scid.num_retired;
- n = ngtcp2_min_uint64(NGTCP2_MAX_SCID_POOL_SIZE, n) - len;
- return (size_t)ngtcp2_min_uint64(lim, n);
- }
- /*
- * conn_enqueue_new_connection_id generates additional connection IDs
- * and prepares to send them to the remote endpoint.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) {
- size_t i, need = conn_required_num_new_connection_id(conn);
- size_t cidlen = conn->oscid.datalen;
- ngtcp2_cid cid;
- uint64_t seq;
- int rv;
- uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
- ngtcp2_frame_chain *nfrc;
- ngtcp2_pktns *pktns = &conn->pktns;
- ngtcp2_scid *scid;
- ngtcp2_ksl_it it;
- for (i = 0; i < need; ++i) {
- rv = conn_call_get_new_connection_id(conn, &cid, token, cidlen);
- if (rv != 0) {
- return rv;
- }
- if (cid.datalen != cidlen) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- /* Assert uniqueness */
- it = ngtcp2_ksl_lower_bound(&conn->scid.set, &cid);
- if (!ngtcp2_ksl_it_end(&it) &&
- ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it), &cid)) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- seq = ++conn->scid.last_seq;
- scid = ngtcp2_mem_malloc(conn->mem, sizeof(*scid));
- if (scid == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- ngtcp2_scid_init(scid, seq, &cid);
- rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scid->cid, scid);
- if (rv != 0) {
- ngtcp2_mem_free(conn->mem, scid);
- return rv;
- }
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_NEW_CONNECTION_ID;
- nfrc->fr.new_connection_id.seq = seq;
- nfrc->fr.new_connection_id.retire_prior_to = 0;
- nfrc->fr.new_connection_id.cid = cid;
- memcpy(nfrc->fr.new_connection_id.stateless_reset_token, token,
- sizeof(token));
- nfrc->next = pktns->tx.frq;
- pktns->tx.frq = nfrc;
- assert(NGTCP2_MAX_SCID_POOL_SIZE > conn->scid.num_in_flight);
- ++conn->scid.num_in_flight;
- }
- return 0;
- }
- /*
- * conn_remove_retired_connection_id removes the already retired
- * connection ID. It waits PTO before actually removing a connection
- * ID after it receives RETIRE_CONNECTION_ID from peer to catch
- * reordered packets.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_remove_retired_connection_id(ngtcp2_conn *conn,
- ngtcp2_duration pto,
- ngtcp2_tstamp ts) {
- ngtcp2_duration timeout = pto;
- ngtcp2_scid *scid;
- ngtcp2_dcid *dcid;
- int rv;
- for (; !ngtcp2_pq_empty(&conn->scid.used);) {
- scid = ngtcp2_struct_of(ngtcp2_pq_top(&conn->scid.used), ngtcp2_scid, pe);
- if (!ngtcp2_tstamp_elapsed(scid->retired_ts, timeout, ts)) {
- break;
- }
- assert(scid->flags & NGTCP2_SCID_FLAG_RETIRED);
- rv = conn_call_remove_connection_id(conn, &scid->cid);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_ksl_remove(&conn->scid.set, NULL, &scid->cid);
- ngtcp2_pq_pop(&conn->scid.used);
- ngtcp2_mem_free(conn->mem, scid);
- assert(conn->scid.num_retired);
- --conn->scid.num_retired;
- }
- for (; ngtcp2_ringbuf_len(&conn->dcid.retired.rb);) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.retired.rb, 0);
- if (dcid->retired_ts + timeout >= ts) {
- break;
- }
- rv = conn_call_deactivate_dcid(conn, dcid);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_ringbuf_pop_front(&conn->dcid.retired.rb);
- }
- return 0;
- }
- /*
- * conn_min_pktlen returns the minimum length of packet this endpoint
- * sends. It may underestimate the length because this does not take
- * into account header protection sample.
- */
- static size_t conn_min_pktlen(ngtcp2_conn *conn) {
- return conn->oscid.datalen + NGTCP2_MIN_PKT_EXPANDLEN;
- }
- /*
- * conn_handle_unconfirmed_key_update_from_remote deals with key
- * update which has not been confirmed yet and initiated by the remote
- * endpoint.
- *
- * If key update was initiated by the remote endpoint, acknowledging a
- * packet encrypted with the new key completes key update procedure.
- */
- static void conn_handle_unconfirmed_key_update_from_remote(ngtcp2_conn *conn,
- int64_t largest_ack,
- ngtcp2_tstamp ts) {
- if (!(conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) ||
- (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR) ||
- largest_ack < conn->pktns.crypto.rx.ckm->pkt_num) {
- return;
- }
- conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED;
- conn->crypto.key_update.confirmed_ts = ts;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed");
- }
- static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn);
- /*
- * strm_should_send_stream_data_blocked returns nonzero if
- * STREAM_DATA_BLOCKED frame should be sent to |strm|.
- */
- static int strm_should_send_stream_data_blocked(ngtcp2_strm *strm) {
- return strm->tx.offset == strm->tx.max_offset &&
- strm->tx.last_blocked_offset != strm->tx.max_offset;
- }
- /*
- * conn_should_send_data_blocked returns nonzero if DATA_BLOCKED frame
- * should be sent.
- */
- static int conn_should_send_data_blocked(ngtcp2_conn *conn) {
- return conn->tx.offset == conn->tx.max_offset &&
- conn->tx.last_blocked_offset != conn->tx.max_offset;
- }
- /*
- * conn_reset_ppe_pending clears NGTCP2_CONN_FLAG_PPE_PENDING flag and
- * nullifies conn->pkt.
- */
- static void conn_reset_ppe_pending(ngtcp2_conn *conn) {
- conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_PPE_PENDING;
- memset(&conn->pkt, 0, sizeof(conn->pkt));
- }
- /*
- * conn_write_pkt writes a protected packet in the buffer pointed by
- * |dest| whose length if |destlen|. |dgram_offset| is the offset in
- * UDP datagram payload where this QUIC packet is positioned at.
- * |type| specifies the type of packet. It can be NGTCP2_PKT_1RTT or
- * NGTCP2_PKT_0RTT.
- *
- * This function can send new stream data. In order to send stream
- * data, specify the underlying stream and parameters to
- * |vmsg|->stream. If |vmsg|->stream.fin is set to nonzero, it
- * signals that the given data is the final portion of the stream.
- * |vmsg|->stream.data vector of length |vmsg|->stream.datacnt
- * specifies stream data to send. The number of bytes sent to the
- * stream is assigned to *|vmsg|->stream.pdatalen. If 0 length STREAM
- * data is sent, 0 is assigned to it. The caller should initialize
- * *|vmsg|->stream.pdatalen to -1.
- *
- * If |require_padding| is nonzero, padding bytes are added to occupy
- * the remaining packet payload.
- *
- * This function returns the number of bytes written in |dest| if it
- * succeeds, or one of the following negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_STREAM_DATA_BLOCKED
- * Stream data could not be written because of flow control.
- */
- static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- size_t dgram_offset, ngtcp2_vmsg *vmsg,
- uint8_t type, uint8_t flags,
- ngtcp2_tstamp ts) {
- int rv = 0;
- ngtcp2_crypto_cc *cc = &conn->pkt.cc;
- ngtcp2_ppe *ppe = &conn->pkt.ppe;
- ngtcp2_pkt_hd *hd = &conn->pkt.hd;
- ngtcp2_frame *ackfr = NULL, lfr;
- ngtcp2_ssize nwrite;
- ngtcp2_frame_chain **pfrc, *nfrc, *frc;
- ngtcp2_rtb_entry *ent;
- ngtcp2_strm *strm;
- int pkt_empty = 1;
- uint64_t ndatalen = 0;
- int send_stream = 0;
- int stream_blocked = 0;
- int send_datagram = 0;
- ngtcp2_pktns *pktns = &conn->pktns;
- size_t left;
- uint64_t datalen = 0;
- ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
- size_t datacnt;
- uint16_t rtb_entry_flags = NGTCP2_RTB_ENTRY_FLAG_NONE;
- int hd_logged = 0;
- ngtcp2_path_challenge_entry *pcent;
- uint8_t hd_flags = NGTCP2_PKT_FLAG_NONE;
- int require_padding = (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) != 0;
- int write_more = (flags & NGTCP2_WRITE_PKT_FLAG_MORE) != 0;
- int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0;
- size_t min_pktlen = conn_min_pktlen(conn);
- int min_padded = 0;
- int padded = 0;
- ngtcp2_cc_pkt cc_pkt;
- uint64_t crypto_offset;
- uint64_t stream_offset;
- ngtcp2_ssize num_reclaimed;
- int fin;
- uint64_t target_max_data;
- ngtcp2_conn_stat *cstat = &conn->cstat;
- uint64_t delta;
- const ngtcp2_cid *scid = NULL;
- int keep_alive_expired = 0;
- uint32_t version = 0;
- /* Return 0 if destlen is less than minimum packet length which can
- trigger Stateless Reset */
- if (destlen < min_pktlen) {
- return 0;
- }
- if (vmsg) {
- switch (vmsg->type) {
- case NGTCP2_VMSG_TYPE_STREAM:
- datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt);
- ndatalen = conn_enforce_flow_control(conn, vmsg->stream.strm, datalen);
- /* 0 length STREAM frame is allowed */
- if (ndatalen || datalen == 0) {
- send_stream = 1;
- } else {
- stream_blocked = 1;
- }
- break;
- case NGTCP2_VMSG_TYPE_DATAGRAM:
- datalen = ngtcp2_vec_len(vmsg->datagram.data, vmsg->datagram.datacnt);
- send_datagram = 1;
- break;
- default:
- break;
- }
- }
- if (!ppe_pending) {
- switch (type) {
- case NGTCP2_PKT_1RTT:
- hd_flags = conn_pkt_flags_short(conn);
- scid = NULL;
- cc->aead = pktns->crypto.ctx.aead;
- cc->hp = pktns->crypto.ctx.hp;
- cc->ckm = pktns->crypto.tx.ckm;
- cc->hp_ctx = pktns->crypto.tx.hp_ctx;
- assert(conn->negotiated_version);
- version = conn->negotiated_version;
- /* transport parameter is only valid after handshake completion
- which means we don't know how many connection ID that remote
- peer can accept before handshake completion. Because server
- can use remote transport parameters sending stream data in
- 0.5 RTT, it is also allowed to use remote transport
- parameters here. */
- if (conn->oscid.datalen &&
- (conn->server || conn_is_tls_handshake_completed(conn))) {
- rv = conn_enqueue_new_connection_id(conn);
- if (rv != 0) {
- return rv;
- }
- }
- break;
- case NGTCP2_PKT_0RTT:
- assert(!conn->server);
- if (!conn->early.ckm) {
- return 0;
- }
- hd_flags = conn_pkt_flags_long(conn);
- scid = &conn->oscid;
- cc->aead = conn->early.ctx.aead;
- cc->hp = conn->early.ctx.hp;
- cc->ckm = conn->early.ckm;
- cc->hp_ctx = conn->early.hp_ctx;
- version = conn->client_chosen_version;
- break;
- default:
- /* Unreachable */
- ngtcp2_unreachable();
- }
- cc->encrypt = conn->callbacks.encrypt;
- cc->hp_mask = conn->callbacks.hp_mask;
- if (conn_should_send_max_data(conn)) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- if (conn->local.settings.max_window &&
- conn->tx.last_max_data_ts != UINT64_MAX &&
- ts - conn->tx.last_max_data_ts <
- NGTCP2_FLOW_WINDOW_RTT_FACTOR * cstat->smoothed_rtt &&
- conn->local.settings.max_window > conn->rx.window) {
- target_max_data = NGTCP2_FLOW_WINDOW_SCALING_FACTOR * conn->rx.window;
- if (target_max_data > conn->local.settings.max_window) {
- target_max_data = conn->local.settings.max_window;
- }
- delta = target_max_data - conn->rx.window;
- if (conn->rx.unsent_max_offset + delta > NGTCP2_MAX_VARINT) {
- delta = NGTCP2_MAX_VARINT - conn->rx.unsent_max_offset;
- }
- conn->rx.window = target_max_data;
- } else {
- delta = 0;
- }
- conn->tx.last_max_data_ts = ts;
- nfrc->fr.type = NGTCP2_FRAME_MAX_DATA;
- nfrc->fr.max_data.max_data = conn->rx.unsent_max_offset + delta;
- nfrc->next = pktns->tx.frq;
- pktns->tx.frq = nfrc;
- conn->rx.max_offset = conn->rx.unsent_max_offset =
- nfrc->fr.max_data.max_data;
- }
- if (stream_blocked && conn_should_send_max_data(conn)) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED;
- nfrc->fr.data_blocked.offset = conn->tx.max_offset;
- nfrc->next = pktns->tx.frq;
- pktns->tx.frq = nfrc;
- conn->tx.last_blocked_offset = conn->tx.max_offset;
- }
- if (stream_blocked && !ngtcp2_strm_is_tx_queued(vmsg->stream.strm) &&
- strm_should_send_stream_data_blocked(vmsg->stream.strm)) {
- assert(vmsg);
- assert(vmsg->type == NGTCP2_VMSG_TYPE_STREAM);
- vmsg->stream.strm->cycle = conn_tx_strmq_first_cycle(conn);
- rv = ngtcp2_conn_tx_strmq_push(conn, vmsg->stream.strm);
- if (rv != 0) {
- return rv;
- }
- }
- ngtcp2_pkt_hd_init(hd, hd_flags, type, &conn->dcid.current.cid, scid,
- pktns->tx.last_pkt_num + 1,
- pktns_select_pkt_numlen(pktns), version, 0);
- ngtcp2_ppe_init(ppe, dest, destlen, dgram_offset, cc);
- rv = ngtcp2_ppe_encode_hd(ppe, hd);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return 0;
- }
- if (!ngtcp2_ppe_ensure_hp_sample(ppe)) {
- return 0;
- }
- if (ngtcp2_ringbuf_len(&conn->rx.path_challenge.rb)) {
- pcent = ngtcp2_ringbuf_get(&conn->rx.path_challenge.rb, 0);
- /* PATH_RESPONSE is bound to the path that the corresponding
- PATH_CHALLENGE is received. */
- if (ngtcp2_path_eq(&conn->dcid.current.ps.path, &pcent->ps.path)) {
- lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
- memcpy(lfr.path_response.data, pcent->data,
- sizeof(lfr.path_response.data));
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- } else {
- ngtcp2_ringbuf_pop_front(&conn->rx.path_challenge.rb);
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING;
- require_padding = require_padding || !conn->server ||
- destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE;
- /* We don't retransmit PATH_RESPONSE. */
- }
- }
- }
- rv = ngtcp2_conn_create_ack_frame(
- conn, &ackfr, pktns, type, ts, conn_compute_ack_delay(conn),
- conn->local.transport_params.ack_delay_exponent);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- if (ackfr) {
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, ackfr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- } else {
- ngtcp2_acktr_commit_ack(&pktns->acktr);
- ngtcp2_acktr_add_ack(&pktns->acktr, hd->pkt_num,
- ackfr->ack.largest_ack);
- assert(NGTCP2_PKT_1RTT == type);
- conn_handle_unconfirmed_key_update_from_remote(
- conn, ackfr->ack.largest_ack, ts);
- pkt_empty = 0;
- }
- }
- build_pkt:
- for (pfrc = &pktns->tx.frq; *pfrc;) {
- if ((*pfrc)->binder &&
- ((*pfrc)->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK)) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- switch ((*pfrc)->fr.type) {
- case NGTCP2_FRAME_RESET_STREAM:
- strm =
- ngtcp2_conn_find_stream(conn, (*pfrc)->fr.reset_stream.stream_id);
- if (strm == NULL ||
- !ngtcp2_strm_require_retransmit_reset_stream(strm)) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_STOP_SENDING:
- strm =
- ngtcp2_conn_find_stream(conn, (*pfrc)->fr.stop_sending.stream_id);
- if (strm == NULL ||
- !ngtcp2_strm_require_retransmit_stop_sending(strm)) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_STREAM:
- ngtcp2_unreachable();
- case NGTCP2_FRAME_MAX_STREAMS_BIDI:
- if ((*pfrc)->fr.max_streams.max_streams <
- conn->remote.bidi.max_streams) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_MAX_STREAMS_UNI:
- if ((*pfrc)->fr.max_streams.max_streams <
- conn->remote.uni.max_streams) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_MAX_STREAM_DATA:
- strm =
- ngtcp2_conn_find_stream(conn, (*pfrc)->fr.max_stream_data.stream_id);
- if (strm == NULL || !ngtcp2_strm_require_retransmit_max_stream_data(
- strm, &(*pfrc)->fr.max_stream_data)) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_MAX_DATA:
- if ((*pfrc)->fr.max_data.max_data < conn->rx.max_offset) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
- strm = ngtcp2_conn_find_stream(
- conn, (*pfrc)->fr.stream_data_blocked.stream_id);
- if (strm == NULL || !ngtcp2_strm_require_retransmit_stream_data_blocked(
- strm, &(*pfrc)->fr.stream_data_blocked)) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_DATA_BLOCKED:
- if ((*pfrc)->fr.data_blocked.offset != conn->tx.max_offset) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- continue;
- }
- break;
- case NGTCP2_FRAME_CRYPTO:
- ngtcp2_unreachable();
- }
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- break;
- }
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- if (*pfrc == NULL) {
- for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) {
- left = ngtcp2_ppe_left(ppe);
- crypto_offset =
- ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm);
- if (crypto_offset == (uint64_t)-1) {
- ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm);
- break;
- }
- left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
- if (left == (size_t)-1) {
- break;
- }
- rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- if (nfrc == NULL) {
- break;
- }
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- ngtcp2_unreachable();
- }
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- }
- }
- if (*pfrc == NULL) {
- for (; !ngtcp2_pq_empty(&conn->tx.strmq);) {
- strm = ngtcp2_conn_tx_strmq_top(conn);
- if (strm->flags & NGTCP2_STRM_FLAG_SEND_RESET_STREAM) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_RESET_STREAM;
- nfrc->fr.reset_stream.stream_id = strm->stream_id;
- nfrc->fr.reset_stream.app_error_code =
- strm->tx.reset_stream_app_error_code;
- nfrc->fr.reset_stream.final_size = strm->tx.offset;
- *pfrc = nfrc;
- strm->flags &= ~NGTCP2_STRM_FLAG_SEND_RESET_STREAM;
- rv =
- conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- break;
- }
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_SEND_STOP_SENDING) {
- if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
- ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) {
- strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING;
- } else {
- rv = conn_call_stream_stop_sending(
- conn, strm->stream_id, strm->tx.stop_sending_app_error_code,
- strm->stream_user_data);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_STOP_SENDING;
- nfrc->fr.stop_sending.stream_id = strm->stream_id;
- nfrc->fr.stop_sending.app_error_code =
- strm->tx.stop_sending_app_error_code;
- *pfrc = nfrc;
- strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING;
- rv =
- conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- break;
- }
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- }
- if (!(strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) &&
- strm_should_send_stream_data_blocked(strm)) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
- nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
- nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
- *pfrc = nfrc;
- strm->tx.last_blocked_offset = strm->tx.max_offset;
- rv =
- conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- break;
- }
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- if (!(strm->flags &
- (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) &&
- conn_should_send_max_stream_data(conn, strm)) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- if (conn->local.settings.max_stream_window &&
- strm->tx.last_max_stream_data_ts != UINT64_MAX &&
- ts - strm->tx.last_max_stream_data_ts <
- NGTCP2_FLOW_WINDOW_RTT_FACTOR * cstat->smoothed_rtt &&
- conn->local.settings.max_stream_window > strm->rx.window) {
- target_max_data =
- NGTCP2_FLOW_WINDOW_SCALING_FACTOR * strm->rx.window;
- if (target_max_data > conn->local.settings.max_stream_window) {
- target_max_data = conn->local.settings.max_stream_window;
- }
- delta = target_max_data - strm->rx.window;
- if (strm->rx.unsent_max_offset + delta > NGTCP2_MAX_VARINT) {
- delta = NGTCP2_MAX_VARINT - strm->rx.unsent_max_offset;
- }
- strm->rx.window = target_max_data;
- } else {
- delta = 0;
- }
- strm->tx.last_max_stream_data_ts = ts;
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAM_DATA;
- nfrc->fr.max_stream_data.stream_id = strm->stream_id;
- nfrc->fr.max_stream_data.max_stream_data =
- strm->rx.unsent_max_offset + delta;
- *pfrc = nfrc;
- strm->rx.max_offset = strm->rx.unsent_max_offset =
- nfrc->fr.max_stream_data.max_stream_data;
- rv =
- conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- break;
- }
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- if (ngtcp2_strm_streamfrq_empty(strm)) {
- ngtcp2_conn_tx_strmq_pop(conn);
- continue;
- }
- stream_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
- if (stream_offset == (uint64_t)-1) {
- ngtcp2_strm_streamfrq_clear(strm);
- ngtcp2_conn_tx_strmq_pop(conn);
- continue;
- }
- left = ngtcp2_ppe_left(ppe);
- left = ngtcp2_pkt_stream_max_datalen(strm->stream_id, stream_offset,
- left, left);
- if (left == (size_t)-1) {
- break;
- }
- rv = ngtcp2_strm_streamfrq_pop(strm, &nfrc, left);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- if (nfrc == NULL) {
- /* TODO Why? */
- break;
- }
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- ngtcp2_unreachable();
- }
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- if (ngtcp2_strm_streamfrq_empty(strm)) {
- ngtcp2_conn_tx_strmq_pop(conn);
- continue;
- }
- ngtcp2_conn_tx_strmq_pop(conn);
- ++strm->cycle;
- rv = ngtcp2_conn_tx_strmq_push(conn, strm);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- }
- }
- /* Write MAX_STREAMS after RESET_STREAM so that we can extend
- stream ID space in one packet. */
- if (*pfrc == NULL &&
- conn->remote.bidi.unsent_max_streams > conn->remote.bidi.max_streams) {
- rv = conn_call_extend_max_remote_streams_bidi(
- conn, conn->remote.bidi.unsent_max_streams);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI;
- nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams;
- *pfrc = nfrc;
- conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- } else {
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- }
- if (*pfrc == NULL &&
- conn->remote.uni.unsent_max_streams > conn->remote.uni.max_streams) {
- rv = conn_call_extend_max_remote_streams_uni(
- conn, conn->remote.uni.unsent_max_streams);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI;
- nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams;
- *pfrc = nfrc;
- conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- } else {
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- pfrc = &(*pfrc)->next;
- }
- }
- if (pktns->tx.frq == NULL && !send_stream && !send_datagram &&
- !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
- pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) {
- num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1);
- if (num_reclaimed < 0) {
- return rv;
- }
- if (num_reclaimed) {
- goto build_pkt;
- }
- /* We had pktns->rtb.num_retransmittable > 0 but we were unable
- to reclaim any frame. In this case, we do not have to send
- any probe packet. */
- if (pktns->rtb.num_pto_eliciting == 0) {
- pktns->rtb.probe_pkt_left = 0;
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- if (pkt_empty && conn_cwnd_is_zero(conn) && !require_padding) {
- return 0;
- }
- }
- }
- } else {
- pfrc = conn->pkt.pfrc;
- rtb_entry_flags |= conn->pkt.rtb_entry_flags;
- pkt_empty = conn->pkt.pkt_empty;
- hd_logged = conn->pkt.hd_logged;
- }
- left = ngtcp2_ppe_left(ppe);
- if (*pfrc == NULL && send_stream &&
- (ndatalen = ngtcp2_pkt_stream_max_datalen(
- vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen,
- left)) != (size_t)-1 &&
- (ndatalen || datalen == 0)) {
- datacnt = ngtcp2_vec_copy_at_most(data, NGTCP2_MAX_STREAM_DATACNT,
- vmsg->stream.data, vmsg->stream.datacnt,
- (size_t)ndatalen);
- ndatalen = ngtcp2_vec_len(data, datacnt);
- assert((datacnt == 0 && datalen == 0) || (datacnt && datalen));
- rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
- &nfrc, datacnt, &conn->frc_objalloc, conn->mem);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- nfrc->fr.stream.type = NGTCP2_FRAME_STREAM;
- nfrc->fr.stream.flags = 0;
- nfrc->fr.stream.stream_id = vmsg->stream.strm->stream_id;
- nfrc->fr.stream.offset = vmsg->stream.strm->tx.offset;
- nfrc->fr.stream.datacnt = datacnt;
- ngtcp2_vec_copy(nfrc->fr.stream.data, data, datacnt);
- fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
- ndatalen == datalen;
- nfrc->fr.stream.fin = (uint8_t)fin;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- ngtcp2_unreachable();
- }
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- vmsg->stream.strm->tx.offset += ndatalen;
- conn->tx.offset += ndatalen;
- vmsg->stream.strm->flags |= NGTCP2_STRM_FLAG_ANY_SENT;
- if (fin) {
- ngtcp2_strm_shutdown(vmsg->stream.strm, NGTCP2_STRM_FLAG_SHUT_WR);
- }
- if (vmsg->stream.pdatalen) {
- *vmsg->stream.pdatalen = (ngtcp2_ssize)ndatalen;
- }
- } else {
- send_stream = 0;
- }
- if (vmsg && vmsg->type == NGTCP2_VMSG_TYPE_STREAM &&
- ((stream_blocked && *pfrc == NULL) ||
- (send_stream &&
- !(vmsg->stream.strm->flags & NGTCP2_STRM_FLAG_SHUT_WR)))) {
- if (conn_should_send_data_blocked(conn)) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED;
- nfrc->fr.data_blocked.offset = conn->tx.offset;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- /* We cannot add nfrc to pktns->tx.frq here. */
- ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem);
- } else {
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- conn->tx.last_blocked_offset = conn->tx.max_offset;
- }
- }
- strm = vmsg->stream.strm;
- if (strm_should_send_stream_data_blocked(strm)) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
- nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
- nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- /* We cannot add nfrc to pktns->tx.frq here. */
- ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem);
- if (!ngtcp2_strm_is_tx_queued(strm)) {
- strm->cycle = conn_tx_strmq_first_cycle(conn);
- rv = ngtcp2_conn_tx_strmq_push(conn, strm);
- if (rv != 0) {
- return rv;
- }
- }
- } else {
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE;
- strm->tx.last_blocked_offset = strm->tx.max_offset;
- }
- }
- }
- if (*pfrc == NULL && send_datagram &&
- left >= ngtcp2_pkt_datagram_framelen((size_t)datalen)) {
- if (conn->callbacks.ack_datagram || conn->callbacks.lost_datagram) {
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- nfrc->fr.datagram.type = NGTCP2_FRAME_DATAGRAM_LEN;
- nfrc->fr.datagram.dgram_id = vmsg->datagram.dgram_id;
- nfrc->fr.datagram.datacnt = vmsg->datagram.datacnt;
- nfrc->fr.datagram.data = (ngtcp2_vec *)vmsg->datagram.data;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
- assert(rv == 0);
- /* Because DATAGRAM will not be retransmitted, we do not use
- data anymore. Just nullify it. The only reason to keep
- track a frame is keep dgram_id to pass it to
- ngtcp2_ack_datagram or ngtcp2_lost_datagram callbacks. */
- nfrc->fr.datagram.datacnt = 0;
- nfrc->fr.datagram.data = NULL;
- *pfrc = nfrc;
- pfrc = &(*pfrc)->next;
- } else {
- lfr.datagram.type = NGTCP2_FRAME_DATAGRAM_LEN;
- lfr.datagram.datacnt = vmsg->datagram.datacnt;
- lfr.datagram.data = (ngtcp2_vec *)vmsg->datagram.data;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
- assert(rv == 0);
- }
- pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_DATAGRAM;
- if (vmsg->datagram.paccepted) {
- *vmsg->datagram.paccepted = 1;
- }
- } else {
- send_datagram = 0;
- }
- if (pkt_empty) {
- if (*pfrc == NULL && rv == 0 && stream_blocked &&
- (write_more || !require_padding) &&
- ngtcp2_conn_get_max_data_left(conn)) {
- if (write_more) {
- conn->pkt.pfrc = pfrc;
- conn->pkt.pkt_empty = pkt_empty;
- conn->pkt.rtb_entry_flags = rtb_entry_flags;
- conn->pkt.hd_logged = hd_logged;
- conn->flags |= NGTCP2_CONN_FLAG_PPE_PENDING;
- }
- return NGTCP2_ERR_STREAM_DATA_BLOCKED;
- }
- keep_alive_expired =
- type == NGTCP2_PKT_1RTT && conn_keep_alive_expired(conn, ts);
- if (conn->pktns.rtb.probe_pkt_left == 0 && !keep_alive_expired &&
- !require_padding) {
- conn_reset_ppe_pending(conn);
- return 0;
- }
- } else if (write_more) {
- conn->pkt.pfrc = pfrc;
- conn->pkt.pkt_empty = pkt_empty;
- conn->pkt.rtb_entry_flags = rtb_entry_flags;
- conn->pkt.hd_logged = hd_logged;
- conn->flags |= NGTCP2_CONN_FLAG_PPE_PENDING;
- assert(vmsg);
- switch (vmsg->type) {
- case NGTCP2_VMSG_TYPE_STREAM:
- if (send_stream) {
- if (ngtcp2_ppe_left(ppe)) {
- return NGTCP2_ERR_WRITE_MORE;
- }
- break;
- }
- if (*pfrc == NULL && ngtcp2_conn_get_max_data_left(conn) &&
- stream_blocked) {
- return NGTCP2_ERR_STREAM_DATA_BLOCKED;
- }
- break;
- case NGTCP2_VMSG_TYPE_DATAGRAM:
- if (send_datagram && ngtcp2_ppe_left(ppe)) {
- return NGTCP2_ERR_WRITE_MORE;
- }
- /* If DATAGRAM cannot be written due to insufficient space,
- continue to create a packet with the hope that application
- calls ngtcp2_conn_writev_datagram again. */
- break;
- default:
- ngtcp2_unreachable();
- }
- }
- if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts,
- cstat->smoothed_rtt, ts) ||
- keep_alive_expired || conn->pktns.rtb.probe_pkt_left) {
- lfr.type = NGTCP2_FRAME_PING;
- rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
- if (rv != 0) {
- assert(rv == NGTCP2_ERR_NOBUF);
- /* TODO If buffer is too small, PING cannot be written if
- packet is still empty. */
- } else {
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING;
- if (conn->pktns.rtb.probe_pkt_left) {
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PROBE;
- } else {
- rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING;
- }
- pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
- pkt_empty = 0;
- }
- } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) {
- pktns->tx.non_ack_pkt_start_ts = ts;
- }
- } else {
- pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
- }
- /* TODO Push STREAM frame back to ngtcp2_strm if there is an error
- before ngtcp2_rtb_entry is safely created and added. */
- if (require_padding) {
- lfr.padding.len = ngtcp2_ppe_dgram_padding(ppe);
- } else {
- lfr.padding.len = ngtcp2_ppe_padding_size(ppe, min_pktlen);
- min_padded = 1;
- }
- if (lfr.padding.len) {
- if (!min_padded ||
- (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- padded = 1;
- }
- lfr.type = NGTCP2_FRAME_PADDING;
- ngtcp2_log_tx_fr(&conn->log, hd, &lfr);
- ngtcp2_qlog_write_frame(&conn->qlog, &lfr);
- }
- nwrite = ngtcp2_ppe_final(ppe, NULL);
- if (nwrite < 0) {
- assert(ngtcp2_err_is_fatal((int)nwrite));
- return nwrite;
- }
- ++cc->ckm->use_count;
- ngtcp2_qlog_pkt_sent_end(&conn->qlog, hd, (size_t)nwrite);
- /* TODO ack-eliciting vs needs-tracking */
- /* probe packet needs tracking but it does not need ACK, could be lost. */
- if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) {
- if (pi) {
- conn_handle_tx_ecn(conn, pi, &rtb_entry_flags, pktns, hd, ts);
- }
- rv =
- ngtcp2_rtb_entry_objalloc_new(&ent, hd, NULL, ts, (size_t)nwrite,
- rtb_entry_flags, &conn->rtb_entry_objalloc);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- if (*pfrc != pktns->tx.frq) {
- ent->frc = pktns->tx.frq;
- pktns->tx.frq = *pfrc;
- *pfrc = NULL;
- }
- if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
- pktns->rtb.num_ack_eliciting == 0 && conn->cc.event) {
- conn->cc.event(&conn->cc, &conn->cstat, NGTCP2_CC_EVENT_TYPE_TX_START,
- ts);
- }
- rv = conn_on_pkt_sent(conn, pktns, ent);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_rtb_entry_objalloc_del(ent, &conn->rtb_entry_objalloc,
- &conn->frc_objalloc, conn->mem);
- return rv;
- }
- if (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
- if (conn->cc.on_pkt_sent) {
- conn->cc.on_pkt_sent(
- &conn->cc, &conn->cstat,
- ngtcp2_cc_pkt_init(&cc_pkt, hd->pkt_num, (size_t)nwrite,
- NGTCP2_PKTNS_ID_APPLICATION, ts, ent->rst.lost,
- ent->rst.tx_in_flight, ent->rst.is_app_limited));
- }
- if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) {
- conn_restart_timer_on_write(conn, ts);
- }
- }
- } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
- conn_handle_tx_ecn(conn, pi, NULL, pktns, hd, ts);
- }
- conn_reset_ppe_pending(conn);
- if (pktns->rtb.probe_pkt_left &&
- (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- --pktns->rtb.probe_pkt_left;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
- nwrite);
- }
- conn_update_keep_alive_last_ts(conn, ts);
- conn->dcid.current.bytes_sent += (uint64_t)nwrite;
- conn->tx.pacing.pktlen += (size_t)nwrite;
- ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
- ++pktns->tx.last_pkt_num;
- return nwrite;
- }
- ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
- ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen,
- uint8_t type, uint8_t flags, const ngtcp2_cid *dcid, ngtcp2_frame *fr,
- uint16_t rtb_entry_flags, const ngtcp2_path *path, ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_ppe ppe;
- ngtcp2_pkt_hd hd;
- ngtcp2_frame lfr;
- ngtcp2_ssize nwrite;
- ngtcp2_crypto_cc cc;
- ngtcp2_pktns *pktns;
- uint8_t hd_flags;
- ngtcp2_rtb_entry *rtbent;
- int padded = 0;
- const ngtcp2_cid *scid;
- uint32_t version;
- switch (type) {
- case NGTCP2_PKT_INITIAL:
- pktns = conn->in_pktns;
- hd_flags = conn_pkt_flags_long(conn);
- scid = &conn->oscid;
- version = conn->negotiated_version ? conn->negotiated_version
- : conn->client_chosen_version;
- if (version == conn->client_chosen_version) {
- cc.ckm = pktns->crypto.tx.ckm;
- cc.hp_ctx = pktns->crypto.tx.hp_ctx;
- } else {
- assert(version == conn->vneg.version);
- cc.ckm = conn->vneg.tx.ckm;
- cc.hp_ctx = conn->vneg.tx.hp_ctx;
- }
- break;
- case NGTCP2_PKT_HANDSHAKE:
- pktns = conn->hs_pktns;
- hd_flags = conn_pkt_flags_long(conn);
- scid = &conn->oscid;
- version = conn->negotiated_version;
- cc.ckm = pktns->crypto.tx.ckm;
- cc.hp_ctx = pktns->crypto.tx.hp_ctx;
- break;
- case NGTCP2_PKT_1RTT:
- pktns = &conn->pktns;
- hd_flags = conn_pkt_flags_short(conn);
- scid = NULL;
- version = conn->negotiated_version;
- cc.ckm = pktns->crypto.tx.ckm;
- cc.hp_ctx = pktns->crypto.tx.hp_ctx;
- break;
- default:
- /* We don't support 0-RTT packet in this function. */
- ngtcp2_unreachable();
- }
- cc.aead = pktns->crypto.ctx.aead;
- cc.hp = pktns->crypto.ctx.hp;
- cc.encrypt = conn->callbacks.encrypt;
- cc.hp_mask = conn->callbacks.hp_mask;
- ngtcp2_pkt_hd_init(&hd, hd_flags, type, dcid, scid,
- pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns),
- version, 0);
- ngtcp2_ppe_init(&ppe, dest, destlen, 0, &cc);
- rv = ngtcp2_ppe_encode_hd(&ppe, &hd);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return 0;
- }
- if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) {
- return 0;
- }
- ngtcp2_log_tx_pkt_hd(&conn->log, &hd);
- ngtcp2_qlog_pkt_sent_start(&conn->qlog);
- rv = conn_ppe_write_frame(conn, &ppe, &hd, fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return 0;
- }
- lfr.type = NGTCP2_FRAME_PADDING;
- if (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL) {
- lfr.padding.len = ngtcp2_ppe_dgram_padding_size(&ppe, destlen);
- } else if (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) {
- lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
- } else {
- switch (fr->type) {
- case NGTCP2_FRAME_PATH_CHALLENGE:
- case NGTCP2_FRAME_PATH_RESPONSE:
- if (!conn->server || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
- } else {
- lfr.padding.len = 0;
- }
- break;
- default:
- lfr.padding.len = ngtcp2_ppe_padding_size(&ppe, conn_min_pktlen(conn));
- }
- }
- if (lfr.padding.len) {
- padded = 1;
- ngtcp2_log_tx_fr(&conn->log, &hd, &lfr);
- ngtcp2_qlog_write_frame(&conn->qlog, &lfr);
- }
- nwrite = ngtcp2_ppe_final(&ppe, NULL);
- if (nwrite < 0) {
- return nwrite;
- }
- if (type == NGTCP2_PKT_1RTT) {
- ++cc.ckm->use_count;
- }
- ngtcp2_qlog_pkt_sent_end(&conn->qlog, &hd, (size_t)nwrite);
- /* Do this when we are sure that there is no error. */
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- ngtcp2_acktr_commit_ack(&pktns->acktr);
- ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, fr->ack.largest_ack);
- if (type == NGTCP2_PKT_1RTT) {
- conn_handle_unconfirmed_key_update_from_remote(conn, fr->ack.largest_ack,
- ts);
- }
- if (!(flags & (NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL |
- NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING))) {
- padded = 0;
- }
- break;
- }
- if (((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) &&
- (!path || ngtcp2_path_eq(&conn->dcid.current.ps.path, path))) {
- if (pi && (conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE ||
- !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE))) {
- conn_handle_tx_ecn(conn, pi, &rtb_entry_flags, pktns, &hd, ts);
- }
- rv =
- ngtcp2_rtb_entry_objalloc_new(&rtbent, &hd, NULL, ts, (size_t)nwrite,
- rtb_entry_flags, &conn->rtb_entry_objalloc);
- if (rv != 0) {
- return rv;
- }
- rv = conn_on_pkt_sent(conn, pktns, rtbent);
- if (rv != 0) {
- ngtcp2_rtb_entry_objalloc_del(rtbent, &conn->rtb_entry_objalloc,
- &conn->frc_objalloc, conn->mem);
- return rv;
- }
- if (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
- if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) {
- conn_restart_timer_on_write(conn, ts);
- }
- if (pktns->rtb.probe_pkt_left && path &&
- ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- --pktns->rtb.probe_pkt_left;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
- nwrite);
- }
- }
- } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
- conn_handle_tx_ecn(conn, pi, NULL, pktns, &hd, ts);
- }
- if (path && ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- conn_update_keep_alive_last_ts(conn, ts);
- }
- if (!padded) {
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- break;
- default:
- conn->tx.pacing.pktlen += (size_t)nwrite;
- }
- } else {
- conn->tx.pacing.pktlen += (size_t)nwrite;
- }
- ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
- ++pktns->tx.last_pkt_num;
- return nwrite;
- }
- /*
- * conn_process_early_rtb makes any pending 0RTT packet 1RTT packet.
- */
- static void conn_process_early_rtb(ngtcp2_conn *conn) {
- ngtcp2_rtb_entry *ent;
- ngtcp2_rtb *rtb = &conn->pktns.rtb;
- ngtcp2_ksl_it it;
- for (it = ngtcp2_rtb_head(rtb); !ngtcp2_ksl_it_end(&it);
- ngtcp2_ksl_it_next(&it)) {
- ent = ngtcp2_ksl_it_get(&it);
- if ((ent->hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) == 0 ||
- ent->hd.type != NGTCP2_PKT_0RTT) {
- continue;
- }
- /* 0-RTT packet is retransmitted as a 1RTT packet. */
- ent->hd.flags &= (uint8_t)~NGTCP2_PKT_FLAG_LONG_FORM;
- ent->hd.type = NGTCP2_PKT_1RTT;
- }
- }
- /*
- * conn_handshake_remnants_left returns nonzero if there may be
- * handshake packets the local endpoint has to send, including new
- * packets and lost ones.
- */
- static int conn_handshake_remnants_left(ngtcp2_conn *conn) {
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- return !conn_is_tls_handshake_completed(conn) ||
- (in_pktns && (in_pktns->rtb.num_pto_eliciting ||
- !ngtcp2_strm_streamfrq_empty(&in_pktns->crypto.strm))) ||
- (hs_pktns && (hs_pktns->rtb.num_pto_eliciting ||
- !ngtcp2_strm_streamfrq_empty(&hs_pktns->crypto.strm)));
- }
- /*
- * conn_retire_dcid_seq retires destination connection ID denoted by
- * |seq|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CONNECTION_ID_LIMIT
- * The number of unacknowledged retirement exceeds the limit.
- */
- static int conn_retire_dcid_seq(ngtcp2_conn *conn, uint64_t seq) {
- ngtcp2_pktns *pktns = &conn->pktns;
- ngtcp2_frame_chain *nfrc;
- int rv;
- if (ngtcp2_conn_check_retired_dcid_tracked(conn, seq)) {
- return 0;
- }
- rv = ngtcp2_conn_track_retired_dcid_seq(conn, seq);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_RETIRE_CONNECTION_ID;
- nfrc->fr.retire_connection_id.seq = seq;
- nfrc->next = pktns->tx.frq;
- pktns->tx.frq = nfrc;
- return 0;
- }
- /*
- * conn_retire_dcid retires |dcid|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- */
- static int conn_retire_dcid(ngtcp2_conn *conn, const ngtcp2_dcid *dcid,
- ngtcp2_tstamp ts) {
- ngtcp2_ringbuf *rb = &conn->dcid.retired.rb;
- ngtcp2_dcid *dest, *stale_dcid;
- int rv;
- assert(dcid->cid.datalen);
- if (ngtcp2_ringbuf_full(rb)) {
- stale_dcid = ngtcp2_ringbuf_get(rb, 0);
- rv = conn_call_deactivate_dcid(conn, stale_dcid);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_ringbuf_pop_front(rb);
- }
- dest = ngtcp2_ringbuf_push_back(rb);
- ngtcp2_dcid_copy(dest, dcid);
- dest->retired_ts = ts;
- return conn_retire_dcid_seq(conn, dcid->seq);
- }
- /*
- * conn_bind_dcid stores the DCID to |*pdcid| bound to |path|. If
- * such DCID is not found, bind the new DCID to |path| and stores it
- * to |*pdcid|. If a remote endpoint uses zero-length connection ID,
- * the pointer to conn->dcid.current is assigned to |*pdcid|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CONN_ID_BLOCKED
- * No unused DCID is available
- * NGTCP2_ERR_NOMEM
- * Out of memory
- */
- static int conn_bind_dcid(ngtcp2_conn *conn, ngtcp2_dcid **pdcid,
- const ngtcp2_path *path, ngtcp2_tstamp ts) {
- ngtcp2_dcid *dcid, *ndcid;
- ngtcp2_cid cid;
- size_t i, len;
- int rv;
- assert(!ngtcp2_path_eq(&conn->dcid.current.ps.path, path));
- assert(!conn->pv || !ngtcp2_path_eq(&conn->pv->dcid.ps.path, path));
- assert(!conn->pv || !(conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) ||
- !ngtcp2_path_eq(&conn->pv->fallback_dcid.ps.path, path));
- len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, i);
- if (ngtcp2_path_eq(&dcid->ps.path, path)) {
- *pdcid = dcid;
- return 0;
- }
- }
- if (conn->dcid.current.cid.datalen == 0) {
- ndcid = ngtcp2_ringbuf_push_back(&conn->dcid.bound.rb);
- ngtcp2_cid_zero(&cid);
- ngtcp2_dcid_init(ndcid, ++conn->dcid.zerolen_seq, &cid, NULL);
- ngtcp2_dcid_set_path(ndcid, path);
- *pdcid = ndcid;
- return 0;
- }
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb) == 0) {
- return NGTCP2_ERR_CONN_ID_BLOCKED;
- }
- if (ngtcp2_ringbuf_full(&conn->dcid.bound.rb)) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, 0);
- rv = conn_retire_dcid(conn, dcid, ts);
- if (rv != 0) {
- return rv;
- }
- }
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- ndcid = ngtcp2_ringbuf_push_back(&conn->dcid.bound.rb);
- ngtcp2_dcid_copy(ndcid, dcid);
- ndcid->bound_ts = ts;
- ngtcp2_dcid_set_path(ndcid, path);
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- *pdcid = ndcid;
- return 0;
- }
- static int conn_start_pmtud(ngtcp2_conn *conn) {
- int rv;
- size_t hard_max_udp_payload_size;
- assert(!conn->local.settings.no_pmtud);
- assert(!conn->pmtud);
- assert(conn_is_tls_handshake_completed(conn));
- assert(conn->remote.transport_params);
- assert(conn->remote.transport_params->max_udp_payload_size >=
- NGTCP2_MAX_UDP_PAYLOAD_SIZE);
- hard_max_udp_payload_size = (size_t)ngtcp2_min_uint64(
- conn->remote.transport_params->max_udp_payload_size,
- (uint64_t)conn->local.settings.max_tx_udp_payload_size);
- rv =
- ngtcp2_pmtud_new(&conn->pmtud, conn->dcid.current.max_udp_payload_size,
- hard_max_udp_payload_size, conn->pktns.tx.last_pkt_num + 1,
- conn->local.settings.pmtud_probes,
- conn->local.settings.pmtud_probeslen, conn->mem);
- if (rv != 0) {
- return rv;
- }
- if (ngtcp2_pmtud_finished(conn->pmtud)) {
- ngtcp2_conn_stop_pmtud(conn);
- }
- return 0;
- }
- int ngtcp2_conn_start_pmtud(ngtcp2_conn *conn) {
- return conn_start_pmtud(conn);
- }
- void ngtcp2_conn_stop_pmtud(ngtcp2_conn *conn) {
- if (!conn->pmtud) {
- return;
- }
- ngtcp2_pmtud_del(conn->pmtud);
- conn->pmtud = NULL;
- }
- static ngtcp2_ssize conn_write_pmtud_probe(ngtcp2_conn *conn,
- ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, ngtcp2_tstamp ts) {
- size_t probelen;
- ngtcp2_ssize nwrite;
- ngtcp2_frame lfr;
- assert(conn->pmtud);
- assert(!ngtcp2_pmtud_finished(conn->pmtud));
- if (!ngtcp2_pmtud_require_probe(conn->pmtud)) {
- return 0;
- }
- probelen = ngtcp2_pmtud_probelen(conn->pmtud);
- if (probelen > destlen) {
- return 0;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "sending PMTUD probe packet len=%zu", probelen);
- lfr.type = NGTCP2_FRAME_PING;
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, probelen, NGTCP2_PKT_1RTT,
- NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL, &conn->dcid.current.cid, &lfr,
- NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING |
- NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE,
- NULL, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- assert(nwrite);
- ngtcp2_pmtud_probe_sent(conn->pmtud, conn_compute_pto(conn, &conn->pktns),
- ts);
- return nwrite;
- }
- /*
- * conn_stop_pv stops the path validation which is currently running.
- * This function does nothing if no path validation is currently being
- * performed.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- */
- static int conn_stop_pv(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- int rv = 0;
- ngtcp2_pv *pv = conn->pv;
- if (pv == NULL) {
- return 0;
- }
- if (pv->dcid.cid.datalen && pv->dcid.seq != conn->dcid.current.seq) {
- rv = conn_retire_dcid(conn, &pv->dcid, ts);
- if (rv != 0) {
- goto fin;
- }
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->fallback_dcid.cid.datalen &&
- pv->fallback_dcid.seq != conn->dcid.current.seq &&
- pv->fallback_dcid.seq != pv->dcid.seq) {
- rv = conn_retire_dcid(conn, &pv->fallback_dcid, ts);
- if (rv != 0) {
- goto fin;
- }
- }
- fin:
- ngtcp2_pv_del(pv);
- conn->pv = NULL;
- return rv;
- }
- /*
- * conn_abort_pv aborts the current path validation and frees
- * resources allocated for it. This function assumes that conn->pv is
- * not NULL.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_abort_pv(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- ngtcp2_pv *pv = conn->pv;
- int rv;
- assert(pv);
- if (!(pv->flags & NGTCP2_PV_FLAG_DONT_CARE)) {
- rv = conn_call_path_validation(conn, pv,
- NGTCP2_PATH_VALIDATION_RESULT_ABORTED);
- if (rv != 0) {
- return rv;
- }
- }
- return conn_stop_pv(conn, ts);
- }
- static size_t conn_shape_udp_payload(ngtcp2_conn *conn, const ngtcp2_dcid *dcid,
- size_t payloadlen) {
- if (conn->remote.transport_params &&
- conn->remote.transport_params->max_udp_payload_size) {
- assert(conn->remote.transport_params->max_udp_payload_size >=
- NGTCP2_MAX_UDP_PAYLOAD_SIZE);
- payloadlen = (size_t)ngtcp2_min_uint64(
- (uint64_t)payloadlen,
- conn->remote.transport_params->max_udp_payload_size);
- }
- payloadlen =
- ngtcp2_min_size(payloadlen, conn->local.settings.max_tx_udp_payload_size);
- if (conn->local.settings.no_tx_udp_payload_size_shaping) {
- return payloadlen;
- }
- return ngtcp2_min_size(payloadlen, dcid->max_udp_payload_size);
- }
- static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts);
- /*
- * conn_on_path_validation_failed is called when path validation
- * fails. This function may delete |pv|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_on_path_validation_failed(ngtcp2_conn *conn, ngtcp2_pv *pv,
- ngtcp2_tstamp ts) {
- int rv;
- if (!(pv->flags & NGTCP2_PV_FLAG_DONT_CARE)) {
- rv = conn_call_path_validation(conn, pv,
- NGTCP2_PATH_VALIDATION_RESULT_FAILURE);
- if (rv != 0) {
- return rv;
- }
- }
- if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) {
- ngtcp2_dcid_copy(&conn->dcid.current, &pv->fallback_dcid);
- conn_reset_congestion_state(conn, ts);
- }
- return conn_stop_pv(conn, ts);
- }
- /*
- * conn_write_path_challenge writes a packet which includes
- * PATH_CHALLENGE frame into |dest| of length |destlen|.
- *
- * This function returns the number of bytes written to |dest|, or one
- * of the following negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn,
- ngtcp2_path *path,
- ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- ngtcp2_tstamp ts) {
- ngtcp2_ssize nwrite;
- ngtcp2_tstamp expiry;
- ngtcp2_pv *pv = conn->pv;
- ngtcp2_frame lfr;
- ngtcp2_duration timeout, initial_pto;
- uint8_t flags;
- uint64_t tx_left;
- int rv;
- if (ngtcp2_pv_validation_timed_out(pv, ts)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PTV,
- "path validation was timed out");
- rv = conn_on_path_validation_failed(conn, pv, ts);
- if (rv != 0) {
- return rv;
- }
- /* We might set path to the one which we just failed validate.
- Set it to the current path here. */
- if (path) {
- ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
- }
- return 0;
- }
- ngtcp2_pv_handle_entry_expiry(pv, ts);
- if (!ngtcp2_pv_should_send_probe(pv)) {
- return 0;
- }
- rv = conn_call_get_path_challenge_data(conn, lfr.path_challenge.data);
- if (rv != 0) {
- return rv;
- }
- lfr.type = NGTCP2_FRAME_PATH_CHALLENGE;
- initial_pto = conn_compute_initial_pto(conn, &conn->pktns);
- timeout = conn_compute_pto(conn, &conn->pktns);
- timeout = ngtcp2_max_uint64(timeout, initial_pto);
- expiry = ts + timeout * (1ULL << pv->round);
- destlen = ngtcp2_min_size(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE);
- if (conn->server) {
- if (!(pv->dcid.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) {
- tx_left = conn_server_tx_left(conn, &pv->dcid);
- destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, tx_left);
- if (destlen == 0) {
- return 0;
- }
- }
- if (destlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- flags = NGTCP2_PV_ENTRY_FLAG_UNDERSIZED;
- } else {
- flags = NGTCP2_PV_ENTRY_FLAG_NONE;
- }
- } else {
- flags = NGTCP2_PV_ENTRY_FLAG_NONE;
- }
- ngtcp2_pv_add_entry(pv, lfr.path_challenge.data, expiry, flags, ts);
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
- &pv->dcid.cid, &lfr,
- NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING,
- &pv->dcid.ps.path, ts);
- if (nwrite <= 0) {
- return nwrite;
- }
- if (path) {
- ngtcp2_path_copy(path, &pv->dcid.ps.path);
- }
- if (ngtcp2_path_eq(&pv->dcid.ps.path, &conn->dcid.current.ps.path)) {
- conn->dcid.current.bytes_sent += (uint64_t)nwrite;
- } else {
- pv->dcid.bytes_sent += (uint64_t)nwrite;
- }
- return nwrite;
- }
- /*
- * conn_write_path_response writes a packet which includes
- * PATH_RESPONSE frame into |dest| of length |destlen|.
- *
- * This function returns the number of bytes written to |dest|, or one
- * of the following negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static ngtcp2_ssize conn_write_path_response(ngtcp2_conn *conn,
- ngtcp2_path *path,
- ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, ngtcp2_tstamp ts) {
- ngtcp2_pv *pv = conn->pv;
- ngtcp2_path_challenge_entry *pcent = NULL;
- ngtcp2_dcid *dcid = NULL;
- ngtcp2_frame lfr;
- ngtcp2_ssize nwrite;
- int rv;
- uint64_t tx_left;
- for (; ngtcp2_ringbuf_len(&conn->rx.path_challenge.rb);) {
- pcent = ngtcp2_ringbuf_get(&conn->rx.path_challenge.rb, 0);
- if (ngtcp2_path_eq(&conn->dcid.current.ps.path, &pcent->ps.path)) {
- /* Send PATH_RESPONSE from conn_write_pkt. */
- return 0;
- }
- if (pv) {
- if (ngtcp2_path_eq(&pv->dcid.ps.path, &pcent->ps.path)) {
- dcid = &pv->dcid;
- break;
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- ngtcp2_path_eq(&pv->fallback_dcid.ps.path, &pcent->ps.path)) {
- dcid = &pv->fallback_dcid;
- break;
- }
- }
- if (conn->server) {
- break;
- }
- /* Client does not expect to respond to path validation against
- unknown path */
- ngtcp2_ringbuf_pop_front(&conn->rx.path_challenge.rb);
- pcent = NULL;
- }
- if (pcent == NULL) {
- return 0;
- }
- if (dcid == NULL) {
- /* client is expected to have |path| in conn->dcid.current or
- conn->pv. */
- assert(conn->server);
- rv = conn_bind_dcid(conn, &dcid, &pcent->ps.path, ts);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- return 0;
- }
- }
- destlen = ngtcp2_min_size(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE);
- if (conn->server && !(dcid->flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) {
- tx_left = conn_server_tx_left(conn, dcid);
- destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, tx_left);
- if (destlen == 0) {
- return 0;
- }
- }
- lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
- memcpy(lfr.path_response.data, pcent->data, sizeof(lfr.path_response.data));
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
- &dcid->cid, &lfr, NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING, &pcent->ps.path, ts);
- if (nwrite <= 0) {
- return nwrite;
- }
- if (path) {
- ngtcp2_path_copy(path, &pcent->ps.path);
- }
- ngtcp2_ringbuf_pop_front(&conn->rx.path_challenge.rb);
- dcid->bytes_sent += (uint64_t)nwrite;
- return nwrite;
- }
- ngtcp2_ssize ngtcp2_conn_write_pkt_versioned(ngtcp2_conn *conn,
- ngtcp2_path *path,
- int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, ngtcp2_tstamp ts) {
- return ngtcp2_conn_writev_stream_versioned(
- conn, path, pkt_info_version, pi, dest, destlen,
- /* pdatalen = */ NULL, NGTCP2_WRITE_STREAM_FLAG_NONE,
- /* stream_id = */ -1,
- /* datav = */ NULL, /* datavcnt = */ 0, ts);
- }
- /*
- * conn_on_version_negotiation is called when Version Negotiation
- * packet is received. The function decodes the data in the buffer
- * pointed by |payload| whose length is |payloadlen| as Version
- * Negotiation packet payload. The packet header is given in |hd|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_INVALID_ARGUMENT
- * Packet payload is badly formatted.
- */
- static int conn_on_version_negotiation(ngtcp2_conn *conn,
- const ngtcp2_pkt_hd *hd,
- const uint8_t *payload,
- size_t payloadlen) {
- uint32_t sv[16];
- uint32_t *p;
- int rv = 0;
- size_t nsv;
- size_t i;
- if (payloadlen % sizeof(uint32_t)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- /* Version Negotiation packet is ignored if client has reacted upon
- Version Negotiation packet. */
- if (conn->local.settings.original_version != conn->client_chosen_version) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- if (payloadlen > sizeof(sv)) {
- p = ngtcp2_mem_malloc(conn->mem, payloadlen);
- if (p == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- } else {
- p = sv;
- }
- nsv = ngtcp2_pkt_decode_version_negotiation(p, payload, payloadlen);
- ngtcp2_log_rx_vn(&conn->log, hd, p, nsv);
- ngtcp2_qlog_version_negotiation_pkt_received(&conn->qlog, hd, p, nsv);
- if (!ngtcp2_is_reserved_version(conn->local.settings.original_version)) {
- for (i = 0; i < nsv; ++i) {
- if (p[i] == conn->local.settings.original_version) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "ignore Version Negotiation because it contains the "
- "original version");
- rv = NGTCP2_ERR_INVALID_ARGUMENT;
- goto fin;
- }
- }
- }
- rv = conn_call_recv_version_negotiation(conn, hd, p, nsv);
- if (rv != 0) {
- goto fin;
- }
- fin:
- if (p != sv) {
- ngtcp2_mem_free(conn->mem, p);
- }
- return rv;
- }
- static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn) {
- ngtcp2_strm *strm;
- if (ngtcp2_pq_empty(&conn->tx.strmq)) {
- return 0;
- }
- strm = ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe);
- return strm->cycle;
- }
- uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn) {
- ngtcp2_strm *strm;
- if (ngtcp2_pq_empty(&conn->tx.strmq)) {
- return 0;
- }
- strm = ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe);
- return strm->cycle;
- }
- /*
- * conn_on_retry is called when Retry packet is received. The
- * function decodes the data in the buffer pointed by |pkt| whose
- * length is |pktlen| as Retry packet. The length of long packet
- * header is given in |hdpktlen|. |pkt| includes packet header.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_INVALID_ARGUMENT
- * Packet payload is badly formatted.
- * NGTCP2_ERR_PROTO
- * ODCID does not match; or Token is empty.
- */
- static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
- size_t hdpktlen, const uint8_t *pkt, size_t pktlen,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_pkt_retry retry;
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_rtb *rtb = &conn->pktns.rtb;
- ngtcp2_rtb *in_rtb;
- uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1];
- uint8_t *token;
- if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) {
- return 0;
- }
- in_rtb = &in_pktns->rtb;
- rv = ngtcp2_pkt_decode_retry(&retry, pkt + hdpktlen, pktlen - hdpktlen);
- if (rv != 0) {
- return rv;
- }
- retry.odcid = conn->dcid.current.cid;
- rv = ngtcp2_pkt_verify_retry_tag(
- conn->client_chosen_version, &retry, pkt, pktlen, conn->callbacks.encrypt,
- &conn->crypto.retry_aead, &conn->crypto.retry_aead_ctx);
- if (rv != 0) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "unable to verify Retry packet integrity");
- return rv;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
- (const char *)ngtcp2_encode_hex(cidbuf, retry.odcid.data,
- retry.odcid.datalen));
- if (retry.tokenlen == 0) {
- return NGTCP2_ERR_PROTO;
- }
- if (ngtcp2_cid_eq(&conn->dcid.current.cid, &hd->scid)) {
- return 0;
- }
- ngtcp2_qlog_retry_pkt_received(&conn->qlog, hd, &retry);
- /* DCID must be updated before invoking callback because client
- generates new initial keys there. */
- conn->dcid.current.cid = hd->scid;
- conn->retry_scid = hd->scid;
- conn->flags |= NGTCP2_CONN_FLAG_RECV_RETRY;
- rv = conn_call_recv_retry(conn, hd);
- if (rv != 0) {
- return rv;
- }
- conn->state = NGTCP2_CS_CLIENT_INITIAL;
- /* Just freeing memory is dangerous because we might free twice. */
- rv = ngtcp2_rtb_remove_all(rtb, conn, &conn->pktns, &conn->cstat);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_rtb_remove_all(in_rtb, conn, in_pktns, &conn->cstat);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_mem_free(conn->mem, (uint8_t *)conn->local.settings.token);
- conn->local.settings.token = NULL;
- conn->local.settings.tokenlen = 0;
- token = ngtcp2_mem_malloc(conn->mem, retry.tokenlen);
- if (token == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- ngtcp2_cpymem(token, retry.token, retry.tokenlen);
- conn->local.settings.token = token;
- conn->local.settings.tokenlen = retry.tokenlen;
- reset_conn_stat_recovery(&conn->cstat);
- conn_reset_congestion_state(conn, ts);
- conn_reset_ecn_validation_state(conn);
- return 0;
- }
- int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
- ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) {
- return ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, conn, pktns, cstat, ts);
- }
- /*
- * conn_recv_ack processes received ACK frame |fr|. |pkt_ts| is the
- * timestamp when packet is received. |ts| should be the current
- * time. Usually they are the same, but for buffered packets,
- * |pkt_ts| would be earlier than |ts|. This function needs to be
- * called after |fr| is validated by ngtcp2_pkt_validate_ack.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_PROTO
- * |fr| acknowledges a packet this endpoint has not sent.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed.
- */
- static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr,
- ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) {
- ngtcp2_ssize num_acked;
- ngtcp2_conn_stat *cstat = &conn->cstat;
- if (pktns->tx.last_pkt_num < fr->largest_ack) {
- return NGTCP2_ERR_PROTO;
- }
- ngtcp2_acktr_recv_ack(&pktns->acktr, fr);
- num_acked =
- ngtcp2_rtb_recv_ack(&pktns->rtb, fr, &conn->cstat, conn, pktns, pkt_ts, ts);
- if (num_acked < 0) {
- assert(ngtcp2_err_is_fatal((int)num_acked));
- return (int)num_acked;
- }
- if (num_acked == 0) {
- return 0;
- }
- pktns->rtb.probe_pkt_left = 0;
- if (cstat->pto_count &&
- (conn->server || (conn->flags & NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED))) {
- /* Reset PTO count but no less than 2 to avoid frequent probe
- packet transmission. */
- cstat->pto_count = ngtcp2_min_size(cstat->pto_count, 2);
- }
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- return 0;
- }
- /*
- * conn_assign_recved_ack_delay_unscaled assigns
- * fr->ack_delay_unscaled.
- */
- static void assign_recved_ack_delay_unscaled(ngtcp2_ack *fr,
- uint64_t ack_delay_exponent) {
- fr->ack_delay_unscaled =
- fr->ack_delay * (1ULL << ack_delay_exponent) * NGTCP2_MICROSECONDS;
- }
- /*
- * conn_recv_max_stream_data processes received MAX_STREAM_DATA frame
- * |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_STREAM_STATE
- * Stream ID indicates that it is a local stream, and the local
- * endpoint has not initiated it; or stream is peer initiated
- * unidirectional stream.
- * NGTCP2_ERR_STREAM_LIMIT
- * Stream ID exceeds allowed limit.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_recv_max_stream_data(ngtcp2_conn *conn,
- const ngtcp2_max_stream_data *fr) {
- ngtcp2_strm *strm;
- ngtcp2_idtr *idtr;
- int local_stream = conn_local_stream(conn, fr->stream_id);
- int bidi = bidi_stream(fr->stream_id);
- int rv;
- if (bidi) {
- if (local_stream) {
- if (conn->local.bidi.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- } else if (conn->remote.bidi.max_streams <
- ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.bidi.idtr;
- } else {
- if (!local_stream || conn->local.uni.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- idtr = &conn->remote.uni.idtr;
- }
- strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
- if (strm == NULL) {
- if (local_stream) {
- /* Stream has been closed. */
- return 0;
- }
- rv = ngtcp2_idtr_open(idtr, fr->stream_id);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- assert(rv == NGTCP2_ERR_STREAM_IN_USE);
- /* Stream has been closed. */
- return 0;
- }
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- rv = conn_call_stream_open(conn, strm);
- if (rv != 0) {
- return rv;
- }
- }
- if (strm->tx.max_offset < fr->max_stream_data) {
- strm->tx.max_offset = fr->max_stream_data;
- /* Don't call callback if stream is half-closed local */
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
- return 0;
- }
- rv = conn_call_extend_max_stream_data(conn, strm, fr->stream_id,
- fr->max_stream_data);
- if (rv != 0) {
- return rv;
- }
- }
- return 0;
- }
- /*
- * conn_recv_max_data processes received MAX_DATA frame |fr|.
- */
- static void conn_recv_max_data(ngtcp2_conn *conn, const ngtcp2_max_data *fr) {
- conn->tx.max_offset = ngtcp2_max_uint64(conn->tx.max_offset, fr->max_data);
- }
- /*
- * conn_buffer_pkt buffers |pkt| of length |pktlen|, chaining it from
- * |*ppc|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_buffer_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
- const ngtcp2_path *path, const ngtcp2_pkt_info *pi,
- const uint8_t *pkt, size_t pktlen, size_t dgramlen,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_pkt_chain **ppc = &pktns->rx.buffed_pkts, *pc;
- size_t i;
- for (i = 0; *ppc && i < NGTCP2_MAX_NUM_BUFFED_RX_PKTS;
- ppc = &(*ppc)->next, ++i)
- ;
- if (i == NGTCP2_MAX_NUM_BUFFED_RX_PKTS) {
- return 0;
- }
- rv =
- ngtcp2_pkt_chain_new(&pc, path, pi, pkt, pktlen, dgramlen, ts, conn->mem);
- if (rv != 0) {
- return rv;
- }
- *ppc = pc;
- return 0;
- }
- static int ensure_decrypt_buffer(ngtcp2_vec *vec, size_t n, size_t initial,
- const ngtcp2_mem *mem) {
- uint8_t *nbuf;
- size_t len;
- if (vec->len >= n) {
- return 0;
- }
- len = vec->len == 0 ? initial : vec->len * 2;
- for (; len < n; len *= 2)
- ;
- nbuf = ngtcp2_mem_realloc(mem, vec->base, len);
- if (nbuf == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- vec->base = nbuf;
- vec->len = len;
- return 0;
- }
- /*
- * conn_ensure_decrypt_hp_buffer ensures that
- * conn->crypto.decrypt_hp_buf has at least |n| bytes space.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_ensure_decrypt_hp_buffer(ngtcp2_conn *conn, size_t n) {
- return ensure_decrypt_buffer(&conn->crypto.decrypt_hp_buf, n, 256, conn->mem);
- }
- /*
- * conn_ensure_decrypt_buffer ensures that conn->crypto.decrypt_buf
- * has at least |n| bytes space.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_ensure_decrypt_buffer(ngtcp2_conn *conn, size_t n) {
- return ensure_decrypt_buffer(&conn->crypto.decrypt_buf, n, 2048, conn->mem);
- }
- /*
- * decrypt_pkt decrypts the data pointed by |payload| whose length is
- * |payloadlen|, and writes plaintext data to the buffer pointed by
- * |dest|. The buffer pointed by |aad| is the Additional
- * Authenticated Data, and its length is |aadlen|. |pkt_num| is used
- * to create a nonce. |ckm| is the cryptographic key, and iv to use.
- * |decrypt| is a callback function which actually decrypts a packet.
- *
- * This function returns the number of bytes written in |dest| if it
- * succeeds, or one of the following negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed.
- * NGTCP2_ERR_DECRYPT
- * Failed to decrypt a packet.
- */
- static ngtcp2_ssize decrypt_pkt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
- const uint8_t *payload, size_t payloadlen,
- const uint8_t *aad, size_t aadlen,
- int64_t pkt_num, ngtcp2_crypto_km *ckm,
- ngtcp2_decrypt decrypt) {
- /* TODO nonce is limited to 64 bytes. */
- uint8_t nonce[64];
- int rv;
- assert(sizeof(nonce) >= ckm->iv.len);
- ngtcp2_crypto_create_nonce(nonce, ckm->iv.base, ckm->iv.len, pkt_num);
- rv = decrypt(dest, aead, &ckm->aead_ctx, payload, payloadlen, nonce,
- ckm->iv.len, aad, aadlen);
- if (rv != 0) {
- if (rv == NGTCP2_ERR_DECRYPT) {
- return rv;
- }
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- assert(payloadlen >= aead->max_overhead);
- return (ngtcp2_ssize)(payloadlen - aead->max_overhead);
- }
- /*
- * decrypt_hp decryptes packet header. The packet number starts at
- * |pkt| + |pkt_num_offset|. The entire plaintext QUIC packet header
- * will be written to the buffer pointed by |dest| whose capacity is
- * |destlen|.
- *
- * This function returns the number of bytes written to |dest|, or one
- * of the following negative error codes:
- *
- * NGTCP2_ERR_PROTO
- * Packet is badly formatted
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed; or it does not return
- * expected result.
- */
- static ngtcp2_ssize
- decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp,
- const uint8_t *pkt, size_t pktlen, size_t pkt_num_offset,
- const ngtcp2_crypto_cipher_ctx *hp_ctx, ngtcp2_hp_mask hp_mask) {
- size_t sample_offset;
- uint8_t *p = dest;
- uint8_t mask[NGTCP2_HP_SAMPLELEN];
- size_t i;
- int rv;
- assert(hp_mask);
- if (pkt_num_offset + 4 + NGTCP2_HP_SAMPLELEN > pktlen) {
- return NGTCP2_ERR_PROTO;
- }
- p = ngtcp2_cpymem(p, pkt, pkt_num_offset);
- sample_offset = pkt_num_offset + 4;
- rv = hp_mask(mask, hp, hp_ctx, pkt + sample_offset);
- if (rv != 0) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
- }
- if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
- dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0f));
- } else {
- dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1f));
- if (dest[0] & NGTCP2_SHORT_KEY_PHASE_BIT) {
- hd->flags |= NGTCP2_PKT_FLAG_KEY_PHASE;
- }
- }
- hd->pkt_numlen = (size_t)((dest[0] & NGTCP2_PKT_NUMLEN_MASK) + 1);
- for (i = 0; i < hd->pkt_numlen; ++i) {
- *p++ = *(pkt + pkt_num_offset + i) ^ mask[i + 1];
- }
- hd->pkt_num = ngtcp2_get_pkt_num(p - hd->pkt_numlen, hd->pkt_numlen);
- return p - dest;
- }
- /*
- * conn_emit_pending_crypto_data delivers pending stream data to the
- * application due to packet reordering.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed
- * NGTCP2_ERR_CRYPTO
- * TLS backend reported error
- */
- static int
- conn_emit_pending_crypto_data(ngtcp2_conn *conn,
- ngtcp2_encryption_level encryption_level,
- ngtcp2_strm *strm, uint64_t rx_offset) {
- size_t datalen;
- const uint8_t *data;
- int rv;
- uint64_t offset;
- if (!strm->rx.rob) {
- return 0;
- }
- for (;;) {
- datalen = ngtcp2_rob_data_at(strm->rx.rob, &data, rx_offset);
- if (datalen == 0) {
- assert(rx_offset == ngtcp2_strm_rx_offset(strm));
- return 0;
- }
- offset = rx_offset;
- rx_offset += datalen;
- rv =
- conn_call_recv_crypto_data(conn, encryption_level, offset, data, datalen);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_rob_pop(strm->rx.rob, rx_offset - datalen, datalen);
- }
- }
- /*
- * conn_recv_connection_close is called when CONNECTION_CLOSE or
- * APPLICATION_CLOSE frame is received.
- */
- static int conn_recv_connection_close(ngtcp2_conn *conn,
- ngtcp2_connection_close *fr) {
- ngtcp2_ccerr *ccerr = &conn->rx.ccerr;
- conn->state = NGTCP2_CS_DRAINING;
- if (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE) {
- ccerr->type = NGTCP2_CCERR_TYPE_TRANSPORT;
- } else {
- ccerr->type = NGTCP2_CCERR_TYPE_APPLICATION;
- }
- ccerr->error_code = fr->error_code;
- ccerr->frame_type = fr->frame_type;
- if (!fr->reasonlen) {
- ccerr->reasonlen = 0;
- return 0;
- }
- if (ccerr->reason == NULL) {
- ccerr->reason = ngtcp2_mem_malloc(conn->mem, NGTCP2_CCERR_MAX_REASONLEN);
- if (ccerr->reason == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- }
- ccerr->reasonlen = ngtcp2_min_size(fr->reasonlen, NGTCP2_CCERR_MAX_REASONLEN);
- ngtcp2_cpymem((uint8_t *)ccerr->reason, fr->reason, ccerr->reasonlen);
- return 0;
- }
- static void conn_recv_path_challenge(ngtcp2_conn *conn, const ngtcp2_path *path,
- ngtcp2_path_challenge *fr) {
- ngtcp2_path_challenge_entry *ent;
- /* client only responds to PATH_CHALLENGE from the current path or
- path which client is migrating to. */
- if (!conn->server && !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) &&
- (!conn->pv || !ngtcp2_path_eq(&conn->pv->dcid.ps.path, path))) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "discard PATH_CHALLENGE from the path which is not current "
- "or endpoint is migrating to");
- return;
- }
- ent = ngtcp2_ringbuf_push_front(&conn->rx.path_challenge.rb);
- ngtcp2_path_challenge_entry_init(ent, path, fr->data);
- }
- /*
- * conn_reset_congestion_state resets congestion state.
- */
- static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- conn_reset_conn_stat_cc(conn, &conn->cstat);
- if (conn->cc.reset) {
- conn->cc.reset(&conn->cc, &conn->cstat, ts);
- }
- if (conn->hs_pktns) {
- ngtcp2_rtb_reset_cc_state(&conn->hs_pktns->rtb,
- conn->hs_pktns->tx.last_pkt_num + 1);
- }
- ngtcp2_rtb_reset_cc_state(&conn->pktns.rtb, conn->pktns.tx.last_pkt_num + 1);
- ngtcp2_rst_init(&conn->rst);
- conn->tx.pacing.next_ts = UINT64_MAX;
- }
- static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_pv *pv = conn->pv, *npv;
- uint8_t ent_flags;
- if (!pv) {
- return 0;
- }
- rv = ngtcp2_pv_validate(pv, &ent_flags, fr->data);
- if (rv != 0) {
- assert(!ngtcp2_err_is_fatal(rv));
- return 0;
- }
- if (!(pv->flags & NGTCP2_PV_FLAG_DONT_CARE)) {
- if (pv->dcid.seq != conn->dcid.current.seq) {
- assert(!conn->server);
- assert(conn->dcid.current.cid.datalen);
- rv = conn_retire_dcid(conn, &conn->dcid.current, ts);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_dcid_copy(&conn->dcid.current, &pv->dcid);
- conn_reset_congestion_state(conn, ts);
- conn_reset_ecn_validation_state(conn);
- }
- assert(ngtcp2_path_eq(&pv->dcid.ps.path, &conn->dcid.current.ps.path));
- conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED;
- if (!conn->local.settings.no_pmtud) {
- ngtcp2_conn_stop_pmtud(conn);
- if (!(ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) {
- rv = conn_start_pmtud(conn);
- if (rv != 0) {
- return rv;
- }
- }
- }
- if (!(ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) {
- rv = conn_call_path_validation(conn, pv,
- NGTCP2_PATH_VALIDATION_RESULT_SUCCESS);
- if (rv != 0) {
- return rv;
- }
- }
- }
- if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) {
- if (ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED) {
- assert(conn->server);
- /* Validate path again */
- rv = ngtcp2_pv_new(&npv, &pv->dcid, conn_compute_pv_timeout(conn),
- NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, &conn->log,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- npv->dcid.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED;
- ngtcp2_dcid_copy(&npv->fallback_dcid, &pv->fallback_dcid);
- npv->fallback_pto = pv->fallback_pto;
- } else {
- rv = ngtcp2_pv_new(&npv, &pv->fallback_dcid,
- conn_compute_pv_timeout_pto(conn, pv->fallback_pto),
- NGTCP2_PV_FLAG_DONT_CARE, &conn->log, conn->mem);
- if (rv != 0) {
- return rv;
- }
- }
- /* Unset the flag bit so that conn_stop_pv does not retire
- DCID. */
- pv->flags &= (uint8_t)~NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE;
- rv = conn_stop_pv(conn, ts);
- if (rv != 0) {
- ngtcp2_pv_del(npv);
- return rv;
- }
- conn->pv = npv;
- return 0;
- }
- return conn_stop_pv(conn, ts);
- }
- /*
- * pktns_pkt_num_is_duplicate returns nonzero if |pkt_num| is
- * duplicated packet number.
- */
- static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, int64_t pkt_num) {
- return ngtcp2_gaptr_is_pushed(&pktns->rx.pngap, (uint64_t)pkt_num, 1);
- }
- /*
- * pktns_commit_recv_pkt_num marks packet number |pkt_num| as
- * received.
- */
- static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num,
- int ack_eliciting, ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_range r;
- rv = ngtcp2_gaptr_push(&pktns->rx.pngap, (uint64_t)pkt_num, 1);
- if (rv != 0) {
- return rv;
- }
- if (ngtcp2_ksl_len(&pktns->rx.pngap.gap) > 256) {
- ngtcp2_gaptr_drop_first_gap(&pktns->rx.pngap);
- }
- if (ack_eliciting) {
- if (pktns->rx.max_ack_eliciting_pkt_num != -1) {
- if (pkt_num < pktns->rx.max_ack_eliciting_pkt_num) {
- ngtcp2_acktr_immediate_ack(&pktns->acktr);
- } else if (pkt_num != pktns->rx.max_ack_eliciting_pkt_num + 1) {
- r = ngtcp2_gaptr_get_first_gap_after(
- &pktns->rx.pngap, (uint64_t)pktns->rx.max_ack_eliciting_pkt_num);
- if (r.begin < (uint64_t)pkt_num) {
- ngtcp2_acktr_immediate_ack(&pktns->acktr);
- }
- }
- }
- if (pktns->rx.max_ack_eliciting_pkt_num < pkt_num) {
- pktns->rx.max_ack_eliciting_pkt_num = pkt_num;
- }
- }
- if (pktns->rx.max_pkt_num < pkt_num) {
- pktns->rx.max_pkt_num = pkt_num;
- pktns->rx.max_pkt_ts = ts;
- }
- return 0;
- }
- /*
- * verify_token verifies |hd| contains |token| in its token field. It
- * returns 0 if it succeeds, or NGTCP2_ERR_PROTO.
- */
- static int verify_token(const uint8_t *token, size_t tokenlen,
- const ngtcp2_pkt_hd *hd) {
- if (tokenlen == hd->tokenlen && ngtcp2_cmemeq(token, hd->token, tokenlen)) {
- return 0;
- }
- return NGTCP2_ERR_PROTO;
- }
- static void pktns_increase_ecn_counts(ngtcp2_pktns *pktns,
- const ngtcp2_pkt_info *pi) {
- switch (pi->ecn & NGTCP2_ECN_MASK) {
- case NGTCP2_ECN_ECT_0:
- ++pktns->rx.ecn.ect0;
- break;
- case NGTCP2_ECN_ECT_1:
- ++pktns->rx.ecn.ect1;
- break;
- case NGTCP2_ECN_CE:
- ++pktns->rx.ecn.ce;
- break;
- }
- }
- /*
- * vneg_available_versions_includes returns nonzero if
- * |available_versions| of length |available_versionslen| includes
- * |version|. |available_versions| is the wire image of
- * available_versions field of version_information transport
- * parameter, and each version is encoded in network byte order.
- */
- static int vneg_available_versions_includes(const uint8_t *available_versions,
- size_t available_versionslen,
- uint32_t version) {
- size_t i;
- uint32_t v;
- assert(!(available_versionslen & 0x3));
- if (available_versionslen == 0) {
- return 0;
- }
- for (i = 0; i < available_versionslen; i += sizeof(uint32_t)) {
- available_versions = ngtcp2_get_uint32be(&v, available_versions);
- if (version == v) {
- return 1;
- }
- }
- return 0;
- }
- /*
- * conn_verify_fixed_bit verifies that fixed bit in |hd| is
- * acceptable.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_INVALID_ARGUMENT
- * Clearing fixed bit is not permitted.
- */
- static int conn_verify_fixed_bit(ngtcp2_conn *conn, ngtcp2_pkt_hd *hd) {
- if (!(hd->flags & NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR)) {
- return 0;
- }
- if (conn->server) {
- switch (hd->type) {
- case NGTCP2_PKT_INITIAL:
- case NGTCP2_PKT_0RTT:
- case NGTCP2_PKT_HANDSHAKE:
- /* RFC 9287 requires that a token from NEW_TOKEN. */
- if (!(conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) &&
- (conn->local.settings.token_type != NGTCP2_TOKEN_TYPE_NEW_TOKEN ||
- !conn->local.settings.tokenlen)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- break;
- }
- }
- /* TODO we have no information that we enabled grease_quic_bit in
- the previous connection. */
- if (!conn->local.transport_params.grease_quic_bit) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- return 0;
- }
- static int conn_recv_crypto(ngtcp2_conn *conn,
- ngtcp2_encryption_level encryption_level,
- ngtcp2_strm *strm, const ngtcp2_stream *fr);
- static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
- const ngtcp2_pkt_info *pi, const uint8_t *pkt,
- size_t pktlen, size_t dgramlen,
- ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts);
- static int conn_process_buffered_protected_pkt(ngtcp2_conn *conn,
- ngtcp2_pktns *pktns,
- ngtcp2_tstamp ts);
- /*
- * conn_recv_handshake_pkt processes received packet |pkt| whose
- * length is |pktlen| during handshake period. The buffer pointed by
- * |pkt| might contain multiple packets. This function only processes
- * one packet. |pkt_ts| is the timestamp when packet is received.
- * |ts| should be the current time. Usually they are the same, but
- * for buffered packets, |pkt_ts| would be earlier than |ts|.
- *
- * This function returns the number of bytes it reads if it succeeds,
- * or one of the following negative error codes:
- *
- * NGTCP2_ERR_RECV_VERSION_NEGOTIATION
- * Version Negotiation packet is received.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_DISCARD_PKT
- * Packet was discarded because plain text header was malformed;
- * or its payload could not be decrypted.
- * NGTCP2_ERR_FRAME_FORMAT
- * Frame is badly formatted
- * NGTCP2_ERR_ACK_FRAME
- * ACK frame is malformed.
- * NGTCP2_ERR_CRYPTO
- * TLS stack reported error.
- * NGTCP2_ERR_PROTO
- * Generic QUIC protocol error.
- *
- * In addition to the above error codes, error codes returned from
- * conn_recv_pkt are also returned.
- */
- static ngtcp2_ssize
- conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
- const ngtcp2_pkt_info *pi, const uint8_t *pkt,
- size_t pktlen, size_t dgramlen, ngtcp2_tstamp pkt_ts,
- ngtcp2_tstamp ts) {
- ngtcp2_ssize nread;
- ngtcp2_pkt_hd hd;
- ngtcp2_max_frame mfr;
- ngtcp2_frame *fr = &mfr.fr;
- int rv;
- int require_ack = 0;
- size_t hdpktlen;
- const uint8_t *payload;
- size_t payloadlen;
- ngtcp2_ssize nwrite;
- ngtcp2_crypto_aead *aead;
- ngtcp2_crypto_cipher *hp;
- ngtcp2_crypto_km *ckm;
- ngtcp2_crypto_cipher_ctx *hp_ctx;
- ngtcp2_hp_mask hp_mask;
- ngtcp2_decrypt decrypt;
- ngtcp2_pktns *pktns;
- ngtcp2_strm *crypto;
- ngtcp2_encryption_level encryption_level;
- int invalid_reserved_bits = 0;
- size_t num_ack_processed = 0;
- if (pktlen == 0) {
- return 0;
- }
- if (!(pkt[0] & NGTCP2_HEADER_FORM_BIT)) {
- if (conn->state == NGTCP2_CS_SERVER_INITIAL) {
- /* Ignore 1RTT packet unless server's first Handshake packet has
- been transmitted. */
- return (ngtcp2_ssize)pktlen;
- }
- if (conn->pktns.crypto.rx.ckm) {
- return 0;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "buffering 1RTT packet len=%zu", pktlen);
- rv =
- conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt, pktlen, dgramlen, ts);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- return (ngtcp2_ssize)pktlen;
- }
- nread = ngtcp2_pkt_decode_hd_long(&hd, pkt, pktlen);
- if (nread < 0) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- switch (hd.type) {
- case NGTCP2_PKT_VERSION_NEGOTIATION:
- hdpktlen = (size_t)nread;
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- if (conn->server) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- /* Receiving Version Negotiation packet after getting Handshake
- packet from server is invalid. */
- if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (!ngtcp2_cid_eq(&conn->oscid, &hd.dcid)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched DCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (!ngtcp2_cid_eq(&conn->dcid.current.cid, &hd.scid)) {
- /* Just discard invalid Version Negotiation packet */
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched SCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- rv =
- conn_on_version_negotiation(conn, &hd, pkt + hdpktlen, pktlen - hdpktlen);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- return NGTCP2_ERR_DISCARD_PKT;
- }
- return NGTCP2_ERR_RECV_VERSION_NEGOTIATION;
- case NGTCP2_PKT_RETRY:
- hdpktlen = (size_t)nread;
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- if (conn->server) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn_verify_fixed_bit(conn, &hd) != 0) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- /* Receiving Retry packet after getting Initial packet from server
- is invalid. */
- if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn->client_chosen_version != hd.version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- rv = conn_on_retry(conn, &hd, hdpktlen, pkt, pktlen, ts);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- return NGTCP2_ERR_DISCARD_PKT;
- }
- return (ngtcp2_ssize)pktlen;
- }
- if (pktlen < (size_t)nread + hd.len) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- pktlen = (size_t)nread + hd.len;
- if (!ngtcp2_is_supported_version(hd.version)) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn->server) {
- if (hd.version != conn->client_chosen_version &&
- (!conn->negotiated_version || hd.version != conn->negotiated_version)) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- } else if (hd.version != conn->client_chosen_version &&
- conn->negotiated_version &&
- hd.version != conn->negotiated_version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn_verify_fixed_bit(conn, &hd) != 0) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- /* Quoted from spec: if subsequent packets of those types include a
- different Source Connection ID, they MUST be discarded. */
- if ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) &&
- !ngtcp2_cid_eq(&conn->dcid.current.cid, &hd.scid)) {
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched SCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- switch (hd.type) {
- case NGTCP2_PKT_0RTT:
- if (!conn->server) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (hd.version != conn->client_chosen_version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) {
- if (conn->early.ckm) {
- ngtcp2_ssize nread2;
- /* TODO Avoid to parse header twice. */
- nread2 =
- conn_recv_pkt(conn, path, pi, pkt, pktlen, dgramlen, pkt_ts, ts);
- if (nread2 < 0) {
- return nread2;
- }
- }
- /* Discard 0-RTT packet if we don't have a key to decrypt it. */
- return (ngtcp2_ssize)pktlen;
- }
- /* Buffer re-ordered 0-RTT packet. */
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "buffering 0-RTT packet len=%zu", pktlen);
- rv = conn_buffer_pkt(conn, conn->in_pktns, path, pi, pkt, pktlen, dgramlen,
- ts);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- return (ngtcp2_ssize)pktlen;
- case NGTCP2_PKT_INITIAL:
- if (!conn->in_pktns) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_PKT,
- "Initial packet is discarded because keys have been discarded");
- return (ngtcp2_ssize)pktlen;
- }
- assert(conn->in_pktns);
- if (conn->server) {
- if (dgramlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_PKT,
- "Initial packet was ignored because it is included in UDP datagram "
- "less than %zu bytes: %zu bytes",
- NGTCP2_MAX_UDP_PAYLOAD_SIZE, dgramlen);
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn->local.settings.tokenlen) {
- rv = verify_token(conn->local.settings.token,
- conn->local.settings.tokenlen, &hd);
- if (rv != 0) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because token is invalid");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- }
- if ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) == 0) {
- /* Set rcid here so that it is available to callback. If this
- packet is discarded later in this function and no packet is
- processed in this connection attempt so far, connection
- will be dropped. */
- conn->rcid = hd.dcid;
- rv = conn_call_recv_client_initial(conn, &hd.dcid);
- if (rv != 0) {
- return rv;
- }
- }
- } else {
- if (hd.tokenlen != 0) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because token is not empty");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (hd.version != conn->client_chosen_version &&
- !conn->negotiated_version && conn->vneg.version != hd.version) {
- if (!vneg_available_versions_includes(conn->vneg.available_versions,
- conn->vneg.available_versionslen,
- hd.version)) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- /* Install new Initial keys using QUIC version = hd.version */
- rv = conn_call_version_negotiation(
- conn, hd.version,
- (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) ? &conn->dcid.current.cid
- : &conn->rcid);
- if (rv != 0) {
- return rv;
- }
- assert(conn->vneg.version == hd.version);
- }
- }
- pktns = conn->in_pktns;
- crypto = &pktns->crypto.strm;
- encryption_level = NGTCP2_ENCRYPTION_LEVEL_INITIAL;
- if (hd.version == conn->client_chosen_version) {
- ckm = pktns->crypto.rx.ckm;
- hp_ctx = &pktns->crypto.rx.hp_ctx;
- } else {
- assert(conn->vneg.version == hd.version);
- ckm = conn->vneg.rx.ckm;
- hp_ctx = &conn->vneg.rx.hp_ctx;
- }
- break;
- case NGTCP2_PKT_HANDSHAKE:
- if (hd.version != conn->negotiated_version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (!conn->hs_pktns->crypto.rx.ckm) {
- if (conn->server) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_PKT,
- "Handshake packet at this point is unexpected and discarded");
- return (ngtcp2_ssize)pktlen;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "buffering Handshake packet len=%zu", pktlen);
- rv = conn_buffer_pkt(conn, conn->hs_pktns, path, pi, pkt, pktlen,
- dgramlen, ts);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- return (ngtcp2_ssize)pktlen;
- }
- pktns = conn->hs_pktns;
- crypto = &pktns->crypto.strm;
- encryption_level = NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE;
- ckm = pktns->crypto.rx.ckm;
- hp_ctx = &pktns->crypto.rx.hp_ctx;
- break;
- default:
- ngtcp2_unreachable();
- }
- hp_mask = conn->callbacks.hp_mask;
- decrypt = conn->callbacks.decrypt;
- aead = &pktns->crypto.ctx.aead;
- hp = &pktns->crypto.ctx.hp;
- assert(ckm);
- assert(hp_mask);
- assert(decrypt);
- rv = conn_ensure_decrypt_hp_buffer(conn, (size_t)nread + 4);
- if (rv != 0) {
- return rv;
- }
- nwrite = decrypt_hp(&hd, conn->crypto.decrypt_hp_buf.base, hp, pkt, pktlen,
- (size_t)nread, hp_ctx, hp_mask);
- if (nwrite < 0) {
- if (ngtcp2_err_is_fatal((int)nwrite)) {
- return nwrite;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decrypt packet number");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- hdpktlen = (size_t)nwrite;
- payload = pkt + hdpktlen;
- payloadlen = hd.len - hd.pkt_numlen;
- hd.pkt_num =
- ngtcp2_pkt_adjust_pkt_num(pktns->rx.max_pkt_num, hd.pkt_num, hd.pkt_numlen);
- if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
- return NGTCP2_ERR_DISCARD_PKT;
- }
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- rv = ngtcp2_pkt_verify_reserved_bits(conn->crypto.decrypt_hp_buf.base[0]);
- if (rv != 0) {
- invalid_reserved_bits = 1;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet has incorrect reserved bits");
- /* Will return error after decrypting payload */
- }
- if (pktns_pkt_num_is_duplicate(pktns, hd.pkt_num)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was discarded because of duplicated packet number");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- rv = conn_ensure_decrypt_buffer(conn, payloadlen);
- if (rv != 0) {
- return rv;
- }
- nwrite = decrypt_pkt(conn->crypto.decrypt_buf.base, aead, payload, payloadlen,
- conn->crypto.decrypt_hp_buf.base, hdpktlen, hd.pkt_num,
- ckm, decrypt);
- if (nwrite < 0) {
- if (ngtcp2_err_is_fatal((int)nwrite)) {
- return nwrite;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decrypt packet payload");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (invalid_reserved_bits) {
- return NGTCP2_ERR_PROTO;
- }
- if (!conn->server && hd.version != conn->client_chosen_version &&
- !conn->negotiated_version) {
- conn->negotiated_version = hd.version;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "the negotiated version is 0x%08x",
- conn->negotiated_version);
- }
- payload = conn->crypto.decrypt_buf.base;
- payloadlen = (size_t)nwrite;
- switch (hd.type) {
- case NGTCP2_PKT_INITIAL:
- if (!conn->server ||
- ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) &&
- !ngtcp2_cid_eq(&conn->rcid, &hd.dcid))) {
- rv = conn_verify_dcid(conn, NULL, &hd);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched DCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- }
- break;
- case NGTCP2_PKT_HANDSHAKE:
- rv = conn_verify_dcid(conn, NULL, &hd);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched DCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- break;
- default:
- ngtcp2_unreachable();
- }
- if (payloadlen == 0) {
- /* QUIC packet must contain at least one frame */
- if (hd.type == NGTCP2_PKT_INITIAL) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- return NGTCP2_ERR_PROTO;
- }
- if (hd.type == NGTCP2_PKT_INITIAL &&
- !(conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED)) {
- conn->flags |= NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED;
- if (!conn->server) {
- conn->dcid.current.cid = hd.scid;
- }
- }
- ngtcp2_qlog_pkt_received_start(&conn->qlog);
- for (; payloadlen;) {
- nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
- if (nread < 0) {
- return nread;
- }
- payload += nread;
- payloadlen -= (size_t)nread;
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- fr->ack.ack_delay = 0;
- fr->ack.ack_delay_unscaled = 0;
- rv =
- ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
- if (rv != 0) {
- return rv;
- }
- break;
- }
- ngtcp2_log_rx_fr(&conn->log, &hd, fr);
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
- break;
- }
- if (!conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) {
- conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
- }
- rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
- if (rv != 0) {
- return rv;
- }
- ++num_ack_processed;
- break;
- case NGTCP2_FRAME_PADDING:
- break;
- case NGTCP2_FRAME_CRYPTO:
- if (!conn->server && !conn->negotiated_version &&
- ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt)) {
- conn->negotiated_version = hd.version;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "the negotiated version is 0x%08x",
- conn->negotiated_version);
- }
- rv = conn_recv_crypto(conn, encryption_level, crypto, &fr->stream);
- if (rv != 0) {
- return rv;
- }
- require_ack = 1;
- break;
- case NGTCP2_FRAME_CONNECTION_CLOSE:
- rv = conn_recv_connection_close(conn, &fr->connection_close);
- if (rv != 0) {
- return rv;
- }
- break;
- case NGTCP2_FRAME_PING:
- require_ack = 1;
- break;
- default:
- return NGTCP2_ERR_PROTO;
- }
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
- }
- if (hd.type == NGTCP2_PKT_HANDSHAKE) {
- /* Successful processing of Handshake packet from a remote
- endpoint validates its source address. */
- conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED;
- }
- ngtcp2_qlog_pkt_received_end(&conn->qlog, &hd, pktlen);
- rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num, require_ack, pkt_ts);
- if (rv != 0) {
- return rv;
- }
- pktns_increase_ecn_counts(pktns, pi);
- /* Initial and Handshake are always acknowledged without delay. No
- need to call ngtcp2_acktr_immediate_ack(). */
- rv =
- ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd.pkt_num, require_ack, pkt_ts);
- if (rv != 0) {
- return rv;
- }
- conn_restart_timer_on_read(conn, ts);
- ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
- return conn->state == NGTCP2_CS_DRAINING ? NGTCP2_ERR_DRAINING
- : (ngtcp2_ssize)pktlen;
- }
- static int is_unrecoverable_error(int liberr) {
- switch (liberr) {
- case NGTCP2_ERR_CRYPTO:
- case NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM:
- case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
- case NGTCP2_ERR_TRANSPORT_PARAM:
- case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
- return 1;
- }
- return 0;
- }
- /*
- * conn_recv_handshake_cpkt processes compound packet during
- * handshake. The buffer pointed by |pkt| might contain multiple
- * packets. The 1RTT packet must be the last one because it does not
- * have payload length field.
- *
- * This function returns the same error code returned by
- * conn_recv_handshake_pkt.
- */
- static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn,
- const ngtcp2_path *path,
- const ngtcp2_pkt_info *pi,
- const uint8_t *pkt, size_t pktlen,
- ngtcp2_tstamp ts) {
- ngtcp2_ssize nread;
- size_t dgramlen = pktlen;
- const uint8_t *origpkt = pkt;
- uint32_t version;
- if (ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- conn->dcid.current.bytes_recv += dgramlen;
- }
- while (pktlen) {
- nread =
- conn_recv_handshake_pkt(conn, path, pi, pkt, pktlen, dgramlen, ts, ts);
- if (nread < 0) {
- if (ngtcp2_err_is_fatal((int)nread)) {
- return nread;
- }
- if (nread == NGTCP2_ERR_DRAINING) {
- return NGTCP2_ERR_DRAINING;
- }
- if ((pkt[0] & NGTCP2_HEADER_FORM_BIT) && pktlen > 4) {
- /* Not a Version Negotiation packet */
- ngtcp2_get_uint32be(&version, &pkt[1]);
- if (ngtcp2_pkt_get_type_long(version, pkt[0]) == NGTCP2_PKT_INITIAL) {
- if (conn->server) {
- if (is_unrecoverable_error((int)nread)) {
- /* If server gets crypto error from TLS stack, it is
- unrecoverable, therefore drop connection. */
- return nread;
- }
- /* If server discards first Initial, then drop connection
- state. This is because SCID in packet might be corrupted
- and the current connection state might wrongly discard
- valid packet and prevent the handshake from
- completing. */
- if (conn->in_pktns && conn->in_pktns->rx.max_pkt_num == -1) {
- return NGTCP2_ERR_DROP_CONN;
- }
- return (ngtcp2_ssize)dgramlen;
- }
- /* client */
- if (is_unrecoverable_error((int)nread)) {
- /* If client gets crypto error from TLS stack, it is
- unrecoverable, therefore drop connection. */
- return nread;
- }
- return (ngtcp2_ssize)dgramlen;
- }
- }
- if (nread == NGTCP2_ERR_DISCARD_PKT) {
- return (ngtcp2_ssize)dgramlen;
- }
- return nread;
- }
- if (nread == 0) {
- assert(!(pkt[0] & NGTCP2_HEADER_FORM_BIT));
- return pkt - origpkt;
- }
- assert(pktlen >= (size_t)nread);
- pkt += nread;
- pktlen -= (size_t)nread;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "read packet %td left %zu", nread, pktlen);
- }
- return (ngtcp2_ssize)dgramlen;
- }
- int ngtcp2_conn_init_stream(ngtcp2_conn *conn, ngtcp2_strm *strm,
- int64_t stream_id, void *stream_user_data) {
- int rv;
- uint64_t max_rx_offset;
- uint64_t max_tx_offset;
- int local_stream = conn_local_stream(conn, stream_id);
- assert(conn->remote.transport_params);
- if (bidi_stream(stream_id)) {
- if (local_stream) {
- max_rx_offset =
- conn->local.transport_params.initial_max_stream_data_bidi_local;
- max_tx_offset =
- conn->remote.transport_params->initial_max_stream_data_bidi_remote;
- } else {
- max_rx_offset =
- conn->local.transport_params.initial_max_stream_data_bidi_remote;
- max_tx_offset =
- conn->remote.transport_params->initial_max_stream_data_bidi_local;
- }
- } else if (local_stream) {
- max_rx_offset = 0;
- max_tx_offset = conn->remote.transport_params->initial_max_stream_data_uni;
- } else {
- max_rx_offset = conn->local.transport_params.initial_max_stream_data_uni;
- max_tx_offset = 0;
- }
- ngtcp2_strm_init(strm, stream_id, NGTCP2_STRM_FLAG_NONE, max_rx_offset,
- max_tx_offset, stream_user_data, &conn->frc_objalloc,
- conn->mem);
- rv =
- ngtcp2_map_insert(&conn->strms, (ngtcp2_map_key_type)strm->stream_id, strm);
- if (rv != 0) {
- assert(rv != NGTCP2_ERR_INVALID_ARGUMENT);
- goto fail;
- }
- return 0;
- fail:
- ngtcp2_strm_free(strm);
- return rv;
- }
- /*
- * conn_emit_pending_stream_data passes buffered ordered stream data
- * to the application. |rx_offset| is the first offset to deliver to
- * the application. This function assumes that the data up to
- * |rx_offset| has been delivered already. This function only passes
- * the ordered data without any gap. If there is a gap, it stops
- * providing the data to the application, and returns.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t rx_offset) {
- size_t datalen;
- const uint8_t *data;
- int rv;
- uint64_t offset;
- uint32_t sdflags;
- int handshake_completed = conn_is_tls_handshake_completed(conn);
- if (!strm->rx.rob) {
- return 0;
- }
- for (;;) {
- /* Stop calling callback if application has called
- ngtcp2_conn_shutdown_stream_read() inside the callback.
- Because it doubly counts connection window. */
- if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) {
- return 0;
- }
- datalen = ngtcp2_rob_data_at(strm->rx.rob, &data, rx_offset);
- if (datalen == 0) {
- assert(rx_offset == ngtcp2_strm_rx_offset(strm));
- return 0;
- }
- offset = rx_offset;
- rx_offset += datalen;
- sdflags = NGTCP2_STREAM_DATA_FLAG_NONE;
- if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
- rx_offset == strm->rx.last_offset) {
- sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
- }
- if (!handshake_completed) {
- sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
- }
- rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, datalen);
- if (rv != 0) {
- return rv;
- }
- /* ngtcp2_conn_shutdown_stream_read from a callback will free
- strm->rx.rob. */
- if (!strm->rx.rob) {
- return 0;
- }
- ngtcp2_rob_pop(strm->rx.rob, rx_offset - datalen, datalen);
- }
- }
- /*
- * conn_recv_crypto is called when CRYPTO frame |fr| is received.
- * |rx_offset_base| is the offset in the entire TLS handshake stream.
- * fr->offset specifies the offset in each encryption level.
- * |max_rx_offset| is, if it is nonzero, the maximum offset in the
- * entire TLS handshake stream that |fr| can carry.
- * |encryption_level| is the encryption level where this data is
- * received.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_PROTO
- * CRYPTO frame has invalid offset.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CRYPTO
- * TLS stack reported error.
- * NGTCP2_ERR_FRAME_ENCODING
- * The end offset exceeds the maximum value.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_recv_crypto(ngtcp2_conn *conn,
- ngtcp2_encryption_level encryption_level,
- ngtcp2_strm *crypto, const ngtcp2_stream *fr) {
- uint64_t fr_end_offset;
- uint64_t rx_offset;
- int rv;
- if (fr->datacnt == 0) {
- return 0;
- }
- fr_end_offset = fr->offset + fr->data[0].len;
- if (NGTCP2_MAX_VARINT < fr_end_offset) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
- rx_offset = ngtcp2_strm_rx_offset(crypto);
- if (fr_end_offset <= rx_offset) {
- if (conn->server &&
- !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT) &&
- encryption_level == NGTCP2_ENCRYPTION_LEVEL_INITIAL) {
- /* https://datatracker.ietf.org/doc/html/rfc9002#section-6.2.3:
- Speeding Up Handshake Completion
- When a server receives an Initial packet containing duplicate
- CRYPTO data, it can assume the client did not receive all of
- the server's CRYPTO data sent in Initial packets, or the
- client's estimated RTT is too small. ... To speed up
- handshake completion under these conditions, an endpoint MAY
- send a packet containing unacknowledged CRYPTO data earlier
- than the PTO expiry, subject to address validation limits;
- ... */
- conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT;
- conn->in_pktns->rtb.probe_pkt_left = 1;
- conn->hs_pktns->rtb.probe_pkt_left = 1;
- }
- return 0;
- }
- crypto->rx.last_offset =
- ngtcp2_max_uint64(crypto->rx.last_offset, fr_end_offset);
- /* TODO Before dispatching incoming data to TLS stack, make sure
- that previous data in previous encryption level has been
- completely sent to TLS stack. Usually, if data is left, it is an
- error because key is generated after consuming all data in the
- previous encryption level. */
- if (fr->offset <= rx_offset) {
- size_t ncut = (size_t)(rx_offset - fr->offset);
- const uint8_t *data = fr->data[0].base + ncut;
- size_t datalen = fr->data[0].len - ncut;
- uint64_t offset = rx_offset;
- rx_offset += datalen;
- ngtcp2_strm_update_rx_offset(crypto, rx_offset);
- rv =
- conn_call_recv_crypto_data(conn, encryption_level, offset, data, datalen);
- if (rv != 0) {
- return rv;
- }
- rv =
- conn_emit_pending_crypto_data(conn, encryption_level, crypto, rx_offset);
- if (rv != 0) {
- return rv;
- }
- return 0;
- }
- if (fr_end_offset - rx_offset > NGTCP2_MAX_REORDERED_CRYPTO_DATA) {
- return NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED;
- }
- return ngtcp2_strm_recv_reordering(crypto, fr->data[0].base, fr->data[0].len,
- fr->offset);
- }
- /*
- * conn_max_data_violated returns nonzero if receiving |datalen|
- * violates connection flow control on local endpoint.
- */
- static int conn_max_data_violated(ngtcp2_conn *conn, uint64_t datalen) {
- return conn->rx.max_offset - conn->rx.offset < datalen;
- }
- /*
- * conn_recv_stream is called when STREAM frame |fr| is received.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_STREAM_STATE
- * STREAM frame is received for a local stream which is not
- * initiated; or STREAM frame is received for a local
- * unidirectional stream
- * NGTCP2_ERR_STREAM_LIMIT
- * STREAM frame has remote stream ID which is strictly greater
- * than the allowed limit.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_FLOW_CONTROL
- * Flow control limit is violated; or the end offset of stream
- * data is beyond the NGTCP2_MAX_VARINT.
- * NGTCP2_ERR_FINAL_SIZE
- * STREAM frame has strictly larger end offset than it is
- * permitted.
- */
- static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
- int rv;
- ngtcp2_strm *strm;
- ngtcp2_idtr *idtr;
- uint64_t rx_offset, fr_end_offset;
- int local_stream;
- int bidi;
- uint64_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
- uint32_t sdflags = NGTCP2_STREAM_DATA_FLAG_NONE;
- local_stream = conn_local_stream(conn, fr->stream_id);
- bidi = bidi_stream(fr->stream_id);
- if (bidi) {
- if (local_stream) {
- if (conn->local.bidi.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- } else if (conn->remote.bidi.max_streams <
- ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.bidi.idtr;
- } else {
- if (local_stream) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- if (conn->remote.uni.max_streams < ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.uni.idtr;
- }
- if (NGTCP2_MAX_VARINT - datalen < fr->offset) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
- if (strm == NULL) {
- if (local_stream) {
- /* TODO The stream has been closed. This should be responded
- with RESET_STREAM, or simply ignored. */
- return 0;
- }
- rv = ngtcp2_idtr_open(idtr, fr->stream_id);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- assert(rv == NGTCP2_ERR_STREAM_IN_USE);
- /* TODO The stream has been closed. This should be responded
- with RESET_STREAM, or simply ignored. */
- return 0;
- }
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- if (!bidi) {
- ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR);
- strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED;
- }
- rv = conn_call_stream_open(conn, strm);
- if (rv != 0) {
- return rv;
- }
- }
- fr_end_offset = fr->offset + datalen;
- if (strm->rx.max_offset < fr_end_offset) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- if (strm->rx.last_offset < fr_end_offset) {
- uint64_t len = fr_end_offset - strm->rx.last_offset;
- if (conn_max_data_violated(conn, len)) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- conn->rx.offset += len;
- if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) {
- ngtcp2_conn_extend_max_offset(conn, len);
- }
- }
- rx_offset = ngtcp2_strm_rx_offset(strm);
- if (fr->fin) {
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) {
- if (strm->rx.last_offset != fr_end_offset) {
- return NGTCP2_ERR_FINAL_SIZE;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
- return 0;
- }
- if (rx_offset == fr_end_offset) {
- return 0;
- }
- } else if (strm->rx.last_offset > fr_end_offset) {
- return NGTCP2_ERR_FINAL_SIZE;
- } else {
- strm->rx.last_offset = fr_end_offset;
- ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_RD);
- }
- } else {
- if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
- strm->rx.last_offset < fr_end_offset) {
- return NGTCP2_ERR_FINAL_SIZE;
- }
- strm->rx.last_offset =
- ngtcp2_max_uint64(strm->rx.last_offset, fr_end_offset);
- if (fr_end_offset <= rx_offset) {
- return 0;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
- return 0;
- }
- }
- if (fr->offset <= rx_offset) {
- size_t ncut = (size_t)(rx_offset - fr->offset);
- uint64_t offset = rx_offset;
- const uint8_t *data;
- int fin;
- if (fr->datacnt) {
- data = fr->data[0].base + ncut;
- datalen -= ncut;
- rx_offset += datalen;
- ngtcp2_strm_update_rx_offset(strm, rx_offset);
- } else {
- data = NULL;
- datalen = 0;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) {
- return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
- }
- fin = (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
- rx_offset == strm->rx.last_offset;
- if (fin || datalen) {
- if (fin) {
- sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
- }
- if (!conn_is_tls_handshake_completed(conn)) {
- sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
- }
- rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
- (size_t)datalen);
- if (rv != 0) {
- return rv;
- }
- rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
- if (rv != 0) {
- return rv;
- }
- }
- } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
- rv = ngtcp2_strm_recv_reordering(strm, fr->data[0].base, fr->data[0].len,
- fr->offset);
- if (rv != 0) {
- return rv;
- }
- }
- return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
- }
- /*
- * conn_reset_stream adds RESET_STREAM frame to the transmission
- * queue.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_reset_stream(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t app_error_code) {
- strm->flags |= NGTCP2_STRM_FLAG_SEND_RESET_STREAM;
- strm->tx.reset_stream_app_error_code = app_error_code;
- if (ngtcp2_strm_is_tx_queued(strm)) {
- return 0;
- }
- strm->cycle = conn_tx_strmq_first_cycle(conn);
- return ngtcp2_conn_tx_strmq_push(conn, strm);
- }
- /*
- * conn_stop_sending adds STOP_SENDING frame to the transmission
- * queue.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_stop_sending(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t app_error_code) {
- strm->flags |= NGTCP2_STRM_FLAG_SEND_STOP_SENDING;
- strm->tx.stop_sending_app_error_code = app_error_code;
- if (ngtcp2_strm_is_tx_queued(strm)) {
- return 0;
- }
- strm->cycle = conn_tx_strmq_first_cycle(conn);
- return ngtcp2_conn_tx_strmq_push(conn, strm);
- }
- /*
- * handle_max_remote_streams_extension extends
- * |*punsent_max_remote_streams| by |n| if a condition allows it.
- */
- static void
- handle_max_remote_streams_extension(uint64_t *punsent_max_remote_streams,
- size_t n) {
- if (
- #if SIZE_MAX > UINT32_MAX
- NGTCP2_MAX_STREAMS < n ||
- #endif /* SIZE_MAX > UINT32_MAX */
- *punsent_max_remote_streams > (uint64_t)(NGTCP2_MAX_STREAMS - n)) {
- *punsent_max_remote_streams = NGTCP2_MAX_STREAMS;
- } else {
- *punsent_max_remote_streams += n;
- }
- }
- /*
- * conn_recv_reset_stream is called when RESET_STREAM |fr| is
- * received.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_STREAM_STATE
- * RESET_STREAM frame is received to the local stream which is not
- * initiated.
- * NGTCP2_ERR_STREAM_LIMIT
- * RESET_STREAM frame has remote stream ID which is strictly
- * greater than the allowed limit.
- * NGTCP2_ERR_PROTO
- * RESET_STREAM frame is received to the local unidirectional
- * stream
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_FLOW_CONTROL
- * Flow control limit is violated; or the final size is beyond the
- * NGTCP2_MAX_VARINT.
- * NGTCP2_ERR_FINAL_SIZE
- * The final offset is strictly larger than it is permitted.
- */
- static int conn_recv_reset_stream(ngtcp2_conn *conn,
- const ngtcp2_reset_stream *fr) {
- ngtcp2_strm *strm;
- int local_stream = conn_local_stream(conn, fr->stream_id);
- int bidi = bidi_stream(fr->stream_id);
- uint64_t datalen;
- ngtcp2_idtr *idtr;
- int rv;
- /* TODO share this piece of code */
- if (bidi) {
- if (local_stream) {
- if (conn->local.bidi.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- } else if (conn->remote.bidi.max_streams <
- ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.bidi.idtr;
- } else {
- if (local_stream) {
- return NGTCP2_ERR_PROTO;
- }
- if (conn->remote.uni.max_streams < ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.uni.idtr;
- }
- if (NGTCP2_MAX_VARINT < fr->final_size) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
- if (strm == NULL) {
- if (local_stream) {
- return 0;
- }
- rv = ngtcp2_idtr_open(idtr, fr->stream_id);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- assert(rv == NGTCP2_ERR_STREAM_IN_USE);
- return 0;
- }
- if (conn_initial_stream_rx_offset(conn, fr->stream_id) < fr->final_size ||
- conn_max_data_violated(conn, fr->final_size)) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- /* Stream is reset before we create ngtcp2_strm object. */
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- rv = conn_call_stream_open(conn, strm);
- if (rv != 0) {
- return rv;
- }
- }
- if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD)) {
- if (strm->rx.last_offset != fr->final_size) {
- return NGTCP2_ERR_FINAL_SIZE;
- }
- } else if (strm->rx.last_offset > fr->final_size) {
- return NGTCP2_ERR_FINAL_SIZE;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
- return 0;
- }
- if (strm->rx.max_offset < fr->final_size) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- datalen = fr->final_size - strm->rx.last_offset;
- if (conn_max_data_violated(conn, datalen)) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- rv = conn_call_stream_reset(conn, fr->stream_id, fr->final_size,
- fr->app_error_code, strm->stream_user_data);
- if (rv != 0) {
- return rv;
- }
- /* Extend connection flow control window for the amount of data
- which are not passed to application. */
- if (!(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
- ngtcp2_conn_extend_max_offset(conn, strm->rx.last_offset -
- ngtcp2_strm_rx_offset(strm));
- }
- conn->rx.offset += datalen;
- ngtcp2_conn_extend_max_offset(conn, datalen);
- strm->rx.last_offset = fr->final_size;
- strm->flags |=
- NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_RESET_STREAM_RECVED;
- ngtcp2_strm_set_app_error_code(strm, fr->app_error_code);
- return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
- }
- /*
- * conn_recv_stop_sending is called when STOP_SENDING |fr| is received.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_STREAM_STATE
- * STOP_SENDING frame is received for a local stream which is not
- * initiated; or STOP_SENDING frame is received for a local
- * unidirectional stream.
- * NGTCP2_ERR_STREAM_LIMIT
- * STOP_SENDING frame has remote stream ID which is strictly
- * greater than the allowed limit.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_recv_stop_sending(ngtcp2_conn *conn,
- const ngtcp2_stop_sending *fr) {
- int rv;
- ngtcp2_strm *strm;
- ngtcp2_idtr *idtr;
- int local_stream = conn_local_stream(conn, fr->stream_id);
- int bidi = bidi_stream(fr->stream_id);
- if (bidi) {
- if (local_stream) {
- if (conn->local.bidi.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- } else if (conn->remote.bidi.max_streams <
- ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.bidi.idtr;
- } else {
- if (!local_stream || conn->local.uni.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- idtr = &conn->remote.uni.idtr;
- }
- strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
- if (strm == NULL) {
- if (local_stream) {
- return 0;
- }
- rv = ngtcp2_idtr_open(idtr, fr->stream_id);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- assert(rv == NGTCP2_ERR_STREAM_IN_USE);
- return 0;
- }
- /* STOP_SENDING frame is received before we create ngtcp2_strm
- object. */
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- rv = conn_call_stream_open(conn, strm);
- if (rv != 0) {
- return rv;
- }
- }
- if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING_RECVED) {
- return 0;
- }
- ngtcp2_strm_set_app_error_code(strm, fr->app_error_code);
- /* No RESET_STREAM is required if we have sent FIN and all data have
- been acknowledged. */
- if (!ngtcp2_strm_is_all_tx_data_fin_acked(strm) &&
- !(strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM)) {
- strm->flags |= NGTCP2_STRM_FLAG_RESET_STREAM;
- rv = conn_reset_stream(conn, strm, fr->app_error_code);
- if (rv != 0) {
- return rv;
- }
- }
- strm->flags |=
- NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_STOP_SENDING_RECVED;
- ngtcp2_strm_streamfrq_clear(strm);
- return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
- }
- /*
- * check_stateless_reset returns nonzero if Stateless Reset |sr|
- * coming via |path| is valid against |dcid|.
- */
- static int check_stateless_reset(const ngtcp2_dcid *dcid,
- const ngtcp2_path *path,
- const ngtcp2_pkt_stateless_reset *sr) {
- return ngtcp2_path_eq(&dcid->ps.path, path) &&
- ngtcp2_dcid_verify_stateless_reset_token(
- dcid, sr->stateless_reset_token) == 0;
- }
- /*
- * conn_on_stateless_reset decodes Stateless Reset from the buffer
- * pointed by |payload| whose length is |payloadlen|. |payload|
- * should start after first byte of packet.
- *
- * If Stateless Reset is decoded, and the Stateless Reset Token is
- * validated, the connection is closed.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_INVALID_ARGUMENT
- * Could not decode Stateless Reset; or Stateless Reset Token does
- * not match; or No stateless reset token is available.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed.
- */
- static int conn_on_stateless_reset(ngtcp2_conn *conn, const ngtcp2_path *path,
- const uint8_t *payload, size_t payloadlen) {
- int rv = 1;
- ngtcp2_pv *pv = conn->pv;
- ngtcp2_dcid *dcid;
- ngtcp2_pkt_stateless_reset sr;
- size_t len, i;
- rv = ngtcp2_pkt_decode_stateless_reset(&sr, payload, payloadlen);
- if (rv != 0) {
- return rv;
- }
- if (!check_stateless_reset(&conn->dcid.current, path, &sr) &&
- (!pv || (!check_stateless_reset(&pv->dcid, path, &sr) &&
- (!(pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) ||
- !check_stateless_reset(&pv->fallback_dcid, path, &sr))))) {
- len = ngtcp2_ringbuf_len(&conn->dcid.retired.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.retired.rb, i);
- if (check_stateless_reset(dcid, path, &sr)) {
- break;
- }
- }
- if (i == len) {
- len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, i);
- if (check_stateless_reset(dcid, path, &sr)) {
- break;
- }
- }
- if (i == len) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- }
- }
- conn->state = NGTCP2_CS_DRAINING;
- ngtcp2_log_rx_sr(&conn->log, &sr);
- ngtcp2_qlog_stateless_reset_pkt_received(&conn->qlog, &sr);
- return conn_call_recv_stateless_reset(conn, &sr);
- }
- /*
- * conn_recv_max_streams processes the incoming MAX_STREAMS frame
- * |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed.
- * NGTCP2_ERR_FRAME_ENCODING
- * The maximum streams field exceeds the maximum value.
- */
- static int conn_recv_max_streams(ngtcp2_conn *conn,
- const ngtcp2_max_streams *fr) {
- uint64_t n;
- if (fr->max_streams > NGTCP2_MAX_STREAMS) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
- n = ngtcp2_min_uint64(fr->max_streams, NGTCP2_MAX_STREAMS);
- if (fr->type == NGTCP2_FRAME_MAX_STREAMS_BIDI) {
- if (conn->local.bidi.max_streams < n) {
- conn->local.bidi.max_streams = n;
- return conn_call_extend_max_local_streams_bidi(conn, n);
- }
- return 0;
- }
- if (conn->local.uni.max_streams < n) {
- conn->local.uni.max_streams = n;
- return conn_call_extend_max_local_streams_uni(conn, n);
- }
- return 0;
- }
- static int conn_retire_dcid_prior_to(ngtcp2_conn *conn, ngtcp2_ringbuf *rb,
- uint64_t retire_prior_to) {
- size_t i;
- ngtcp2_dcid *dcid, *last;
- int rv;
- for (i = 0; i < ngtcp2_ringbuf_len(rb);) {
- dcid = ngtcp2_ringbuf_get(rb, i);
- if (dcid->seq >= retire_prior_to) {
- ++i;
- continue;
- }
- rv = conn_retire_dcid_seq(conn, dcid->seq);
- if (rv != 0) {
- return rv;
- }
- if (i == 0) {
- ngtcp2_ringbuf_pop_front(rb);
- continue;
- }
- if (i == ngtcp2_ringbuf_len(rb) - 1) {
- ngtcp2_ringbuf_pop_back(rb);
- break;
- }
- last = ngtcp2_ringbuf_get(rb, ngtcp2_ringbuf_len(rb) - 1);
- ngtcp2_dcid_copy(dcid, last);
- ngtcp2_ringbuf_pop_back(rb);
- }
- return 0;
- }
- /*
- * conn_recv_new_connection_id processes the incoming
- * NEW_CONNECTION_ID frame |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_PROTO
- * |fr| has the duplicated sequence number with different CID or
- * token; or DCID is zero-length.
- */
- static int conn_recv_new_connection_id(ngtcp2_conn *conn,
- const ngtcp2_new_connection_id *fr) {
- size_t i, len;
- ngtcp2_dcid *dcid;
- ngtcp2_pv *pv = conn->pv;
- int rv;
- int found = 0;
- size_t extra_dcid = 0;
- if (conn->dcid.current.cid.datalen == 0) {
- return NGTCP2_ERR_PROTO;
- }
- if (fr->retire_prior_to > fr->seq) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
- rv = ngtcp2_dcid_verify_uniqueness(&conn->dcid.current, fr->seq, &fr->cid,
- fr->stateless_reset_token);
- if (rv != 0) {
- return rv;
- }
- if (ngtcp2_cid_eq(&conn->dcid.current.cid, &fr->cid)) {
- found = 1;
- }
- if (pv) {
- rv = ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid,
- fr->stateless_reset_token);
- if (rv != 0) {
- return rv;
- }
- if (ngtcp2_cid_eq(&pv->dcid.cid, &fr->cid)) {
- found = 1;
- }
- }
- len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, i);
- rv = ngtcp2_dcid_verify_uniqueness(dcid, fr->seq, &fr->cid,
- fr->stateless_reset_token);
- if (rv != 0) {
- return NGTCP2_ERR_PROTO;
- }
- if (ngtcp2_cid_eq(&dcid->cid, &fr->cid)) {
- found = 1;
- }
- }
- len = ngtcp2_ringbuf_len(&conn->dcid.unused.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, i);
- rv = ngtcp2_dcid_verify_uniqueness(dcid, fr->seq, &fr->cid,
- fr->stateless_reset_token);
- if (rv != 0) {
- return NGTCP2_ERR_PROTO;
- }
- if (ngtcp2_cid_eq(&dcid->cid, &fr->cid)) {
- found = 1;
- }
- }
- if (conn->dcid.retire_prior_to < fr->retire_prior_to) {
- conn->dcid.retire_prior_to = fr->retire_prior_to;
- rv = conn_retire_dcid_prior_to(conn, &conn->dcid.bound.rb,
- fr->retire_prior_to);
- if (rv != 0) {
- return rv;
- }
- rv = conn_retire_dcid_prior_to(conn, &conn->dcid.unused.rb,
- conn->dcid.retire_prior_to);
- if (rv != 0) {
- return rv;
- }
- } else if (fr->seq < conn->dcid.retire_prior_to) {
- /* If packets are reordered, we might have retire_prior_to which
- is larger than fr->seq.
- A malicious peer might send crafted NEW_CONNECTION_ID to force
- local endpoint to create lots of RETIRE_CONNECTION_ID frames.
- For example, a peer might send seq = 50000 and retire_prior_to
- = 50000. Then send NEW_CONNECTION_ID frames with seq <
- 50000. */
- return conn_retire_dcid_seq(conn, fr->seq);
- }
- if (found) {
- return 0;
- }
- if (ngtcp2_gaptr_is_pushed(&conn->dcid.seqgap, fr->seq, 1)) {
- return 0;
- }
- rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, fr->seq, 1);
- if (rv != 0) {
- return rv;
- }
- if (ngtcp2_ksl_len(&conn->dcid.seqgap.gap) > 32) {
- ngtcp2_gaptr_drop_first_gap(&conn->dcid.seqgap);
- }
- len = ngtcp2_ringbuf_len(&conn->dcid.unused.rb);
- if (conn->dcid.current.seq >= conn->dcid.retire_prior_to) {
- ++extra_dcid;
- }
- if (pv) {
- if (pv->dcid.seq != conn->dcid.current.seq &&
- pv->dcid.seq >= conn->dcid.retire_prior_to) {
- ++extra_dcid;
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->fallback_dcid.seq != conn->dcid.current.seq &&
- pv->fallback_dcid.seq >= conn->dcid.retire_prior_to) {
- ++extra_dcid;
- }
- }
- if (conn->local.transport_params.active_connection_id_limit <=
- len + extra_dcid) {
- return NGTCP2_ERR_CONNECTION_ID_LIMIT;
- }
- if (len >= NGTCP2_MAX_DCID_POOL_SIZE) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "too many connection ID");
- return 0;
- }
- dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused.rb);
- ngtcp2_dcid_init(dcid, fr->seq, &fr->cid, fr->stateless_reset_token);
- return 0;
- }
- /*
- * conn_post_process_recv_new_connection_id handles retirement request
- * of active DCIDs.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_post_process_recv_new_connection_id(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- ngtcp2_pv *pv = conn->pv;
- ngtcp2_dcid *dcid;
- int rv;
- if (conn->dcid.current.seq < conn->dcid.retire_prior_to) {
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb) == 0) {
- return 0;
- }
- rv = conn_retire_dcid(conn, &conn->dcid.current, ts);
- if (rv != 0) {
- return rv;
- }
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- if (pv) {
- if (conn->dcid.current.seq == pv->dcid.seq) {
- ngtcp2_dcid_copy_cid_token(&pv->dcid, dcid);
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- conn->dcid.current.seq == pv->fallback_dcid.seq) {
- ngtcp2_dcid_copy_cid_token(&pv->fallback_dcid, dcid);
- }
- }
- ngtcp2_dcid_copy_cid_token(&conn->dcid.current, dcid);
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- rv = conn_call_activate_dcid(conn, &conn->dcid.current);
- if (rv != 0) {
- return rv;
- }
- }
- if (pv) {
- if (pv->dcid.seq < conn->dcid.retire_prior_to) {
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb)) {
- rv = conn_retire_dcid(conn, &pv->dcid, ts);
- if (rv != 0) {
- return rv;
- }
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->dcid.seq == pv->fallback_dcid.seq) {
- ngtcp2_dcid_copy_cid_token(&pv->fallback_dcid, dcid);
- }
- ngtcp2_dcid_copy_cid_token(&pv->dcid, dcid);
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- rv = conn_call_activate_dcid(conn, &pv->dcid);
- if (rv != 0) {
- return rv;
- }
- } else {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PTV,
- "path migration is aborted because connection ID is"
- "retired and no unused connection ID is available");
- return conn_abort_pv(conn, ts);
- }
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->fallback_dcid.seq < conn->dcid.retire_prior_to) {
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb)) {
- rv = conn_retire_dcid(conn, &pv->fallback_dcid, ts);
- if (rv != 0) {
- return rv;
- }
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- ngtcp2_dcid_copy_cid_token(&pv->fallback_dcid, dcid);
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- rv = conn_call_activate_dcid(conn, &pv->fallback_dcid);
- if (rv != 0) {
- return rv;
- }
- } else {
- /* Now we have no fallback dcid. */
- return conn_abort_pv(conn, ts);
- }
- }
- }
- return 0;
- }
- /*
- * conn_recv_retire_connection_id processes the incoming
- * RETIRE_CONNECTION_ID frame |fr|. |hd| is a packet header which
- * |fr| is included.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_PROTO
- * SCID is zero-length.
- * NGTCP2_ERR_FRAME_ENCODING
- * Attempt to retire CID which is used as DCID to send this frame.
- */
- static int conn_recv_retire_connection_id(ngtcp2_conn *conn,
- const ngtcp2_pkt_hd *hd,
- const ngtcp2_retire_connection_id *fr,
- ngtcp2_tstamp ts) {
- ngtcp2_ksl_it it;
- ngtcp2_scid *scid;
- if (conn->oscid.datalen == 0 || conn->scid.last_seq < fr->seq) {
- return NGTCP2_ERR_PROTO;
- }
- for (it = ngtcp2_ksl_begin(&conn->scid.set); !ngtcp2_ksl_it_end(&it);
- ngtcp2_ksl_it_next(&it)) {
- scid = ngtcp2_ksl_it_get(&it);
- if (scid->seq == fr->seq) {
- if (ngtcp2_cid_eq(&scid->cid, &hd->dcid)) {
- return NGTCP2_ERR_PROTO;
- }
- if (!(scid->flags & NGTCP2_SCID_FLAG_RETIRED)) {
- scid->flags |= NGTCP2_SCID_FLAG_RETIRED;
- ++conn->scid.num_retired;
- }
- if (scid->pe.index != NGTCP2_PQ_BAD_INDEX) {
- ngtcp2_pq_remove(&conn->scid.used, &scid->pe);
- scid->pe.index = NGTCP2_PQ_BAD_INDEX;
- }
- scid->retired_ts = ts;
- return ngtcp2_pq_push(&conn->scid.used, &scid->pe);
- }
- }
- return 0;
- }
- /*
- * conn_recv_new_token processes the incoming NEW_TOKEN frame |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_FRAME_ENCODING
- * Token is empty
- * NGTCP2_ERR_PROTO:
- * Server received NEW_TOKEN.
- */
- static int conn_recv_new_token(ngtcp2_conn *conn, const ngtcp2_new_token *fr) {
- if (conn->server) {
- return NGTCP2_ERR_PROTO;
- }
- if (fr->tokenlen == 0) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
- return conn_call_recv_new_token(conn, fr->token, fr->tokenlen);
- }
- /*
- * conn_recv_streams_blocked_bidi processes the incoming
- * STREAMS_BLOCKED (0x16).
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_FRAME_ENCODING
- * Maximum Streams is larger than advertised value.
- */
- static int conn_recv_streams_blocked_bidi(ngtcp2_conn *conn,
- ngtcp2_streams_blocked *fr) {
- if (fr->max_streams > conn->remote.bidi.max_streams) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
- return 0;
- }
- /*
- * conn_recv_streams_blocked_uni processes the incoming
- * STREAMS_BLOCKED (0x17).
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_FRAME_ENCODING
- * Maximum Streams is larger than advertised value.
- */
- static int conn_recv_streams_blocked_uni(ngtcp2_conn *conn,
- ngtcp2_streams_blocked *fr) {
- if (fr->max_streams > conn->remote.uni.max_streams) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
- return 0;
- }
- /*
- * conn_recv_stream_data_blocked processes the incoming
- * STREAM_DATA_BLOCKED frame |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_STREAM_STATE
- * STREAM_DATA_BLOCKED is received for a local stream which is not
- * initiated; or it is received for a local unidirectional stream.
- * NGTCP2_ERR_STREAM_LIMIT
- * STREAM_DATA_BLOCKED has remote stream ID which is strictly
- * greater than the allowed limit.
- * NGTCP2_ERR_FLOW_CONTROL
- * STREAM_DATA_BLOCKED frame violates flow control limit.
- * NGTCP2_ERR_FINAL_SIZE
- * The offset is strictly larger than it is permitted.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_recv_stream_data_blocked(ngtcp2_conn *conn,
- ngtcp2_stream_data_blocked *fr) {
- int rv;
- ngtcp2_strm *strm;
- ngtcp2_idtr *idtr;
- int local_stream = conn_local_stream(conn, fr->stream_id);
- int bidi = bidi_stream(fr->stream_id);
- uint64_t datalen;
- if (bidi) {
- if (local_stream) {
- if (conn->local.bidi.next_stream_id <= fr->stream_id) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- } else if (conn->remote.bidi.max_streams <
- ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.bidi.idtr;
- } else {
- if (local_stream) {
- return NGTCP2_ERR_STREAM_STATE;
- }
- if (conn->remote.uni.max_streams < ngtcp2_ord_stream_id(fr->stream_id)) {
- return NGTCP2_ERR_STREAM_LIMIT;
- }
- idtr = &conn->remote.uni.idtr;
- }
- strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
- if (strm == NULL) {
- if (local_stream) {
- return 0;
- }
- rv = ngtcp2_idtr_open(idtr, fr->stream_id);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- assert(rv == NGTCP2_ERR_STREAM_IN_USE);
- return 0;
- }
- /* Frame is received before we create ngtcp2_strm object. */
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- if (!bidi) {
- ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR);
- strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED;
- }
- rv = conn_call_stream_open(conn, strm);
- if (rv != 0) {
- return rv;
- }
- }
- if (strm->rx.max_offset < fr->offset) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- if (fr->offset <= strm->rx.last_offset) {
- return 0;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) {
- return NGTCP2_ERR_FINAL_SIZE;
- }
- datalen = fr->offset - strm->rx.last_offset;
- if (datalen) {
- if (conn_max_data_violated(conn, datalen)) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- conn->rx.offset += datalen;
- if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) {
- ngtcp2_conn_extend_max_offset(conn, datalen);
- }
- }
- strm->rx.last_offset = fr->offset;
- return 0;
- }
- /*
- * conn_recv_data_blocked processes the incoming DATA_BLOCKED frame
- * |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_FLOW_CONTROL
- * It violates connection-level flow control limit.
- */
- static int conn_recv_data_blocked(ngtcp2_conn *conn, ngtcp2_data_blocked *fr) {
- if (conn->rx.max_offset < fr->offset) {
- return NGTCP2_ERR_FLOW_CONTROL;
- }
- return 0;
- }
- /*
- * conn_select_preferred_addr asks a client application to select a
- * server address from preferred addresses received from server. If a
- * client chooses the address, path validation will start.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_select_preferred_addr(ngtcp2_conn *conn) {
- ngtcp2_path_storage ps;
- int rv;
- ngtcp2_pv *pv;
- ngtcp2_dcid *dcid;
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb) == 0) {
- return 0;
- }
- ngtcp2_path_storage_zero(&ps);
- ngtcp2_addr_copy(&ps.path.local, &conn->dcid.current.ps.path.local);
- rv = conn_call_select_preferred_addr(conn, &ps.path);
- if (rv != 0) {
- return rv;
- }
- if (ps.path.remote.addrlen == 0 ||
- ngtcp2_addr_eq(&conn->dcid.current.ps.path.remote, &ps.path.remote)) {
- return 0;
- }
- assert(conn->pv == NULL);
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- ngtcp2_dcid_set_path(dcid, &ps.path);
- rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn),
- NGTCP2_PV_FLAG_PREFERRED_ADDR, &conn->log, conn->mem);
- if (rv != 0) {
- /* TODO Call ngtcp2_dcid_free here if it is introduced */
- return rv;
- }
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- conn->pv = pv;
- return conn_call_activate_dcid(conn, &pv->dcid);
- }
- /*
- * conn_recv_handshake_done processes the incoming HANDSHAKE_DONE
- * frame |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_PROTO
- * Server received HANDSHAKE_DONE frame.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_recv_handshake_done(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- int rv;
- if (conn->server) {
- return NGTCP2_ERR_PROTO;
- }
- if (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) {
- return 0;
- }
- conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED |
- NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
- conn->pktns.rtb.persistent_congestion_start_ts = ts;
- ngtcp2_conn_discard_handshake_state(conn, ts);
- assert(conn->remote.transport_params);
- if (conn->remote.transport_params->preferred_addr_present) {
- rv = conn_select_preferred_addr(conn);
- if (rv != 0) {
- return rv;
- }
- }
- rv = conn_call_handshake_confirmed(conn);
- if (rv != 0) {
- return rv;
- }
- /* Re-arm loss detection timer after handshake has been
- confirmed. */
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- return 0;
- }
- /*
- * conn_recv_datagram processes the incoming DATAGRAM frame |fr|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- */
- static int conn_recv_datagram(ngtcp2_conn *conn, ngtcp2_datagram *fr) {
- assert(conn->local.transport_params.max_datagram_frame_size);
- return conn_call_recv_datagram(conn, fr);
- }
- /*
- * conn_key_phase_changed returns nonzero if |hd| indicates that the
- * key phase has unexpected value.
- */
- static int conn_key_phase_changed(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) {
- ngtcp2_pktns *pktns = &conn->pktns;
- return !(pktns->crypto.rx.ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE) ^
- !(hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE);
- }
- static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts);
- /*
- * conn_prepare_key_update installs new updated keys.
- */
- static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_tstamp confirmed_ts = conn->crypto.key_update.confirmed_ts;
- ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns);
- ngtcp2_pktns *pktns = &conn->pktns;
- ngtcp2_crypto_km *rx_ckm = pktns->crypto.rx.ckm;
- ngtcp2_crypto_km *tx_ckm = pktns->crypto.tx.ckm;
- ngtcp2_crypto_km *new_rx_ckm, *new_tx_ckm;
- ngtcp2_crypto_aead_ctx rx_aead_ctx = {0}, tx_aead_ctx = {0};
- size_t secretlen, ivlen;
- if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
- tx_ckm->use_count >= pktns->crypto.ctx.max_encryption &&
- conn_initiate_key_update(conn, ts) != 0) {
- return NGTCP2_ERR_AEAD_LIMIT_REACHED;
- }
- if ((conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) ||
- ngtcp2_tstamp_not_elapsed(confirmed_ts, pto, ts)) {
- return 0;
- }
- if (conn->crypto.key_update.new_rx_ckm ||
- conn->crypto.key_update.new_tx_ckm) {
- assert(conn->crypto.key_update.new_rx_ckm);
- assert(conn->crypto.key_update.new_tx_ckm);
- return 0;
- }
- secretlen = rx_ckm->secret.len;
- ivlen = rx_ckm->iv.len;
- rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_rx_ckm,
- secretlen, ivlen, conn->mem);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_tx_ckm,
- secretlen, ivlen, conn->mem);
- if (rv != 0) {
- return rv;
- }
- new_rx_ckm = conn->crypto.key_update.new_rx_ckm;
- new_tx_ckm = conn->crypto.key_update.new_tx_ckm;
- rv = conn_call_update_key(
- conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base, &rx_aead_ctx,
- new_rx_ckm->iv.base, &tx_aead_ctx, new_tx_ckm->iv.base, rx_ckm->secret.base,
- tx_ckm->secret.base, secretlen);
- if (rv != 0) {
- return rv;
- }
- new_rx_ckm->aead_ctx = rx_aead_ctx;
- new_tx_ckm->aead_ctx = tx_aead_ctx;
- if (!(rx_ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE)) {
- new_rx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE;
- new_tx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE;
- }
- if (conn->crypto.key_update.old_rx_ckm) {
- conn_call_delete_crypto_aead_ctx(
- conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx);
- ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem);
- conn->crypto.key_update.old_rx_ckm = NULL;
- }
- return 0;
- }
- /*
- * conn_rotate_keys rotates keys. The current key moves to old key,
- * and new key moves to the current key. If the local endpoint
- * initiated this key update, pass nonzero as |initiator|.
- */
- static void conn_rotate_keys(ngtcp2_conn *conn, int64_t pkt_num,
- int initiator) {
- ngtcp2_pktns *pktns = &conn->pktns;
- assert(conn->crypto.key_update.new_rx_ckm);
- assert(conn->crypto.key_update.new_tx_ckm);
- assert(!conn->crypto.key_update.old_rx_ckm);
- assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING));
- conn->crypto.key_update.old_rx_ckm = pktns->crypto.rx.ckm;
- pktns->crypto.rx.ckm = conn->crypto.key_update.new_rx_ckm;
- conn->crypto.key_update.new_rx_ckm = NULL;
- pktns->crypto.rx.ckm->pkt_num = pkt_num;
- assert(pktns->crypto.tx.ckm);
- conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx);
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
- pktns->crypto.tx.ckm = conn->crypto.key_update.new_tx_ckm;
- conn->crypto.key_update.new_tx_ckm = NULL;
- pktns->crypto.tx.ckm->pkt_num = pktns->tx.last_pkt_num + 1;
- conn->flags |= NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED;
- if (initiator) {
- conn->flags |= NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR;
- }
- }
- /*
- * conn_path_validation_in_progress returns nonzero if path validation
- * against |path| is underway.
- */
- static int conn_path_validation_in_progress(ngtcp2_conn *conn,
- const ngtcp2_path *path) {
- ngtcp2_pv *pv = conn->pv;
- return pv && ngtcp2_path_eq(&pv->dcid.ps.path, path);
- }
- /*
- * conn_recv_non_probing_pkt_on_new_path is called when non-probing
- * packet is received via new path. It starts path validation against
- * the new path.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CONN_ID_BLOCKED
- * No DCID is available
- * NGTCP2_ERR_NOMEM
- * Out of memory
- */
- static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
- const ngtcp2_path *path,
- size_t dgramlen,
- int new_cid_used,
- ngtcp2_tstamp ts) {
- ngtcp2_dcid dcid, *bound_dcid, *last;
- ngtcp2_pv *pv;
- int rv;
- ngtcp2_duration pto;
- int require_new_cid;
- int local_addr_eq;
- uint32_t remote_addr_cmp;
- size_t len, i;
- assert(conn->server);
- if (conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- ngtcp2_path_eq(&conn->pv->fallback_dcid.ps.path, path)) {
- /* If new path equals fallback path, that means connection
- migrated back to the original path. Fallback path is
- considered to be validated. */
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PTV,
- "path is migrated back to the original path");
- ngtcp2_dcid_copy(&conn->dcid.current, &conn->pv->fallback_dcid);
- conn_reset_congestion_state(conn, ts);
- conn->dcid.current.bytes_recv += dgramlen;
- conn_reset_ecn_validation_state(conn);
- rv = conn_abort_pv(conn, ts);
- if (rv != 0) {
- return rv;
- }
- /* Run PMTUD just in case if it is prematurely aborted */
- assert(!conn->pmtud);
- return conn_start_pmtud(conn);
- }
- remote_addr_cmp =
- ngtcp2_addr_compare(&conn->dcid.current.ps.path.remote, &path->remote);
- local_addr_eq =
- ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local);
- /*
- * When to change DCID? RFC 9002 section 9.5 says:
- *
- * An endpoint MUST NOT reuse a connection ID when sending from more
- * than one local address -- for example, when initiating connection
- * migration as described in Section 9.2 or when probing a new
- * network path as described in Section 9.1.
- *
- * Similarly, an endpoint MUST NOT reuse a connection ID when
- * sending to more than one destination address. Due to network
- * changes outside the control of its peer, an endpoint might
- * receive packets from a new source address with the same
- * Destination Connection ID field value, in which case it MAY
- * continue to use the current connection ID with the new remote
- * address while still sending from the same local address.
- */
- require_new_cid = conn->dcid.current.cid.datalen &&
- ((new_cid_used && remote_addr_cmp) || !local_addr_eq);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "non-probing packet was received from new remote address");
- len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb);
- for (i = 0; i < len; ++i) {
- bound_dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, i);
- if (ngtcp2_path_eq(&bound_dcid->ps.path, path)) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_CON,
- "Found DCID which has already been bound to the new path");
- ngtcp2_dcid_copy(&dcid, bound_dcid);
- if (i == 0) {
- ngtcp2_ringbuf_pop_front(&conn->dcid.bound.rb);
- } else if (i == ngtcp2_ringbuf_len(&conn->dcid.bound.rb) - 1) {
- ngtcp2_ringbuf_pop_back(&conn->dcid.bound.rb);
- } else {
- last = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, len - 1);
- ngtcp2_dcid_copy(bound_dcid, last);
- ngtcp2_ringbuf_pop_back(&conn->dcid.bound.rb);
- }
- require_new_cid = 0;
- if (dcid.cid.datalen) {
- rv = conn_call_activate_dcid(conn, &dcid);
- if (rv != 0) {
- return rv;
- }
- }
- break;
- }
- }
- if (i == len) {
- if (require_new_cid) {
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb) == 0) {
- return NGTCP2_ERR_CONN_ID_BLOCKED;
- }
- ngtcp2_dcid_copy(&dcid, ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0));
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- rv = conn_call_activate_dcid(conn, &dcid);
- if (rv != 0) {
- return rv;
- }
- } else {
- /* Use the current DCID if a remote endpoint does not change
- DCID. */
- ngtcp2_dcid_copy(&dcid, &conn->dcid.current);
- dcid.bytes_sent = 0;
- dcid.bytes_recv = 0;
- dcid.flags &= (uint8_t)~NGTCP2_DCID_FLAG_PATH_VALIDATED;
- }
- ngtcp2_dcid_set_path(&dcid, path);
- }
- dcid.bytes_recv += dgramlen;
- pto = conn_compute_pto(conn, &conn->pktns);
- rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout_pto(conn, pto),
- NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, &conn->log, conn->mem);
- if (rv != 0) {
- return rv;
- }
- if (conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE)) {
- ngtcp2_dcid_copy(&pv->fallback_dcid, &conn->pv->fallback_dcid);
- pv->fallback_pto = conn->pv->fallback_pto;
- /* Unset the flag bit so that conn_stop_pv does not retire
- DCID. */
- conn->pv->flags &= (uint8_t)~NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE;
- } else {
- ngtcp2_dcid_copy(&pv->fallback_dcid, &conn->dcid.current);
- pv->fallback_pto = pto;
- }
- ngtcp2_dcid_copy(&conn->dcid.current, &dcid);
- if (!local_addr_eq || (remote_addr_cmp & (NGTCP2_ADDR_COMPARE_FLAG_ADDR |
- NGTCP2_ADDR_COMPARE_FLAG_FAMILY))) {
- conn_reset_congestion_state(conn, ts);
- }
- conn_reset_ecn_validation_state(conn);
- ngtcp2_conn_stop_pmtud(conn);
- if (conn->pv) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_PTV,
- "path migration is aborted because new migration has started");
- rv = conn_abort_pv(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- conn->pv = pv;
- return 0;
- }
- /*
- * conn_recv_pkt_from_new_path is called when a 1RTT packet is
- * received from new path (not current path). This packet would be a
- * packet which only contains probing frame, or reordered packet, or a
- * path is being validated.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CONN_ID_BLOCKED
- * No unused DCID is available
- * NGTCP2_ERR_NOMEM
- * Out of memory
- */
- static int conn_recv_pkt_from_new_path(ngtcp2_conn *conn,
- const ngtcp2_path *path, size_t dgramlen,
- int path_challenge_recved,
- ngtcp2_tstamp ts) {
- ngtcp2_pv *pv = conn->pv;
- ngtcp2_dcid *bound_dcid;
- int rv;
- if (pv) {
- if (ngtcp2_path_eq(&pv->dcid.ps.path, path)) {
- pv->dcid.bytes_recv += dgramlen;
- return 0;
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- ngtcp2_path_eq(&pv->fallback_dcid.ps.path, path)) {
- pv->fallback_dcid.bytes_recv += dgramlen;
- return 0;
- }
- }
- if (!path_challenge_recved) {
- return 0;
- }
- rv = conn_bind_dcid(conn, &bound_dcid, path, ts);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_dcid_set_path(bound_dcid, path);
- bound_dcid->bytes_recv += dgramlen;
- return 0;
- }
- /*
- * conn_recv_delayed_handshake_pkt processes the received Handshake
- * packet which is received after handshake completed. This function
- * does the minimal job, and its purpose is send acknowledgement of
- * this packet to the peer. We assume that hd->type ==
- * NGTCP2_PKT_HANDSHAKE.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_FRAME_ENCODING
- * Frame is badly formatted; or frame type is unknown.
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_DISCARD_PKT
- * Packet was discarded.
- * NGTCP2_ERR_ACK_FRAME
- * ACK frame is malformed.
- * NGTCP2_ERR_PROTO
- * Frame that is not allowed in Handshake packet is received.
- */
- static int
- conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
- const ngtcp2_pkt_hd *hd, size_t pktlen,
- const uint8_t *payload, size_t payloadlen,
- ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) {
- ngtcp2_ssize nread;
- ngtcp2_max_frame mfr;
- ngtcp2_frame *fr = &mfr.fr;
- int rv;
- int require_ack = 0;
- ngtcp2_pktns *pktns;
- size_t num_ack_processed = 0;
- assert(hd->type == NGTCP2_PKT_HANDSHAKE);
- pktns = conn->hs_pktns;
- if (payloadlen == 0) {
- /* QUIC packet must contain at least one frame */
- return NGTCP2_ERR_PROTO;
- }
- ngtcp2_qlog_pkt_received_start(&conn->qlog);
- for (; payloadlen;) {
- nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
- if (nread < 0) {
- return (int)nread;
- }
- payload += nread;
- payloadlen -= (size_t)nread;
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- fr->ack.ack_delay = 0;
- fr->ack.ack_delay_unscaled = 0;
- rv =
- ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
- if (rv != 0) {
- return rv;
- }
- break;
- }
- ngtcp2_log_rx_fr(&conn->log, hd, fr);
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
- break;
- }
- if (!conn->server) {
- conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
- }
- rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
- if (rv != 0) {
- return rv;
- }
- ++num_ack_processed;
- break;
- case NGTCP2_FRAME_PADDING:
- break;
- case NGTCP2_FRAME_CONNECTION_CLOSE:
- rv = conn_recv_connection_close(conn, &fr->connection_close);
- if (rv != 0) {
- return rv;
- }
- break;
- case NGTCP2_FRAME_CRYPTO:
- case NGTCP2_FRAME_PING:
- require_ack = 1;
- break;
- default:
- return NGTCP2_ERR_PROTO;
- }
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
- }
- ngtcp2_qlog_pkt_received_end(&conn->qlog, hd, pktlen);
- rv = pktns_commit_recv_pkt_num(pktns, hd->pkt_num, require_ack, pkt_ts);
- if (rv != 0) {
- return rv;
- }
- pktns_increase_ecn_counts(pktns, pi);
- /* Initial and Handshake are always acknowledged without delay. No
- need to call ngtcp2_acktr_immediate_ack(). */
- rv = ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd->pkt_num, require_ack,
- pkt_ts);
- if (rv != 0) {
- return rv;
- }
- conn_restart_timer_on_read(conn, ts);
- ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
- return 0;
- }
- /*
- * conn_allow_path_change_under_disable_active_migration returns
- * nonzero if a packet from |path| is acceptable under
- * disable_active_migration is on.
- */
- static int
- conn_allow_path_change_under_disable_active_migration(ngtcp2_conn *conn,
- const ngtcp2_path *path) {
- uint32_t remote_addr_cmp;
- const ngtcp2_preferred_addr *paddr;
- ngtcp2_addr addr;
- assert(conn->server);
- assert(conn->local.transport_params.disable_active_migration);
- /* If local address does not change, it must be passive migration
- (NAT rebinding). */
- if (ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local)) {
- remote_addr_cmp =
- ngtcp2_addr_compare(&conn->dcid.current.ps.path.remote, &path->remote);
- return (remote_addr_cmp | NGTCP2_ADDR_COMPARE_FLAG_PORT) ==
- NGTCP2_ADDR_COMPARE_FLAG_PORT;
- }
- /* If local address changes, it must be one of the preferred
- addresses. */
- if (!conn->local.transport_params.preferred_addr_present) {
- return 0;
- }
- paddr = &conn->local.transport_params.preferred_addr;
- if (paddr->ipv4_present) {
- ngtcp2_addr_init(&addr, (const ngtcp2_sockaddr *)&paddr->ipv4,
- sizeof(paddr->ipv4));
- if (ngtcp2_addr_eq(&addr, &path->local)) {
- return 1;
- }
- }
- if (paddr->ipv6_present) {
- ngtcp2_addr_init(&addr, (const ngtcp2_sockaddr *)&paddr->ipv6,
- sizeof(paddr->ipv6));
- if (ngtcp2_addr_eq(&addr, &path->local)) {
- return 1;
- }
- }
- return 0;
- }
- /*
- * conn_recv_pkt processes a packet contained in the buffer pointed by
- * |pkt| of length |pktlen|. |pkt| may contain multiple QUIC packets.
- * This function only processes the first packet. |pkt_ts| is the
- * timestamp when packet is received. |ts| should be the current
- * time. Usually they are the same, but for buffered packets,
- * |pkt_ts| would be earlier than |ts|.
- *
- * This function returns the number of bytes processed if it succeeds,
- * or one of the following negative error codes:
- *
- * NGTCP2_ERR_DISCARD_PKT
- * Packet was discarded because plain text header was malformed;
- * or its payload could not be decrypted.
- * NGTCP2_ERR_PROTO
- * Packet is badly formatted; or 0RTT packet contains other than
- * PADDING or STREAM frames; or other QUIC protocol violation is
- * found.
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User-defined callback function failed.
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- * NGTCP2_ERR_FRAME_ENCODING
- * Frame is badly formatted; or frame type is unknown.
- * NGTCP2_ERR_ACK_FRAME
- * ACK frame is malformed.
- * NGTCP2_ERR_STREAM_STATE
- * Frame is received to the local stream which is not initiated.
- * NGTCP2_ERR_STREAM_LIMIT
- * Frame has remote stream ID which is strictly greater than the
- * allowed limit.
- * NGTCP2_ERR_FLOW_CONTROL
- * Flow control limit is violated.
- * NGTCP2_ERR_FINAL_SIZE
- * Frame has strictly larger end offset than it is permitted.
- */
- static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
- const ngtcp2_pkt_info *pi, const uint8_t *pkt,
- size_t pktlen, size_t dgramlen,
- ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) {
- ngtcp2_pkt_hd hd;
- int rv = 0;
- size_t hdpktlen;
- const uint8_t *payload;
- size_t payloadlen;
- ngtcp2_ssize nread, nwrite;
- ngtcp2_max_frame mfr;
- ngtcp2_frame *fr = &mfr.fr;
- int require_ack = 0;
- ngtcp2_crypto_aead *aead;
- ngtcp2_crypto_cipher *hp;
- ngtcp2_crypto_km *ckm;
- ngtcp2_crypto_cipher_ctx *hp_ctx;
- ngtcp2_hp_mask hp_mask;
- ngtcp2_decrypt decrypt;
- ngtcp2_pktns *pktns;
- int non_probing_pkt = 0;
- int key_phase_bit_changed = 0;
- int force_decrypt_failure = 0;
- int recv_ncid = 0;
- int new_cid_used = 0;
- int path_challenge_recved = 0;
- size_t num_ack_processed = 0;
- if (conn->server && conn->local.transport_params.disable_active_migration &&
- !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) &&
- !conn_allow_path_change_under_disable_active_migration(conn, path)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet is discarded because active migration is disabled");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (pkt[0] & NGTCP2_HEADER_FORM_BIT) {
- nread = ngtcp2_pkt_decode_hd_long(&hd, pkt, pktlen);
- if (nread < 0) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decode long header");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (pktlen < (size_t)nread + hd.len) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- assert(conn->negotiated_version);
- if (hd.version != conn->client_chosen_version &&
- hd.version != conn->negotiated_version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn_verify_fixed_bit(conn, &hd) != 0) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- pktlen = (size_t)nread + hd.len;
- /* Quoted from spec: if subsequent packets of those types include
- a different Source Connection ID, they MUST be discarded. */
- if (!ngtcp2_cid_eq(&conn->dcid.current.cid, &hd.scid)) {
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched SCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- switch (hd.type) {
- case NGTCP2_PKT_INITIAL:
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "delayed Initial packet was discarded");
- return (ngtcp2_ssize)pktlen;
- case NGTCP2_PKT_HANDSHAKE:
- if (hd.version != conn->negotiated_version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (!conn->hs_pktns) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "delayed Handshake packet was discarded");
- return (ngtcp2_ssize)pktlen;
- }
- pktns = conn->hs_pktns;
- aead = &pktns->crypto.ctx.aead;
- hp = &pktns->crypto.ctx.hp;
- ckm = pktns->crypto.rx.ckm;
- hp_ctx = &pktns->crypto.rx.hp_ctx;
- hp_mask = conn->callbacks.hp_mask;
- decrypt = conn->callbacks.decrypt;
- break;
- case NGTCP2_PKT_0RTT:
- if (!conn->server || hd.version != conn->client_chosen_version) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (!conn->early.ckm) {
- return (ngtcp2_ssize)pktlen;
- }
- pktns = &conn->pktns;
- aead = &conn->early.ctx.aead;
- hp = &conn->early.ctx.hp;
- ckm = conn->early.ckm;
- hp_ctx = &conn->early.hp_ctx;
- hp_mask = conn->callbacks.hp_mask;
- decrypt = conn->callbacks.decrypt;
- break;
- default:
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet type 0x%02x was ignored", hd.type);
- return (ngtcp2_ssize)pktlen;
- }
- } else {
- nread = ngtcp2_pkt_decode_hd_short(&hd, pkt, pktlen, conn->oscid.datalen);
- if (nread < 0) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decode short header");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- if (conn_verify_fixed_bit(conn, &hd) != 0) {
- return NGTCP2_ERR_DISCARD_PKT;
- }
- pktns = &conn->pktns;
- aead = &pktns->crypto.ctx.aead;
- hp = &pktns->crypto.ctx.hp;
- ckm = pktns->crypto.rx.ckm;
- hp_ctx = &pktns->crypto.rx.hp_ctx;
- hp_mask = conn->callbacks.hp_mask;
- decrypt = conn->callbacks.decrypt;
- }
- rv = conn_ensure_decrypt_hp_buffer(conn, (size_t)nread + 4);
- if (rv != 0) {
- return rv;
- }
- nwrite = decrypt_hp(&hd, conn->crypto.decrypt_hp_buf.base, hp, pkt, pktlen,
- (size_t)nread, hp_ctx, hp_mask);
- if (nwrite < 0) {
- if (ngtcp2_err_is_fatal((int)nwrite)) {
- return nwrite;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decrypt packet number");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- hdpktlen = (size_t)nwrite;
- payload = pkt + hdpktlen;
- payloadlen = pktlen - hdpktlen;
- hd.pkt_num =
- ngtcp2_pkt_adjust_pkt_num(pktns->rx.max_pkt_num, hd.pkt_num, hd.pkt_numlen);
- if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
- return NGTCP2_ERR_DISCARD_PKT;
- }
- ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
- if (hd.type == NGTCP2_PKT_1RTT) {
- key_phase_bit_changed = conn_key_phase_changed(conn, &hd);
- }
- rv = conn_ensure_decrypt_buffer(conn, payloadlen);
- if (rv != 0) {
- return rv;
- }
- if (key_phase_bit_changed) {
- assert(hd.type == NGTCP2_PKT_1RTT);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "unexpected KEY_PHASE");
- if (ckm->pkt_num > hd.pkt_num) {
- if (conn->crypto.key_update.old_rx_ckm) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "decrypting with old key");
- ckm = conn->crypto.key_update.old_rx_ckm;
- } else {
- force_decrypt_failure = 1;
- }
- } else if (pktns->rx.max_pkt_num < hd.pkt_num) {
- assert(ckm->pkt_num < hd.pkt_num);
- if (!conn->crypto.key_update.new_rx_ckm) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "new key is not available");
- force_decrypt_failure = 1;
- } else {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "decrypting with new key");
- ckm = conn->crypto.key_update.new_rx_ckm;
- }
- } else {
- force_decrypt_failure = 1;
- }
- }
- nwrite = decrypt_pkt(conn->crypto.decrypt_buf.base, aead, payload, payloadlen,
- conn->crypto.decrypt_hp_buf.base, hdpktlen, hd.pkt_num,
- ckm, decrypt);
- if (force_decrypt_failure) {
- nwrite = NGTCP2_ERR_DECRYPT;
- }
- if (nwrite < 0) {
- if (ngtcp2_err_is_fatal((int)nwrite)) {
- return nwrite;
- }
- assert(NGTCP2_ERR_DECRYPT == nwrite);
- if (hd.type == NGTCP2_PKT_1RTT &&
- ++conn->crypto.decryption_failure_count >=
- pktns->crypto.ctx.max_decryption_failure) {
- return NGTCP2_ERR_AEAD_LIMIT_REACHED;
- }
- if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decrypt packet payload");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "could not decrypt packet payload");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- rv = ngtcp2_pkt_verify_reserved_bits(conn->crypto.decrypt_hp_buf.base[0]);
- if (rv != 0) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet has incorrect reserved bits");
- return NGTCP2_ERR_PROTO;
- }
- if (pktns_pkt_num_is_duplicate(pktns, hd.pkt_num)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was discarded because of duplicated packet number");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- payload = conn->crypto.decrypt_buf.base;
- payloadlen = (size_t)nwrite;
- if (payloadlen == 0) {
- /* QUIC packet must contain at least one frame */
- return NGTCP2_ERR_PROTO;
- }
- if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) {
- switch (hd.type) {
- case NGTCP2_PKT_HANDSHAKE:
- rv = conn_verify_dcid(conn, NULL, &hd);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched DCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- rv = conn_recv_delayed_handshake_pkt(conn, pi, &hd, pktlen, payload,
- payloadlen, pkt_ts, ts);
- if (rv < 0) {
- return (ngtcp2_ssize)rv;
- }
- return (ngtcp2_ssize)pktlen;
- case NGTCP2_PKT_0RTT:
- if (!ngtcp2_cid_eq(&conn->rcid, &hd.dcid)) {
- rv = conn_verify_dcid(conn, NULL, &hd);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched DCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- }
- break;
- default:
- /* Unreachable */
- ngtcp2_unreachable();
- }
- } else {
- rv = conn_verify_dcid(conn, &new_cid_used, &hd);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "packet was ignored because of mismatched DCID");
- return NGTCP2_ERR_DISCARD_PKT;
- }
- }
- ngtcp2_qlog_pkt_received_start(&conn->qlog);
- for (; payloadlen;) {
- nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
- if (nread < 0) {
- return nread;
- }
- payload += nread;
- payloadlen -= (size_t)nread;
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- if ((hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) &&
- hd.type == NGTCP2_PKT_0RTT) {
- return NGTCP2_ERR_PROTO;
- }
- assert(conn->remote.transport_params);
- assign_recved_ack_delay_unscaled(
- &fr->ack, conn->remote.transport_params->ack_delay_exponent);
- rv =
- ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
- if (rv != 0) {
- return rv;
- }
- break;
- }
- ngtcp2_log_rx_fr(&conn->log, &hd, fr);
- if (hd.type == NGTCP2_PKT_0RTT) {
- switch (fr->type) {
- case NGTCP2_FRAME_PADDING:
- case NGTCP2_FRAME_PING:
- case NGTCP2_FRAME_RESET_STREAM:
- case NGTCP2_FRAME_STOP_SENDING:
- case NGTCP2_FRAME_STREAM:
- case NGTCP2_FRAME_MAX_DATA:
- case NGTCP2_FRAME_MAX_STREAM_DATA:
- case NGTCP2_FRAME_MAX_STREAMS_BIDI:
- case NGTCP2_FRAME_MAX_STREAMS_UNI:
- case NGTCP2_FRAME_DATA_BLOCKED:
- case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
- case NGTCP2_FRAME_STREAMS_BLOCKED_BIDI:
- case NGTCP2_FRAME_STREAMS_BLOCKED_UNI:
- case NGTCP2_FRAME_NEW_CONNECTION_ID:
- case NGTCP2_FRAME_PATH_CHALLENGE:
- case NGTCP2_FRAME_CONNECTION_CLOSE:
- case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
- case NGTCP2_FRAME_DATAGRAM:
- case NGTCP2_FRAME_DATAGRAM_LEN:
- break;
- default:
- return NGTCP2_ERR_PROTO;
- }
- }
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- case NGTCP2_FRAME_PADDING:
- case NGTCP2_FRAME_CONNECTION_CLOSE:
- case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
- break;
- default:
- require_ack = 1;
- }
- switch (fr->type) {
- case NGTCP2_FRAME_ACK:
- case NGTCP2_FRAME_ACK_ECN:
- if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
- break;
- }
- if (!conn->server) {
- conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
- }
- rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- ++num_ack_processed;
- break;
- case NGTCP2_FRAME_STREAM:
- rv = conn_recv_stream(conn, &fr->stream);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_CRYPTO:
- rv = conn_recv_crypto(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT,
- &pktns->crypto.strm, &fr->stream);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_RESET_STREAM:
- rv = conn_recv_reset_stream(conn, &fr->reset_stream);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_STOP_SENDING:
- rv = conn_recv_stop_sending(conn, &fr->stop_sending);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_MAX_STREAM_DATA:
- rv = conn_recv_max_stream_data(conn, &fr->max_stream_data);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_MAX_DATA:
- conn_recv_max_data(conn, &fr->max_data);
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_MAX_STREAMS_BIDI:
- case NGTCP2_FRAME_MAX_STREAMS_UNI:
- rv = conn_recv_max_streams(conn, &fr->max_streams);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_CONNECTION_CLOSE:
- case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
- rv = conn_recv_connection_close(conn, &fr->connection_close);
- if (rv != 0) {
- return rv;
- }
- break;
- case NGTCP2_FRAME_PING:
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_PATH_CHALLENGE:
- conn_recv_path_challenge(conn, path, &fr->path_challenge);
- path_challenge_recved = 1;
- break;
- case NGTCP2_FRAME_PATH_RESPONSE:
- rv = conn_recv_path_response(conn, &fr->path_response, ts);
- if (rv != 0) {
- return rv;
- }
- break;
- case NGTCP2_FRAME_NEW_CONNECTION_ID:
- rv = conn_recv_new_connection_id(conn, &fr->new_connection_id);
- if (rv != 0) {
- return rv;
- }
- recv_ncid = 1;
- break;
- case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
- rv = conn_recv_retire_connection_id(conn, &hd, &fr->retire_connection_id,
- ts);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_NEW_TOKEN:
- rv = conn_recv_new_token(conn, &fr->new_token);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_HANDSHAKE_DONE:
- rv = conn_recv_handshake_done(conn, ts);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_STREAMS_BLOCKED_BIDI:
- rv = conn_recv_streams_blocked_bidi(conn, &fr->streams_blocked);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_STREAMS_BLOCKED_UNI:
- rv = conn_recv_streams_blocked_uni(conn, &fr->streams_blocked);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
- rv = conn_recv_stream_data_blocked(conn, &fr->stream_data_blocked);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_DATA_BLOCKED:
- rv = conn_recv_data_blocked(conn, &fr->data_blocked);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- case NGTCP2_FRAME_DATAGRAM:
- case NGTCP2_FRAME_DATAGRAM_LEN:
- if ((uint64_t)nread >
- conn->local.transport_params.max_datagram_frame_size) {
- return NGTCP2_ERR_PROTO;
- }
- rv = conn_recv_datagram(conn, &fr->datagram);
- if (rv != 0) {
- return rv;
- }
- non_probing_pkt = 1;
- break;
- }
- ngtcp2_qlog_write_frame(&conn->qlog, fr);
- }
- ngtcp2_qlog_pkt_received_end(&conn->qlog, &hd, pktlen);
- if (recv_ncid) {
- rv = conn_post_process_recv_new_connection_id(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- if (conn->server && hd.type == NGTCP2_PKT_1RTT &&
- !ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- if (non_probing_pkt && pktns->rx.max_pkt_num < hd.pkt_num &&
- !conn_path_validation_in_progress(conn, path)) {
- rv = conn_recv_non_probing_pkt_on_new_path(conn, path, dgramlen,
- new_cid_used, ts);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- /* DCID is not available. Just continue. */
- assert(NGTCP2_ERR_CONN_ID_BLOCKED == rv);
- }
- } else {
- rv = conn_recv_pkt_from_new_path(conn, path, dgramlen,
- path_challenge_recved, ts);
- if (rv != 0) {
- if (ngtcp2_err_is_fatal(rv)) {
- return rv;
- }
- /* DCID is not available. Just continue. */
- assert(NGTCP2_ERR_CONN_ID_BLOCKED == rv);
- }
- }
- }
- if (hd.type == NGTCP2_PKT_1RTT) {
- if (ckm == conn->crypto.key_update.new_rx_ckm) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "rotate keys");
- conn_rotate_keys(conn, hd.pkt_num, /* initiator = */ 0);
- } else if (ckm->pkt_num > hd.pkt_num) {
- ckm->pkt_num = hd.pkt_num;
- }
- if (conn->server && conn->early.ckm &&
- conn->early.discard_started_ts == UINT64_MAX) {
- conn->early.discard_started_ts = ts;
- }
- if (ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- conn_update_keep_alive_last_ts(conn, ts);
- }
- }
- rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num, require_ack, pkt_ts);
- if (rv != 0) {
- return rv;
- }
- pktns_increase_ecn_counts(pktns, pi);
- if (require_ack &&
- (++pktns->acktr.rx_npkt >= conn->local.settings.ack_thresh ||
- (pi->ecn & NGTCP2_ECN_MASK) == NGTCP2_ECN_CE)) {
- ngtcp2_acktr_immediate_ack(&pktns->acktr);
- }
- rv =
- ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd.pkt_num, require_ack, pkt_ts);
- if (rv != 0) {
- return rv;
- }
- conn_restart_timer_on_read(conn, ts);
- ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
- return conn->state == NGTCP2_CS_DRAINING ? NGTCP2_ERR_DRAINING
- : (ngtcp2_ssize)pktlen;
- }
- /*
- * conn_process_buffered_protected_pkt processes buffered 0RTT or 1RTT
- * packets.
- *
- * This function returns 0 if it succeeds, or the same negative error
- * codes from conn_recv_pkt.
- */
- static int conn_process_buffered_protected_pkt(ngtcp2_conn *conn,
- ngtcp2_pktns *pktns,
- ngtcp2_tstamp ts) {
- ngtcp2_ssize nread;
- ngtcp2_pkt_chain **ppc, *next;
- int rv;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "processing buffered protected packet");
- for (ppc = &pktns->rx.buffed_pkts; *ppc;) {
- next = (*ppc)->next;
- nread = conn_recv_pkt(conn, &(*ppc)->path.path, &(*ppc)->pi, (*ppc)->pkt,
- (*ppc)->pktlen, (*ppc)->dgramlen, (*ppc)->ts, ts);
- if (nread < 0 && !ngtcp2_err_is_fatal((int)nread) &&
- nread != NGTCP2_ERR_DRAINING) {
- /* TODO We don't know this is the first QUIC packet in a
- datagram. */
- rv = conn_on_stateless_reset(conn, &(*ppc)->path.path, (*ppc)->pkt,
- (*ppc)->pktlen);
- if (rv == 0) {
- ngtcp2_pkt_chain_del(*ppc, conn->mem);
- *ppc = next;
- return NGTCP2_ERR_DRAINING;
- }
- }
- ngtcp2_pkt_chain_del(*ppc, conn->mem);
- *ppc = next;
- if (nread < 0) {
- if (nread == NGTCP2_ERR_DISCARD_PKT) {
- continue;
- }
- return (int)nread;
- }
- }
- return 0;
- }
- /*
- * conn_process_buffered_handshake_pkt processes buffered Handshake
- * packets.
- *
- * This function returns 0 if it succeeds, or the same negative error
- * codes from conn_recv_handshake_pkt.
- */
- static int conn_process_buffered_handshake_pkt(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- ngtcp2_pktns *pktns = conn->hs_pktns;
- ngtcp2_ssize nread;
- ngtcp2_pkt_chain **ppc, *next;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "processing buffered handshake packet");
- for (ppc = &pktns->rx.buffed_pkts; *ppc;) {
- next = (*ppc)->next;
- nread = conn_recv_handshake_pkt(conn, &(*ppc)->path.path, &(*ppc)->pi,
- (*ppc)->pkt, (*ppc)->pktlen,
- (*ppc)->dgramlen, (*ppc)->ts, ts);
- ngtcp2_pkt_chain_del(*ppc, conn->mem);
- *ppc = next;
- if (nread < 0) {
- if (nread == NGTCP2_ERR_DISCARD_PKT) {
- continue;
- }
- return (int)nread;
- }
- }
- return 0;
- }
- static void conn_sync_stream_id_limit(ngtcp2_conn *conn) {
- ngtcp2_transport_params *params = conn->remote.transport_params;
- assert(params);
- conn->local.bidi.max_streams = params->initial_max_streams_bidi;
- conn->local.uni.max_streams = params->initial_max_streams_uni;
- }
- static int strm_set_max_offset(void *data, void *ptr) {
- ngtcp2_conn *conn = ptr;
- ngtcp2_transport_params *params = conn->remote.transport_params;
- ngtcp2_strm *strm = data;
- uint64_t max_offset;
- int rv;
- assert(params);
- if (!conn_local_stream(conn, strm->stream_id)) {
- return 0;
- }
- if (bidi_stream(strm->stream_id)) {
- max_offset = params->initial_max_stream_data_bidi_remote;
- } else {
- max_offset = params->initial_max_stream_data_uni;
- }
- if (strm->tx.max_offset < max_offset) {
- strm->tx.max_offset = max_offset;
- /* Don't call callback if stream is half-closed local */
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
- return 0;
- }
- rv = conn_call_extend_max_stream_data(conn, strm, strm->stream_id,
- strm->tx.max_offset);
- if (rv != 0) {
- return rv;
- }
- }
- return 0;
- }
- static int conn_sync_stream_data_limit(ngtcp2_conn *conn) {
- return ngtcp2_map_each(&conn->strms, strm_set_max_offset, conn);
- }
- /*
- * conn_handshake_completed is called once cryptographic handshake has
- * completed.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_CALLBACK_FAILURE
- * User callback failed.
- */
- static int conn_handshake_completed(ngtcp2_conn *conn) {
- int rv;
- conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED;
- rv = conn_call_handshake_completed(conn);
- if (rv != 0) {
- return rv;
- }
- if (conn->local.bidi.max_streams > 0) {
- rv = conn_call_extend_max_local_streams_bidi(conn,
- conn->local.bidi.max_streams);
- if (rv != 0) {
- return rv;
- }
- }
- if (conn->local.uni.max_streams > 0) {
- rv =
- conn_call_extend_max_local_streams_uni(conn, conn->local.uni.max_streams);
- if (rv != 0) {
- return rv;
- }
- }
- return 0;
- }
- /*
- * conn_recv_cpkt processes compound packet after handshake. The
- * buffer pointed by |pkt| might contain multiple packets. The 1RTT
- * packet must be the last one because it does not have payload length
- * field.
- *
- * This function returns 0 if it succeeds, or the same negative error
- * codes from conn_recv_pkt except for NGTCP2_ERR_DISCARD_PKT.
- */
- static int conn_recv_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path,
- const ngtcp2_pkt_info *pi, const uint8_t *pkt,
- size_t pktlen, ngtcp2_tstamp ts) {
- ngtcp2_ssize nread;
- int rv;
- const uint8_t *origpkt = pkt;
- size_t dgramlen = pktlen;
- if (ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- conn->dcid.current.bytes_recv += dgramlen;
- }
- while (pktlen) {
- nread = conn_recv_pkt(conn, path, pi, pkt, pktlen, dgramlen, ts, ts);
- if (nread < 0) {
- if (ngtcp2_err_is_fatal((int)nread)) {
- return (int)nread;
- }
- if (nread == NGTCP2_ERR_DRAINING) {
- return NGTCP2_ERR_DRAINING;
- }
- if (origpkt == pkt) {
- rv = conn_on_stateless_reset(conn, path, origpkt, dgramlen);
- if (rv == 0) {
- return NGTCP2_ERR_DRAINING;
- }
- }
- if (nread == NGTCP2_ERR_DISCARD_PKT) {
- return 0;
- }
- return (int)nread;
- }
- assert(pktlen >= (size_t)nread);
- pkt += nread;
- pktlen -= (size_t)nread;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
- "read packet %td left %zu", nread, pktlen);
- }
- return 0;
- }
- /*
- * conn_is_retired_path returns nonzero if |path| is included in
- * retired path list.
- */
- static int conn_is_retired_path(ngtcp2_conn *conn, const ngtcp2_path *path) {
- size_t i, len = ngtcp2_ringbuf_len(&conn->dcid.retired.rb);
- ngtcp2_dcid *dcid;
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.retired.rb, i);
- if (ngtcp2_path_eq(&dcid->ps.path, path)) {
- return 1;
- }
- }
- return 0;
- }
- /*
- * conn_enqueue_handshake_done enqueues HANDSHAKE_DONE frame for
- * transmission.
- */
- static int conn_enqueue_handshake_done(ngtcp2_conn *conn) {
- ngtcp2_pktns *pktns = &conn->pktns;
- ngtcp2_frame_chain *nfrc;
- int rv;
- assert(conn->server);
- rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- nfrc->fr.type = NGTCP2_FRAME_HANDSHAKE_DONE;
- nfrc->next = pktns->tx.frq;
- pktns->tx.frq = nfrc;
- return 0;
- }
- /**
- * @function
- *
- * `conn_read_handshake` performs QUIC cryptographic handshake by
- * reading given data. |pkt| points to the buffer to read and
- * |pktlen| is the length of the buffer. |path| is the network path.
- *
- * This function returns the number of bytes processed. Unless the
- * last packet is 1RTT packet and an application decryption key has
- * been installed, it returns |pktlen| if it succeeds. If it finds
- * 1RTT packet and an application decryption key has been installed,
- * it returns the number of bytes just before 1RTT packet begins.
- *
- * This function returns the number of bytes processed if it succeeds,
- * or one of the following negative error codes: (TBD).
- */
- static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn,
- const ngtcp2_path *path,
- const ngtcp2_pkt_info *pi,
- const uint8_t *pkt, size_t pktlen,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_ssize nread;
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- /* TODO Better to log something when we ignore input */
- return (ngtcp2_ssize)pktlen;
- case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE:
- nread = conn_recv_handshake_cpkt(conn, path, pi, pkt, pktlen, ts);
- if (nread < 0) {
- return nread;
- }
- if (conn->state == NGTCP2_CS_CLIENT_INITIAL) {
- /* Retry packet was received */
- return (ngtcp2_ssize)pktlen;
- }
- assert(conn->hs_pktns);
- if (conn->hs_pktns->crypto.rx.ckm && conn->in_pktns) {
- rv = conn_process_buffered_handshake_pkt(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- if (conn_is_tls_handshake_completed(conn) &&
- !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
- rv = conn_handshake_completed(conn);
- if (rv != 0) {
- return rv;
- }
- rv = conn_process_buffered_protected_pkt(conn, &conn->pktns, ts);
- if (rv != 0) {
- return rv;
- }
- }
- return nread;
- case NGTCP2_CS_SERVER_INITIAL:
- nread = conn_recv_handshake_cpkt(conn, path, pi, pkt, pktlen, ts);
- if (nread < 0) {
- return nread;
- }
- /*
- * Client Hello might not fit into single Initial packet (e.g.,
- * resuming session with client authentication). If we get Client
- * Initial which does not increase offset or it is 0RTT packet
- * buffered, perform address validation in order to buffer
- * validated data only.
- */
- if (ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm) == 0) {
- if (conn->in_pktns->crypto.strm.rx.rob &&
- ngtcp2_rob_data_buffered(conn->in_pktns->crypto.strm.rx.rob)) {
- /* Address has been validated with token */
- if (conn->local.settings.tokenlen) {
- return nread;
- }
- return NGTCP2_ERR_RETRY;
- }
- /* If CRYPTO frame is not processed, just drop connection. */
- return NGTCP2_ERR_DROP_CONN;
- }
- /* Process re-ordered 0-RTT packets which arrived before Initial
- packet. */
- if (conn->early.ckm) {
- assert(conn->in_pktns);
- rv = conn_process_buffered_protected_pkt(conn, conn->in_pktns, ts);
- if (rv != 0) {
- return rv;
- }
- }
- return nread;
- case NGTCP2_CS_SERVER_WAIT_HANDSHAKE:
- nread = conn_recv_handshake_cpkt(conn, path, pi, pkt, pktlen, ts);
- if (nread < 0) {
- return nread;
- }
- if (conn->hs_pktns->crypto.rx.ckm) {
- rv = conn_process_buffered_handshake_pkt(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- if (conn->hs_pktns->rx.max_pkt_num != -1) {
- ngtcp2_conn_discard_initial_state(conn, ts);
- }
- if (!conn_is_tls_handshake_completed(conn)) {
- /* If server hits amplification limit, it cancels loss detection
- timer. If server receives a packet from client, the limit is
- increased and server can send more. If server has
- ack-eliciting Initial or Handshake packets, it should resend
- it if timer fired but timer is not armed in this case. So
- instead of resending Initial/Handshake packets, if server has
- 1RTT data to send, it might send them and then might hit
- amplification limit again until it hits stream data limit.
- Initial/Handshake data is not resent. In order to avoid this
- situation, try to arm loss detection and check the expiry
- here so that on next write call, we can resend
- Initial/Handshake first. */
- if (conn->cstat.loss_detection_timer == UINT64_MAX) {
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- if (ngtcp2_conn_loss_detection_expiry(conn) <= ts) {
- rv = ngtcp2_conn_on_loss_detection_timer(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- }
- if ((size_t)nread < pktlen) {
- /* We have 1RTT packet and application rx key, but the
- handshake has not completed yet. */
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "buffering 1RTT packet len=%zu",
- pktlen - (size_t)nread);
- rv = conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt + nread,
- pktlen - (size_t)nread, pktlen, ts);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- return rv;
- }
- return (ngtcp2_ssize)pktlen;
- }
- return nread;
- }
- if (!(conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED)) {
- return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
- }
- rv = conn_handshake_completed(conn);
- if (rv != 0) {
- return rv;
- }
- conn->state = NGTCP2_CS_POST_HANDSHAKE;
- rv = conn_call_activate_dcid(conn, &conn->dcid.current);
- if (rv != 0) {
- return rv;
- }
- rv = conn_process_buffered_protected_pkt(conn, &conn->pktns, ts);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_conn_discard_handshake_state(conn, ts);
- rv = conn_enqueue_handshake_done(conn);
- if (rv != 0) {
- return rv;
- }
- if (!conn->local.settings.no_pmtud) {
- rv = conn_start_pmtud(conn);
- if (rv != 0) {
- return rv;
- }
- }
- conn->pktns.rtb.persistent_congestion_start_ts = ts;
- /* Re-arm loss detection timer here after handshake has been
- confirmed. */
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- return nread;
- case NGTCP2_CS_CLOSING:
- return NGTCP2_ERR_CLOSING;
- case NGTCP2_CS_DRAINING:
- return NGTCP2_ERR_DRAINING;
- default:
- return (ngtcp2_ssize)pktlen;
- }
- }
- int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path,
- int pkt_info_version,
- const ngtcp2_pkt_info *pi,
- const uint8_t *pkt, size_t pktlen,
- ngtcp2_tstamp ts) {
- int rv = 0;
- ngtcp2_ssize nread = 0;
- const ngtcp2_pkt_info zero_pi = {0};
- (void)pkt_info_version;
- assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING));
- conn_update_timestamp(conn, ts);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu",
- pktlen);
- if (pktlen == 0) {
- return 0;
- }
- /* client does not expect a packet from unknown path. */
- if (!conn->server && !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) &&
- (!conn->pv || !ngtcp2_path_eq(&conn->pv->dcid.ps.path, path)) &&
- !conn_is_retired_path(conn, path)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "ignore packet from unknown path");
- return 0;
- }
- if (!pi) {
- pi = &zero_pi;
- }
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE:
- nread = conn_read_handshake(conn, path, pi, pkt, pktlen, ts);
- if (nread < 0) {
- return (int)nread;
- }
- if ((size_t)nread == pktlen) {
- return 0;
- }
- assert(conn->pktns.crypto.rx.ckm);
- pkt += nread;
- pktlen -= (size_t)nread;
- break;
- case NGTCP2_CS_SERVER_INITIAL:
- case NGTCP2_CS_SERVER_WAIT_HANDSHAKE:
- if (!ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "ignore packet from unknown path during handshake");
- if (conn->state == NGTCP2_CS_SERVER_INITIAL &&
- ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm) == 0 &&
- (!conn->in_pktns->crypto.strm.rx.rob ||
- !ngtcp2_rob_data_buffered(conn->in_pktns->crypto.strm.rx.rob))) {
- return NGTCP2_ERR_DROP_CONN;
- }
- return 0;
- }
- nread = conn_read_handshake(conn, path, pi, pkt, pktlen, ts);
- if (nread < 0) {
- return (int)nread;
- }
- if ((size_t)nread == pktlen) {
- return 0;
- }
- assert(conn->pktns.crypto.rx.ckm);
- pkt += nread;
- pktlen -= (size_t)nread;
- break;
- case NGTCP2_CS_CLOSING:
- return NGTCP2_ERR_CLOSING;
- case NGTCP2_CS_DRAINING:
- return NGTCP2_ERR_DRAINING;
- case NGTCP2_CS_POST_HANDSHAKE:
- rv = conn_prepare_key_update(conn, ts);
- if (rv != 0) {
- return rv;
- }
- break;
- default:
- ngtcp2_unreachable();
- }
- return conn_recv_cpkt(conn, path, pi, pkt, pktlen, ts);
- }
- /*
- * conn_check_pkt_num_exhausted returns nonzero if packet number is
- * exhausted in at least one of packet number space.
- */
- static int conn_check_pkt_num_exhausted(ngtcp2_conn *conn) {
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- return (in_pktns && in_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) ||
- (hs_pktns && hs_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) ||
- conn->pktns.tx.last_pkt_num == NGTCP2_MAX_PKT_NUM;
- }
- /*
- * conn_retransmit_retry_early retransmits 0RTT packet after Retry is
- * received from server.
- */
- static ngtcp2_ssize
- conn_retransmit_retry_early(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen, size_t dgram_offset,
- uint8_t flags, ngtcp2_tstamp ts) {
- return conn_write_pkt(conn, pi, dest, destlen, dgram_offset, NULL,
- NGTCP2_PKT_0RTT, flags, ts);
- }
- /*
- * conn_handshake_probe_left returns nonzero if there are probe
- * packets to be sent for Initial or Handshake packet number space
- * left.
- */
- static int conn_handshake_probe_left(ngtcp2_conn *conn) {
- return (conn->in_pktns && conn->in_pktns->rtb.probe_pkt_left) ||
- conn->hs_pktns->rtb.probe_pkt_left;
- }
- /*
- * conn_validate_early_transport_params_limits validates that the
- * limits in transport parameters remembered by client for early data
- * are not reduced. This function is only used by client and should
- * only be called when early data is accepted by server.
- */
- static int conn_validate_early_transport_params_limits(ngtcp2_conn *conn) {
- const ngtcp2_transport_params *params = conn->remote.transport_params;
- assert(!conn->server);
- assert(params);
- if (conn->early.transport_params.active_connection_id_limit >
- params->active_connection_id_limit ||
- conn->early.transport_params.initial_max_data >
- params->initial_max_data ||
- conn->early.transport_params.initial_max_stream_data_bidi_local >
- params->initial_max_stream_data_bidi_local ||
- conn->early.transport_params.initial_max_stream_data_bidi_remote >
- params->initial_max_stream_data_bidi_remote ||
- conn->early.transport_params.initial_max_stream_data_uni >
- params->initial_max_stream_data_uni ||
- conn->early.transport_params.initial_max_streams_bidi >
- params->initial_max_streams_bidi ||
- conn->early.transport_params.initial_max_streams_uni >
- params->initial_max_streams_uni ||
- conn->early.transport_params.max_datagram_frame_size >
- params->max_datagram_frame_size) {
- return NGTCP2_ERR_PROTO;
- }
- return 0;
- }
- /*
- * conn_write_handshake writes QUIC handshake packets to the buffer
- * pointed by |dest| of length |destlen|. |write_datalen| specifies
- * the expected length of 0RTT packet payload. Specify 0 to
- * |write_datalen| if there is no such data.
- *
- * This function returns the number of bytes written to the buffer, or
- * one of the following negative error codes:
- *
- * NGTCP2_ERR_PKT_NUM_EXHAUSTED
- * Packet number is exhausted.
- * NGTCP2_ERR_NOMEM
- * Out of memory
- * NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM
- * Required transport parameter is missing.
- * NGTCP2_CS_CLOSING
- * Connection is in closing state.
- * NGTCP2_CS_DRAINING
- * Connection is in draining state.
- *
- * In addition to the above negative error codes, the same error codes
- * from conn_recv_pkt may also be returned.
- */
- static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- uint64_t write_datalen,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_ssize res = 0, nwrite = 0, early_spktlen = 0;
- size_t origlen = destlen;
- uint64_t pending_early_datalen;
- ngtcp2_dcid *dcid;
- ngtcp2_preferred_addr *paddr;
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- pending_early_datalen = conn_retry_early_payloadlen(conn);
- if (pending_early_datalen) {
- write_datalen = pending_early_datalen;
- }
- if (!(conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY)) {
- nwrite =
- conn_write_client_initial(conn, pi, dest, destlen, write_datalen, ts);
- if (nwrite <= 0) {
- return nwrite;
- }
- } else {
- nwrite =
- conn_write_handshake_pkt(conn, pi, dest, destlen, 0, NGTCP2_PKT_INITIAL,
- NGTCP2_WRITE_PKT_FLAG_NONE, write_datalen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- }
- if (pending_early_datalen) {
- early_spktlen = conn_retransmit_retry_early(
- conn, pi, dest + nwrite, destlen - (size_t)nwrite, (size_t)nwrite,
- nwrite ? NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING
- : NGTCP2_WRITE_PKT_FLAG_NONE,
- ts);
- if (early_spktlen < 0) {
- assert(ngtcp2_err_is_fatal((int)early_spktlen));
- return early_spktlen;
- }
- }
- conn->state = NGTCP2_CS_CLIENT_WAIT_HANDSHAKE;
- res = nwrite + early_spktlen;
- return res;
- case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE:
- pending_early_datalen = 0;
- if (!conn_handshake_probe_left(conn) && conn_cwnd_is_zero(conn)) {
- destlen = 0;
- } else {
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
- pending_early_datalen = conn_retry_early_payloadlen(conn);
- if (pending_early_datalen) {
- write_datalen = pending_early_datalen;
- }
- }
- nwrite =
- conn_write_handshake_pkts(conn, pi, dest, destlen, write_datalen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res += nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- }
- if (!conn_is_tls_handshake_completed(conn)) {
- if (pending_early_datalen &&
- !(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) {
- nwrite = conn_retransmit_retry_early(
- conn, pi, dest, destlen, (size_t)res, NGTCP2_WRITE_PKT_FLAG_NONE, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res += nwrite;
- }
- if (res == 0) {
- nwrite = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res = nwrite;
- }
- return res;
- }
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
- return res;
- }
- if (!(conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED)) {
- return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
- }
- if ((conn->flags & NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED) &&
- !(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) {
- rv = conn_validate_early_transport_params_limits(conn);
- if (rv != 0) {
- return rv;
- }
- }
- /* Server might increase stream data limits. Extend it if we have
- streams created for early data. */
- rv = conn_sync_stream_data_limit(conn);
- if (rv != 0) {
- return rv;
- }
- conn->state = NGTCP2_CS_POST_HANDSHAKE;
- assert(conn->remote.transport_params);
- if (conn->remote.transport_params->preferred_addr_present) {
- assert(!ngtcp2_ringbuf_full(&conn->dcid.unused.rb));
- paddr = &conn->remote.transport_params->preferred_addr;
- dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused.rb);
- ngtcp2_dcid_init(dcid, 1, &paddr->cid, paddr->stateless_reset_token);
- rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, 1, 1);
- if (rv != 0) {
- return (ngtcp2_ssize)rv;
- }
- }
- if (conn->remote.transport_params->stateless_reset_token_present) {
- assert(conn->dcid.current.seq == 0);
- assert(!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT));
- ngtcp2_dcid_set_token(
- &conn->dcid.current,
- conn->remote.transport_params->stateless_reset_token);
- }
- rv = conn_call_activate_dcid(conn, &conn->dcid.current);
- if (rv != 0) {
- return rv;
- }
- conn_process_early_rtb(conn);
- if (!conn->local.settings.no_pmtud) {
- rv = conn_start_pmtud(conn);
- if (rv != 0) {
- return rv;
- }
- }
- return res;
- case NGTCP2_CS_SERVER_INITIAL:
- nwrite =
- conn_write_handshake_pkts(conn, pi, dest, destlen, write_datalen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- if (nwrite) {
- conn->state = NGTCP2_CS_SERVER_WAIT_HANDSHAKE;
- }
- return nwrite;
- case NGTCP2_CS_SERVER_WAIT_HANDSHAKE:
- if (conn_handshake_probe_left(conn) || !conn_cwnd_is_zero(conn)) {
- nwrite =
- conn_write_handshake_pkts(conn, pi, dest, destlen, write_datalen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res += nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- }
- if (res == 0) {
- nwrite = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res += nwrite;
- dest += nwrite;
- origlen -= (size_t)nwrite;
- }
- return res;
- case NGTCP2_CS_CLOSING:
- return NGTCP2_ERR_CLOSING;
- case NGTCP2_CS_DRAINING:
- return NGTCP2_ERR_DRAINING;
- default:
- return 0;
- }
- }
- /**
- * @function
- *
- * `conn_client_write_handshake` writes client side handshake data and
- * 0RTT packet.
- *
- * In order to send STREAM data in 0RTT packet, specify
- * |vmsg|->stream. |vmsg|->stream.strm, |vmsg|->stream.fin,
- * |vmsg|->stream.data, and |vmsg|->stream.datacnt are stream to which
- * 0-RTT data is sent, whether it is a last data chunk in this stream,
- * a vector of 0-RTT data, and its number of elements respectively.
- * The amount of 0RTT data sent is assigned to
- * *|vmsg|->stream.pdatalen. If no data is sent, -1 is assigned.
- * Note that 0 length STREAM frame is allowed in QUIC, so 0 might be
- * assigned to *|vmsg|->stream.pdatalen.
- *
- * This function returns 0 if it cannot write any frame because buffer
- * is too small, or packet is congestion limited. Application should
- * keep reading and wait for congestion window to grow.
- *
- * This function returns the number of bytes written to the buffer
- * pointed by |dest| if it succeeds, or one of the following negative
- * error codes: (TBD).
- */
- static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn,
- ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- ngtcp2_vmsg *vmsg,
- ngtcp2_tstamp ts) {
- int send_stream = 0;
- int send_datagram = 0;
- ngtcp2_ssize spktlen, early_spktlen;
- uint64_t datalen;
- uint64_t write_datalen = 0;
- uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE;
- int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0;
- uint32_t version;
- assert(!conn->server);
- /* conn->early.ckm might be created in the first call of
- conn_handshake(). Check it later. */
- if (vmsg) {
- switch (vmsg->type) {
- case NGTCP2_VMSG_TYPE_STREAM:
- datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt);
- send_stream = conn_retry_early_payloadlen(conn) == 0;
- if (send_stream) {
- write_datalen = ngtcp2_min_uint64(datalen + NGTCP2_STREAM_OVERHEAD,
- NGTCP2_MIN_COALESCED_PAYLOADLEN);
- if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_MORE;
- }
- } else {
- vmsg = NULL;
- }
- break;
- case NGTCP2_VMSG_TYPE_DATAGRAM:
- datalen = ngtcp2_vec_len(vmsg->datagram.data, vmsg->datagram.datacnt);
- send_datagram = conn_retry_early_payloadlen(conn) == 0;
- if (send_datagram) {
- write_datalen = datalen + NGTCP2_DATAGRAM_OVERHEAD;
- if (vmsg->datagram.flags & NGTCP2_WRITE_DATAGRAM_FLAG_MORE) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_MORE;
- }
- } else {
- vmsg = NULL;
- }
- break;
- }
- }
- if (!ppe_pending) {
- spktlen = conn_write_handshake(conn, pi, dest, destlen, write_datalen, ts);
- if (spktlen < 0) {
- return spktlen;
- }
- if ((conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) ||
- !conn->early.ckm || (!send_stream && !send_datagram)) {
- return spktlen;
- }
- /* If spktlen > 0, we are making a compound packet. If Initial
- packet is written, we have to pad bytes to 0-RTT packet. */
- version = conn->negotiated_version ? conn->negotiated_version
- : conn->client_chosen_version;
- if (spktlen > 0 &&
- ngtcp2_pkt_get_type_long(version, dest[0]) == NGTCP2_PKT_INITIAL) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- conn->pkt.require_padding = 1;
- }
- } else {
- assert(!conn->pktns.crypto.rx.ckm);
- assert(!conn->pktns.crypto.tx.ckm);
- assert(conn->early.ckm);
- if (conn->pkt.require_padding) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- spktlen = conn->pkt.hs_spktlen;
- }
- dest += spktlen;
- destlen -= (size_t)spktlen;
- if (conn_cwnd_is_zero(conn)) {
- return spktlen;
- }
- early_spktlen = conn_write_pkt(conn, pi, dest, destlen, (size_t)spktlen, vmsg,
- NGTCP2_PKT_0RTT, wflags, ts);
- if (early_spktlen < 0) {
- switch (early_spktlen) {
- case NGTCP2_ERR_STREAM_DATA_BLOCKED:
- if (!(wflags & NGTCP2_WRITE_PKT_FLAG_MORE)) {
- if (spktlen) {
- return spktlen;
- }
- break;
- }
- /* fall through */
- case NGTCP2_ERR_WRITE_MORE:
- conn->pkt.hs_spktlen = spktlen;
- break;
- }
- return early_spktlen;
- }
- return spktlen + early_spktlen;
- }
- void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn) {
- conn->flags |= NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED;
- if (conn->server) {
- conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED;
- }
- }
- int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn) {
- return conn_is_tls_handshake_completed(conn) &&
- (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED);
- }
- int ngtcp2_conn_sched_ack(ngtcp2_conn *conn, ngtcp2_acktr *acktr,
- int64_t pkt_num, int active_ack, ngtcp2_tstamp ts) {
- int rv;
- (void)conn;
- rv = ngtcp2_acktr_add(acktr, pkt_num, active_ack, ts);
- if (rv != 0) {
- assert(rv != NGTCP2_ERR_INVALID_ARGUMENT);
- return rv;
- }
- return 0;
- }
- int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen) {
- ngtcp2_ssize nread;
- ngtcp2_pkt_hd hd, *p;
- if (dest) {
- p = dest;
- } else {
- p = &hd;
- }
- if (pktlen == 0 || (pkt[0] & NGTCP2_HEADER_FORM_BIT) == 0) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- nread = ngtcp2_pkt_decode_hd_long(p, pkt, pktlen);
- if (nread < 0) {
- return (int)nread;
- }
- switch (p->type) {
- case NGTCP2_PKT_INITIAL:
- break;
- case NGTCP2_PKT_0RTT:
- /* 0-RTT packet may arrive before Initial packet due to
- re-ordering. ngtcp2 does not buffer 0RTT packet unless the
- very first Initial packet is received or token is received.
- Previously, we returned NGTCP2_ERR_RETRY here, so that client
- can resend 0RTT data. But it incurs 1RTT already and
- diminishes the value of 0RTT. Therefore, we just discard the
- packet here for now. */
- default:
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- if (pktlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE ||
- (p->tokenlen == 0 && p->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- return 0;
- }
- int ngtcp2_conn_install_initial_key(
- ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *rx_aead_ctx,
- const uint8_t *rx_iv, const ngtcp2_crypto_cipher_ctx *rx_hp_ctx,
- const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv,
- const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen) {
- ngtcp2_pktns *pktns = conn->in_pktns;
- int rv;
- assert(ivlen >= 8);
- assert(pktns);
- conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx);
- pktns->crypto.rx.hp_ctx.native_handle = NULL;
- if (pktns->crypto.rx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx);
- ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
- pktns->crypto.rx.ckm = NULL;
- }
- conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx);
- pktns->crypto.tx.hp_ctx.native_handle = NULL;
- if (pktns->crypto.tx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx);
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
- pktns->crypto.tx.ckm = NULL;
- }
- rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, NULL, rx_iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- /* Take owner ship after we are sure that no failure occurs, so that
- caller can delete these contexts on failure. */
- pktns->crypto.rx.ckm->aead_ctx = *rx_aead_ctx;
- pktns->crypto.rx.hp_ctx = *rx_hp_ctx;
- pktns->crypto.tx.ckm->aead_ctx = *tx_aead_ctx;
- pktns->crypto.tx.hp_ctx = *tx_hp_ctx;
- return 0;
- }
- int ngtcp2_conn_install_vneg_initial_key(
- ngtcp2_conn *conn, uint32_t version,
- const ngtcp2_crypto_aead_ctx *rx_aead_ctx, const uint8_t *rx_iv,
- const ngtcp2_crypto_cipher_ctx *rx_hp_ctx,
- const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv,
- const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen) {
- int rv;
- assert(ivlen >= 8);
- conn_call_delete_crypto_cipher_ctx(conn, &conn->vneg.rx.hp_ctx);
- conn->vneg.rx.hp_ctx.native_handle = NULL;
- if (conn->vneg.rx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &conn->vneg.rx.ckm->aead_ctx);
- ngtcp2_crypto_km_del(conn->vneg.rx.ckm, conn->mem);
- conn->vneg.rx.ckm = NULL;
- }
- conn_call_delete_crypto_cipher_ctx(conn, &conn->vneg.tx.hp_ctx);
- conn->vneg.tx.hp_ctx.native_handle = NULL;
- if (conn->vneg.tx.ckm) {
- conn_call_delete_crypto_aead_ctx(conn, &conn->vneg.tx.ckm->aead_ctx);
- ngtcp2_crypto_km_del(conn->vneg.tx.ckm, conn->mem);
- conn->vneg.tx.ckm = NULL;
- }
- rv = ngtcp2_crypto_km_new(&conn->vneg.rx.ckm, NULL, 0, NULL, rx_iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_crypto_km_new(&conn->vneg.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- /* Take owner ship after we are sure that no failure occurs, so that
- caller can delete these contexts on failure. */
- conn->vneg.rx.ckm->aead_ctx = *rx_aead_ctx;
- conn->vneg.rx.hp_ctx = *rx_hp_ctx;
- conn->vneg.tx.ckm->aead_ctx = *tx_aead_ctx;
- conn->vneg.tx.hp_ctx = *tx_hp_ctx;
- conn->vneg.version = version;
- return 0;
- }
- int ngtcp2_conn_install_rx_handshake_key(
- ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv,
- size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) {
- ngtcp2_pktns *pktns = conn->hs_pktns;
- int rv;
- assert(ivlen >= 8);
- assert(pktns);
- assert(!pktns->crypto.rx.hp_ctx.native_handle);
- assert(!pktns->crypto.rx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, aead_ctx, iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- pktns->crypto.rx.hp_ctx = *hp_ctx;
- rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE);
- if (rv != 0) {
- ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
- pktns->crypto.rx.ckm = NULL;
- memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx));
- return rv;
- }
- return 0;
- }
- int ngtcp2_conn_install_tx_handshake_key(
- ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv,
- size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) {
- ngtcp2_pktns *pktns = conn->hs_pktns;
- int rv;
- assert(ivlen >= 8);
- assert(pktns);
- assert(!pktns->crypto.tx.hp_ctx.native_handle);
- assert(!pktns->crypto.tx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, aead_ctx, iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- pktns->crypto.tx.hp_ctx = *hp_ctx;
- if (conn->server) {
- rv = ngtcp2_conn_commit_local_transport_params(conn);
- if (rv != 0) {
- return rv;
- }
- }
- rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE);
- if (rv != 0) {
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
- pktns->crypto.tx.ckm = NULL;
- memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
- return rv;
- }
- return 0;
- }
- int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn,
- const ngtcp2_crypto_aead_ctx *aead_ctx,
- const uint8_t *iv, size_t ivlen,
- const ngtcp2_crypto_cipher_ctx *hp_ctx) {
- int rv;
- assert(ivlen >= 8);
- assert(!conn->early.hp_ctx.native_handle);
- assert(!conn->early.ckm);
- rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, aead_ctx, iv, ivlen,
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- conn->early.hp_ctx = *hp_ctx;
- conn->flags |= NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED;
- if (conn->server) {
- rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_0RTT);
- } else {
- rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_0RTT);
- }
- if (rv != 0) {
- ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
- conn->early.ckm = NULL;
- memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx));
- return rv;
- }
- return 0;
- }
- int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret,
- size_t secretlen,
- const ngtcp2_crypto_aead_ctx *aead_ctx,
- const uint8_t *iv, size_t ivlen,
- const ngtcp2_crypto_cipher_ctx *hp_ctx) {
- ngtcp2_pktns *pktns = &conn->pktns;
- int rv;
- assert(ivlen >= 8);
- assert(!pktns->crypto.rx.hp_ctx.native_handle);
- assert(!pktns->crypto.rx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, aead_ctx,
- iv, ivlen, conn->mem);
- if (rv != 0) {
- return rv;
- }
- pktns->crypto.rx.hp_ctx = *hp_ctx;
- if (!conn->server) {
- if (conn->remote.pending_transport_params) {
- ngtcp2_transport_params_del(conn->remote.transport_params, conn->mem);
- conn->remote.transport_params = conn->remote.pending_transport_params;
- conn->remote.pending_transport_params = NULL;
- conn_sync_stream_id_limit(conn);
- conn->tx.max_offset = conn->remote.transport_params->initial_max_data;
- }
- if (conn->early.ckm) {
- conn_discard_early_key(conn);
- }
- }
- rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT);
- if (rv != 0) {
- ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
- pktns->crypto.rx.ckm = NULL;
- memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx));
- return rv;
- }
- return 0;
- }
- int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret,
- size_t secretlen,
- const ngtcp2_crypto_aead_ctx *aead_ctx,
- const uint8_t *iv, size_t ivlen,
- const ngtcp2_crypto_cipher_ctx *hp_ctx) {
- ngtcp2_pktns *pktns = &conn->pktns;
- int rv;
- assert(ivlen >= 8);
- assert(!pktns->crypto.tx.hp_ctx.native_handle);
- assert(!pktns->crypto.tx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, aead_ctx,
- iv, ivlen, conn->mem);
- if (rv != 0) {
- return rv;
- }
- pktns->crypto.tx.hp_ctx = *hp_ctx;
- if (conn->server) {
- if (conn->remote.pending_transport_params) {
- ngtcp2_transport_params_del(conn->remote.transport_params, conn->mem);
- conn->remote.transport_params = conn->remote.pending_transport_params;
- conn->remote.pending_transport_params = NULL;
- conn_sync_stream_id_limit(conn);
- conn->tx.max_offset = conn->remote.transport_params->initial_max_data;
- }
- } else if (conn->early.ckm) {
- conn_discard_early_key(conn);
- }
- rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT);
- if (rv != 0) {
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
- pktns->crypto.tx.ckm = NULL;
- memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
- return rv;
- }
- return 0;
- }
- static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- ngtcp2_tstamp confirmed_ts = conn->crypto.key_update.confirmed_ts;
- ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns);
- assert(conn->state == NGTCP2_CS_POST_HANDSHAKE);
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) ||
- (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) ||
- !conn->crypto.key_update.new_tx_ckm ||
- !conn->crypto.key_update.new_rx_ckm ||
- ngtcp2_tstamp_not_elapsed(confirmed_ts, 3 * pto, ts)) {
- return NGTCP2_ERR_INVALID_STATE;
- }
- conn_rotate_keys(conn, NGTCP2_MAX_PKT_NUM, /* initiator = */ 1);
- return 0;
- }
- int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- conn_update_timestamp(conn, ts);
- return conn_initiate_key_update(conn, ts);
- }
- /*
- * conn_retire_stale_bound_dcid retires stale destination connection
- * ID in conn->dcid.bound to keep some unused destination connection
- * IDs available.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_retire_stale_bound_dcid(ngtcp2_conn *conn,
- ngtcp2_duration timeout,
- ngtcp2_tstamp ts) {
- size_t i;
- ngtcp2_dcid *dcid, *last;
- int rv;
- for (i = 0; i < ngtcp2_ringbuf_len(&conn->dcid.bound.rb);) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, i);
- assert(dcid->cid.datalen);
- if (ngtcp2_tstamp_not_elapsed(dcid->bound_ts, timeout, ts)) {
- ++i;
- continue;
- }
- rv = conn_retire_dcid_seq(conn, dcid->seq);
- if (rv != 0) {
- return rv;
- }
- if (i == 0) {
- ngtcp2_ringbuf_pop_front(&conn->dcid.bound.rb);
- continue;
- }
- if (i == ngtcp2_ringbuf_len(&conn->dcid.bound.rb) - 1) {
- ngtcp2_ringbuf_pop_back(&conn->dcid.bound.rb);
- break;
- }
- last = ngtcp2_ringbuf_get(&conn->dcid.bound.rb,
- ngtcp2_ringbuf_len(&conn->dcid.bound.rb) - 1);
- ngtcp2_dcid_copy(dcid, last);
- ngtcp2_ringbuf_pop_back(&conn->dcid.bound.rb);
- }
- return 0;
- }
- ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn) {
- return conn->cstat.loss_detection_timer;
- }
- ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn) {
- ngtcp2_tstamp res = UINT64_MAX;
- ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns);
- ngtcp2_scid *scid;
- ngtcp2_dcid *dcid;
- size_t i, len;
- if (conn->pv) {
- res = ngtcp2_pv_next_expiry(conn->pv);
- }
- if (conn->pmtud) {
- res = ngtcp2_min_uint64(res, conn->pmtud->expiry);
- }
- if (!ngtcp2_pq_empty(&conn->scid.used)) {
- scid = ngtcp2_struct_of(ngtcp2_pq_top(&conn->scid.used), ngtcp2_scid, pe);
- if (scid->retired_ts != UINT64_MAX) {
- res = ngtcp2_min_uint64(res, scid->retired_ts + pto);
- }
- }
- if (ngtcp2_ringbuf_len(&conn->dcid.retired.rb)) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.retired.rb, 0);
- res = ngtcp2_min_uint64(res, dcid->retired_ts + pto);
- }
- if (conn->dcid.current.cid.datalen) {
- len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.bound.rb, i);
- assert(dcid->cid.datalen);
- assert(dcid->bound_ts != UINT64_MAX);
- res = ngtcp2_min_uint64(res, dcid->bound_ts + 3 * pto);
- }
- }
- if (conn->server && conn->early.ckm &&
- conn->early.discard_started_ts != UINT64_MAX) {
- res = ngtcp2_min_uint64(res, conn->early.discard_started_ts + 3 * pto);
- }
- return res;
- }
- ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) {
- ngtcp2_acktr *acktr = &conn->pktns.acktr;
- if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) &&
- acktr->first_unacked_ts != UINT64_MAX) {
- return acktr->first_unacked_ts + conn_compute_ack_delay(conn);
- }
- return UINT64_MAX;
- }
- static ngtcp2_tstamp conn_handshake_expiry(ngtcp2_conn *conn) {
- if (conn_is_tls_handshake_completed(conn) ||
- conn->local.settings.handshake_timeout == UINT64_MAX ||
- conn->local.settings.initial_ts >=
- UINT64_MAX - conn->local.settings.handshake_timeout) {
- return UINT64_MAX;
- }
- return conn->local.settings.initial_ts +
- conn->local.settings.handshake_timeout;
- }
- ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) {
- ngtcp2_tstamp res = ngtcp2_min_uint64(ngtcp2_conn_loss_detection_expiry(conn),
- ngtcp2_conn_ack_delay_expiry(conn));
- res = ngtcp2_min_uint64(res, ngtcp2_conn_internal_expiry(conn));
- res = ngtcp2_min_uint64(res, ngtcp2_conn_lost_pkt_expiry(conn));
- res = ngtcp2_min_uint64(res, conn_keep_alive_expiry(conn));
- res = ngtcp2_min_uint64(res, conn_handshake_expiry(conn));
- res = ngtcp2_min_uint64(res, ngtcp2_conn_get_idle_expiry(conn));
- return ngtcp2_min_uint64(res, conn->tx.pacing.next_ts);
- }
- int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_duration pto;
- conn_update_timestamp(conn, ts);
- pto = conn_compute_pto(conn, &conn->pktns);
- assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING));
- if (ngtcp2_conn_get_idle_expiry(conn) <= ts) {
- return NGTCP2_ERR_IDLE_CLOSE;
- }
- ngtcp2_conn_cancel_expired_ack_delay_timer(conn, ts);
- conn_cancel_expired_keep_alive_timer(conn, ts);
- conn_cancel_expired_pkt_tx_timer(conn, ts);
- ngtcp2_conn_remove_lost_pkt(conn, ts);
- if (conn->pv) {
- ngtcp2_pv_cancel_expired_timer(conn->pv, ts);
- }
- if (conn->pmtud) {
- ngtcp2_pmtud_handle_expiry(conn->pmtud, ts);
- if (ngtcp2_pmtud_finished(conn->pmtud)) {
- ngtcp2_conn_stop_pmtud(conn);
- }
- }
- if (ngtcp2_conn_loss_detection_expiry(conn) <= ts) {
- rv = ngtcp2_conn_on_loss_detection_timer(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- if (conn->dcid.current.cid.datalen) {
- rv = conn_retire_stale_bound_dcid(conn, 3 * pto, ts);
- if (rv != 0) {
- return rv;
- }
- }
- rv = conn_remove_retired_connection_id(conn, pto, ts);
- if (rv != 0) {
- return rv;
- }
- if (conn->server && conn->early.ckm &&
- ngtcp2_tstamp_elapsed(conn->early.discard_started_ts, 3 * pto, ts)) {
- conn_discard_early_key(conn);
- }
- if (!conn_is_tls_handshake_completed(conn) &&
- ngtcp2_tstamp_elapsed(conn->local.settings.initial_ts,
- conn->local.settings.handshake_timeout, ts)) {
- return NGTCP2_ERR_HANDSHAKE_TIMEOUT;
- }
- return 0;
- }
- static void acktr_cancel_expired_ack_delay_timer(ngtcp2_acktr *acktr,
- ngtcp2_duration max_ack_delay,
- ngtcp2_tstamp ts) {
- if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) &&
- ngtcp2_tstamp_elapsed(acktr->first_unacked_ts, max_ack_delay, ts)) {
- acktr->flags |= NGTCP2_ACKTR_FLAG_CANCEL_TIMER;
- }
- }
- void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- ngtcp2_duration ack_delay = conn_compute_ack_delay(conn);
- if (conn->in_pktns) {
- acktr_cancel_expired_ack_delay_timer(&conn->in_pktns->acktr, 0, ts);
- }
- if (conn->hs_pktns) {
- acktr_cancel_expired_ack_delay_timer(&conn->hs_pktns->acktr, 0, ts);
- }
- acktr_cancel_expired_ack_delay_timer(&conn->pktns.acktr, ack_delay, ts);
- }
- ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) {
- ngtcp2_tstamp res = UINT64_MAX, ts;
- if (conn->in_pktns) {
- ts = ngtcp2_rtb_lost_pkt_ts(&conn->in_pktns->rtb);
- if (ts != UINT64_MAX) {
- ts += conn_compute_pto(conn, conn->in_pktns);
- res = ngtcp2_min_uint64(res, ts);
- }
- }
- if (conn->hs_pktns) {
- ts = ngtcp2_rtb_lost_pkt_ts(&conn->hs_pktns->rtb);
- if (ts != UINT64_MAX) {
- ts += conn_compute_pto(conn, conn->hs_pktns);
- res = ngtcp2_min_uint64(res, ts);
- }
- }
- ts = ngtcp2_rtb_lost_pkt_ts(&conn->pktns.rtb);
- if (ts != UINT64_MAX) {
- ts += conn_compute_pto(conn, &conn->pktns);
- res = ngtcp2_min_uint64(res, ts);
- }
- return res;
- }
- void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- ngtcp2_duration pto;
- if (conn->in_pktns) {
- pto = conn_compute_pto(conn, conn->in_pktns);
- ngtcp2_rtb_remove_expired_lost_pkt(&conn->in_pktns->rtb, pto, ts);
- }
- if (conn->hs_pktns) {
- pto = conn_compute_pto(conn, conn->hs_pktns);
- ngtcp2_rtb_remove_expired_lost_pkt(&conn->hs_pktns->rtb, pto, ts);
- }
- pto = conn_compute_pto(conn, &conn->pktns);
- ngtcp2_rtb_remove_expired_lost_pkt(&conn->pktns.rtb, pto, ts);
- }
- /*
- * select_preferred_version selects the most preferred version.
- * |fallback_version| is chosen if no preference is made, or
- * |preferred_versions| does not include any of |chosen_version| or
- * |available_versions|. |chosen_version| is treated as an extra
- * other version.
- */
- static uint32_t select_preferred_version(const uint32_t *preferred_versions,
- size_t preferred_versionslen,
- uint32_t chosen_version,
- const uint8_t *available_versions,
- size_t available_versionslen,
- uint32_t fallback_version) {
- size_t i, j;
- const uint8_t *p;
- uint32_t v;
- if (!preferred_versionslen ||
- (!available_versionslen && chosen_version == fallback_version)) {
- return fallback_version;
- }
- for (i = 0; i < preferred_versionslen; ++i) {
- if (preferred_versions[i] == chosen_version) {
- return chosen_version;
- }
- for (j = 0, p = available_versions; j < available_versionslen;
- j += sizeof(uint32_t)) {
- p = ngtcp2_get_uint32be(&v, p);
- if (preferred_versions[i] == v) {
- return v;
- }
- }
- }
- return fallback_version;
- }
- /*
- * conn_client_validate_transport_params validates |params| as client.
- * |params| must be sent with Encrypted Extensions.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_TRANSPORT_PARAM
- * params contains preferred address but server chose zero-length
- * connection ID.
- * NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE
- * Validation against version negotiation parameters failed.
- */
- static int
- conn_client_validate_transport_params(ngtcp2_conn *conn,
- const ngtcp2_transport_params *params) {
- if (!params->original_dcid_present) {
- return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
- }
- if (!ngtcp2_cid_eq(&conn->rcid, ¶ms->original_dcid)) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) {
- if (!params->retry_scid_present) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (!ngtcp2_cid_eq(&conn->retry_scid, ¶ms->retry_scid)) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- } else if (params->retry_scid_present) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (params->preferred_addr_present && conn->dcid.current.cid.datalen == 0) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (params->version_info_present) {
- if (conn->negotiated_version != params->version_info.chosen_version) {
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- assert(vneg_available_versions_includes(conn->vneg.available_versions,
- conn->vneg.available_versionslen,
- conn->negotiated_version));
- } else if (conn->client_chosen_version != conn->negotiated_version) {
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- /* When client reacted upon Version Negotiation */
- if (conn->local.settings.original_version != conn->client_chosen_version) {
- if (!params->version_info_present) {
- assert(conn->client_chosen_version == conn->negotiated_version);
- /* QUIC v1 is treated specially. If version_info is missing, no
- further validation is necessary. See
- https://datatracker.ietf.org/doc/html/rfc9368#section-8
- */
- if (conn->client_chosen_version == NGTCP2_PROTO_VER_V1) {
- return 0;
- }
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- /* Server choose original version after Version Negotiation. RFC
- 9368 does not say this particular case, but this smells like
- misbehaved server because server should accept original_version
- in the original connection. */
- if (conn->local.settings.original_version ==
- params->version_info.chosen_version) {
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- /* Check version downgrade on incompatible version negotiation. */
- if (params->version_info.available_versionslen == 0) {
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- if (conn->client_chosen_version !=
- select_preferred_version(conn->vneg.preferred_versions,
- conn->vneg.preferred_versionslen,
- params->version_info.chosen_version,
- params->version_info.available_versions,
- params->version_info.available_versionslen,
- /* fallback_version = */ 0)) {
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- }
- return 0;
- }
- uint32_t
- ngtcp2_conn_server_negotiate_version(ngtcp2_conn *conn,
- const ngtcp2_version_info *version_info) {
- assert(conn->server);
- assert(conn->client_chosen_version == version_info->chosen_version);
- return select_preferred_version(
- conn->vneg.preferred_versions, conn->vneg.preferred_versionslen,
- version_info->chosen_version, version_info->available_versions,
- version_info->available_versionslen, version_info->chosen_version);
- }
- int ngtcp2_conn_set_remote_transport_params(
- ngtcp2_conn *conn, const ngtcp2_transport_params *params) {
- int rv;
- /* We expect this function is called once per QUIC connection, but
- GnuTLS server seems to call TLS extension callback twice if it
- sends HelloRetryRequest. In practice, same QUIC transport
- parameters are sent in the 2nd client flight, just returning 0
- would cause no harm. */
- if (conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED) {
- return 0;
- }
- if (!params->initial_scid_present) {
- return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
- }
- /* Assume that ngtcp2_transport_params_decode sets default value if
- active_connection_id_limit is omitted. */
- if (params->active_connection_id_limit <
- NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- /* We assume that conn->dcid.current.cid is still the initial one.
- This requires that transport parameter must be fed into
- ngtcp2_conn as early as possible. */
- if (!ngtcp2_cid_eq(&conn->dcid.current.cid, ¶ms->initial_scid)) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (params->max_udp_payload_size < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (conn->server) {
- if (params->original_dcid_present ||
- params->stateless_reset_token_present ||
- params->preferred_addr_present || params->retry_scid_present) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (params->version_info_present) {
- if (!vneg_available_versions_includes(
- params->version_info.available_versions,
- params->version_info.available_versionslen,
- params->version_info.chosen_version)) {
- return NGTCP2_ERR_TRANSPORT_PARAM;
- }
- if (params->version_info.chosen_version != conn->client_chosen_version) {
- return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE;
- }
- conn->negotiated_version =
- ngtcp2_conn_server_negotiate_version(conn, ¶ms->version_info);
- if (conn->negotiated_version != conn->client_chosen_version) {
- rv = conn_call_version_negotiation(conn, conn->negotiated_version,
- &conn->rcid);
- if (rv != 0) {
- return rv;
- }
- }
- } else {
- conn->negotiated_version = conn->client_chosen_version;
- }
- conn->local.transport_params.version_info.chosen_version =
- conn->negotiated_version;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "the negotiated version is 0x%08x",
- conn->negotiated_version);
- } else {
- rv = conn_client_validate_transport_params(conn, params);
- if (rv != 0) {
- return rv;
- }
- }
- ngtcp2_log_remote_tp(&conn->log, params);
- ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server,
- NGTCP2_QLOG_SIDE_REMOTE);
- if ((conn->server && conn->pktns.crypto.tx.ckm) ||
- (!conn->server && conn->pktns.crypto.rx.ckm)) {
- ngtcp2_transport_params_del(conn->remote.transport_params, conn->mem);
- conn->remote.transport_params = NULL;
- rv = ngtcp2_transport_params_copy_new(&conn->remote.transport_params,
- params, conn->mem);
- if (rv != 0) {
- return rv;
- }
- conn_sync_stream_id_limit(conn);
- conn->tx.max_offset = conn->remote.transport_params->initial_max_data;
- } else {
- assert(!conn->remote.pending_transport_params);
- rv = ngtcp2_transport_params_copy_new(
- &conn->remote.pending_transport_params, params, conn->mem);
- if (rv != 0) {
- return rv;
- }
- }
- conn->flags |= NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED;
- return 0;
- }
- int ngtcp2_conn_decode_and_set_remote_transport_params(ngtcp2_conn *conn,
- const uint8_t *data,
- size_t datalen) {
- ngtcp2_transport_params params;
- int rv;
- rv = ngtcp2_transport_params_decode(¶ms, data, datalen);
- if (rv != 0) {
- return rv;
- }
- return ngtcp2_conn_set_remote_transport_params(conn, ¶ms);
- }
- const ngtcp2_transport_params *
- ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn) {
- if (conn->remote.pending_transport_params) {
- return conn->remote.pending_transport_params;
- }
- return conn->remote.transport_params;
- }
- ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn,
- uint8_t *dest,
- size_t destlen) {
- ngtcp2_transport_params params, *src;
- if (conn->server) {
- src = &conn->local.transport_params;
- } else {
- assert(conn->remote.transport_params);
- src = conn->remote.transport_params;
- }
- ngtcp2_transport_params_default(¶ms);
- params.initial_max_streams_bidi = src->initial_max_streams_bidi;
- params.initial_max_streams_uni = src->initial_max_streams_uni;
- params.initial_max_stream_data_bidi_local =
- src->initial_max_stream_data_bidi_local;
- params.initial_max_stream_data_bidi_remote =
- src->initial_max_stream_data_bidi_remote;
- params.initial_max_stream_data_uni = src->initial_max_stream_data_uni;
- params.initial_max_data = src->initial_max_data;
- params.active_connection_id_limit = src->active_connection_id_limit;
- params.max_datagram_frame_size = src->max_datagram_frame_size;
- if (conn->server) {
- params.max_idle_timeout = src->max_idle_timeout;
- params.max_udp_payload_size = src->max_udp_payload_size;
- params.disable_active_migration = src->disable_active_migration;
- }
- return ngtcp2_transport_params_encode(dest, destlen, ¶ms);
- }
- int ngtcp2_conn_decode_and_set_0rtt_transport_params(ngtcp2_conn *conn,
- const uint8_t *data,
- size_t datalen) {
- ngtcp2_transport_params params;
- int rv;
- rv = ngtcp2_transport_params_decode(¶ms, data, datalen);
- if (rv != 0) {
- return rv;
- }
- return ngtcp2_conn_set_0rtt_remote_transport_params(conn, ¶ms);
- }
- int ngtcp2_conn_set_0rtt_remote_transport_params(
- ngtcp2_conn *conn, const ngtcp2_transport_params *params) {
- ngtcp2_transport_params *p;
- assert(!conn->server);
- assert(!conn->remote.transport_params);
- /* Assume that all pointer fields in p are NULL */
- p = ngtcp2_mem_calloc(conn->mem, 1, sizeof(*p));
- if (p == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- conn->remote.transport_params = p;
- ngtcp2_transport_params_default(conn->remote.transport_params);
- p->initial_max_streams_bidi = params->initial_max_streams_bidi;
- p->initial_max_streams_uni = params->initial_max_streams_uni;
- p->initial_max_stream_data_bidi_local =
- params->initial_max_stream_data_bidi_local;
- p->initial_max_stream_data_bidi_remote =
- params->initial_max_stream_data_bidi_remote;
- p->initial_max_stream_data_uni = params->initial_max_stream_data_uni;
- p->initial_max_data = params->initial_max_data;
- /* we might hit garbage, then set the sane default. */
- p->active_connection_id_limit =
- ngtcp2_max_uint64(NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT,
- params->active_connection_id_limit);
- p->max_datagram_frame_size = params->max_datagram_frame_size;
- /* we might hit garbage, then set the sane default. */
- if (params->max_udp_payload_size) {
- p->max_udp_payload_size = ngtcp2_max_uint64(NGTCP2_MAX_UDP_PAYLOAD_SIZE,
- params->max_udp_payload_size);
- }
- /* These parameters are treated specially. If server accepts early
- data, it must not set values for these parameters that are
- smaller than these remembered values. */
- conn->early.transport_params.initial_max_streams_bidi =
- params->initial_max_streams_bidi;
- conn->early.transport_params.initial_max_streams_uni =
- params->initial_max_streams_uni;
- conn->early.transport_params.initial_max_stream_data_bidi_local =
- params->initial_max_stream_data_bidi_local;
- conn->early.transport_params.initial_max_stream_data_bidi_remote =
- params->initial_max_stream_data_bidi_remote;
- conn->early.transport_params.initial_max_stream_data_uni =
- params->initial_max_stream_data_uni;
- conn->early.transport_params.initial_max_data = params->initial_max_data;
- conn->early.transport_params.active_connection_id_limit =
- params->active_connection_id_limit;
- conn->early.transport_params.max_datagram_frame_size =
- params->max_datagram_frame_size;
- conn_sync_stream_id_limit(conn);
- conn->tx.max_offset = p->initial_max_data;
- ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, p, conn->server,
- NGTCP2_QLOG_SIDE_REMOTE);
- return 0;
- }
- int ngtcp2_conn_set_local_transport_params_versioned(
- ngtcp2_conn *conn, int transport_params_version,
- const ngtcp2_transport_params *params) {
- ngtcp2_transport_params paramsbuf;
- params = ngtcp2_transport_params_convert_to_latest(
- ¶msbuf, transport_params_version, params);
- assert(conn->server);
- assert(params->active_connection_id_limit >=
- NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT);
- assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE);
- if (conn->hs_pktns == NULL || conn->hs_pktns->crypto.tx.ckm) {
- return NGTCP2_ERR_INVALID_STATE;
- }
- conn_set_local_transport_params(conn, params);
- return 0;
- }
- int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) {
- const ngtcp2_mem *mem = conn->mem;
- ngtcp2_transport_params *params = &conn->local.transport_params;
- ngtcp2_scid *scident;
- int rv;
- assert(1 == ngtcp2_ksl_len(&conn->scid.set));
- params->initial_scid = conn->oscid;
- params->initial_scid_present = 1;
- if (conn->oscid.datalen == 0) {
- params->preferred_addr_present = 0;
- }
- if (conn->server && params->preferred_addr_present) {
- scident = ngtcp2_mem_malloc(mem, sizeof(*scident));
- if (scident == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- ngtcp2_scid_init(scident, 1, ¶ms->preferred_addr.cid);
- rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scident->cid, scident);
- if (rv != 0) {
- ngtcp2_mem_free(mem, scident);
- return rv;
- }
- conn->scid.last_seq = 1;
- }
- conn->rx.window = conn->rx.unsent_max_offset = conn->rx.max_offset =
- params->initial_max_data;
- conn->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi;
- conn->remote.bidi.max_streams = params->initial_max_streams_bidi;
- conn->remote.uni.unsent_max_streams = params->initial_max_streams_uni;
- conn->remote.uni.max_streams = params->initial_max_streams_uni;
- conn->flags |= NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED;
- ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server,
- NGTCP2_QLOG_SIDE_LOCAL);
- return 0;
- }
- const ngtcp2_transport_params *
- ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn) {
- return &conn->local.transport_params;
- }
- ngtcp2_ssize ngtcp2_conn_encode_local_transport_params(ngtcp2_conn *conn,
- uint8_t *dest,
- size_t destlen) {
- return ngtcp2_transport_params_encode(dest, destlen,
- &conn->local.transport_params);
- }
- int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id,
- void *stream_user_data) {
- int rv;
- ngtcp2_strm *strm;
- if (ngtcp2_conn_get_streams_bidi_left(conn) == 0) {
- return NGTCP2_ERR_STREAM_ID_BLOCKED;
- }
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, conn->local.bidi.next_stream_id,
- stream_user_data);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- *pstream_id = conn->local.bidi.next_stream_id;
- conn->local.bidi.next_stream_id += 4;
- return 0;
- }
- int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, int64_t *pstream_id,
- void *stream_user_data) {
- int rv;
- ngtcp2_strm *strm;
- if (ngtcp2_conn_get_streams_uni_left(conn) == 0) {
- return NGTCP2_ERR_STREAM_ID_BLOCKED;
- }
- strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc);
- if (strm == NULL) {
- return NGTCP2_ERR_NOMEM;
- }
- rv = ngtcp2_conn_init_stream(conn, strm, conn->local.uni.next_stream_id,
- stream_user_data);
- if (rv != 0) {
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return rv;
- }
- ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_RD);
- *pstream_id = conn->local.uni.next_stream_id;
- conn->local.uni.next_stream_id += 4;
- return 0;
- }
- ngtcp2_strm *ngtcp2_conn_find_stream(ngtcp2_conn *conn, int64_t stream_id) {
- return ngtcp2_map_find(&conn->strms, (uint64_t)stream_id);
- }
- ngtcp2_ssize ngtcp2_conn_write_stream_versioned(
- ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen,
- uint32_t flags, int64_t stream_id, const uint8_t *data, size_t datalen,
- ngtcp2_tstamp ts) {
- ngtcp2_vec datav;
- datav.len = datalen;
- datav.base = (uint8_t *)data;
- return ngtcp2_conn_writev_stream_versioned(conn, path, pkt_info_version, pi,
- dest, destlen, pdatalen, flags,
- stream_id, &datav, 1, ts);
- }
- static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn,
- ngtcp2_path *path,
- int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, ngtcp2_vmsg *vmsg,
- ngtcp2_tstamp ts) {
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_ssize nwrite;
- nwrite = ngtcp2_conn_write_vmsg(conn, path, pkt_info_version, pi, dest,
- destlen, vmsg, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- if (cstat->bytes_in_flight >= cstat->cwnd) {
- conn->rst.is_cwnd_limited = 1;
- } else if (conn->rst.app_limited == 0 &&
- (cstat->cwnd >= cstat->ssthresh ||
- cstat->bytes_in_flight * 2 < cstat->cwnd) &&
- nwrite == 0 && conn_pacing_pkt_tx_allowed(conn, ts) &&
- (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
- conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight;
- if (conn->rst.app_limited == 0) {
- conn->rst.app_limited = cstat->max_tx_udp_payload_size;
- }
- }
- return nwrite;
- }
- ngtcp2_ssize ngtcp2_conn_writev_stream_versioned(
- ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen,
- uint32_t flags, int64_t stream_id, const ngtcp2_vec *datav, size_t datavcnt,
- ngtcp2_tstamp ts) {
- ngtcp2_vmsg vmsg, *pvmsg;
- ngtcp2_strm *strm;
- int64_t datalen;
- if (pdatalen) {
- *pdatalen = -1;
- }
- if (stream_id != -1) {
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return NGTCP2_ERR_STREAM_NOT_FOUND;
- }
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
- return NGTCP2_ERR_STREAM_SHUT_WR;
- }
- datalen = ngtcp2_vec_len_varint(datav, datavcnt);
- if (datalen == -1) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- if (datalen == 0 && !(flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
- (strm->flags & NGTCP2_STRM_FLAG_ANY_SENT)) {
- pvmsg = NULL;
- } else {
- if ((uint64_t)datalen > NGTCP2_MAX_VARINT - strm->tx.offset ||
- (uint64_t)datalen > NGTCP2_MAX_VARINT - conn->tx.offset) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- vmsg.type = NGTCP2_VMSG_TYPE_STREAM;
- vmsg.stream.strm = strm;
- vmsg.stream.flags = flags;
- vmsg.stream.data = datav;
- vmsg.stream.datacnt = datavcnt;
- vmsg.stream.pdatalen = pdatalen;
- pvmsg = &vmsg;
- }
- } else {
- pvmsg = NULL;
- }
- return conn_write_vmsg_wrapper(conn, path, pkt_info_version, pi, dest,
- destlen, pvmsg, ts);
- }
- ngtcp2_ssize ngtcp2_conn_write_datagram_versioned(
- ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted,
- uint32_t flags, uint64_t dgram_id, const uint8_t *data, size_t datalen,
- ngtcp2_tstamp ts) {
- ngtcp2_vec datav;
- datav.len = datalen;
- datav.base = (uint8_t *)data;
- return ngtcp2_conn_writev_datagram_versioned(conn, path, pkt_info_version, pi,
- dest, destlen, paccepted, flags,
- dgram_id, &datav, 1, ts);
- }
- ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned(
- ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted,
- uint32_t flags, uint64_t dgram_id, const ngtcp2_vec *datav, size_t datavcnt,
- ngtcp2_tstamp ts) {
- ngtcp2_vmsg vmsg;
- int64_t datalen;
- if (paccepted) {
- *paccepted = 0;
- }
- if (conn->remote.transport_params == NULL ||
- conn->remote.transport_params->max_datagram_frame_size == 0) {
- return NGTCP2_ERR_INVALID_STATE;
- }
- datalen = ngtcp2_vec_len_varint(datav, datavcnt);
- if (datalen == -1
- #if UINT64_MAX > SIZE_MAX
- || (uint64_t)datalen > SIZE_MAX
- #endif /* UINT64_MAX > SIZE_MAX */
- ) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- if (conn->remote.transport_params->max_datagram_frame_size <
- ngtcp2_pkt_datagram_framelen((size_t)datalen)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- vmsg.type = NGTCP2_VMSG_TYPE_DATAGRAM;
- vmsg.datagram.dgram_id = dgram_id;
- vmsg.datagram.flags = flags;
- vmsg.datagram.data = datav;
- vmsg.datagram.datacnt = datavcnt;
- vmsg.datagram.paccepted = paccepted;
- return conn_write_vmsg_wrapper(conn, path, pkt_info_version, pi, dest,
- destlen, &vmsg, ts);
- }
- ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
- int pkt_info_version, ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen,
- ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts) {
- ngtcp2_ssize nwrite;
- size_t origlen;
- size_t origdestlen = destlen;
- int rv;
- uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE;
- int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0;
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_ssize res = 0;
- uint64_t server_tx_left;
- int64_t prev_in_pkt_num = -1;
- ngtcp2_ksl_it it;
- ngtcp2_rtb_entry *rtbent;
- (void)pkt_info_version;
- conn_update_timestamp(conn, ts);
- if (path) {
- ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
- }
- origlen = destlen =
- conn_shape_udp_payload(conn, &conn->dcid.current, destlen);
- if (!ppe_pending && pi) {
- pi->ecn = NGTCP2_ECN_NOT_ECT;
- }
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE:
- if (!conn_pacing_pkt_tx_allowed(conn, ts)) {
- assert(!ppe_pending);
- return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
- }
- nwrite = conn_client_write_handshake(conn, pi, dest, destlen, vmsg, ts);
- /* We might be unable to write a packet because of depletion of
- congestion window budget, perhaps due to packet loss that
- shrinks the window drastically. */
- if (nwrite <= 0) {
- return nwrite;
- }
- if (conn->state != NGTCP2_CS_POST_HANDSHAKE) {
- return nwrite;
- }
- assert(nwrite);
- assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
- assert(conn->negotiated_version);
- if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE &&
- ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
- NGTCP2_PKT_INITIAL) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- res = nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- /* Break here so that we can coalesces 1RTT packet. */
- break;
- case NGTCP2_CS_SERVER_INITIAL:
- case NGTCP2_CS_SERVER_WAIT_HANDSHAKE:
- if (!conn_pacing_pkt_tx_allowed(conn, ts)) {
- assert(!ppe_pending);
- if (!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) {
- server_tx_left = conn_server_tx_left(conn, &conn->dcid.current);
- if (server_tx_left == 0) {
- return 0;
- }
- origlen = (size_t)ngtcp2_min_uint64((uint64_t)origlen, server_tx_left);
- }
- return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
- }
- if (!ppe_pending) {
- if (!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) {
- server_tx_left = conn_server_tx_left(conn, &conn->dcid.current);
- if (server_tx_left == 0) {
- if (cstat->loss_detection_timer != UINT64_MAX) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss detection timer canceled due to amplification limit");
- ngtcp2_conn_cancel_loss_detection_timer(conn);
- }
- return 0;
- }
- destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left);
- }
- if (conn->in_pktns) {
- it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
- if (!ngtcp2_ksl_it_end(&it)) {
- rtbent = ngtcp2_ksl_it_get(&it);
- prev_in_pkt_num = rtbent->hd.pkt_num;
- }
- }
- nwrite = conn_write_handshake(conn, pi, dest, destlen,
- /* write_datalen = */ 0, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res = nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- if (res < NGTCP2_MAX_UDP_PAYLOAD_SIZE && conn->in_pktns && nwrite > 0) {
- it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
- if (!ngtcp2_ksl_it_end(&it)) {
- rtbent = ngtcp2_ksl_it_get(&it);
- if (rtbent->hd.pkt_num != prev_in_pkt_num &&
- (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- }
- }
- }
- if (conn->pktns.crypto.tx.ckm == NULL) {
- return res;
- }
- break;
- case NGTCP2_CS_POST_HANDSHAKE:
- if (!conn_pacing_pkt_tx_allowed(conn, ts)) {
- assert(!ppe_pending);
- if (conn->server &&
- !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) {
- server_tx_left = conn_server_tx_left(conn, &conn->dcid.current);
- if (server_tx_left == 0) {
- return 0;
- }
- origlen = (size_t)ngtcp2_min_uint64((uint64_t)origlen, server_tx_left);
- }
- return conn_write_ack_pkt(conn, pi, dest, origlen, NGTCP2_PKT_1RTT, ts);
- }
- break;
- case NGTCP2_CS_CLOSING:
- return NGTCP2_ERR_CLOSING;
- case NGTCP2_CS_DRAINING:
- return NGTCP2_ERR_DRAINING;
- default:
- return 0;
- }
- assert(conn->pktns.crypto.tx.ckm);
- if (conn_check_pkt_num_exhausted(conn)) {
- return NGTCP2_ERR_PKT_NUM_EXHAUSTED;
- }
- if (vmsg) {
- switch (vmsg->type) {
- case NGTCP2_VMSG_TYPE_STREAM:
- if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_MORE;
- }
- break;
- case NGTCP2_VMSG_TYPE_DATAGRAM:
- if (vmsg->datagram.flags & NGTCP2_WRITE_DATAGRAM_FLAG_MORE) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_MORE;
- }
- break;
- default:
- break;
- }
- }
- if (ppe_pending) {
- res = conn->pkt.hs_spktlen;
- if (conn->pkt.require_padding) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- /* dest and destlen have already been adjusted in ppe in the first
- run. They are adjusted for probe packet later. */
- nwrite = conn_write_pkt(conn, pi, dest, destlen, (size_t)res, vmsg,
- NGTCP2_PKT_1RTT, wflags, ts);
- goto fin;
- } else {
- conn->pkt.require_padding =
- (wflags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING);
- if (conn->state == NGTCP2_CS_POST_HANDSHAKE) {
- rv = conn_prepare_key_update(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- if (!conn->pktns.rtb.probe_pkt_left && conn_cwnd_is_zero(conn)) {
- destlen = 0;
- } else {
- if (res == 0) {
- nwrite =
- conn_write_path_response(conn, path, pi, dest, origdestlen, ts);
- if (nwrite) {
- goto fin;
- }
- if (conn->pv) {
- nwrite =
- conn_write_path_challenge(conn, path, pi, dest, origdestlen, ts);
- if (nwrite) {
- goto fin;
- }
- }
- if (conn->pmtud &&
- (conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) &&
- (!conn->hs_pktns ||
- ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm))) {
- nwrite = conn_write_pmtud_probe(conn, pi, dest, origdestlen, ts);
- if (nwrite) {
- goto fin;
- }
- }
- }
- }
- if (conn->server &&
- !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) {
- server_tx_left = conn_server_tx_left(conn, &conn->dcid.current);
- origlen = (size_t)ngtcp2_min_uint64((uint64_t)origlen, server_tx_left);
- destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left);
- if (server_tx_left == 0 &&
- conn->cstat.loss_detection_timer != UINT64_MAX) {
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss detection timer canceled due to amplification limit");
- ngtcp2_conn_cancel_loss_detection_timer(conn);
- }
- }
- }
- if (res == 0) {
- if (conn_handshake_remnants_left(conn)) {
- if (conn_handshake_probe_left(conn) ||
- /* Allow exceeding CWND if an Handshake packet needs to be
- sent in order to avoid dead lock. In some situation,
- typically for client, 1 RTT packets may occupy in-flight
- bytes (e.g., some large requests and PMTUD), and
- Handshake packet loss shrinks CWND, and we may get in the
- situation that we are unable to send Handshake packet. */
- (conn->hs_pktns->rtb.num_pto_eliciting == 0 &&
- !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm))) {
- destlen = origlen;
- }
- nwrite = conn_write_handshake_pkts(conn, pi, dest, destlen,
- /* write_datalen = */ 0, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- if (nwrite > 0) {
- res = nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- } else if (destlen == 0) {
- res = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
- if (res) {
- return res;
- }
- }
- }
- }
- if (conn->pktns.rtb.probe_pkt_left) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "transmit probe pkt left=%zu",
- conn->pktns.rtb.probe_pkt_left);
- nwrite = conn_write_pkt(conn, pi, dest, destlen, (size_t)res, vmsg,
- NGTCP2_PKT_1RTT, wflags, ts);
- goto fin;
- }
- nwrite = conn_write_pkt(conn, pi, dest, destlen, (size_t)res, vmsg,
- NGTCP2_PKT_1RTT, wflags, ts);
- if (nwrite) {
- assert(nwrite != NGTCP2_ERR_NOBUF);
- goto fin;
- }
- if (res == 0) {
- nwrite = conn_write_ack_pkt(conn, pi, dest, origlen, NGTCP2_PKT_1RTT, ts);
- }
- fin:
- if (nwrite >= 0) {
- res += nwrite;
- return res;
- }
- switch (nwrite) {
- case NGTCP2_ERR_STREAM_DATA_BLOCKED:
- if (!(wflags & NGTCP2_WRITE_PKT_FLAG_MORE)) {
- if (res) {
- return res;
- }
- break;
- }
- /* fall through */
- case NGTCP2_ERR_WRITE_MORE:
- conn->pkt.hs_spktlen = res;
- break;
- }
- return nwrite;
- }
- static ngtcp2_ssize
- conn_write_connection_close(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
- uint8_t *dest, size_t destlen, uint8_t pkt_type,
- uint64_t error_code, const uint8_t *reason,
- size_t reasonlen, ngtcp2_tstamp ts) {
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- ngtcp2_ssize res = 0, nwrite;
- ngtcp2_frame fr;
- uint8_t flags = NGTCP2_WRITE_PKT_FLAG_NONE;
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
- fr.connection_close.error_code = error_code;
- fr.connection_close.frame_type = 0;
- fr.connection_close.reasonlen = reasonlen;
- fr.connection_close.reason = (uint8_t *)reason;
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
- pkt_type != NGTCP2_PKT_INITIAL) {
- if (in_pktns && conn->server) {
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, NGTCP2_PKT_INITIAL, NGTCP2_WRITE_PKT_FLAG_NONE,
- &conn->dcid.current.cid, &fr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- dest += nwrite;
- destlen -= (size_t)nwrite;
- res += nwrite;
- }
- if (pkt_type != NGTCP2_PKT_HANDSHAKE && hs_pktns &&
- hs_pktns->crypto.tx.ckm) {
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, NGTCP2_PKT_HANDSHAKE,
- NGTCP2_WRITE_PKT_FLAG_NONE, &conn->dcid.current.cid, &fr,
- NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- dest += nwrite;
- destlen -= (size_t)nwrite;
- res += nwrite;
- }
- }
- if (!conn->server && pkt_type == NGTCP2_PKT_INITIAL) {
- flags = NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, pkt_type, flags, &conn->dcid.current.cid, &fr,
- NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res += nwrite;
- if (res == 0) {
- return NGTCP2_ERR_NOBUF;
- }
- return res;
- }
- ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt(
- ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, uint64_t error_code, const uint8_t *reason, size_t reasonlen,
- ngtcp2_tstamp ts) {
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- uint8_t pkt_type;
- ngtcp2_ssize nwrite;
- uint64_t server_tx_left;
- if (conn_check_pkt_num_exhausted(conn)) {
- return NGTCP2_ERR_PKT_NUM_EXHAUSTED;
- }
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- return NGTCP2_ERR_INVALID_STATE;
- case NGTCP2_CS_CLOSING:
- case NGTCP2_CS_DRAINING:
- return 0;
- default:
- break;
- }
- if (path) {
- ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
- }
- destlen = conn_shape_udp_payload(conn, &conn->dcid.current, destlen);
- if (pi) {
- pi->ecn = NGTCP2_ECN_NOT_ECT;
- }
- if (conn->server) {
- server_tx_left = conn_server_tx_left(conn, &conn->dcid.current);
- destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left);
- }
- if (conn->state == NGTCP2_CS_POST_HANDSHAKE ||
- (conn->server && conn->pktns.crypto.tx.ckm)) {
- pkt_type = NGTCP2_PKT_1RTT;
- } else if (hs_pktns && hs_pktns->crypto.tx.ckm) {
- pkt_type = NGTCP2_PKT_HANDSHAKE;
- } else if (in_pktns && in_pktns->crypto.tx.ckm) {
- pkt_type = NGTCP2_PKT_INITIAL;
- } else {
- /* This branch is taken if server has not read any Initial packet
- from client. */
- return NGTCP2_ERR_INVALID_STATE;
- }
- nwrite = conn_write_connection_close(conn, pi, dest, destlen, pkt_type,
- error_code, reason, reasonlen, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- conn->state = NGTCP2_CS_CLOSING;
- return nwrite;
- }
- ngtcp2_ssize ngtcp2_conn_write_application_close_pkt(
- ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest,
- size_t destlen, uint64_t app_error_code, const uint8_t *reason,
- size_t reasonlen, ngtcp2_tstamp ts) {
- ngtcp2_ssize nwrite;
- ngtcp2_ssize res = 0;
- ngtcp2_frame fr;
- uint64_t server_tx_left;
- if (conn_check_pkt_num_exhausted(conn)) {
- return NGTCP2_ERR_PKT_NUM_EXHAUSTED;
- }
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- return NGTCP2_ERR_INVALID_STATE;
- case NGTCP2_CS_CLOSING:
- case NGTCP2_CS_DRAINING:
- return 0;
- default:
- break;
- }
- if (path) {
- ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
- }
- destlen = conn_shape_udp_payload(conn, &conn->dcid.current, destlen);
- if (pi) {
- pi->ecn = NGTCP2_ECN_NOT_ECT;
- }
- if (conn->server) {
- server_tx_left = conn_server_tx_left(conn, &conn->dcid.current);
- destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left);
- }
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)) {
- nwrite = conn_write_connection_close(
- conn, pi, dest, destlen,
- conn->hs_pktns->crypto.tx.ckm ? NGTCP2_PKT_HANDSHAKE : NGTCP2_PKT_INITIAL,
- NGTCP2_APPLICATION_ERROR, NULL, 0, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res = nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
- }
- if (conn->state != NGTCP2_CS_POST_HANDSHAKE &&
- (!conn->server || !conn->pktns.crypto.tx.ckm)) {
- return res;
- }
- assert(conn->pktns.crypto.tx.ckm);
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE_APP;
- fr.connection_close.error_code = app_error_code;
- fr.connection_close.frame_type = 0;
- fr.connection_close.reasonlen = reasonlen;
- fr.connection_close.reason = (uint8_t *)reason;
- nwrite = ngtcp2_conn_write_single_frame_pkt(
- conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
- &conn->dcid.current.cid, &fr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
- if (nwrite < 0) {
- return nwrite;
- }
- res += nwrite;
- if (res == 0) {
- return NGTCP2_ERR_NOBUF;
- }
- conn->state = NGTCP2_CS_CLOSING;
- return res;
- }
- static void ccerr_init(ngtcp2_ccerr *ccerr, ngtcp2_ccerr_type type,
- uint64_t error_code, const uint8_t *reason,
- size_t reasonlen) {
- ccerr->type = type;
- ccerr->error_code = error_code;
- ccerr->frame_type = 0;
- ccerr->reason = (uint8_t *)reason;
- ccerr->reasonlen = reasonlen;
- }
- void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr) {
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_TRANSPORT, NGTCP2_NO_ERROR, NULL, 0);
- }
- void ngtcp2_ccerr_set_transport_error(ngtcp2_ccerr *ccerr, uint64_t error_code,
- const uint8_t *reason, size_t reasonlen) {
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_TRANSPORT, error_code, reason, reasonlen);
- }
- void ngtcp2_ccerr_set_liberr(ngtcp2_ccerr *ccerr, int liberr,
- const uint8_t *reason, size_t reasonlen) {
- switch (liberr) {
- case NGTCP2_ERR_RECV_VERSION_NEGOTIATION:
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION, NGTCP2_NO_ERROR,
- reason, reasonlen);
- return;
- case NGTCP2_ERR_IDLE_CLOSE:
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_IDLE_CLOSE, NGTCP2_NO_ERROR, reason,
- reasonlen);
- return;
- case NGTCP2_ERR_DROP_CONN:
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_DROP_CONN, NGTCP2_NO_ERROR, reason,
- reasonlen);
- return;
- case NGTCP2_ERR_RETRY:
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_RETRY, NGTCP2_NO_ERROR, reason,
- reasonlen);
- return;
- };
- ngtcp2_ccerr_set_transport_error(
- ccerr, ngtcp2_err_infer_quic_transport_error_code(liberr), reason,
- reasonlen);
- }
- void ngtcp2_ccerr_set_tls_alert(ngtcp2_ccerr *ccerr, uint8_t tls_alert,
- const uint8_t *reason, size_t reasonlen) {
- ngtcp2_ccerr_set_transport_error(ccerr, NGTCP2_CRYPTO_ERROR | tls_alert,
- reason, reasonlen);
- }
- void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr,
- uint64_t error_code,
- const uint8_t *reason,
- size_t reasonlen) {
- ccerr_init(ccerr, NGTCP2_CCERR_TYPE_APPLICATION, error_code, reason,
- reasonlen);
- }
- ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned(
- ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
- ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, const ngtcp2_ccerr *ccerr,
- ngtcp2_tstamp ts) {
- (void)pkt_info_version;
- conn_update_timestamp(conn, ts);
- switch (ccerr->type) {
- case NGTCP2_CCERR_TYPE_TRANSPORT:
- return ngtcp2_conn_write_connection_close_pkt(
- conn, path, pi, dest, destlen, ccerr->error_code, ccerr->reason,
- ccerr->reasonlen, ts);
- case NGTCP2_CCERR_TYPE_APPLICATION:
- return ngtcp2_conn_write_application_close_pkt(
- conn, path, pi, dest, destlen, ccerr->error_code, ccerr->reason,
- ccerr->reasonlen, ts);
- default:
- return 0;
- }
- }
- int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn) {
- return conn->state == NGTCP2_CS_CLOSING;
- }
- int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn) {
- return conn->state == NGTCP2_CS_DRAINING;
- }
- int ngtcp2_conn_close_stream(ngtcp2_conn *conn, ngtcp2_strm *strm) {
- int rv;
- rv = conn_call_stream_close(conn, strm);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_map_remove(&conn->strms, (ngtcp2_map_key_type)strm->stream_id);
- if (rv != 0) {
- assert(rv != NGTCP2_ERR_INVALID_ARGUMENT);
- return rv;
- }
- if (ngtcp2_strm_is_tx_queued(strm)) {
- ngtcp2_pq_remove(&conn->tx.strmq, &strm->pe);
- }
- ngtcp2_strm_free(strm);
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm);
- return 0;
- }
- int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn,
- ngtcp2_strm *strm) {
- if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RDWR) ==
- NGTCP2_STRM_FLAG_SHUT_RDWR &&
- ((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) ||
- ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) &&
- (((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM) &&
- (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_ACKED)) ||
- ngtcp2_strm_is_all_tx_data_fin_acked(strm))) {
- return ngtcp2_conn_close_stream(conn, strm);
- }
- return 0;
- }
- /*
- * conn_shutdown_stream_write closes send stream with error code
- * |app_error_code|. RESET_STREAM frame is scheduled.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t app_error_code) {
- ngtcp2_strm_set_app_error_code(strm, app_error_code);
- if ((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM) ||
- ngtcp2_strm_is_all_tx_data_fin_acked(strm)) {
- return 0;
- }
- /* Set this flag so that we don't accidentally send DATA to this
- stream. */
- strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_RESET_STREAM;
- ngtcp2_strm_streamfrq_clear(strm);
- return conn_reset_stream(conn, strm, app_error_code);
- }
- /*
- * conn_shutdown_stream_read closes read stream with error code
- * |app_error_code|. STOP_SENDING frame is scheduled.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_shutdown_stream_read(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t app_error_code) {
- ngtcp2_strm_set_app_error_code(strm, app_error_code);
- if (strm->flags &
- (NGTCP2_STRM_FLAG_STOP_SENDING | NGTCP2_STRM_FLAG_RESET_STREAM_RECVED)) {
- return 0;
- }
- if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
- ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) {
- return 0;
- }
- /* Extend connection flow control window for the amount of data
- which are not passed to application. */
- if (!(strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED)) {
- ngtcp2_conn_extend_max_offset(conn, strm->rx.last_offset -
- ngtcp2_strm_rx_offset(strm));
- }
- strm->flags |= NGTCP2_STRM_FLAG_STOP_SENDING;
- ngtcp2_strm_discard_reordered_data(strm);
- return conn_stop_sending(conn, strm, app_error_code);
- }
- int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, uint32_t flags,
- int64_t stream_id, uint64_t app_error_code) {
- int rv;
- ngtcp2_strm *strm;
- (void)flags;
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return 0;
- }
- if (bidi_stream(stream_id) || !conn_local_stream(conn, stream_id)) {
- rv = conn_shutdown_stream_read(conn, strm, app_error_code);
- if (rv != 0) {
- return rv;
- }
- }
- if (bidi_stream(stream_id) || conn_local_stream(conn, stream_id)) {
- rv = conn_shutdown_stream_write(conn, strm, app_error_code);
- if (rv != 0) {
- return rv;
- }
- }
- return 0;
- }
- int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, uint32_t flags,
- int64_t stream_id,
- uint64_t app_error_code) {
- ngtcp2_strm *strm;
- (void)flags;
- if (!bidi_stream(stream_id) && !conn_local_stream(conn, stream_id)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return 0;
- }
- return conn_shutdown_stream_write(conn, strm, app_error_code);
- }
- int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, uint32_t flags,
- int64_t stream_id,
- uint64_t app_error_code) {
- ngtcp2_strm *strm;
- (void)flags;
- if (!bidi_stream(stream_id) && conn_local_stream(conn, stream_id)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return 0;
- }
- return conn_shutdown_stream_read(conn, strm, app_error_code);
- }
- /*
- * conn_extend_max_stream_offset extends stream level flow control
- * window by |datalen| of the stream denoted by |strm|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
- static int conn_extend_max_stream_offset(ngtcp2_conn *conn, ngtcp2_strm *strm,
- uint64_t datalen) {
- ngtcp2_strm *top;
- if (datalen > NGTCP2_MAX_VARINT ||
- strm->rx.unsent_max_offset > NGTCP2_MAX_VARINT - datalen) {
- strm->rx.unsent_max_offset = NGTCP2_MAX_VARINT;
- } else {
- strm->rx.unsent_max_offset += datalen;
- }
- if (!(strm->flags &
- (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) &&
- !ngtcp2_strm_is_tx_queued(strm) &&
- conn_should_send_max_stream_data(conn, strm)) {
- if (!ngtcp2_pq_empty(&conn->tx.strmq)) {
- top = ngtcp2_conn_tx_strmq_top(conn);
- strm->cycle = top->cycle;
- }
- strm->cycle = conn_tx_strmq_first_cycle(conn);
- return ngtcp2_conn_tx_strmq_push(conn, strm);
- }
- return 0;
- }
- int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id,
- uint64_t datalen) {
- ngtcp2_strm *strm;
- if (!bidi_stream(stream_id) && conn_local_stream(conn, stream_id)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return 0;
- }
- return conn_extend_max_stream_offset(conn, strm, datalen);
- }
- void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, uint64_t datalen) {
- if (NGTCP2_MAX_VARINT < datalen ||
- conn->rx.unsent_max_offset > NGTCP2_MAX_VARINT - datalen) {
- conn->rx.unsent_max_offset = NGTCP2_MAX_VARINT;
- return;
- }
- conn->rx.unsent_max_offset += datalen;
- }
- void ngtcp2_conn_extend_max_streams_bidi(ngtcp2_conn *conn, size_t n) {
- handle_max_remote_streams_extension(&conn->remote.bidi.unsent_max_streams, n);
- }
- void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, size_t n) {
- handle_max_remote_streams_extension(&conn->remote.uni.unsent_max_streams, n);
- }
- const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn) {
- return &conn->dcid.current.cid;
- }
- const ngtcp2_cid *ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn) {
- return &conn->rcid;
- }
- uint32_t ngtcp2_conn_get_client_chosen_version(ngtcp2_conn *conn) {
- return conn->client_chosen_version;
- }
- uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn) {
- return conn->negotiated_version;
- }
- static int delete_strms_pq_each(void *data, void *ptr) {
- ngtcp2_conn *conn = ptr;
- ngtcp2_strm *s = data;
- if (ngtcp2_strm_is_tx_queued(s)) {
- ngtcp2_pq_remove(&conn->tx.strmq, &s->pe);
- }
- ngtcp2_strm_free(s);
- ngtcp2_objalloc_strm_release(&conn->strm_objalloc, s);
- return 0;
- }
- /*
- * conn_discard_early_data_state discards any connection states which
- * are altered by any operations during early data transfer.
- */
- static void conn_discard_early_data_state(ngtcp2_conn *conn) {
- ngtcp2_frame_chain **pfrc, *frc;
- ngtcp2_rtb_remove_early_data(&conn->pktns.rtb, &conn->cstat);
- ngtcp2_map_each(&conn->strms, delete_strms_pq_each, conn);
- ngtcp2_map_clear(&conn->strms);
- conn->tx.offset = 0;
- conn->tx.last_blocked_offset = UINT64_MAX;
- conn->rx.unsent_max_offset = conn->rx.max_offset =
- conn->local.transport_params.initial_max_data;
- conn->remote.bidi.unsent_max_streams = conn->remote.bidi.max_streams =
- conn->local.transport_params.initial_max_streams_bidi;
- conn->remote.uni.unsent_max_streams = conn->remote.uni.max_streams =
- conn->local.transport_params.initial_max_streams_uni;
- if (conn->server) {
- conn->local.bidi.next_stream_id = 1;
- conn->local.uni.next_stream_id = 3;
- } else {
- conn->local.bidi.next_stream_id = 0;
- conn->local.uni.next_stream_id = 2;
- }
- for (pfrc = &conn->pktns.tx.frq; *pfrc;) {
- frc = *pfrc;
- *pfrc = (*pfrc)->next;
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- }
- }
- int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn) {
- if (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) {
- return 0;
- }
- conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED;
- conn_discard_early_data_state(conn);
- if (conn->callbacks.tls_early_data_rejected) {
- return conn->callbacks.tls_early_data_rejected(conn, conn->user_data);
- }
- if (conn->early.ckm) {
- conn_discard_early_key(conn);
- }
- return 0;
- }
- int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn) {
- return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0;
- }
- int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
- ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
- ngtcp2_conn_stat *cstat = &conn->cstat;
- assert(rtt > 0);
- if (cstat->min_rtt == UINT64_MAX) {
- cstat->latest_rtt = rtt;
- cstat->min_rtt = rtt;
- cstat->smoothed_rtt = rtt;
- cstat->rttvar = rtt / 2;
- cstat->first_rtt_sample_ts = ts;
- } else {
- if (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) {
- assert(conn->remote.transport_params);
- ack_delay = ngtcp2_min_uint64(
- ack_delay, conn->remote.transport_params->max_ack_delay);
- } else if (ack_delay > 0 && rtt >= cstat->min_rtt &&
- rtt < cstat->min_rtt + ack_delay) {
- /* Ignore RTT sample if adjusting ack_delay causes the sample
- less than min_rtt before handshake confirmation. */
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_LDC,
- "ignore rtt sample because ack_delay is too large latest_rtt=%" PRIu64
- " min_rtt=%" PRIu64 " ack_delay=%" PRIu64,
- rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS,
- ack_delay / NGTCP2_MILLISECONDS);
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- cstat->latest_rtt = rtt;
- cstat->min_rtt = ngtcp2_min_uint64(cstat->min_rtt, rtt);
- if (rtt >= cstat->min_rtt + ack_delay) {
- rtt -= ack_delay;
- }
- cstat->rttvar = (cstat->rttvar * 3 + (cstat->smoothed_rtt < rtt
- ? rtt - cstat->smoothed_rtt
- : cstat->smoothed_rtt - rtt)) /
- 4;
- cstat->smoothed_rtt = (cstat->smoothed_rtt * 7 + rtt) / 8;
- }
- ngtcp2_log_info(
- &conn->log, NGTCP2_LOG_EVENT_LDC,
- "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64
- " rttvar=%" PRIu64 " ack_delay=%" PRIu64,
- cstat->latest_rtt / NGTCP2_MILLISECONDS,
- cstat->min_rtt / NGTCP2_MILLISECONDS,
- cstat->smoothed_rtt / NGTCP2_MILLISECONDS,
- cstat->rttvar / NGTCP2_MILLISECONDS, ack_delay / NGTCP2_MILLISECONDS);
- return 0;
- }
- void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn,
- int conn_info_version,
- ngtcp2_conn_info *cinfo) {
- const ngtcp2_conn_stat *cstat = &conn->cstat;
- (void)conn_info_version;
- cinfo->latest_rtt = cstat->latest_rtt;
- cinfo->min_rtt = cstat->min_rtt;
- cinfo->smoothed_rtt = cstat->smoothed_rtt;
- cinfo->rttvar = cstat->rttvar;
- cinfo->cwnd = cstat->cwnd;
- cinfo->ssthresh = cstat->ssthresh;
- cinfo->bytes_in_flight = cstat->bytes_in_flight;
- }
- static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn,
- ngtcp2_tstamp *ploss_time,
- ngtcp2_pktns **ppktns) {
- ngtcp2_pktns *const ns[] = {conn->hs_pktns, &conn->pktns};
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_duration *loss_time = cstat->loss_time + 1;
- ngtcp2_tstamp earliest_loss_time = cstat->loss_time[NGTCP2_PKTNS_ID_INITIAL];
- ngtcp2_pktns *pktns = conn->in_pktns;
- size_t i;
- for (i = 0; i < ngtcp2_arraylen(ns); ++i) {
- if (ns[i] == NULL || loss_time[i] >= earliest_loss_time) {
- continue;
- }
- earliest_loss_time = loss_time[i];
- pktns = ns[i];
- }
- if (ploss_time) {
- *ploss_time = earliest_loss_time;
- }
- if (ppktns) {
- *ppktns = pktns;
- }
- }
- static ngtcp2_tstamp conn_get_earliest_pto_expiry(ngtcp2_conn *conn,
- ngtcp2_tstamp ts) {
- ngtcp2_pktns *ns[] = {conn->in_pktns, conn->hs_pktns, &conn->pktns};
- size_t i;
- ngtcp2_tstamp earliest_ts = UINT64_MAX, t;
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_tstamp *times = cstat->last_tx_pkt_ts;
- ngtcp2_duration duration =
- compute_pto(cstat->smoothed_rtt, cstat->rttvar, /* max_ack_delay = */ 0) *
- (1ULL << cstat->pto_count);
- for (i = NGTCP2_PKTNS_ID_INITIAL; i < NGTCP2_PKTNS_ID_MAX; ++i) {
- if (ns[i] == NULL || ns[i]->rtb.num_pto_eliciting == 0 ||
- (times[i] == UINT64_MAX ||
- (i == NGTCP2_PKTNS_ID_APPLICATION &&
- !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) {
- continue;
- }
- t = times[i] + duration;
- if (i == NGTCP2_PKTNS_ID_APPLICATION) {
- assert(conn->remote.transport_params);
- t += conn->remote.transport_params->max_ack_delay *
- (1ULL << cstat->pto_count);
- }
- if (t < earliest_ts) {
- earliest_ts = t;
- }
- }
- if (earliest_ts == UINT64_MAX) {
- return ts + duration;
- }
- return earliest_ts;
- }
- void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- ngtcp2_conn_stat *cstat = &conn->cstat;
- ngtcp2_duration timeout;
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- ngtcp2_pktns *pktns = &conn->pktns;
- ngtcp2_tstamp earliest_loss_time;
- conn_get_loss_time_and_pktns(conn, &earliest_loss_time, NULL);
- if (earliest_loss_time != UINT64_MAX) {
- cstat->loss_detection_timer = earliest_loss_time;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss_detection_timer=%" PRIu64 " nonzero crypto loss time",
- cstat->loss_detection_timer);
- return;
- }
- if ((!in_pktns || in_pktns->rtb.num_pto_eliciting == 0) &&
- (!hs_pktns || hs_pktns->rtb.num_pto_eliciting == 0) &&
- (pktns->rtb.num_pto_eliciting == 0 ||
- !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)) &&
- (conn->server ||
- (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED |
- NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) {
- if (cstat->loss_detection_timer != UINT64_MAX) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss detection timer canceled");
- ngtcp2_conn_cancel_loss_detection_timer(conn);
- }
- return;
- }
- cstat->loss_detection_timer = conn_get_earliest_pto_expiry(conn, ts);
- timeout =
- cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64,
- cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS);
- }
- void ngtcp2_conn_cancel_loss_detection_timer(ngtcp2_conn *conn) {
- ngtcp2_conn_stat *cstat = &conn->cstat;
- cstat->loss_detection_timer = UINT64_MAX;
- cstat->pto_count = 0;
- }
- int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- ngtcp2_conn_stat *cstat = &conn->cstat;
- int rv;
- ngtcp2_pktns *in_pktns = conn->in_pktns;
- ngtcp2_pktns *hs_pktns = conn->hs_pktns;
- ngtcp2_tstamp earliest_loss_time;
- ngtcp2_pktns *loss_pktns = NULL;
- switch (conn->state) {
- case NGTCP2_CS_CLOSING:
- case NGTCP2_CS_DRAINING:
- ngtcp2_conn_cancel_loss_detection_timer(conn);
- return 0;
- default:
- break;
- }
- if (cstat->loss_detection_timer == UINT64_MAX) {
- return 0;
- }
- conn_get_loss_time_and_pktns(conn, &earliest_loss_time, &loss_pktns);
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
- "loss detection timer fired");
- if (earliest_loss_time != UINT64_MAX) {
- assert(loss_pktns);
- rv = ngtcp2_conn_detect_lost_pkt(conn, loss_pktns, cstat, ts);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- return 0;
- }
- if (!conn->server && !conn_is_tls_handshake_completed(conn)) {
- if (hs_pktns->crypto.tx.ckm) {
- hs_pktns->rtb.probe_pkt_left = 1;
- } else {
- in_pktns->rtb.probe_pkt_left = 1;
- }
- } else {
- if (in_pktns && in_pktns->rtb.num_pto_eliciting) {
- in_pktns->rtb.probe_pkt_left = 1;
- assert(hs_pktns);
- if (conn->server && hs_pktns->rtb.num_pto_eliciting) {
- /* let server coalesce packets */
- hs_pktns->rtb.probe_pkt_left = 1;
- }
- } else if (hs_pktns && hs_pktns->rtb.num_pto_eliciting) {
- hs_pktns->rtb.probe_pkt_left = 2;
- } else {
- conn->pktns.rtb.probe_pkt_left = 2;
- }
- }
- ++cstat->pto_count;
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu",
- cstat->pto_count);
- ngtcp2_conn_set_loss_detection_timer(conn, ts);
- return 0;
- }
- static int conn_buffer_crypto_data(ngtcp2_conn *conn, const uint8_t **pdata,
- ngtcp2_pktns *pktns, const uint8_t *data,
- size_t datalen) {
- int rv;
- ngtcp2_buf_chain **pbufchain = &pktns->crypto.tx.data;
- if (*pbufchain) {
- for (; (*pbufchain)->next; pbufchain = &(*pbufchain)->next)
- ;
- if (ngtcp2_buf_left(&(*pbufchain)->buf) < datalen) {
- pbufchain = &(*pbufchain)->next;
- }
- }
- if (!*pbufchain) {
- rv = ngtcp2_buf_chain_new(pbufchain, ngtcp2_max_size(1024, datalen),
- conn->mem);
- if (rv != 0) {
- return rv;
- }
- }
- *pdata = (*pbufchain)->buf.last;
- (*pbufchain)->buf.last = ngtcp2_cpymem((*pbufchain)->buf.last, data, datalen);
- return 0;
- }
- int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn,
- ngtcp2_encryption_level encryption_level,
- const uint8_t *data, const size_t datalen) {
- ngtcp2_pktns *pktns;
- ngtcp2_frame_chain *frc;
- ngtcp2_stream *fr;
- int rv;
- if (datalen == 0) {
- return 0;
- }
- switch (encryption_level) {
- case NGTCP2_ENCRYPTION_LEVEL_INITIAL:
- assert(conn->in_pktns);
- pktns = conn->in_pktns;
- break;
- case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE:
- assert(conn->hs_pktns);
- pktns = conn->hs_pktns;
- break;
- case NGTCP2_ENCRYPTION_LEVEL_1RTT:
- pktns = &conn->pktns;
- break;
- default:
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- rv = conn_buffer_crypto_data(conn, &data, pktns, data, datalen);
- if (rv != 0) {
- return rv;
- }
- rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc);
- if (rv != 0) {
- return rv;
- }
- fr = &frc->fr.stream;
- fr->type = NGTCP2_FRAME_CRYPTO;
- fr->flags = 0;
- fr->fin = 0;
- fr->stream_id = 0;
- fr->offset = pktns->crypto.tx.offset;
- fr->datacnt = 1;
- fr->data[0].len = datalen;
- fr->data[0].base = (uint8_t *)data;
- rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc);
- if (rv != 0) {
- ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem);
- return rv;
- }
- pktns->crypto.strm.tx.offset += datalen;
- pktns->crypto.tx.offset += datalen;
- return 0;
- }
- int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, const uint8_t *token,
- size_t tokenlen) {
- int rv;
- ngtcp2_frame_chain *nfrc;
- assert(conn->server);
- assert(token);
- assert(tokenlen);
- rv = ngtcp2_frame_chain_new_token_objalloc_new(
- &nfrc, token, tokenlen, &conn->frc_objalloc, conn->mem);
- if (rv != 0) {
- return rv;
- }
- nfrc->next = conn->pktns.tx.frq;
- conn->pktns.tx.frq = nfrc;
- return 0;
- }
- ngtcp2_strm *ngtcp2_conn_tx_strmq_top(ngtcp2_conn *conn) {
- assert(!ngtcp2_pq_empty(&conn->tx.strmq));
- return ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe);
- }
- void ngtcp2_conn_tx_strmq_pop(ngtcp2_conn *conn) {
- ngtcp2_strm *strm = ngtcp2_conn_tx_strmq_top(conn);
- assert(strm);
- ngtcp2_pq_pop(&conn->tx.strmq);
- strm->pe.index = NGTCP2_PQ_BAD_INDEX;
- }
- int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm) {
- return ngtcp2_pq_push(&conn->tx.strmq, &strm->pe);
- }
- static int conn_has_uncommitted_preferred_addr_cid(ngtcp2_conn *conn) {
- return conn->server &&
- !(conn->flags & NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED) &&
- conn->oscid.datalen &&
- conn->local.transport_params.preferred_addr_present;
- }
- size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) {
- ngtcp2_cid *origdest = dest;
- ngtcp2_ksl_it it;
- ngtcp2_scid *scid;
- if (dest == NULL) {
- return ngtcp2_ksl_len(&conn->scid.set) +
- (size_t)conn_has_uncommitted_preferred_addr_cid(conn);
- }
- for (it = ngtcp2_ksl_begin(&conn->scid.set); !ngtcp2_ksl_it_end(&it);
- ngtcp2_ksl_it_next(&it)) {
- scid = ngtcp2_ksl_it_get(&it);
- *dest++ = scid->cid;
- }
- if (conn_has_uncommitted_preferred_addr_cid(conn)) {
- *dest++ = conn->local.transport_params.preferred_addr.cid;
- }
- return (size_t)(dest - origdest);
- }
- static size_t conn_get_num_active_dcid(ngtcp2_conn *conn) {
- size_t n = 1; /* for conn->dcid.current */
- ngtcp2_pv *pv = conn->pv;
- if (pv) {
- if (pv->dcid.seq != conn->dcid.current.seq) {
- ++n;
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->fallback_dcid.seq != conn->dcid.current.seq &&
- pv->fallback_dcid.seq != pv->dcid.seq) {
- ++n;
- }
- }
- n += ngtcp2_ringbuf_len(&conn->dcid.retired.rb);
- return n;
- }
- static void copy_dcid_to_cid_token(ngtcp2_cid_token *dest,
- const ngtcp2_dcid *src) {
- dest->seq = src->seq;
- dest->cid = src->cid;
- ngtcp2_path_storage_init2(&dest->ps, &src->ps.path);
- if ((dest->token_present =
- (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) != 0)) {
- memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
- }
- }
- size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) {
- ngtcp2_pv *pv = conn->pv;
- ngtcp2_cid_token *orig = dest;
- ngtcp2_dcid *dcid;
- size_t len, i;
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
- return 0;
- }
- if (dest == NULL) {
- return conn_get_num_active_dcid(conn);
- }
- copy_dcid_to_cid_token(dest, &conn->dcid.current);
- ++dest;
- if (pv) {
- if (pv->dcid.seq != conn->dcid.current.seq) {
- copy_dcid_to_cid_token(dest, &pv->dcid);
- ++dest;
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->fallback_dcid.seq != conn->dcid.current.seq &&
- pv->fallback_dcid.seq != pv->dcid.seq) {
- copy_dcid_to_cid_token(dest, &pv->fallback_dcid);
- ++dest;
- }
- }
- len = ngtcp2_ringbuf_len(&conn->dcid.retired.rb);
- for (i = 0; i < len; ++i) {
- dcid = ngtcp2_ringbuf_get(&conn->dcid.retired.rb, i);
- copy_dcid_to_cid_token(dest, dcid);
- ++dest;
- }
- return (size_t)(dest - orig);
- }
- void ngtcp2_conn_set_local_addr(ngtcp2_conn *conn, const ngtcp2_addr *addr) {
- ngtcp2_addr *dest = &conn->dcid.current.ps.path.local;
- assert(addr->addrlen <=
- (ngtcp2_socklen)sizeof(conn->dcid.current.ps.local_addrbuf));
- ngtcp2_addr_copy(dest, addr);
- }
- void ngtcp2_conn_set_path_user_data(ngtcp2_conn *conn, void *path_user_data) {
- conn->dcid.current.ps.path.user_data = path_user_data;
- }
- const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn) {
- return &conn->dcid.current.ps.path;
- }
- size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn) {
- return conn->local.settings.max_tx_udp_payload_size;
- }
- size_t ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn) {
- if (conn->local.settings.no_tx_udp_payload_size_shaping) {
- return ngtcp2_conn_get_max_tx_udp_payload_size(conn);
- }
- return conn->dcid.current.max_udp_payload_size;
- }
- static int conn_initiate_migration_precheck(ngtcp2_conn *conn,
- const ngtcp2_addr *local_addr) {
- if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) ||
- conn->remote.transport_params->disable_active_migration ||
- conn->dcid.current.cid.datalen == 0 ||
- (conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_PREFERRED_ADDR))) {
- return NGTCP2_ERR_INVALID_STATE;
- }
- if (ngtcp2_ringbuf_len(&conn->dcid.unused.rb) == 0) {
- return NGTCP2_ERR_CONN_ID_BLOCKED;
- }
- if (ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, local_addr)) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
- return 0;
- }
- int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn,
- const ngtcp2_path *path,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_dcid *dcid;
- ngtcp2_pv *pv;
- assert(!conn->server);
- conn_update_timestamp(conn, ts);
- rv = conn_initiate_migration_precheck(conn, &path->local);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_conn_stop_pmtud(conn);
- if (conn->pv) {
- rv = conn_abort_pv(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- rv = conn_retire_dcid(conn, &conn->dcid.current, ts);
- if (rv != 0) {
- return rv;
- }
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- ngtcp2_dcid_set_path(dcid, path);
- ngtcp2_dcid_copy(&conn->dcid.current, dcid);
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- conn_reset_congestion_state(conn, ts);
- conn_reset_ecn_validation_state(conn);
- /* TODO It might be better to add a new flag which indicates that a
- connection should be closed if this path validation failed. The
- current design allows an application to continue, by migrating
- into yet another path. */
- rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn),
- NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem);
- if (rv != 0) {
- return rv;
- }
- conn->pv = pv;
- return conn_call_activate_dcid(conn, &conn->dcid.current);
- }
- int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path,
- ngtcp2_tstamp ts) {
- int rv;
- ngtcp2_dcid *dcid;
- ngtcp2_pv *pv;
- assert(!conn->server);
- conn_update_timestamp(conn, ts);
- rv = conn_initiate_migration_precheck(conn, &path->local);
- if (rv != 0) {
- return rv;
- }
- if (conn->pv) {
- rv = conn_abort_pv(conn, ts);
- if (rv != 0) {
- return rv;
- }
- }
- dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0);
- ngtcp2_dcid_set_path(dcid, path);
- rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn),
- NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem);
- if (rv != 0) {
- return rv;
- }
- ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb);
- conn->pv = pv;
- return conn_call_activate_dcid(conn, &pv->dcid);
- }
- uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) {
- return conn->tx.max_offset - conn->tx.offset;
- }
- uint64_t ngtcp2_conn_get_max_stream_data_left(ngtcp2_conn *conn,
- int64_t stream_id) {
- ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return 0;
- }
- return strm->tx.max_offset - strm->tx.offset;
- }
- uint64_t ngtcp2_conn_get_streams_bidi_left(ngtcp2_conn *conn) {
- uint64_t n = ngtcp2_ord_stream_id(conn->local.bidi.next_stream_id);
- return n > conn->local.bidi.max_streams
- ? 0
- : conn->local.bidi.max_streams - n + 1;
- }
- uint64_t ngtcp2_conn_get_streams_uni_left(ngtcp2_conn *conn) {
- uint64_t n = ngtcp2_ord_stream_id(conn->local.uni.next_stream_id);
- return n > conn->local.uni.max_streams ? 0
- : conn->local.uni.max_streams - n + 1;
- }
- uint64_t ngtcp2_conn_get_cwnd_left(ngtcp2_conn *conn) {
- uint64_t bytes_in_flight = conn->cstat.bytes_in_flight;
- uint64_t cwnd = conn_get_cwnd(conn);
- if (cwnd > bytes_in_flight) {
- return cwnd - bytes_in_flight;
- }
- return 0;
- }
- ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) {
- ngtcp2_duration trpto;
- ngtcp2_duration idle_timeout;
- /* TODO Remote max_idle_timeout becomes effective after handshake
- completion. */
- if (!conn_is_tls_handshake_completed(conn) ||
- conn->remote.transport_params->max_idle_timeout == 0 ||
- (conn->local.transport_params.max_idle_timeout &&
- conn->local.transport_params.max_idle_timeout <
- conn->remote.transport_params->max_idle_timeout)) {
- idle_timeout = conn->local.transport_params.max_idle_timeout;
- } else {
- idle_timeout = conn->remote.transport_params->max_idle_timeout;
- }
- if (idle_timeout == 0) {
- return UINT64_MAX;
- }
- trpto = 3 * conn_compute_pto(conn, conn_is_tls_handshake_completed(conn)
- ? &conn->pktns
- : conn->hs_pktns);
- idle_timeout = ngtcp2_max_uint64(idle_timeout, trpto);
- if (conn->idle_ts >= UINT64_MAX - idle_timeout) {
- return UINT64_MAX;
- }
- return conn->idle_ts + idle_timeout;
- }
- ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn) {
- return conn_compute_pto(conn, conn_is_tls_handshake_completed(conn)
- ? &conn->pktns
- : conn->hs_pktns);
- }
- void ngtcp2_conn_set_initial_crypto_ctx(ngtcp2_conn *conn,
- const ngtcp2_crypto_ctx *ctx) {
- assert(conn->in_pktns);
- conn->in_pktns->crypto.ctx = *ctx;
- }
- const ngtcp2_crypto_ctx *ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn) {
- assert(conn->in_pktns);
- return &conn->in_pktns->crypto.ctx;
- }
- void ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn,
- const ngtcp2_crypto_aead *aead,
- const ngtcp2_crypto_aead_ctx *aead_ctx) {
- assert(!conn->crypto.retry_aead_ctx.native_handle);
- conn->crypto.retry_aead = *aead;
- conn->crypto.retry_aead_ctx = *aead_ctx;
- }
- void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn,
- const ngtcp2_crypto_ctx *ctx) {
- assert(conn->hs_pktns);
- conn->hs_pktns->crypto.ctx = *ctx;
- conn->pktns.crypto.ctx = *ctx;
- }
- const ngtcp2_crypto_ctx *ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn) {
- return &conn->pktns.crypto.ctx;
- }
- void ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn,
- const ngtcp2_crypto_ctx *ctx) {
- conn->early.ctx = *ctx;
- }
- const ngtcp2_crypto_ctx *ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn) {
- return &conn->early.ctx;
- }
- void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn) {
- return conn->crypto.tls_native_handle;
- }
- void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn,
- void *tls_native_handle) {
- conn->crypto.tls_native_handle = tls_native_handle;
- }
- const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn) {
- return &conn->rx.ccerr;
- }
- void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr) {
- conn->crypto.tls_error = liberr;
- }
- int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn) {
- return conn->crypto.tls_error;
- }
- void ngtcp2_conn_set_tls_alert(ngtcp2_conn *conn, uint8_t alert) {
- conn->crypto.tls_alert = alert;
- }
- uint8_t ngtcp2_conn_get_tls_alert(ngtcp2_conn *conn) {
- return conn->crypto.tls_alert;
- }
- int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id) {
- return conn_local_stream(conn, stream_id);
- }
- int ngtcp2_conn_is_server(ngtcp2_conn *conn) { return conn->server; }
- int ngtcp2_conn_after_retry(ngtcp2_conn *conn) {
- return (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) != 0;
- }
- int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id,
- void *stream_user_data) {
- ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return NGTCP2_ERR_STREAM_NOT_FOUND;
- }
- strm->stream_user_data = stream_user_data;
- return 0;
- }
- void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
- ngtcp2_duration pacing_interval;
- ngtcp2_duration wait;
- conn_update_timestamp(conn, ts);
- if (conn->tx.pacing.pktlen == 0) {
- return;
- }
- if (conn->cstat.pacing_interval) {
- pacing_interval = conn->cstat.pacing_interval;
- } else {
- /* 1.25 is the under-utilization avoidance factor described in
- https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */
- pacing_interval = (conn->cstat.first_rtt_sample_ts == UINT64_MAX
- ? NGTCP2_MILLISECONDS
- : conn->cstat.smoothed_rtt) *
- 100 / 125 / conn->cstat.cwnd;
- }
- wait = (ngtcp2_duration)(conn->tx.pacing.pktlen * pacing_interval);
- conn->tx.pacing.next_ts = ts + wait;
- conn->tx.pacing.pktlen = 0;
- }
- size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn) {
- return conn->cstat.send_quantum;
- }
- int ngtcp2_conn_track_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq) {
- if (conn->dcid.retire_unacked.len >=
- ngtcp2_arraylen(conn->dcid.retire_unacked.seqs)) {
- return NGTCP2_ERR_CONNECTION_ID_LIMIT;
- }
- conn->dcid.retire_unacked.seqs[conn->dcid.retire_unacked.len++] = seq;
- return 0;
- }
- void ngtcp2_conn_untrack_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq) {
- size_t i;
- for (i = 0; i < conn->dcid.retire_unacked.len; ++i) {
- if (conn->dcid.retire_unacked.seqs[i] != seq) {
- continue;
- }
- if (i != conn->dcid.retire_unacked.len - 1) {
- conn->dcid.retire_unacked.seqs[i] =
- conn->dcid.retire_unacked.seqs[conn->dcid.retire_unacked.len - 1];
- }
- --conn->dcid.retire_unacked.len;
- return;
- }
- }
- int ngtcp2_conn_check_retired_dcid_tracked(ngtcp2_conn *conn, uint64_t seq) {
- size_t i;
- for (i = 0; i < conn->dcid.retire_unacked.len; ++i) {
- if (conn->dcid.retire_unacked.seqs[i] == seq) {
- return 1;
- }
- }
- return 0;
- }
- size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, int64_t stream_id) {
- ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return 0;
- }
- return strm->tx.loss_count;
- }
- void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
- const ngtcp2_path *path,
- const uint8_t *data) {
- ngtcp2_path_storage_init2(&pcent->ps, path);
- memcpy(pcent->data, data, sizeof(pcent->data));
- }
- /* The functions prefixed with ngtcp2_pkt_ are usually put inside
- ngtcp2_pkt.c. This function uses encryption construct and uses
- test data defined only in ngtcp2_conn_test.c, so it is written
- here. */
- ngtcp2_ssize ngtcp2_pkt_write_connection_close(
- uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
- const ngtcp2_cid *scid, uint64_t error_code, const uint8_t *reason,
- size_t reasonlen, ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead,
- const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv,
- ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp,
- const ngtcp2_crypto_cipher_ctx *hp_ctx) {
- ngtcp2_pkt_hd hd;
- ngtcp2_crypto_km ckm;
- ngtcp2_crypto_cc cc;
- ngtcp2_ppe ppe;
- ngtcp2_frame fr = {0};
- int rv;
- ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_INITIAL, dcid,
- scid, /* pkt_num = */ 0, /* pkt_numlen = */ 1, version,
- /* len = */ 0);
- ngtcp2_vec_init(&ckm.secret, NULL, 0);
- ngtcp2_vec_init(&ckm.iv, iv, 12);
- ckm.aead_ctx = *aead_ctx;
- ckm.pkt_num = 0;
- ckm.flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
- cc.aead = *aead;
- cc.hp = *hp;
- cc.ckm = &ckm;
- cc.hp_ctx = *hp_ctx;
- cc.encrypt = encrypt;
- cc.hp_mask = hp_mask;
- ngtcp2_ppe_init(&ppe, dest, destlen, 0, &cc);
- rv = ngtcp2_ppe_encode_hd(&ppe, &hd);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return rv;
- }
- if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) {
- return NGTCP2_ERR_NOBUF;
- }
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
- fr.connection_close.error_code = error_code;
- fr.connection_close.reasonlen = reasonlen;
- fr.connection_close.reason = (uint8_t *)reason;
- rv = ngtcp2_ppe_encode_frame(&ppe, &fr);
- if (rv != 0) {
- assert(NGTCP2_ERR_NOBUF == rv);
- return rv;
- }
- return ngtcp2_ppe_final(&ppe, NULL);
- }
- int ngtcp2_is_bidi_stream(int64_t stream_id) { return bidi_stream(stream_id); }
- uint32_t ngtcp2_select_version(const uint32_t *preferred_versions,
- size_t preferred_versionslen,
- const uint32_t *offered_versions,
- size_t offered_versionslen) {
- size_t i, j;
- if (!preferred_versionslen || !offered_versionslen) {
- return 0;
- }
- for (i = 0; i < preferred_versionslen; ++i) {
- assert(ngtcp2_is_supported_version(preferred_versions[i]));
- for (j = 0; j < offered_versionslen; ++j) {
- if (preferred_versions[i] == offered_versions[j]) {
- return preferred_versions[i];
- }
- }
- }
- return 0;
- }
|