core.cpp 460 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824
  1. /*
  2. * SRT - Secure, Reliable, Transport
  3. * Copyright (c) 2018 Haivision Systems Inc.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. */
  10. /*****************************************************************************
  11. Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
  12. All rights reserved.
  13. Redistribution and use in source and binary forms, with or without
  14. modification, are permitted provided that the following conditions are
  15. met:
  16. * Redistributions of source code must retain the above
  17. copyright notice, this list of conditions and the
  18. following disclaimer.
  19. * Redistributions in binary form must reproduce the
  20. above copyright notice, this list of conditions
  21. and the following disclaimer in the documentation
  22. and/or other materials provided with the distribution.
  23. * Neither the name of the University of Illinois
  24. nor the names of its contributors may be used to
  25. endorse or promote products derived from this
  26. software without specific prior written permission.
  27. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28. IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  31. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *****************************************************************************/
  39. /*****************************************************************************
  40. written by
  41. Yunhong Gu, last updated 02/28/2012
  42. modified by
  43. Haivision Systems Inc.
  44. *****************************************************************************/
  45. #include "platform_sys.h"
  46. // Linux specific
  47. #ifdef SRT_ENABLE_BINDTODEVICE
  48. #include <linux/if.h>
  49. #endif
  50. #include <cmath>
  51. #include <sstream>
  52. #include <algorithm>
  53. #include <iterator>
  54. #include "srt.h"
  55. #include "access_control.h" // Required for SRT_REJX_FALLBACK
  56. #include "queue.h"
  57. #include "api.h"
  58. #include "core.h"
  59. #include "logging.h"
  60. #include "crypto.h"
  61. #include "logging_api.h" // Required due to containing extern srt_logger_config
  62. #include "logger_defs.h"
  63. #if !HAVE_CXX11
  64. // for pthread_once
  65. #include <pthread.h>
  66. #endif
  67. // Again, just in case when some "smart guy" provided such a global macro
  68. #ifdef min
  69. #undef min
  70. #endif
  71. #ifdef max
  72. #undef max
  73. #endif
  74. using namespace std;
  75. using namespace srt;
  76. using namespace srt::sync;
  77. using namespace srt_logging;
  78. const SRTSOCKET UDT::INVALID_SOCK = srt::CUDT::INVALID_SOCK;
  79. const int UDT::ERROR = srt::CUDT::ERROR;
  80. //#define SRT_CMD_HSREQ 1 /* SRT Handshake Request (sender) */
  81. #define SRT_CMD_HSREQ_MINSZ 8 /* Minumum Compatible (1.x.x) packet size (bytes) */
  82. #define SRT_CMD_HSREQ_SZ 12 /* Current version packet size */
  83. #if SRT_CMD_HSREQ_SZ > SRT_CMD_MAXSZ
  84. #error SRT_CMD_MAXSZ too small
  85. #endif
  86. /* Handshake Request (Network Order)
  87. 0[31..0]: SRT version SRT_DEF_VERSION
  88. 1[31..0]: Options 0 [ | SRT_OPT_TSBPDSND ][ | SRT_OPT_HAICRYPT ]
  89. 2[31..16]: TsbPD resv 0
  90. 2[15..0]: TsbPD delay [0..60000] msec
  91. */
  92. //#define SRT_CMD_HSRSP 2 /* SRT Handshake Response (receiver) */
  93. #define SRT_CMD_HSRSP_MINSZ 8 /* Minumum Compatible (1.x.x) packet size (bytes) */
  94. #define SRT_CMD_HSRSP_SZ 12 /* Current version packet size */
  95. #if SRT_CMD_HSRSP_SZ > SRT_CMD_MAXSZ
  96. #error SRT_CMD_MAXSZ too small
  97. #endif
  98. /* Handshake Response (Network Order)
  99. 0[31..0]: SRT version SRT_DEF_VERSION
  100. 1[31..0]: Options 0 [ | SRT_OPT_TSBPDRCV [| SRT_OPT_TLPKTDROP ]][ | SRT_OPT_HAICRYPT]
  101. [ | SRT_OPT_NAKREPORT ] [ | SRT_OPT_REXMITFLG ]
  102. 2[31..16]: TsbPD resv 0
  103. 2[15..0]: TsbPD delay [0..60000] msec
  104. */
  105. extern const SRT_SOCKOPT srt_post_opt_list [SRT_SOCKOPT_NPOST] = {
  106. SRTO_SNDSYN,
  107. SRTO_RCVSYN,
  108. SRTO_LINGER,
  109. SRTO_SNDTIMEO,
  110. SRTO_RCVTIMEO,
  111. SRTO_MAXBW,
  112. SRTO_INPUTBW,
  113. SRTO_MININPUTBW,
  114. SRTO_OHEADBW,
  115. SRTO_SNDDROPDELAY,
  116. SRTO_DRIFTTRACER,
  117. SRTO_LOSSMAXTTL
  118. };
  119. const int32_t
  120. SRTO_R_PREBIND = BIT(0), //< cannot be modified after srt_bind()
  121. SRTO_R_PRE = BIT(1), //< cannot be modified after connection is established
  122. SRTO_POST_SPEC = BIT(2); //< executes some action after setting the option
  123. namespace srt
  124. {
  125. struct SrtOptionAction
  126. {
  127. int flags[SRTO_E_SIZE];
  128. std::map<SRT_SOCKOPT, std::string> private_default;
  129. SrtOptionAction()
  130. {
  131. // Set everything to 0 to clear all flags
  132. // When an option isn't present here, it means that:
  133. // * it is not settable, or
  134. // * the option is POST (non-restricted)
  135. // * it has no post-actions
  136. // The post-action may be defined independently on restrictions.
  137. memset(flags, 0, sizeof flags);
  138. flags[SRTO_MSS] = SRTO_R_PREBIND;
  139. flags[SRTO_FC] = SRTO_R_PRE;
  140. flags[SRTO_SNDBUF] = SRTO_R_PREBIND;
  141. flags[SRTO_RCVBUF] = SRTO_R_PREBIND;
  142. flags[SRTO_UDP_SNDBUF] = SRTO_R_PREBIND;
  143. flags[SRTO_UDP_RCVBUF] = SRTO_R_PREBIND;
  144. flags[SRTO_RENDEZVOUS] = SRTO_R_PRE;
  145. flags[SRTO_REUSEADDR] = SRTO_R_PREBIND;
  146. flags[SRTO_MAXBW] = SRTO_POST_SPEC;
  147. flags[SRTO_SENDER] = SRTO_R_PRE;
  148. flags[SRTO_TSBPDMODE] = SRTO_R_PRE;
  149. flags[SRTO_LATENCY] = SRTO_R_PRE;
  150. flags[SRTO_INPUTBW] = SRTO_POST_SPEC;
  151. flags[SRTO_MININPUTBW] = SRTO_POST_SPEC;
  152. flags[SRTO_OHEADBW] = SRTO_POST_SPEC;
  153. flags[SRTO_PASSPHRASE] = SRTO_R_PRE;
  154. flags[SRTO_PBKEYLEN] = SRTO_R_PRE;
  155. flags[SRTO_IPTTL] = SRTO_R_PREBIND;
  156. flags[SRTO_IPTOS] = SRTO_R_PREBIND;
  157. flags[SRTO_TLPKTDROP] = SRTO_R_PRE;
  158. flags[SRTO_SNDDROPDELAY] = SRTO_POST_SPEC;
  159. flags[SRTO_NAKREPORT] = SRTO_R_PRE;
  160. flags[SRTO_VERSION] = SRTO_R_PRE;
  161. flags[SRTO_CONNTIMEO] = SRTO_R_PRE;
  162. flags[SRTO_LOSSMAXTTL] = SRTO_POST_SPEC;
  163. flags[SRTO_RCVLATENCY] = SRTO_R_PRE;
  164. flags[SRTO_PEERLATENCY] = SRTO_R_PRE;
  165. flags[SRTO_MINVERSION] = SRTO_R_PRE;
  166. flags[SRTO_STREAMID] = SRTO_R_PRE;
  167. flags[SRTO_CONGESTION] = SRTO_R_PRE;
  168. flags[SRTO_MESSAGEAPI] = SRTO_R_PRE;
  169. flags[SRTO_PAYLOADSIZE] = SRTO_R_PRE;
  170. flags[SRTO_TRANSTYPE] = SRTO_R_PREBIND;
  171. flags[SRTO_KMREFRESHRATE] = SRTO_R_PRE;
  172. flags[SRTO_KMPREANNOUNCE] = SRTO_R_PRE;
  173. flags[SRTO_ENFORCEDENCRYPTION] = SRTO_R_PRE;
  174. flags[SRTO_IPV6ONLY] = SRTO_R_PREBIND;
  175. flags[SRTO_PEERIDLETIMEO] = SRTO_R_PRE;
  176. #ifdef SRT_ENABLE_BINDTODEVICE
  177. flags[SRTO_BINDTODEVICE] = SRTO_R_PREBIND;
  178. #endif
  179. #if ENABLE_BONDING
  180. flags[SRTO_GROUPCONNECT] = SRTO_R_PRE;
  181. flags[SRTO_GROUPMINSTABLETIMEO]= SRTO_R_PRE;
  182. #endif
  183. flags[SRTO_PACKETFILTER] = SRTO_R_PRE;
  184. flags[SRTO_RETRANSMITALGO] = SRTO_R_PRE;
  185. #ifdef ENABLE_AEAD_API_PREVIEW
  186. flags[SRTO_CRYPTOMODE] = SRTO_R_PRE;
  187. #endif
  188. // For "private" options (not derived from the listener
  189. // socket by an accepted socket) provide below private_default
  190. // to which these options will be reset after blindly
  191. // copying the option object from the listener socket.
  192. // Note that this option cannot have runtime-dependent
  193. // default value, like options affected by SRTO_TRANSTYPE.
  194. // Options may be of different types, but this value should be only
  195. // used as a source of the value. For example, in case of int64_t you'd
  196. // have to place here a string of 8 characters. It should be copied
  197. // always in the hardware order, as this is what will be directly
  198. // passed to a setting function.
  199. private_default[SRTO_STREAMID] = string();
  200. }
  201. };
  202. const SrtOptionAction s_sockopt_action;
  203. } // namespace srt
  204. #if HAVE_CXX11
  205. CUDTUnited& srt::CUDT::uglobal()
  206. {
  207. static CUDTUnited instance;
  208. return instance;
  209. }
  210. #else // !HAVE_CXX11
  211. static pthread_once_t s_UDTUnitedOnce = PTHREAD_ONCE_INIT;
  212. static CUDTUnited *getInstance()
  213. {
  214. static CUDTUnited instance;
  215. return &instance;
  216. }
  217. CUDTUnited& srt::CUDT::uglobal()
  218. {
  219. // We don't want lock each time, pthread_once can be faster than mutex.
  220. pthread_once(&s_UDTUnitedOnce, reinterpret_cast<void (*)()>(getInstance));
  221. return *getInstance();
  222. }
  223. #endif
  224. void srt::CUDT::construct()
  225. {
  226. m_pSndBuffer = NULL;
  227. m_pRcvBuffer = NULL;
  228. m_pSndLossList = NULL;
  229. m_pRcvLossList = NULL;
  230. m_iReorderTolerance = 0;
  231. // How many times so far the packet considered lost has been received
  232. // before TTL expires.
  233. m_iConsecEarlyDelivery = 0;
  234. m_iConsecOrderedDelivery = 0;
  235. m_pSndQueue = NULL;
  236. m_pRcvQueue = NULL;
  237. m_pSNode = NULL;
  238. m_pRNode = NULL;
  239. // Will be reset to 0 for HSv5, this value is important for HSv4.
  240. m_iSndHsRetryCnt = SRT_MAX_HSRETRY + 1;
  241. m_PeerID = 0;
  242. m_bOpened = false;
  243. m_bListening = false;
  244. m_bConnecting = false;
  245. m_bConnected = false;
  246. m_bClosing = false;
  247. m_bShutdown = false;
  248. m_bBroken = false;
  249. m_bBreakAsUnstable = false;
  250. // TODO: m_iBrokenCounter should be still set to some default.
  251. m_bPeerHealth = true;
  252. m_RejectReason = SRT_REJ_UNKNOWN;
  253. m_tsLastReqTime.store(steady_clock::time_point());
  254. m_SrtHsSide = HSD_DRAW;
  255. m_uPeerSrtVersion = 0; // Not defined until connected.
  256. m_iTsbPdDelay_ms = 0;
  257. m_iPeerTsbPdDelay_ms = 0;
  258. m_bPeerTsbPd = false;
  259. m_bTsbPd = false;
  260. m_bTsbPdAckWakeup = false;
  261. m_bGroupTsbPd = false;
  262. m_bPeerTLPktDrop = false;
  263. // Initilize mutex and condition variables.
  264. initSynch();
  265. // TODO: Uncomment when the callback is implemented.
  266. // m_cbPacketArrival.set(this, &CUDT::defaultPacketArrival);
  267. }
  268. srt::CUDT::CUDT(CUDTSocket* parent)
  269. : m_parent(parent)
  270. #ifdef ENABLE_MAXREXMITBW
  271. , m_SndRexmitRate(sync::steady_clock::now())
  272. #endif
  273. , m_iISN(-1)
  274. , m_iPeerISN(-1)
  275. {
  276. construct();
  277. (void)SRT_DEF_VERSION;
  278. // Runtime fields
  279. #if ENABLE_BONDING
  280. m_HSGroupType = SRT_GTYPE_UNDEFINED;
  281. #endif
  282. m_bTLPktDrop = true; // Too-late Packet Drop
  283. m_pCache = NULL;
  284. // This is in order to set it ANY kind of initial value, however
  285. // this value should not be used when not connected and should be
  286. // updated in the handshake. When this value is 0, it means that
  287. // packets shall not be sent, as the other party doesn't have a
  288. // room to receive and store it. Therefore this value should be
  289. // overridden before any sending happens.
  290. m_iFlowWindowSize = 0;
  291. }
  292. srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor)
  293. : m_parent(parent)
  294. #ifdef ENABLE_MAXREXMITBW
  295. , m_SndRexmitRate(sync::steady_clock::now())
  296. #endif
  297. , m_iISN(-1)
  298. , m_iPeerISN(-1)
  299. {
  300. construct();
  301. // XXX Consider all below fields (except m_bReuseAddr) to be put
  302. // into a separate class for easier copying.
  303. m_config = ancestor.m_config;
  304. // Reset values that shall not be derived to default ones.
  305. // These declarations should be consistent with SRTO_R_PRIVATE flag.
  306. for (size_t i = 0; i < Size(s_sockopt_action.flags); ++i)
  307. {
  308. const string* pdef = map_getp(s_sockopt_action.private_default, SRT_SOCKOPT(i));
  309. if (pdef)
  310. {
  311. try
  312. {
  313. // Ignore errors here - this is a development-time granted
  314. // value, not user-provided value.
  315. m_config.set(SRT_SOCKOPT(i), pdef->data(), (int) pdef->size());
  316. }
  317. catch (...)
  318. {
  319. LOGC(gglog.Error, log << "IPE: failed to set a declared default option!");
  320. }
  321. }
  322. }
  323. m_SrtHsSide = ancestor.m_SrtHsSide; // actually it sets it to HSD_RESPONDER
  324. m_bTLPktDrop = ancestor.m_bTLPktDrop;
  325. m_iReorderTolerance = m_config.iMaxReorderTolerance; // Initialize with maximum value
  326. // Runtime
  327. m_pCache = ancestor.m_pCache;
  328. }
  329. srt::CUDT::~CUDT()
  330. {
  331. // release mutex/condtion variables
  332. destroySynch();
  333. // destroy the data structures
  334. delete m_pSndBuffer;
  335. delete m_pRcvBuffer;
  336. delete m_pSndLossList;
  337. delete m_pRcvLossList;
  338. delete m_pSNode;
  339. delete m_pRNode;
  340. }
  341. void srt::CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)
  342. {
  343. if (m_bBroken || m_bClosing)
  344. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  345. // Match check (confirm optName as index for s_sockopt_action)
  346. if (int(optName) < 0 || int(optName) >= int(SRTO_E_SIZE))
  347. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  348. // Restriction check
  349. const int oflags = s_sockopt_action.flags[optName];
  350. ScopedLock cg (m_ConnectionLock);
  351. ScopedLock sendguard (m_SendLock);
  352. ScopedLock recvguard (m_RecvLock);
  353. HLOGC(aclog.Debug,
  354. log << CONID() << "OPTION: #" << optName << " value:" << FormatBinaryString((uint8_t*)optval, optlen));
  355. if (IsSet(oflags, SRTO_R_PREBIND) && m_bOpened)
  356. throw CUDTException(MJ_NOTSUP, MN_ISBOUND, 0);
  357. if (IsSet(oflags, SRTO_R_PRE) && (m_bConnected || m_bConnecting || m_bListening))
  358. throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);
  359. // Option execution. If this returns -1, there's no such option.
  360. const int status = m_config.set(optName, optval, optlen);
  361. if (status == -1)
  362. {
  363. LOGC(aclog.Error, log << CONID() << "OPTION: #" << optName << " UNKNOWN");
  364. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  365. }
  366. // Post-action, if applicable
  367. if (IsSet(oflags, SRTO_POST_SPEC) && m_bConnected)
  368. {
  369. switch (optName)
  370. {
  371. case SRTO_MAXBW:
  372. updateCC(TEV_INIT, EventVariant(TEV_INIT_RESET));
  373. break;
  374. case SRTO_INPUTBW:
  375. case SRTO_MININPUTBW:
  376. updateCC(TEV_INIT, EventVariant(TEV_INIT_INPUTBW));
  377. break;
  378. case SRTO_OHEADBW:
  379. updateCC(TEV_INIT, EventVariant(TEV_INIT_OHEADBW));
  380. break;
  381. case SRTO_LOSSMAXTTL:
  382. m_iReorderTolerance = m_config.iMaxReorderTolerance;
  383. default: break;
  384. }
  385. }
  386. }
  387. void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen)
  388. {
  389. ScopedLock cg(m_ConnectionLock);
  390. switch (optName)
  391. {
  392. case SRTO_MSS:
  393. *(int *)optval = m_config.iMSS;
  394. optlen = sizeof(int);
  395. break;
  396. case SRTO_SNDSYN:
  397. *(bool *)optval = m_config.bSynSending;
  398. optlen = sizeof(bool);
  399. break;
  400. case SRTO_RCVSYN:
  401. *(bool *)optval = m_config.bSynRecving;
  402. optlen = sizeof(bool);
  403. break;
  404. case SRTO_ISN:
  405. *(int *)optval = m_iISN;
  406. optlen = sizeof(int);
  407. break;
  408. case SRTO_FC:
  409. *(int *)optval = m_config.iFlightFlagSize;
  410. optlen = sizeof(int);
  411. break;
  412. case SRTO_SNDBUF:
  413. *(int *)optval = m_config.iSndBufSize * (m_config.iMSS - CPacket::UDP_HDR_SIZE);
  414. optlen = sizeof(int);
  415. break;
  416. case SRTO_RCVBUF:
  417. *(int *)optval = m_config.iRcvBufSize * (m_config.iMSS - CPacket::UDP_HDR_SIZE);
  418. optlen = sizeof(int);
  419. break;
  420. case SRTO_LINGER:
  421. if (optlen < (int)(sizeof(linger)))
  422. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  423. *(linger *)optval = m_config.Linger;
  424. optlen = sizeof(linger);
  425. break;
  426. case SRTO_UDP_SNDBUF:
  427. *(int *)optval = m_config.iUDPSndBufSize;
  428. optlen = sizeof(int);
  429. break;
  430. case SRTO_UDP_RCVBUF:
  431. *(int *)optval = m_config.iUDPRcvBufSize;
  432. optlen = sizeof(int);
  433. break;
  434. case SRTO_RENDEZVOUS:
  435. *(bool *)optval = m_config.bRendezvous;
  436. optlen = sizeof(bool);
  437. break;
  438. case SRTO_SNDTIMEO:
  439. *(int *)optval = m_config.iSndTimeOut;
  440. optlen = sizeof(int);
  441. break;
  442. case SRTO_RCVTIMEO:
  443. *(int *)optval = m_config.iRcvTimeOut;
  444. optlen = sizeof(int);
  445. break;
  446. case SRTO_REUSEADDR:
  447. *(bool *)optval = m_config.bReuseAddr;
  448. optlen = sizeof(bool);
  449. break;
  450. case SRTO_MAXBW:
  451. if (size_t(optlen) < sizeof(m_config.llMaxBW))
  452. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  453. *(int64_t *)optval = m_config.llMaxBW;
  454. optlen = sizeof(int64_t);
  455. break;
  456. case SRTO_INPUTBW:
  457. if (size_t(optlen) < sizeof(m_config.llInputBW))
  458. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  459. *(int64_t*)optval = m_config.llInputBW;
  460. optlen = sizeof(int64_t);
  461. break;
  462. case SRTO_MININPUTBW:
  463. if (size_t(optlen) < sizeof (m_config.llMinInputBW))
  464. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  465. *(int64_t*)optval = m_config.llMinInputBW;
  466. optlen = sizeof(int64_t);
  467. break;
  468. case SRTO_OHEADBW:
  469. *(int32_t *)optval = m_config.iOverheadBW;
  470. optlen = sizeof(int32_t);
  471. break;
  472. case SRTO_STATE:
  473. *(int32_t *)optval = uglobal().getStatus(m_SocketID);
  474. optlen = sizeof(int32_t);
  475. break;
  476. case SRTO_EVENT:
  477. {
  478. int32_t event = 0;
  479. if (m_bBroken)
  480. event |= SRT_EPOLL_ERR;
  481. else
  482. {
  483. enterCS(m_RecvLock);
  484. if (m_pRcvBuffer && isRcvBufferReady())
  485. event |= SRT_EPOLL_IN;
  486. leaveCS(m_RecvLock);
  487. if (m_pSndBuffer && (m_config.iSndBufSize > m_pSndBuffer->getCurrBufSize()))
  488. event |= SRT_EPOLL_OUT;
  489. }
  490. *(int32_t *)optval = event;
  491. optlen = sizeof(int32_t);
  492. break;
  493. }
  494. case SRTO_SNDDATA:
  495. if (m_pSndBuffer)
  496. *(int32_t *)optval = m_pSndBuffer->getCurrBufSize();
  497. else
  498. *(int32_t *)optval = 0;
  499. optlen = sizeof(int32_t);
  500. break;
  501. case SRTO_RCVDATA:
  502. if (m_pRcvBuffer)
  503. {
  504. enterCS(m_RecvLock);
  505. *(int32_t *)optval = m_pRcvBuffer->getRcvDataSize();
  506. leaveCS(m_RecvLock);
  507. }
  508. else
  509. *(int32_t *)optval = 0;
  510. optlen = sizeof(int32_t);
  511. break;
  512. case SRTO_IPTTL:
  513. if (m_bOpened)
  514. *(int32_t *)optval = m_pSndQueue->getIpTTL();
  515. else
  516. *(int32_t *)optval = m_config.iIpTTL;
  517. optlen = sizeof(int32_t);
  518. break;
  519. case SRTO_IPTOS:
  520. if (m_bOpened)
  521. *(int32_t *)optval = m_pSndQueue->getIpToS();
  522. else
  523. *(int32_t *)optval = m_config.iIpToS;
  524. optlen = sizeof(int32_t);
  525. break;
  526. case SRTO_BINDTODEVICE:
  527. #ifdef SRT_ENABLE_BINDTODEVICE
  528. if (optlen < IFNAMSIZ)
  529. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  530. if (m_bOpened && m_pSndQueue->getBind(((char*)optval), optlen))
  531. {
  532. optlen = strlen((char*)optval);
  533. break;
  534. }
  535. // Fallback: return from internal data
  536. optlen = (int)m_config.sBindToDevice.copy((char*)optval, (size_t)optlen - 1);
  537. ((char*)optval)[optlen] = '\0';
  538. #else
  539. LOGC(smlog.Error, log << "SRTO_BINDTODEVICE is not supported on that platform");
  540. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  541. #endif
  542. break;
  543. case SRTO_SENDER:
  544. *(bool *)optval = m_config.bDataSender;
  545. optlen = sizeof(bool);
  546. break;
  547. case SRTO_TSBPDMODE:
  548. *(bool *)optval = m_config.bTSBPD;
  549. optlen = sizeof(bool);
  550. break;
  551. case SRTO_LATENCY:
  552. case SRTO_RCVLATENCY:
  553. if (m_bConnected)
  554. *(int32_t *)optval = m_iTsbPdDelay_ms;
  555. else
  556. *(int32_t *)optval = m_config.iRcvLatency;
  557. optlen = sizeof(int32_t);
  558. break;
  559. case SRTO_PEERLATENCY:
  560. if (m_bConnected)
  561. *(int32_t *)optval = m_iPeerTsbPdDelay_ms;
  562. else
  563. *(int32_t *)optval = m_config.iPeerLatency;
  564. optlen = sizeof(int32_t);
  565. break;
  566. case SRTO_TLPKTDROP:
  567. if (m_bConnected)
  568. *(bool *)optval = m_bTLPktDrop;
  569. else
  570. *(bool *)optval = m_config.bTLPktDrop;
  571. optlen = sizeof(bool);
  572. break;
  573. case SRTO_SNDDROPDELAY:
  574. *(int32_t *)optval = m_config.iSndDropDelay;
  575. optlen = sizeof(int32_t);
  576. break;
  577. case SRTO_PBKEYLEN:
  578. if (m_pCryptoControl)
  579. *(int32_t *)optval = (int32_t) m_pCryptoControl->KeyLen(); // Running Key length.
  580. else
  581. *(int32_t *)optval = m_config.iSndCryptoKeyLen; // May be 0.
  582. optlen = sizeof(int32_t);
  583. break;
  584. case SRTO_KMSTATE:
  585. if (!m_pCryptoControl)
  586. *(int32_t *)optval = SRT_KM_S_UNSECURED;
  587. else if (m_config.bDataSender)
  588. *(int32_t *)optval = m_pCryptoControl->m_SndKmState;
  589. else
  590. *(int32_t *)optval = m_pCryptoControl->m_RcvKmState;
  591. optlen = sizeof(int32_t);
  592. break;
  593. case SRTO_SNDKMSTATE: // State imposed by Agent depending on PW and KMX
  594. if (m_pCryptoControl)
  595. *(int32_t *)optval = m_pCryptoControl->m_SndKmState;
  596. else
  597. *(int32_t *)optval = SRT_KM_S_UNSECURED;
  598. optlen = sizeof(int32_t);
  599. break;
  600. case SRTO_RCVKMSTATE: // State returned by Peer as informed during KMX
  601. if (m_pCryptoControl)
  602. *(int32_t *)optval = m_pCryptoControl->m_RcvKmState;
  603. else
  604. *(int32_t *)optval = SRT_KM_S_UNSECURED;
  605. optlen = sizeof(int32_t);
  606. break;
  607. case SRTO_LOSSMAXTTL:
  608. *(int32_t*)optval = m_config.iMaxReorderTolerance;
  609. optlen = sizeof(int32_t);
  610. break;
  611. case SRTO_NAKREPORT:
  612. *(bool *)optval = m_config.bRcvNakReport;
  613. optlen = sizeof(bool);
  614. break;
  615. case SRTO_VERSION:
  616. *(int32_t *)optval = m_config.uSrtVersion;
  617. optlen = sizeof(int32_t);
  618. break;
  619. case SRTO_PEERVERSION:
  620. *(int32_t *)optval = m_uPeerSrtVersion;
  621. optlen = sizeof(int32_t);
  622. break;
  623. case SRTO_CONNTIMEO:
  624. *(int*)optval = (int) count_milliseconds(m_config.tdConnTimeOut);
  625. optlen = sizeof(int);
  626. break;
  627. case SRTO_DRIFTTRACER:
  628. *(bool*)optval = m_config.bDriftTracer;
  629. optlen = sizeof(bool);
  630. break;
  631. case SRTO_MINVERSION:
  632. *(uint32_t *)optval = m_config.uMinimumPeerSrtVersion;
  633. optlen = sizeof(uint32_t);
  634. break;
  635. case SRTO_STREAMID:
  636. if (size_t(optlen) < m_config.sStreamName.size() + 1)
  637. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  638. optlen = (int)m_config.sStreamName.copy((char*)optval, (size_t)optlen - 1);
  639. ((char*)optval)[optlen] = '\0';
  640. break;
  641. case SRTO_CONGESTION:
  642. if (size_t(optlen) < m_config.sCongestion.size() + 1)
  643. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  644. optlen = (int)m_config.sCongestion.copy((char*)optval, (size_t)optlen - 1);
  645. ((char*)optval)[optlen] = '\0';
  646. break;
  647. case SRTO_MESSAGEAPI:
  648. optlen = sizeof(bool);
  649. *(bool *)optval = m_config.bMessageAPI;
  650. break;
  651. case SRTO_PAYLOADSIZE:
  652. optlen = sizeof(int);
  653. *(int *)optval = (int) m_config.zExpPayloadSize;
  654. break;
  655. case SRTO_KMREFRESHRATE:
  656. optlen = sizeof(int);
  657. *(int*)optval = (int)m_config.uKmRefreshRatePkt;
  658. break;
  659. case SRTO_KMPREANNOUNCE:
  660. optlen = sizeof(int);
  661. *(int*)optval = (int)m_config.uKmPreAnnouncePkt;
  662. break;
  663. #if ENABLE_BONDING
  664. case SRTO_GROUPCONNECT:
  665. optlen = sizeof (int);
  666. *(int*)optval = m_config.iGroupConnect;
  667. break;
  668. case SRTO_GROUPMINSTABLETIMEO:
  669. optlen = sizeof(int);
  670. *(int*)optval = (int)m_config.uMinStabilityTimeout_ms;
  671. break;
  672. case SRTO_GROUPTYPE:
  673. optlen = sizeof (int);
  674. *(int*)optval = m_HSGroupType;
  675. break;
  676. #endif
  677. case SRTO_ENFORCEDENCRYPTION:
  678. optlen = sizeof(bool);
  679. *(bool *)optval = m_config.bEnforcedEnc;
  680. break;
  681. case SRTO_IPV6ONLY:
  682. optlen = sizeof(int);
  683. *(int *)optval = m_config.iIpV6Only;
  684. break;
  685. case SRTO_PEERIDLETIMEO:
  686. *(int *)optval = m_config.iPeerIdleTimeout_ms;
  687. optlen = sizeof(int);
  688. break;
  689. case SRTO_PACKETFILTER:
  690. if (size_t(optlen) < m_config.sPacketFilterConfig.size() + 1)
  691. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  692. optlen = (int)m_config.sPacketFilterConfig.copy((char*)optval, (size_t)optlen - 1);
  693. ((char*)optval)[optlen] = '\0';
  694. break;
  695. case SRTO_RETRANSMITALGO:
  696. *(int32_t *)optval = m_config.iRetransmitAlgo;
  697. optlen = sizeof(int32_t);
  698. break;
  699. #ifdef ENABLE_AEAD_API_PREVIEW
  700. case SRTO_CRYPTOMODE:
  701. if (m_pCryptoControl)
  702. *(int32_t*)optval = m_pCryptoControl->getCryptoMode();
  703. else
  704. *(int32_t*)optval = m_config.iCryptoMode;
  705. optlen = sizeof(int32_t);
  706. break;
  707. #endif
  708. default:
  709. throw CUDTException(MJ_NOTSUP, MN_NONE, 0);
  710. }
  711. }
  712. #if ENABLE_BONDING
  713. SRT_ERRNO srt::CUDT::applyMemberConfigObject(const SRT_SocketOptionObject& opt)
  714. {
  715. SRT_SOCKOPT this_opt = SRTO_VERSION;
  716. for (size_t i = 0; i < opt.options.size(); ++i)
  717. {
  718. SRT_SocketOptionObject::SingleOption* o = opt.options[i];
  719. HLOGC(smlog.Debug, log << CONID() << "applyMemberConfigObject: OPTION @" << m_SocketID << " #" << o->option);
  720. this_opt = SRT_SOCKOPT(o->option);
  721. setOpt(this_opt, o->storage, o->length);
  722. }
  723. return SRT_SUCCESS;
  724. }
  725. #endif
  726. bool srt::CUDT::setstreamid(SRTSOCKET u, const std::string &sid)
  727. {
  728. CUDT *that = getUDTHandle(u);
  729. if (!that)
  730. return false;
  731. if (sid.size() > CSrtConfig::MAX_SID_LENGTH)
  732. return false;
  733. if (that->m_bConnected)
  734. return false;
  735. that->m_config.sStreamName.set(sid);
  736. return true;
  737. }
  738. string srt::CUDT::getstreamid(SRTSOCKET u)
  739. {
  740. CUDT *that = getUDTHandle(u);
  741. if (!that)
  742. return "";
  743. return that->m_config.sStreamName.str();
  744. }
  745. // XXX REFACTOR: Make common code for CUDT constructor and clearData,
  746. // possibly using CUDT::construct.
  747. // Initial sequence number, loss, acknowledgement, etc.
  748. void srt::CUDT::clearData()
  749. {
  750. m_iMaxSRTPayloadSize = m_config.iMSS - CPacket::UDP_HDR_SIZE - CPacket::HDR_SIZE;
  751. HLOGC(cnlog.Debug, log << CONID() << "clearData: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize);
  752. m_iEXPCount = 1;
  753. m_iBandwidth = 1; // pkts/sec
  754. // XXX use some constant for this 16
  755. m_iDeliveryRate = 16;
  756. m_iByteDeliveryRate = 16 * m_iMaxSRTPayloadSize;
  757. m_iAckSeqNo = 0;
  758. m_tsLastAckTime = steady_clock::now();
  759. // trace information
  760. {
  761. ScopedLock stat_lock(m_StatsLock);
  762. m_stats.tsStartTime = steady_clock::now();
  763. m_stats.sndr.reset();
  764. m_stats.rcvr.reset();
  765. m_stats.tsLastSampleTime = steady_clock::now();
  766. m_stats.traceReorderDistance = 0;
  767. m_stats.sndDuration = m_stats.m_sndDurationTotal = 0;
  768. }
  769. // Resetting these data because this happens when agent isn't connected.
  770. m_bPeerTsbPd = false;
  771. m_iPeerTsbPdDelay_ms = 0;
  772. // TSBPD as state should be set to FALSE here.
  773. // Only when the HSREQ handshake is exchanged,
  774. // should they be set to possibly true.
  775. m_bTsbPd = false;
  776. m_bGroupTsbPd = false;
  777. m_iTsbPdDelay_ms = m_config.iRcvLatency;
  778. m_bTLPktDrop = m_config.bTLPktDrop;
  779. m_bPeerTLPktDrop = false;
  780. m_bPeerNakReport = false;
  781. m_bPeerRexmitFlag = false;
  782. m_RdvState = CHandShake::RDV_INVALID;
  783. m_tsRcvPeerStartTime = steady_clock::time_point();
  784. }
  785. void srt::CUDT::open()
  786. {
  787. ScopedLock cg(m_ConnectionLock);
  788. clearData();
  789. // structures for queue
  790. if (m_pSNode == NULL)
  791. m_pSNode = new CSNode;
  792. m_pSNode->m_pUDT = this;
  793. m_pSNode->m_tsTimeStamp = steady_clock::now();
  794. m_pSNode->m_iHeapLoc = -1;
  795. if (m_pRNode == NULL)
  796. m_pRNode = new CRNode;
  797. m_pRNode->m_pUDT = this;
  798. m_pRNode->m_tsTimeStamp = steady_clock::now();
  799. m_pRNode->m_pPrev = m_pRNode->m_pNext = NULL;
  800. m_pRNode->m_bOnList = false;
  801. // Set initial values of smoothed RTT and RTT variance.
  802. m_iSRTT = INITIAL_RTT;
  803. m_iRTTVar = INITIAL_RTTVAR;
  804. m_bIsFirstRTTReceived = false;
  805. // set minimum NAK and EXP timeout to 300ms
  806. m_tdMinNakInterval = milliseconds_from(300);
  807. m_tdMinExpInterval = milliseconds_from(300);
  808. m_tdACKInterval = microseconds_from(COMM_SYN_INTERVAL_US);
  809. m_tdNAKInterval = m_tdMinNakInterval;
  810. const steady_clock::time_point currtime = steady_clock::now();
  811. m_tsLastRspTime.store(currtime);
  812. m_tsNextACKTime.store(currtime + m_tdACKInterval);
  813. m_tsNextNAKTime.store(currtime + m_tdNAKInterval);
  814. m_tsLastRspAckTime = currtime;
  815. m_tsLastSndTime.store(currtime);
  816. #if ENABLE_BONDING
  817. m_tsUnstableSince = steady_clock::time_point();
  818. m_tsFreshActivation = steady_clock::time_point();
  819. m_tsWarySince = steady_clock::time_point();
  820. #endif
  821. m_iReXmitCount = 1;
  822. m_iPktCount = 0;
  823. m_iLightACKCount = 1;
  824. m_tsNextSendTime = steady_clock::time_point();
  825. m_tdSendTimeDiff = microseconds_from(0);
  826. // Now UDT is opened.
  827. m_bOpened = true;
  828. }
  829. void srt::CUDT::setListenState()
  830. {
  831. ScopedLock cg(m_ConnectionLock);
  832. if (!m_bOpened)
  833. throw CUDTException(MJ_NOTSUP, MN_NONE, 0);
  834. if (m_bConnecting || m_bConnected)
  835. throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);
  836. // listen can be called more than once
  837. if (m_bListening)
  838. return;
  839. // if there is already another socket listening on the same port
  840. if (m_pRcvQueue->setListener(this) < 0)
  841. throw CUDTException(MJ_NOTSUP, MN_BUSY, 0);
  842. m_bListening = true;
  843. }
  844. size_t srt::CUDT::fillSrtHandshake(uint32_t *aw_srtdata, size_t srtlen, int msgtype, int hs_version)
  845. {
  846. if (srtlen < SRT_HS_E_SIZE)
  847. {
  848. LOGC(cnlog.Fatal,
  849. log << CONID() << "IPE: fillSrtHandshake: buffer too small: " << srtlen << " (expected: " << SRT_HS_E_SIZE << ")");
  850. return 0;
  851. }
  852. srtlen = SRT_HS_E_SIZE; // We use only that much space.
  853. memset((aw_srtdata), 0, sizeof(uint32_t) * srtlen);
  854. /* Current version (1.x.x) SRT handshake */
  855. aw_srtdata[SRT_HS_VERSION] = m_config.uSrtVersion; /* Required version */
  856. aw_srtdata[SRT_HS_FLAGS] |= SrtVersionCapabilities();
  857. switch (msgtype)
  858. {
  859. case SRT_CMD_HSREQ:
  860. return fillSrtHandshake_HSREQ((aw_srtdata), srtlen, hs_version);
  861. case SRT_CMD_HSRSP:
  862. return fillSrtHandshake_HSRSP((aw_srtdata), srtlen, hs_version);
  863. default:
  864. LOGC(cnlog.Fatal, log << CONID() << "IPE: fillSrtHandshake/sendSrtMsg called with value " << msgtype);
  865. return 0;
  866. }
  867. }
  868. size_t srt::CUDT::fillSrtHandshake_HSREQ(uint32_t *aw_srtdata, size_t /* srtlen - unused */, int hs_version)
  869. {
  870. // INITIATOR sends HSREQ.
  871. // The TSBPD(SND|RCV) options are being set only if the TSBPD is set in the current agent.
  872. // The agent has a decisive power only in the range of RECEIVING the data, however it can
  873. // also influence the peer's latency. If agent doesn't set TSBPD mode, it doesn't send any
  874. // latency flags, although the peer might still want to do Rx with TSBPD. When agent sets
  875. // TsbPd mode, it defines latency values for Rx (itself) and Tx (peer's Rx). If peer does
  876. // not set TsbPd mode, it will simply ignore the proposed latency (PeerTsbPdDelay), although
  877. // if it has received the Rx latency as well, it must honor it and respond accordingly
  878. // (the latter is only in case of HSv5 and bidirectional connection).
  879. if (m_config.bTSBPD)
  880. {
  881. m_iTsbPdDelay_ms = m_config.iRcvLatency;
  882. m_iPeerTsbPdDelay_ms = m_config.iPeerLatency;
  883. /*
  884. * Sent data is real-time, use Time-based Packet Delivery,
  885. * set option bit and configured delay
  886. */
  887. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_TSBPDSND;
  888. if (hs_version < CUDT::HS_VERSION_SRT1)
  889. {
  890. // HSv4 - this uses only one value.
  891. aw_srtdata[SRT_HS_LATENCY] = SRT_HS_LATENCY_LEG::wrap(m_iPeerTsbPdDelay_ms);
  892. }
  893. else
  894. {
  895. // HSv5 - this will be understood only since this version when this exists.
  896. aw_srtdata[SRT_HS_LATENCY] = SRT_HS_LATENCY_SND::wrap(m_iPeerTsbPdDelay_ms);
  897. // And in the reverse direction.
  898. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_TSBPDRCV;
  899. aw_srtdata[SRT_HS_LATENCY] |= SRT_HS_LATENCY_RCV::wrap(m_iTsbPdDelay_ms);
  900. // This wasn't there for HSv4, this setting is only for the receiver.
  901. // HSv5 is bidirectional, so every party is a receiver.
  902. if (m_bTLPktDrop)
  903. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_TLPKTDROP;
  904. }
  905. }
  906. if (m_config.bRcvNakReport)
  907. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_NAKREPORT;
  908. // I support SRT_OPT_REXMITFLG. Do you?
  909. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_REXMITFLG;
  910. // Declare the API used. The flag is set for "stream" API because
  911. // the older versions will never set this flag, but all old SRT versions use message API.
  912. if (!m_config.bMessageAPI)
  913. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_STREAM;
  914. HLOGC(cnlog.Debug,
  915. log << CONID() << "HSREQ/snd: LATENCY[SND:" << SRT_HS_LATENCY_SND::unwrap(aw_srtdata[SRT_HS_LATENCY])
  916. << " RCV:" << SRT_HS_LATENCY_RCV::unwrap(aw_srtdata[SRT_HS_LATENCY]) << "] FLAGS["
  917. << SrtFlagString(aw_srtdata[SRT_HS_FLAGS]) << "]");
  918. return 3;
  919. }
  920. size_t srt::CUDT::fillSrtHandshake_HSRSP(uint32_t *aw_srtdata, size_t /* srtlen - unused */, int hs_version)
  921. {
  922. // Setting m_tsRcvPeerStartTime is done in processSrtMsg_HSREQ(), so
  923. // this condition will be skipped only if this function is called without
  924. // getting first received HSREQ. Doesn't look possible in both HSv4 and HSv5.
  925. if (is_zero(m_tsRcvPeerStartTime))
  926. {
  927. LOGC(cnlog.Fatal, log << CONID() << "IPE: fillSrtHandshake_HSRSP: m_tsRcvPeerStartTime NOT SET!");
  928. return 0;
  929. }
  930. // If Agent doesn't set TSBPD, it will not set the TSBPD flag back to the Peer.
  931. // The peer doesn't have be disturbed by it anyway.
  932. if (isOPT_TsbPd())
  933. {
  934. /*
  935. * We got and transposed peer start time (HandShake request timestamp),
  936. * we can support Timestamp-based Packet Delivery
  937. */
  938. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_TSBPDRCV;
  939. if (hs_version < HS_VERSION_SRT1)
  940. {
  941. // HSv4 - this uses only one value
  942. aw_srtdata[SRT_HS_LATENCY] = SRT_HS_LATENCY_LEG::wrap(m_iTsbPdDelay_ms);
  943. }
  944. else
  945. {
  946. // HSv5 - this puts "agent's" latency into RCV field and "peer's" -
  947. // into SND field.
  948. aw_srtdata[SRT_HS_LATENCY] = SRT_HS_LATENCY_RCV::wrap(m_iTsbPdDelay_ms);
  949. }
  950. }
  951. else
  952. {
  953. HLOGC(cnlog.Debug, log << CONID() << "HSRSP/snd: TSBPD off, NOT responding TSBPDRCV flag.");
  954. }
  955. // Hsv5, only when peer has declared TSBPD mode.
  956. // The flag was already set, and the value already "maximized" in processSrtMsg_HSREQ().
  957. if (m_bPeerTsbPd && hs_version >= HS_VERSION_SRT1)
  958. {
  959. // HSv5 is bidirectional - so send the TSBPDSND flag, and place also the
  960. // peer's latency into SND field.
  961. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_TSBPDSND;
  962. aw_srtdata[SRT_HS_LATENCY] |= SRT_HS_LATENCY_SND::wrap(m_iPeerTsbPdDelay_ms);
  963. HLOGC(cnlog.Debug,
  964. log << CONID()
  965. << "HSRSP/snd: HSv5 peer uses TSBPD, responding TSBPDSND latency=" << m_iPeerTsbPdDelay_ms);
  966. }
  967. else
  968. {
  969. HLOGC(cnlog.Debug,
  970. log << CONID() << "HSRSP/snd: HSv" << (hs_version == CUDT::HS_VERSION_UDT4 ? 4 : 5)
  971. << " with peer TSBPD=" << (m_bPeerTsbPd ? "on" : "off") << " - NOT responding TSBPDSND");
  972. }
  973. if (m_bTLPktDrop)
  974. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_TLPKTDROP;
  975. if (m_config.bRcvNakReport)
  976. {
  977. // HSv5: Note that this setting is independent on the value of
  978. // m_bPeerNakReport, which represent this setting in the peer.
  979. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_NAKREPORT;
  980. /*
  981. * NAK Report is so efficient at controlling bandwidth that sender TLPktDrop
  982. * is not needed. SRT 1.0.5 to 1.0.7 sender TLPktDrop combined with SRT 1.0
  983. * Timestamp-Based Packet Delivery was not well implemented and could drop
  984. * big I-Frame tail before sending once on low latency setups.
  985. * Disabling TLPktDrop in the receiver SRT Handshake Reply prevents the sender
  986. * from enabling Too-Late Packet Drop.
  987. */
  988. if (m_uPeerSrtVersion <= SrtVersion(1, 0, 7))
  989. aw_srtdata[SRT_HS_FLAGS] &= ~SRT_OPT_TLPKTDROP;
  990. }
  991. if (m_config.uSrtVersion >= SrtVersion(1, 2, 0))
  992. {
  993. if (!m_bPeerRexmitFlag)
  994. {
  995. // Peer does not request to use rexmit flag, if so,
  996. // we won't use as well.
  997. HLOGC(cnlog.Debug,
  998. log << CONID() << "HSRSP/snd: AGENT understands REXMIT flag, but PEER DOES NOT. NOT setting.");
  999. }
  1000. else
  1001. {
  1002. // Request that the rexmit bit be used as a part of msgno.
  1003. aw_srtdata[SRT_HS_FLAGS] |= SRT_OPT_REXMITFLG;
  1004. HLOGP(cnlog.Debug, "HSRSP/snd: AGENT UNDERSTANDS REXMIT flag and PEER reported that it does, too.");
  1005. }
  1006. }
  1007. else
  1008. {
  1009. // Since this is now in the code, it can occur only in case when you change the
  1010. // version specification in the build configuration.
  1011. HLOGP(cnlog.Debug, "HSRSP/snd: AGENT DOES NOT UNDERSTAND REXMIT flag");
  1012. }
  1013. HLOGC(cnlog.Debug,
  1014. log << CONID() << "HSRSP/snd: LATENCY[SND:" << SRT_HS_LATENCY_SND::unwrap(aw_srtdata[SRT_HS_LATENCY])
  1015. << " RCV:" << SRT_HS_LATENCY_RCV::unwrap(aw_srtdata[SRT_HS_LATENCY]) << "] FLAGS["
  1016. << SrtFlagString(aw_srtdata[SRT_HS_FLAGS]) << "]");
  1017. return 3;
  1018. }
  1019. size_t srt::CUDT::prepareSrtHsMsg(int cmd, uint32_t *srtdata, size_t size)
  1020. {
  1021. size_t srtlen = fillSrtHandshake(srtdata, size, cmd, handshakeVersion());
  1022. HLOGC(cnlog.Debug, log << "CMD:" << MessageTypeStr(UMSG_EXT, cmd) << "(" << cmd << ") Len:"
  1023. << int(srtlen * sizeof(int32_t))
  1024. << " Version: " << SrtVersionString(srtdata[SRT_HS_VERSION])
  1025. << " Flags: " << srtdata[SRT_HS_FLAGS]
  1026. << " (" << SrtFlagString(srtdata[SRT_HS_FLAGS]) << ") sdelay:"
  1027. << srtdata[SRT_HS_LATENCY]);
  1028. return srtlen;
  1029. }
  1030. void srt::CUDT::sendSrtMsg(int cmd, uint32_t *srtdata_in, size_t srtlen_in)
  1031. {
  1032. CPacket srtpkt;
  1033. int32_t srtcmd = (int32_t)cmd;
  1034. SRT_STATIC_ASSERT(SRTDATA_MAXSIZE >= SRT_HS_E_SIZE, "SRT_CMD_MAXSZ is too small to hold all the data");
  1035. // This will be effectively larger than SRT_HS_E_SIZE, but it will be also used for incoming data.
  1036. uint32_t srtdata[SRTDATA_MAXSIZE];
  1037. size_t srtlen = 0;
  1038. if (cmd == SRT_CMD_REJECT)
  1039. {
  1040. // This is a value returned by processSrtMsg underlying layer, potentially
  1041. // to be reported here. Should this happen, just send a rejection message.
  1042. cmd = SRT_CMD_HSRSP;
  1043. srtdata[SRT_HS_VERSION] = 0;
  1044. }
  1045. switch (cmd)
  1046. {
  1047. case SRT_CMD_HSREQ:
  1048. case SRT_CMD_HSRSP:
  1049. srtlen = prepareSrtHsMsg(cmd, srtdata, SRTDATA_MAXSIZE);
  1050. break;
  1051. case SRT_CMD_KMREQ: // Sender
  1052. case SRT_CMD_KMRSP: // Receiver
  1053. srtlen = srtlen_in;
  1054. /* Msg already in network order
  1055. * But CChannel:sendto will swap again (assuming 32-bit fields)
  1056. * Pre-swap to cancel it.
  1057. */
  1058. HtoNLA(srtdata, srtdata_in, srtlen);
  1059. m_pCryptoControl->updateKmState(cmd, srtlen); // <-- THIS function can't be moved to CUDT
  1060. break;
  1061. default:
  1062. LOGC(cnlog.Error, log << "sndSrtMsg: IPE: cmd=" << cmd << " unsupported");
  1063. break;
  1064. }
  1065. if (srtlen > 0)
  1066. {
  1067. /* srtpkt.pack will set message data in network order */
  1068. srtpkt.pack(UMSG_EXT, &srtcmd, srtdata, srtlen * sizeof(int32_t));
  1069. addressAndSend(srtpkt);
  1070. }
  1071. }
  1072. size_t srt::CUDT::fillHsExtConfigString(uint32_t* pcmdspec, int cmd, const string& str)
  1073. {
  1074. uint32_t* space = pcmdspec + 1;
  1075. size_t wordsize = (str.size() + 3) / 4;
  1076. size_t aligned_bytesize = wordsize * 4;
  1077. memset((space), 0, aligned_bytesize);
  1078. memcpy((space), str.data(), str.size());
  1079. // Preswap to little endian (in place due to possible padding zeros)
  1080. HtoILA((space), space, wordsize);
  1081. *pcmdspec = HS_CMDSPEC_CMD::wrap(cmd) | HS_CMDSPEC_SIZE::wrap((uint32_t) wordsize);
  1082. return wordsize;
  1083. }
  1084. #if ENABLE_BONDING
  1085. // [[using locked(m_parent->m_ControlLock)]]
  1086. // [[using locked(s_UDTUnited.m_GlobControlLock)]]
  1087. size_t srt::CUDT::fillHsExtGroup(uint32_t* pcmdspec)
  1088. {
  1089. SRT_ASSERT(m_parent->m_GroupOf != NULL);
  1090. uint32_t* space = pcmdspec + 1;
  1091. SRTSOCKET id = m_parent->m_GroupOf->id();
  1092. SRT_GROUP_TYPE tp = m_parent->m_GroupOf->type();
  1093. uint32_t flags = 0;
  1094. // NOTE: this code remains as is for historical reasons.
  1095. // The initial implementation stated that the peer id be
  1096. // extracted so that it can be reported and possibly the
  1097. // start time somehow encoded and written into the group
  1098. // extension, but it was later seen not necessary. Therefore
  1099. // this code remains, but now it's informational only.
  1100. #if ENABLE_HEAVY_LOGGING
  1101. m_parent->m_GroupOf->debugMasterData(m_SocketID);
  1102. #endif
  1103. // See CUDT::interpretGroup()
  1104. uint32_t dataword = 0
  1105. | SrtHSRequest::HS_GROUP_TYPE::wrap(tp)
  1106. | SrtHSRequest::HS_GROUP_FLAGS::wrap(flags)
  1107. | SrtHSRequest::HS_GROUP_WEIGHT::wrap(m_parent->m_GroupMemberData->weight);
  1108. const uint32_t storedata [GRPD_E_SIZE] = { uint32_t(id), dataword };
  1109. memcpy((space), storedata, sizeof storedata);
  1110. const size_t ra_size = Size(storedata);
  1111. *pcmdspec = HS_CMDSPEC_CMD::wrap(SRT_CMD_GROUP) | HS_CMDSPEC_SIZE::wrap(ra_size);
  1112. return ra_size;
  1113. }
  1114. #endif
  1115. size_t srt::CUDT::fillHsExtKMREQ(uint32_t* pcmdspec, size_t ki)
  1116. {
  1117. uint32_t* space = pcmdspec + 1;
  1118. size_t msglen = m_pCryptoControl->getKmMsg_size(ki);
  1119. // Make ra_size back in element unit
  1120. // Add one extra word if the size isn't aligned to 32-bit.
  1121. size_t ra_size = (msglen / sizeof(uint32_t)) + (msglen % sizeof(uint32_t) ? 1 : 0);
  1122. // Store the CMD + SIZE in the next field
  1123. *pcmdspec = HS_CMDSPEC_CMD::wrap(SRT_CMD_KMREQ) | HS_CMDSPEC_SIZE::wrap((uint32_t) ra_size);
  1124. // Copy the key - do the endian inversion because another endian inversion
  1125. // will be done for every control message before sending, and this KM message
  1126. // is ALREADY in network order.
  1127. const uint32_t* keydata = reinterpret_cast<const uint32_t*>(m_pCryptoControl->getKmMsg_data(ki));
  1128. HLOGC(cnlog.Debug,
  1129. log << CONID() << "createSrtHandshake: KMREQ: adding key #" << ki << " length=" << ra_size
  1130. << " words (KmMsg_size=" << msglen << ")");
  1131. // XXX INSECURE ": [" << FormatBinaryString((uint8_t*)keydata, msglen) << "]";
  1132. // Yes, I know HtoNLA and NtoHLA do exactly the same operation, but I want
  1133. // to be clear about the true intention.
  1134. NtoHLA((space), keydata, ra_size);
  1135. return ra_size;
  1136. }
  1137. size_t srt::CUDT::fillHsExtKMRSP(uint32_t* pcmdspec, const uint32_t* kmdata, size_t kmdata_wordsize)
  1138. {
  1139. uint32_t* space = pcmdspec + 1;
  1140. const uint32_t failure_kmrsp[] = {SRT_KM_S_UNSECURED};
  1141. const uint32_t* keydata = 0;
  1142. // Shift the starting point with the value of previously added block,
  1143. // to start with the new one.
  1144. size_t ra_size;
  1145. if (kmdata_wordsize == 0)
  1146. {
  1147. LOGC(cnlog.Warn,
  1148. log << CONID()
  1149. << "createSrtHandshake: Agent has PW, but Peer sent no KMREQ. Sending error KMRSP response");
  1150. ra_size = 1;
  1151. keydata = failure_kmrsp;
  1152. // Update the KM state as well
  1153. m_pCryptoControl->m_SndKmState = SRT_KM_S_NOSECRET; // Agent has PW, but Peer won't decrypt
  1154. m_pCryptoControl->m_RcvKmState = SRT_KM_S_UNSECURED; // Peer won't encrypt as well.
  1155. }
  1156. else
  1157. {
  1158. if (!kmdata)
  1159. {
  1160. m_RejectReason = SRT_REJ_IPE;
  1161. LOGC(cnlog.Fatal, log << CONID() << "createSrtHandshake: IPE: srtkm_cmd=SRT_CMD_KMRSP and no kmdata!");
  1162. return 0;
  1163. }
  1164. ra_size = kmdata_wordsize;
  1165. keydata = reinterpret_cast<const uint32_t *>(kmdata);
  1166. }
  1167. *pcmdspec = HS_CMDSPEC_CMD::wrap(SRT_CMD_KMRSP) | HS_CMDSPEC_SIZE::wrap((uint32_t) ra_size);
  1168. HLOGC(cnlog.Debug,
  1169. log << CONID() << "createSrtHandshake: KMRSP: applying returned key length="
  1170. << ra_size); // XXX INSECURE << " words: [" << FormatBinaryString((uint8_t*)kmdata,
  1171. // kmdata_wordsize*sizeof(uint32_t)) << "]";
  1172. NtoHLA((space), keydata, ra_size);
  1173. return ra_size;
  1174. }
  1175. // PREREQUISITE:
  1176. // pkt must be set the buffer and configured for UMSG_HANDSHAKE.
  1177. // Note that this function replaces also serialization for the HSv4.
  1178. bool srt::CUDT::createSrtHandshake(
  1179. int srths_cmd,
  1180. int srtkm_cmd,
  1181. const uint32_t* kmdata,
  1182. size_t kmdata_wordsize, // IN WORDS, NOT BYTES!!!
  1183. CPacket& w_pkt,
  1184. CHandShake& w_hs)
  1185. {
  1186. // This function might be called before the opposite version was recognized.
  1187. // Check if the version is exactly 4 because this means that the peer has already
  1188. // sent something - asynchronously, and usually in rendezvous - and we already know
  1189. // that the peer is version 4. In this case, agent must behave as HSv4, til the end.
  1190. if (m_ConnRes.m_iVersion == HS_VERSION_UDT4)
  1191. {
  1192. w_hs.m_iVersion = HS_VERSION_UDT4;
  1193. w_hs.m_iType = UDT_DGRAM;
  1194. if (w_hs.m_extension)
  1195. {
  1196. // Should be impossible
  1197. LOGC(cnlog.Error,
  1198. log << CONID() << "createSrtHandshake: IPE: EXTENSION SET WHEN peer reports version 4 - fixing...");
  1199. w_hs.m_extension = false;
  1200. }
  1201. }
  1202. else
  1203. {
  1204. w_hs.m_iType = 0; // Prepare it for flags
  1205. }
  1206. HLOGC(cnlog.Debug,
  1207. log << CONID() << "createSrtHandshake: buf size=" << w_pkt.getLength()
  1208. << " hsx=" << MessageTypeStr(UMSG_EXT, srths_cmd) << " kmx=" << MessageTypeStr(UMSG_EXT, srtkm_cmd)
  1209. << " kmdata_wordsize=" << kmdata_wordsize << " version=" << w_hs.m_iVersion);
  1210. // Once you are certain that the version is HSv5, set the enc type flags
  1211. // to advertise pbkeylen. Otherwise make sure that the old interpretation
  1212. // will correctly pick up the type field. PBKEYLEN should be advertized
  1213. // regardless of what URQ stage the handshake is (note that in case of rendezvous
  1214. // CONCLUSION might be the FIRST MESSAGE EVER RECEIVED by a party).
  1215. if (w_hs.m_iVersion > HS_VERSION_UDT4)
  1216. {
  1217. // Check if there was a failure to receie HSREQ before trying to craft HSRSP.
  1218. // If fillSrtHandshake_HSRSP catches the condition of m_tsRcvPeerStartTime == steady_clock::zero(),
  1219. // it will return size 0, which will mess up with further extension procedures;
  1220. // PREVENT THIS HERE.
  1221. if (w_hs.m_iReqType == URQ_CONCLUSION && srths_cmd == SRT_CMD_HSRSP && is_zero(m_tsRcvPeerStartTime))
  1222. {
  1223. LOGC(cnlog.Error,
  1224. log << CONID()
  1225. << "createSrtHandshake: IPE (non-fatal): Attempting to craft HSRSP without received HSREQ. "
  1226. "BLOCKING extensions.");
  1227. w_hs.m_extension = false;
  1228. }
  1229. // The situation when this function is called without requested extensions
  1230. // is URQ_CONCLUSION in rendezvous mode in some of the transitions.
  1231. // In this case for version 5 just clear the m_iType field, as it has
  1232. // different meaning in HSv5 and contains extension flags.
  1233. //
  1234. // Keep 0 in the SRT_HSTYPE_HSFLAGS field, but still advertise PBKEYLEN
  1235. // in the SRT_HSTYPE_ENCFLAGS field.
  1236. w_hs.m_iType = SrtHSRequest::wrapFlags(false /*no magic in HSFLAGS*/, m_config.iSndCryptoKeyLen);
  1237. IF_HEAVY_LOGGING(bool whether = m_config.iSndCryptoKeyLen != 0);
  1238. HLOGC(cnlog.Debug,
  1239. log << CONID() << "createSrtHandshake: " << (whether ? "" : "NOT ")
  1240. << " Advertising PBKEYLEN - value = " << m_config.iSndCryptoKeyLen);
  1241. // Note: This is required only when sending a HS message without SRT extensions.
  1242. // When this is to be sent with SRT extensions, then KMREQ will be attached here
  1243. // and the PBKEYLEN will be extracted from it. If this is going to attach KMRSP
  1244. // here, it's already too late (it should've been advertised before getting the first
  1245. // handshake message with KMREQ).
  1246. }
  1247. else
  1248. {
  1249. w_hs.m_iType = UDT_DGRAM;
  1250. }
  1251. // values > URQ_CONCLUSION include also error types
  1252. // if (w_hs.m_iVersion == HS_VERSION_UDT4 || w_hs.m_iReqType > URQ_CONCLUSION) <--- This condition was checked b4 and
  1253. // it's only valid for caller-listener mode
  1254. if (!w_hs.m_extension)
  1255. {
  1256. // Serialize only the basic handshake, if this is predicted for
  1257. // Hsv4 peer or this is URQ_INDUCTION or URQ_WAVEAHAND.
  1258. size_t hs_size = w_pkt.getLength();
  1259. w_hs.store_to((w_pkt.m_pcData), (hs_size));
  1260. w_pkt.setLength(hs_size);
  1261. HLOGC(cnlog.Debug,
  1262. log << CONID() << "createSrtHandshake: (no ext) size=" << hs_size << " data: " << w_hs.show());
  1263. return true;
  1264. }
  1265. // Sanity check, applies to HSv5 only cases.
  1266. if (srths_cmd == SRT_CMD_HSREQ && m_SrtHsSide == HSD_RESPONDER)
  1267. {
  1268. m_RejectReason = SRT_REJ_IPE;
  1269. LOGC(cnlog.Fatal,
  1270. log << CONID() << "IPE: SRT_CMD_HSREQ was requested to be sent in HSv5 by an INITIATOR side!");
  1271. return false; // should cause rejection
  1272. }
  1273. ostringstream logext;
  1274. logext << "HSX";
  1275. // Install the SRT extensions
  1276. w_hs.m_iType |= CHandShake::HS_EXT_HSREQ;
  1277. bool have_sid = false;
  1278. if (srths_cmd == SRT_CMD_HSREQ && !m_config.sStreamName.empty())
  1279. {
  1280. have_sid = true;
  1281. w_hs.m_iType |= CHandShake::HS_EXT_CONFIG;
  1282. logext << ",SID";
  1283. }
  1284. // If this is a response, we have also information
  1285. // on the peer. If Peer is NOT filter capable, don't
  1286. // put filter config, even if agent is capable.
  1287. bool peer_filter_capable = true;
  1288. if (srths_cmd == SRT_CMD_HSRSP)
  1289. {
  1290. if (m_sPeerPktFilterConfigString != "")
  1291. {
  1292. peer_filter_capable = true;
  1293. }
  1294. else if (IsSet(m_uPeerSrtFlags, SRT_OPT_FILTERCAP))
  1295. {
  1296. peer_filter_capable = true;
  1297. }
  1298. else
  1299. {
  1300. peer_filter_capable = false;
  1301. }
  1302. }
  1303. // Now, if this is INITIATOR, then it has its
  1304. // filter config already set, if configured, otherwise
  1305. // it should not attach the filter config extension.
  1306. // If this is a RESPONDER, then it has already received
  1307. // the filter config string from the peer and therefore
  1308. // possibly confronted with the contents of m_OPT_FECConfigString,
  1309. // and if it decided to go with filter, it will be nonempty.
  1310. bool have_filter = false;
  1311. if (peer_filter_capable && !m_config.sPacketFilterConfig.empty())
  1312. {
  1313. have_filter = true;
  1314. w_hs.m_iType |= CHandShake::HS_EXT_CONFIG;
  1315. logext << ",filter";
  1316. }
  1317. bool have_congctl = false;
  1318. const string sm = m_config.sCongestion.str();
  1319. if (sm != "" && sm != "live")
  1320. {
  1321. have_congctl = true;
  1322. w_hs.m_iType |= CHandShake::HS_EXT_CONFIG;
  1323. logext << ",CONGCTL";
  1324. }
  1325. bool have_kmreq = false;
  1326. // Prevent adding KMRSP only in case when BOTH:
  1327. // - Agent has set no password
  1328. // - no KMREQ has arrived from Peer
  1329. // KMRSP must be always sent when:
  1330. // - Agent set a password, Peer did not send KMREQ: Agent sets snd=NOSECRET.
  1331. // - Agent set no password, but Peer sent KMREQ: Ageng sets rcv=NOSECRET.
  1332. if (m_config.CryptoSecret.len > 0 || kmdata_wordsize > 0)
  1333. {
  1334. have_kmreq = true;
  1335. w_hs.m_iType |= CHandShake::HS_EXT_KMREQ;
  1336. logext << ",KMX";
  1337. }
  1338. #if ENABLE_BONDING
  1339. bool have_group = false;
  1340. // Note: this is done without locking because we have the following possibilities:
  1341. //
  1342. // 1. Most positive: the group will be the same all the time up to the moment when we use it.
  1343. // 2. The group will disappear when next time we try to use it having now have_group set true.
  1344. //
  1345. // Not possible that a group is NULL now but would appear later: the group must be either empty
  1346. // or already set as valid at this time.
  1347. //
  1348. // If the 2nd possibility happens, then simply it means that the group has been closed during
  1349. // the operation and the socket got this information updated in the meantime. This means that
  1350. // it was an abnormal interrupt during the processing so the handshake process should be aborted
  1351. // anyway, and that's what will be done.
  1352. // LOCKING INFORMATION: accesing this field just for NULL check doesn't
  1353. // hurt, even if this field could be dangling in the moment. This will be
  1354. // followed by an additional check, done this time under lock, and there will
  1355. // be no dangling pointers at this time.
  1356. if (m_parent->m_GroupOf)
  1357. {
  1358. // Whatever group this socket belongs to, the information about
  1359. // the group is always sent the same way with the handshake.
  1360. have_group = true;
  1361. w_hs.m_iType |= CHandShake::HS_EXT_CONFIG;
  1362. logext << ",GROUP";
  1363. }
  1364. #endif
  1365. HLOGC(cnlog.Debug, log << CONID() << "createSrtHandshake: (ext: " << logext.str() << ") data: " << w_hs.show());
  1366. // NOTE: The HSREQ is practically always required, although may happen
  1367. // in future that CONCLUSION can be sent multiple times for a separate
  1368. // stream encryption support, and this way it won't enclose HSREQ.
  1369. // Also, KMREQ may occur multiple times.
  1370. // So, initially store the UDT legacy handshake.
  1371. size_t hs_size = w_pkt.getLength(), total_ra_size = (hs_size / sizeof(uint32_t)); // Maximum size of data
  1372. w_hs.store_to((w_pkt.m_pcData), (hs_size)); // hs_size is updated
  1373. size_t ra_size = hs_size / sizeof(int32_t);
  1374. // Now attach the SRT handshake for HSREQ
  1375. size_t offset = ra_size;
  1376. uint32_t *p = reinterpret_cast<uint32_t *>(w_pkt.m_pcData);
  1377. // NOTE: since this point, ra_size has a size in int32_t elements, NOT BYTES.
  1378. // The first 4-byte item is the CMD/LENGTH spec.
  1379. uint32_t *pcmdspec = p + offset; // Remember the location to be filled later, when we know the length
  1380. ++offset;
  1381. // Now use the original function to store the actual SRT_HS data
  1382. // ra_size after that
  1383. // NOTE: so far, ra_size is m_iMaxSRTPayloadSize expressed in number of elements.
  1384. // WILL BE CHANGED HERE.
  1385. ra_size = fillSrtHandshake((p + offset), total_ra_size - offset, srths_cmd, HS_VERSION_SRT1);
  1386. *pcmdspec = HS_CMDSPEC_CMD::wrap(srths_cmd) | HS_CMDSPEC_SIZE::wrap((uint32_t) ra_size);
  1387. HLOGC(cnlog.Debug,
  1388. log << CONID() << "createSrtHandshake: after HSREQ: offset=" << offset << " HSREQ size=" << ra_size
  1389. << " space left: " << (total_ra_size - offset));
  1390. // Use only in REQ phase and only if stream name is set
  1391. if (have_sid)
  1392. {
  1393. // Now prepare the string with 4-byte alignment. The string size is limited
  1394. // to half the payload size. Just a sanity check to not pack too much into
  1395. // the conclusion packet.
  1396. size_t size_limit = m_iMaxSRTPayloadSize / 2;
  1397. if (m_config.sStreamName.size() >= size_limit)
  1398. {
  1399. m_RejectReason = SRT_REJ_ROGUE;
  1400. LOGC(cnlog.Warn,
  1401. log << CONID() << "createSrtHandshake: stream id too long, limited to " << (size_limit - 1)
  1402. << " bytes");
  1403. return false;
  1404. }
  1405. offset += ra_size + 1;
  1406. ra_size = fillHsExtConfigString(p + offset - 1, SRT_CMD_SID, m_config.sStreamName.str());
  1407. HLOGC(cnlog.Debug,
  1408. log << CONID() << "createSrtHandshake: after SID [" << m_config.sStreamName.c_str()
  1409. << "] length=" << m_config.sStreamName.size() << " alignedln=" << (4 * ra_size)
  1410. << ": offset=" << offset << " SID size=" << ra_size << " space left: " << (total_ra_size - offset));
  1411. }
  1412. if (have_congctl)
  1413. {
  1414. // Pass the congctl to the other side as informational.
  1415. // The other side should reject connection if it uses a different congctl.
  1416. // The other side should also respond with the congctl it uses, if its non-default (for backward compatibility).
  1417. offset += ra_size + 1;
  1418. ra_size = fillHsExtConfigString(p + offset - 1, SRT_CMD_CONGESTION, sm);
  1419. HLOGC(cnlog.Debug,
  1420. log << CONID() << "createSrtHandshake: after CONGCTL [" << sm << "] length=" << sm.size()
  1421. << " alignedln=" << (4 * ra_size) << ": offset=" << offset << " CONGCTL size=" << ra_size
  1422. << " space left: " << (total_ra_size - offset));
  1423. }
  1424. if (have_filter)
  1425. {
  1426. offset += ra_size + 1;
  1427. ra_size = fillHsExtConfigString(p + offset - 1, SRT_CMD_FILTER, m_config.sPacketFilterConfig.str());
  1428. HLOGC(cnlog.Debug,
  1429. log << CONID() << "createSrtHandshake: after filter [" << m_config.sPacketFilterConfig.c_str()
  1430. << "] length=" << m_config.sPacketFilterConfig.size() << " alignedln=" << (4 * ra_size) << ": offset="
  1431. << offset << " filter size=" << ra_size << " space left: " << (total_ra_size - offset));
  1432. }
  1433. #if ENABLE_BONDING
  1434. // Note that this will fire in both cases:
  1435. // - When the group has been set by the user on a socket (or socket was created as a part of the group),
  1436. // and the handshake request is to be sent with informing the peer that this conenction belongs to a group
  1437. // - When the agent received a HS request with a group, has created its mirror group on its side, and
  1438. // now sends the HS response to the peer, with ITS OWN group id (the mirror one).
  1439. //
  1440. // XXX Probably a condition should be checked here around the group type.
  1441. // The time synchronization should be done only on any kind of parallel sending group.
  1442. // Currently all groups are such groups (broadcast, backup, balancing), but it may
  1443. // need to be changed for some other types.
  1444. if (have_group)
  1445. {
  1446. // NOTE: See information about mutex ordering in api.h
  1447. ScopedLock gdrg (uglobal().m_GlobControlLock);
  1448. if (!m_parent->m_GroupOf)
  1449. {
  1450. // This may only happen if since last check of m_GroupOf pointer the socket was removed
  1451. // from the group in the meantime, which can only happen due to that the group was closed.
  1452. // In such a case it simply means that the handshake process was requested to be interrupted.
  1453. LOGC(cnlog.Fatal, log << CONID() << "GROUP DISAPPEARED. Socket not capable of continuing HS");
  1454. return false;
  1455. }
  1456. else
  1457. {
  1458. if (m_parent->m_GroupOf->closing())
  1459. {
  1460. m_RejectReason = SRT_REJ_IPE;
  1461. LOGC(cnlog.Error,
  1462. log << CONID() << "createSrtHandshake: group is closing during the process, rejecting.");
  1463. return false;
  1464. }
  1465. offset += ra_size + 1;
  1466. ra_size = fillHsExtGroup(p + offset - 1);
  1467. HLOGC(cnlog.Debug,
  1468. log << CONID() << "createSrtHandshake: after GROUP [" << sm << "] length=" << sm.size() << ": offset="
  1469. << offset << " GROUP size=" << ra_size << " space left: " << (total_ra_size - offset));
  1470. }
  1471. }
  1472. #endif
  1473. // When encryption turned on
  1474. if (have_kmreq)
  1475. {
  1476. HLOGC(cnlog.Debug,
  1477. log << CONID() << "createSrtHandshake: "
  1478. << (m_config.CryptoSecret.len > 0 ? "Agent uses ENCRYPTION" : "Peer requires ENCRYPTION"));
  1479. if (!m_pCryptoControl && (srtkm_cmd == SRT_CMD_KMREQ || srtkm_cmd == SRT_CMD_KMRSP))
  1480. {
  1481. m_RejectReason = SRT_REJ_IPE;
  1482. LOGC(cnlog.Error,
  1483. log << CONID() << "createSrtHandshake: IPE: need to send KM, but CryptoControl does not exist."
  1484. << " Socket state: connected=" << boolalpha << m_bConnected << ", connecting=" << m_bConnecting
  1485. << ", broken=" << m_bBroken << ", closing=" << m_bClosing << ".");
  1486. return false;
  1487. }
  1488. if (srtkm_cmd == SRT_CMD_KMREQ)
  1489. {
  1490. bool have_any_keys = false;
  1491. for (size_t ki = 0; ki < 2; ++ki)
  1492. {
  1493. // Skip those that have expired
  1494. if (!m_pCryptoControl->getKmMsg_needSend(ki, false))
  1495. continue;
  1496. m_pCryptoControl->getKmMsg_markSent(ki, false);
  1497. offset += ra_size + 1;
  1498. ra_size = fillHsExtKMREQ(p + offset - 1, ki);
  1499. have_any_keys = true;
  1500. }
  1501. if (!have_any_keys)
  1502. {
  1503. m_RejectReason = SRT_REJ_IPE;
  1504. LOGC(cnlog.Error, log << CONID() << "createSrtHandshake: IPE: all keys have expired, no KM to send.");
  1505. return false;
  1506. }
  1507. }
  1508. else if (srtkm_cmd == SRT_CMD_KMRSP)
  1509. {
  1510. offset += ra_size + 1;
  1511. ra_size = fillHsExtKMRSP(p + offset - 1, kmdata, kmdata_wordsize);
  1512. }
  1513. else
  1514. {
  1515. m_RejectReason = SRT_REJ_IPE;
  1516. LOGC(cnlog.Fatal, log << CONID() << "createSrtHandshake: IPE: wrong value of srtkm_cmd: " << srtkm_cmd);
  1517. return false;
  1518. }
  1519. }
  1520. if (ra_size == 0)
  1521. {
  1522. // m_RejectReason is expected to be set by fillHsExtKMRSP(..) in this case.
  1523. return false;
  1524. }
  1525. // ra_size + offset has a value in element unit.
  1526. // Switch it again to byte unit.
  1527. w_pkt.setLength((ra_size + offset) * sizeof(int32_t));
  1528. HLOGC(cnlog.Debug,
  1529. log << CONID() << "createSrtHandshake: filled HSv5 handshake flags: "
  1530. << CHandShake::ExtensionFlagStr(w_hs.m_iType) << " length: " << w_pkt.getLength() << " bytes");
  1531. return true;
  1532. }
  1533. template <class Integer>
  1534. static inline int FindExtensionBlock(Integer* begin, size_t total_length,
  1535. size_t& w_out_len, Integer*& w_next_block)
  1536. {
  1537. // Check if there's anything to process
  1538. if (total_length == 0)
  1539. {
  1540. w_next_block = NULL;
  1541. w_out_len = 0;
  1542. return SRT_CMD_NONE;
  1543. }
  1544. // This function extracts the block command from the block and its length.
  1545. // The command value is returned as a function result.
  1546. // The size of that command block is stored into w_out_len.
  1547. // The beginning of the prospective next block is stored in w_next_block.
  1548. // The caller must be aware that:
  1549. // - exactly one element holds the block header (cmd+size), so the actual data are after this one.
  1550. // - the returned size is the number of uint32_t elements since that first data element
  1551. // - the remaining size should be manually calculated as total_length - 1 - w_out_len, or
  1552. // simply, as w_next_block - begin.
  1553. // Note that if the total_length is too short to extract the whole block, it will return
  1554. // SRT_CMD_NONE. Note that total_length includes this first CMDSPEC word.
  1555. //
  1556. // When SRT_CMD_NONE is returned, it means that nothing has been extracted and nothing else
  1557. // can be further extracted from this block.
  1558. int cmd = HS_CMDSPEC_CMD::unwrap(*begin);
  1559. size_t size = HS_CMDSPEC_SIZE::unwrap(*begin);
  1560. if (size + 1 > total_length)
  1561. return SRT_CMD_NONE;
  1562. w_out_len = size;
  1563. if (total_length == size + 1)
  1564. w_next_block = NULL;
  1565. else
  1566. w_next_block = begin + 1 + size;
  1567. return cmd;
  1568. }
  1569. // NOTE: the rule of order of arguments is broken here because this order
  1570. // serves better the logics and readability.
  1571. template <class Integer>
  1572. static inline bool NextExtensionBlock(Integer*& w_begin, Integer* next, size_t& w_length)
  1573. {
  1574. if (!next)
  1575. return false;
  1576. w_length = w_length - (next - w_begin);
  1577. w_begin = next;
  1578. return true;
  1579. }
  1580. void SrtExtractHandshakeExtensions(const char* bufbegin, size_t buflength,
  1581. vector<SrtHandshakeExtension>& w_output)
  1582. {
  1583. const uint32_t *begin = reinterpret_cast<const uint32_t *>(bufbegin + CHandShake::m_iContentSize);
  1584. size_t size = buflength - CHandShake::m_iContentSize; // Due to previous cond check we grant it's >0
  1585. const uint32_t *next = 0;
  1586. size_t length = size / sizeof(uint32_t);
  1587. size_t blocklen = 0;
  1588. for (;;) // ONE SHOT, but continuable loop
  1589. {
  1590. const int cmd = FindExtensionBlock(begin, length, (blocklen), (next));
  1591. if (cmd == SRT_CMD_NONE)
  1592. {
  1593. // End of blocks
  1594. break;
  1595. }
  1596. w_output.push_back(SrtHandshakeExtension(cmd));
  1597. SrtHandshakeExtension& ext = w_output.back();
  1598. std::copy(begin+1, begin+blocklen+1, back_inserter(ext.contents));
  1599. // Any other kind of message extracted. Search on.
  1600. if (!NextExtensionBlock((begin), next, (length)))
  1601. break;
  1602. }
  1603. }
  1604. #if SRT_DEBUG_RTT
  1605. class RttTracer
  1606. {
  1607. public:
  1608. RttTracer()
  1609. {
  1610. }
  1611. ~RttTracer()
  1612. {
  1613. srt::sync::ScopedLock lck(m_mtx);
  1614. m_fout.close();
  1615. }
  1616. void trace(const srt::sync::steady_clock::time_point& currtime,
  1617. const std::string& event, int rtt_sample, int rttvar_sample,
  1618. bool is_smoothed_rtt_reset, int64_t recvTotal,
  1619. int smoothed_rtt, int rttvar)
  1620. {
  1621. srt::sync::ScopedLock lck(m_mtx);
  1622. create_file();
  1623. m_fout << srt::sync::FormatTimeSys(currtime) << ",";
  1624. m_fout << srt::sync::FormatTime(currtime) << ",";
  1625. m_fout << event << ",";
  1626. m_fout << rtt_sample << ",";
  1627. m_fout << rttvar_sample << ",";
  1628. m_fout << is_smoothed_rtt_reset << ",";
  1629. m_fout << recvTotal << ",";
  1630. m_fout << smoothed_rtt << ",";
  1631. m_fout << rttvar << "\n";
  1632. m_fout.flush();
  1633. }
  1634. private:
  1635. void print_header()
  1636. {
  1637. m_fout << "Timepoint_SYST,Timepoint_STDY,Event,usRTTSample,"
  1638. "usRTTVarSample,IsSmoothedRTTReset,pktsRecvTotal,"
  1639. "usSmoothedRTT,usRTTVar\n";
  1640. }
  1641. void create_file()
  1642. {
  1643. if (m_fout.is_open())
  1644. return;
  1645. std::string str_tnow = srt::sync::FormatTimeSys(srt::sync::steady_clock::now());
  1646. str_tnow.resize(str_tnow.size() - 7); // remove trailing ' [SYST]' part
  1647. while (str_tnow.find(':') != std::string::npos) {
  1648. str_tnow.replace(str_tnow.find(':'), 1, 1, '_');
  1649. }
  1650. const std::string fname = "rtt_trace_" + str_tnow + "_" + SRT_SYNC_CLOCK_STR + ".csv";
  1651. m_fout.open(fname, std::ofstream::out);
  1652. if (!m_fout)
  1653. std::cerr << "IPE: Failed to open " << fname << "!!!\n";
  1654. print_header();
  1655. }
  1656. private:
  1657. srt::sync::Mutex m_mtx;
  1658. std::ofstream m_fout;
  1659. };
  1660. RttTracer s_rtt_trace;
  1661. #endif
  1662. bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt)
  1663. {
  1664. uint32_t *srtdata = (uint32_t *)ctrlpkt->m_pcData;
  1665. size_t len = ctrlpkt->getLength();
  1666. int etype = ctrlpkt->getExtendedType();
  1667. uint32_t ts = ctrlpkt->m_iTimeStamp;
  1668. int res = SRT_CMD_NONE;
  1669. HLOGC(cnlog.Debug,
  1670. log << CONID() << "Dispatching message type=" << etype << " data length=" << (len / sizeof(int32_t)));
  1671. switch (etype)
  1672. {
  1673. case SRT_CMD_HSREQ:
  1674. {
  1675. res = processSrtMsg_HSREQ(srtdata, len, ts, CUDT::HS_VERSION_UDT4);
  1676. break;
  1677. }
  1678. case SRT_CMD_HSRSP:
  1679. {
  1680. res = processSrtMsg_HSRSP(srtdata, len, ts, CUDT::HS_VERSION_UDT4);
  1681. break;
  1682. }
  1683. case SRT_CMD_KMREQ:
  1684. // Special case when the data need to be processed here
  1685. // and the appropriate message must be constructed for sending.
  1686. // No further processing required
  1687. {
  1688. uint32_t srtdata_out[SRTDATA_MAXSIZE];
  1689. size_t len_out = 0;
  1690. res = m_pCryptoControl->processSrtMsg_KMREQ(srtdata, len, CUDT::HS_VERSION_UDT4,
  1691. (srtdata_out), (len_out));
  1692. if (res == SRT_CMD_KMRSP)
  1693. {
  1694. if (len_out == 1)
  1695. {
  1696. if (m_config.bEnforcedEnc)
  1697. {
  1698. LOGC(cnlog.Warn,
  1699. log << CONID() << "KMREQ FAILURE: " << KmStateStr(SRT_KM_STATE(srtdata_out[0]))
  1700. << " - rejecting per enforced encryption");
  1701. res = SRT_CMD_NONE;
  1702. break;
  1703. }
  1704. HLOGC(cnlog.Debug,
  1705. log << CONID()
  1706. << "MKREQ -> KMRSP FAILURE state: " << KmStateStr(SRT_KM_STATE(srtdata_out[0])));
  1707. }
  1708. else
  1709. {
  1710. HLOGC(cnlog.Debug, log << CONID() << "KMREQ -> requested to send KMRSP length=" << len_out);
  1711. }
  1712. sendSrtMsg(SRT_CMD_KMRSP, srtdata_out, len_out);
  1713. }
  1714. // XXX Dead code. processSrtMsg_KMREQ now doesn't return any other value now.
  1715. // Please review later.
  1716. else
  1717. {
  1718. LOGC(cnlog.Warn, log << CONID() << "KMREQ failed to process the request - ignoring");
  1719. }
  1720. return true; // already done what's necessary
  1721. }
  1722. case SRT_CMD_KMRSP:
  1723. {
  1724. // KMRSP doesn't expect any following action
  1725. m_pCryptoControl->processSrtMsg_KMRSP(srtdata, len, CUDT::HS_VERSION_UDT4);
  1726. return true; // nothing to do
  1727. }
  1728. default:
  1729. return false;
  1730. }
  1731. if (res == SRT_CMD_NONE)
  1732. return true;
  1733. // Send the message that the message handler requested.
  1734. sendSrtMsg(res);
  1735. return true;
  1736. }
  1737. int srt::CUDT::processSrtMsg_HSREQ(const uint32_t *srtdata, size_t bytelen, uint32_t ts, int hsv)
  1738. {
  1739. // Set this start time in the beginning, regardless as to whether TSBPD is being
  1740. // used or not. This must be done in the Initiator as well as Responder.
  1741. /*
  1742. * Compute peer StartTime in our time reference
  1743. * This takes time zone, time drift into account.
  1744. * Also includes current packet transit time (rtt/2)
  1745. */
  1746. m_tsRcvPeerStartTime = steady_clock::now() - microseconds_from(ts);
  1747. // (in case of bonding group, this value will be OVERWRITTEN
  1748. // later in CUDT::interpretGroup).
  1749. // Prepare the initial runtime values of latency basing on the option values.
  1750. // They are going to get the value fixed HERE.
  1751. m_iTsbPdDelay_ms = m_config.iRcvLatency;
  1752. m_iPeerTsbPdDelay_ms = m_config.iPeerLatency;
  1753. if (bytelen < SRT_CMD_HSREQ_MINSZ)
  1754. {
  1755. m_RejectReason = SRT_REJ_ROGUE;
  1756. /* Packet smaller than minimum compatible packet size */
  1757. LOGC(cnlog.Error, log << "HSREQ/rcv: cmd=" << SRT_CMD_HSREQ << "(HSREQ) len=" << bytelen << " invalid");
  1758. return SRT_CMD_NONE;
  1759. }
  1760. LOGC(cnlog.Note, log << "HSREQ/rcv: cmd=" << SRT_CMD_HSREQ << "(HSREQ) len=" << bytelen
  1761. << hex << " vers=0x" << srtdata[SRT_HS_VERSION] << " opts=0x" << srtdata[SRT_HS_FLAGS]
  1762. << dec << " delay=" << SRT_HS_LATENCY_RCV::unwrap(srtdata[SRT_HS_LATENCY]));
  1763. m_uPeerSrtVersion = srtdata[SRT_HS_VERSION];
  1764. m_uPeerSrtFlags = srtdata[SRT_HS_FLAGS];
  1765. if (hsv == CUDT::HS_VERSION_UDT4)
  1766. {
  1767. if (m_uPeerSrtVersion >= SRT_VERSION_FEAT_HSv5)
  1768. {
  1769. m_RejectReason = SRT_REJ_ROGUE;
  1770. LOGC(cnlog.Error,
  1771. log << CONID() << "HSREQ/rcv: With HSv4 version >= " << SrtVersionString(SRT_VERSION_FEAT_HSv5)
  1772. << " is not acceptable.");
  1773. return SRT_CMD_REJECT;
  1774. }
  1775. }
  1776. else
  1777. {
  1778. if (m_uPeerSrtVersion < SRT_VERSION_FEAT_HSv5)
  1779. {
  1780. m_RejectReason = SRT_REJ_ROGUE;
  1781. LOGC(cnlog.Error,
  1782. log << CONID() << "HSREQ/rcv: With HSv5 version must be >= " << SrtVersionString(SRT_VERSION_FEAT_HSv5)
  1783. << " .");
  1784. return SRT_CMD_REJECT;
  1785. }
  1786. }
  1787. // Check also if the version satisfies the minimum required version
  1788. if (m_uPeerSrtVersion < m_config.uMinimumPeerSrtVersion)
  1789. {
  1790. m_RejectReason = SRT_REJ_VERSION;
  1791. LOGC(cnlog.Error,
  1792. log << CONID() << "HSREQ/rcv: Peer version: " << SrtVersionString(m_uPeerSrtVersion)
  1793. << " is too old for requested: " << SrtVersionString(m_config.uMinimumPeerSrtVersion)
  1794. << " - REJECTING");
  1795. return SRT_CMD_REJECT;
  1796. }
  1797. HLOGC(cnlog.Debug,
  1798. log << CONID() << "HSREQ/rcv: PEER Version: " << SrtVersionString(m_uPeerSrtVersion)
  1799. << " Flags: " << m_uPeerSrtFlags << "(" << SrtFlagString(m_uPeerSrtFlags)
  1800. << ") Min req version:" << SrtVersionString(m_config.uMinimumPeerSrtVersion));
  1801. m_bPeerRexmitFlag = IsSet(m_uPeerSrtFlags, SRT_OPT_REXMITFLG);
  1802. HLOGC(cnlog.Debug, log << CONID() << "HSREQ/rcv: peer " << (m_bPeerRexmitFlag ? "UNDERSTANDS" : "DOES NOT UNDERSTAND") << " REXMIT flag");
  1803. // Check if both use the same API type. Reject if not.
  1804. bool peer_message_api = !IsSet(m_uPeerSrtFlags, SRT_OPT_STREAM);
  1805. if (peer_message_api != m_config.bMessageAPI)
  1806. {
  1807. m_RejectReason = SRT_REJ_MESSAGEAPI;
  1808. LOGC(cnlog.Error,
  1809. log << CONID() << "HSREQ/rcv: Agent uses " << (m_config.bMessageAPI ? "MESSAGE" : "STREAM")
  1810. << " API, but the Peer declares " << (peer_message_api ? "MESSAGE" : "STREAM")
  1811. << " API. Not compatible transmission type, rejecting.");
  1812. return SRT_CMD_REJECT;
  1813. }
  1814. SRT_STATIC_ASSERT(SRT_HS_E_SIZE == SRT_HS_LATENCY + 1, "Assuming latency is the last field");
  1815. if (bytelen < (SRT_HS_E_SIZE * sizeof(uint32_t)))
  1816. {
  1817. // Handshake extension message includes VERSION, FLAGS and LATENCY
  1818. // (3 x 32 bits). SRT v1.2.0 and earlier might supply shorter extension message,
  1819. // without LATENCY fields.
  1820. // It is acceptable, as long as the latency flags are not set on our side.
  1821. //
  1822. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  1823. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1824. // | SRT Version |
  1825. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1826. // | SRT Flags |
  1827. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1828. // | Receiver TSBPD Delay | Sender TSBPD Delay |
  1829. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1830. if (IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDSND) || IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDRCV))
  1831. {
  1832. m_RejectReason = SRT_REJ_ROGUE;
  1833. LOGC(cnlog.Error,
  1834. log << CONID()
  1835. << "HSREQ/rcv: Peer sent only VERSION + FLAGS HSREQ, but TSBPD flags are set. Rejecting.");
  1836. return SRT_CMD_REJECT;
  1837. }
  1838. LOGC(cnlog.Warn,
  1839. log << CONID() << "HSREQ/rcv: Peer sent only VERSION + FLAGS HSREQ, not getting any TSBPD settings.");
  1840. // Don't process any further settings in this case. Turn off TSBPD, just for a case.
  1841. m_bTsbPd = false;
  1842. m_bPeerTsbPd = false;
  1843. return SRT_CMD_HSRSP;
  1844. }
  1845. const uint32_t latencystr = srtdata[SRT_HS_LATENCY];
  1846. if (IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDSND))
  1847. {
  1848. // TimeStamp-based Packet Delivery feature enabled
  1849. if (!isOPT_TsbPd())
  1850. {
  1851. LOGC(cnlog.Warn,
  1852. log << CONID() << "HSREQ/rcv: Agent did not set rcv-TSBPD - ignoring proposed latency from peer");
  1853. // Note: also don't set the peer TSBPD flag HERE because
  1854. // - in HSv4 it will be a sender, so it doesn't matter anyway
  1855. // - in HSv5 if it's going to receive, the TSBPDRCV flag will define it.
  1856. }
  1857. else
  1858. {
  1859. int peer_decl_latency;
  1860. if (hsv < CUDT::HS_VERSION_SRT1)
  1861. {
  1862. // In HSv4 there is only one value and this is the latency
  1863. // that the sender peer proposes for the agent.
  1864. peer_decl_latency = SRT_HS_LATENCY_LEG::unwrap(latencystr);
  1865. }
  1866. else
  1867. {
  1868. // In HSv5 there are latency declared for sending and receiving separately.
  1869. // SRT_HS_LATENCY_SND is the value that the peer proposes to be the
  1870. // value used by agent when receiving data. We take this as a local latency value.
  1871. peer_decl_latency = SRT_HS_LATENCY_SND::unwrap(srtdata[SRT_HS_LATENCY]);
  1872. }
  1873. // Use the maximum latency out of latency from our settings and the latency
  1874. // "proposed" by the peer.
  1875. int maxdelay = std::max(m_iTsbPdDelay_ms, peer_decl_latency);
  1876. HLOGC(cnlog.Debug,
  1877. log << CONID() << "HSREQ/rcv: LOCAL/RCV LATENCY: Agent:" << m_iTsbPdDelay_ms
  1878. << " Peer:" << peer_decl_latency << " Selecting:" << maxdelay);
  1879. m_iTsbPdDelay_ms = maxdelay;
  1880. m_bTsbPd = true;
  1881. }
  1882. }
  1883. else
  1884. {
  1885. std::string how_about_agent = isOPT_TsbPd() ? "BUT AGENT DOES" : "and nor does Agent";
  1886. HLOGC(cnlog.Debug, log << CONID() << "HSREQ/rcv: Peer DOES NOT USE latency for sending - " << how_about_agent);
  1887. }
  1888. // This happens when the HSv5 RESPONDER receives the HSREQ message; it declares
  1889. // that the peer INITIATOR will receive the data and informs about its predefined
  1890. // latency. We need to maximize this with our setting of the peer's latency and
  1891. // record as peer's latency, which will be then sent back with HSRSP.
  1892. if (hsv > CUDT::HS_VERSION_UDT4 && IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDRCV))
  1893. {
  1894. // So, PEER uses TSBPD, set the flag.
  1895. // NOTE: it doesn't matter, if AGENT uses TSBPD.
  1896. m_bPeerTsbPd = true;
  1897. // SRT_HS_LATENCY_RCV is the value that the peer declares as to be
  1898. // used by it when receiving data. We take this as a peer's value,
  1899. // and select the maximum of this one and our proposed latency for the peer.
  1900. int peer_decl_latency = SRT_HS_LATENCY_RCV::unwrap(latencystr);
  1901. int maxdelay = std::max(m_iPeerTsbPdDelay_ms, peer_decl_latency);
  1902. HLOGC(cnlog.Debug,
  1903. log << CONID() << "HSREQ/rcv: PEER/RCV LATENCY: Agent:" << m_iPeerTsbPdDelay_ms
  1904. << " Peer:" << peer_decl_latency << " Selecting:" << maxdelay);
  1905. m_iPeerTsbPdDelay_ms = maxdelay;
  1906. }
  1907. else
  1908. {
  1909. std::string how_about_agent = isOPT_TsbPd() ? "BUT AGENT DOES" : "and nor does Agent";
  1910. HLOGC(cnlog.Debug,
  1911. log << CONID() << "HSREQ/rcv: Peer DOES NOT USE latency for receiving - " << how_about_agent);
  1912. }
  1913. if (hsv > CUDT::HS_VERSION_UDT4)
  1914. {
  1915. // This is HSv5, do the same things as required for the sending party in HSv4,
  1916. // as in HSv5 this can also be a sender.
  1917. if (IsSet(m_uPeerSrtFlags, SRT_OPT_TLPKTDROP))
  1918. {
  1919. // Too late packets dropping feature supported
  1920. m_bPeerTLPktDrop = true;
  1921. }
  1922. if (IsSet(m_uPeerSrtFlags, SRT_OPT_NAKREPORT))
  1923. {
  1924. // Peer will send Periodic NAK Reports
  1925. m_bPeerNakReport = true;
  1926. }
  1927. }
  1928. return SRT_CMD_HSRSP;
  1929. }
  1930. int srt::CUDT::processSrtMsg_HSRSP(const uint32_t *srtdata, size_t bytelen, uint32_t ts, int hsv)
  1931. {
  1932. // XXX Check for mis-version
  1933. // With HSv4 we accept only version less than 1.3.0
  1934. if (hsv == CUDT::HS_VERSION_UDT4 && srtdata[SRT_HS_VERSION] >= SRT_VERSION_FEAT_HSv5)
  1935. {
  1936. LOGC(cnlog.Error, log << CONID() << "HSRSP/rcv: With HSv4 version >= 1.2.0 is not acceptable.");
  1937. return SRT_CMD_NONE;
  1938. }
  1939. if (bytelen < SRT_CMD_HSRSP_MINSZ)
  1940. {
  1941. /* Packet smaller than minimum compatible packet size */
  1942. LOGC(cnlog.Error, log << CONID() << "HSRSP/rcv: cmd=" << SRT_CMD_HSRSP << "(HSRSP) len=" << bytelen << " invalid");
  1943. return SRT_CMD_NONE;
  1944. }
  1945. // Set this start time in the beginning, regardless as to whether TSBPD is being
  1946. // used or not. This must be done in the Initiator as well as Responder. In case when
  1947. // agent is sender only (HSv4) this value simply won't be used.
  1948. /*
  1949. * Compute peer StartTime in our time reference
  1950. * This takes time zone, time drift into account.
  1951. * Also includes current packet transit time (rtt/2)
  1952. */
  1953. if (is_zero(m_tsRcvPeerStartTime))
  1954. {
  1955. // Do not set this time when it's already set, which may be the case
  1956. // if the agent has this value already "borrowed" from a master socket
  1957. // that was in the group at the time when it was added.
  1958. m_tsRcvPeerStartTime = steady_clock::now() - microseconds_from(ts);
  1959. HLOGC(cnlog.Debug,
  1960. log << CONID()
  1961. << "HSRSP/rcv: PEER START TIME not yet defined, setting: " << FormatTime(m_tsRcvPeerStartTime));
  1962. }
  1963. else
  1964. {
  1965. HLOGC(cnlog.Debug,
  1966. log << CONID()
  1967. << "HSRSP/rcv: PEER START TIME already set (derived): " << FormatTime(m_tsRcvPeerStartTime));
  1968. }
  1969. m_uPeerSrtVersion = srtdata[SRT_HS_VERSION];
  1970. m_uPeerSrtFlags = srtdata[SRT_HS_FLAGS];
  1971. HLOGC(cnlog.Debug, log << "HSRSP/rcv: Version: " << SrtVersionString(m_uPeerSrtVersion)
  1972. << " Flags: SND:" << setw(8) << setfill('0') << hex << m_uPeerSrtFlags
  1973. << setw(0) << " (" << SrtFlagString(m_uPeerSrtFlags) << ")");
  1974. // Basic version check
  1975. if (m_uPeerSrtVersion < m_config.uMinimumPeerSrtVersion)
  1976. {
  1977. m_RejectReason = SRT_REJ_VERSION;
  1978. LOGC(cnlog.Error,
  1979. log << CONID() << "HSRSP/rcv: Peer version: " << SrtVersionString(m_uPeerSrtVersion)
  1980. << " is too old for requested: " << SrtVersionString(m_config.uMinimumPeerSrtVersion)
  1981. << " - REJECTING");
  1982. return SRT_CMD_REJECT;
  1983. }
  1984. if (hsv == CUDT::HS_VERSION_UDT4)
  1985. {
  1986. // The old HSv4 way: extract just one value and put it under peer.
  1987. if (IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDRCV))
  1988. {
  1989. // TsbPd feature enabled
  1990. m_bPeerTsbPd = true;
  1991. m_iPeerTsbPdDelay_ms = SRT_HS_LATENCY_LEG::unwrap(srtdata[SRT_HS_LATENCY]);
  1992. HLOGC(cnlog.Debug,
  1993. log << CONID() << "HSRSP/rcv: LATENCY: Peer/snd:" << m_iPeerTsbPdDelay_ms
  1994. << " (Agent: declared:" << m_iTsbPdDelay_ms << " rcv:" << m_iTsbPdDelay_ms << ")");
  1995. }
  1996. // TSBPDSND isn't set in HSv4 by the RESPONDER, because HSv4 RESPONDER is always RECEIVER.
  1997. }
  1998. else
  1999. {
  2000. // HSv5 way: extract the receiver latency and sender latency, if used.
  2001. // PEER WILL RECEIVE TSBPD == AGENT SHALL SEND TSBPD.
  2002. if (IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDRCV))
  2003. {
  2004. // TsbPd feature enabled
  2005. m_bPeerTsbPd = true;
  2006. m_iPeerTsbPdDelay_ms = SRT_HS_LATENCY_RCV::unwrap(srtdata[SRT_HS_LATENCY]);
  2007. HLOGC(cnlog.Debug, log << CONID() << "HSRSP/rcv: LATENCY: Peer/snd:" << m_iPeerTsbPdDelay_ms << "ms");
  2008. }
  2009. else
  2010. {
  2011. HLOGC(cnlog.Debug, log << CONID() << "HSRSP/rcv: Peer (responder) DOES NOT USE latency");
  2012. }
  2013. // PEER WILL SEND TSBPD == AGENT SHALL RECEIVE TSBPD.
  2014. if (IsSet(m_uPeerSrtFlags, SRT_OPT_TSBPDSND))
  2015. {
  2016. if (!isOPT_TsbPd())
  2017. {
  2018. LOGC(cnlog.Warn,
  2019. log << CONID()
  2020. << "HSRSP/rcv: BUG? Peer (responder) declares sending latency, but Agent turned off TSBPD.");
  2021. }
  2022. else
  2023. {
  2024. m_bTsbPd = true; // NOTE: in case of Group TSBPD receiving, this field will be SWITCHED TO m_bGroupTsbPd.
  2025. // Take this value as a good deal. In case when the Peer did not "correct" the latency
  2026. // because it has TSBPD turned off, just stay with the present value defined in options.
  2027. m_iTsbPdDelay_ms = SRT_HS_LATENCY_SND::unwrap(srtdata[SRT_HS_LATENCY]);
  2028. HLOGC(cnlog.Debug, log << CONID() << "HSRSP/rcv: LATENCY Agent/rcv: " << m_iTsbPdDelay_ms << "ms");
  2029. }
  2030. }
  2031. }
  2032. if ((m_config.uSrtVersion >= SrtVersion(1, 0, 5)) && IsSet(m_uPeerSrtFlags, SRT_OPT_TLPKTDROP))
  2033. {
  2034. // Too late packets dropping feature supported
  2035. m_bPeerTLPktDrop = true;
  2036. }
  2037. if ((m_config.uSrtVersion >= SrtVersion(1, 1, 0)) && IsSet(m_uPeerSrtFlags, SRT_OPT_NAKREPORT))
  2038. {
  2039. // Peer will send Periodic NAK Reports
  2040. m_bPeerNakReport = true;
  2041. }
  2042. if (m_config.uSrtVersion >= SrtVersion(1, 2, 0))
  2043. {
  2044. if (IsSet(m_uPeerSrtFlags, SRT_OPT_REXMITFLG))
  2045. {
  2046. // Peer will use REXMIT flag in packet retransmission.
  2047. m_bPeerRexmitFlag = true;
  2048. HLOGP(cnlog.Debug, "HSRSP/rcv: 1.2.0+ Agent understands REXMIT flag and so does peer.");
  2049. }
  2050. else
  2051. {
  2052. HLOGP(cnlog.Debug, "HSRSP/rcv: Agent understands REXMIT flag, but PEER DOES NOT");
  2053. }
  2054. }
  2055. else
  2056. {
  2057. HLOGP(cnlog.Debug, "HSRSP/rcv: <1.2.0 Agent DOESN'T understand REXMIT flag");
  2058. }
  2059. handshakeDone();
  2060. return SRT_CMD_NONE;
  2061. }
  2062. // This function is called only when the URQ_CONCLUSION handshake has been received from the peer.
  2063. bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,
  2064. const CPacket& hspkt,
  2065. uint32_t* out_data SRT_ATR_UNUSED,
  2066. size_t* pw_len)
  2067. {
  2068. // Initialize pw_len to 0 to handle the unencrypted case
  2069. if (pw_len)
  2070. *pw_len = 0;
  2071. // The version=0 statement as rejection is used only since HSv5.
  2072. // The HSv4 sends the AGREEMENT handshake message with version=0, do not misinterpret it.
  2073. if (m_ConnRes.m_iVersion > HS_VERSION_UDT4 && hs.m_iVersion == 0)
  2074. {
  2075. m_RejectReason = SRT_REJ_PEER;
  2076. LOGC(cnlog.Error, log << CONID() << "HS VERSION = 0, meaning the handshake has been rejected.");
  2077. return false;
  2078. }
  2079. if (hs.m_iVersion < HS_VERSION_SRT1)
  2080. {
  2081. if (m_config.uMinimumPeerSrtVersion && m_config.uMinimumPeerSrtVersion >= SRT_VERSION_FEAT_HSv5)
  2082. {
  2083. m_RejectReason = SRT_REJ_VERSION;
  2084. // This means that a version with minimum 1.3.0 that features HSv5 is required,
  2085. // hence all HSv4 clients should be rejected.
  2086. LOGP(cnlog.Error, "interpretSrtHandshake: minimum peer version 1.3.0 (HSv5 only), rejecting HSv4 client");
  2087. return false;
  2088. }
  2089. return true; // do nothing
  2090. }
  2091. // Anyway, check if the handshake contains any extra data.
  2092. if (hspkt.getLength() <= CHandShake::m_iContentSize)
  2093. {
  2094. m_RejectReason = SRT_REJ_ROGUE;
  2095. // This would mean that the handshake was at least HSv5, but somehow no extras were added.
  2096. // Dismiss it then, however this has to be logged.
  2097. LOGC(cnlog.Error, log << CONID() << "HS VERSION=" << hs.m_iVersion << " but no handshake extension found!");
  2098. return false;
  2099. }
  2100. // We still believe it should work, let's check the flags.
  2101. const int ext_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(hs.m_iType);
  2102. if (ext_flags == 0)
  2103. {
  2104. m_RejectReason = SRT_REJ_ROGUE;
  2105. LOGC(cnlog.Error,
  2106. log << CONID() << "HS VERSION=" << hs.m_iVersion << " but no handshake extension flags are set!");
  2107. return false;
  2108. }
  2109. HLOGC(cnlog.Debug,
  2110. log << CONID() << "HS VERSION=" << hs.m_iVersion
  2111. << " EXTENSIONS: " << CHandShake::ExtensionFlagStr(ext_flags));
  2112. // Ok, now find the beginning of an int32_t array that follows the UDT handshake.
  2113. uint32_t* p = reinterpret_cast<uint32_t*>(hspkt.m_pcData + CHandShake::m_iContentSize);
  2114. size_t size = hspkt.getLength() - CHandShake::m_iContentSize; // Due to previous cond check we grant it's >0
  2115. int hsreq_type_cmd SRT_ATR_UNUSED = SRT_CMD_NONE;
  2116. if (IsSet(ext_flags, CHandShake::HS_EXT_HSREQ))
  2117. {
  2118. HLOGC(cnlog.Debug, log << CONID() << "interpretSrtHandshake: extracting HSREQ/RSP type extension");
  2119. uint32_t *begin = p;
  2120. uint32_t *next = 0;
  2121. size_t length = size / sizeof(uint32_t);
  2122. size_t blocklen = 0;
  2123. for (;;) // this is ONE SHOT LOOP
  2124. {
  2125. int cmd = FindExtensionBlock(begin, length, (blocklen), (next));
  2126. size_t bytelen = blocklen * sizeof(uint32_t);
  2127. if (cmd == SRT_CMD_HSREQ)
  2128. {
  2129. hsreq_type_cmd = cmd;
  2130. // Set is the size as it should, then give it for interpretation for
  2131. // the proper function.
  2132. if (blocklen < SRT_HS_E_SIZE)
  2133. {
  2134. m_RejectReason = SRT_REJ_ROGUE;
  2135. LOGC(cnlog.Error,
  2136. log << CONID() << "HS-ext HSREQ found but invalid size: " << bytelen
  2137. << " (expected: " << SRT_HS_E_SIZE << ")");
  2138. return false; // don't interpret
  2139. }
  2140. int rescmd = processSrtMsg_HSREQ(begin + 1, bytelen, hspkt.m_iTimeStamp, HS_VERSION_SRT1);
  2141. // Interpreted? Then it should be responded with SRT_CMD_HSRSP.
  2142. if (rescmd != SRT_CMD_HSRSP)
  2143. {
  2144. // m_RejectReason already set
  2145. LOGC(cnlog.Error,
  2146. log << CONID() << "interpretSrtHandshake: process HSREQ returned unexpected value " << rescmd);
  2147. return false;
  2148. }
  2149. handshakeDone();
  2150. // updateAfterSrtHandshake -> moved to postConnect and processRendezvous
  2151. }
  2152. else if (cmd == SRT_CMD_HSRSP)
  2153. {
  2154. hsreq_type_cmd = cmd;
  2155. // Set is the size as it should, then give it for interpretation for
  2156. // the proper function.
  2157. if (blocklen < SRT_HS_E_SIZE)
  2158. {
  2159. m_RejectReason = SRT_REJ_ROGUE;
  2160. LOGC(cnlog.Error,
  2161. log << CONID() << "HS-ext HSRSP found but invalid size: " << bytelen
  2162. << " (expected: " << SRT_HS_E_SIZE << ")");
  2163. return false; // don't interpret
  2164. }
  2165. int rescmd = processSrtMsg_HSRSP(begin + 1, bytelen, hspkt.m_iTimeStamp, HS_VERSION_SRT1);
  2166. // Interpreted? Then it should be responded with SRT_CMD_NONE.
  2167. // (nothing to be responded for HSRSP, unless there was some kinda problem)
  2168. if (rescmd != SRT_CMD_NONE)
  2169. {
  2170. // Just formally; the current code doesn't seem to return anything else
  2171. // (unless it's already set)
  2172. if (m_RejectReason == SRT_REJ_UNKNOWN)
  2173. m_RejectReason = SRT_REJ_ROGUE;
  2174. LOGC(cnlog.Error,
  2175. log << CONID() << "interpretSrtHandshake: process HSRSP returned unexpected value " << rescmd);
  2176. return false;
  2177. }
  2178. handshakeDone();
  2179. // updateAfterSrtHandshake -> moved to postConnect and processRendezvous
  2180. }
  2181. else if (cmd == SRT_CMD_NONE)
  2182. {
  2183. m_RejectReason = SRT_REJ_ROGUE;
  2184. LOGC(cnlog.Warn,
  2185. log << CONID() << "interpretSrtHandshake: no HSREQ/HSRSP block found in the handshake msg!");
  2186. // This means that there can be no more processing done by FindExtensionBlock().
  2187. // And we haven't found what we need - otherwise one of the above cases would pass
  2188. // and lead to exit this loop immediately.
  2189. return false;
  2190. }
  2191. else
  2192. {
  2193. // Any other kind of message extracted. Search on.
  2194. length -= (next - begin);
  2195. begin = next;
  2196. if (begin)
  2197. continue;
  2198. }
  2199. break;
  2200. }
  2201. }
  2202. HLOGC(cnlog.Debug, log << CONID() << "interpretSrtHandshake: HSREQ done, checking KMREQ");
  2203. // Now check the encrypted
  2204. bool encrypted = false;
  2205. if (IsSet(ext_flags, CHandShake::HS_EXT_KMREQ))
  2206. {
  2207. HLOGC(cnlog.Debug, log << CONID() << "interpretSrtHandshake: extracting KMREQ/RSP type extension");
  2208. #ifdef SRT_ENABLE_ENCRYPTION
  2209. if (!m_pCryptoControl->hasPassphrase())
  2210. {
  2211. if (m_config.bEnforcedEnc)
  2212. {
  2213. m_RejectReason = SRT_REJ_UNSECURE;
  2214. LOGC(cnlog.Error,
  2215. log << CONID()
  2216. << "HS KMREQ: Peer declares encryption, but agent does not - rejecting per enforced "
  2217. "encryption");
  2218. return false;
  2219. }
  2220. LOGC(cnlog.Warn,
  2221. log << CONID()
  2222. << "HS KMREQ: Peer declares encryption, but agent does not - still allowing connection.");
  2223. // Still allow for connection, and allow Agent to send unencrypted stream to the peer.
  2224. // Also normally allow the key to be processed; worst case it will send the failure response.
  2225. }
  2226. uint32_t *begin = p;
  2227. uint32_t *next = 0;
  2228. size_t length = size / sizeof(uint32_t);
  2229. size_t blocklen = 0;
  2230. for (;;) // This is one shot loop, unless REPEATED by 'continue'.
  2231. {
  2232. int cmd = FindExtensionBlock(begin, length, (blocklen), (next));
  2233. HLOGC(cnlog.Debug,
  2234. log << CONID() << "interpretSrtHandshake: found extension: (" << cmd << ") "
  2235. << MessageTypeStr(UMSG_EXT, cmd));
  2236. size_t bytelen = blocklen * sizeof(uint32_t);
  2237. if (cmd == SRT_CMD_KMREQ)
  2238. {
  2239. if (!out_data || !pw_len)
  2240. {
  2241. m_RejectReason = SRT_REJ_IPE;
  2242. LOGC(cnlog.Fatal, log << CONID() << "IPE: HS/KMREQ extracted without passing target buffer!");
  2243. return false;
  2244. }
  2245. int res = m_pCryptoControl->processSrtMsg_KMREQ(begin + 1, bytelen, HS_VERSION_SRT1,
  2246. (out_data), (*pw_len));
  2247. if (res != SRT_CMD_KMRSP)
  2248. {
  2249. m_RejectReason = SRT_REJ_IPE;
  2250. // Something went wrong.
  2251. HLOGC(cnlog.Debug,
  2252. log << CONID() << "interpretSrtHandshake: IPE/EPE KMREQ processing failed - returned "
  2253. << res);
  2254. return false;
  2255. }
  2256. if (*pw_len == 1)
  2257. {
  2258. #ifdef ENABLE_AEAD_API_PREVIEW
  2259. if (m_pCryptoControl->m_RcvKmState == SRT_KM_S_BADCRYPTOMODE)
  2260. {
  2261. // Cryptographic modes mismatch. Not acceptable at all.
  2262. m_RejectReason = SRT_REJ_CRYPTO;
  2263. LOGC(cnlog.Error,
  2264. log << CONID()
  2265. << "interpretSrtHandshake: KMREQ result: Bad crypto mode - rejecting");
  2266. return false;
  2267. }
  2268. #endif
  2269. // This means that there was an abnormal encryption situation occurred.
  2270. // This is inacceptable in case of strict encryption.
  2271. if (m_config.bEnforcedEnc)
  2272. {
  2273. if (m_pCryptoControl->m_RcvKmState == SRT_KM_S_BADSECRET)
  2274. {
  2275. m_RejectReason = SRT_REJ_BADSECRET;
  2276. }
  2277. else
  2278. {
  2279. m_RejectReason = SRT_REJ_UNSECURE;
  2280. }
  2281. LOGC(cnlog.Error,
  2282. log << CONID()
  2283. << "interpretSrtHandshake: KMREQ result abnornal - rejecting per enforced encryption");
  2284. return false;
  2285. }
  2286. }
  2287. encrypted = true;
  2288. }
  2289. else if (cmd == SRT_CMD_KMRSP)
  2290. {
  2291. int res = m_pCryptoControl->processSrtMsg_KMRSP(begin + 1, bytelen, HS_VERSION_SRT1);
  2292. if (m_config.bEnforcedEnc && res == -1)
  2293. {
  2294. if (m_pCryptoControl->m_SndKmState == SRT_KM_S_BADSECRET)
  2295. m_RejectReason = SRT_REJ_BADSECRET;
  2296. #ifdef ENABLE_AEAD_API_PREVIEW
  2297. else if (m_pCryptoControl->m_SndKmState == SRT_KM_S_BADCRYPTOMODE)
  2298. m_RejectReason = SRT_REJ_CRYPTO;
  2299. #endif
  2300. else
  2301. m_RejectReason = SRT_REJ_UNSECURE;
  2302. LOGC(cnlog.Error,
  2303. log << CONID() << "KMRSP failed - rejecting connection as per enforced encryption.");
  2304. return false;
  2305. }
  2306. encrypted = true;
  2307. }
  2308. else if (cmd == SRT_CMD_NONE)
  2309. {
  2310. m_RejectReason = SRT_REJ_ROGUE;
  2311. LOGC(cnlog.Error, log << CONID() << "HS KMREQ expected - none found!");
  2312. return false;
  2313. }
  2314. else
  2315. {
  2316. HLOGC(cnlog.Debug, log << CONID() << "interpretSrtHandshake: ... skipping " << MessageTypeStr(UMSG_EXT, cmd));
  2317. if (NextExtensionBlock((begin), next, (length)))
  2318. continue;
  2319. }
  2320. break;
  2321. }
  2322. #else
  2323. // When encryption is not enabled at compile time, behave as if encryption wasn't set,
  2324. // so accordingly to StrictEncryption flag.
  2325. if (m_config.bEnforcedEnc)
  2326. {
  2327. m_RejectReason = SRT_REJ_UNSECURE;
  2328. LOGC(cnlog.Error,
  2329. log << CONID()
  2330. << "HS KMREQ: Peer declares encryption, but agent didn't enable it at compile time - rejecting "
  2331. "per enforced encryption");
  2332. return false;
  2333. }
  2334. LOGC(cnlog.Warn,
  2335. log << CONID()
  2336. << "HS KMREQ: Peer declares encryption, but agent didn't enable it at compile time - still allowing "
  2337. "connection.");
  2338. encrypted = true;
  2339. #endif
  2340. }
  2341. bool have_congctl = false;
  2342. bool have_filter = false;
  2343. string agsm = m_config.sCongestion.str();
  2344. if (agsm == "")
  2345. {
  2346. agsm = "live";
  2347. m_config.sCongestion.set("live", 4);
  2348. }
  2349. bool have_group SRT_ATR_UNUSED = false;
  2350. if (IsSet(ext_flags, CHandShake::HS_EXT_CONFIG))
  2351. {
  2352. HLOGC(cnlog.Debug, log << CONID() << "interpretSrtHandshake: extracting various CONFIG extensions");
  2353. uint32_t *begin = p;
  2354. uint32_t *next = 0;
  2355. size_t length = size / sizeof(uint32_t);
  2356. size_t blocklen = 0;
  2357. for (;;) // This is one shot loop, unless REPEATED by 'continue'.
  2358. {
  2359. int cmd = FindExtensionBlock(begin, length, (blocklen), (next));
  2360. HLOGC(cnlog.Debug,
  2361. log << CONID() << "interpretSrtHandshake: found extension: (" << cmd << ") "
  2362. << MessageTypeStr(UMSG_EXT, cmd));
  2363. const size_t bytelen = blocklen * sizeof(uint32_t);
  2364. if (cmd == SRT_CMD_SID)
  2365. {
  2366. if (!bytelen || bytelen > CSrtConfig::MAX_SID_LENGTH)
  2367. {
  2368. LOGC(cnlog.Error,
  2369. log << CONID() << "interpretSrtHandshake: STREAMID length " << bytelen << " is 0 or > "
  2370. << +CSrtConfig::MAX_SID_LENGTH << " - PROTOCOL ERROR, REJECTING");
  2371. return false;
  2372. }
  2373. // Copied through a cleared array. This is because the length is aligned to 4
  2374. // where the padding is filled by zero bytes. For the case when the string is
  2375. // exactly of a 4-divisible length, we make a big array with maximum allowed size
  2376. // filled with zeros. Copying to this array should then copy either only the valid
  2377. // characters of the string (if the length is divisible by 4), or the string with
  2378. // padding zeros. In all these cases in the resulting array we should have all
  2379. // subsequent characters of the string plus at least one '\0' at the end. This will
  2380. // make it a perfect NUL-terminated string, to be used to initialize a string.
  2381. char target[CSrtConfig::MAX_SID_LENGTH + 1];
  2382. memset((target), 0, CSrtConfig::MAX_SID_LENGTH + 1);
  2383. memcpy((target), begin + 1, bytelen);
  2384. // Un-swap on big endian machines
  2385. ItoHLA((uint32_t *)target, (uint32_t *)target, blocklen);
  2386. m_config.sStreamName.set(target, strlen(target));
  2387. HLOGC(cnlog.Debug,
  2388. log << CONID() << "CONNECTOR'S REQUESTED SID [" << m_config.sStreamName.c_str()
  2389. << "] (bytelen=" << bytelen << " blocklen=" << blocklen << ")");
  2390. }
  2391. else if (cmd == SRT_CMD_CONGESTION)
  2392. {
  2393. if (have_congctl)
  2394. {
  2395. m_RejectReason = SRT_REJ_ROGUE;
  2396. LOGC(cnlog.Error, log << CONID() << "CONGCTL BLOCK REPEATED!");
  2397. return false;
  2398. }
  2399. if (!bytelen || bytelen > CSrtConfig::MAX_CONG_LENGTH)
  2400. {
  2401. LOGC(cnlog.Error,
  2402. log << CONID() << "interpretSrtHandshake: CONGESTION-control type length " << bytelen
  2403. << " is 0 or > " << +CSrtConfig::MAX_CONG_LENGTH << " - PROTOCOL ERROR, REJECTING");
  2404. return false;
  2405. }
  2406. // Declare that congctl has been received
  2407. have_congctl = true;
  2408. char target[CSrtConfig::MAX_CONG_LENGTH + 1];
  2409. memset((target), 0, CSrtConfig::MAX_CONG_LENGTH + 1);
  2410. memcpy((target), begin + 1, bytelen);
  2411. // Un-swap on big endian machines
  2412. ItoHLA((uint32_t *)target, (uint32_t *)target, blocklen);
  2413. string sm = target;
  2414. // As the congctl has been declared by the peer,
  2415. // check if your congctl is compatible.
  2416. // sm cannot be empty, but the agent's sm can be empty meaning live.
  2417. if (sm != agsm)
  2418. {
  2419. m_RejectReason = SRT_REJ_CONGESTION;
  2420. LOGC(cnlog.Error,
  2421. log << CONID() << "PEER'S CONGCTL '" << sm << "' does not match AGENT'S CONGCTL '" << agsm
  2422. << "'");
  2423. return false;
  2424. }
  2425. HLOGC(cnlog.Debug,
  2426. log << CONID() << "CONNECTOR'S CONGCTL [" << sm << "] (bytelen=" << bytelen
  2427. << " blocklen=" << blocklen << ")");
  2428. }
  2429. else if (cmd == SRT_CMD_FILTER)
  2430. {
  2431. if (have_filter)
  2432. {
  2433. m_RejectReason = SRT_REJ_FILTER;
  2434. LOGC(cnlog.Error, log << CONID() << "FILTER BLOCK REPEATED!");
  2435. return false;
  2436. }
  2437. if (!bytelen || bytelen > CSrtConfig::MAX_PFILTER_LENGTH)
  2438. {
  2439. LOGC(cnlog.Error,
  2440. log << CONID() << "interpretSrtHandshake: packet-filter type length " << bytelen
  2441. << " is 0 or > " << +CSrtConfig::MAX_PFILTER_LENGTH << " - PROTOCOL ERROR, REJECTING");
  2442. return false;
  2443. }
  2444. // Declare that filter has been received
  2445. have_filter = true;
  2446. char target[CSrtConfig::MAX_PFILTER_LENGTH + 1];
  2447. memset((target), 0, CSrtConfig::MAX_PFILTER_LENGTH + 1);
  2448. memcpy((target), begin + 1, bytelen);
  2449. // Un-swap on big endian machines
  2450. ItoHLA((uint32_t *)target, (uint32_t *)target, blocklen);
  2451. string fltcfg = target;
  2452. HLOGC(cnlog.Debug,
  2453. log << CONID() << "PEER'S FILTER CONFIG [" << fltcfg << "] (bytelen=" << bytelen
  2454. << " blocklen=" << blocklen << ")");
  2455. if (!checkApplyFilterConfig(fltcfg))
  2456. {
  2457. m_RejectReason = SRT_REJ_FILTER;
  2458. LOGC(cnlog.Error, log << CONID() << "PEER'S FILTER CONFIG [" << fltcfg << "] has been rejected");
  2459. return false;
  2460. }
  2461. }
  2462. #if ENABLE_BONDING
  2463. else if ( cmd == SRT_CMD_GROUP )
  2464. {
  2465. // Note that this will fire in both cases:
  2466. // - When receiving HS request from the Initiator, which belongs to a group, and agent must
  2467. // create the mirror group on his side (or join the existing one, if there's already
  2468. // a mirror group for that group ID).
  2469. // - When receiving HS response from the Responder, with its mirror group ID, so the agent
  2470. // must put the group into his peer group data
  2471. int32_t groupdata[GRPD_E_SIZE] = {};
  2472. if (bytelen < GRPD_MIN_SIZE * GRPD_FIELD_SIZE || bytelen % GRPD_FIELD_SIZE)
  2473. {
  2474. m_RejectReason = SRT_REJ_ROGUE;
  2475. LOGC(cnlog.Error, log << CONID() << "PEER'S GROUP wrong size: " << (bytelen/GRPD_FIELD_SIZE));
  2476. return false;
  2477. }
  2478. size_t groupdata_size = bytelen / GRPD_FIELD_SIZE;
  2479. memcpy(groupdata, begin+1, bytelen);
  2480. if (!interpretGroup(groupdata, groupdata_size, hsreq_type_cmd) )
  2481. {
  2482. // m_RejectReason handled inside interpretGroup().
  2483. return false;
  2484. }
  2485. have_group = true;
  2486. HLOGC(cnlog.Debug,
  2487. log << CONID() << "CONNECTOR'S PEER GROUP [" << groupdata[0] << "] (bytelen=" << bytelen
  2488. << " blocklen=" << blocklen << ")");
  2489. }
  2490. #endif
  2491. else if (cmd == SRT_CMD_NONE)
  2492. {
  2493. break;
  2494. }
  2495. else
  2496. {
  2497. // Found some block that is not interesting here. Skip this and get the next one.
  2498. HLOGC(cnlog.Debug,
  2499. log << CONID() << "interpretSrtHandshake: ... skipping " << MessageTypeStr(UMSG_EXT, cmd));
  2500. }
  2501. if (!NextExtensionBlock((begin), next, (length)))
  2502. break;
  2503. }
  2504. }
  2505. // Post-checks
  2506. // Check if peer declared encryption
  2507. if (!encrypted && m_config.CryptoSecret.len > 0)
  2508. {
  2509. if (m_config.bEnforcedEnc)
  2510. {
  2511. m_RejectReason = SRT_REJ_UNSECURE;
  2512. LOGC(cnlog.Error,
  2513. log << CONID()
  2514. << "HS EXT: Agent declares encryption, but Peer does not - rejecting connection per "
  2515. "enforced encryption.");
  2516. return false;
  2517. }
  2518. LOGC(cnlog.Warn,
  2519. log << CONID()
  2520. << "HS EXT: Agent declares encryption, but Peer does not (Agent can still receive unencrypted packets "
  2521. "from Peer).");
  2522. // This is required so that the sender is still allowed to send data, when encryption is required,
  2523. // just this will be for waste because the receiver won't decrypt them anyway.
  2524. m_pCryptoControl->createFakeSndContext();
  2525. m_pCryptoControl->m_SndKmState = SRT_KM_S_NOSECRET; // Because Peer did not send KMX, though Agent has pw
  2526. m_pCryptoControl->m_RcvKmState = SRT_KM_S_UNSECURED; // Because Peer has no PW, as has sent no KMREQ.
  2527. return true;
  2528. }
  2529. // If agent has set some nondefault congctl, then congctl is expected from the peer.
  2530. if (agsm != "live" && !have_congctl)
  2531. {
  2532. m_RejectReason = SRT_REJ_CONGESTION;
  2533. LOGC(cnlog.Error,
  2534. log << CONID() << "HS EXT: Agent uses '" << agsm
  2535. << "' congctl, but peer DID NOT DECLARE congctl (assuming 'live').");
  2536. return false;
  2537. }
  2538. #if ENABLE_BONDING
  2539. // m_GroupOf and locking info: NULL check won't hurt here. If the group
  2540. // was deleted in the meantime, it will be found out later anyway and result with error.
  2541. if (m_SrtHsSide == HSD_INITIATOR && m_parent->m_GroupOf)
  2542. {
  2543. // XXX Later probably needs to check if this group REQUIRES the group
  2544. // response. Currently this implements the bonding-category group, and this
  2545. // always requires that the listener respond with the group id, otherwise
  2546. // it probably DID NOT UNDERSTAND THE GROUP, so the connection should be rejected.
  2547. if (!have_group)
  2548. {
  2549. m_RejectReason = SRT_REJ_GROUP;
  2550. LOGC(cnlog.Error,
  2551. log << CONID()
  2552. << "HS EXT: agent is a group member, but the listener did not respond with group ID. Rejecting.");
  2553. return false;
  2554. }
  2555. }
  2556. #endif
  2557. // Ok, finished, for now.
  2558. return true;
  2559. }
  2560. bool srt::CUDT::checkApplyFilterConfig(const std::string &confstr)
  2561. {
  2562. SrtFilterConfig cfg;
  2563. if (!ParseFilterConfig(confstr, (cfg)))
  2564. return false;
  2565. // Now extract the type, if present, and
  2566. // check if you have this type of corrector available.
  2567. if (!PacketFilter::correctConfig(cfg))
  2568. return false;
  2569. string thisconf = m_config.sPacketFilterConfig.str();
  2570. // Now parse your own string, if you have it.
  2571. if (thisconf != "")
  2572. {
  2573. // - for rendezvous, both must be exactly the same (it's unspecified, which will be the first one)
  2574. if (m_config.bRendezvous && thisconf != confstr)
  2575. {
  2576. return false;
  2577. }
  2578. SrtFilterConfig mycfg;
  2579. if (!ParseFilterConfig(thisconf, (mycfg)))
  2580. return false;
  2581. // Check only if both have set a filter of the same type.
  2582. if (mycfg.type != cfg.type)
  2583. return false;
  2584. // If so, then:
  2585. // - for caller-listener configuration, accept the listener version.
  2586. if (m_SrtHsSide == HSD_INITIATOR)
  2587. {
  2588. // This is a caller, this should apply all parameters received
  2589. // from the listener, forcefully.
  2590. for (map<string, string>::iterator x = cfg.parameters.begin(); x != cfg.parameters.end(); ++x)
  2591. {
  2592. mycfg.parameters[x->first] = x->second;
  2593. }
  2594. }
  2595. else
  2596. {
  2597. if (!CheckFilterCompat((mycfg), cfg))
  2598. return false;
  2599. }
  2600. HLOGC(cnlog.Debug,
  2601. log << CONID() << "checkApplyFilterConfig: param: LOCAL: " << Printable(mycfg.parameters)
  2602. << " FORGN: " << Printable(cfg.parameters));
  2603. ostringstream myos;
  2604. myos << mycfg.type;
  2605. for (map<string, string>::iterator x = mycfg.parameters.begin(); x != mycfg.parameters.end(); ++x)
  2606. {
  2607. myos << "," << x->first << ":" << x->second;
  2608. }
  2609. m_config.sPacketFilterConfig.set(myos.str());
  2610. HLOGC(cnlog.Debug, log << CONID() << "checkApplyFilterConfig: Effective config: " << thisconf);
  2611. }
  2612. else
  2613. {
  2614. // Take the foreign configuration as a good deal.
  2615. HLOGC(cnlog.Debug, log << CONID() << "checkApplyFilterConfig: Good deal config: " << thisconf);
  2616. m_config.sPacketFilterConfig.set(confstr);
  2617. }
  2618. size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - cfg.extra_size;
  2619. if (m_config.zExpPayloadSize > efc_max_payload_size)
  2620. {
  2621. LOGC(cnlog.Warn,
  2622. log << CONID() << "Due to filter-required extra " << cfg.extra_size << " bytes, SRTO_PAYLOADSIZE fixed to "
  2623. << efc_max_payload_size << " bytes");
  2624. m_config.zExpPayloadSize = efc_max_payload_size;
  2625. }
  2626. return true;
  2627. }
  2628. #if ENABLE_BONDING
  2629. bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_ATR_UNUSED, int hsreq_type_cmd SRT_ATR_UNUSED)
  2630. {
  2631. // `data_size` isn't checked because we believe it's checked earlier.
  2632. // Also this code doesn't predict to get any other format than the official one,
  2633. // so there are only data in two fields. Passing this argument is only left
  2634. // for consistency and possibly changes in future.
  2635. // We are granted these two fields do exist
  2636. SRTSOCKET grpid = groupdata[GRPD_GROUPID];
  2637. uint32_t gd = groupdata[GRPD_GROUPDATA];
  2638. SRT_GROUP_TYPE gtp = SRT_GROUP_TYPE(SrtHSRequest::HS_GROUP_TYPE::unwrap(gd));
  2639. int link_weight = SrtHSRequest::HS_GROUP_WEIGHT::unwrap(gd);
  2640. uint32_t link_flags = SrtHSRequest::HS_GROUP_FLAGS::unwrap(gd);
  2641. if (m_config.iGroupConnect == 0)
  2642. {
  2643. m_RejectReason = SRT_REJ_GROUP;
  2644. LOGC(cnlog.Error, log << CONID() << "HS/GROUP: this socket is not allowed for group connect.");
  2645. return false;
  2646. }
  2647. // This is called when the group type has come in the handshake is invalid.
  2648. if (gtp >= SRT_GTYPE_E_END)
  2649. {
  2650. m_RejectReason = SRT_REJ_GROUP;
  2651. LOGC(cnlog.Error,
  2652. log << CONID() << "HS/GROUP: incorrect group type value " << gtp << " (max is " << SRT_GTYPE_E_END << ")");
  2653. return false;
  2654. }
  2655. if ((grpid & SRTGROUP_MASK) == 0)
  2656. {
  2657. m_RejectReason = SRT_REJ_ROGUE;
  2658. LOGC(cnlog.Error, log << CONID() << "HS/GROUP: socket ID passed as a group ID is not a group ID");
  2659. return false;
  2660. }
  2661. // We have the group, now take appropriate action.
  2662. // The redundancy group requires to make a mirror group
  2663. // on this side, and the newly created socket should
  2664. // be made belong to it.
  2665. #if ENABLE_HEAVY_LOGGING
  2666. static const char* hs_side_name[] = {"draw", "initiator", "responder"};
  2667. HLOGC(cnlog.Debug,
  2668. log << CONID() << "interpretGroup: STATE: HsSide=" << hs_side_name[m_SrtHsSide]
  2669. << " HS MSG: " << MessageTypeStr(UMSG_EXT, hsreq_type_cmd) << " $" << grpid << " type=" << gtp
  2670. << " weight=" << link_weight << " flags=0x" << std::hex << link_flags);
  2671. #endif
  2672. // XXX Here are two separate possibilities:
  2673. //
  2674. // 1. This is a HS request and this is a newly created socket not yet part of any group.
  2675. // 2. This is a HS response and the group is the mirror group for the group to which the agent belongs; we need to pin the mirror group as peer group
  2676. //
  2677. // These two situations can be only distinguished by the HS side.
  2678. if (m_SrtHsSide == HSD_DRAW)
  2679. {
  2680. m_RejectReason = SRT_REJ_IPE;
  2681. LOGC(cnlog.Error,
  2682. log << CONID()
  2683. << "IPE: interpretGroup: The HS side should have been already decided; it's still DRAW. Grouping "
  2684. "rejected.");
  2685. return false;
  2686. }
  2687. ScopedLock guard_group_existence (uglobal().m_GlobControlLock);
  2688. if (m_SrtHsSide == HSD_INITIATOR)
  2689. {
  2690. // This is a connection initiator that has requested the peer to make a
  2691. // mirror group and join it, then respond its mirror group id. The
  2692. // `grpid` variable contains this group ID; map this as your peer
  2693. // group. If your group already has a peer group set, check if this is
  2694. // the same id, otherwise the connection should be rejected.
  2695. // So, first check the group of the current socket and see if a peer is set.
  2696. CUDTGroup* pg = m_parent->m_GroupOf;
  2697. if (!pg)
  2698. {
  2699. // This means that the responder has responded with a group membership,
  2700. // but the initiator did not request any group membership presence.
  2701. // Currently impossible situation.
  2702. m_RejectReason = SRT_REJ_IPE;
  2703. LOGC(cnlog.Error, log << CONID() << "IPE: HS/RSP: group membership responded, while not requested.");
  2704. return false;
  2705. }
  2706. // Group existence is guarded, so we can now lock the group as well.
  2707. ScopedLock gl(*pg->exp_groupLock());
  2708. // Now we know the group exists, but it might still be closed
  2709. if (pg->closing())
  2710. {
  2711. LOGC(cnlog.Error, log << CONID() << "HS/RSP: group was closed in the process, can't continue connecting");
  2712. m_RejectReason = SRT_REJ_IPE;
  2713. return false;
  2714. }
  2715. SRTSOCKET peer = pg->peerid();
  2716. if (peer == -1)
  2717. {
  2718. // This is the first connection within this group, so this group
  2719. // has just been informed about the peer membership. Accept it.
  2720. pg->set_peerid(grpid);
  2721. HLOGC(cnlog.Debug,
  2722. log << CONID() << "HS/RSP: group $" << pg->id() << " -> peer $" << pg->peerid()
  2723. << ", copying characteristic data");
  2724. // The call to syncWithSocket is copying
  2725. // some interesting data from the first connected
  2726. // socket. This should be only done for the first successful connection.
  2727. pg->syncWithSocket(*this, HSD_INITIATOR);
  2728. }
  2729. // Otherwise the peer id must be the same as existing, otherwise
  2730. // this group is considered already bound to another peer group.
  2731. // (Note that the peer group is peer-specific, and peer id numbers
  2732. // may repeat among sockets connected to groups established on
  2733. // different peers).
  2734. else if (peer != grpid)
  2735. {
  2736. LOGC(cnlog.Error,
  2737. log << CONID() << "IPE: HS/RSP: group membership responded for peer $" << grpid
  2738. << " but the current socket's group $" << pg->id() << " has already a peer $" << peer);
  2739. m_RejectReason = SRT_REJ_GROUP;
  2740. return false;
  2741. }
  2742. else
  2743. {
  2744. HLOGC(cnlog.Debug,
  2745. log << CONID() << "HS/RSP: group $" << pg->id() << " ALREADY MAPPED to peer mirror $"
  2746. << pg->peerid());
  2747. }
  2748. }
  2749. else
  2750. {
  2751. // This is a connection responder that has been requested to make a
  2752. // mirror group and join it. Later on, the HS response will be sent
  2753. // and its group ID will be added to the HS extensions as mirror group
  2754. // ID to the peer.
  2755. SRTSOCKET lgid = makeMePeerOf(grpid, gtp, link_flags);
  2756. if (!lgid)
  2757. return true; // already done
  2758. if (lgid == -1)
  2759. {
  2760. // NOTE: This error currently isn't reported by makeMePeerOf,
  2761. // so this is left to handle a possible error introduced in future.
  2762. m_RejectReason = SRT_REJ_GROUP;
  2763. return false; // error occurred
  2764. }
  2765. if (!m_parent->m_GroupOf)
  2766. {
  2767. // Strange, we just added it...
  2768. m_RejectReason = SRT_REJ_IPE;
  2769. LOGC(cnlog.Fatal, log << CONID() << "IPE: socket not in group after adding to it");
  2770. return false;
  2771. }
  2772. groups::SocketData* f = m_parent->m_GroupMemberData;
  2773. f->weight = link_weight;
  2774. f->agent = m_parent->m_SelfAddr;
  2775. f->peer = m_PeerAddr;
  2776. }
  2777. m_parent->m_GroupOf->debugGroup();
  2778. // That's all. For specific things concerning group
  2779. // types, this will be later.
  2780. return true;
  2781. }
  2782. #endif
  2783. #if ENABLE_BONDING
  2784. // NOTE: This function is called only in one place and it's done
  2785. // exclusively on the listener side (HSD_RESPONDER, HSv5+).
  2786. // [[using locked(s_UDTUnited.m_GlobControlLock)]]
  2787. SRTSOCKET srt::CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint32_t link_flags)
  2788. {
  2789. // Note: This function will lock pg->m_GroupLock!
  2790. CUDTSocket* s = m_parent;
  2791. // Note that the socket being worked out here is about to be returned
  2792. // from `srt_accept` call, and until this moment it will be inaccessible
  2793. // for any other thread. It is then assumed that no other thread is accessing
  2794. // it right now so there's no need to lock s->m_ControlLock.
  2795. // Check if there exists a group that this one is a peer of.
  2796. CUDTGroup* gp = uglobal().findPeerGroup_LOCKED(peergroup);
  2797. bool was_empty = true;
  2798. if (gp)
  2799. {
  2800. if (gp->type() != gtp)
  2801. {
  2802. LOGC(gmlog.Error,
  2803. log << CONID() << "HS: GROUP TYPE COLLISION: peer group=$" << peergroup << " type " << gtp
  2804. << " agent group=$" << gp->id() << " type" << gp->type());
  2805. return -1;
  2806. }
  2807. HLOGC(gmlog.Debug, log << CONID() << "makeMePeerOf: group for peer=$" << peergroup << " found: $" << gp->id());
  2808. if (!gp->groupEmpty())
  2809. was_empty = false;
  2810. }
  2811. else
  2812. {
  2813. try
  2814. {
  2815. gp = &newGroup(gtp);
  2816. }
  2817. catch (...)
  2818. {
  2819. // Expected exceptions are only those referring to system resources
  2820. return -1;
  2821. }
  2822. if (!gp->applyFlags(link_flags, m_SrtHsSide))
  2823. {
  2824. // Wrong settings. Must reject. Delete group.
  2825. uglobal().deleteGroup_LOCKED(gp);
  2826. return -1;
  2827. }
  2828. gp->set_peerid(peergroup);
  2829. gp->deriveSettings(this);
  2830. // This can only happen on a listener (it's only called on a site that is
  2831. // HSD_RESPONDER), so it was a response for a groupwise connection.
  2832. // Therefore such a group shall always be considered opened.
  2833. gp->setOpen();
  2834. HLOGC(gmlog.Debug,
  2835. log << CONID() << "makeMePeerOf: no group has peer=$" << peergroup << " - creating new mirror group $"
  2836. << gp->id());
  2837. }
  2838. {
  2839. ScopedLock glock (*gp->exp_groupLock());
  2840. if (gp->closing())
  2841. {
  2842. HLOGC(gmlog.Debug, log << CONID() << "makeMePeerOf: group $" << gp->id() << " is being closed, can't process");
  2843. }
  2844. if (was_empty)
  2845. {
  2846. gp->syncWithSocket(s->core(), HSD_RESPONDER);
  2847. }
  2848. }
  2849. // Setting non-blocking reading for group socket.
  2850. s->core().m_config.bSynRecving = false;
  2851. s->core().m_config.bSynSending = false;
  2852. // Copy of addSocketToGroup. No idea how many parts could be common, not much.
  2853. // Check if the socket already is in the group
  2854. groups::SocketData* f;
  2855. if (gp->contains(m_SocketID, (f)))
  2856. {
  2857. // XXX This is internal error. Report it, but continue
  2858. // (A newly created socket from acceptAndRespond should not have any group membership yet)
  2859. LOGC(gmlog.Error, log << CONID() << "IPE (non-fatal): the socket is in the group, but has no clue about it!");
  2860. s->m_GroupOf = gp;
  2861. s->m_GroupMemberData = f;
  2862. return 0;
  2863. }
  2864. s->m_GroupMemberData = gp->add(groups::prepareSocketData(s));
  2865. s->m_GroupOf = gp;
  2866. m_HSGroupType = gtp;
  2867. // Record the remote address in the group data.
  2868. return gp->id();
  2869. }
  2870. void srt::CUDT::synchronizeWithGroup(CUDTGroup* gp)
  2871. {
  2872. ScopedLock gl (*gp->exp_groupLock());
  2873. // We have blocked here the process of connecting a new
  2874. // socket and adding anything new to the group, so no such
  2875. // thing may happen in the meantime.
  2876. steady_clock::time_point start_time, peer_start_time;
  2877. start_time = m_stats.tsStartTime;
  2878. peer_start_time = m_tsRcvPeerStartTime;
  2879. if (!gp->applyGroupTime((start_time), (peer_start_time)))
  2880. {
  2881. HLOGC(gmlog.Debug,
  2882. log << CONID() << "synchronizeWithGroup: ST=" << FormatTime(m_stats.tsStartTime) << " -> "
  2883. << FormatTime(start_time) << " PST=" << FormatTime(m_tsRcvPeerStartTime) << " -> "
  2884. << FormatTime(peer_start_time));
  2885. m_stats.tsStartTime = start_time;
  2886. m_tsRcvPeerStartTime = peer_start_time;
  2887. }
  2888. else
  2889. {
  2890. // This was the first connected socket and it defined start time.
  2891. HLOGC(gmlog.Debug,
  2892. log << CONID() << "synchronizeWithGroup: ST=" << FormatTime(m_stats.tsStartTime)
  2893. << " PST=" << FormatTime(m_tsRcvPeerStartTime));
  2894. }
  2895. steady_clock::time_point rcv_buffer_time_base;
  2896. bool rcv_buffer_wrap_period = false;
  2897. steady_clock::duration rcv_buffer_udrift(0);
  2898. if (m_bTsbPd && gp->getBufferTimeBase(this, (rcv_buffer_time_base), (rcv_buffer_wrap_period), (rcv_buffer_udrift)))
  2899. {
  2900. // We have at least one socket in the group, each socket should have
  2901. // the value of the timebase set exactly THE SAME.
  2902. // In case when we have the following situation:
  2903. // - the existing link is before [LAST30] (so wrap period is off)
  2904. // - the new link gets the timestamp from [LAST30] range
  2905. // --> this will be recognized as entering the wrap period, next
  2906. // timebase will get added a segment to this value
  2907. //
  2908. // The only dangerous situations could be when one link gets
  2909. // timestamps from the [FOLLOWING30] and the other in [FIRST30],
  2910. // but between them there's a 30s distance, considered large enough
  2911. // time to not fill a network window.
  2912. enterCS(m_RecvLock);
  2913. m_pRcvBuffer->applyGroupTime(rcv_buffer_time_base, rcv_buffer_wrap_period, m_iTsbPdDelay_ms * 1000, rcv_buffer_udrift);
  2914. m_pRcvBuffer->setPeerRexmitFlag(m_bPeerRexmitFlag);
  2915. leaveCS(m_RecvLock);
  2916. HLOGC(gmlog.Debug, log << "AFTER HS: Set Rcv TsbPd mode: delay="
  2917. << (m_iTsbPdDelay_ms/1000) << "." << (m_iTsbPdDelay_ms%1000)
  2918. << "s GROUP TIME BASE: " << FormatTime(rcv_buffer_time_base)
  2919. << " (" << (rcv_buffer_wrap_period ? "" : "NOT") << " WRAP PERIOD)");
  2920. }
  2921. else
  2922. {
  2923. HLOGC(gmlog.Debug,
  2924. log << CONID() << "AFTER HS: (GROUP, but "
  2925. << (m_bTsbPd ? "FIRST SOCKET is initialized normally)" : "no TSBPD set)"));
  2926. updateSrtRcvSettings();
  2927. }
  2928. // This function currently does nothing, just left for consistency
  2929. // with updateAfterSrtHandshake().
  2930. updateSrtSndSettings();
  2931. // These are the values that are normally set initially by setters.
  2932. int32_t snd_isn = m_iSndLastAck, rcv_isn = m_iRcvLastAck;
  2933. if (!gp->applyGroupSequences(m_SocketID, (snd_isn), (rcv_isn)))
  2934. {
  2935. HLOGC(gmlog.Debug,
  2936. log << CONID() << "synchronizeWithGroup: DERIVED ISN: RCV=%" << m_iRcvLastAck << " -> %" << rcv_isn
  2937. << " (shift by " << CSeqNo::seqcmp(rcv_isn, m_iRcvLastAck) << ") SND=%" << m_iSndLastAck
  2938. << " -> %" << snd_isn << " (shift by " << CSeqNo::seqcmp(snd_isn, m_iSndLastAck) << ")");
  2939. setInitialRcvSeq(rcv_isn);
  2940. setInitialSndSeq(snd_isn);
  2941. }
  2942. else
  2943. {
  2944. HLOGC(gmlog.Debug,
  2945. log << CONID() << "synchronizeWithGroup: DEFINED ISN: RCV=%" << m_iRcvLastAck << " SND=%"
  2946. << m_iSndLastAck);
  2947. }
  2948. }
  2949. #endif
  2950. void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)
  2951. {
  2952. ScopedLock cg (m_ConnectionLock);
  2953. HLOGC(aclog.Debug, log << CONID() << "startConnect: -> " << serv_addr.str()
  2954. << (m_config.bSynRecving ? " (SYNCHRONOUS)" : " (ASYNCHRONOUS)") << "...");
  2955. if (!m_bOpened)
  2956. throw CUDTException(MJ_NOTSUP, MN_NONE, 0);
  2957. if (m_bListening)
  2958. throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);
  2959. if (m_bConnecting || m_bConnected)
  2960. throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);
  2961. // record peer/server address
  2962. m_PeerAddr = serv_addr;
  2963. // register this socket in the rendezvous queue
  2964. // RendezevousQueue is used to temporarily store incoming handshake, non-rendezvous connections also require this
  2965. // function
  2966. steady_clock::duration ttl = m_config.tdConnTimeOut;
  2967. if (m_config.bRendezvous)
  2968. ttl *= 10;
  2969. const steady_clock::time_point ttl_time = steady_clock::now() + ttl;
  2970. m_pRcvQueue->registerConnector(m_SocketID, this, serv_addr, ttl_time);
  2971. // The m_iType is used in the INDUCTION for nothing. This value is only regarded
  2972. // in CONCLUSION handshake, however this must be created after the handshake version
  2973. // is already known. UDT_DGRAM is the value that was the only valid in the old SRT
  2974. // with HSv4 (it supported only live transmission), for HSv5 it will be changed to
  2975. // handle handshake extension flags.
  2976. m_ConnReq.m_iType = UDT_DGRAM;
  2977. // Auto mode for Caller and in Rendezvous is equivalent to CIPHER_MODE_AES_CTR.
  2978. if (m_config.iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO)
  2979. m_config.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;
  2980. // This is my current configuration
  2981. if (m_config.bRendezvous)
  2982. {
  2983. // For rendezvous, use version 5 in the waveahand and the cookie.
  2984. // In case when you get the version 4 waveahand, simply switch to
  2985. // the legacy HSv4 rendezvous and this time send version 4 CONCLUSION.
  2986. // The HSv4 client simply won't check the version nor the cookie and it
  2987. // will be sending its waveahands with version 4. Only when the party
  2988. // has sent version 5 waveahand should the agent continue with HSv5
  2989. // rendezvous.
  2990. m_ConnReq.m_iVersion = HS_VERSION_SRT1;
  2991. // m_ConnReq.m_iVersion = HS_VERSION_UDT4; // <--- Change in order to do regression test.
  2992. m_ConnReq.m_iReqType = URQ_WAVEAHAND;
  2993. m_ConnReq.m_iCookie = bake(serv_addr);
  2994. // This will be also passed to a HSv4 rendezvous, but fortunately the old
  2995. // SRT didn't read this field from URQ_WAVEAHAND message, only URQ_CONCLUSION.
  2996. m_ConnReq.m_iType = SrtHSRequest::wrapFlags(false /* no MAGIC here */, m_config.iSndCryptoKeyLen);
  2997. IF_HEAVY_LOGGING(const bool whether = m_config.iSndCryptoKeyLen != 0);
  2998. HLOGC(aclog.Debug,
  2999. log << CONID() << "startConnect (rnd): " << (whether ? "" : "NOT ")
  3000. << " Advertising PBKEYLEN - value = " << m_config.iSndCryptoKeyLen);
  3001. m_RdvState = CHandShake::RDV_WAVING;
  3002. m_SrtHsSide = HSD_DRAW; // initially not resolved.
  3003. }
  3004. else
  3005. {
  3006. // For caller-listener configuration, set the version 4 for INDUCTION
  3007. // due to a serious problem in UDT code being also in the older SRT versions:
  3008. // the listener peer simply sents the EXACT COPY of the caller's induction
  3009. // handshake, except the cookie, which means that when the caller sents version 5,
  3010. // the listener will respond with version 5, which is a false information. Therefore
  3011. // HSv5 clients MUST send HS_VERSION_UDT4 from the caller, regardless of currently
  3012. // supported handshake version.
  3013. //
  3014. // The HSv5 listener should only respond with INDUCTION with m_iVersion == HS_VERSION_SRT1.
  3015. m_ConnReq.m_iVersion = HS_VERSION_UDT4;
  3016. m_ConnReq.m_iReqType = URQ_INDUCTION;
  3017. m_ConnReq.m_iCookie = 0;
  3018. m_RdvState = CHandShake::RDV_INVALID;
  3019. }
  3020. m_ConnReq.m_iMSS = m_config.iMSS;
  3021. // Defined as the size of the receiver buffer in packets, unless
  3022. // SRTO_FC has been set to a less value.
  3023. m_ConnReq.m_iFlightFlagSize = m_config.flightCapacity();
  3024. m_ConnReq.m_iID = m_SocketID;
  3025. CIPAddress::ntop(serv_addr, (m_ConnReq.m_piPeerIP));
  3026. if (forced_isn == SRT_SEQNO_NONE)
  3027. {
  3028. forced_isn = generateISN();
  3029. HLOGC(aclog.Debug, log << CONID() << "startConnect: ISN generated = " << forced_isn);
  3030. }
  3031. else
  3032. {
  3033. HLOGC(aclog.Debug, log << CONID() << "startConnect: ISN forced = " << forced_isn);
  3034. }
  3035. m_iISN = m_ConnReq.m_iISN = forced_isn;
  3036. setInitialSndSeq(m_iISN);
  3037. // Inform the server my configurations.
  3038. CPacket reqpkt;
  3039. reqpkt.setControl(UMSG_HANDSHAKE);
  3040. reqpkt.allocate(m_iMaxSRTPayloadSize);
  3041. // XXX NOTE: Now the memory for the payload part is allocated automatically,
  3042. // and such allocated memory is also automatically deallocated in the
  3043. // destructor. If you use CPacket::allocate, remember that you must not:
  3044. // - delete this memory
  3045. // - assign to m_pcData.
  3046. // If you use only manual assignment to m_pCData, this is then manual
  3047. // allocation and so it won't be deallocated in the destructor.
  3048. //
  3049. // (Desired would be to disallow modification of m_pcData outside the
  3050. // control of methods.)
  3051. // ID = 0, connection request
  3052. reqpkt.m_iID = 0;
  3053. size_t hs_size = m_iMaxSRTPayloadSize;
  3054. m_ConnReq.store_to((reqpkt.m_pcData), (hs_size));
  3055. // Note that CPacket::allocate() sets also the size
  3056. // to the size of the allocated buffer, which not
  3057. // necessarily is to be the size of the data.
  3058. reqpkt.setLength(hs_size);
  3059. const steady_clock::time_point tnow = steady_clock::now();
  3060. m_SndLastAck2Time = tnow;
  3061. setPacketTS(reqpkt, tnow);
  3062. HLOGC(cnlog.Debug,
  3063. log << CONID() << "CUDT::startConnect: REQ-TIME set HIGH (TimeStamp: " << reqpkt.m_iTimeStamp
  3064. << "). SENDING HS: " << m_ConnReq.show());
  3065. /*
  3066. * Race condition if non-block connect response thread scheduled before we set m_bConnecting to true?
  3067. * Connect response will be ignored and connecting will wait until timeout.
  3068. * Maybe m_ConnectionLock handling problem? Not used in CUDT::connect(const CPacket& response)
  3069. */
  3070. m_tsLastReqTime = tnow;
  3071. m_bConnecting = true;
  3072. // At this point m_SourceAddr is probably default-any, but this function
  3073. // now requires that the address be specified here because there will be
  3074. // no possibility to do it at any next stage of sending.
  3075. m_pSndQueue->sendto(serv_addr, reqpkt, m_SourceAddr);
  3076. //
  3077. ///
  3078. //// ---> CONTINUE TO: <PEER>.CUDT::processConnectRequest()
  3079. /// (Take the part under condition: hs.m_iReqType == URQ_INDUCTION)
  3080. //// <--- RETURN WHEN: m_pSndQueue->sendto() is called.
  3081. //// .... SKIP UNTIL m_pRcvQueue->recvfrom() HERE....
  3082. //// (the first "sendto" will not be called due to being too early)
  3083. ///
  3084. //
  3085. //////////////////////////////////////////////////////
  3086. // SYNCHRO BAR
  3087. //////////////////////////////////////////////////////
  3088. if (!m_config.bSynRecving)
  3089. {
  3090. HLOGC(cnlog.Debug, log << CONID() << "startConnect: ASYNC MODE DETECTED. Deferring the process to RcvQ:worker");
  3091. return;
  3092. }
  3093. // Below this bar, rest of function maintains only and exclusively
  3094. // the SYNCHRONOUS (blocking) connection process.
  3095. // Wait for the negotiated configurations from the peer side.
  3096. // This packet only prepares the storage where we will read the
  3097. // next incoming packet.
  3098. CPacket response;
  3099. response.setControl(UMSG_HANDSHAKE);
  3100. response.allocate(m_iMaxSRTPayloadSize);
  3101. CUDTException e;
  3102. EConnectStatus cst = CONN_CONTINUE;
  3103. // This is a temporary place to store the DESTINATION IP from the incoming packet.
  3104. // We can't record this address yet until the cookie-confirmation is done, for safety reasons.
  3105. sockaddr_any use_source_adr(serv_addr.family());
  3106. while (!m_bClosing)
  3107. {
  3108. const steady_clock::time_point local_tnow = steady_clock::now();
  3109. const steady_clock::duration tdiff = local_tnow - m_tsLastReqTime.load();
  3110. // avoid sending too many requests, at most 1 request per 250ms
  3111. // SHORT VERSION:
  3112. // The immediate first run of this loop WILL SKIP THIS PART, so
  3113. // the processing really begins AFTER THIS CONDITION.
  3114. //
  3115. // Note that some procedures inside may set m_tsLastReqTime to 0,
  3116. // which will result of this condition to trigger immediately in
  3117. // the next iteration.
  3118. if (count_milliseconds(tdiff) > 250)
  3119. {
  3120. HLOGC(cnlog.Debug,
  3121. log << CONID() << "startConnect: LOOP: time to send (" << count_milliseconds(tdiff)
  3122. << " > 250 ms). size=" << reqpkt.getLength());
  3123. if (m_config.bRendezvous)
  3124. reqpkt.m_iID = m_ConnRes.m_iID;
  3125. #if ENABLE_HEAVY_LOGGING
  3126. {
  3127. CHandShake debughs;
  3128. debughs.load_from(reqpkt.m_pcData, reqpkt.getLength());
  3129. HLOGC(cnlog.Debug,
  3130. log << CONID() << "startConnect: REQ-TIME HIGH."
  3131. << " cont/sending HS to peer: " << debughs.show());
  3132. }
  3133. #endif
  3134. m_tsLastReqTime = local_tnow;
  3135. setPacketTS(reqpkt, local_tnow);
  3136. m_pSndQueue->sendto(serv_addr, reqpkt, use_source_adr);
  3137. }
  3138. else
  3139. {
  3140. HLOGC(cnlog.Debug,
  3141. log << CONID() << "startConnect: LOOP: too early to send - " << count_milliseconds(tdiff)
  3142. << " < 250ms");
  3143. }
  3144. cst = CONN_CONTINUE;
  3145. response.setLength(m_iMaxSRTPayloadSize);
  3146. if (m_pRcvQueue->recvfrom(m_SocketID, (response)) > 0)
  3147. {
  3148. use_source_adr = response.udpDestAddr();
  3149. HLOGC(cnlog.Debug, log << CONID() << "startConnect: got response for connect request");
  3150. cst = processConnectResponse(response, &e);
  3151. HLOGC(cnlog.Debug, log << CONID() << "startConnect: response processing result: " << ConnectStatusStr(cst));
  3152. // Expected is that:
  3153. // - the peer responded with URQ_INDUCTION + cookie. This above function
  3154. // should check that and craft the URQ_CONCLUSION handshake, in which
  3155. // case this function returns CONN_CONTINUE. As an extra action taken
  3156. // for that case, we set the SECURING mode if encryption requested,
  3157. // and serialize again the handshake, possibly together with HS extension
  3158. // blocks, if HSv5 peer responded. The serialized handshake will be then
  3159. // sent again, as the loop is repeated.
  3160. // - the peer responded with URQ_CONCLUSION. This handshake was accepted
  3161. // as a connection, and for >= HSv5 the HS extension blocks have been
  3162. // also read and interpreted. In this case this function returns:
  3163. // - CONN_ACCEPT, if everything was correct - break this loop and return normally
  3164. // - CONN_REJECT in case of any problems with the delivered handshake
  3165. // (incorrect data or data conflict) - throw error exception
  3166. // - the peer responded with any of URQ_ERROR_*. - throw error exception
  3167. //
  3168. // The error exception should make the API connect() function fail, if blocking
  3169. // or mark the failure for that socket in epoll, if non-blocking.
  3170. if (cst == CONN_RENDEZVOUS)
  3171. {
  3172. // When this function returned CONN_RENDEZVOUS, this requires
  3173. // very special processing for the Rendezvous-v5 algorithm. This MAY
  3174. // involve also preparing a new handshake form, also interpreting the
  3175. // SRT handshake extension and crafting SRT handshake extension for the
  3176. // peer, which should be next sent. When this function returns CONN_CONTINUE,
  3177. // it means that it has done all that was required, however none of the below
  3178. // things has to be done (this function will do it by itself if needed).
  3179. // Otherwise the handshake rolling can be interrupted and considered complete.
  3180. cst = processRendezvous(&response, serv_addr, RST_OK, (reqpkt));
  3181. if (cst == CONN_CONTINUE)
  3182. continue;
  3183. HLOGC(cnlog.Debug,
  3184. log << CONID() << "startConnect: processRendezvous returned cst=" << ConnectStatusStr(cst));
  3185. if (cst == CONN_REJECT)
  3186. {
  3187. // Just in case it wasn't set, set this as a fallback
  3188. if (m_RejectReason == SRT_REJ_UNKNOWN)
  3189. m_RejectReason = SRT_REJ_ROGUE;
  3190. // rejection or erroneous code.
  3191. reqpkt.setLength(m_iMaxSRTPayloadSize);
  3192. reqpkt.setControl(UMSG_HANDSHAKE);
  3193. sendRendezvousRejection(serv_addr, (reqpkt));
  3194. }
  3195. }
  3196. if (cst == CONN_REJECT)
  3197. {
  3198. HLOGC(cnlog.Debug,
  3199. log << CONID() << "startConnect: REJECTED by processConnectResponse - sending SHUTDOWN");
  3200. sendCtrl(UMSG_SHUTDOWN);
  3201. }
  3202. if (cst != CONN_CONTINUE && cst != CONN_CONFUSED)
  3203. break; // --> OUTSIDE-LOOP
  3204. // IMPORTANT
  3205. // [[using assert(m_pCryptoControl != nullptr)]];
  3206. // new request/response should be sent out immediately on receiving a response
  3207. HLOGC(cnlog.Debug,
  3208. log << CONID() << "startConnect: SYNC CONNECTION STATUS:" << ConnectStatusStr(cst)
  3209. << ", REQ-TIME: LOW.");
  3210. m_tsLastReqTime = steady_clock::time_point();
  3211. // Now serialize the handshake again to the existing buffer so that it's
  3212. // then sent later in this loop.
  3213. // First, set the size back to the original size, m_iMaxSRTPayloadSize because
  3214. // this is the size of the originally allocated space. It might have been
  3215. // shrunk by serializing the INDUCTION handshake (which was required before
  3216. // sending this packet to the output queue) and therefore be too
  3217. // small to store the CONCLUSION handshake (with HSv5 extensions).
  3218. reqpkt.setLength(m_iMaxSRTPayloadSize);
  3219. HLOGC(cnlog.Debug,
  3220. log << CONID() << "startConnect: creating HS CONCLUSION: buffer size=" << reqpkt.getLength());
  3221. // NOTE: BUGFIX: SERIALIZE AGAIN.
  3222. // The original UDT code didn't do it, so it was theoretically
  3223. // turned into conclusion, but was sending still the original
  3224. // induction handshake challenge message. It was working only
  3225. // thanks to that simultaneously there were being sent handshake
  3226. // messages from a separate thread (CSndQueue::worker) from
  3227. // RendezvousQueue, this time serialized properly, which caused
  3228. // that with blocking mode there was a kinda initial "drunk
  3229. // passenger with taxi driver talk" until the RendezvousQueue sends
  3230. // (when "the time comes") the right CONCLUSION handshake
  3231. // challenge message.
  3232. //
  3233. // Now that this is fixed, the handshake messages from RendezvousQueue
  3234. // are sent only when there is a rendezvous mode or non-blocking mode.
  3235. if (!createSrtHandshake(SRT_CMD_HSREQ, SRT_CMD_KMREQ, 0, 0, (reqpkt), (m_ConnReq)))
  3236. {
  3237. LOGC(cnlog.Warn, log << CONID() << "createSrtHandshake failed - REJECTING.");
  3238. cst = CONN_REJECT;
  3239. break;
  3240. }
  3241. // These last 2 parameters designate the buffer, which is in use only for SRT_CMD_KMRSP.
  3242. // If m_ConnReq.m_iVersion == HS_VERSION_UDT4, this function will do nothing,
  3243. // except just serializing the UDT handshake.
  3244. // The trick is that the HS challenge is with version HS_VERSION_UDT4, but the
  3245. // listener should respond with HS_VERSION_SRT1, if it is HSv5 capable.
  3246. }
  3247. HLOGC(cnlog.Debug,
  3248. log << CONID() << "startConnect: timeout from Q:recvfrom, looping again; cst=" << ConnectStatusStr(cst));
  3249. #if ENABLE_HEAVY_LOGGING
  3250. // Non-fatal assertion
  3251. if (cst == CONN_REJECT) // Might be returned by processRendezvous
  3252. {
  3253. LOGC(cnlog.Error,
  3254. log << CONID()
  3255. << "startConnect: IPE: cst=REJECT NOT EXPECTED HERE, the loop should've been interrupted!");
  3256. break;
  3257. }
  3258. #endif
  3259. if (steady_clock::now() > ttl_time)
  3260. {
  3261. // timeout
  3262. e = CUDTException(MJ_SETUP, MN_TIMEOUT, 0);
  3263. m_RejectReason = SRT_REJ_TIMEOUT;
  3264. HLOGC(cnlog.Debug,
  3265. log << CONID() << "startConnect: TTL time " << FormatTime(ttl_time) << " exceeded, TIMEOUT.");
  3266. break;
  3267. }
  3268. }
  3269. // <--- OUTSIDE-LOOP
  3270. // Here will fall the break when not CONN_CONTINUE.
  3271. // CONN_RENDEZVOUS is handled by processRendezvous.
  3272. // CONN_ACCEPT will skip this and pass on.
  3273. if (cst == CONN_REJECT)
  3274. {
  3275. e = CUDTException(MJ_SETUP, MN_REJECTED, 0);
  3276. }
  3277. if (e.getErrorCode() == 0)
  3278. {
  3279. if (m_bClosing) // if the socket is closed before connection...
  3280. e = CUDTException(MJ_SETUP, MN_CLOSED, 0);
  3281. else if (m_ConnRes.m_iReqType > URQ_FAILURE_TYPES) // connection request rejected
  3282. {
  3283. m_RejectReason = RejectReasonForURQ(m_ConnRes.m_iReqType);
  3284. e = CUDTException(MJ_SETUP, MN_REJECTED, 0);
  3285. }
  3286. else if ((!m_config.bRendezvous) && (m_ConnRes.m_iISN != m_iISN)) // secuity check
  3287. e = CUDTException(MJ_SETUP, MN_SECURITY, 0);
  3288. }
  3289. if (e.getErrorCode() != 0)
  3290. {
  3291. m_bConnecting = false;
  3292. // The process is to be abnormally terminated, remove the connector
  3293. // now because most likely no other processing part has done anything with it.
  3294. m_pRcvQueue->removeConnector(m_SocketID);
  3295. throw e;
  3296. }
  3297. HLOGC(cnlog.Debug,
  3298. log << CONID() << "startConnect: handshake exchange succeeded. sourceIP=" << m_SourceAddr.str());
  3299. // Parameters at the end.
  3300. HLOGC(cnlog.Debug,
  3301. log << CONID() << "startConnect: END. Parameters: mss=" << m_config.iMSS
  3302. << " max-cwnd-size=" << m_CongCtl->cgWindowMaxSize() << " cwnd-size=" << m_CongCtl->cgWindowSize()
  3303. << " rtt=" << m_iSRTT << " bw=" << m_iBandwidth);
  3304. }
  3305. // Asynchronous connection
  3306. EConnectStatus srt::CUDT::processAsyncConnectResponse(const CPacket &pkt) ATR_NOEXCEPT
  3307. {
  3308. EConnectStatus cst = CONN_CONTINUE;
  3309. CUDTException e;
  3310. ScopedLock cg(m_ConnectionLock);
  3311. HLOGC(cnlog.Debug, log << CONID() << "processAsyncConnectResponse: got response for connect request, processing");
  3312. cst = processConnectResponse(pkt, &e);
  3313. HLOGC(cnlog.Debug,
  3314. log << CONID() << "processAsyncConnectResponse: response processing result: " << ConnectStatusStr(cst)
  3315. << "; REQ-TIME LOW to enforce immediate response");
  3316. m_tsLastReqTime = steady_clock::time_point();
  3317. return cst;
  3318. }
  3319. bool srt::CUDT::processAsyncConnectRequest(EReadStatus rst,
  3320. EConnectStatus cst,
  3321. const CPacket* pResponse /*[[nullable]]*/,
  3322. const sockaddr_any& serv_addr)
  3323. {
  3324. // IMPORTANT!
  3325. // This function is called, still asynchronously, but in the order
  3326. // of call just after the call to the above processAsyncConnectResponse.
  3327. // This should have got the original value returned from
  3328. // processConnectResponse through processAsyncConnectResponse.
  3329. CPacket request;
  3330. request.setControl(UMSG_HANDSHAKE);
  3331. request.allocate(m_iMaxSRTPayloadSize);
  3332. const steady_clock::time_point now = steady_clock::now();
  3333. setPacketTS(request, now);
  3334. HLOGC(cnlog.Debug,
  3335. log << CONID() << "processAsyncConnectRequest: REQ-TIME: HIGH. Should prevent too quick responses.");
  3336. m_tsLastReqTime = now;
  3337. // ID = 0, connection request
  3338. request.m_iID = !m_config.bRendezvous ? 0 : m_ConnRes.m_iID;
  3339. bool status = true;
  3340. ScopedLock cg(m_ConnectionLock);
  3341. if (!m_bOpened) // Check the socket has not been closed before already.
  3342. return false;
  3343. if (cst == CONN_RENDEZVOUS)
  3344. {
  3345. HLOGC(cnlog.Debug, log << CONID() << "processAsyncConnectRequest: passing to processRendezvous");
  3346. cst = processRendezvous(pResponse, serv_addr, rst, (request));
  3347. if (cst == CONN_ACCEPT)
  3348. {
  3349. HLOGC(cnlog.Debug,
  3350. log << CONID()
  3351. << "processAsyncConnectRequest: processRendezvous completed the process and responded by itself. "
  3352. "Done.");
  3353. return true;
  3354. }
  3355. if (cst != CONN_CONTINUE)
  3356. {
  3357. // processRendezvous already set the reject reason
  3358. LOGC(cnlog.Warn,
  3359. log << CONID()
  3360. << "processAsyncConnectRequest: REJECT reported from processRendezvous, not processing further.");
  3361. if (m_RejectReason == SRT_REJ_UNKNOWN)
  3362. m_RejectReason = SRT_REJ_ROGUE;
  3363. sendRendezvousRejection(serv_addr, (request));
  3364. status = false;
  3365. }
  3366. }
  3367. else if (cst == CONN_REJECT)
  3368. {
  3369. // m_RejectReason already set at worker_ProcessAddressedPacket.
  3370. LOGC(cnlog.Warn,
  3371. log << CONID() << "processAsyncConnectRequest: REJECT reported from HS processing: "
  3372. << srt_rejectreason_str(m_RejectReason) << " - not processing further");
  3373. // m_tsLastReqTime = steady_clock::time_point(); XXX ?
  3374. return false;
  3375. }
  3376. else
  3377. {
  3378. // (this procedure will be also run for HSv4 rendezvous)
  3379. HLOGC(cnlog.Debug,
  3380. log << CONID() << "processAsyncConnectRequest: serializing HS: buffer size=" << request.getLength());
  3381. if (!createSrtHandshake(SRT_CMD_HSREQ, SRT_CMD_KMREQ, 0, 0, (request), (m_ConnReq)))
  3382. {
  3383. // All 'false' returns from here are IPE-type, mostly "invalid argument" plus "all keys expired".
  3384. LOGC(cnlog.Error,
  3385. log << CONID() << "IPE: processAsyncConnectRequest: createSrtHandshake failed, dismissing.");
  3386. status = false;
  3387. }
  3388. else
  3389. {
  3390. HLOGC(cnlog.Debug,
  3391. log << CONID()
  3392. << "processAsyncConnectRequest: sending HS reqtype=" << RequestTypeStr(m_ConnReq.m_iReqType)
  3393. << " to socket " << request.m_iID << " size=" << request.getLength());
  3394. }
  3395. }
  3396. if (!status)
  3397. {
  3398. return false;
  3399. /* XXX Shouldn't it send a single response packet for the rejection?
  3400. // Set the version to 0 as "handshake rejection" status and serialize it
  3401. CHandShake zhs;
  3402. size_t size = request.getLength();
  3403. zhs.store_to((request.m_pcData), (size));
  3404. request.setLength(size);
  3405. */
  3406. }
  3407. HLOGC(cnlog.Debug,
  3408. log << CONID() << "processAsyncConnectRequest: setting REQ-TIME HIGH, SENDING HS:" << m_ConnReq.show());
  3409. m_tsLastReqTime = steady_clock::now();
  3410. m_pSndQueue->sendto(serv_addr, request, m_SourceAddr);
  3411. return status;
  3412. }
  3413. void srt::CUDT::sendRendezvousRejection(const sockaddr_any& serv_addr, CPacket& r_rsppkt)
  3414. {
  3415. // We can reuse m_ConnReq because we are about to abandon the connection process.
  3416. m_ConnReq.m_iReqType = URQFailure(m_RejectReason);
  3417. // Assumed that r_rsppkt refers to a packet object that was already prepared
  3418. // to be used for storing the handshake there.
  3419. size_t size = r_rsppkt.getLength();
  3420. m_ConnReq.store_to((r_rsppkt.m_pcData), (size));
  3421. r_rsppkt.setLength(size);
  3422. HLOGC(cnlog.Debug, log << CONID() << "sendRendezvousRejection: using code=" << m_ConnReq.m_iReqType
  3423. << " for reject reason code " << m_RejectReason << " (" << srt_rejectreason_str(m_RejectReason) << ")");
  3424. setPacketTS(r_rsppkt, steady_clock::now());
  3425. m_pSndQueue->sendto(serv_addr, r_rsppkt, m_SourceAddr);
  3426. }
  3427. void srt::CUDT::cookieContest()
  3428. {
  3429. if (m_SrtHsSide != HSD_DRAW)
  3430. return;
  3431. LOGC(cnlog.Debug,
  3432. log << CONID() << "cookieContest: agent=" << m_ConnReq.m_iCookie << " peer=" << m_ConnRes.m_iCookie);
  3433. // Here m_ConnReq.m_iCookie is a local cookie value sent in connection request to the peer.
  3434. // m_ConnRes.m_iCookie is a cookie value sent by the peer in its connection request.
  3435. if (m_ConnReq.m_iCookie == 0 || m_ConnRes.m_iCookie == 0)
  3436. {
  3437. // Note that it's virtually impossible that Agent's cookie is not ready, this
  3438. // shall be considered IPE.
  3439. // Not all cookies are ready, don't start the contest.
  3440. return;
  3441. }
  3442. // INITIATOR/RESPONDER role is resolved by COOKIE CONTEST.
  3443. //
  3444. // The cookie contest must be repeated every time because it
  3445. // may change the state at some point.
  3446. //
  3447. // In SRT v1.4.3 and prior the below subtraction was performed in 32-bit arithmetic.
  3448. // The result of subtraction can overflow 32-bits.
  3449. // Example
  3450. // m_ConnReq.m_iCookie = -1480577720;
  3451. // m_ConnRes.m_iCookie = 811599203;
  3452. // int64_t llBetterCookie = -1480577720 - 811599203 = -2292176923 (FFFF FFFF 7760 27E5);
  3453. // int32_t iBetterCookie = 2002790373 (7760 27E5);
  3454. //
  3455. // Now 64-bit arithmetic is used to calculate the actual result of subtraction.
  3456. // The 31-st bit is then checked to check if the resulting is negative in 32-bit aritmetics.
  3457. // This way the old contest behavior is preserved, and potential compiler optimisations are avoided.
  3458. const int64_t contest = int64_t(m_ConnReq.m_iCookie) - int64_t(m_ConnRes.m_iCookie);
  3459. if ((contest & 0xFFFFFFFF) == 0)
  3460. {
  3461. // DRAW! The only way to continue would be to force the
  3462. // cookies to be regenerated and to start over. But it's
  3463. // not worth a shot - this is an extremely rare case.
  3464. // This can simply do reject so that it can be started again.
  3465. // Pretend then that the cookie contest wasn't done so that
  3466. // it's done again. Cookies are baked every time anew, however
  3467. // the successful initial contest remains valid no matter how
  3468. // cookies will change.
  3469. m_SrtHsSide = HSD_DRAW;
  3470. return;
  3471. }
  3472. if (contest & 0x80000000)
  3473. {
  3474. m_SrtHsSide = HSD_RESPONDER;
  3475. return;
  3476. }
  3477. m_SrtHsSide = HSD_INITIATOR;
  3478. }
  3479. // This function should complete the data for KMX needed for an out-of-band
  3480. // handshake response. Possibilities are:
  3481. // - There's no KMX (including first responder's handshake in rendezvous). This writes 0 to w_kmdatasize.
  3482. // - The encryption status is failure. Respond with fail code and w_kmdatasize = 1.
  3483. // - The last KMX was successful. Respond with the original kmdata and their size in w_kmdatasize.
  3484. EConnectStatus srt::CUDT::craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatasize)
  3485. {
  3486. // If the last CONCLUSION message didn't contain the KMX extension, there's
  3487. // no key recorded yet, so it can't be extracted. Mark this w_kmdatasize empty though.
  3488. int hs_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_ConnRes.m_iType);
  3489. if (IsSet(hs_flags, CHandShake::HS_EXT_KMREQ))
  3490. {
  3491. // m_pCryptoControl can be NULL if the socket has been closed already. See issue #2231.
  3492. if (!m_pCryptoControl)
  3493. {
  3494. m_RejectReason = SRT_REJ_IPE;
  3495. LOGC(cnlog.Error,
  3496. log << CONID() << "IPE: craftKmResponse needs to send KM, but CryptoControl does not exist."
  3497. << " Socket state: connected=" << boolalpha << m_bConnected << ", connecting=" << m_bConnecting
  3498. << ", broken=" << m_bBroken << ", opened " << m_bOpened << ", closing=" << m_bClosing << ".");
  3499. return CONN_REJECT;
  3500. }
  3501. // This is a periodic handshake update, so you need to extract the KM data from the
  3502. // first message, provided that it is there.
  3503. size_t msgsize = m_pCryptoControl->getKmMsg_size(0);
  3504. if (msgsize == 0)
  3505. {
  3506. switch (m_pCryptoControl->m_RcvKmState)
  3507. {
  3508. // If the KMX process ended up with a failure, the KMX is not recorded.
  3509. // In this case as the KMRSP answer the "failure status" should be crafted.
  3510. case SRT_KM_S_NOSECRET:
  3511. case SRT_KM_S_BADSECRET:
  3512. {
  3513. HLOGC(cnlog.Debug,
  3514. log << CONID() << "craftKmResponse: No KMX recorded, status = "
  3515. << KmStateStr(m_pCryptoControl->m_RcvKmState) << ". Respond it.");
  3516. // Just do the same thing as in CCryptoControl::processSrtMsg_KMREQ for that case,
  3517. // that is, copy the NOSECRET code into KMX message.
  3518. memcpy((aw_kmdata), &m_pCryptoControl->m_RcvKmState, sizeof(int32_t));
  3519. w_kmdatasize = 1;
  3520. }
  3521. break; // Treat as ACCEPT in general; might change to REJECT on enforced-encryption
  3522. default:
  3523. // Remaining values:
  3524. // UNSECURED: should not fall here at all
  3525. // SECURING: should not happen in HSv5
  3526. // SECURED: should have received the recorded KMX correctly (getKmMsg_size(0) > 0)
  3527. {
  3528. m_RejectReason = SRT_REJ_IPE;
  3529. // Remaining situations:
  3530. // - password only on this site: shouldn't be considered to be sent to a no-password site
  3531. LOGC(cnlog.Error,
  3532. log << CONID() << "craftKmResponse: IPE: PERIODIC HS: NO KMREQ RECORDED KMSTATE: RCV="
  3533. << KmStateStr(m_pCryptoControl->m_RcvKmState)
  3534. << " SND=" << KmStateStr(m_pCryptoControl->m_SndKmState));
  3535. return CONN_REJECT;
  3536. }
  3537. break;
  3538. }
  3539. }
  3540. else
  3541. {
  3542. w_kmdatasize = msgsize / 4;
  3543. if (msgsize > w_kmdatasize * 4)
  3544. {
  3545. // Sanity check
  3546. LOGC(cnlog.Error, log << CONID() << "IPE: KMX data not aligned to 4 bytes! size=" << msgsize);
  3547. memset((aw_kmdata + (w_kmdatasize * 4)), 0, msgsize - (w_kmdatasize * 4));
  3548. ++w_kmdatasize;
  3549. }
  3550. HLOGC(cnlog.Debug,
  3551. log << CONID() << "craftKmResponse: getting KM DATA from the fore-recorded KMX from KMREQ, size="
  3552. << w_kmdatasize);
  3553. memcpy((aw_kmdata), m_pCryptoControl->getKmMsg_data(0), msgsize);
  3554. }
  3555. }
  3556. else
  3557. {
  3558. HLOGC(cnlog.Debug, log << CONID() << "craftKmResponse: no KMX flag - not extracting KM data for KMRSP");
  3559. w_kmdatasize = 0;
  3560. }
  3561. return CONN_ACCEPT;
  3562. }
  3563. EConnectStatus srt::CUDT::processRendezvous(
  3564. const CPacket* pResponse /*[[nullable]]*/, const sockaddr_any& serv_addr,
  3565. EReadStatus rst, CPacket& w_reqpkt)
  3566. {
  3567. if (m_RdvState == CHandShake::RDV_CONNECTED)
  3568. {
  3569. HLOGC(cnlog.Debug, log << CONID() << "processRendezvous: already in CONNECTED state.");
  3570. return CONN_ACCEPT;
  3571. }
  3572. uint32_t kmdata[SRTDATA_MAXSIZE];
  3573. size_t kmdatasize = SRTDATA_MAXSIZE;
  3574. cookieContest();
  3575. // We know that the other side was contacted and the other side has sent
  3576. // the handshake message - we know then both cookies. If it's a draw, it's
  3577. // a very rare case of creating identical cookies.
  3578. if (m_SrtHsSide == HSD_DRAW)
  3579. {
  3580. m_RejectReason = SRT_REJ_RDVCOOKIE;
  3581. LOGC(cnlog.Error,
  3582. log << CONID() << "COOKIE CONTEST UNRESOLVED: can't assign connection roles, please wait another minute.");
  3583. return CONN_REJECT;
  3584. }
  3585. UDTRequestType rsp_type = URQ_FAILURE_TYPES; // just to track uninitialized errors
  3586. // We can assume that the Handshake packet received here as 'response'
  3587. // is already serialized in m_ConnRes. Check extra flags that are meaningful
  3588. // for further processing here.
  3589. int ext_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_ConnRes.m_iType);
  3590. bool needs_extension = ext_flags != 0; // Initial value: received HS has extensions.
  3591. bool needs_hsrsp;
  3592. rendezvousSwitchState((rsp_type), (needs_extension), (needs_hsrsp));
  3593. if (rsp_type > URQ_FAILURE_TYPES)
  3594. {
  3595. m_RejectReason = RejectReasonForURQ(rsp_type);
  3596. HLOGC(cnlog.Debug,
  3597. log << CONID()
  3598. << "processRendezvous: rejecting due to switch-state response: " << RequestTypeStr(rsp_type));
  3599. return CONN_REJECT;
  3600. }
  3601. checkUpdateCryptoKeyLen("processRendezvous", m_ConnRes.m_iType);
  3602. // We have three possibilities here as it comes to HSREQ extensions:
  3603. // 1. The agent is loser in attention state, it sends EMPTY conclusion (without extensions)
  3604. // 2. The agent is loser in initiated state, it interprets incoming HSREQ and creates HSRSP
  3605. // 3. The agent is winner in attention or fine state, it sends HSREQ extension
  3606. m_ConnReq.m_iReqType = rsp_type;
  3607. m_ConnReq.m_extension = needs_extension;
  3608. // This must be done before prepareConnectionObjects(), because it sets ISN and m_iMaxSRTPayloadSize needed to create buffers.
  3609. if (!applyResponseSettings(pResponse))
  3610. {
  3611. LOGC(cnlog.Error, log << CONID() << "processRendezvous: rogue peer");
  3612. return CONN_REJECT;
  3613. }
  3614. // The CryptoControl must be created by the prepareConnectionObjects() before interpreting and creating HSv5 extensions
  3615. // because the it will be used there.
  3616. if (!prepareConnectionObjects(m_ConnRes, m_SrtHsSide, NULL) || !prepareBuffers(NULL))
  3617. {
  3618. // m_RejectReason already handled
  3619. HLOGC(cnlog.Debug,
  3620. log << CONID() << "processRendezvous: rejecting due to problems in prepareConnectionObjects.");
  3621. return CONN_REJECT;
  3622. }
  3623. // Case 2.
  3624. if (needs_hsrsp)
  3625. {
  3626. // This means that we have received HSREQ extension with the handshake, so we need to interpret
  3627. // it and craft the response.
  3628. if (rst == RST_OK)
  3629. {
  3630. // We have JUST RECEIVED packet in this session (not that this is called as periodic update).
  3631. // Sanity check
  3632. m_tsLastReqTime = steady_clock::time_point();
  3633. if (!pResponse || pResponse->getLength() == size_t(-1))
  3634. {
  3635. m_RejectReason = SRT_REJ_IPE;
  3636. LOGC(cnlog.Fatal,
  3637. log << CONID() << "IPE: rst=RST_OK, but the packet has set -1 length - REJECTING (REQ-TIME: LOW)");
  3638. return CONN_REJECT;
  3639. }
  3640. if (!interpretSrtHandshake(m_ConnRes, *pResponse, kmdata, &kmdatasize))
  3641. {
  3642. HLOGC(cnlog.Debug,
  3643. log << CONID() << "processRendezvous: rejecting due to problems in interpretSrtHandshake REQ-TIME: LOW.");
  3644. return CONN_REJECT;
  3645. }
  3646. updateAfterSrtHandshake(HS_VERSION_SRT1);
  3647. // Pass on, inform about the shortened response-waiting period.
  3648. HLOGC(cnlog.Debug, log << CONID() << "processRendezvous: setting REQ-TIME: LOW. Forced to respond immediately.");
  3649. }
  3650. else
  3651. {
  3652. // This is a repeated handshake, so you can't use the incoming data to
  3653. // prepare data for createSrtHandshake. They have to be extracted from inside.
  3654. EConnectStatus conn = craftKmResponse((kmdata), (kmdatasize));
  3655. if (conn != CONN_ACCEPT)
  3656. return conn;
  3657. }
  3658. // No matter the value of needs_extension, the extension is always needed
  3659. // when HSREQ was interpreted (to store HSRSP extension).
  3660. m_ConnReq.m_extension = true;
  3661. HLOGC(cnlog.Debug,
  3662. log << CONID()
  3663. << "processRendezvous: HSREQ extension ok, creating HSRSP response. kmdatasize=" << kmdatasize);
  3664. w_reqpkt.setLength(m_iMaxSRTPayloadSize);
  3665. if (!createSrtHandshake(SRT_CMD_HSRSP, SRT_CMD_KMRSP,
  3666. kmdata, kmdatasize,
  3667. (w_reqpkt), (m_ConnReq)))
  3668. {
  3669. HLOGC(cnlog.Debug,
  3670. log << CONID()
  3671. << "processRendezvous: rejecting due to problems in createSrtHandshake. REQ-TIME: LOW");
  3672. m_tsLastReqTime = steady_clock::time_point();
  3673. return CONN_REJECT;
  3674. }
  3675. // This means that it has received URQ_CONCLUSION with HSREQ, agent is then in RDV_FINE
  3676. // state, it sends here URQ_CONCLUSION with HSREQ/KMREQ extensions and it awaits URQ_AGREEMENT.
  3677. return CONN_CONTINUE;
  3678. }
  3679. // Special case: if URQ_AGREEMENT is to be sent, when this side is INITIATOR,
  3680. // then it must have received HSRSP, so it must interpret it. Otherwise it would
  3681. // end up with URQ_DONE, which means that it is the other side to interpret HSRSP.
  3682. if (m_SrtHsSide == HSD_INITIATOR && m_ConnReq.m_iReqType == URQ_AGREEMENT)
  3683. {
  3684. // The same is done in CUDT::postConnect(), however this section will
  3685. // not be done in case of rendezvous. The section in postConnect() is
  3686. // predicted to run only in regular CALLER handling.
  3687. if (rst != RST_OK || !pResponse || pResponse->getLength() == size_t(-1))
  3688. {
  3689. // Actually the -1 length would be an IPE, but it's likely that this was reported already.
  3690. HLOGC(
  3691. cnlog.Debug,
  3692. log << CONID()
  3693. << "processRendezvous: no INCOMING packet, NOT interpreting extensions (relying on exising data)");
  3694. }
  3695. else
  3696. {
  3697. HLOGC(cnlog.Debug,
  3698. log << CONID() << "processRendezvous: INITIATOR, will send AGREEMENT - interpreting HSRSP extension");
  3699. if (!interpretSrtHandshake(m_ConnRes, *pResponse, 0, 0))
  3700. {
  3701. // m_RejectReason is already set, so set the reqtype accordingly
  3702. m_ConnReq.m_iReqType = URQFailure(m_RejectReason);
  3703. return CONN_REJECT;
  3704. }
  3705. }
  3706. // This should be false, make a kinda assert here.
  3707. if (needs_extension)
  3708. {
  3709. LOGC(cnlog.Fatal,
  3710. log << CONID() << "IPE: INITIATOR responding AGREEMENT should declare no extensions to HS");
  3711. m_ConnReq.m_extension = false;
  3712. }
  3713. updateAfterSrtHandshake(HS_VERSION_SRT1);
  3714. }
  3715. HLOGC(cnlog.Debug,
  3716. log << CONID() << "processRendezvous: COOKIES Agent/Peer: " << m_ConnReq.m_iCookie << "/"
  3717. << m_ConnRes.m_iCookie << " HSD:" << (m_SrtHsSide == HSD_INITIATOR ? "initiator" : "responder")
  3718. << " STATE:" << CHandShake::RdvStateStr(m_RdvState) << " ...");
  3719. if (rsp_type == URQ_DONE)
  3720. {
  3721. HLOGC(cnlog.Debug, log << CONID() << "... WON'T SEND any response, both sides considered connected");
  3722. }
  3723. else
  3724. {
  3725. HLOGC(cnlog.Debug,
  3726. log << CONID() << "... WILL SEND " << RequestTypeStr(rsp_type) << " "
  3727. << (m_ConnReq.m_extension ? "with" : "without") << " SRT HS extensions");
  3728. }
  3729. // This marks the information for the serializer that
  3730. // the SRT handshake extension is required.
  3731. // Rest of the data will be filled together with
  3732. // serialization.
  3733. m_ConnReq.m_extension = needs_extension;
  3734. w_reqpkt.setLength(m_iMaxSRTPayloadSize);
  3735. if (m_RdvState == CHandShake::RDV_CONNECTED)
  3736. {
  3737. int cst = postConnect(pResponse, true, 0);
  3738. if (cst == CONN_REJECT)
  3739. {
  3740. // m_RejectReason already set
  3741. HLOGC(cnlog.Debug, log << CONID() << "processRendezvous: rejecting due to problems in postConnect.");
  3742. return CONN_REJECT;
  3743. }
  3744. }
  3745. // URQ_DONE or URQ_AGREEMENT can be the result if the state is RDV_CONNECTED.
  3746. // If URQ_DONE, then there's nothing to be done, when URQ_AGREEMENT then return
  3747. // CONN_CONTINUE to make the caller send again the contents if the packet buffer,
  3748. // this time with URQ_AGREEMENT message, but still consider yourself connected.
  3749. if (rsp_type == URQ_DONE)
  3750. {
  3751. HLOGC(cnlog.Debug, log << CONID() << "processRendezvous: rsp=DONE, reporting ACCEPT (nothing to respond)");
  3752. return CONN_ACCEPT;
  3753. }
  3754. // createSrtHandshake moved here because if the above conditions are satisfied,
  3755. // no response is going to be send, so nothing needs to be "created".
  3756. // needs_extension here distinguishes between cases 1 and 3.
  3757. // NOTE: in case when interpretSrtHandshake was run under the conditions above (to interpret HSRSP),
  3758. // then createSrtHandshake below will create only empty AGREEMENT message.
  3759. if (!createSrtHandshake(SRT_CMD_HSREQ, SRT_CMD_KMREQ, 0, 0,
  3760. (w_reqpkt), (m_ConnReq)))
  3761. {
  3762. // m_RejectReason already set
  3763. LOGC(cnlog.Warn, log << CONID() << "createSrtHandshake failed (IPE?), connection rejected. REQ-TIME: LOW");
  3764. m_tsLastReqTime = steady_clock::time_point();
  3765. return CONN_REJECT;
  3766. }
  3767. if (rsp_type == URQ_AGREEMENT && m_RdvState == CHandShake::RDV_CONNECTED)
  3768. {
  3769. // We are using our own serialization method (not the one called after
  3770. // processConnectResponse, this is skipped in case when this function
  3771. // is called), so we can also send this immediately. Agreement must be
  3772. // sent just once and the party must switch into CONNECTED state - in
  3773. // contrast to CONCLUSION messages, which should be sent in loop repeatedly.
  3774. //
  3775. // Even though in theory the AGREEMENT message sent just once may miss
  3776. // the target (as normal thing in UDP), this is little probable to happen,
  3777. // and this doesn't matter much because even if the other party doesn't
  3778. // get AGREEMENT, but will get payload or KEEPALIVE messages, it will
  3779. // turn into connected state as well. The AGREEMENT is rather kinda
  3780. // catalyzer here and may turn the entity on the right track faster. When
  3781. // AGREEMENT is missed, it may have kinda initial tearing.
  3782. const steady_clock::time_point now = steady_clock::now();
  3783. m_tsLastReqTime = now;
  3784. setPacketTS(w_reqpkt, now);
  3785. HLOGC(cnlog.Debug,
  3786. log << CONID()
  3787. << "processRendezvous: rsp=AGREEMENT, reporting ACCEPT and sending just this one, REQ-TIME HIGH.");
  3788. m_pSndQueue->sendto(serv_addr, w_reqpkt, m_SourceAddr);
  3789. return CONN_ACCEPT;
  3790. }
  3791. if (rst == RST_OK)
  3792. {
  3793. // the request time must be updated so that the next handshake can be sent out immediately
  3794. HLOGC(cnlog.Debug,
  3795. log << "processRendezvous: rsp=" << RequestTypeStr(m_ConnReq.m_iReqType)
  3796. << " REQ-TIME: LOW to send immediately, consider yourself conencted");
  3797. m_tsLastReqTime = steady_clock::time_point();
  3798. }
  3799. else
  3800. {
  3801. HLOGC(cnlog.Debug,
  3802. log << CONID() << "processRendezvous: REQ-TIME: remains previous value, consider yourself connected");
  3803. }
  3804. return CONN_CONTINUE;
  3805. }
  3806. // [[using locked(m_ConnectionLock)]];
  3807. EConnectStatus srt::CUDT::processConnectResponse(const CPacket& response, CUDTException* eout) ATR_NOEXCEPT
  3808. {
  3809. // NOTE: ASSUMED LOCK ON: m_ConnectionLock.
  3810. // this is the 2nd half of a connection request. If the connection is setup successfully this returns 0.
  3811. // Returned values:
  3812. // - CONN_REJECT: there was some error when processing the response, connection should be rejected
  3813. // - CONN_ACCEPT: the handshake is done and finished correctly
  3814. // - CONN_CONTINUE: the induction handshake has been processed correctly, and expects CONCLUSION handshake
  3815. if (!m_bConnecting)
  3816. return CONN_REJECT;
  3817. // This is required in HSv5 rendezvous, in which it should send the URQ_AGREEMENT message to
  3818. // the peer, however switch to connected state.
  3819. HLOGC(cnlog.Debug,
  3820. log << CONID() << "processConnectResponse: TYPE:"
  3821. << (response.isControl() ? MessageTypeStr(response.getType(), response.getExtendedType())
  3822. : string("DATA")));
  3823. // ConnectStatus res = CONN_REJECT; // used later for status - must be declared here due to goto POST_CONNECT.
  3824. // For HSv4, the data sender is INITIATOR, and the data receiver is RESPONDER,
  3825. // regardless of the connecting side affiliation. This will be changed for HSv5.
  3826. bool bidirectional = false;
  3827. HandshakeSide hsd = m_config.bDataSender ? HSD_INITIATOR : HSD_RESPONDER;
  3828. // (defined here due to 'goto' below).
  3829. // SRT peer may send the SRT handshake private message (type 0x7fff) before a keep-alive.
  3830. // This condition is checked when the current agent is trying to do connect() in rendezvous mode,
  3831. // but the peer was faster to send a handshake packet earlier. This makes it continue with connecting
  3832. // process if the peer is already behaving as if the connection was already established.
  3833. // This value will check either the initial value, which is less than SRT1, or
  3834. // the value previously loaded to m_ConnReq during the previous handshake response.
  3835. // For the initial form this value should not be checked.
  3836. bool hsv5 = m_ConnRes.m_iVersion >= HS_VERSION_SRT1;
  3837. if (m_config.bRendezvous &&
  3838. (m_RdvState == CHandShake::RDV_CONNECTED // somehow Rendezvous-v5 switched it to CONNECTED.
  3839. || !response.isControl() // WAS A PAYLOAD PACKET.
  3840. || (response.getType() == UMSG_KEEPALIVE) // OR WAS A UMSG_KEEPALIVE message.
  3841. || (response.getType() == UMSG_EXT) // OR WAS a CONTROL packet of some extended type (i.e. any SRT specific)
  3842. )
  3843. // This may happen if this is an initial state in which the socket type was not yet set.
  3844. // If this is a field that holds the response handshake record from the peer, this means that it wasn't received
  3845. // yet. HSv5: added version check because in HSv5 the m_iType field has different meaning and it may be 0 in
  3846. // case when the handshake does not carry SRT extensions.
  3847. && (hsv5 || m_ConnRes.m_iType != UDT_UNDEFINED))
  3848. {
  3849. // a data packet or a keep-alive packet comes, which means the peer side is already connected
  3850. // in this situation, the previously recorded response will be used
  3851. // In HSv5 this situation is theoretically possible if this party has missed the URQ_AGREEMENT message.
  3852. HLOGC(cnlog.Debug, log << CONID() << "processConnectResponse: already connected - pinning in");
  3853. if (hsv5)
  3854. {
  3855. m_RdvState = CHandShake::RDV_CONNECTED;
  3856. }
  3857. return postConnect(&response, hsv5, eout);
  3858. }
  3859. if (!response.isControl(UMSG_HANDSHAKE))
  3860. {
  3861. m_RejectReason = SRT_REJ_ROGUE;
  3862. if (!response.isControl())
  3863. {
  3864. LOGC(cnlog.Warn, log << CONID() << "processConnectResponse: received DATA while HANDSHAKE expected");
  3865. }
  3866. else
  3867. {
  3868. LOGC(cnlog.Error,
  3869. log << CONID()
  3870. << "processConnectResponse: CONFUSED: expected UMSG_HANDSHAKE as connection not yet established, "
  3871. "got: "
  3872. << MessageTypeStr(response.getType(), response.getExtendedType()));
  3873. if (response.getType() == UMSG_SHUTDOWN)
  3874. {
  3875. LOGC(cnlog.Error,
  3876. log << CONID() << "processConnectResponse: UMSG_SHUTDOWN received, rejecting connection.");
  3877. return CONN_REJECT;
  3878. }
  3879. }
  3880. if (m_config.bRendezvous)
  3881. {
  3882. // In rendezvous mode we expect that both sides are known
  3883. // to the service operator (unlike a listener, which may
  3884. // operate connections from unknown sources). This means that
  3885. // the connection process should be terminated anyway, on
  3886. // whichever side it would happen.
  3887. return CONN_REJECT;
  3888. }
  3889. return CONN_CONFUSED;
  3890. }
  3891. if (m_config.bRendezvous)
  3892. {
  3893. m_SourceAddr = response.udpDestAddr();
  3894. }
  3895. if (m_ConnRes.load_from(response.m_pcData, response.getLength()) == -1)
  3896. {
  3897. m_RejectReason = SRT_REJ_ROGUE;
  3898. // Handshake data were too small to reach the Handshake structure. Reject.
  3899. LOGC(cnlog.Error,
  3900. log << CONID()
  3901. << "processConnectResponse: HANDSHAKE data buffer too small - possible blueboxing. Rejecting.");
  3902. return CONN_REJECT;
  3903. }
  3904. HLOGC(cnlog.Debug, log << CONID() << "processConnectResponse: HS RECEIVED: " << m_ConnRes.show());
  3905. if (m_ConnRes.m_iReqType >= URQ_FAILURE_TYPES)
  3906. {
  3907. m_RejectReason = RejectReasonForURQ(m_ConnRes.m_iReqType);
  3908. LOGC(cnlog.Warn,
  3909. log << CONID() << "processConnectResponse: rejecting per reception of a rejection HS response: "
  3910. << RequestTypeStr(m_ConnRes.m_iReqType));
  3911. return CONN_REJECT;
  3912. }
  3913. if (size_t(m_ConnRes.m_iMSS) > CPacket::ETH_MAX_MTU_SIZE)
  3914. {
  3915. // Yes, we do abort to prevent buffer overrun. Set your MSS correctly
  3916. // and you'll avoid problems.
  3917. m_RejectReason = SRT_REJ_ROGUE;
  3918. LOGC(cnlog.Fatal, log << CONID() << "MSS size " << m_config.iMSS << "exceeds MTU size!");
  3919. return CONN_REJECT;
  3920. }
  3921. // (see createCrypter() call below)
  3922. //
  3923. // The CCryptoControl attached object must be created early
  3924. // because it will be required to create a conclusion handshake in HSv5
  3925. //
  3926. if (m_config.bRendezvous)
  3927. {
  3928. // SANITY CHECK: A rendezvous socket should reject any caller requests (it's not a listener)
  3929. if (m_ConnRes.m_iReqType == URQ_INDUCTION)
  3930. {
  3931. m_RejectReason = SRT_REJ_ROGUE;
  3932. LOGC(cnlog.Error,
  3933. log << CONID()
  3934. << "processConnectResponse: Rendezvous-point received INDUCTION handshake (expected WAVEAHAND). "
  3935. "Rejecting.");
  3936. return CONN_REJECT;
  3937. }
  3938. // The procedure for version 5 is completely different and changes the states
  3939. // differently, so the old code will still maintain HSv4 the old way.
  3940. if (m_ConnRes.m_iVersion > HS_VERSION_UDT4)
  3941. {
  3942. HLOGC(cnlog.Debug, log << CONID() << "processConnectResponse: Rendezvous HSv5 DETECTED.");
  3943. return CONN_RENDEZVOUS; // --> will continue in CUDT::processRendezvous().
  3944. }
  3945. HLOGC(cnlog.Debug, log << CONID() << "processConnectResponse: Rendsezvous HSv4 DETECTED.");
  3946. // So, here it has either received URQ_WAVEAHAND handshake message (while it should be in URQ_WAVEAHAND itself)
  3947. // or it has received URQ_CONCLUSION/URQ_AGREEMENT message while this box has already sent URQ_WAVEAHAND to the
  3948. // peer, and DID NOT send the URQ_CONCLUSION yet.
  3949. if (m_ConnReq.m_iReqType == URQ_WAVEAHAND || m_ConnRes.m_iReqType == URQ_WAVEAHAND)
  3950. {
  3951. HLOGC(cnlog.Debug,
  3952. log << CONID() << "processConnectResponse: REQ-TIME LOW. got HS RDV. Agent state:"
  3953. << RequestTypeStr(m_ConnReq.m_iReqType) << " Peer HS:" << m_ConnRes.show());
  3954. // Here we could have received WAVEAHAND or CONCLUSION.
  3955. // For HSv4 simply switch to CONCLUSION for the sake of further handshake rolling.
  3956. // For HSv5, make the cookie contest and basing on this decide, which party
  3957. // should provide the HSREQ/KMREQ attachment.
  3958. if (!createCrypter(hsd, false /* unidirectional */))
  3959. {
  3960. m_RejectReason = SRT_REJ_RESOURCE;
  3961. m_ConnReq.m_iReqType = URQFailure(SRT_REJ_RESOURCE);
  3962. // the request time must be updated so that the next handshake can be sent out immediately.
  3963. m_tsLastReqTime = steady_clock::time_point();
  3964. return CONN_REJECT;
  3965. }
  3966. m_ConnReq.m_iReqType = URQ_CONCLUSION;
  3967. // the request time must be updated so that the next handshake can be sent out immediately.
  3968. m_tsLastReqTime = steady_clock::time_point();
  3969. return CONN_CONTINUE;
  3970. }
  3971. else
  3972. {
  3973. HLOGC(cnlog.Debug, log << CONID() << "processConnectResponse: Rendezvous HSv4 PAST waveahand");
  3974. }
  3975. }
  3976. else
  3977. {
  3978. // set cookie
  3979. if (m_ConnRes.m_iReqType == URQ_INDUCTION)
  3980. {
  3981. HLOGC(cnlog.Debug,
  3982. log << CONID() << "processConnectResponse: REQ-TIME LOW; got INDUCTION HS response (cookie:" << hex
  3983. << m_ConnRes.m_iCookie << " version:" << dec << m_ConnRes.m_iVersion
  3984. << "), sending CONCLUSION HS with this cookie");
  3985. m_ConnReq.m_iCookie = m_ConnRes.m_iCookie;
  3986. m_ConnReq.m_iReqType = URQ_CONCLUSION;
  3987. // Here test if the LISTENER has responded with version HS_VERSION_SRT1,
  3988. // it means that it is HSv5 capable. It can still accept the HSv4 handshake.
  3989. if (m_ConnRes.m_iVersion > HS_VERSION_UDT4)
  3990. {
  3991. const int hs_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_ConnRes.m_iType);
  3992. if (hs_flags != SrtHSRequest::SRT_MAGIC_CODE)
  3993. {
  3994. LOGC(cnlog.Warn,
  3995. log << CONID() << "processConnectResponse: Listener HSv5 did not set the SRT_MAGIC_CODE.");
  3996. m_RejectReason = SRT_REJ_ROGUE;
  3997. return CONN_REJECT;
  3998. }
  3999. checkUpdateCryptoKeyLen("processConnectResponse", m_ConnRes.m_iType);
  4000. // This will catch HS_VERSION_SRT1 and any newer.
  4001. // Set your highest version.
  4002. m_ConnReq.m_iVersion = HS_VERSION_SRT1;
  4003. // CONTROVERSIAL: use 0 as m_iType according to the meaning in HSv5.
  4004. // The HSv4 client might not understand it, which means that agent
  4005. // must switch itself to HSv4 rendezvous, and this time iType should
  4006. // be set to UDT_DGRAM value.
  4007. m_ConnReq.m_iType = 0;
  4008. // This marks the information for the serializer that
  4009. // the SRT handshake extension is required.
  4010. // Rest of the data will be filled together with
  4011. // serialization.
  4012. m_ConnReq.m_extension = true;
  4013. // For HSv5, the caller is INITIATOR and the listener is RESPONDER.
  4014. // The m_config.bDataSender value should be completely ignored and the
  4015. // connection is always bidirectional.
  4016. bidirectional = true;
  4017. hsd = HSD_INITIATOR;
  4018. m_SrtHsSide = hsd;
  4019. }
  4020. m_tsLastReqTime = steady_clock::time_point();
  4021. if (!createCrypter(hsd, bidirectional))
  4022. {
  4023. m_RejectReason = SRT_REJ_RESOURCE;
  4024. return CONN_REJECT;
  4025. }
  4026. // NOTE: This setup sets URQ_CONCLUSION and appropriate data in the handshake structure.
  4027. // The full handshake to be sent will be filled back in the caller function -- CUDT::startConnect().
  4028. return CONN_CONTINUE;
  4029. }
  4030. }
  4031. return postConnect(&response, false, eout);
  4032. }
  4033. bool srt::CUDT::applyResponseSettings(const CPacket* pHspkt /*[[nullable]]*/) ATR_NOEXCEPT
  4034. {
  4035. if (!m_ConnRes.valid())
  4036. {
  4037. LOGC(cnlog.Error, log << CONID() << "applyResponseSettings: ROGUE HANDSHAKE - rejecting");
  4038. m_RejectReason = SRT_REJ_ROGUE;
  4039. return false;
  4040. }
  4041. // Re-configure according to the negotiated values.
  4042. m_config.iMSS = m_ConnRes.m_iMSS;
  4043. m_iFlowWindowSize = m_ConnRes.m_iFlightFlagSize;
  4044. const int udpsize = m_config.iMSS - CPacket::UDP_HDR_SIZE;
  4045. m_iMaxSRTPayloadSize = udpsize - CPacket::HDR_SIZE;
  4046. m_iPeerISN = m_ConnRes.m_iISN;
  4047. setInitialRcvSeq(m_iPeerISN);
  4048. m_iRcvCurrPhySeqNo = CSeqNo::decseq(m_ConnRes.m_iISN);
  4049. m_PeerID = m_ConnRes.m_iID;
  4050. memcpy((m_piSelfIP), m_ConnRes.m_piPeerIP, sizeof m_piSelfIP);
  4051. if (pHspkt)
  4052. m_SourceAddr = pHspkt->udpDestAddr();
  4053. HLOGC(cnlog.Debug,
  4054. log << CONID() << "applyResponseSettings: HANSHAKE CONCLUDED. SETTING: payload-size=" << m_iMaxSRTPayloadSize
  4055. << " mss=" << m_ConnRes.m_iMSS << " flw=" << m_ConnRes.m_iFlightFlagSize << " peer-ISN=" << m_ConnRes.m_iISN
  4056. << " local-ISN=" << m_iISN
  4057. << " peerID=" << m_ConnRes.m_iID
  4058. << " sourceIP=" << m_SourceAddr.str());
  4059. return true;
  4060. }
  4061. EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, CUDTException *eout) ATR_NOEXCEPT
  4062. {
  4063. if (m_ConnRes.m_iVersion < HS_VERSION_SRT1)
  4064. m_tsRcvPeerStartTime = steady_clock::time_point(); // will be set correctly in SRT HS.
  4065. // This procedure isn't being executed in rendezvous because
  4066. // in rendezvous it's completed before calling this function.
  4067. if (!rendezvous)
  4068. {
  4069. HLOGC(cnlog.Debug, log << CONID() << boolalpha << "postConnect: packet:" << bool(pResponse) << " rendezvous:" << rendezvous);
  4070. // The "local storage depleted" case shouldn't happen here, but
  4071. // this is a theoretical path that needs prevention.
  4072. bool ok = pResponse;
  4073. if (!ok)
  4074. {
  4075. m_RejectReason = SRT_REJ_IPE;
  4076. if (eout)
  4077. {
  4078. *eout = CUDTException(MJ_SETUP, MN_REJECTED, 0);
  4079. }
  4080. return CONN_REJECT;
  4081. }
  4082. // [[assert (pResponse != NULL)]];
  4083. // NOTE: THIS function must be called before calling prepareConnectionObjects.
  4084. // The reason why it's not part of prepareConnectionObjects is that the activities
  4085. // done there are done SIMILAR way in acceptAndRespond, which also calls this
  4086. // function. In fact, prepareConnectionObjects() represents the code that was
  4087. // done separately in processConnectResponse() and acceptAndRespond(), so this way
  4088. // this code is now common. Now acceptAndRespond() does "manually" something similar
  4089. // to applyResponseSettings(), just a little bit differently. This SHOULD be made
  4090. // common as a part of refactoring job, just needs a bit more time.
  4091. //
  4092. // Currently just this function must be called always BEFORE prepareConnectionObjects
  4093. // everywhere except acceptAndRespond().
  4094. ok = applyResponseSettings(pResponse);
  4095. // This will actually be done also in rendezvous HSv4,
  4096. // however in this case the HSREQ extension will not be attached,
  4097. // so it will simply go the "old way".
  4098. // (&&: skip if failed already)
  4099. // Must be called before interpretSrtHandshake() to create the CryptoControl.
  4100. ok = ok && prepareConnectionObjects(m_ConnRes, m_SrtHsSide, eout);
  4101. // May happen that 'response' contains a data packet that was sent in rendezvous mode.
  4102. // In this situation the interpretation of handshake was already done earlier.
  4103. ok = ok && pResponse->isControl();
  4104. ok = ok && interpretSrtHandshake(m_ConnRes, *pResponse, 0, 0);
  4105. ok = ok && prepareBuffers(eout);
  4106. if (!ok)
  4107. {
  4108. if (eout)
  4109. {
  4110. *eout = CUDTException(MJ_SETUP, MN_REJECTED, 0);
  4111. }
  4112. // m_RejectReason already set
  4113. return CONN_REJECT;
  4114. }
  4115. }
  4116. bool have_group = false;
  4117. {
  4118. #if ENABLE_BONDING
  4119. ScopedLock cl (uglobal().m_GlobControlLock);
  4120. CUDTGroup* g = m_parent->m_GroupOf;
  4121. if (g)
  4122. {
  4123. // This is the last moment when this can be done.
  4124. // The updateAfterSrtHandshake call will copy the receiver
  4125. // start time to the receiver buffer data, so the correct
  4126. // value must be set before this happens.
  4127. synchronizeWithGroup(g);
  4128. have_group = true;
  4129. }
  4130. #endif
  4131. }
  4132. if (!have_group)
  4133. {
  4134. // This function will be called internally inside
  4135. // synchronizeWithGroup(). This is just more complicated.
  4136. updateAfterSrtHandshake(m_ConnRes.m_iVersion);
  4137. }
  4138. CInfoBlock ib;
  4139. ib.m_iIPversion = m_PeerAddr.family();
  4140. CInfoBlock::convert(m_PeerAddr, ib.m_piIP);
  4141. if (m_pCache->lookup(&ib) >= 0)
  4142. {
  4143. m_iSRTT = ib.m_iSRTT;
  4144. m_iRTTVar = ib.m_iSRTT / 2;
  4145. m_iBandwidth = ib.m_iBandwidth;
  4146. }
  4147. #if SRT_DEBUG_RTT
  4148. s_rtt_trace.trace(steady_clock::now(), "Connect", -1, -1,
  4149. m_bIsFirstRTTReceived, -1, m_iSRTT, m_iRTTVar);
  4150. #endif
  4151. SRT_REJECT_REASON rr = setupCC();
  4152. if (rr != SRT_REJ_UNKNOWN)
  4153. {
  4154. m_RejectReason = rr;
  4155. return CONN_REJECT;
  4156. }
  4157. // And, I am connected too.
  4158. m_bConnecting = false;
  4159. // The lock on m_ConnectionLock should still be applied, but
  4160. // the socket could have been started removal before this function
  4161. // has started. Do a sanity check before you continue with the
  4162. // connection process.
  4163. CUDTSocket* s = uglobal().locateSocket(m_SocketID);
  4164. if (s)
  4165. {
  4166. // The socket could be closed at this very moment.
  4167. // Continue with removing the socket from the pending structures,
  4168. // but prevent it from setting it as connected.
  4169. m_bConnected = true;
  4170. // register this socket for receiving data packets
  4171. m_pRNode->m_bOnList = true;
  4172. m_pRcvQueue->setNewEntry(this);
  4173. }
  4174. // XXX Problem around CONN_CONFUSED!
  4175. // If some too-eager packets were received from a listener
  4176. // that thinks it's connected, but his last handshake was missed,
  4177. // they are collected by CRcvQueue::storePktClone. The removeConnector
  4178. // function will want to delete them all, so it would be nice
  4179. // if these packets can be re-delivered. Of course the listener
  4180. // should be prepared to resend them (as every packet can be lost
  4181. // on UDP), but it's kinda overkill when we have them already and
  4182. // can dispatch them.
  4183. // Remove from rendezvous queue (in this particular case it's
  4184. // actually removing the socket that undergoes asynchronous HS processing).
  4185. // Removing at THIS point because since when setNewEntry is called,
  4186. // the next iteration in the CRcvQueue::worker loop will be dispatching
  4187. // packets normally, as within-connection, so the "connector" won't
  4188. // play any role since this time.
  4189. // The connector, however, must stay alive until the setNewEntry is called
  4190. // because otherwise the packets that are coming for this socket before the
  4191. // connection process is complete will be rejected as "attack", instead of
  4192. // being enqueued for later pickup from the queue.
  4193. m_pRcvQueue->removeConnector(m_SocketID);
  4194. // Ok, no more things to be done as per "clear connecting state"
  4195. if (!s)
  4196. {
  4197. LOGC(cnlog.Error, log << CONID() << "Connection broken in the process - socket closed");
  4198. m_RejectReason = SRT_REJ_CLOSE;
  4199. if (eout)
  4200. {
  4201. *eout = CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  4202. }
  4203. return CONN_REJECT;
  4204. }
  4205. // copy address information of local node
  4206. // the local port must be correctly assigned BEFORE CUDT::startConnect(),
  4207. // otherwise if startConnect() fails, the multiplexer cannot be located
  4208. // by garbage collection and will cause leak
  4209. s->core().m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr));
  4210. CIPAddress::pton((s->m_SelfAddr), s->core().m_piSelfIP, m_PeerAddr);
  4211. //int token = -1;
  4212. #if ENABLE_BONDING
  4213. {
  4214. ScopedLock cl (uglobal().m_GlobControlLock);
  4215. CUDTGroup* g = m_parent->m_GroupOf;
  4216. if (g)
  4217. {
  4218. // XXX this might require another check of group type.
  4219. // For redundancy group, at least, update the status in the group.
  4220. // LEAVING as comment for historical reasons. Locking is here most
  4221. // likely not necessary because the socket cannot be removed from the
  4222. // group until the socket isn't removed, and this requires locking of
  4223. // m_GlobControlLock. This should ensure that when m_GroupOf is
  4224. // not NULL, m_GroupMemberData is also valid.
  4225. // ScopedLock glock(g->m_GroupLock);
  4226. HLOGC(cnlog.Debug, log << "group: Socket @" << m_parent->m_SocketID << " fresh connected, setting IDLE");
  4227. groups::SocketData* gi = m_parent->m_GroupMemberData;
  4228. gi->sndstate = SRT_GST_IDLE;
  4229. gi->rcvstate = SRT_GST_IDLE;
  4230. gi->laststatus = SRTS_CONNECTED;
  4231. //token = gi->token;
  4232. g->setGroupConnected();
  4233. }
  4234. }
  4235. #endif
  4236. s->m_Status = SRTS_CONNECTED;
  4237. // acknowledde any waiting epolls to write
  4238. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_CONNECT, true);
  4239. CGlobEvent::triggerEvent();
  4240. /* XXX Likely it should NOT be called here for two reasons:
  4241. - likely lots of mutexes are locked here so any
  4242. API call from here might cause a deadlock
  4243. - if called from an asynchronous connection process, it was
  4244. already called from inside updateConnStatus
  4245. - if called from startConnect (synchronous mode), it is even wrong.
  4246. if (m_cbConnectHook)
  4247. {
  4248. CALLBACK_CALL(m_cbConnectHook, m_SocketID, SRT_SUCCESS, m_PeerAddr.get(), token);
  4249. }
  4250. */
  4251. LOGC(cnlog.Note, log << CONID() << "Connection established to: " << m_PeerAddr.str());
  4252. return CONN_ACCEPT;
  4253. }
  4254. void srt::CUDT::checkUpdateCryptoKeyLen(const char *loghdr SRT_ATR_UNUSED, int32_t typefield)
  4255. {
  4256. int enc_flags = SrtHSRequest::SRT_HSTYPE_ENCFLAGS::unwrap(typefield);
  4257. // potentially 0-7 values are possible.
  4258. // When 0, don't change anything - it should rely on the value 0.
  4259. // When 1, 5, 6, 7, this is kinda internal error - ignore.
  4260. if (enc_flags >= 2 && enc_flags <= 4) // 2 = 128, 3 = 192, 4 = 256
  4261. {
  4262. int rcv_pbkeylen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(enc_flags);
  4263. if (m_config.iSndCryptoKeyLen == 0)
  4264. {
  4265. m_config.iSndCryptoKeyLen = rcv_pbkeylen;
  4266. HLOGC(cnlog.Debug,
  4267. log << CONID() << loghdr
  4268. << ": PBKEYLEN adopted from advertised value: " << m_config.iSndCryptoKeyLen);
  4269. }
  4270. else if (m_config.iSndCryptoKeyLen != rcv_pbkeylen)
  4271. {
  4272. // Conflict. Use SRTO_SENDER flag to check if this side should accept
  4273. // the enforcement, otherwise simply let it win.
  4274. if (!m_config.bDataSender)
  4275. {
  4276. LOGC(cnlog.Warn,
  4277. log << CONID() << loghdr << ": PBKEYLEN conflict - OVERRIDDEN " << m_config.iSndCryptoKeyLen
  4278. << " by " << rcv_pbkeylen << " from PEER (as AGENT is not SRTO_SENDER)");
  4279. m_config.iSndCryptoKeyLen = rcv_pbkeylen;
  4280. }
  4281. else
  4282. {
  4283. LOGC(cnlog.Warn,
  4284. log << CONID() << loghdr << ": PBKEYLEN conflict - keep " << m_config.iSndCryptoKeyLen
  4285. << "; peer-advertised PBKEYLEN " << rcv_pbkeylen << " rejected because Agent is SRTO_SENDER");
  4286. }
  4287. }
  4288. }
  4289. else if (enc_flags != 0)
  4290. {
  4291. LOGC(cnlog.Error, log << CONID() << loghdr << ": IPE: enc_flags outside allowed 2, 3, 4: " << enc_flags);
  4292. }
  4293. else
  4294. {
  4295. HLOGC(cnlog.Debug, log << CONID() << loghdr << ": No encryption flags found in type field: " << typefield);
  4296. }
  4297. }
  4298. // Rendezvous
  4299. void srt::CUDT::rendezvousSwitchState(UDTRequestType& w_rsptype, bool& w_needs_extension, bool& w_needs_hsrsp)
  4300. {
  4301. UDTRequestType req = m_ConnRes.m_iReqType;
  4302. int hs_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_ConnRes.m_iType);
  4303. bool has_extension = !!hs_flags; // it holds flags, if no flags, there are no extensions.
  4304. const HandshakeSide &hsd = m_SrtHsSide;
  4305. // Note important possibilities that are considered here:
  4306. // 1. The serial arrangement. This happens when one party has missed the
  4307. // URQ_WAVEAHAND message, it sent its own URQ_WAVEAHAND message, and then the
  4308. // firstmost message it received from the peer is URQ_CONCLUSION, as a response
  4309. // for agent's URQ_WAVEAHAND.
  4310. //
  4311. // In this case, Agent switches to RDV_FINE state and Peer switches to RDV_ATTENTION state.
  4312. //
  4313. // 2. The parallel arrangement. This happens when the URQ_WAVEAHAND message sent
  4314. // by both parties are almost in a perfect synch (a rare, but possible case). In this
  4315. // case, both parties receive one another's URQ_WAVEAHAND message and both switch to
  4316. // RDV_ATTENTION state.
  4317. //
  4318. // It's not possible to predict neither which arrangement will happen, or which
  4319. // party will be RDV_FINE in case when the serial arrangement has happened. What
  4320. // will actually happen will depend on random conditions.
  4321. //
  4322. // No matter this randomity, we have a limited number of possible conditions:
  4323. //
  4324. // Stating that "agent" is the party that has received the URQ_WAVEAHAND in whatever
  4325. // arrangement, we are certain, that "agent" switched to RDV_ATTENTION, and peer:
  4326. //
  4327. // - switched to RDV_ATTENTION state (so, both are in the same state independently)
  4328. // - switched to RDV_FINE state (so, the message interchange is actually more-less sequenced)
  4329. //
  4330. // In particular, there's no possibility of a situation that both are in RDV_FINE state
  4331. // because the agent can switch to RDV_FINE state only if it received URQ_CONCLUSION from
  4332. // the peer, while the peer could not send URQ_CONCLUSION without switching off RDV_WAVING
  4333. // (actually to RDV_ATTENTION). There's also no exit to RDV_FINE from RDV_ATTENTION.
  4334. // DEFAULT STATEMENT: don't attach extensions to URQ_CONCLUSION, neither HSREQ nor HSRSP.
  4335. w_needs_extension = false;
  4336. w_needs_hsrsp = false;
  4337. string reason;
  4338. #if ENABLE_HEAVY_LOGGING
  4339. HLOGC(cnlog.Debug, log << CONID() << "rendezvousSwitchState: HS: " << m_ConnRes.show());
  4340. struct LogAtTheEnd
  4341. {
  4342. CHandShake::RendezvousState ost;
  4343. UDTRequestType orq;
  4344. const CHandShake::RendezvousState &nst;
  4345. const UDTRequestType & nrq;
  4346. bool & needext;
  4347. bool & needrsp;
  4348. string & reason;
  4349. ~LogAtTheEnd()
  4350. {
  4351. HLOGC(cnlog.Debug,
  4352. log << "rendezvousSwitchState: STATE[" << CHandShake::RdvStateStr(ost) << "->"
  4353. << CHandShake::RdvStateStr(nst) << "] REQTYPE[" << RequestTypeStr(orq) << "->"
  4354. << RequestTypeStr(nrq) << "] "
  4355. << "ext:" << (needext ? (needrsp ? "HSRSP" : "HSREQ") : "NONE")
  4356. << (reason == "" ? string() : "reason:" + reason));
  4357. }
  4358. } l_logend = {m_RdvState, req, m_RdvState, w_rsptype, w_needs_extension, w_needs_hsrsp, reason};
  4359. #endif
  4360. switch (m_RdvState)
  4361. {
  4362. case CHandShake::RDV_INVALID:
  4363. return;
  4364. case CHandShake::RDV_WAVING:
  4365. {
  4366. if (req == URQ_WAVEAHAND)
  4367. {
  4368. m_RdvState = CHandShake::RDV_ATTENTION;
  4369. // NOTE: if this->isWinner(), attach HSREQ
  4370. w_rsptype = URQ_CONCLUSION;
  4371. if (hsd == HSD_INITIATOR)
  4372. w_needs_extension = true;
  4373. return;
  4374. }
  4375. if (req == URQ_CONCLUSION)
  4376. {
  4377. m_RdvState = CHandShake::RDV_FINE;
  4378. w_rsptype = URQ_CONCLUSION;
  4379. w_needs_extension = true; // (see below - this needs to craft either HSREQ or HSRSP)
  4380. // if this->isWinner(), then craft HSREQ for that response.
  4381. // if this->isLoser(), then this packet should bring HSREQ, so craft HSRSP for the response.
  4382. if (hsd == HSD_RESPONDER)
  4383. w_needs_hsrsp = true;
  4384. return;
  4385. }
  4386. }
  4387. reason = "WAVING -> WAVEAHAND or CONCLUSION";
  4388. break;
  4389. case CHandShake::RDV_ATTENTION:
  4390. {
  4391. if (req == URQ_WAVEAHAND)
  4392. {
  4393. // This is only possible if the URQ_CONCLUSION sent to the peer
  4394. // was lost on track. The peer is then simply unaware that the
  4395. // agent has switched to ATTENTION state and continues sending
  4396. // waveahands. In this case, just remain in ATTENTION state and
  4397. // retry with URQ_CONCLUSION, as normally.
  4398. w_rsptype = URQ_CONCLUSION;
  4399. if (hsd == HSD_INITIATOR)
  4400. w_needs_extension = true;
  4401. return;
  4402. }
  4403. if (req == URQ_CONCLUSION)
  4404. {
  4405. // We have two possibilities here:
  4406. //
  4407. // WINNER (HSD_INITIATOR): send URQ_AGREEMENT
  4408. if (hsd == HSD_INITIATOR)
  4409. {
  4410. // WINNER should get a response with HSRSP, otherwise this is kinda empty conclusion.
  4411. // If no HSRSP attached, stay in this state.
  4412. if (hs_flags == 0)
  4413. {
  4414. HLOGC(cnlog.Debug,
  4415. log << CONID()
  4416. << "rendezvousSwitchState: {INITIATOR}[ATTENTION] awaits CONCLUSION+HSRSP, got "
  4417. "CONCLUSION, remain in [ATTENTION]");
  4418. w_rsptype = URQ_CONCLUSION;
  4419. w_needs_extension = true; // If you expect to receive HSRSP, continue sending HSREQ
  4420. return;
  4421. }
  4422. m_RdvState = CHandShake::RDV_CONNECTED;
  4423. w_rsptype = URQ_AGREEMENT;
  4424. return;
  4425. }
  4426. // LOSER (HSD_RESPONDER): send URQ_CONCLUSION and attach HSRSP extension, then expect URQ_AGREEMENT
  4427. if (hsd == HSD_RESPONDER)
  4428. {
  4429. // If no HSREQ attached, stay in this state.
  4430. // (Although this seems completely impossible).
  4431. if (hs_flags == 0)
  4432. {
  4433. LOGC(cnlog.Warn,
  4434. log << CONID()
  4435. << "rendezvousSwitchState: (IPE!){RESPONDER}[ATTENTION] awaits CONCLUSION+HSREQ, got "
  4436. "CONCLUSION, remain in [ATTENTION]");
  4437. w_rsptype = URQ_CONCLUSION;
  4438. w_needs_extension = false; // If you received WITHOUT extensions, respond WITHOUT extensions (wait
  4439. // for the right message)
  4440. return;
  4441. }
  4442. m_RdvState = CHandShake::RDV_INITIATED;
  4443. w_rsptype = URQ_CONCLUSION;
  4444. w_needs_extension = true;
  4445. w_needs_hsrsp = true;
  4446. return;
  4447. }
  4448. LOGC(cnlog.Error, log << CONID() << "RENDEZVOUS COOKIE DRAW! Cannot resolve to a valid state.");
  4449. // Fallback for cookie draw
  4450. m_RdvState = CHandShake::RDV_INVALID;
  4451. w_rsptype = URQFailure(SRT_REJ_RDVCOOKIE);
  4452. return;
  4453. }
  4454. if (req == URQ_AGREEMENT)
  4455. {
  4456. // This means that the peer has received our URQ_CONCLUSION, but
  4457. // the agent missed the peer's URQ_CONCLUSION (received only initial
  4458. // URQ_WAVEAHAND).
  4459. if (hsd == HSD_INITIATOR)
  4460. {
  4461. // In this case the missed URQ_CONCLUSION was sent without extensions,
  4462. // whereas the peer received our URQ_CONCLUSION with HSREQ, and therefore
  4463. // it sent URQ_AGREEMENT already with HSRSP. This isn't a problem for
  4464. // us, we can go on with it, especially that the peer is already switched
  4465. // into CHandShake::RDV_CONNECTED state.
  4466. m_RdvState = CHandShake::RDV_CONNECTED;
  4467. // Both sides are connected, no need to send anything anymore.
  4468. w_rsptype = URQ_DONE;
  4469. return;
  4470. }
  4471. if (hsd == HSD_RESPONDER)
  4472. {
  4473. // In this case the missed URQ_CONCLUSION was sent with extensions, so
  4474. // we have to request this once again. Send URQ_CONCLUSION in order to
  4475. // inform the other party that we need the conclusion message once again.
  4476. // The ATTENTION state should be maintained.
  4477. w_rsptype = URQ_CONCLUSION;
  4478. w_needs_extension = true;
  4479. w_needs_hsrsp = true;
  4480. return;
  4481. }
  4482. }
  4483. }
  4484. reason = "ATTENTION -> WAVEAHAND(conclusion), CONCLUSION(agreement/conclusion), AGREEMENT (done/conclusion)";
  4485. break;
  4486. case CHandShake::RDV_FINE:
  4487. {
  4488. // In FINE state we can't receive URQ_WAVEAHAND because if the peer has already
  4489. // sent URQ_CONCLUSION, it's already in CHandShake::RDV_ATTENTION, and in this state it can
  4490. // only send URQ_CONCLUSION, whereas when it isn't in CHandShake::RDV_ATTENTION, it couldn't
  4491. // have sent URQ_CONCLUSION, and if it didn't, the agent wouldn't be in CHandShake::RDV_FINE state.
  4492. if (req == URQ_CONCLUSION)
  4493. {
  4494. // There's only one case when it should receive CONCLUSION in FINE state:
  4495. // When it's the winner. If so, it should then contain HSREQ extension.
  4496. // In case of loser, it shouldn't receive CONCLUSION at all - it should
  4497. // receive AGREEMENT.
  4498. // The winner case, received CONCLUSION + HSRSP - switch to CONNECTED and send AGREEMENT.
  4499. // So, check first if HAS EXTENSION
  4500. bool correct_switch = false;
  4501. if (hsd == HSD_INITIATOR && !has_extension)
  4502. {
  4503. // Received REPEATED empty conclusion that has initially switched it into FINE state.
  4504. // To exit FINE state we need the CONCLUSION message with HSRSP.
  4505. HLOGC(cnlog.Debug,
  4506. log << CONID()
  4507. << "rendezvousSwitchState: {INITIATOR}[FINE] <CONCLUSION without HSRSP. Stay in [FINE], "
  4508. "await CONCLUSION+HSRSP");
  4509. }
  4510. else if (hsd == HSD_RESPONDER)
  4511. {
  4512. // In FINE state the RESPONDER expects only to be sent AGREEMENT.
  4513. // It has previously received CONCLUSION in WAVING state and this has switched
  4514. // it to FINE state. That CONCLUSION message should have contained extension,
  4515. // so if this is a repeated CONCLUSION+HSREQ, it should be responded with
  4516. // CONCLUSION+HSRSP.
  4517. HLOGC(cnlog.Debug,
  4518. log << CONID()
  4519. << "rendezvousSwitchState: {RESPONDER}[FINE] <CONCLUSION. Stay in [FINE], await AGREEMENT");
  4520. }
  4521. else
  4522. {
  4523. correct_switch = true;
  4524. }
  4525. if (!correct_switch)
  4526. {
  4527. w_rsptype = URQ_CONCLUSION;
  4528. // initiator should send HSREQ, responder HSRSP,
  4529. // in both cases extension is needed
  4530. w_needs_extension = true;
  4531. w_needs_hsrsp = hsd == HSD_RESPONDER;
  4532. return;
  4533. }
  4534. m_RdvState = CHandShake::RDV_CONNECTED;
  4535. w_rsptype = URQ_AGREEMENT;
  4536. return;
  4537. }
  4538. if (req == URQ_AGREEMENT)
  4539. {
  4540. // The loser case, the agreement was sent in response to conclusion that
  4541. // already carried over the HSRSP extension.
  4542. // There's a theoretical case when URQ_AGREEMENT can be received in case of
  4543. // parallel arrangement, while the agent is already in CHandShake::RDV_CONNECTED state.
  4544. // This will be dispatched in the main loop and discarded.
  4545. m_RdvState = CHandShake::RDV_CONNECTED;
  4546. w_rsptype = URQ_DONE;
  4547. return;
  4548. }
  4549. }
  4550. reason = "FINE -> CONCLUSION(agreement), AGREEMENT(done)";
  4551. break;
  4552. case CHandShake::RDV_INITIATED:
  4553. {
  4554. // In this state we just wait for URQ_AGREEMENT, which should cause it to
  4555. // switch to CONNECTED. No response required.
  4556. if (req == URQ_AGREEMENT)
  4557. {
  4558. // No matter in which state we'd be, just switch to connected.
  4559. if (m_RdvState == CHandShake::RDV_CONNECTED)
  4560. {
  4561. HLOGC(cnlog.Debug, log << CONID() << "<-- AGREEMENT: already connected");
  4562. }
  4563. else
  4564. {
  4565. HLOGC(cnlog.Debug, log << CONID() << "<-- AGREEMENT: switched to connected");
  4566. }
  4567. m_RdvState = CHandShake::RDV_CONNECTED;
  4568. w_rsptype = URQ_DONE;
  4569. return;
  4570. }
  4571. if (req == URQ_CONCLUSION)
  4572. {
  4573. // Receiving conclusion in this state means that the other party
  4574. // didn't get our conclusion, so send it again, the same as when
  4575. // exiting the ATTENTION state.
  4576. w_rsptype = URQ_CONCLUSION;
  4577. if (hsd == HSD_RESPONDER)
  4578. {
  4579. HLOGC(cnlog.Debug,
  4580. log << CONID()
  4581. << "rendezvousSwitchState: {RESPONDER}[INITIATED] awaits AGREEMENT, "
  4582. "got CONCLUSION, sending CONCLUSION+HSRSP");
  4583. w_needs_extension = true;
  4584. w_needs_hsrsp = true;
  4585. return;
  4586. }
  4587. // Loser, initiated? This may only happen in parallel arrangement, where
  4588. // the agent exchanges empty conclusion messages with the peer, simultaneously
  4589. // exchanging HSREQ-HSRSP conclusion messages. Check if THIS message contained
  4590. // HSREQ, and set responding HSRSP in that case.
  4591. if (hs_flags == 0)
  4592. {
  4593. HLOGC(cnlog.Debug,
  4594. log << CONID()
  4595. << "rendezvousSwitchState: {INITIATOR}[INITIATED] awaits AGREEMENT, "
  4596. "got empty CONCLUSION, STILL RESPONDING CONCLUSION+HSRSP");
  4597. }
  4598. else
  4599. {
  4600. HLOGC(cnlog.Debug,
  4601. log << CONID()
  4602. << "rendezvousSwitchState: {INITIATOR}[INITIATED] awaits AGREEMENT, "
  4603. "got CONCLUSION+HSREQ, responding CONCLUSION+HSRSP");
  4604. }
  4605. w_needs_extension = true;
  4606. w_needs_hsrsp = true;
  4607. return;
  4608. }
  4609. }
  4610. reason = "INITIATED -> AGREEMENT(done)";
  4611. break;
  4612. case CHandShake::RDV_CONNECTED:
  4613. // Do nothing. This theoretically should never happen.
  4614. w_rsptype = URQ_DONE;
  4615. return;
  4616. }
  4617. HLOGC(cnlog.Debug, log << CONID() << "rendezvousSwitchState: INVALID STATE TRANSITION, result: INVALID");
  4618. // All others are treated as errors
  4619. m_RdvState = CHandShake::RDV_WAVING;
  4620. w_rsptype = URQFailure(SRT_REJ_ROGUE);
  4621. }
  4622. /*
  4623. * Timestamp-based Packet Delivery (TsbPd) thread
  4624. * This thread runs only if TsbPd mode is enabled
  4625. * Hold received packets until its time to 'play' them, at PktTimeStamp + TsbPdDelay.
  4626. */
  4627. void * srt::CUDT::tsbpd(void* param)
  4628. {
  4629. CUDT* self = (CUDT*)param;
  4630. THREAD_STATE_INIT("SRT:TsbPd");
  4631. #if ENABLE_BONDING
  4632. // Make the TSBPD thread a "client" of the group,
  4633. // which will ensure that the group will not be physically
  4634. // deleted until this thread exits.
  4635. // NOTE: DO NOT LEAD TO EVER CANCEL THE THREAD!!!
  4636. CUDTUnited::GroupKeeper gkeeper(self->uglobal(), self->m_parent);
  4637. #endif
  4638. CUniqueSync recvdata_lcc (self->m_RecvLock, self->m_RecvDataCond);
  4639. CSync tsbpd_cc(self->m_RcvTsbPdCond, recvdata_lcc.locker());
  4640. self->m_bTsbPdAckWakeup = true;
  4641. while (!self->m_bClosing)
  4642. {
  4643. steady_clock::time_point tsNextDelivery; // Next packet delivery time
  4644. bool rxready = false;
  4645. #if ENABLE_BONDING
  4646. bool shall_update_group = false;
  4647. #endif
  4648. INCREMENT_THREAD_ITERATIONS();
  4649. enterCS(self->m_RcvBufferLock);
  4650. const steady_clock::time_point tnow = steady_clock::now();
  4651. self->m_pRcvBuffer->updRcvAvgDataSize(tnow);
  4652. const srt::CRcvBuffer::PacketInfo info = self->m_pRcvBuffer->getFirstValidPacketInfo();
  4653. const bool is_time_to_deliver = !is_zero(info.tsbpd_time) && (tnow >= info.tsbpd_time);
  4654. tsNextDelivery = info.tsbpd_time;
  4655. if (!self->m_bTLPktDrop)
  4656. {
  4657. rxready = !info.seq_gap && is_time_to_deliver;
  4658. }
  4659. else if (is_time_to_deliver)
  4660. {
  4661. rxready = true;
  4662. if (info.seq_gap)
  4663. {
  4664. const int iDropCnt SRT_ATR_UNUSED = self->rcvDropTooLateUpTo(info.seqno);
  4665. #if ENABLE_BONDING
  4666. shall_update_group = true;
  4667. #endif
  4668. #if ENABLE_LOGGING
  4669. const int64_t timediff_us = count_microseconds(tnow - info.tsbpd_time);
  4670. #if ENABLE_HEAVY_LOGGING
  4671. HLOGC(tslog.Debug,
  4672. log << self->CONID() << "tsbpd: DROPSEQ: up to seqno %" << CSeqNo::decseq(info.seqno) << " ("
  4673. << iDropCnt << " packets) playable at " << FormatTime(info.tsbpd_time) << " delayed "
  4674. << (timediff_us / 1000) << "." << std::setw(3) << std::setfill('0') << (timediff_us % 1000) << " ms");
  4675. #endif
  4676. LOGC(brlog.Warn, log << self->CONID() << "RCV-DROPPED " << iDropCnt << " packet(s). Packet seqno %" << info.seqno
  4677. << " delayed for " << (timediff_us / 1000) << "." << std::setw(3) << std::setfill('0')
  4678. << (timediff_us % 1000) << " ms");
  4679. #endif
  4680. tsNextDelivery = steady_clock::time_point(); // Ready to read, nothing to wait for.
  4681. }
  4682. }
  4683. leaveCS(self->m_RcvBufferLock);
  4684. if (rxready)
  4685. {
  4686. HLOGC(tslog.Debug,
  4687. log << self->CONID() << "tsbpd: PLAYING PACKET seq=" << info.seqno << " (belated "
  4688. << (count_milliseconds(steady_clock::now() - info.tsbpd_time)) << "ms)");
  4689. /*
  4690. * There are packets ready to be delivered
  4691. * signal a waiting "recv" call if there is any data available
  4692. */
  4693. if (self->m_config.bSynRecving)
  4694. {
  4695. recvdata_lcc.notify_one();
  4696. }
  4697. /*
  4698. * Set EPOLL_IN to wakeup any thread waiting on epoll
  4699. */
  4700. self->uglobal().m_EPoll.update_events(self->m_SocketID, self->m_sPollID, SRT_EPOLL_IN, true);
  4701. #if ENABLE_BONDING
  4702. // If this is NULL, it means:
  4703. // - the socket never was a group member
  4704. // - the socket was a group member, but:
  4705. // - was just removed as a part of closure
  4706. // - and will never be member of the group anymore
  4707. // If this is not NULL, it means:
  4708. // - This socket is currently member of the group
  4709. // - This socket WAS a member of the group, though possibly removed from it already, BUT:
  4710. // - the group that this socket IS OR WAS member of is in the GroupKeeper
  4711. // - the GroupKeeper prevents the group from being deleted
  4712. // - it is then completely safe to access the group here,
  4713. // EVEN IF THE SOCKET THAT WAS ITS MEMBER IS BEING DELETED.
  4714. // It is ensured that the group object exists here because GroupKeeper
  4715. // keeps it busy, even if you just closed the socket, remove it as a member
  4716. // or even the group is empty and was explicitly closed.
  4717. if (gkeeper.group)
  4718. {
  4719. // Functions called below will lock m_GroupLock, which in hierarchy
  4720. // lies after m_RecvLock. Must unlock m_RecvLock to be able to lock
  4721. // m_GroupLock inside the calls.
  4722. InvertedLock unrecv(self->m_RecvLock);
  4723. // The current "APP reader" needs to simply decide as to whether
  4724. // the next CUDTGroup::recv() call should return with no blocking or not.
  4725. // When the group is read-ready, it should update its pollers as it sees fit.
  4726. // NOTE: this call will set lock to m_IncludedGroup->m_GroupLock
  4727. HLOGC(tslog.Debug, log << self->CONID() << "tsbpd: GROUP: checking if %" << info.seqno << " makes group readable");
  4728. gkeeper.group->updateReadState(self->m_SocketID, info.seqno);
  4729. if (shall_update_group)
  4730. {
  4731. // A group may need to update the parallelly used idle links,
  4732. // should it have any. Pass the current socket position in order
  4733. // to skip it from the group loop.
  4734. // NOTE: SELF LOCKING.
  4735. gkeeper.group->updateLatestRcv(self->m_parent);
  4736. }
  4737. }
  4738. #endif
  4739. CGlobEvent::triggerEvent();
  4740. tsNextDelivery = steady_clock::time_point(); // Ready to read, nothing to wait for.
  4741. }
  4742. // We may just briefly unlocked the m_RecvLock, so we need to check m_bClosing again to avoid deadlock.
  4743. if (self->m_bClosing)
  4744. break;
  4745. if (!is_zero(tsNextDelivery))
  4746. {
  4747. IF_HEAVY_LOGGING(const steady_clock::duration timediff = tsNextDelivery - tnow);
  4748. /*
  4749. * Buffer at head of queue is not ready to play.
  4750. * Schedule wakeup when it will be.
  4751. */
  4752. self->m_bTsbPdAckWakeup = false;
  4753. HLOGC(tslog.Debug,
  4754. log << self->CONID() << "tsbpd: FUTURE PACKET seq=" << info.seqno
  4755. << " T=" << FormatTime(tsNextDelivery) << " - waiting " << count_milliseconds(timediff) << "ms");
  4756. THREAD_PAUSED();
  4757. tsbpd_cc.wait_until(tsNextDelivery);
  4758. THREAD_RESUMED();
  4759. }
  4760. else
  4761. {
  4762. /*
  4763. * We have just signaled epoll; or
  4764. * receive queue is empty; or
  4765. * next buffer to deliver is not in receive queue (missing packet in sequence).
  4766. *
  4767. * Block until woken up by one of the following event:
  4768. * - All ready-to-play packets have been pulled and EPOLL_IN cleared (then loop to block until next pkt time
  4769. * if any)
  4770. * - New buffers ACKed
  4771. * - Closing the connection
  4772. */
  4773. HLOGC(tslog.Debug, log << self->CONID() << "tsbpd: no data, scheduling wakeup at ack");
  4774. self->m_bTsbPdAckWakeup = true;
  4775. THREAD_PAUSED();
  4776. tsbpd_cc.wait();
  4777. THREAD_RESUMED();
  4778. }
  4779. HLOGC(tslog.Debug, log << self->CONID() << "tsbpd: WAKE UP!!!");
  4780. }
  4781. THREAD_EXIT();
  4782. HLOGC(tslog.Debug, log << self->CONID() << "tsbpd: EXITING");
  4783. return NULL;
  4784. }
  4785. int srt::CUDT::rcvDropTooLateUpTo(int seqno)
  4786. {
  4787. // Make sure that it would not drop over m_iRcvCurrSeqNo, which may break senders.
  4788. if (CSeqNo::seqcmp(seqno, CSeqNo::incseq(m_iRcvCurrSeqNo)) > 0)
  4789. seqno = CSeqNo::incseq(m_iRcvCurrSeqNo);
  4790. dropFromLossLists(SRT_SEQNO_NONE, CSeqNo::decseq(seqno));
  4791. const int iDropCnt = m_pRcvBuffer->dropUpTo(seqno);
  4792. if (iDropCnt > 0)
  4793. {
  4794. enterCS(m_StatsLock);
  4795. // Estimate dropped bytes from average payload size.
  4796. const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize();
  4797. m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt));
  4798. leaveCS(m_StatsLock);
  4799. }
  4800. return iDropCnt;
  4801. }
  4802. void srt::CUDT::setInitialRcvSeq(int32_t isn)
  4803. {
  4804. m_iRcvLastAck = isn;
  4805. #ifdef ENABLE_LOGGING
  4806. m_iDebugPrevLastAck = isn;
  4807. #endif
  4808. m_iRcvLastAckAck = isn;
  4809. m_iRcvCurrSeqNo = CSeqNo::decseq(isn);
  4810. sync::ScopedLock rb(m_RcvBufferLock);
  4811. if (m_pRcvBuffer)
  4812. {
  4813. if (!m_pRcvBuffer->empty())
  4814. {
  4815. LOGC(cnlog.Error, log << CONID() << "IPE: setInitialRcvSeq expected empty RCV buffer. Dropping all.");
  4816. const int iDropCnt = m_pRcvBuffer->dropAll();
  4817. const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize();
  4818. sync::ScopedLock sl(m_StatsLock);
  4819. m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt));
  4820. }
  4821. m_pRcvBuffer->setStartSeqNo(isn);
  4822. }
  4823. }
  4824. bool srt::CUDT::prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout)
  4825. {
  4826. // This will be lazily created due to being the common
  4827. // code with HSv5 rendezvous, in which this will be run
  4828. // in a little bit "randomly selected" moment, but must
  4829. // be run once in the whole connection process.
  4830. if (m_pCryptoControl)
  4831. {
  4832. HLOGC(rslog.Debug, log << CONID() << "prepareConnectionObjects: (lazy) already created.");
  4833. return true;
  4834. }
  4835. // HSv5 is always bidirectional
  4836. const bool bidirectional = (hs.m_iVersion > HS_VERSION_UDT4);
  4837. // HSD_DRAW is received only if this side is listener.
  4838. // If this side is caller with HSv5, HSD_INITIATOR should be passed.
  4839. // If this is a rendezvous connection with HSv5, the handshake role
  4840. // is taken from m_SrtHsSide field.
  4841. if (hsd == HSD_DRAW)
  4842. {
  4843. if (bidirectional)
  4844. {
  4845. hsd = HSD_RESPONDER; // In HSv5, listener is always RESPONDER and caller always INITIATOR.
  4846. }
  4847. else
  4848. {
  4849. hsd = m_config.bDataSender ? HSD_INITIATOR : HSD_RESPONDER;
  4850. }
  4851. }
  4852. if (!createCrypter(hsd, bidirectional)) // Make sure CC is created (lazy)
  4853. {
  4854. if (eout)
  4855. *eout = CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
  4856. m_RejectReason = SRT_REJ_RESOURCE;
  4857. return false;
  4858. }
  4859. return true;
  4860. }
  4861. bool srt::CUDT::prepareBuffers(CUDTException* eout)
  4862. {
  4863. if (m_pSndBuffer)
  4864. {
  4865. HLOGC(rslog.Debug, log << CONID() << "prepareBuffers: (lazy) already created.");
  4866. return true;
  4867. }
  4868. try
  4869. {
  4870. // CryptoControl has to be initialized and in case of RESPONDER the KM REQ must be processed (interpretSrtHandshake(..)) for the crypto mode to be deduced.
  4871. const int authtag = (m_pCryptoControl && m_pCryptoControl->getCryptoMode() == CSrtConfig::CIPHER_MODE_AES_GCM) ? HAICRYPT_AUTHTAG_MAX : 0;
  4872. m_pSndBuffer = new CSndBuffer(32, m_iMaxSRTPayloadSize, authtag);
  4873. SRT_ASSERT(m_iPeerISN != -1);
  4874. m_pRcvBuffer = new srt::CRcvBuffer(m_iPeerISN, m_config.iRcvBufSize, m_pRcvQueue->m_pUnitQueue, m_config.bMessageAPI);
  4875. // After introducing lite ACK, the sndlosslist may not be cleared in time, so it requires twice a space.
  4876. m_pSndLossList = new CSndLossList(m_iFlowWindowSize * 2);
  4877. m_pRcvLossList = new CRcvLossList(m_config.iFlightFlagSize);
  4878. }
  4879. catch (...)
  4880. {
  4881. // Simply reject.
  4882. if (eout)
  4883. *eout = CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
  4884. m_RejectReason = SRT_REJ_RESOURCE;
  4885. return false;
  4886. }
  4887. return true;
  4888. }
  4889. void srt::CUDT::rewriteHandshakeData(const sockaddr_any& peer, CHandShake& w_hs)
  4890. {
  4891. // this is a response handshake
  4892. w_hs.m_iReqType = URQ_CONCLUSION;
  4893. w_hs.m_iMSS = m_config.iMSS;
  4894. w_hs.m_iFlightFlagSize = m_config.flightCapacity();
  4895. w_hs.m_iID = m_SocketID;
  4896. if (w_hs.m_iVersion > HS_VERSION_UDT4)
  4897. {
  4898. // The version is agreed; this code is executed only in case
  4899. // when AGENT is listener. In this case, conclusion response
  4900. // must always contain HSv5 handshake extensions.
  4901. w_hs.m_extension = true;
  4902. }
  4903. CIPAddress::ntop(peer, (w_hs.m_piPeerIP));
  4904. }
  4905. void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& peer, const CPacket& hspkt, CHandShake& w_hs)
  4906. {
  4907. HLOGC(cnlog.Debug, log << CONID() << "acceptAndRespond: setting up data according to handshake");
  4908. ScopedLock cg(m_ConnectionLock);
  4909. m_tsRcvPeerStartTime = steady_clock::time_point(); // will be set correctly at SRT HS
  4910. // Uses the smaller MSS between the peers
  4911. m_config.iMSS = std::min(m_config.iMSS, w_hs.m_iMSS);
  4912. // exchange info for maximum flow window size
  4913. m_iFlowWindowSize = w_hs.m_iFlightFlagSize;
  4914. m_iPeerISN = w_hs.m_iISN;
  4915. setInitialRcvSeq(m_iPeerISN);
  4916. m_iRcvCurrPhySeqNo = CSeqNo::decseq(w_hs.m_iISN);
  4917. m_PeerID = w_hs.m_iID;
  4918. // use peer's ISN and send it back for security check
  4919. m_iISN = w_hs.m_iISN;
  4920. setInitialSndSeq(m_iISN);
  4921. m_SndLastAck2Time = steady_clock::now();
  4922. // get local IP address and send the peer its IP address (because UDP cannot get local IP address)
  4923. memcpy((m_piSelfIP), w_hs.m_piPeerIP, sizeof m_piSelfIP);
  4924. m_parent->m_SelfAddr = agent;
  4925. CIPAddress::pton((m_parent->m_SelfAddr), m_piSelfIP, peer);
  4926. rewriteHandshakeData(peer, (w_hs));
  4927. int udpsize = m_config.iMSS - CPacket::UDP_HDR_SIZE;
  4928. m_iMaxSRTPayloadSize = udpsize - CPacket::HDR_SIZE;
  4929. HLOGC(cnlog.Debug, log << CONID() << "acceptAndRespond: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize);
  4930. // Prepare all structures
  4931. if (!prepareConnectionObjects(w_hs, HSD_DRAW, 0))
  4932. {
  4933. HLOGC(cnlog.Debug,
  4934. log << CONID() << "acceptAndRespond: prepareConnectionObjects failed - responding with REJECT.");
  4935. // If the SRT Handshake extension was provided and wasn't interpreted
  4936. // correctly, the connection should be rejected.
  4937. //
  4938. // Respond with the rejection message and exit with exception
  4939. // so that the caller will know that this new socket should be deleted.
  4940. w_hs.m_iReqType = URQFailure(m_RejectReason);
  4941. throw CUDTException(MJ_SETUP, MN_REJECTED, 0);
  4942. }
  4943. // Since now you can use m_pCryptoControl
  4944. CInfoBlock ib;
  4945. ib.m_iIPversion = peer.family();
  4946. CInfoBlock::convert(peer, ib.m_piIP);
  4947. if (m_pCache->lookup(&ib) >= 0)
  4948. {
  4949. m_iSRTT = ib.m_iSRTT;
  4950. m_iRTTVar = ib.m_iSRTT / 2;
  4951. m_iBandwidth = ib.m_iBandwidth;
  4952. }
  4953. #if SRT_DEBUG_RTT
  4954. s_rtt_trace.trace(steady_clock::now(), "Accept", -1, -1,
  4955. m_bIsFirstRTTReceived, -1, m_iSRTT, m_iRTTVar);
  4956. #endif
  4957. m_PeerAddr = peer;
  4958. // This should extract the HSREQ and KMREQ portion in the handshake packet.
  4959. // This could still be a HSv4 packet and contain no such parts, which will leave
  4960. // this entity as "non-SRT-handshaken", and await further HSREQ and KMREQ sent
  4961. // as UMSG_EXT.
  4962. uint32_t kmdata[SRTDATA_MAXSIZE];
  4963. size_t kmdatasize = SRTDATA_MAXSIZE;
  4964. if (!interpretSrtHandshake(w_hs, hspkt, (kmdata), (&kmdatasize)))
  4965. {
  4966. HLOGC(cnlog.Debug,
  4967. log << CONID() << "acceptAndRespond: interpretSrtHandshake failed - responding with REJECT.");
  4968. // If the SRT Handshake extension was provided and wasn't interpreted
  4969. // correctly, the connection should be rejected.
  4970. //
  4971. // Respond with the rejection message and return false from
  4972. // this function so that the caller will know that this new
  4973. // socket should be deleted.
  4974. w_hs.m_iReqType = URQFailure(m_RejectReason);
  4975. throw CUDTException(MJ_SETUP, MN_REJECTED, 0);
  4976. }
  4977. if (!prepareBuffers(NULL))
  4978. {
  4979. HLOGC(cnlog.Debug,
  4980. log << CONID() << "acceptAndRespond: prepareConnectionObjects failed - responding with REJECT.");
  4981. // If the SRT buffers failed to be allocated,
  4982. // the connection must be rejected.
  4983. //
  4984. // Respond with the rejection message and exit with exception
  4985. // so that the caller will know that this new socket should be deleted.
  4986. w_hs.m_iReqType = URQFailure(m_RejectReason);
  4987. throw CUDTException(MJ_SETUP, MN_REJECTED, 0);
  4988. }
  4989. // Synchronize the time NOW because the following function is about
  4990. // to use the start time to pass it to the receiver buffer data.
  4991. bool have_group = false;
  4992. {
  4993. #if ENABLE_BONDING
  4994. ScopedLock cl (uglobal().m_GlobControlLock);
  4995. CUDTGroup* g = m_parent->m_GroupOf;
  4996. if (g)
  4997. {
  4998. // This is the last moment when this can be done.
  4999. // The updateAfterSrtHandshake call will copy the receiver
  5000. // start time to the receiver buffer data, so the correct
  5001. // value must be set before this happens.
  5002. synchronizeWithGroup(g);
  5003. have_group = true;
  5004. }
  5005. #endif
  5006. }
  5007. if (!have_group)
  5008. {
  5009. // This function will be called internally inside
  5010. // synchronizeWithGroup(). This is just more complicated.
  5011. updateAfterSrtHandshake(w_hs.m_iVersion);
  5012. }
  5013. SRT_REJECT_REASON rr = setupCC();
  5014. // UNKNOWN used as a "no error" value
  5015. if (rr != SRT_REJ_UNKNOWN)
  5016. {
  5017. w_hs.m_iReqType = URQFailure(rr);
  5018. m_RejectReason = rr;
  5019. throw CUDTException(MJ_SETUP, MN_REJECTED, 0);
  5020. }
  5021. // And of course, it is connected.
  5022. m_bConnected = true;
  5023. // Register this socket for receiving data packets.
  5024. m_pRNode->m_bOnList = true;
  5025. m_pRcvQueue->setNewEntry(this);
  5026. // Save the handshake in m_ConnRes in case when needs repeating.
  5027. m_ConnRes = w_hs;
  5028. // Send the response to the peer, see listen() for more discussions
  5029. // about this.
  5030. // TODO: Here create CONCLUSION RESPONSE with:
  5031. // - just the UDT handshake, if HS_VERSION_UDT4,
  5032. // - if higher, the UDT handshake, the SRT HSRSP, the SRT KMRSP.
  5033. size_t size = m_iMaxSRTPayloadSize;
  5034. // Allocate the maximum possible memory for an SRT payload.
  5035. // This is a maximum you can send once.
  5036. CPacket response;
  5037. response.setControl(UMSG_HANDSHAKE);
  5038. response.allocate(size);
  5039. // This will serialize the handshake according to its current form.
  5040. HLOGC(cnlog.Debug,
  5041. log << CONID()
  5042. << "acceptAndRespond: creating CONCLUSION response (HSv5: with HSRSP/KMRSP) buffer size=" << size);
  5043. if (!createSrtHandshake(SRT_CMD_HSRSP, SRT_CMD_KMRSP, kmdata, kmdatasize, (response), (w_hs)))
  5044. {
  5045. LOGC(cnlog.Error, log << CONID() << "acceptAndRespond: error creating handshake response");
  5046. throw CUDTException(MJ_SETUP, MN_REJECTED, 0);
  5047. }
  5048. // We can safely assign it here stating that this has passed the cookie test.
  5049. m_SourceAddr = hspkt.udpDestAddr();
  5050. #if ENABLE_HEAVY_LOGGING
  5051. {
  5052. // To make sure what REALLY is being sent, parse back the handshake
  5053. // data that have been just written into the buffer.
  5054. CHandShake debughs;
  5055. debughs.load_from(response.m_pcData, response.getLength());
  5056. HLOGC(cnlog.Debug,
  5057. log << CONID() << "acceptAndRespond: sending HS from agent @"
  5058. << debughs.m_iID << " to peer @" << response.m_iID
  5059. << "HS:" << debughs.show()
  5060. << " sourceIP=" << m_SourceAddr.str());
  5061. }
  5062. #endif
  5063. // NOTE: BLOCK THIS instruction in order to cause the final
  5064. // handshake to be missed and cause the problem solved in PR #417.
  5065. // When missed this message, the caller should not accept packets
  5066. // coming as connected, but continue repeated handshake until finally
  5067. // received the listener's handshake.
  5068. addressAndSend((response));
  5069. }
  5070. bool srt::CUDT::frequentLogAllowed(const time_point& tnow) const
  5071. {
  5072. #ifndef SRT_LOG_SLOWDOWN_FREQ_MS
  5073. #define SRT_LOG_SLOWDOWN_FREQ_MS 1000
  5074. #endif
  5075. return (m_tsLogSlowDown + milliseconds_from(SRT_LOG_SLOWDOWN_FREQ_MS)) <= tnow;
  5076. }
  5077. // This function is required to be called when a caller receives an INDUCTION
  5078. // response from the listener and would like to create a CONCLUSION that includes
  5079. // the SRT handshake extension. This extension requires that the crypter object
  5080. // be created, but it's still too early for it to be completely configured.
  5081. // This function then precreates the object so that the handshake extension can
  5082. // be created, as this happens before the completion of the connection (and
  5083. // therefore configuration of the crypter object), which can only take place upon
  5084. // reception of CONCLUSION response from the listener.
  5085. bool srt::CUDT::createCrypter(HandshakeSide side, bool bidirectional)
  5086. {
  5087. // Lazy initialization
  5088. if (m_pCryptoControl)
  5089. return true;
  5090. // Write back this value, when it was just determined.
  5091. m_SrtHsSide = side;
  5092. m_pCryptoControl.reset(new CCryptoControl(m_SocketID));
  5093. // XXX These below are a little bit controversial.
  5094. // These data should probably be filled only upon
  5095. // reception of the conclusion handshake - otherwise
  5096. // they have outdated values.
  5097. m_pCryptoControl->setCryptoSecret(m_config.CryptoSecret);
  5098. if (bidirectional || m_config.bDataSender)
  5099. {
  5100. HLOGC(rslog.Debug, log << CONID() << "createCrypter: setting RCV/SND KeyLen=" << m_config.iSndCryptoKeyLen);
  5101. m_pCryptoControl->setCryptoKeylen(m_config.iSndCryptoKeyLen);
  5102. }
  5103. return m_pCryptoControl->init(side, m_config, bidirectional);
  5104. }
  5105. SRT_REJECT_REASON srt::CUDT::setupCC()
  5106. {
  5107. // Prepare configuration object,
  5108. // Create the CCC object and configure it.
  5109. // UDT also sets back the congestion window: ???
  5110. // m_dCongestionWindow = m_pCC->m_dCWndSize;
  5111. // XXX Not sure about that. May happen that AGENT wants
  5112. // tsbpd mode, but PEER doesn't, even in bidirectional mode.
  5113. // This way, the reception side should get precedense.
  5114. // if (bidirectional || m_config.bDataSender || m_bTwoWayData)
  5115. // m_bPeerTsbPd = m_bTSBPD;
  5116. // SrtCongestion will retrieve whatever parameters it needs
  5117. // from *this.
  5118. bool res = m_CongCtl.select(m_config.sCongestion.str());
  5119. if (!res || !m_CongCtl.configure(this))
  5120. {
  5121. return SRT_REJ_CONGESTION;
  5122. }
  5123. // Configure filter module
  5124. if (!m_config.sPacketFilterConfig.empty())
  5125. {
  5126. // This string, when nonempty, defines that the corrector shall be
  5127. // configured. Otherwise it's left uninitialized.
  5128. // At this point we state everything is checked and the appropriate
  5129. // corrector type is already selected, so now create it.
  5130. HLOGC(pflog.Debug, log << CONID() << "filter: Configuring: " << m_config.sPacketFilterConfig.c_str());
  5131. bool status = true;
  5132. try
  5133. {
  5134. // The filter configurer is build the way that allows to quit immediately
  5135. // exit by exception, but the exception is meant for the filter only.
  5136. status = m_PacketFilter.configure(this, m_pRcvQueue->m_pUnitQueue, m_config.sPacketFilterConfig.str());
  5137. }
  5138. catch (CUDTException& )
  5139. {
  5140. status = false;
  5141. }
  5142. if (!status)
  5143. return SRT_REJ_FILTER;
  5144. m_PktFilterRexmitLevel = m_PacketFilter.arqLevel();
  5145. }
  5146. else
  5147. {
  5148. // When we have no filter, ARQ should work in ALWAYS mode.
  5149. m_PktFilterRexmitLevel = SRT_ARQ_ALWAYS;
  5150. }
  5151. // Override the value of minimum NAK interval, per SrtCongestion's wish.
  5152. // When default 0 value is returned, the current value set by CUDT
  5153. // is preserved.
  5154. const steady_clock::duration min_nak = microseconds_from(m_CongCtl->minNAKInterval());
  5155. if (min_nak != steady_clock::duration::zero())
  5156. m_tdMinNakInterval = min_nak;
  5157. // Update timers
  5158. const steady_clock::time_point currtime = steady_clock::now();
  5159. m_tsLastRspTime.store(currtime);
  5160. m_tsNextACKTime.store(currtime + m_tdACKInterval);
  5161. m_tsNextNAKTime.store(currtime + m_tdNAKInterval);
  5162. m_tsLastRspAckTime = currtime;
  5163. m_tsLastSndTime.store(currtime);
  5164. HLOGC(rslog.Debug,
  5165. log << CONID() << "setupCC: setting parameters: mss=" << m_config.iMSS << " maxCWNDSize/FlowWindowSize="
  5166. << m_iFlowWindowSize << " rcvrate=" << m_iDeliveryRate << "p/s (" << m_iByteDeliveryRate << "B/S)"
  5167. << " rtt=" << m_iSRTT << " bw=" << m_iBandwidth);
  5168. if (!updateCC(TEV_INIT, EventVariant(TEV_INIT_RESET)))
  5169. {
  5170. LOGC(rslog.Error, log << CONID() << "setupCC: IPE: resrouces not yet initialized!");
  5171. return SRT_REJ_IPE;
  5172. }
  5173. return SRT_REJ_UNKNOWN;
  5174. }
  5175. void srt::CUDT::considerLegacySrtHandshake(const steady_clock::time_point &timebase)
  5176. {
  5177. // Do a fast pre-check first - this simply declares that agent uses HSv5
  5178. // and the legacy SRT Handshake is not to be done. Second check is whether
  5179. // agent is sender (=initiator in HSv4).
  5180. if (!isOPT_TsbPd() || !m_config.bDataSender)
  5181. return;
  5182. if (m_iSndHsRetryCnt <= 0)
  5183. {
  5184. HLOGC(cnlog.Debug, log << CONID() << "Legacy HSREQ: not needed, expire counter=" << m_iSndHsRetryCnt);
  5185. return;
  5186. }
  5187. const steady_clock::time_point now = steady_clock::now();
  5188. if (!is_zero(timebase))
  5189. {
  5190. // Then this should be done only if it's the right time,
  5191. // the TSBPD mode is on, and when the counter is "still rolling".
  5192. /*
  5193. * SRT Handshake with peer:
  5194. * If...
  5195. * - we want TsbPd mode; and
  5196. * - we have not tried more than CSRTCC_MAXRETRY times (peer may not be SRT); and
  5197. * - and did not get answer back from peer
  5198. * - last sent handshake req should have been replied (RTT*1.5 elapsed); and
  5199. * then (re-)send handshake request.
  5200. */
  5201. if (timebase > now) // too early
  5202. {
  5203. HLOGC(cnlog.Debug,
  5204. log << CONID() << "Legacy HSREQ: TOO EARLY, will still retry " << m_iSndHsRetryCnt << " times");
  5205. return;
  5206. }
  5207. }
  5208. // If 0 timebase, it means that this is the initial sending with the very first
  5209. // payload packet sent. Send only if this is still set to maximum+1 value.
  5210. else if (m_iSndHsRetryCnt < SRT_MAX_HSRETRY + 1)
  5211. {
  5212. HLOGC(cnlog.Debug,
  5213. log << CONID() << "Legacy HSREQ: INITIAL, REPEATED, so not to be done. Will repeat on sending "
  5214. << m_iSndHsRetryCnt << " times");
  5215. return;
  5216. }
  5217. HLOGC(cnlog.Debug,
  5218. log << CONID() << "Legacy HSREQ: SENDING, will repeat " << m_iSndHsRetryCnt << " times if no response");
  5219. m_iSndHsRetryCnt--;
  5220. m_tsSndHsLastTime = now;
  5221. sendSrtMsg(SRT_CMD_HSREQ);
  5222. }
  5223. void srt::CUDT::checkSndTimers()
  5224. {
  5225. if (m_SrtHsSide == HSD_INITIATOR)
  5226. {
  5227. HLOGC(cnlog.Debug,
  5228. log << CONID() << "checkSndTimers: HS SIDE: INITIATOR, considering legacy handshake with timebase");
  5229. // Legacy method for HSREQ, only if initiator.
  5230. considerLegacySrtHandshake(m_tsSndHsLastTime + microseconds_from(m_iSRTT * 3 / 2));
  5231. }
  5232. else
  5233. {
  5234. HLOGC(cnlog.Debug,
  5235. log << CONID()
  5236. << "checkSndTimers: HS SIDE: " << (m_SrtHsSide == HSD_RESPONDER ? "RESPONDER" : "DRAW (IPE?)")
  5237. << " - not considering legacy handshake");
  5238. }
  5239. // Retransmit KM request after a timeout if there is no response (KM RSP).
  5240. // Or send KM REQ in case of the HSv4.
  5241. ScopedLock lck(m_ConnectionLock);
  5242. if (m_pCryptoControl)
  5243. m_pCryptoControl->sendKeysToPeer(this, SRTT());
  5244. }
  5245. void srt::CUDT::checkSndKMRefresh()
  5246. {
  5247. // Do not apply the regenerated key to the to the receiver context.
  5248. const bool bidir = false;
  5249. if (m_pCryptoControl)
  5250. m_pCryptoControl->regenCryptoKm(this, bidir);
  5251. }
  5252. void srt::CUDT::addressAndSend(CPacket& w_pkt)
  5253. {
  5254. w_pkt.m_iID = m_PeerID;
  5255. setPacketTS(w_pkt, steady_clock::now());
  5256. // NOTE: w_pkt isn't modified in this call,
  5257. // just in CChannel::sendto it's modified in place
  5258. // before sending for performance purposes,
  5259. // and then modification is undone. Logically then
  5260. // there's no modification here.
  5261. m_pSndQueue->sendto(m_PeerAddr, w_pkt, m_SourceAddr);
  5262. }
  5263. // [[using maybe_locked(m_GlobControlLock, if called from GC)]]
  5264. bool srt::CUDT::closeInternal()
  5265. {
  5266. // NOTE: this function is called from within the garbage collector thread.
  5267. if (!m_bOpened)
  5268. {
  5269. return false;
  5270. }
  5271. // IMPORTANT:
  5272. // This function may block indefinitely, if called for a socket
  5273. // that has m_bBroken == false or m_bConnected == true.
  5274. // If it is intended to forcefully close the socket, make sure
  5275. // that it's in response to a broken connection.
  5276. HLOGC(smlog.Debug, log << CONID() << "closing socket");
  5277. if (m_config.Linger.l_onoff != 0)
  5278. {
  5279. const steady_clock::time_point entertime = steady_clock::now();
  5280. HLOGC(smlog.Debug, log << CONID() << "... (linger)");
  5281. while (!m_bBroken && m_bConnected && (m_pSndBuffer->getCurrBufSize() > 0) &&
  5282. (steady_clock::now() - entertime < seconds_from(m_config.Linger.l_linger)))
  5283. {
  5284. // linger has been checked by previous close() call and has expired
  5285. if (m_tsLingerExpiration >= entertime)
  5286. break;
  5287. if (!m_config.bSynSending)
  5288. {
  5289. // if this socket enables asynchronous sending, return immediately and let GC to close it later
  5290. if (is_zero(m_tsLingerExpiration))
  5291. m_tsLingerExpiration = entertime + seconds_from(m_config.Linger.l_linger);
  5292. HLOGC(smlog.Debug,
  5293. log << CONID() << "CUDT::close: linger-nonblocking, setting expire time T="
  5294. << FormatTime(m_tsLingerExpiration));
  5295. return false;
  5296. }
  5297. #ifndef _WIN32
  5298. timespec ts;
  5299. ts.tv_sec = 0;
  5300. ts.tv_nsec = 1000000;
  5301. nanosleep(&ts, NULL);
  5302. #else
  5303. Sleep(1);
  5304. #endif
  5305. }
  5306. }
  5307. // remove this socket from the snd queue
  5308. if (m_bConnected)
  5309. m_pSndQueue->m_pSndUList->remove(this);
  5310. /*
  5311. * update_events below useless
  5312. * removing usock for EPolls right after (update_usocks) clears it (in other HAI patch).
  5313. *
  5314. * What is in EPoll shall be the responsibility of the application, if it want local close event,
  5315. * it would remove the socket from the EPoll after close.
  5316. */
  5317. // Make a copy under a lock because other thread might access it
  5318. // at the same time.
  5319. enterCS(uglobal().m_EPoll.m_EPollLock);
  5320. set<int> epollid = m_sPollID;
  5321. leaveCS(uglobal().m_EPoll.m_EPollLock);
  5322. // trigger any pending IO events.
  5323. HLOGC(smlog.Debug, log << CONID() << "close: SETTING ERR readiness on E" << Printable(epollid));
  5324. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_ERR, true);
  5325. // then remove itself from all epoll monitoring
  5326. int no_events = 0;
  5327. for (set<int>::iterator i = epollid.begin(); i != epollid.end(); ++i)
  5328. {
  5329. HLOGC(smlog.Debug, log << CONID() << "close: CLEARING subscription on E" << (*i));
  5330. try
  5331. {
  5332. uglobal().m_EPoll.update_usock(*i, m_SocketID, &no_events);
  5333. }
  5334. catch (...)
  5335. {
  5336. // The goal of this loop is to remove all subscriptions in
  5337. // the epoll system to this socket. If it's unsubscribed already,
  5338. // that's even better.
  5339. }
  5340. HLOGC(smlog.Debug, log << CONID() << "close: removing E" << (*i) << " from back-subscribers");
  5341. }
  5342. // Not deleting elements from m_sPollID inside the loop because it invalidates
  5343. // the control iterator of the loop. Instead, all will be removed at once.
  5344. // IMPORTANT: there's theoretically little time between setting ERR readiness
  5345. // and unsubscribing, however if there's an application waiting on this event,
  5346. // it should be informed before this below instruction locks the epoll mutex.
  5347. enterCS(uglobal().m_EPoll.m_EPollLock);
  5348. m_sPollID.clear();
  5349. leaveCS(uglobal().m_EPoll.m_EPollLock);
  5350. // XXX What's this, could any of the above actions make it !m_bOpened?
  5351. if (!m_bOpened)
  5352. {
  5353. return true;
  5354. }
  5355. // Inform the threads handler to stop.
  5356. m_bClosing = true;
  5357. HLOGC(smlog.Debug, log << CONID() << "CLOSING STATE. Acquiring connection lock");
  5358. ScopedLock connectguard(m_ConnectionLock);
  5359. // Signal the sender and recver if they are waiting for data.
  5360. releaseSynch();
  5361. HLOGC(smlog.Debug, log << CONID() << "CLOSING, removing from listener/connector");
  5362. if (m_bListening)
  5363. {
  5364. m_bListening = false;
  5365. m_pRcvQueue->removeListener(this);
  5366. }
  5367. else if (m_bConnecting)
  5368. {
  5369. m_pRcvQueue->removeConnector(m_SocketID);
  5370. }
  5371. if (m_bConnected)
  5372. {
  5373. if (!m_bShutdown)
  5374. {
  5375. HLOGC(smlog.Debug, log << CONID() << "CLOSING - sending SHUTDOWN to the peer @" << m_PeerID);
  5376. sendCtrl(UMSG_SHUTDOWN);
  5377. }
  5378. // Store current connection information.
  5379. CInfoBlock ib;
  5380. ib.m_iIPversion = m_PeerAddr.family();
  5381. CInfoBlock::convert(m_PeerAddr, ib.m_piIP);
  5382. ib.m_iSRTT = m_iSRTT;
  5383. ib.m_iBandwidth = m_iBandwidth;
  5384. m_pCache->update(&ib);
  5385. #if SRT_DEBUG_RTT
  5386. s_rtt_trace.trace(steady_clock::now(), "Cache", -1, -1,
  5387. m_bIsFirstRTTReceived, -1, m_iSRTT, -1);
  5388. #endif
  5389. m_bConnected = false;
  5390. }
  5391. HLOGC(smlog.Debug, log << CONID() << "CLOSING, joining send/receive threads");
  5392. // waiting all send and recv calls to stop
  5393. ScopedLock sendguard(m_SendLock);
  5394. ScopedLock recvguard(m_RecvLock);
  5395. // Locking m_RcvBufferLock to protect calling to m_pCryptoControl->decrypt((packet))
  5396. // from the processData(...) function while resetting Crypto Control.
  5397. enterCS(m_RcvBufferLock);
  5398. if (m_pCryptoControl)
  5399. m_pCryptoControl->close();
  5400. m_pCryptoControl.reset();
  5401. leaveCS(m_RcvBufferLock);
  5402. m_uPeerSrtVersion = SRT_VERSION_UNK;
  5403. m_tsRcvPeerStartTime = steady_clock::time_point();
  5404. m_bOpened = false;
  5405. return true;
  5406. }
  5407. int srt::CUDT::receiveBuffer(char *data, int len)
  5408. {
  5409. if (!m_CongCtl->checkTransArgs(SrtCongestion::STA_BUFFER, SrtCongestion::STAD_RECV, data, len, SRT_MSGTTL_INF, false))
  5410. throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0);
  5411. if (isOPT_TsbPd())
  5412. {
  5413. LOGP(arlog.Error, "recv: This function is not intended to be used in Live mode with TSBPD.");
  5414. throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0);
  5415. }
  5416. UniqueLock recvguard(m_RecvLock);
  5417. if ((m_bBroken || m_bClosing) && !isRcvBufferReady())
  5418. {
  5419. if (m_bShutdown)
  5420. {
  5421. // For stream API, return 0 as a sign of EOF for transmission.
  5422. // That's a bit controversial because theoretically the
  5423. // UMSG_SHUTDOWN message may be lost as every UDP packet, although
  5424. // another theory states that this will never happen because this
  5425. // packet has a total size of 42 bytes and such packets are
  5426. // declared as never dropped - but still, this is UDP so there's no
  5427. // guarantee.
  5428. // The most reliable way to inform the party that the transmission
  5429. // has ended would be to send a single empty packet (that is,
  5430. // a data packet that contains only an SRT header in the UDP
  5431. // payload), which is a normal data packet that can undergo
  5432. // normal sequence check and retransmission rules, so it's ensured
  5433. // that this packet will be received. Receiving such a packet should
  5434. // make this function return 0, potentially also without breaking
  5435. // the connection and potentially also with losing no ability to
  5436. // send some larger portion of data next time.
  5437. HLOGC(arlog.Debug, log << CONID() << "STREAM API, SHUTDOWN: marking as EOF");
  5438. return 0;
  5439. }
  5440. HLOGC(arlog.Debug,
  5441. log << CONID() << (m_config.bMessageAPI ? "MESSAGE" : "STREAM") << " API, " << (m_bShutdown ? "" : "no")
  5442. << " SHUTDOWN. Reporting as BROKEN.");
  5443. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  5444. }
  5445. CSync rcond (m_RecvDataCond, recvguard);
  5446. CSync tscond (m_RcvTsbPdCond, recvguard);
  5447. if (!isRcvBufferReady())
  5448. {
  5449. if (!m_config.bSynRecving)
  5450. {
  5451. throw CUDTException(MJ_AGAIN, MN_RDAVAIL, 0);
  5452. }
  5453. // Kick TsbPd thread to schedule next wakeup (if running)
  5454. if (m_config.iRcvTimeOut < 0)
  5455. {
  5456. THREAD_PAUSED();
  5457. while (stillConnected() && !isRcvBufferReady())
  5458. {
  5459. // Do not block forever, check connection status each 1 sec.
  5460. rcond.wait_for(seconds_from(1));
  5461. }
  5462. THREAD_RESUMED();
  5463. }
  5464. else
  5465. {
  5466. const steady_clock::time_point exptime =
  5467. steady_clock::now() + milliseconds_from(m_config.iRcvTimeOut);
  5468. THREAD_PAUSED();
  5469. while (stillConnected() && !isRcvBufferReady())
  5470. {
  5471. if (!rcond.wait_until(exptime)) // NOT means "not received a signal"
  5472. break; // timeout
  5473. }
  5474. THREAD_RESUMED();
  5475. }
  5476. }
  5477. // throw an exception if not connected
  5478. if (!m_bConnected)
  5479. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  5480. if ((m_bBroken || m_bClosing) && !isRcvBufferReady())
  5481. {
  5482. // See at the beginning
  5483. if (!m_config.bMessageAPI && m_bShutdown)
  5484. {
  5485. HLOGC(arlog.Debug, log << CONID() << "STREAM API, SHUTDOWN: marking as EOF");
  5486. return 0;
  5487. }
  5488. HLOGC(arlog.Debug,
  5489. log << CONID() << (m_config.bMessageAPI ? "MESSAGE" : "STREAM") << " API, " << (m_bShutdown ? "" : "no")
  5490. << " SHUTDOWN. Reporting as BROKEN.");
  5491. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  5492. }
  5493. enterCS(m_RcvBufferLock);
  5494. const int res = m_pRcvBuffer->readBuffer(data, len);
  5495. leaveCS(m_RcvBufferLock);
  5496. /* Kick TsbPd thread to schedule next wakeup (if running) */
  5497. if (m_bTsbPd)
  5498. {
  5499. HLOGP(tslog.Debug, "Ping TSBPD thread to schedule wakeup");
  5500. tscond.notify_one_locked(recvguard);
  5501. }
  5502. else
  5503. {
  5504. HLOGP(tslog.Debug, "NOT pinging TSBPD - not set");
  5505. }
  5506. if (!isRcvBufferReady())
  5507. {
  5508. // read is not available any more
  5509. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false);
  5510. }
  5511. if ((res <= 0) && (m_config.iRcvTimeOut >= 0))
  5512. throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
  5513. return res;
  5514. }
  5515. // [[using maybe_locked(CUDTGroup::m_GroupLock, m_parent->m_GroupOf != NULL)]];
  5516. // [[using locked(m_SendLock)]];
  5517. int srt::CUDT::sndDropTooLate()
  5518. {
  5519. if (!m_bPeerTLPktDrop)
  5520. return 0;
  5521. if (!m_config.bMessageAPI)
  5522. {
  5523. LOGC(aslog.Error, log << CONID() << "The SRTO_TLPKTDROP flag can only be used with message API.");
  5524. throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0);
  5525. }
  5526. const time_point tnow = steady_clock::now();
  5527. const int buffdelay_ms = (int) count_milliseconds(m_pSndBuffer->getBufferingDelay(tnow));
  5528. // high threshold (msec) at tsbpd_delay plus sender/receiver reaction time (2 * 10ms)
  5529. // Minimum value must accommodate an I-Frame (~8 x average frame size)
  5530. // >>need picture rate or app to set min treshold
  5531. // >>using 1 sec for worse case 1 frame using all bit budget.
  5532. // picture rate would be useful in auto SRT setting for min latency
  5533. // XXX Make SRT_TLPKTDROP_MINTHRESHOLD_MS option-configurable
  5534. const int threshold_ms = (m_config.iSndDropDelay >= 0)
  5535. ? std::max(m_iPeerTsbPdDelay_ms + m_config.iSndDropDelay, +SRT_TLPKTDROP_MINTHRESHOLD_MS)
  5536. + (2 * COMM_SYN_INTERVAL_US / 1000)
  5537. : 0;
  5538. if (threshold_ms == 0 || buffdelay_ms <= threshold_ms)
  5539. return 0;
  5540. // protect packet retransmission
  5541. ScopedLock rcvlck(m_RecvAckLock);
  5542. int dbytes;
  5543. int32_t first_msgno;
  5544. const int dpkts = m_pSndBuffer->dropLateData((dbytes), (first_msgno), tnow - milliseconds_from(threshold_ms));
  5545. if (dpkts <= 0)
  5546. return 0;
  5547. // If some packets were dropped update stats, socket state, loss list and the parent group if any.
  5548. enterCS(m_StatsLock);
  5549. m_stats.sndr.dropped.count(dbytes);;
  5550. leaveCS(m_StatsLock);
  5551. IF_HEAVY_LOGGING(const int32_t realack = m_iSndLastDataAck);
  5552. const int32_t fakeack = CSeqNo::incseq(m_iSndLastDataAck, dpkts);
  5553. m_iSndLastAck = fakeack;
  5554. m_iSndLastDataAck = fakeack;
  5555. const int32_t minlastack = CSeqNo::decseq(m_iSndLastDataAck);
  5556. m_pSndLossList->removeUpTo(minlastack);
  5557. /* If we dropped packets not yet sent, advance current position */
  5558. // THIS MEANS: m_iSndCurrSeqNo = MAX(m_iSndCurrSeqNo, m_iSndLastDataAck-1)
  5559. if (CSeqNo::seqcmp(m_iSndCurrSeqNo, minlastack) < 0)
  5560. {
  5561. m_iSndCurrSeqNo = minlastack;
  5562. }
  5563. HLOGC(aslog.Debug,
  5564. log << CONID() << "SND-DROP: %(" << realack << "-" << m_iSndCurrSeqNo << ") n=" << dpkts << "pkt " << dbytes
  5565. << "B, span=" << buffdelay_ms << " ms, FIRST #" << first_msgno);
  5566. #if ENABLE_BONDING
  5567. // This is done with a presumption that the group
  5568. // exists and if this is not NULL, it means that this
  5569. // function was called with locked m_GroupLock, as sendmsg2
  5570. // function was called from inside CUDTGroup::send, which
  5571. // locks the whole function.
  5572. //
  5573. // XXX This is true only because all existing groups are managed
  5574. // groups, that is, sockets cannot be added or removed from group
  5575. // manually, nor can send/recv operation be done on a single socket
  5576. // from the API call directly. This should be extra verified, if that
  5577. // changes in the future.
  5578. //
  5579. if (m_parent->m_GroupOf)
  5580. {
  5581. // What's important is that the lock on GroupLock cannot be applied
  5582. // here, both because it might be applied already, that is, according
  5583. // to the condition defined at this function's header, it is applied
  5584. // under this condition. Hence ackMessage can be defined as 100% locked.
  5585. m_parent->m_GroupOf->ackMessage(first_msgno);
  5586. }
  5587. #endif
  5588. return dpkts;
  5589. }
  5590. int srt::CUDT::sendmsg(const char *data, int len, int msttl, bool inorder, int64_t srctime)
  5591. {
  5592. SRT_MSGCTRL mctrl = srt_msgctrl_default;
  5593. mctrl.msgttl = msttl;
  5594. mctrl.inorder = inorder;
  5595. mctrl.srctime = srctime;
  5596. return this->sendmsg2(data, len, (mctrl));
  5597. }
  5598. // [[using maybe_locked(CUDTGroup::m_GroupLock, m_parent->m_GroupOf != NULL)]]
  5599. // GroupLock is applied when this function is called from inside CUDTGroup::send,
  5600. // which is the only case when the m_parent->m_GroupOf is not NULL.
  5601. int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl)
  5602. {
  5603. // throw an exception if not connected
  5604. if (m_bBroken || m_bClosing)
  5605. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  5606. else if (!m_bConnected || !m_CongCtl.ready())
  5607. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  5608. if (len <= 0)
  5609. {
  5610. LOGC(aslog.Error, log << CONID() << "INVALID: Data size for sending declared with length: " << len);
  5611. return 0;
  5612. }
  5613. if (w_mctrl.msgno != -1) // most unlikely, unless you use balancing groups
  5614. {
  5615. if (w_mctrl.msgno < 1 || w_mctrl.msgno > MSGNO_SEQ_MAX)
  5616. {
  5617. LOGC(aslog.Error,
  5618. log << CONID() << "INVALID forced msgno " << w_mctrl.msgno << ": can be -1 (trap) or <1..."
  5619. << MSGNO_SEQ_MAX << ">");
  5620. throw CUDTException(MJ_NOTSUP, MN_INVAL);
  5621. }
  5622. }
  5623. int msttl = w_mctrl.msgttl;
  5624. bool inorder = w_mctrl.inorder;
  5625. // Sendmsg isn't restricted to the congctl type, however the congctl
  5626. // may want to have something to say here.
  5627. // NOTE: SrtCongestion is also allowed to throw CUDTException() by itself!
  5628. {
  5629. SrtCongestion::TransAPI api = SrtCongestion::STA_MESSAGE;
  5630. CodeMinor mn = MN_INVALMSGAPI;
  5631. if (!m_config.bMessageAPI)
  5632. {
  5633. api = SrtCongestion::STA_BUFFER;
  5634. mn = MN_INVALBUFFERAPI;
  5635. }
  5636. if (!m_CongCtl->checkTransArgs(api, SrtCongestion::STAD_SEND, data, len, msttl, inorder))
  5637. throw CUDTException(MJ_NOTSUP, mn, 0);
  5638. }
  5639. // NOTE: the length restrictions differ in STREAM API and in MESSAGE API:
  5640. // - STREAM API:
  5641. // At least 1 byte free sending buffer space is needed
  5642. // (in practice, one unit buffer of 1456 bytes).
  5643. // This function will send as much as possible, and return
  5644. // how much was actually sent.
  5645. // - MESSAGE API:
  5646. // At least so many bytes free in the sending buffer is needed,
  5647. // as the length of the data, otherwise this function will block
  5648. // or return MJ_AGAIN until this condition is satisfied. The EXACTLY
  5649. // such number of data will be then written out, and this function
  5650. // will effectively return either -1 (error) or the value of 'len'.
  5651. // This call will be also rejected from upside when trying to send
  5652. // out a message of a length that exceeds the total size of the sending
  5653. // buffer (configurable by SRTO_SNDBUF).
  5654. if (m_config.bMessageAPI && len > int(m_config.iSndBufSize * m_iMaxSRTPayloadSize))
  5655. {
  5656. LOGC(aslog.Error,
  5657. log << CONID() << "Message length (" << len << ") exceeds the size of sending buffer: "
  5658. << (m_config.iSndBufSize * m_iMaxSRTPayloadSize) << ". Use SRTO_SNDBUF if needed.");
  5659. throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);
  5660. }
  5661. /* XXX
  5662. This might be worth preserving for several occasions, but it
  5663. must be at least conditional because it breaks backward compat.
  5664. if (!m_pCryptoControl || !m_pCryptoControl->isSndEncryptionOK())
  5665. {
  5666. LOGC(aslog.Error, log << "Encryption is required, but the peer did not supply correct credentials. Sending
  5667. rejected."); throw CUDTException(MJ_SETUP, MN_SECURITY, 0);
  5668. }
  5669. */
  5670. UniqueLock sendguard(m_SendLock);
  5671. if (m_pSndBuffer->getCurrBufSize() == 0)
  5672. {
  5673. // delay the EXP timer to avoid mis-fired timeout
  5674. ScopedLock ack_lock(m_RecvAckLock);
  5675. m_tsLastRspAckTime = steady_clock::now();
  5676. m_iReXmitCount = 1;
  5677. }
  5678. // sndDropTooLate(...) may lock m_RecvAckLock
  5679. // to modify m_pSndBuffer and m_pSndLossList
  5680. const int iPktsTLDropped SRT_ATR_UNUSED = sndDropTooLate();
  5681. // For MESSAGE API the minimum outgoing buffer space required is
  5682. // the size that can carry over the whole message as passed here.
  5683. // Otherwise it is allowed to send less bytes.
  5684. const int iNumPktsRequired = m_config.bMessageAPI ? m_pSndBuffer->countNumPacketsRequired(len) : 1;
  5685. if (m_bTsbPd && iNumPktsRequired > 1)
  5686. {
  5687. LOGC(aslog.Error,
  5688. log << CONID() << "Message length (" << len << ") can't fit into a single data packet ("
  5689. << m_pSndBuffer->getMaxPacketLen() << " bytes max).");
  5690. throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);
  5691. }
  5692. if (sndBuffersLeft() < iNumPktsRequired)
  5693. {
  5694. //>>We should not get here if SRT_ENABLE_TLPKTDROP
  5695. // XXX Check if this needs to be removed, or put to an 'else' condition for m_bTLPktDrop.
  5696. if (!m_config.bSynSending)
  5697. throw CUDTException(MJ_AGAIN, MN_WRAVAIL, 0);
  5698. {
  5699. // wait here during a blocking sending
  5700. UniqueLock sendblock_lock (m_SendBlockLock);
  5701. if (m_config.iSndTimeOut < 0)
  5702. {
  5703. while (stillConnected() && sndBuffersLeft() < iNumPktsRequired && m_bPeerHealth)
  5704. m_SendBlockCond.wait(sendblock_lock);
  5705. }
  5706. else
  5707. {
  5708. const steady_clock::time_point exptime =
  5709. steady_clock::now() + milliseconds_from(m_config.iSndTimeOut);
  5710. THREAD_PAUSED();
  5711. while (stillConnected() && sndBuffersLeft() < iNumPktsRequired && m_bPeerHealth)
  5712. {
  5713. if (!m_SendBlockCond.wait_until(sendblock_lock, exptime))
  5714. break;
  5715. }
  5716. THREAD_RESUMED();
  5717. }
  5718. }
  5719. // check the connection status
  5720. if (m_bBroken || m_bClosing)
  5721. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  5722. else if (!m_bConnected)
  5723. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  5724. else if (!m_bPeerHealth)
  5725. {
  5726. m_bPeerHealth = true;
  5727. throw CUDTException(MJ_PEERERROR);
  5728. }
  5729. /*
  5730. * The code below is to return ETIMEOUT when blocking mode could not get free buffer in time.
  5731. * If no free buffer available in non-blocking mode, we alredy returned. If buffer available,
  5732. * we test twice if this code is outside the else section.
  5733. * This fix move it in the else (blocking-mode) section
  5734. */
  5735. if (sndBuffersLeft() < iNumPktsRequired)
  5736. {
  5737. if (m_config.iSndTimeOut >= 0)
  5738. throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
  5739. // XXX This looks very weird here, however most likely
  5740. // this will happen only in the following case, when
  5741. // the above loop has been interrupted, which happens when:
  5742. // 1. The buffers left gets enough for minlen - but this is excluded
  5743. // in the first condition here.
  5744. // 2. In the case of sending timeout, the above loop was interrupted
  5745. // due to reaching timeout, but this is excluded by the second
  5746. // condition here
  5747. // 3. The 'stillConnected()' or m_bPeerHealth condition is false, of which:
  5748. // - broken/closing status is checked and responded with CONNECTION/CONNLOST
  5749. // - not connected status is checked and responded with CONNECTION/NOCONN
  5750. // - m_bPeerHealth condition is checked and responded with PEERERROR
  5751. //
  5752. // ERGO: never happens?
  5753. LOGC(aslog.Fatal,
  5754. log << CONID()
  5755. << "IPE: sendmsg: the loop exited, while not enough size, still connected, peer healthy. "
  5756. "Impossible.");
  5757. return 0;
  5758. }
  5759. }
  5760. // If the sender's buffer is empty,
  5761. // record total time used for sending
  5762. if (m_pSndBuffer->getCurrBufSize() == 0)
  5763. {
  5764. ScopedLock lock(m_StatsLock);
  5765. m_stats.sndDurationCounter = steady_clock::now();
  5766. }
  5767. int size = len;
  5768. if (!m_config.bMessageAPI)
  5769. {
  5770. // For STREAM API it's allowed to send less bytes than the given buffer.
  5771. // Just return how many bytes were actually scheduled for writing.
  5772. // XXX May be reasonable to add a flag that requires that the function
  5773. // not return until the buffer is sent completely.
  5774. size = min(len, sndBuffersLeft() * m_iMaxSRTPayloadSize);
  5775. }
  5776. {
  5777. ScopedLock recvAckLock(m_RecvAckLock);
  5778. // insert the user buffer into the sending list
  5779. int32_t seqno = m_iSndNextSeqNo;
  5780. IF_HEAVY_LOGGING(int32_t orig_seqno = seqno);
  5781. IF_HEAVY_LOGGING(steady_clock::time_point ts_srctime =
  5782. steady_clock::time_point() + microseconds_from(w_mctrl.srctime));
  5783. #if ENABLE_BONDING
  5784. // Check if seqno has been set, in case when this is a group sender.
  5785. // If the sequence is from the past towards the "next sequence",
  5786. // simply return the size, pretending that it has been sent.
  5787. // NOTE: it's assumed that if this is a group member, then
  5788. // an attempt to call srt_sendmsg2 has been rejected, and so
  5789. // the pktseq field has been set by the internal group sender function.
  5790. if (m_parent->m_GroupOf
  5791. && w_mctrl.pktseq != SRT_SEQNO_NONE
  5792. && m_iSndNextSeqNo != SRT_SEQNO_NONE)
  5793. {
  5794. if (CSeqNo::seqcmp(w_mctrl.pktseq, seqno) < 0)
  5795. {
  5796. HLOGC(aslog.Debug, log << CONID() << "sock:SENDING (NOT): group-req %" << w_mctrl.pktseq
  5797. << " OLDER THAN next expected %" << seqno << " - FAKE-SENDING.");
  5798. return size;
  5799. }
  5800. }
  5801. #endif
  5802. // Set this predicted next sequence to the control information.
  5803. // It's the sequence of the FIRST (!) packet from all packets used to send
  5804. // this buffer. Values from this field will be monotonic only if you always
  5805. // have one packet per buffer (as it's in live mode).
  5806. w_mctrl.pktseq = seqno;
  5807. // Now seqno is the sequence to which it was scheduled
  5808. // XXX Conversion from w_mctrl.srctime -> steady_clock::time_point need not be accurrate.
  5809. HLOGC(aslog.Debug, log << CONID() << "buf:SENDING (BEFORE) srctime:"
  5810. << (w_mctrl.srctime ? FormatTime(ts_srctime) : "none")
  5811. << " DATA SIZE: " << size << " sched-SEQUENCE: " << seqno
  5812. << " STAMP: " << BufferStamp(data, size));
  5813. if (w_mctrl.srctime && w_mctrl.srctime < count_microseconds(m_stats.tsStartTime.time_since_epoch()))
  5814. {
  5815. LOGC(aslog.Error,
  5816. log << CONID() << "Wrong source time was provided. Sending is rejected.");
  5817. throw CUDTException(MJ_NOTSUP, MN_INVALMSGAPI);
  5818. }
  5819. if (w_mctrl.srctime && (!m_config.bMessageAPI || !m_bTsbPd))
  5820. {
  5821. HLOGC(
  5822. aslog.Warn,
  5823. log << CONID()
  5824. << "Source time can only be used with TSBPD and Message API enabled. Using default time instead.");
  5825. w_mctrl.srctime = 0;
  5826. }
  5827. // w_mctrl.seqno is INPUT-OUTPUT value:
  5828. // - INPUT: the current sequence number to be placed for the next scheduled packet
  5829. // - OUTPUT: value of the sequence number to be put on the first packet at the next sendmsg2 call.
  5830. // We need to supply to the output the value that was STAMPED ON THE PACKET,
  5831. // which is seqno. In the output we'll get the next sequence number.
  5832. m_pSndBuffer->addBuffer(data, size, (w_mctrl));
  5833. m_iSndNextSeqNo = w_mctrl.pktseq;
  5834. w_mctrl.pktseq = seqno;
  5835. HLOGC(aslog.Debug, log << CONID() << "buf:SENDING srctime:" << FormatTime(ts_srctime)
  5836. << " size=" << size << " #" << w_mctrl.msgno << " SCHED %" << orig_seqno
  5837. << "(>> %" << seqno << ") !" << BufferStamp(data, size));
  5838. if (sndBuffersLeft() < 1) // XXX Not sure if it should test if any space in the buffer, or as requried.
  5839. {
  5840. // write is not available any more
  5841. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false);
  5842. }
  5843. }
  5844. // Insert this socket to the snd list if it is not on the list already.
  5845. // m_pSndUList->pop may lock CSndUList::m_ListLock and then m_RecvAckLock
  5846. m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);
  5847. #ifdef SRT_ENABLE_ECN
  5848. // IF there was a packet drop on the sender side, report congestion to the app.
  5849. if (iPktsTLDropped > 0)
  5850. {
  5851. LOGC(aslog.Error, log << CONID() << "sendmsg2: CONGESTION; reporting error");
  5852. throw CUDTException(MJ_AGAIN, MN_CONGESTION, 0);
  5853. }
  5854. #endif /* SRT_ENABLE_ECN */
  5855. HLOGC(aslog.Debug, log << CONID() << "sock:SENDING (END): success, size=" << size);
  5856. return size;
  5857. }
  5858. int srt::CUDT::recv(char* data, int len)
  5859. {
  5860. SRT_MSGCTRL mctrl = srt_msgctrl_default;
  5861. return recvmsg2(data, len, (mctrl));
  5862. }
  5863. int srt::CUDT::recvmsg(char* data, int len, int64_t& srctime)
  5864. {
  5865. SRT_MSGCTRL mctrl = srt_msgctrl_default;
  5866. int res = recvmsg2(data, len, (mctrl));
  5867. srctime = mctrl.srctime;
  5868. return res;
  5869. }
  5870. // [[using maybe_locked(CUDTGroup::m_GroupLock, m_parent->m_GroupOf != NULL)]]
  5871. // GroupLock is applied when this function is called from inside CUDTGroup::recv,
  5872. // which is the only case when the m_parent->m_GroupOf is not NULL.
  5873. int srt::CUDT::recvmsg2(char* data, int len, SRT_MSGCTRL& w_mctrl)
  5874. {
  5875. // Check if the socket is a member of a receiver group.
  5876. // If so, then reading by receiveMessage is disallowed.
  5877. #if ENABLE_BONDING
  5878. if (m_parent->m_GroupOf && m_parent->m_GroupOf->isGroupReceiver())
  5879. {
  5880. LOGP(arlog.Error, "recv*: This socket is a receiver group member. Use group ID, NOT socket ID.");
  5881. throw CUDTException(MJ_NOTSUP, MN_INVALMSGAPI, 0);
  5882. }
  5883. #endif
  5884. if (!m_bConnected || !m_CongCtl.ready())
  5885. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  5886. if (len <= 0)
  5887. {
  5888. LOGC(arlog.Error, log << CONID() << "Length of '" << len << "' supplied to srt_recvmsg.");
  5889. throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
  5890. }
  5891. if (m_config.bMessageAPI)
  5892. return receiveMessage(data, len, (w_mctrl));
  5893. return receiveBuffer(data, len);
  5894. }
  5895. // [[using locked(m_RcvBufferLock)]]
  5896. size_t srt::CUDT::getAvailRcvBufferSizeNoLock() const
  5897. {
  5898. return m_pRcvBuffer->getAvailSize(m_iRcvLastAck);
  5899. }
  5900. bool srt::CUDT::isRcvBufferReady() const
  5901. {
  5902. ScopedLock lck(m_RcvBufferLock);
  5903. return m_pRcvBuffer->isRcvDataReady(steady_clock::now());
  5904. }
  5905. bool srt::CUDT::isRcvBufferReadyNoLock() const
  5906. {
  5907. return m_pRcvBuffer->isRcvDataReady(steady_clock::now());
  5908. }
  5909. // int by_exception: accepts values of CUDTUnited::ErrorHandling:
  5910. // - 0 - by return value
  5911. // - 1 - by exception
  5912. // - 2 - by abort (unused)
  5913. int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_exception)
  5914. {
  5915. // Recvmsg isn't restricted to the congctl type, it's the most
  5916. // basic method of passing the data. You can retrieve data as
  5917. // they come in, however you need to match the size of the buffer.
  5918. // Note: if by_exception = ERH_RETURN, this would still break it
  5919. // by exception. The intention of by_exception isn't to prevent
  5920. // exceptions here, but to intercept the erroneous situation should
  5921. // it be handled by the caller in a less than general way. As this
  5922. // is only used internally, we state that the problem that would be
  5923. // handled by exception here should not happen, and in case if it does,
  5924. // it's a bug to fix, so the exception is nothing wrong.
  5925. if (!m_CongCtl->checkTransArgs(SrtCongestion::STA_MESSAGE, SrtCongestion::STAD_RECV, data, len, SRT_MSGTTL_INF, false))
  5926. throw CUDTException(MJ_NOTSUP, MN_INVALMSGAPI, 0);
  5927. UniqueLock recvguard (m_RecvLock);
  5928. CSync tscond (m_RcvTsbPdCond, recvguard);
  5929. /* XXX DEBUG STUFF - enable when required
  5930. char charbool[2] = {'0', '1'};
  5931. char ptrn [] = "RECVMSG/BEGIN BROKEN 1 CONN 1 CLOSING 1 SYNCR 1 NMSG ";
  5932. int pos [] = {21, 28, 38, 46, 53};
  5933. ptrn[pos[0]] = charbool[m_bBroken];
  5934. ptrn[pos[1]] = charbool[m_bConnected];
  5935. ptrn[pos[2]] = charbool[m_bClosing];
  5936. ptrn[pos[3]] = charbool[m_config.m_bSynRecving];
  5937. int wrtlen = sprintf(ptrn + pos[4], "%d", m_pRcvBuffer->getRcvMsgNum());
  5938. strcpy(ptrn + pos[4] + wrtlen, "\n");
  5939. fputs(ptrn, stderr);
  5940. // */
  5941. if (m_bBroken || m_bClosing)
  5942. {
  5943. HLOGC(arlog.Debug, log << CONID() << "receiveMessage: CONNECTION BROKEN - reading from recv buffer just for formality");
  5944. enterCS(m_RcvBufferLock);
  5945. const int res = (m_pRcvBuffer->isRcvDataReady(steady_clock::now()))
  5946. ? m_pRcvBuffer->readMessage(data, len, &w_mctrl)
  5947. : 0;
  5948. leaveCS(m_RcvBufferLock);
  5949. // Kick TsbPd thread to schedule next wakeup (if running)
  5950. if (m_bTsbPd)
  5951. {
  5952. HLOGP(tslog.Debug, "Ping TSBPD thread to schedule wakeup");
  5953. tscond.notify_one_locked(recvguard);
  5954. }
  5955. else
  5956. {
  5957. HLOGP(tslog.Debug, "NOT pinging TSBPD - not set");
  5958. }
  5959. if (!isRcvBufferReady())
  5960. {
  5961. // read is not available any more
  5962. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false);
  5963. }
  5964. if (res == 0)
  5965. {
  5966. if (!m_config.bMessageAPI && m_bShutdown)
  5967. return 0;
  5968. // Forced to return error instead of throwing exception.
  5969. if (!by_exception)
  5970. return APIError(MJ_CONNECTION, MN_CONNLOST, 0);
  5971. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  5972. }
  5973. else
  5974. return res;
  5975. }
  5976. if (!m_config.bSynRecving)
  5977. {
  5978. HLOGC(arlog.Debug, log << CONID() << "receiveMessage: BEGIN ASYNC MODE. Going to extract payload size=" << len);
  5979. enterCS(m_RcvBufferLock);
  5980. const int res = (m_pRcvBuffer->isRcvDataReady(steady_clock::now()))
  5981. ? m_pRcvBuffer->readMessage(data, len, &w_mctrl)
  5982. : 0;
  5983. leaveCS(m_RcvBufferLock);
  5984. HLOGC(arlog.Debug, log << CONID() << "AFTER readMsg: (NON-BLOCKING) result=" << res);
  5985. if (res == 0)
  5986. {
  5987. // read is not available any more
  5988. // Kick TsbPd thread to schedule next wakeup (if running)
  5989. if (m_bTsbPd)
  5990. {
  5991. HLOGP(arlog.Debug, "receiveMessage: nothing to read, kicking TSBPD, return AGAIN");
  5992. tscond.notify_one_locked(recvguard);
  5993. }
  5994. else
  5995. {
  5996. HLOGP(arlog.Debug, "receiveMessage: nothing to read, return AGAIN");
  5997. }
  5998. // Shut up EPoll if no more messages in non-blocking mode
  5999. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false);
  6000. // Forced to return 0 instead of throwing exception, in case of AGAIN/READ
  6001. if (!by_exception)
  6002. return 0;
  6003. throw CUDTException(MJ_AGAIN, MN_RDAVAIL, 0);
  6004. }
  6005. if (!isRcvBufferReady())
  6006. {
  6007. // Kick TsbPd thread to schedule next wakeup (if running)
  6008. if (m_bTsbPd)
  6009. {
  6010. HLOGP(arlog.Debug, "receiveMessage: DATA READ, but nothing more - kicking TSBPD.");
  6011. tscond.notify_one_locked(recvguard);
  6012. }
  6013. else
  6014. {
  6015. HLOGP(arlog.Debug, "receiveMessage: DATA READ, but nothing more");
  6016. }
  6017. // Shut up EPoll if no more messages in non-blocking mode
  6018. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false);
  6019. // After signaling the tsbpd for ready data, report the bandwidth.
  6020. #if ENABLE_HEAVY_LOGGING
  6021. double bw = Bps2Mbps(int64_t(m_iBandwidth) * m_iMaxSRTPayloadSize );
  6022. HLOGC(arlog.Debug, log << CONID() << "CURRENT BANDWIDTH: " << bw << "Mbps (" << m_iBandwidth << " buffers per second)");
  6023. #endif
  6024. }
  6025. return res;
  6026. }
  6027. HLOGC(arlog.Debug, log << CONID() << "receiveMessage: BEGIN SYNC MODE. Going to extract payload size max=" << len);
  6028. int res = 0;
  6029. bool timeout = false;
  6030. // Do not block forever, check connection status each 1 sec.
  6031. const steady_clock::duration recv_timeout = m_config.iRcvTimeOut < 0 ? seconds_from(1) : milliseconds_from(m_config.iRcvTimeOut);
  6032. CSync recv_cond (m_RecvDataCond, recvguard);
  6033. do
  6034. {
  6035. if (stillConnected() && !timeout && !m_pRcvBuffer->isRcvDataReady(steady_clock::now()))
  6036. {
  6037. /* Kick TsbPd thread to schedule next wakeup (if running) */
  6038. if (m_bTsbPd)
  6039. {
  6040. // XXX Experimental, so just inform:
  6041. // Check if the last check of isRcvDataReady has returned any "next time for a packet".
  6042. // If so, then it means that TSBPD has fallen asleep only up to this time, so waking it up
  6043. // would be "spurious". If a new packet comes ahead of the packet which's time is returned
  6044. // in tstime (as TSBPD sleeps up to then), the procedure that receives it is responsible
  6045. // of kicking TSBPD.
  6046. // bool spurious = (tstime != 0);
  6047. HLOGC(tslog.Debug, log << CONID() << "receiveMessage: KICK tsbpd");
  6048. tscond.notify_one_locked(recvguard);
  6049. }
  6050. THREAD_PAUSED();
  6051. do
  6052. {
  6053. // `wait_for(recv_timeout)` wouldn't be correct here. Waiting should be
  6054. // only until the time that is now + timeout since the first moment
  6055. // when this started, or sliced-waiting for 1 second, if timtout is
  6056. // higher than this.
  6057. const steady_clock::time_point exptime = steady_clock::now() + recv_timeout;
  6058. HLOGC(tslog.Debug,
  6059. log << CONID() << "receiveMessage: fall asleep up to TS=" << FormatTime(exptime)
  6060. << " lock=" << (&m_RecvLock) << " cond=" << (&m_RecvDataCond));
  6061. if (!recv_cond.wait_until(exptime))
  6062. {
  6063. if (m_config.iRcvTimeOut >= 0) // otherwise it's "no timeout set"
  6064. timeout = true;
  6065. HLOGP(tslog.Debug,
  6066. "receiveMessage: DATA COND: EXPIRED -- checking connection conditions and rolling again");
  6067. }
  6068. else
  6069. {
  6070. HLOGP(tslog.Debug, "receiveMessage: DATA COND: KICKED.");
  6071. }
  6072. } while (stillConnected() && !timeout && (!isRcvBufferReady()));
  6073. THREAD_RESUMED();
  6074. HLOGC(tslog.Debug,
  6075. log << CONID() << "receiveMessage: lock-waiting loop exited: stillConntected=" << stillConnected()
  6076. << " timeout=" << timeout << " data-ready=" << isRcvBufferReady());
  6077. }
  6078. /* XXX DEBUG STUFF - enable when required
  6079. LOGC(arlog.Debug, "RECVMSG/GO-ON BROKEN " << m_bBroken << " CONN " << m_bConnected
  6080. << " CLOSING " << m_bClosing << " TMOUT " << timeout
  6081. << " NMSG " << m_pRcvBuffer->getRcvMsgNum());
  6082. */
  6083. enterCS(m_RcvBufferLock);
  6084. res = m_pRcvBuffer->readMessage((data), len, &w_mctrl);
  6085. leaveCS(m_RcvBufferLock);
  6086. HLOGC(arlog.Debug, log << CONID() << "AFTER readMsg: (BLOCKING) result=" << res);
  6087. if (m_bBroken || m_bClosing)
  6088. {
  6089. // Forced to return 0 instead of throwing exception.
  6090. if (!by_exception)
  6091. return APIError(MJ_CONNECTION, MN_CONNLOST, 0);
  6092. if (!m_config.bMessageAPI && m_bShutdown)
  6093. return 0;
  6094. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  6095. }
  6096. else if (!m_bConnected)
  6097. {
  6098. // Forced to return -1 instead of throwing exception.
  6099. if (!by_exception)
  6100. return APIError(MJ_CONNECTION, MN_NOCONN, 0);
  6101. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  6102. }
  6103. } while ((res == 0) && !timeout);
  6104. if (!isRcvBufferReady())
  6105. {
  6106. // Falling here means usually that res == 0 && timeout == true.
  6107. // res == 0 would repeat the above loop, unless there was also a timeout.
  6108. // timeout has interrupted the above loop, but with res > 0 this condition
  6109. // wouldn't be satisfied.
  6110. // read is not available any more
  6111. // Kick TsbPd thread to schedule next wakeup (if running)
  6112. if (m_bTsbPd)
  6113. {
  6114. HLOGP(tslog.Debug, "recvmsg: KICK tsbpd() (buffer empty)");
  6115. tscond.notify_one_locked(recvguard);
  6116. }
  6117. // Shut up EPoll if no more messages in non-blocking mode
  6118. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false);
  6119. }
  6120. // Unblock when required
  6121. // LOGC(tslog.Debug, "RECVMSG/EXIT RES " << res << " RCVTIMEOUT");
  6122. if ((res <= 0) && (m_config.iRcvTimeOut >= 0))
  6123. {
  6124. // Forced to return -1 instead of throwing exception.
  6125. if (!by_exception)
  6126. return APIError(MJ_AGAIN, MN_XMTIMEOUT, 0);
  6127. throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
  6128. }
  6129. return res;
  6130. }
  6131. int64_t srt::CUDT::sendfile(fstream &ifs, int64_t &offset, int64_t size, int block)
  6132. {
  6133. if (m_bBroken || m_bClosing)
  6134. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  6135. else if (!m_bConnected || !m_CongCtl.ready())
  6136. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  6137. if (size <= 0 && size != -1)
  6138. return 0;
  6139. if (!m_CongCtl->checkTransArgs(SrtCongestion::STA_FILE, SrtCongestion::STAD_SEND, 0, size, SRT_MSGTTL_INF, false))
  6140. throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0);
  6141. if (!m_pCryptoControl || !m_pCryptoControl->isSndEncryptionOK())
  6142. {
  6143. LOGC(aslog.Error,
  6144. log << CONID()
  6145. << "Encryption is required, but the peer did not supply correct credentials. Sending rejected.");
  6146. throw CUDTException(MJ_SETUP, MN_SECURITY, 0);
  6147. }
  6148. ScopedLock sendguard (m_SendLock);
  6149. if (m_pSndBuffer->getCurrBufSize() == 0)
  6150. {
  6151. // delay the EXP timer to avoid mis-fired timeout
  6152. ScopedLock ack_lock(m_RecvAckLock);
  6153. m_tsLastRspAckTime = steady_clock::now();
  6154. m_iReXmitCount = 1;
  6155. }
  6156. // positioning...
  6157. try
  6158. {
  6159. if (size == -1)
  6160. {
  6161. ifs.seekg(0, std::ios::end);
  6162. size = ifs.tellg();
  6163. if (offset > size)
  6164. throw 0; // let it be caught below
  6165. }
  6166. // This will also set the position back to the beginning
  6167. // in case when it was moved to the end for measuring the size.
  6168. // This will also fail if the offset exceeds size, so measuring
  6169. // the size can be skipped if not needed.
  6170. ifs.seekg((streamoff)offset);
  6171. if (!ifs.good())
  6172. throw 0;
  6173. }
  6174. catch (...)
  6175. {
  6176. // XXX It would be nice to note that this is reported
  6177. // by exception only if explicitly requested by setting
  6178. // the exception flags in the stream. Here it's fixed so
  6179. // that when this isn't set, the exception is "thrown manually".
  6180. throw CUDTException(MJ_FILESYSTEM, MN_SEEKGFAIL);
  6181. }
  6182. int64_t tosend = size;
  6183. int unitsize;
  6184. // sending block by block
  6185. while (tosend > 0)
  6186. {
  6187. if (ifs.fail())
  6188. throw CUDTException(MJ_FILESYSTEM, MN_WRITEFAIL);
  6189. if (ifs.eof())
  6190. break;
  6191. unitsize = int((tosend >= block) ? block : tosend);
  6192. {
  6193. UniqueLock lock(m_SendBlockLock);
  6194. THREAD_PAUSED();
  6195. while (stillConnected() && (sndBuffersLeft() <= 0) && m_bPeerHealth)
  6196. m_SendBlockCond.wait(lock);
  6197. THREAD_RESUMED();
  6198. }
  6199. if (m_bBroken || m_bClosing)
  6200. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  6201. else if (!m_bConnected)
  6202. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  6203. else if (!m_bPeerHealth)
  6204. {
  6205. // reset peer health status, once this error returns, the app should handle the situation at the peer side
  6206. m_bPeerHealth = true;
  6207. throw CUDTException(MJ_PEERERROR);
  6208. }
  6209. // record total time used for sending
  6210. if (m_pSndBuffer->getCurrBufSize() == 0)
  6211. {
  6212. ScopedLock lock(m_StatsLock);
  6213. m_stats.sndDurationCounter = steady_clock::now();
  6214. }
  6215. {
  6216. ScopedLock recvAckLock(m_RecvAckLock);
  6217. const int64_t sentsize = m_pSndBuffer->addBufferFromFile(ifs, unitsize);
  6218. if (sentsize > 0)
  6219. {
  6220. tosend -= sentsize;
  6221. offset += sentsize;
  6222. }
  6223. if (sndBuffersLeft() <= 0)
  6224. {
  6225. // write is not available any more
  6226. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false);
  6227. }
  6228. }
  6229. // insert this socket to snd list if it is not on the list yet
  6230. m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);
  6231. }
  6232. return size - tosend;
  6233. }
  6234. int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int block)
  6235. {
  6236. if (!m_bConnected || !m_CongCtl.ready())
  6237. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  6238. else if ((m_bBroken || m_bClosing) && !isRcvBufferReady())
  6239. {
  6240. if (!m_config.bMessageAPI && m_bShutdown)
  6241. return 0;
  6242. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  6243. }
  6244. if (size <= 0)
  6245. return 0;
  6246. if (!m_CongCtl->checkTransArgs(SrtCongestion::STA_FILE, SrtCongestion::STAD_RECV, 0, size, SRT_MSGTTL_INF, false))
  6247. throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0);
  6248. if (isOPT_TsbPd())
  6249. {
  6250. LOGC(arlog.Error,
  6251. log << CONID() << "Reading from file is incompatible with TSBPD mode and would cause a deadlock");
  6252. throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0);
  6253. }
  6254. UniqueLock recvguard(m_RecvLock);
  6255. // Well, actually as this works over a FILE (fstream), not just a stream,
  6256. // the size can be measured anyway and predicted if setting the offset might
  6257. // have a chance to work or not.
  6258. // positioning...
  6259. try
  6260. {
  6261. if (offset > 0)
  6262. {
  6263. // Don't do anything around here if the offset == 0, as this
  6264. // is the default offset after opening. Whether this operation
  6265. // is performed correctly, it highly depends on how the file
  6266. // has been open. For example, if you want to overwrite parts
  6267. // of an existing file, the file must exist, and the ios::trunc
  6268. // flag must not be set. If the file is open for only ios::out,
  6269. // then the file will be truncated since the offset position on
  6270. // at the time when first written; if ios::in|ios::out, then
  6271. // it won't be truncated, just overwritten.
  6272. // What is required here is that if offset is 0, don't try to
  6273. // change the offset because this might be impossible with
  6274. // the current flag set anyway.
  6275. // Also check the status and CAUSE exception manually because
  6276. // you don't know, as well, whether the user has set exception
  6277. // flags.
  6278. ofs.seekp((streamoff)offset);
  6279. if (!ofs.good())
  6280. throw 0; // just to get caught :)
  6281. }
  6282. }
  6283. catch (...)
  6284. {
  6285. // XXX It would be nice to note that this is reported
  6286. // by exception only if explicitly requested by setting
  6287. // the exception flags in the stream. For a case, when it's not,
  6288. // an additional explicit throwing happens when failbit is set.
  6289. throw CUDTException(MJ_FILESYSTEM, MN_SEEKPFAIL);
  6290. }
  6291. int64_t torecv = size;
  6292. int unitsize = block;
  6293. int recvsize;
  6294. // receiving... "recvfile" is always blocking
  6295. while (torecv > 0)
  6296. {
  6297. if (ofs.fail())
  6298. {
  6299. // send the sender a signal so it will not be blocked forever
  6300. int32_t err_code = CUDTException::EFILE;
  6301. sendCtrl(UMSG_PEERERROR, &err_code);
  6302. throw CUDTException(MJ_FILESYSTEM, MN_WRITEFAIL);
  6303. }
  6304. {
  6305. CSync rcond (m_RecvDataCond, recvguard);
  6306. THREAD_PAUSED();
  6307. while (stillConnected() && !isRcvBufferReady())
  6308. rcond.wait();
  6309. THREAD_RESUMED();
  6310. }
  6311. if (!m_bConnected)
  6312. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  6313. else if ((m_bBroken || m_bClosing) && !isRcvBufferReady())
  6314. {
  6315. if (!m_config.bMessageAPI && m_bShutdown)
  6316. return 0;
  6317. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  6318. }
  6319. unitsize = int((torecv > block) ? block : torecv);
  6320. enterCS(m_RcvBufferLock);
  6321. recvsize = m_pRcvBuffer->readBufferToFile(ofs, unitsize);
  6322. leaveCS(m_RcvBufferLock);
  6323. if (recvsize > 0)
  6324. {
  6325. torecv -= recvsize;
  6326. offset += recvsize;
  6327. }
  6328. }
  6329. if (!isRcvBufferReady())
  6330. {
  6331. // read is not available any more
  6332. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false);
  6333. }
  6334. return size - torecv;
  6335. }
  6336. void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous)
  6337. {
  6338. if (!m_bConnected)
  6339. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  6340. if (m_bBroken || m_bClosing)
  6341. throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
  6342. const int pktHdrSize = CPacket::HDR_SIZE + CPacket::UDP_HDR_SIZE;
  6343. {
  6344. ScopedLock statsguard(m_StatsLock);
  6345. const steady_clock::time_point currtime = steady_clock::now();
  6346. perf->msTimeStamp = count_milliseconds(currtime - m_stats.tsStartTime);
  6347. perf->pktSent = m_stats.sndr.sent.trace.count();
  6348. perf->pktSentUnique = m_stats.sndr.sentUnique.trace.count();
  6349. perf->pktRecv = m_stats.rcvr.recvd.trace.count();
  6350. perf->pktRecvUnique = m_stats.rcvr.recvdUnique.trace.count();
  6351. perf->pktSndLoss = m_stats.sndr.lost.trace.count();
  6352. perf->pktRcvLoss = m_stats.rcvr.lost.trace.count();
  6353. perf->pktRetrans = m_stats.sndr.sentRetrans.trace.count();
  6354. perf->pktRcvRetrans = m_stats.rcvr.recvdRetrans.trace.count();
  6355. perf->pktSentACK = m_stats.rcvr.sentAck.trace.count();
  6356. perf->pktRecvACK = m_stats.sndr.recvdAck.trace.count();
  6357. perf->pktSentNAK = m_stats.rcvr.sentNak.trace.count();
  6358. perf->pktRecvNAK = m_stats.sndr.recvdNak.trace.count();
  6359. perf->usSndDuration = m_stats.sndDuration;
  6360. perf->pktReorderDistance = m_stats.traceReorderDistance;
  6361. perf->pktReorderTolerance = m_iReorderTolerance;
  6362. perf->pktRcvAvgBelatedTime = m_stats.traceBelatedTime;
  6363. perf->pktRcvBelated = m_stats.rcvr.recvdBelated.trace.count();
  6364. perf->pktSndFilterExtra = m_stats.sndr.sentFilterExtra.trace.count();
  6365. perf->pktRcvFilterExtra = m_stats.rcvr.recvdFilterExtra.trace.count();
  6366. perf->pktRcvFilterSupply = m_stats.rcvr.suppliedByFilter.trace.count();
  6367. perf->pktRcvFilterLoss = m_stats.rcvr.lossFilter.trace.count();
  6368. /* perf byte counters include all headers (SRT+UDP+IP) */
  6369. perf->byteSent = m_stats.sndr.sent.trace.bytesWithHdr();
  6370. perf->byteSentUnique = m_stats.sndr.sentUnique.trace.bytesWithHdr();
  6371. perf->byteRecv = m_stats.rcvr.recvd.trace.bytesWithHdr();
  6372. perf->byteRecvUnique = m_stats.rcvr.recvdUnique.trace.bytesWithHdr();
  6373. perf->byteRetrans = m_stats.sndr.sentRetrans.trace.bytesWithHdr();
  6374. perf->byteRcvLoss = m_stats.rcvr.lost.trace.bytesWithHdr();
  6375. perf->pktSndDrop = m_stats.sndr.dropped.trace.count();
  6376. perf->pktRcvDrop = m_stats.rcvr.dropped.trace.count();
  6377. perf->byteSndDrop = m_stats.sndr.dropped.trace.bytesWithHdr();
  6378. perf->byteRcvDrop = m_stats.rcvr.dropped.trace.bytesWithHdr();
  6379. perf->pktRcvUndecrypt = m_stats.rcvr.undecrypted.trace.count();
  6380. perf->byteRcvUndecrypt = m_stats.rcvr.undecrypted.trace.bytes();
  6381. perf->pktSentTotal = m_stats.sndr.sent.total.count();
  6382. perf->pktSentUniqueTotal = m_stats.sndr.sentUnique.total.count();
  6383. perf->pktRecvTotal = m_stats.rcvr.recvd.total.count();
  6384. perf->pktRecvUniqueTotal = m_stats.rcvr.recvdUnique.total.count();
  6385. perf->pktSndLossTotal = m_stats.sndr.lost.total.count();
  6386. perf->pktRcvLossTotal = m_stats.rcvr.lost.total.count();
  6387. perf->pktRetransTotal = m_stats.sndr.sentRetrans.total.count();
  6388. perf->pktSentACKTotal = m_stats.rcvr.sentAck.total.count();
  6389. perf->pktRecvACKTotal = m_stats.sndr.recvdAck.total.count();
  6390. perf->pktSentNAKTotal = m_stats.rcvr.sentNak.total.count();
  6391. perf->pktRecvNAKTotal = m_stats.sndr.recvdNak.total.count();
  6392. perf->usSndDurationTotal = m_stats.m_sndDurationTotal;
  6393. perf->byteSentTotal = m_stats.sndr.sent.total.bytesWithHdr();
  6394. perf->byteSentUniqueTotal = m_stats.sndr.sentUnique.total.bytesWithHdr();
  6395. perf->byteRecvTotal = m_stats.rcvr.recvd.total.bytesWithHdr();
  6396. perf->byteRecvUniqueTotal = m_stats.rcvr.recvdUnique.total.bytesWithHdr();
  6397. perf->byteRetransTotal = m_stats.sndr.sentRetrans.total.bytesWithHdr();
  6398. perf->pktSndFilterExtraTotal = m_stats.sndr.sentFilterExtra.total.count();
  6399. perf->pktRcvFilterExtraTotal = m_stats.rcvr.recvdFilterExtra.total.count();
  6400. perf->pktRcvFilterSupplyTotal = m_stats.rcvr.suppliedByFilter.total.count();
  6401. perf->pktRcvFilterLossTotal = m_stats.rcvr.lossFilter.total.count();
  6402. perf->byteRcvLossTotal = m_stats.rcvr.lost.total.bytesWithHdr();
  6403. perf->pktSndDropTotal = m_stats.sndr.dropped.total.count();
  6404. perf->pktRcvDropTotal = m_stats.rcvr.dropped.total.count();
  6405. // TODO: The payload is dropped. Probably header sizes should not be counted?
  6406. perf->byteSndDropTotal = m_stats.sndr.dropped.total.bytesWithHdr();
  6407. perf->byteRcvDropTotal = m_stats.rcvr.dropped.total.bytesWithHdr();
  6408. perf->pktRcvUndecryptTotal = m_stats.rcvr.undecrypted.total.count();
  6409. perf->byteRcvUndecryptTotal = m_stats.rcvr.undecrypted.total.bytes();
  6410. // TODO: The following class members must be protected with a different mutex, not the m_StatsLock.
  6411. const double interval = (double) count_microseconds(currtime - m_stats.tsLastSampleTime);
  6412. perf->mbpsSendRate = double(perf->byteSent) * 8.0 / interval;
  6413. perf->mbpsRecvRate = double(perf->byteRecv) * 8.0 / interval;
  6414. perf->usPktSndPeriod = (double) count_microseconds(m_tdSendInterval.load());
  6415. perf->pktFlowWindow = m_iFlowWindowSize.load();
  6416. perf->pktCongestionWindow = (int)m_dCongestionWindow;
  6417. perf->pktFlightSize = getFlightSpan();
  6418. perf->msRTT = (double)m_iSRTT / 1000.0;
  6419. perf->msSndTsbPdDelay = m_bPeerTsbPd ? m_iPeerTsbPdDelay_ms : 0;
  6420. perf->msRcvTsbPdDelay = isOPT_TsbPd() ? m_iTsbPdDelay_ms : 0;
  6421. perf->byteMSS = m_config.iMSS;
  6422. perf->mbpsMaxBW = m_config.llMaxBW > 0 ? Bps2Mbps(m_config.llMaxBW)
  6423. : m_CongCtl.ready() ? Bps2Mbps(m_CongCtl->sndBandwidth())
  6424. : 0;
  6425. if (clear)
  6426. {
  6427. m_stats.sndr.resetTrace();
  6428. m_stats.rcvr.resetTrace();
  6429. m_stats.sndDuration = 0;
  6430. m_stats.tsLastSampleTime = currtime;
  6431. }
  6432. }
  6433. const int64_t availbw = m_iBandwidth == 1 ? m_RcvTimeWindow.getBandwidth() : m_iBandwidth.load();
  6434. perf->mbpsBandwidth = Bps2Mbps(availbw * (m_iMaxSRTPayloadSize + pktHdrSize));
  6435. if (tryEnterCS(m_ConnectionLock))
  6436. {
  6437. if (m_pSndBuffer)
  6438. {
  6439. if (instantaneous)
  6440. {
  6441. /* Get instant SndBuf instead of moving average for application-based Algorithm
  6442. (such as NAE) in need of fast reaction to network condition changes. */
  6443. perf->pktSndBuf = m_pSndBuffer->getCurrBufSize((perf->byteSndBuf), (perf->msSndBuf));
  6444. }
  6445. else
  6446. {
  6447. perf->pktSndBuf = m_pSndBuffer->getAvgBufSize((perf->byteSndBuf), (perf->msSndBuf));
  6448. }
  6449. perf->byteSndBuf += (perf->pktSndBuf * pktHdrSize);
  6450. perf->byteAvailSndBuf = (m_config.iSndBufSize - perf->pktSndBuf) * m_config.iMSS;
  6451. }
  6452. else
  6453. {
  6454. perf->byteAvailSndBuf = 0;
  6455. perf->pktSndBuf = 0;
  6456. perf->byteSndBuf = 0;
  6457. perf->msSndBuf = 0;
  6458. }
  6459. if (m_pRcvBuffer)
  6460. {
  6461. ScopedLock lck(m_RcvBufferLock);
  6462. perf->byteAvailRcvBuf = (int) getAvailRcvBufferSizeNoLock() * m_config.iMSS;
  6463. if (instantaneous) // no need for historical API for Rcv side
  6464. {
  6465. perf->pktRcvBuf = m_pRcvBuffer->getRcvDataSize(perf->byteRcvBuf, perf->msRcvBuf);
  6466. }
  6467. else
  6468. {
  6469. perf->pktRcvBuf = m_pRcvBuffer->getRcvAvgDataSize(perf->byteRcvBuf, perf->msRcvBuf);
  6470. }
  6471. }
  6472. else
  6473. {
  6474. perf->byteAvailRcvBuf = 0;
  6475. perf->pktRcvBuf = 0;
  6476. perf->byteRcvBuf = 0;
  6477. perf->msRcvBuf = 0;
  6478. }
  6479. leaveCS(m_ConnectionLock);
  6480. }
  6481. else
  6482. {
  6483. perf->byteAvailSndBuf = 0;
  6484. perf->byteAvailRcvBuf = 0;
  6485. perf->pktSndBuf = 0;
  6486. perf->byteSndBuf = 0;
  6487. perf->msSndBuf = 0;
  6488. perf->byteRcvBuf = 0;
  6489. perf->msRcvBuf = 0;
  6490. }
  6491. }
  6492. bool srt::CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg)
  6493. {
  6494. // Special things that must be done HERE, not in SrtCongestion,
  6495. // because it involves the input buffer in CUDT. It would be
  6496. // slightly dangerous to give SrtCongestion access to it.
  6497. // According to the rules, the congctl should be ready at the same
  6498. // time when the sending buffer. For sanity check, check both first.
  6499. if (!m_CongCtl.ready() || !m_pSndBuffer)
  6500. {
  6501. LOGC(rslog.Error,
  6502. log << CONID() << "updateCC: CAN'T DO UPDATE - congctl " << (m_CongCtl.ready() ? "ready" : "NOT READY")
  6503. << "; sending buffer " << (m_pSndBuffer ? "NOT CREATED" : "created"));
  6504. return false;
  6505. }
  6506. HLOGC(rslog.Debug, log << CONID() << "updateCC: EVENT:" << TransmissionEventStr(evt));
  6507. if (evt == TEV_INIT)
  6508. {
  6509. // only_input uses:
  6510. // 0: in the beginning and when SRTO_MAXBW was changed
  6511. // 1: SRTO_INPUTBW was changed
  6512. // 2: SRTO_OHEADBW was changed
  6513. EInitEvent only_input = arg.get<EventVariant::INIT>();
  6514. // false = TEV_INIT_RESET: in the beginning, or when MAXBW was changed.
  6515. if (only_input != TEV_INIT_RESET && m_config.llMaxBW)
  6516. {
  6517. HLOGC(rslog.Debug, log << CONID() << "updateCC/TEV_INIT: non-RESET stage and m_config.llMaxBW already set to " << m_config.llMaxBW);
  6518. // Don't change
  6519. }
  6520. else // either m_config.llMaxBW == 0 or only_input == TEV_INIT_RESET
  6521. {
  6522. // Use the values:
  6523. // - if SRTO_MAXBW is >0, use it.
  6524. // - if SRTO_MAXBW == 0, use SRTO_INPUTBW + SRTO_OHEADBW
  6525. // - if SRTO_INPUTBW == 0, pass 0 to requst in-buffer sampling
  6526. // Bytes/s
  6527. const int64_t bw = m_config.llMaxBW != 0 ? m_config.llMaxBW : // When used SRTO_MAXBW
  6528. m_config.llInputBW != 0 ? withOverhead(m_config.llInputBW) : // SRTO_INPUTBW + SRT_OHEADBW
  6529. 0; // When both MAXBW and INPUTBW are 0, request in-buffer sampling
  6530. // Note: setting bw == 0 uses BW_INFINITE value in LiveCC
  6531. m_CongCtl->updateBandwidth(m_config.llMaxBW, bw);
  6532. if (only_input == TEV_INIT_OHEADBW)
  6533. {
  6534. // On updated SRTO_OHEADBW don't change input rate.
  6535. // This only influences the call to withOverhead().
  6536. }
  6537. else
  6538. {
  6539. // No need to calculate input rate if the bandwidth is set
  6540. const bool disable_in_rate_calc = (bw != 0);
  6541. m_pSndBuffer->resetInputRateSmpPeriod(disable_in_rate_calc);
  6542. }
  6543. HLOGC(rslog.Debug,
  6544. log << CONID() << "updateCC/TEV_INIT: updating BW=" << m_config.llMaxBW
  6545. << (only_input == TEV_INIT_RESET
  6546. ? " (UNCHANGED)"
  6547. : only_input == TEV_INIT_OHEADBW ? " (only Overhead)" : " (updated sampling rate)"));
  6548. }
  6549. }
  6550. // This part is also required only by LiveCC, however not
  6551. // moved there due to that it needs access to CSndBuffer.
  6552. if (evt == TEV_ACK || evt == TEV_LOSSREPORT || evt == TEV_CHECKTIMER || evt == TEV_SYNC)
  6553. {
  6554. // Specific part done when MaxBW is set to 0 (auto) and InputBW is 0.
  6555. // This requests internal input rate sampling.
  6556. if (m_config.llMaxBW == 0 && m_config.llInputBW == 0)
  6557. {
  6558. // Get auto-calculated input rate, Bytes per second
  6559. const int64_t inputbw = m_pSndBuffer->getInputRate();
  6560. /*
  6561. * On blocked transmitter (tx full) and until connection closes,
  6562. * auto input rate falls to 0 but there may be still lot of packet to retransmit
  6563. * Calling updateBandwidth with 0 sets maxBW to default BW_INFINITE (1 Gbps)
  6564. * and sendrate skyrockets for retransmission.
  6565. * Keep previously set maximum in that case (inputbw == 0).
  6566. */
  6567. if (inputbw >= 0)
  6568. m_CongCtl->updateBandwidth(0, withOverhead(std::max(m_config.llMinInputBW, inputbw))); // Bytes/sec
  6569. }
  6570. }
  6571. HLOGC(rslog.Debug, log << CONID() << "updateCC: emitting signal for EVENT:" << TransmissionEventStr(evt));
  6572. // Now execute a congctl-defined action for that event.
  6573. EmitSignal(evt, arg);
  6574. // This should be done with every event except ACKACK and SEND/RECEIVE
  6575. // After any action was done by the congctl, update the congestion window and sending interval.
  6576. if (evt != TEV_ACKACK && evt != TEV_SEND && evt != TEV_RECEIVE)
  6577. {
  6578. // This part comes from original UDT.
  6579. // NOTE: THESE things come from CCC class:
  6580. // - m_dPktSndPeriod
  6581. // - m_dCWndSize
  6582. m_tdSendInterval = microseconds_from((int64_t)m_CongCtl->pktSndPeriod_us());
  6583. m_dCongestionWindow = m_CongCtl->cgWindowSize();
  6584. #if ENABLE_HEAVY_LOGGING
  6585. HLOGC(rslog.Debug,
  6586. log << CONID() << "updateCC: updated values from congctl: interval=" << count_microseconds(m_tdSendInterval) << " us ("
  6587. << "tk (" << m_CongCtl->pktSndPeriod_us() << "us) cgwindow="
  6588. << std::setprecision(3) << m_dCongestionWindow);
  6589. #endif
  6590. }
  6591. HLOGC(rslog.Debug, log << CONID() << "udpateCC: finished handling for EVENT:" << TransmissionEventStr(evt));
  6592. return true;
  6593. }
  6594. void srt::CUDT::initSynch()
  6595. {
  6596. setupMutex(m_SendBlockLock, "SendBlock");
  6597. setupCond(m_SendBlockCond, "SendBlock");
  6598. setupCond(m_RecvDataCond, "RecvData");
  6599. setupMutex(m_SendLock, "Send");
  6600. setupMutex(m_RecvLock, "Recv");
  6601. setupMutex(m_RcvLossLock, "RcvLoss");
  6602. setupMutex(m_RecvAckLock, "RecvAck");
  6603. setupMutex(m_RcvBufferLock, "RcvBuffer");
  6604. setupMutex(m_ConnectionLock, "Connection");
  6605. setupMutex(m_StatsLock, "Stats");
  6606. setupCond(m_RcvTsbPdCond, "RcvTsbPd");
  6607. }
  6608. void srt::CUDT::destroySynch()
  6609. {
  6610. releaseMutex(m_SendBlockLock);
  6611. // Just in case, signal the CV, on which some
  6612. // other thread is possibly waiting, because a
  6613. // process hanging on a pthread_cond_wait would
  6614. // cause the call to destroy a CV hang up.
  6615. m_SendBlockCond.notify_all();
  6616. releaseCond(m_SendBlockCond);
  6617. m_RecvDataCond.notify_all();
  6618. releaseCond(m_RecvDataCond);
  6619. releaseMutex(m_SendLock);
  6620. releaseMutex(m_RecvLock);
  6621. releaseMutex(m_RcvLossLock);
  6622. releaseMutex(m_RecvAckLock);
  6623. releaseMutex(m_RcvBufferLock);
  6624. releaseMutex(m_ConnectionLock);
  6625. releaseMutex(m_StatsLock);
  6626. m_RcvTsbPdCond.notify_all();
  6627. releaseCond(m_RcvTsbPdCond);
  6628. }
  6629. void srt::CUDT::releaseSynch()
  6630. {
  6631. SRT_ASSERT(m_bClosing);
  6632. // wake up user calls
  6633. CSync::lock_notify_one(m_SendBlockCond, m_SendBlockLock);
  6634. enterCS(m_SendLock);
  6635. leaveCS(m_SendLock);
  6636. // Awake tsbpd() and srt_recv*(..) threads for them to check m_bClosing.
  6637. CSync::lock_notify_one(m_RecvDataCond, m_RecvLock);
  6638. CSync::lock_notify_one(m_RcvTsbPdCond, m_RecvLock);
  6639. // Azquiring m_RcvTsbPdStartupLock protects race in starting
  6640. // the tsbpd() thread in CUDT::processData().
  6641. // Wait for tsbpd() thread to finish.
  6642. enterCS(m_RcvTsbPdStartupLock);
  6643. if (m_RcvTsbPdThread.joinable())
  6644. {
  6645. m_RcvTsbPdThread.join();
  6646. }
  6647. leaveCS(m_RcvTsbPdStartupLock);
  6648. // Acquiring the m_RecvLock it is assumed that both tsbpd()
  6649. // and srt_recv*(..) threads will be aware about the state of m_bClosing.
  6650. enterCS(m_RecvLock);
  6651. leaveCS(m_RecvLock);
  6652. }
  6653. #if ENABLE_BONDING
  6654. void srt::CUDT::dropToGroupRecvBase()
  6655. {
  6656. int32_t group_recv_base = SRT_SEQNO_NONE;
  6657. if (m_parent->m_GroupOf)
  6658. {
  6659. // Check is first done before locking to avoid unnecessary
  6660. // mutex locking. The condition for this field is that it
  6661. // can be either never set, already reset, or ever set
  6662. // and possibly dangling. The re-check after lock eliminates
  6663. // the dangling case.
  6664. ScopedLock glock (uglobal().m_GlobControlLock);
  6665. // Note that getRcvBaseSeqNo() will lock m_GroupOf->m_GroupLock,
  6666. // but this is an intended order.
  6667. if (m_parent->m_GroupOf)
  6668. group_recv_base = m_parent->m_GroupOf->getRcvBaseSeqNo();
  6669. }
  6670. if (group_recv_base == SRT_SEQNO_NONE)
  6671. return;
  6672. ScopedLock lck(m_RcvBufferLock);
  6673. int cnt = rcvDropTooLateUpTo(CSeqNo::incseq(group_recv_base));
  6674. if (cnt > 0)
  6675. {
  6676. HLOGC(grlog.Debug,
  6677. log << CONID() << "dropToGroupRecvBase: dropped " << cnt << " packets before ACK: group_recv_base="
  6678. << group_recv_base << " m_iRcvLastAck=" << m_iRcvLastAck
  6679. << " m_iRcvCurrSeqNo=" << m_iRcvCurrSeqNo << " m_bTsbPd=" << m_bTsbPd);
  6680. }
  6681. }
  6682. #endif
  6683. namespace srt {
  6684. #if ENABLE_HEAVY_LOGGING
  6685. static void DebugAck(string hdr, int prev, int ack)
  6686. {
  6687. if (!prev)
  6688. {
  6689. HLOGC(xtlog.Debug, log << hdr << "ACK " << ack);
  6690. return;
  6691. }
  6692. int diff = CSeqNo::seqoff(prev, ack);
  6693. if (diff < 0)
  6694. {
  6695. HLOGC(xtlog.Debug, log << hdr << "ACK ERROR: " << prev << "-" << ack << "(diff " << diff << ")");
  6696. return;
  6697. }
  6698. bool shorted = diff > 100; // sanity
  6699. if (shorted)
  6700. ack = CSeqNo::incseq(prev, 100);
  6701. ostringstream ackv;
  6702. for (; prev != ack; prev = CSeqNo::incseq(prev))
  6703. ackv << prev << " ";
  6704. if (shorted)
  6705. ackv << "...";
  6706. HLOGC(xtlog.Debug, log << hdr << "ACK (" << (diff + 1) << "): " << ackv.str() << ack);
  6707. }
  6708. #else
  6709. static inline void DebugAck(string, int, int) {}
  6710. #endif
  6711. }
  6712. void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rparam, int size)
  6713. {
  6714. CPacket ctrlpkt;
  6715. setPacketTS(ctrlpkt, steady_clock::now());
  6716. int nbsent = 0;
  6717. switch (pkttype)
  6718. {
  6719. case UMSG_ACK: // 010 - Acknowledgement
  6720. {
  6721. nbsent = sendCtrlAck(ctrlpkt, size);
  6722. break;
  6723. }
  6724. case UMSG_ACKACK: // 110 - Acknowledgement of Acknowledgement
  6725. ctrlpkt.pack(pkttype, lparam);
  6726. ctrlpkt.m_iID = m_PeerID;
  6727. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6728. break;
  6729. case UMSG_LOSSREPORT: // 011 - Loss Report
  6730. {
  6731. // Explicitly defined lost sequences
  6732. if (rparam)
  6733. {
  6734. int32_t *lossdata = (int32_t *)rparam;
  6735. size_t bytes = sizeof(*lossdata) * size;
  6736. ctrlpkt.pack(pkttype, NULL, lossdata, bytes);
  6737. ctrlpkt.m_iID = m_PeerID;
  6738. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6739. enterCS(m_StatsLock);
  6740. m_stats.rcvr.sentNak.count(1);
  6741. leaveCS(m_StatsLock);
  6742. }
  6743. // Call with no arguments - get loss list from internal data.
  6744. else if (m_pRcvLossList->getLossLength() > 0)
  6745. {
  6746. ScopedLock lock(m_RcvLossLock);
  6747. // this is periodically NAK report; make sure NAK cannot be sent back too often
  6748. // read loss list from the local receiver loss list
  6749. int32_t *data = new int32_t[m_iMaxSRTPayloadSize / 4];
  6750. int losslen;
  6751. m_pRcvLossList->getLossArray(data, losslen, m_iMaxSRTPayloadSize / 4);
  6752. if (0 < losslen)
  6753. {
  6754. ctrlpkt.pack(pkttype, NULL, data, losslen * 4);
  6755. ctrlpkt.m_iID = m_PeerID;
  6756. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6757. enterCS(m_StatsLock);
  6758. m_stats.rcvr.sentNak.count(1);
  6759. leaveCS(m_StatsLock);
  6760. }
  6761. delete[] data;
  6762. }
  6763. // update next NAK time, which should wait enough time for the retansmission, but not too long
  6764. m_tdNAKInterval = microseconds_from(m_iSRTT + 4 * m_iRTTVar);
  6765. // Fix the NAKreport period according to the congctl
  6766. m_tdNAKInterval =
  6767. microseconds_from(m_CongCtl->updateNAKInterval(count_microseconds(m_tdNAKInterval),
  6768. m_RcvTimeWindow.getPktRcvSpeed(),
  6769. m_pRcvLossList->getLossLength()));
  6770. // This is necessary because a congctl need not wish to define
  6771. // its own minimum interval, in which case the default one is used.
  6772. if (m_tdNAKInterval < m_tdMinNakInterval)
  6773. m_tdNAKInterval = m_tdMinNakInterval;
  6774. break;
  6775. }
  6776. case UMSG_CGWARNING: // 100 - Congestion Warning
  6777. ctrlpkt.pack(pkttype);
  6778. ctrlpkt.m_iID = m_PeerID;
  6779. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6780. m_tsLastWarningTime = steady_clock::now();
  6781. break;
  6782. case UMSG_KEEPALIVE: // 001 - Keep-alive
  6783. ctrlpkt.pack(pkttype);
  6784. ctrlpkt.m_iID = m_PeerID;
  6785. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6786. break;
  6787. case UMSG_HANDSHAKE: // 000 - Handshake
  6788. ctrlpkt.pack(pkttype, NULL, rparam, sizeof(CHandShake));
  6789. ctrlpkt.m_iID = m_PeerID;
  6790. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6791. break;
  6792. case UMSG_SHUTDOWN: // 101 - Shutdown
  6793. if (m_PeerID == 0) // Dont't send SHUTDOWN if we don't know peer ID.
  6794. break;
  6795. ctrlpkt.pack(pkttype);
  6796. ctrlpkt.m_iID = m_PeerID;
  6797. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6798. break;
  6799. case UMSG_DROPREQ: // 111 - Msg drop request
  6800. ctrlpkt.pack(pkttype, lparam, rparam, 8);
  6801. ctrlpkt.m_iID = m_PeerID;
  6802. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6803. break;
  6804. case UMSG_PEERERROR: // 1000 - acknowledge the peer side a special error
  6805. ctrlpkt.pack(pkttype, lparam);
  6806. ctrlpkt.m_iID = m_PeerID;
  6807. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6808. break;
  6809. case UMSG_EXT: // 0x7FFF - Resevered for future use
  6810. break;
  6811. default:
  6812. break;
  6813. }
  6814. // Fix keepalive
  6815. if (nbsent)
  6816. m_tsLastSndTime.store(steady_clock::now());
  6817. }
  6818. // [[using locked(m_RcvBufferLock)]]
  6819. bool srt::CUDT::getFirstNoncontSequence(int32_t& w_seq, string& w_log_reason)
  6820. {
  6821. {
  6822. ScopedLock losslock (m_RcvLossLock);
  6823. const int32_t seq = m_pRcvLossList->getFirstLostSeq();
  6824. if (seq != SRT_SEQNO_NONE)
  6825. {
  6826. HLOGC(xtlog.Debug, log << "NONCONT-SEQUENCE: first loss %" << seq << " (loss len=" <<
  6827. m_pRcvLossList->getLossLength() << ")");
  6828. w_seq = seq;
  6829. w_log_reason = "first lost";
  6830. return true;
  6831. }
  6832. }
  6833. w_seq = CSeqNo::incseq(m_iRcvCurrSeqNo);
  6834. HLOGC(xtlog.Debug, log << "NONCONT-SEQUENCE: past-recv %" << w_seq);
  6835. w_log_reason = "expected next";
  6836. return true;
  6837. }
  6838. int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)
  6839. {
  6840. SRT_ASSERT(ctrlpkt.getMsgTimeStamp() != 0);
  6841. int nbsent = 0;
  6842. int local_prevack = 0;
  6843. #if ENABLE_HEAVY_LOGGING
  6844. struct SaveBack
  6845. {
  6846. int& target;
  6847. const int& source;
  6848. ~SaveBack() { target = source; }
  6849. } l_saveback = { m_iDebugPrevLastAck, m_iRcvLastAck };
  6850. (void)l_saveback; // kill compiler warning: unused variable `l_saveback` [-Wunused-variable]
  6851. local_prevack = m_iDebugPrevLastAck;
  6852. #endif
  6853. string reason; // just for "a reason" of giving particular % for ACK
  6854. #if ENABLE_BONDING
  6855. dropToGroupRecvBase();
  6856. #endif
  6857. // The TSBPD thread may change the first lost sequence record (TLPKTDROP).
  6858. // To avoid it the m_RcvBufferLock has to be acquired.
  6859. UniqueLock bufflock(m_RcvBufferLock);
  6860. // The full ACK should be sent to indicate there is now available space in the RCV buffer
  6861. // since the last full ACK. It should unblock the sender to proceed further.
  6862. const bool bNeedFullAck = (m_bBufferWasFull && getAvailRcvBufferSizeNoLock() > 0);
  6863. int32_t ack; // First unacknowledged packet sequence number (acknowledge up to ack).
  6864. if (!getFirstNoncontSequence((ack), (reason)))
  6865. return nbsent;
  6866. if (m_iRcvLastAckAck == ack && !bNeedFullAck)
  6867. {
  6868. HLOGC(xtlog.Debug,
  6869. log << CONID() << "sendCtrl(UMSG_ACK): last ACK %" << ack << "(" << reason << ") == last ACKACK");
  6870. return nbsent;
  6871. }
  6872. // send out a lite ACK
  6873. // to save time on buffer processing and bandwidth/AS measurement, a lite ACK only feeds back an ACK number
  6874. if (size == SEND_LITE_ACK && !bNeedFullAck)
  6875. {
  6876. bufflock.unlock();
  6877. ctrlpkt.pack(UMSG_ACK, NULL, &ack, size);
  6878. ctrlpkt.m_iID = m_PeerID;
  6879. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  6880. DebugAck(CONID() + "sendCtrl(lite): ", local_prevack, ack);
  6881. return nbsent;
  6882. }
  6883. // IF ack %> m_iRcvLastAck
  6884. // There are new received packets to acknowledge, update related information.
  6885. if (CSeqNo::seqcmp(ack, m_iRcvLastAck) > 0)
  6886. {
  6887. // Sanity check if the "selected ACK" points to a sequence
  6888. // in the past for the buffer. This SHOULD NEVER HAPPEN because
  6889. // on drop the loss records should have been removed, and the last received
  6890. // sequence also can't be in the past towards the buffer.
  6891. // NOTE: This problem has been observed when the packet sequence
  6892. // was incorrectly removed from the receiver loss list. This should
  6893. // then stay here as a condition in order to detect this problem,
  6894. // should it happen in the future.
  6895. if (CSeqNo::seqcmp(ack, m_pRcvBuffer->getStartSeqNo()) < 0)
  6896. {
  6897. LOGC(xtlog.Error,
  6898. log << CONID() << "sendCtrlAck: IPE: invalid ACK from %" << m_iRcvLastAck << " to %" << ack << " ("
  6899. << CSeqNo::seqoff(m_iRcvLastAck, ack) << " packets) buffer=%" << m_pRcvBuffer->getStartSeqNo());
  6900. }
  6901. else
  6902. {
  6903. HLOGC(xtlog.Debug,
  6904. log << CONID() << "sendCtrlAck: %" << m_iRcvLastAck << " -> %" << ack << " ("
  6905. << CSeqNo::seqoff(m_iRcvLastAck, ack) << " packets)");
  6906. }
  6907. m_iRcvLastAck = ack;
  6908. #if ENABLE_BONDING
  6909. const int32_t group_read_seq = m_pRcvBuffer->getFirstReadablePacketInfo(steady_clock::now()).seqno;
  6910. #endif
  6911. InvertedLock un_bufflock (m_RcvBufferLock);
  6912. #if ENABLE_BONDING
  6913. // This actually should be done immediately after the ACK pointers were
  6914. // updated in this socket, but it can't be done inside this function due
  6915. // to being run under a lock.
  6916. // At this moment no locks are applied. The only lock used so far
  6917. // was m_RcvBufferLock, but this was lifed above. At this moment
  6918. // it is safe to apply any locks here. This function is affined
  6919. // to CRcvQueue::worker thread, so it is free to apply locks as
  6920. // required in the defined order. At present we only need the lock
  6921. // on m_GlobControlLock to prevent the group from being deleted
  6922. // in the meantime
  6923. if (m_parent->m_GroupOf)
  6924. {
  6925. // Check is first done before locking to avoid unnecessary
  6926. // mutex locking. The condition for this field is that it
  6927. // can be either never set, already reset, or ever set
  6928. // and possibly dangling. The re-check after lock eliminates
  6929. // the dangling case.
  6930. ScopedLock glock (uglobal().m_GlobControlLock);
  6931. // Note that updateLatestRcv will lock m_GroupOf->m_GroupLock,
  6932. // but this is an intended order.
  6933. if (m_parent->m_GroupOf)
  6934. {
  6935. // A group may need to update the parallelly used idle links,
  6936. // should it have any. Pass the current socket position in order
  6937. // to skip it from the group loop.
  6938. m_parent->m_GroupOf->updateLatestRcv(m_parent);
  6939. }
  6940. }
  6941. #endif
  6942. // If TSBPD is enabled, then INSTEAD OF signaling m_RecvDataCond,
  6943. // signal m_RcvTsbPdCond. This will kick in the tsbpd thread, which
  6944. // will signal m_RecvDataCond when there's time to play for particular
  6945. // data packet.
  6946. HLOGC(xtlog.Debug,
  6947. log << CONID() << "ACK: clip %" << m_iRcvLastAck << "-%" << ack << ", REVOKED "
  6948. << CSeqNo::seqoff(ack, m_iRcvLastAck) << " from RCV buffer");
  6949. if (m_bTsbPd)
  6950. {
  6951. /* Newly acknowledged data, signal TsbPD thread */
  6952. CUniqueSync tslcc (m_RecvLock, m_RcvTsbPdCond);
  6953. // m_bTsbPdAckWakeup is protected by m_RecvLock in the tsbpd() thread
  6954. if (m_bTsbPdAckWakeup)
  6955. tslcc.notify_one();
  6956. }
  6957. else
  6958. {
  6959. {
  6960. CUniqueSync rdcc (m_RecvLock, m_RecvDataCond);
  6961. // Locks m_RcvBufferLock, which is unlocked above by InvertedLock un_bufflock.
  6962. // Must check read-readiness under m_RecvLock to protect the epoll from concurrent changes in readBuffer()
  6963. if (isRcvBufferReady())
  6964. {
  6965. if (m_config.bSynRecving)
  6966. {
  6967. // signal a waiting "recv" call if there is any data available
  6968. rdcc.notify_one();
  6969. }
  6970. // acknowledge any waiting epolls to read
  6971. // fix SRT_EPOLL_IN event loss but rcvbuffer still have data:
  6972. // 1. user call receive/receivemessage(about line number:6482)
  6973. // 2. after read/receive, if rcvbuffer is empty, will set SRT_EPOLL_IN event to false
  6974. // 3. but if we do not do some lock work here, will cause some sync problems between threads:
  6975. // (1) user thread: call receive/receivemessage
  6976. // (2) user thread: read data
  6977. // (3) user thread: no data in rcvbuffer, set SRT_EPOLL_IN event to false
  6978. // (4) receive thread: receive data and set SRT_EPOLL_IN to true
  6979. // (5) user thread: set SRT_EPOLL_IN to false
  6980. // 4. so , m_RecvLock must be used here to protect epoll event
  6981. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true);
  6982. }
  6983. }
  6984. #if ENABLE_BONDING
  6985. if (group_read_seq != SRT_SEQNO_NONE && m_parent->m_GroupOf)
  6986. {
  6987. // See above explanation for double-checking
  6988. ScopedLock glock (uglobal().m_GlobControlLock);
  6989. if (m_parent->m_GroupOf)
  6990. {
  6991. // The current "APP reader" needs to simply decide as to whether
  6992. // the next CUDTGroup::recv() call should return with no blocking or not.
  6993. // When the group is read-ready, it should update its pollers as it sees fit.
  6994. m_parent->m_GroupOf->updateReadState(m_SocketID, group_read_seq);
  6995. }
  6996. }
  6997. #endif
  6998. CGlobEvent::triggerEvent();
  6999. }
  7000. }
  7001. else if (ack == m_iRcvLastAck && !bNeedFullAck)
  7002. {
  7003. // If the ACK was just sent already AND elapsed time did not exceed RTT,
  7004. if ((steady_clock::now() - m_tsLastAckTime) <
  7005. (microseconds_from(m_iSRTT + 4 * m_iRTTVar)))
  7006. {
  7007. HLOGC(xtlog.Debug,
  7008. log << CONID() << "sendCtrl(UMSG_ACK): ACK %" << ack << " just sent - too early to repeat");
  7009. return nbsent;
  7010. }
  7011. }
  7012. else if (!bNeedFullAck)
  7013. {
  7014. // Not possible (m_iRcvCurrSeqNo+1 <% m_iRcvLastAck ?)
  7015. LOGC(xtlog.Error, log << CONID() << "sendCtrl(UMSG_ACK): IPE: curr %" << ack << " <% last %" << m_iRcvLastAck);
  7016. return nbsent;
  7017. }
  7018. // [[using assert( ack >= m_iRcvLastAck && is_periodic_ack ) ]];
  7019. // [[using locked(m_RcvBufferLock)]];
  7020. // Send out the ACK only if has not been received by the sender before
  7021. if (CSeqNo::seqcmp(m_iRcvLastAck, m_iRcvLastAckAck) > 0 || bNeedFullAck)
  7022. {
  7023. // NOTE: The BSTATS feature turns on extra fields above size 6
  7024. // also known as ACKD_TOTAL_SIZE_VER100.
  7025. int32_t data[ACKD_TOTAL_SIZE];
  7026. // Case you care, CAckNo::incack does exactly the same thing as
  7027. // CSeqNo::incseq. Logically the ACK number is a different thing
  7028. // than sequence number (it's a "journal" for ACK request-response,
  7029. // and starts from 0, unlike sequence, which starts from a random
  7030. // number), but still the numbers are from exactly the same domain.
  7031. m_iAckSeqNo = CAckNo::incack(m_iAckSeqNo);
  7032. data[ACKD_RCVLASTACK] = m_iRcvLastAck;
  7033. data[ACKD_RTT] = m_iSRTT;
  7034. data[ACKD_RTTVAR] = m_iRTTVar;
  7035. data[ACKD_BUFFERLEFT] = (int) getAvailRcvBufferSizeNoLock();
  7036. m_bBufferWasFull = data[ACKD_BUFFERLEFT] == 0;
  7037. if (steady_clock::now() - m_tsLastAckTime > m_tdACKInterval)
  7038. {
  7039. int rcvRate;
  7040. int ctrlsz = ACKD_TOTAL_SIZE_UDTBASE * ACKD_FIELD_SIZE; // Minimum required size
  7041. data[ACKD_RCVSPEED] = m_RcvTimeWindow.getPktRcvSpeed((rcvRate));
  7042. data[ACKD_BANDWIDTH] = m_RcvTimeWindow.getBandwidth();
  7043. //>>Patch while incompatible (1.0.2) receiver floating around
  7044. if (m_uPeerSrtVersion == SrtVersion(1, 0, 2))
  7045. {
  7046. data[ACKD_RCVRATE] = rcvRate; // bytes/sec
  7047. data[ACKD_XMRATE_VER102_ONLY] = data[ACKD_BANDWIDTH] * m_iMaxSRTPayloadSize; // bytes/sec
  7048. ctrlsz = ACKD_FIELD_SIZE * ACKD_TOTAL_SIZE_VER102_ONLY;
  7049. }
  7050. else if (m_uPeerSrtVersion >= SrtVersion(1, 0, 3))
  7051. {
  7052. // Normal, currently expected version.
  7053. data[ACKD_RCVRATE] = rcvRate; // bytes/sec
  7054. ctrlsz = ACKD_FIELD_SIZE * ACKD_TOTAL_SIZE_VER101;
  7055. }
  7056. // ELSE: leave the buffer with ...UDTBASE size.
  7057. ctrlpkt.pack(UMSG_ACK, &m_iAckSeqNo, data, ctrlsz);
  7058. m_tsLastAckTime = steady_clock::now();
  7059. }
  7060. else
  7061. {
  7062. ctrlpkt.pack(UMSG_ACK, &m_iAckSeqNo, data, ACKD_FIELD_SIZE * ACKD_TOTAL_SIZE_SMALL);
  7063. }
  7064. ctrlpkt.m_iID = m_PeerID;
  7065. setPacketTS(ctrlpkt, steady_clock::now());
  7066. nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);
  7067. DebugAck(CONID() + "sendCtrl(UMSG_ACK): ", local_prevack, ack);
  7068. m_ACKWindow.store(m_iAckSeqNo, m_iRcvLastAck);
  7069. enterCS(m_StatsLock);
  7070. m_stats.rcvr.sentAck.count(1);
  7071. leaveCS(m_StatsLock);
  7072. }
  7073. else
  7074. {
  7075. HLOGC(xtlog.Debug, log << CONID() << "sendCtrl(UMSG_ACK): " << "ACK %" << m_iRcvLastAck
  7076. << " <=% ACKACK %" << m_iRcvLastAckAck << " - NOT SENDING ACK");
  7077. }
  7078. return nbsent;
  7079. }
  7080. void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno)
  7081. {
  7082. #if ENABLE_BONDING
  7083. // This is for the call of CSndBuffer::getMsgNoAt that returns
  7084. // this value as a notfound-trap.
  7085. int32_t msgno_at_last_acked_seq = SRT_MSGNO_CONTROL;
  7086. bool is_group = m_parent->m_GroupOf;
  7087. #endif
  7088. // Update sender's loss list and acknowledge packets in the sender's buffer
  7089. {
  7090. // m_RecvAckLock protects sender's loss list and epoll
  7091. ScopedLock ack_lock(m_RecvAckLock);
  7092. const int offset = CSeqNo::seqoff(m_iSndLastDataAck, ackdata_seqno);
  7093. // IF distance between m_iSndLastDataAck and ack is nonempty...
  7094. if (offset <= 0)
  7095. return;
  7096. // update sending variables
  7097. m_iSndLastDataAck = ackdata_seqno;
  7098. #if ENABLE_BONDING
  7099. if (is_group)
  7100. {
  7101. // Get offset-1 because 'offset' points actually to past-the-end
  7102. // of the sender buffer. We have already checked that offset is
  7103. // at least 1.
  7104. msgno_at_last_acked_seq = m_pSndBuffer->getMsgNoAt(offset-1);
  7105. // Just keep this value prepared; it can't be updated exactly right
  7106. // now because accessing the group needs some locks to be applied
  7107. // with preserved the right locking order.
  7108. }
  7109. #endif
  7110. // remove any loss that predates 'ack' (not to be considered loss anymore)
  7111. m_pSndLossList->removeUpTo(CSeqNo::decseq(m_iSndLastDataAck));
  7112. // acknowledge the sending buffer (remove data that predate 'ack')
  7113. m_pSndBuffer->ackData(offset);
  7114. // acknowledde any waiting epolls to write
  7115. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true);
  7116. CGlobEvent::triggerEvent();
  7117. }
  7118. #if ENABLE_BONDING
  7119. if (is_group)
  7120. {
  7121. // m_RecvAckLock is ordered AFTER m_GlobControlLock, so this can only
  7122. // be done now that m_RecvAckLock is unlocked.
  7123. ScopedLock glock (uglobal().m_GlobControlLock);
  7124. if (m_parent->m_GroupOf)
  7125. {
  7126. HLOGC(inlog.Debug, log << CONID() << "ACK: acking group sender buffer for #" << msgno_at_last_acked_seq);
  7127. // Guard access to m_iSndAckedMsgNo field
  7128. // Note: This can't be done inside CUDTGroup::ackMessage
  7129. // because this function is also called from CUDT::sndDropTooLate
  7130. // called from CUDT::sendmsg2 called from CUDTGroup::send, which
  7131. // applies the lock on m_GroupLock already.
  7132. ScopedLock glk (*m_parent->m_GroupOf->exp_groupLock());
  7133. // NOTE: ackMessage also accepts and ignores the trap representation
  7134. // which is SRT_MSGNO_CONTROL.
  7135. m_parent->m_GroupOf->ackMessage(msgno_at_last_acked_seq);
  7136. }
  7137. }
  7138. #endif
  7139. // insert this socket to snd list if it is not on the list yet
  7140. const steady_clock::time_point currtime = steady_clock::now();
  7141. m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE, currtime);
  7142. if (m_config.bSynSending)
  7143. {
  7144. CSync::lock_notify_one(m_SendBlockCond, m_SendBlockLock);
  7145. }
  7146. // record total time used for sending
  7147. enterCS(m_StatsLock);
  7148. m_stats.sndDuration += count_microseconds(currtime - m_stats.sndDurationCounter);
  7149. m_stats.m_sndDurationTotal += count_microseconds(currtime - m_stats.sndDurationCounter);
  7150. m_stats.sndDurationCounter = currtime;
  7151. leaveCS(m_StatsLock);
  7152. }
  7153. void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point& currtime)
  7154. {
  7155. const int32_t* ackdata = (const int32_t*)ctrlpkt.m_pcData;
  7156. const int32_t ackdata_seqno = ackdata[ACKD_RCVLASTACK];
  7157. // Check the value of ACK in case when it was some rogue peer
  7158. if (ackdata_seqno < 0)
  7159. {
  7160. // This embraces all cases when the most significant bit is set,
  7161. // as the variable is of a signed type. So, SRT_SEQNO_NONE is
  7162. // included, but it also triggers for any other kind of invalid value.
  7163. // This check MUST BE DONE before making any operation on this number.
  7164. LOGC(inlog.Error, log << CONID() << "ACK: IPE/EPE: received invalid ACK value: " << ackdata_seqno
  7165. << " " << std::hex << ackdata_seqno << " (IGNORED)");
  7166. return;
  7167. }
  7168. const bool isLiteAck = ctrlpkt.getLength() == (size_t)SEND_LITE_ACK;
  7169. HLOGC(inlog.Debug,
  7170. log << CONID() << "ACK covers: " << m_iSndLastDataAck << " - " << ackdata_seqno << " [ACK=" << m_iSndLastAck
  7171. << "]" << (isLiteAck ? "[LITE]" : "[FULL]"));
  7172. updateSndLossListOnACK(ackdata_seqno);
  7173. // Process a lite ACK
  7174. if (isLiteAck)
  7175. {
  7176. if (CSeqNo::seqcmp(ackdata_seqno, m_iSndLastAck) >= 0)
  7177. {
  7178. ScopedLock ack_lock(m_RecvAckLock);
  7179. m_iFlowWindowSize = m_iFlowWindowSize - CSeqNo::seqoff(m_iSndLastAck, ackdata_seqno);
  7180. m_iSndLastAck = ackdata_seqno;
  7181. m_tsLastRspAckTime = currtime;
  7182. m_iReXmitCount = 1; // Reset re-transmit count since last ACK
  7183. }
  7184. return;
  7185. }
  7186. // Decide to send ACKACK or not
  7187. {
  7188. // Sequence number of the ACK packet
  7189. const int32_t ack_seqno = ctrlpkt.getAckSeqNo();
  7190. // Send ACK acknowledgement (UMSG_ACKACK).
  7191. // There can be less ACKACK packets in the stream, than the number of ACK packets.
  7192. // Only send ACKACK every syn interval or if ACK packet with the sequence number
  7193. // already acknowledged (with ACKACK) has come again, which probably means ACKACK was lost.
  7194. if ((currtime - m_SndLastAck2Time > microseconds_from(COMM_SYN_INTERVAL_US)) || (ack_seqno == m_iSndLastAck2))
  7195. {
  7196. sendCtrl(UMSG_ACKACK, &ack_seqno);
  7197. m_iSndLastAck2 = ack_seqno;
  7198. m_SndLastAck2Time = currtime;
  7199. }
  7200. }
  7201. //
  7202. // Begin of the new code with TLPKTDROP.
  7203. //
  7204. // Protect packet retransmission
  7205. {
  7206. ScopedLock ack_lock(m_RecvAckLock);
  7207. // Check the validation of the ack
  7208. if (CSeqNo::seqcmp(ackdata_seqno, CSeqNo::incseq(m_iSndCurrSeqNo)) > 0)
  7209. {
  7210. // this should not happen: attack or bug
  7211. LOGC(gglog.Error,
  7212. log << CONID() << "ATTACK/IPE: incoming ack seq " << ackdata_seqno << " exceeds current "
  7213. << m_iSndCurrSeqNo << " by " << (CSeqNo::seqoff(m_iSndCurrSeqNo, ackdata_seqno) - 1) << "!");
  7214. m_bBroken = true;
  7215. m_iBrokenCounter = 0;
  7216. return;
  7217. }
  7218. if (CSeqNo::seqcmp(ackdata_seqno, m_iSndLastAck) >= 0)
  7219. {
  7220. const int cwnd1 = std::min(int(m_iFlowWindowSize), int(m_dCongestionWindow));
  7221. const bool bWasStuck = cwnd1<= getFlightSpan();
  7222. // Update Flow Window Size, must update before and together with m_iSndLastAck
  7223. m_iFlowWindowSize = ackdata[ACKD_BUFFERLEFT];
  7224. m_iSndLastAck = ackdata_seqno;
  7225. m_tsLastRspAckTime = currtime;
  7226. m_iReXmitCount = 1; // Reset re-transmit count since last ACK
  7227. const int cwnd = std::min(int(m_iFlowWindowSize), int(m_dCongestionWindow));
  7228. if (bWasStuck && cwnd > getFlightSpan())
  7229. {
  7230. m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);
  7231. HLOGC(gglog.Debug,
  7232. log << CONID() << "processCtrlAck: could reschedule SND. iFlowWindowSize " << m_iFlowWindowSize
  7233. << " SPAN " << getFlightSpan() << " ackdataseqno %" << ackdata_seqno);
  7234. }
  7235. }
  7236. /*
  7237. * We must not ignore full ack received by peer
  7238. * if data has been artificially acked by late packet drop.
  7239. * Therefore, a distinct ack state is used for received Ack (iSndLastFullAck)
  7240. * and ack position in send buffer (m_iSndLastDataAck).
  7241. * Otherwise, when severe congestion causing packet drops (and m_iSndLastDataAck update)
  7242. * occures, we drop received acks (as duplicates) and do not update stats like RTT,
  7243. * which may go crazy and stay there, preventing proper stream recovery.
  7244. */
  7245. if (CSeqNo::seqoff(m_iSndLastFullAck, ackdata_seqno) <= 0)
  7246. {
  7247. // discard it if it is a repeated ACK
  7248. return;
  7249. }
  7250. m_iSndLastFullAck = ackdata_seqno;
  7251. }
  7252. //
  7253. // END of the new code with TLPKTDROP
  7254. //
  7255. #if ENABLE_BONDING
  7256. if (m_parent->m_GroupOf)
  7257. {
  7258. ScopedLock glock (uglobal().m_GlobControlLock);
  7259. if (m_parent->m_GroupOf)
  7260. {
  7261. // Will apply m_GroupLock, ordered after m_GlobControlLock.
  7262. // m_GlobControlLock is necessary for group existence.
  7263. m_parent->m_GroupOf->updateWriteState();
  7264. }
  7265. }
  7266. #endif
  7267. size_t acksize = ctrlpkt.getLength(); // TEMPORARY VALUE FOR CHECKING
  7268. bool wrongsize = 0 != (acksize % ACKD_FIELD_SIZE);
  7269. acksize = acksize / ACKD_FIELD_SIZE; // ACTUAL VALUE
  7270. if (wrongsize)
  7271. {
  7272. // Issue a log, but don't do anything but skipping the "odd" bytes from the payload.
  7273. LOGC(inlog.Warn,
  7274. log << CONID() << "Received UMSG_ACK payload is not evened up to 4-byte based field size - cutting to "
  7275. << acksize << " fields");
  7276. }
  7277. // Start with checking the base size.
  7278. if (acksize < ACKD_TOTAL_SIZE_SMALL)
  7279. {
  7280. LOGC(inlog.Warn, log << CONID() << "Invalid ACK size " << acksize << " fields - less than minimum required!");
  7281. // Ack is already interpreted, just skip further parts.
  7282. return;
  7283. }
  7284. // This check covers fields up to ACKD_BUFFERLEFT.
  7285. // Extract RTT estimate and RTTVar from the ACK packet.
  7286. const int rtt = ackdata[ACKD_RTT];
  7287. const int rttvar = ackdata[ACKD_RTTVAR];
  7288. // Update the values of smoothed RTT and the variation in RTT samples
  7289. // on subsequent RTT estimates extracted from the ACK packets
  7290. // (during transmission).
  7291. if (m_bIsFirstRTTReceived)
  7292. {
  7293. // Suppose transmission is bidirectional if sender is also receiving
  7294. // data packets.
  7295. enterCS(m_StatsLock);
  7296. const bool bPktsReceived = m_stats.rcvr.recvd.total.count() != 0;
  7297. leaveCS(m_StatsLock);
  7298. if (bPktsReceived) // Transmission is bidirectional.
  7299. {
  7300. // RTT value extracted from the ACK packet (rtt) is already smoothed
  7301. // RTT obtained at the receiver side. Apply EWMA anyway for the second
  7302. // time on the sender side. Ignore initial values which might arrive
  7303. // after the smoothed RTT on the sender side has been
  7304. // reset to the very first RTT sample received from the receiver.
  7305. // TODO: The case of bidirectional transmission requires further
  7306. // improvements and testing. Double smoothing is applied here to be
  7307. // consistent with the previous behavior.
  7308. if (rtt != INITIAL_RTT || rttvar != INITIAL_RTTVAR)
  7309. {
  7310. int iSRTT = m_iSRTT.load(), iRTTVar = m_iRTTVar.load();
  7311. iRTTVar = avg_iir<4>(iRTTVar, abs(rtt - iSRTT));
  7312. iSRTT = avg_iir<8>(iSRTT, rtt);
  7313. m_iSRTT = iSRTT;
  7314. m_iRTTVar = iRTTVar;
  7315. }
  7316. }
  7317. else // Transmission is unidirectional.
  7318. {
  7319. // Simply take the values of smoothed RTT and RTT variance from
  7320. // the ACK packet.
  7321. m_iSRTT = rtt;
  7322. m_iRTTVar = rttvar;
  7323. }
  7324. }
  7325. // Reset the value of smoothed RTT to the first real RTT estimate extracted
  7326. // from an ACK after initialization (at the beginning of transmission).
  7327. // In case of resumed connection over the same network, the very first RTT
  7328. // value sent within an ACK will be taken from cache and equal to previous
  7329. // connection's final smoothed RTT value. The reception of such a value
  7330. // will also trigger the smoothed RTT reset at the sender side.
  7331. else if (rtt != INITIAL_RTT && rttvar != INITIAL_RTTVAR)
  7332. {
  7333. m_iSRTT = rtt;
  7334. m_iRTTVar = rttvar;
  7335. m_bIsFirstRTTReceived = true;
  7336. }
  7337. #if SRT_DEBUG_RTT
  7338. s_rtt_trace.trace(currtime, "ACK", rtt, rttvar, m_bIsFirstRTTReceived,
  7339. m_stats.recvTotal, m_iSRTT, m_iRTTVar);
  7340. #endif
  7341. /* Version-dependent fields:
  7342. * Original UDT (total size: ACKD_TOTAL_SIZE_SMALL):
  7343. * ACKD_RCVLASTACK
  7344. * ACKD_RTT
  7345. * ACKD_RTTVAR
  7346. * ACKD_BUFFERLEFT
  7347. * Additional UDT fields, not always attached:
  7348. * ACKD_RCVSPEED
  7349. * ACKD_BANDWIDTH
  7350. * SRT extension since v1.0.1:
  7351. * ACKD_RCVRATE
  7352. * SRT extension in v1.0.2 only:
  7353. * ACKD_XMRATE_VER102_ONLY
  7354. */
  7355. if (acksize > ACKD_TOTAL_SIZE_SMALL)
  7356. {
  7357. // This means that ACKD_RCVSPEED and ACKD_BANDWIDTH fields are available.
  7358. int pktps = ackdata[ACKD_RCVSPEED];
  7359. int bandwidth = ackdata[ACKD_BANDWIDTH];
  7360. int bytesps;
  7361. /* SRT v1.0.2 Bytes-based stats: bandwidth (pcData[ACKD_XMRATE_VER102_ONLY]) and delivery rate (pcData[ACKD_RCVRATE]) in
  7362. * bytes/sec instead of pkts/sec */
  7363. /* SRT v1.0.3 Bytes-based stats: only delivery rate (pcData[ACKD_RCVRATE]) in bytes/sec instead of pkts/sec */
  7364. if (acksize > ACKD_TOTAL_SIZE_UDTBASE)
  7365. bytesps = ackdata[ACKD_RCVRATE];
  7366. else
  7367. bytesps = pktps * m_iMaxSRTPayloadSize;
  7368. m_iBandwidth = avg_iir<8>(m_iBandwidth.load(), bandwidth);
  7369. m_iDeliveryRate = avg_iir<8>(m_iDeliveryRate.load(), pktps);
  7370. m_iByteDeliveryRate = avg_iir<8>(m_iByteDeliveryRate.load(), bytesps);
  7371. // Update Estimated Bandwidth and packet delivery rate
  7372. // m_iRcvRate = m_iDeliveryRate;
  7373. // ^^ This has been removed because with the SrtCongestion class
  7374. // instead of reading the m_iRcvRate local field this will read
  7375. // cudt->deliveryRate() instead.
  7376. }
  7377. updateCC(TEV_ACK, EventVariant(ackdata_seqno));
  7378. enterCS(m_StatsLock);
  7379. m_stats.sndr.recvdAck.count(1);
  7380. leaveCS(m_StatsLock);
  7381. }
  7382. void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival)
  7383. {
  7384. int32_t ack = 0;
  7385. // Calculate RTT estimate on the receiver side based on ACK/ACKACK pair.
  7386. const int rtt = m_ACKWindow.acknowledge(ctrlpkt.getAckSeqNo(), ack, tsArrival);
  7387. if (rtt == -1)
  7388. {
  7389. if (ctrlpkt.getAckSeqNo() > (m_iAckSeqNo - static_cast<int>(ACK_WND_SIZE)) && ctrlpkt.getAckSeqNo() <= m_iAckSeqNo)
  7390. {
  7391. LOGC(inlog.Note,
  7392. log << CONID() << "ACKACK out of order, skipping RTT calculation "
  7393. << "(ACK number: " << ctrlpkt.getAckSeqNo() << ", last ACK sent: " << m_iAckSeqNo
  7394. << ", RTT (EWMA): " << m_iSRTT << ")");
  7395. return;
  7396. }
  7397. LOGC(inlog.Error,
  7398. log << CONID() << "ACK record not found, can't estimate RTT "
  7399. << "(ACK number: " << ctrlpkt.getAckSeqNo() << ", last ACK sent: " << m_iAckSeqNo
  7400. << ", RTT (EWMA): " << m_iSRTT << ")");
  7401. return;
  7402. }
  7403. if (rtt <= 0)
  7404. {
  7405. LOGC(inlog.Error,
  7406. log << CONID() << "IPE: invalid RTT estimate " << rtt
  7407. << ", possible time shift. Clock: " << SRT_SYNC_CLOCK_STR);
  7408. return;
  7409. }
  7410. // If increasing delay is detected.
  7411. // sendCtrl(UMSG_CGWARNING);
  7412. // Update the values of smoothed RTT and the variation in RTT samples
  7413. // on subsequent RTT samples (during transmission).
  7414. if (m_bIsFirstRTTReceived)
  7415. {
  7416. m_iRTTVar = avg_iir<4>(m_iRTTVar.load(), abs(rtt - m_iSRTT.load()));
  7417. m_iSRTT = avg_iir<8>(m_iSRTT.load(), rtt);
  7418. }
  7419. // Reset the value of smoothed RTT on the first RTT sample after initialization
  7420. // (at the beginning of transmission).
  7421. // In case of resumed connection over the same network, the initial RTT
  7422. // value will be taken from cache and equal to previous connection's
  7423. // final smoothed RTT value.
  7424. else
  7425. {
  7426. m_iSRTT = rtt;
  7427. m_iRTTVar = rtt / 2;
  7428. m_bIsFirstRTTReceived = true;
  7429. }
  7430. #if SRT_DEBUG_RTT
  7431. s_rtt_trace.trace(tsArrival, "ACKACK", rtt, -1, m_bIsFirstRTTReceived,
  7432. -1, m_iSRTT, m_iRTTVar);
  7433. #endif
  7434. updateCC(TEV_ACKACK, EventVariant(ack));
  7435. // This function will put a lock on m_RecvLock by itself, as needed.
  7436. // It must be done inside because this function reads the current time
  7437. // and if waiting for the lock has caused a delay, the time will be
  7438. // inaccurate. Additionally it won't lock if TSBPD mode is off, and
  7439. // won't update anything. Note that if you set TSBPD mode and use
  7440. // srt_recvfile (which doesn't make any sense), you'll have a deadlock.
  7441. if (m_config.bDriftTracer)
  7442. {
  7443. const bool drift_updated SRT_ATR_UNUSED = m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), tsArrival, rtt);
  7444. #if ENABLE_BONDING
  7445. if (drift_updated && m_parent->m_GroupOf)
  7446. {
  7447. ScopedLock glock(uglobal().m_GlobControlLock);
  7448. if (m_parent->m_GroupOf)
  7449. {
  7450. m_parent->m_GroupOf->synchronizeDrift(this);
  7451. }
  7452. }
  7453. #endif
  7454. }
  7455. // Update last ACK that has been received by the sender
  7456. if (CSeqNo::seqcmp(ack, m_iRcvLastAckAck) > 0)
  7457. m_iRcvLastAckAck = ack;
  7458. }
  7459. void srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt)
  7460. {
  7461. const int32_t* losslist = (int32_t*)(ctrlpkt.m_pcData);
  7462. const size_t losslist_len = ctrlpkt.getLength() / 4;
  7463. bool secure = true;
  7464. // This variable is used in "normal" logs, so it may cause a warning
  7465. // when logging is forcefully off.
  7466. int32_t wrong_loss SRT_ATR_UNUSED = SRT_SEQNO_NONE;
  7467. // protect packet retransmission
  7468. {
  7469. ScopedLock ack_lock(m_RecvAckLock);
  7470. // decode loss list message and insert loss into the sender loss list
  7471. for (int i = 0, n = (int)losslist_len; i < n; ++i)
  7472. {
  7473. // IF the loss is a range <LO, HI>
  7474. if (IsSet(losslist[i], LOSSDATA_SEQNO_RANGE_FIRST))
  7475. {
  7476. // Then it's this is a <LO, HI> specification with HI in a consecutive cell.
  7477. const int32_t losslist_lo = SEQNO_VALUE::unwrap(losslist[i]);
  7478. const int32_t losslist_hi = losslist[i + 1];
  7479. // <LO, HI> specification means that the consecutive cell has been already interpreted.
  7480. ++i;
  7481. HLOGC(inlog.Debug, log << CONID() << "received UMSG_LOSSREPORT: "
  7482. << losslist_lo << "-" << losslist_hi
  7483. << " (" << CSeqNo::seqlen(losslist_lo, losslist_hi) << " packets)...");
  7484. if ((CSeqNo::seqcmp(losslist_lo, losslist_hi) > 0) ||
  7485. (CSeqNo::seqcmp(losslist_hi, m_iSndCurrSeqNo) > 0))
  7486. {
  7487. // LO must not be greater than HI.
  7488. // HI must not be greater than the most recent sent seq.
  7489. LOGC(inlog.Warn, log << CONID() << "rcv LOSSREPORT rng " << losslist_lo << " - " << losslist_hi
  7490. << " with last sent " << m_iSndCurrSeqNo << " - DISCARDING");
  7491. secure = false;
  7492. wrong_loss = losslist_hi;
  7493. break;
  7494. }
  7495. int num = 0;
  7496. // IF losslist_lo %>= m_iSndLastAck
  7497. if (CSeqNo::seqcmp(losslist_lo, m_iSndLastAck) >= 0)
  7498. {
  7499. HLOGC(inlog.Debug, log << CONID() << "LOSSREPORT: adding "
  7500. << losslist_lo << " - " << losslist_hi << " to loss list");
  7501. num = m_pSndLossList->insert(losslist_lo, losslist_hi);
  7502. }
  7503. // ELSE losslist_lo %< m_iSndLastAck
  7504. else
  7505. {
  7506. // This should be theoretically impossible because this would mean that
  7507. // the received packet loss report informs about the loss that predates
  7508. // the ACK sequence.
  7509. // However, this can happen in these situations:
  7510. // - if the packet reordering has caused the earlier sent LOSSREPORT will be
  7511. // delivered after later sent ACK. Whatever, ACK should be more important,
  7512. // so simply drop the part that predates ACK.
  7513. // - redundancy second link (ISN was screwed up initially, but late towards last sent)
  7514. // - initial DROPREQ was lost
  7515. // This just causes repeating DROPREQ, as when the receiver continues sending
  7516. // LOSSREPORT, it's probably UNAWARE OF THE SITUATION.
  7517. int32_t dropreq_hi = losslist_hi;
  7518. IF_HEAVY_LOGGING(const char* drop_type = "completely");
  7519. // IF losslist_hi %>= m_iSndLastAck
  7520. if (CSeqNo::seqcmp(losslist_hi, m_iSndLastAck) >= 0)
  7521. {
  7522. HLOGC(inlog.Debug, log << CONID() << "LOSSREPORT: adding "
  7523. << m_iSndLastAck << "[ACK] - " << losslist_hi << " to loss list");
  7524. num = m_pSndLossList->insert(m_iSndLastAck, losslist_hi);
  7525. dropreq_hi = CSeqNo::decseq(m_iSndLastAck);
  7526. IF_HEAVY_LOGGING(drop_type = "partially");
  7527. }
  7528. // In distinction to losslist, DROPREQ has always just one range,
  7529. // and the data are <LO, HI>, with no range bit.
  7530. int32_t seqpair[2] = { losslist_lo, dropreq_hi };
  7531. const int32_t no_msgno = 0; // We don't know.
  7532. // When this DROPREQ gets lost in UDP again, the receiver will do one of these:
  7533. // - repeatedly send LOSSREPORT (as per NAKREPORT), so this will happen again
  7534. // - finally give up rexmit request as per TLPKTDROP (DROPREQ should make
  7535. // TSBPD wake up should it still wait for new packets to get ACK-ed)
  7536. HLOGC(inlog.Debug,
  7537. log << CONID() << "LOSSREPORT: " << drop_type << " IGNORED with SndLastAck=%" << m_iSndLastAck
  7538. << ": %" << losslist_lo << "-" << dropreq_hi << " - sending DROPREQ");
  7539. sendCtrl(UMSG_DROPREQ, &no_msgno, seqpair, sizeof(seqpair));
  7540. }
  7541. enterCS(m_StatsLock);
  7542. m_stats.sndr.lost.count(num);
  7543. leaveCS(m_StatsLock);
  7544. }
  7545. // ELSE the loss is a single seq
  7546. else
  7547. {
  7548. // IF loss_seq %>= m_iSndLastAck
  7549. if (CSeqNo::seqcmp(losslist[i], m_iSndLastAck) >= 0)
  7550. {
  7551. if (CSeqNo::seqcmp(losslist[i], m_iSndCurrSeqNo) > 0)
  7552. {
  7553. LOGC(inlog.Warn, log << CONID() << "rcv LOSSREPORT pkt %" << losslist[i]
  7554. << " with last sent %" << m_iSndCurrSeqNo << " - DISCARDING");
  7555. // loss_seq must not be greater than the most recent sent seq
  7556. secure = false;
  7557. wrong_loss = losslist[i];
  7558. break;
  7559. }
  7560. HLOGC(inlog.Debug,
  7561. log << CONID() << "LOSSREPORT: adding %" << losslist[i] << " (1 packet) to loss list");
  7562. const int num = m_pSndLossList->insert(losslist[i], losslist[i]);
  7563. enterCS(m_StatsLock);
  7564. m_stats.sndr.lost.count(num);
  7565. leaveCS(m_StatsLock);
  7566. }
  7567. // ELSE loss_seq %< m_iSndLastAck
  7568. else
  7569. {
  7570. // In distinction to losslist, DROPREQ has always just one range,
  7571. // and the data are <LO, HI>, with no range bit.
  7572. int32_t seqpair[2] = { losslist[i], losslist[i] };
  7573. const int32_t no_msgno = 0; // We don't know.
  7574. HLOGC(inlog.Debug,
  7575. log << CONID() << "LOSSREPORT: IGNORED with SndLastAck=%" << m_iSndLastAck << ": %" << losslist[i]
  7576. << " - sending DROPREQ");
  7577. sendCtrl(UMSG_DROPREQ, &no_msgno, seqpair, sizeof(seqpair));
  7578. }
  7579. }
  7580. }
  7581. }
  7582. updateCC(TEV_LOSSREPORT, EventVariant(losslist, losslist_len));
  7583. if (!secure)
  7584. {
  7585. LOGC(inlog.Warn,
  7586. log << CONID() << "out-of-band LOSSREPORT received; BUG or ATTACK - last sent %" << m_iSndCurrSeqNo
  7587. << " vs loss %" << wrong_loss);
  7588. // this should not happen: attack or bug
  7589. m_bBroken = true;
  7590. m_iBrokenCounter = 0;
  7591. return;
  7592. }
  7593. // the lost packet (retransmission) should be sent out immediately
  7594. m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);
  7595. enterCS(m_StatsLock);
  7596. m_stats.sndr.recvdNak.count(1);
  7597. leaveCS(m_StatsLock);
  7598. }
  7599. void srt::CUDT::processCtrlHS(const CPacket& ctrlpkt)
  7600. {
  7601. CHandShake req;
  7602. req.load_from(ctrlpkt.m_pcData, ctrlpkt.getLength());
  7603. HLOGC(inlog.Debug, log << CONID() << "processCtrl: got HS: " << req.show());
  7604. if ((req.m_iReqType > URQ_INDUCTION_TYPES) // acually it catches URQ_INDUCTION and URQ_ERROR_* symbols...???
  7605. || (m_config.bRendezvous && (req.m_iReqType != URQ_AGREEMENT))) // rnd sends AGREEMENT in rsp to CONCLUSION
  7606. {
  7607. // The peer side has not received the handshake message, so it keeps querying
  7608. // resend the handshake packet
  7609. // This condition embraces cases when:
  7610. // - this is normal accept() and URQ_INDUCTION was received
  7611. // - this is rendezvous accept() and there's coming any kind of URQ except AGREEMENT (should be RENDEZVOUS
  7612. // or CONCLUSION)
  7613. // - this is any of URQ_ERROR_* - well...
  7614. CHandShake initdata;
  7615. initdata.m_iISN = m_iISN;
  7616. initdata.m_iMSS = m_config.iMSS;
  7617. initdata.m_iFlightFlagSize = m_config.iFlightFlagSize;
  7618. // For rendezvous we do URQ_WAVEAHAND/URQ_CONCLUSION --> URQ_AGREEMENT.
  7619. // For client-server we do URQ_INDUCTION --> URQ_CONCLUSION.
  7620. initdata.m_iReqType = (!m_config.bRendezvous) ? URQ_CONCLUSION : URQ_AGREEMENT;
  7621. initdata.m_iID = m_SocketID;
  7622. uint32_t kmdata[SRTDATA_MAXSIZE];
  7623. size_t kmdatasize = SRTDATA_MAXSIZE;
  7624. bool have_hsreq = false;
  7625. if (req.m_iVersion > HS_VERSION_UDT4)
  7626. {
  7627. initdata.m_iVersion = HS_VERSION_SRT1; // if I remember correctly, this is induction/listener...
  7628. const int hs_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_ConnRes.m_iType);
  7629. if (hs_flags != 0) // has SRT extensions
  7630. {
  7631. HLOGC(inlog.Debug,
  7632. log << CONID() << "processCtrl/HS: got HS reqtype=" << RequestTypeStr(req.m_iReqType)
  7633. << " WITH SRT ext");
  7634. have_hsreq = interpretSrtHandshake(req, ctrlpkt, (kmdata), (&kmdatasize));
  7635. if (!have_hsreq)
  7636. {
  7637. initdata.m_iVersion = 0;
  7638. m_RejectReason = SRT_REJ_ROGUE;
  7639. initdata.m_iReqType = URQFailure(m_RejectReason);
  7640. }
  7641. else
  7642. {
  7643. // Extensions are added only in case of CONCLUSION (not AGREEMENT).
  7644. // Actually what is expected here is that this may either process the
  7645. // belated-repeated handshake from a caller (and then it's CONCLUSION,
  7646. // and should be added with HSRSP/KMRSP), or it's a belated handshake
  7647. // of Rendezvous when it has already considered itself connected.
  7648. // Sanity check - according to the rules, there should be no such situation
  7649. if (m_config.bRendezvous && m_SrtHsSide == HSD_RESPONDER)
  7650. {
  7651. LOGC(inlog.Error,
  7652. log << CONID() << "processCtrl/HS: IPE???: RESPONDER should receive all its handshakes in "
  7653. "handshake phase.");
  7654. }
  7655. // The 'extension' flag will be set from this variable; set it to false
  7656. // in case when the AGREEMENT response is to be sent.
  7657. have_hsreq = initdata.m_iReqType == URQ_CONCLUSION;
  7658. HLOGC(inlog.Debug,
  7659. log << CONID() << "processCtrl/HS: processing ok, reqtype=" << RequestTypeStr(initdata.m_iReqType)
  7660. << " kmdatasize=" << kmdatasize);
  7661. }
  7662. }
  7663. else
  7664. {
  7665. HLOGC(inlog.Debug, log << CONID() << "processCtrl/HS: got HS reqtype=" << RequestTypeStr(req.m_iReqType));
  7666. }
  7667. }
  7668. else
  7669. {
  7670. initdata.m_iVersion = HS_VERSION_UDT4;
  7671. kmdatasize = 0; // HSv4 doesn't add any extensions, no KMX
  7672. }
  7673. initdata.m_extension = have_hsreq;
  7674. HLOGC(inlog.Debug,
  7675. log << CONID() << "processCtrl: responding HS reqtype=" << RequestTypeStr(initdata.m_iReqType)
  7676. << (have_hsreq ? " WITH SRT HS response extensions" : ""));
  7677. CPacket response;
  7678. response.setControl(UMSG_HANDSHAKE);
  7679. response.allocate(m_iMaxSRTPayloadSize);
  7680. // If createSrtHandshake failed, don't send anything. Actually it can only fail on IPE.
  7681. // There is also no possible IPE condition in case of HSv4 - for this version it will always return true.
  7682. if (createSrtHandshake(SRT_CMD_HSRSP, SRT_CMD_KMRSP, kmdata, kmdatasize,
  7683. (response), (initdata)))
  7684. {
  7685. response.m_iID = m_PeerID;
  7686. setPacketTS(response, steady_clock::now());
  7687. const int nbsent = m_pSndQueue->sendto(m_PeerAddr, response, m_SourceAddr);
  7688. if (nbsent)
  7689. {
  7690. m_tsLastSndTime.store(steady_clock::now());
  7691. }
  7692. }
  7693. }
  7694. else
  7695. {
  7696. HLOGC(inlog.Debug, log << CONID() << "processCtrl: ... not INDUCTION, not ERROR, not rendezvous - IGNORED.");
  7697. }
  7698. }
  7699. void srt::CUDT::processCtrlDropReq(const CPacket& ctrlpkt)
  7700. {
  7701. const int32_t* dropdata = (const int32_t*) ctrlpkt.m_pcData;
  7702. {
  7703. CUniqueSync rcvtscc (m_RecvLock, m_RcvTsbPdCond);
  7704. // With both TLPktDrop and TsbPd enabled, a message always consists only of one packet.
  7705. // It will be dropped as too late anyway. Not dropping it from the receiver buffer
  7706. // in advance reduces false drops if the packet somehow manages to arrive.
  7707. // Still remove the record from the loss list to cease further retransmission requests.
  7708. if (!m_bTLPktDrop || !m_bTsbPd)
  7709. {
  7710. const bool using_rexmit_flag = m_bPeerRexmitFlag;
  7711. ScopedLock rblock(m_RcvBufferLock);
  7712. const int iDropCnt = m_pRcvBuffer->dropMessage(dropdata[0], dropdata[1], ctrlpkt.getMsgSeq(using_rexmit_flag), CRcvBuffer::KEEP_EXISTING);
  7713. if (iDropCnt > 0)
  7714. {
  7715. LOGC(brlog.Warn, log << CONID() << "RCV-DROPPED " << iDropCnt << " packet(s), seqno range %"
  7716. << dropdata[0] << "-%" << dropdata[1] << ", msgno " << ctrlpkt.getMsgSeq(using_rexmit_flag)
  7717. << " (SND DROP REQUEST).");
  7718. enterCS(m_StatsLock);
  7719. // Estimate dropped bytes from average payload size.
  7720. const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize();
  7721. m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt));
  7722. leaveCS(m_StatsLock);
  7723. }
  7724. }
  7725. // When the drop request was received, it means that there are
  7726. // packets for which there will never be ACK sent; if the TSBPD thread
  7727. // is currently in the ACK-waiting state, it may never exit.
  7728. if (m_bTsbPd)
  7729. {
  7730. HLOGP(inlog.Debug, "DROPREQ: signal TSBPD");
  7731. rcvtscc.notify_one();
  7732. }
  7733. }
  7734. dropFromLossLists(dropdata[0], dropdata[1]);
  7735. // If dropping ahead of the current largest sequence number,
  7736. // move the recv seq number forward.
  7737. if ((CSeqNo::seqcmp(dropdata[0], CSeqNo::incseq(m_iRcvCurrSeqNo)) <= 0)
  7738. && (CSeqNo::seqcmp(dropdata[1], m_iRcvCurrSeqNo) > 0))
  7739. {
  7740. HLOGC(inlog.Debug, log << CONID() << "DROPREQ: dropping %"
  7741. << dropdata[0] << "-" << dropdata[1] << " <-- set as current seq");
  7742. m_iRcvCurrSeqNo = dropdata[1];
  7743. }
  7744. else
  7745. {
  7746. HLOGC(inlog.Debug, log << CONID() << "DROPREQ: dropping %"
  7747. << dropdata[0] << "-" << dropdata[1] << " current %" << m_iRcvCurrSeqNo);
  7748. }
  7749. }
  7750. void srt::CUDT::processCtrlShutdown()
  7751. {
  7752. m_bShutdown = true;
  7753. m_bClosing = true;
  7754. m_bBroken = true;
  7755. m_iBrokenCounter = 60;
  7756. // This does the same as it would happen on connection timeout,
  7757. // just we know about this state prematurely thanks to this message.
  7758. updateBrokenConnection();
  7759. completeBrokenConnectionDependencies(SRT_ECONNLOST); // LOCKS!
  7760. }
  7761. void srt::CUDT::processCtrlUserDefined(const CPacket& ctrlpkt)
  7762. {
  7763. HLOGC(inlog.Debug, log << CONID() << "CONTROL EXT MSG RECEIVED:"
  7764. << MessageTypeStr(ctrlpkt.getType(), ctrlpkt.getExtendedType())
  7765. << ", value=" << ctrlpkt.getExtendedType());
  7766. // This has currently two roles in SRT:
  7767. // - HSv4 (legacy) handshake
  7768. // - refreshed KMX (initial KMX is done still in the HS process in HSv5)
  7769. const bool understood = processSrtMsg(&ctrlpkt);
  7770. // CAREFUL HERE! This only means that this update comes from the UMSG_EXT
  7771. // message received, REGARDLESS OF WHAT IT IS. This version doesn't mean
  7772. // the handshake version, but the reason of calling this function.
  7773. //
  7774. // Fortunately, the only messages taken into account in this function
  7775. // are HSREQ and HSRSP, which should *never* be interchanged when both
  7776. // parties are HSv5.
  7777. if (understood)
  7778. {
  7779. if (ctrlpkt.getExtendedType() == SRT_CMD_HSREQ || ctrlpkt.getExtendedType() == SRT_CMD_HSRSP)
  7780. {
  7781. updateAfterSrtHandshake(HS_VERSION_UDT4);
  7782. }
  7783. }
  7784. else
  7785. {
  7786. updateCC(TEV_CUSTOM, EventVariant(&ctrlpkt));
  7787. }
  7788. }
  7789. void srt::CUDT::processCtrl(const CPacket &ctrlpkt)
  7790. {
  7791. // Just heard from the peer, reset the expiration count.
  7792. m_iEXPCount = 1;
  7793. const steady_clock::time_point currtime = steady_clock::now();
  7794. m_tsLastRspTime = currtime;
  7795. HLOGC(inlog.Debug,
  7796. log << CONID() << "incoming UMSG:" << ctrlpkt.getType() << " ("
  7797. << MessageTypeStr(ctrlpkt.getType(), ctrlpkt.getExtendedType()) << ") socket=%" << ctrlpkt.m_iID);
  7798. switch (ctrlpkt.getType())
  7799. {
  7800. case UMSG_ACK: // 010 - Acknowledgement
  7801. processCtrlAck(ctrlpkt, currtime);
  7802. break;
  7803. case UMSG_ACKACK: // 110 - Acknowledgement of Acknowledgement
  7804. processCtrlAckAck(ctrlpkt, currtime);
  7805. break;
  7806. case UMSG_LOSSREPORT: // 011 - Loss Report
  7807. processCtrlLossReport(ctrlpkt);
  7808. break;
  7809. case UMSG_CGWARNING: // 100 - Delay Warning
  7810. // One way packet delay is increasing, so decrease the sending rate
  7811. m_tdSendInterval = (m_tdSendInterval.load() * 1125) / 1000;
  7812. // XXX Note as interesting fact: this is only prepared for handling,
  7813. // but nothing in the code is sending this message. Probably predicted
  7814. // for a custom congctl. There's a predicted place to call it under
  7815. // UMSG_ACKACK handling, but it's commented out.
  7816. break;
  7817. case UMSG_KEEPALIVE: // 001 - Keep-alive
  7818. processKeepalive(ctrlpkt, currtime);
  7819. break;
  7820. case UMSG_HANDSHAKE: // 000 - Handshake
  7821. processCtrlHS(ctrlpkt);
  7822. break;
  7823. case UMSG_SHUTDOWN: // 101 - Shutdown
  7824. processCtrlShutdown();
  7825. break;
  7826. case UMSG_DROPREQ: // 111 - Msg drop request
  7827. processCtrlDropReq(ctrlpkt);
  7828. break;
  7829. case UMSG_PEERERROR: // 1000 - An error has happened to the peer side
  7830. // int err_type = packet.getAddInfo();
  7831. // currently only this error is signalled from the peer side
  7832. // if recvfile() failes (e.g., due to disk fail), blcoked sendfile/send should return immediately
  7833. // giving the app a chance to fix the issue
  7834. m_bPeerHealth = false;
  7835. break;
  7836. case UMSG_EXT: // 0x7FFF - reserved and user defined messages
  7837. processCtrlUserDefined(ctrlpkt);
  7838. break;
  7839. default:
  7840. break;
  7841. }
  7842. }
  7843. void srt::CUDT::updateSrtRcvSettings()
  7844. {
  7845. // CHANGED: we need to apply the tsbpd delay only for socket TSBPD.
  7846. // For Group TSBPD the buffer will have to deliver packets always on request
  7847. // by sequence number, although the buffer will have to solve all the TSBPD
  7848. // things internally anyway. Extracting by sequence number means only that
  7849. // the packet can be retrieved from the buffer before its time to play comes
  7850. // (unlike in normal situation when reading directly from socket), however
  7851. // its time to play shall be properly defined.
  7852. ScopedLock lock(m_RecvLock);
  7853. // NOTE: remember to also update synchronizeWithGroup() if more settings are updated here.
  7854. m_pRcvBuffer->setPeerRexmitFlag(m_bPeerRexmitFlag);
  7855. // XXX m_bGroupTsbPd is ignored with SRT_ENABLE_APP_READER
  7856. if (m_bTsbPd || m_bGroupTsbPd)
  7857. {
  7858. m_pRcvBuffer->setTsbPdMode(m_tsRcvPeerStartTime, false, milliseconds_from(m_iTsbPdDelay_ms));
  7859. HLOGC(cnlog.Debug, log << "AFTER HS: Set Rcv TsbPd mode"
  7860. << (m_bGroupTsbPd ? " (AS GROUP MEMBER)" : "")
  7861. << ": delay=" << (m_iTsbPdDelay_ms / 1000) << "." << (m_iTsbPdDelay_ms % 1000)
  7862. << "s RCV START: " << FormatTime(m_tsRcvPeerStartTime).c_str());
  7863. }
  7864. else
  7865. {
  7866. HLOGC(cnlog.Debug, log << CONID() << "AFTER HS: Rcv TsbPd mode not set");
  7867. }
  7868. }
  7869. void srt::CUDT::updateSrtSndSettings()
  7870. {
  7871. if (m_bPeerTsbPd)
  7872. {
  7873. /* We are TsbPd sender */
  7874. // XXX Check what happened here.
  7875. // m_iPeerTsbPdDelay_ms = m_CongCtl->getSndPeerTsbPdDelay();// + ((m_iSRTT + (4 * m_iRTTVar)) / 1000);
  7876. /*
  7877. * For sender to apply Too-Late Packet Drop
  7878. * option (m_bTLPktDrop) must be enabled and receiving peer shall support it
  7879. */
  7880. HLOGC(cnlog.Debug, log << "AFTER HS: Set Snd TsbPd mode "
  7881. << (m_bPeerTLPktDrop ? "with" : "without")
  7882. << " TLPktDrop: delay=" << (m_iPeerTsbPdDelay_ms/1000) << "." << (m_iPeerTsbPdDelay_ms%1000)
  7883. << "s START TIME: " << FormatTime(m_stats.tsStartTime).c_str());
  7884. }
  7885. else
  7886. {
  7887. HLOGC(cnlog.Debug, log << CONID() << "AFTER HS: Snd TsbPd mode not set");
  7888. }
  7889. }
  7890. void srt::CUDT::updateAfterSrtHandshake(int hsv)
  7891. {
  7892. HLOGC(cnlog.Debug, log << CONID() << "updateAfterSrtHandshake: HS version " << hsv);
  7893. // This is blocked from being run in the "app reader" version because here
  7894. // every socket does its TsbPd independently, just the sequence screwup is
  7895. // done and the application reader sorts out packets by sequence numbers,
  7896. // but only when they are signed off by TsbPd.
  7897. // The only possibility here is one of these two:
  7898. // - Agent is RESPONDER and it receives HSREQ.
  7899. // - Agent is INITIATOR and it receives HSRSP.
  7900. //
  7901. // In HSv4, INITIATOR is sender and RESPONDER is receiver.
  7902. // In HSv5, both are sender AND receiver.
  7903. //
  7904. // This function will be called only ONCE in this
  7905. // instance, through either HSREQ or HSRSP.
  7906. #if ENABLE_HEAVY_LOGGING
  7907. const char* hs_side[] = { "DRAW", "INITIATOR", "RESPONDER" };
  7908. #if ENABLE_BONDING
  7909. string grpspec;
  7910. if (m_parent->m_GroupOf)
  7911. {
  7912. ScopedLock glock (uglobal().m_GlobControlLock);
  7913. grpspec = m_parent->m_GroupOf
  7914. ? " group=$" + Sprint(m_parent->m_GroupOf->id())
  7915. : string();
  7916. }
  7917. #else
  7918. const char* grpspec = "";
  7919. #endif
  7920. HLOGC(cnlog.Debug,
  7921. log << CONID() << "updateAfterSrtHandshake: version=" << m_ConnRes.m_iVersion
  7922. << " side=" << hs_side[m_SrtHsSide] << grpspec);
  7923. #endif
  7924. if (hsv > HS_VERSION_UDT4)
  7925. {
  7926. updateSrtRcvSettings();
  7927. updateSrtSndSettings();
  7928. }
  7929. else if (m_SrtHsSide == HSD_INITIATOR)
  7930. {
  7931. // HSv4 INITIATOR is sender
  7932. updateSrtSndSettings();
  7933. }
  7934. else
  7935. {
  7936. // HSv4 RESPONDER is receiver
  7937. updateSrtRcvSettings();
  7938. }
  7939. }
  7940. int srt::CUDT::packLostData(CPacket& w_packet)
  7941. {
  7942. // protect m_iSndLastDataAck from updating by ACK processing
  7943. UniqueLock ackguard(m_RecvAckLock);
  7944. const steady_clock::time_point time_now = steady_clock::now();
  7945. const steady_clock::time_point time_nak = time_now - microseconds_from(m_iSRTT - 4 * m_iRTTVar);
  7946. while ((w_packet.m_iSeqNo = m_pSndLossList->popLostSeq()) >= 0)
  7947. {
  7948. // XXX See the note above the m_iSndLastDataAck declaration in core.h
  7949. // This is the place where the important sequence numbers for
  7950. // sender buffer are actually managed by this field here.
  7951. const int offset = CSeqNo::seqoff(m_iSndLastDataAck, w_packet.m_iSeqNo);
  7952. if (offset < 0)
  7953. {
  7954. // XXX Likely that this will never be executed because if the upper
  7955. // sequence is not in the sender buffer, then most likely the loss
  7956. // was completely ignored.
  7957. LOGC(qrlog.Error,
  7958. log << CONID() << "IPE/EPE: packLostData: LOST packet negative offset: seqoff(m_iSeqNo "
  7959. << w_packet.m_iSeqNo << ", m_iSndLastDataAck " << m_iSndLastDataAck << ")=" << offset
  7960. << ". Continue");
  7961. // No matter whether this is right or not (maybe the attack case should be
  7962. // considered, and some LOSSREPORT flood prevention), send the drop request
  7963. // to the peer.
  7964. int32_t seqpair[2] = {
  7965. w_packet.m_iSeqNo,
  7966. CSeqNo::decseq(m_iSndLastDataAck)
  7967. };
  7968. w_packet.m_iMsgNo = 0; // Message number is not known, setting all 32 bits to 0.
  7969. HLOGC(qrlog.Debug,
  7970. log << CONID() << "PEER reported LOSS not from the sending buffer - requesting DROP: msg="
  7971. << MSGNO_SEQ::unwrap(w_packet.m_iMsgNo) << " SEQ:" << seqpair[0] << " - " << seqpair[1] << "("
  7972. << (-offset) << " packets)");
  7973. sendCtrl(UMSG_DROPREQ, &w_packet.m_iMsgNo, seqpair, sizeof(seqpair));
  7974. continue;
  7975. }
  7976. if (m_bPeerNakReport && m_config.iRetransmitAlgo != 0)
  7977. {
  7978. const steady_clock::time_point tsLastRexmit = m_pSndBuffer->getPacketRexmitTime(offset);
  7979. if (tsLastRexmit >= time_nak)
  7980. {
  7981. HLOGC(qrlog.Debug, log << CONID() << "REXMIT: ignoring seqno "
  7982. << w_packet.m_iSeqNo << ", last rexmit " << (is_zero(tsLastRexmit) ? "never" : FormatTime(tsLastRexmit))
  7983. << " RTT=" << m_iSRTT << " RTTVar=" << m_iRTTVar
  7984. << " now=" << FormatTime(time_now));
  7985. continue;
  7986. }
  7987. }
  7988. int msglen;
  7989. steady_clock::time_point tsOrigin;
  7990. const int payload = m_pSndBuffer->readData(offset, (w_packet), (tsOrigin), (msglen));
  7991. if (payload == -1)
  7992. {
  7993. int32_t seqpair[2];
  7994. seqpair[0] = w_packet.m_iSeqNo;
  7995. SRT_ASSERT(msglen >= 1);
  7996. seqpair[1] = CSeqNo::incseq(seqpair[0], msglen - 1);
  7997. HLOGC(qrlog.Debug,
  7998. log << CONID() << "loss-reported packets expired in SndBuf - requesting DROP: msgno="
  7999. << MSGNO_SEQ::unwrap(w_packet.m_iMsgNo) << " msglen=" << msglen << " SEQ:" << seqpair[0] << " - "
  8000. << seqpair[1]);
  8001. sendCtrl(UMSG_DROPREQ, &w_packet.m_iMsgNo, seqpair, sizeof(seqpair));
  8002. // skip all dropped packets
  8003. m_pSndLossList->removeUpTo(seqpair[1]);
  8004. m_iSndCurrSeqNo = CSeqNo::maxseq(m_iSndCurrSeqNo, seqpair[1]);
  8005. continue;
  8006. }
  8007. else if (payload == 0)
  8008. continue;
  8009. // The packet has been ecrypted, thus the authentication tag is expected to be stored
  8010. // in the SND buffer as well right after the payload.
  8011. if (m_pCryptoControl && m_pCryptoControl->getCryptoMode() == CSrtConfig::CIPHER_MODE_AES_GCM)
  8012. {
  8013. w_packet.setLength(w_packet.getLength() + HAICRYPT_AUTHTAG_MAX);
  8014. }
  8015. // At this point we no longer need the ACK lock,
  8016. // because we are going to return from the function.
  8017. // Therefore unlocking in order not to block other threads.
  8018. ackguard.unlock();
  8019. enterCS(m_StatsLock);
  8020. m_stats.sndr.sentRetrans.count(payload);
  8021. leaveCS(m_StatsLock);
  8022. // Despite the contextual interpretation of packet.m_iMsgNo around
  8023. // CSndBuffer::readData version 2 (version 1 doesn't return -1), in this particular
  8024. // case we can be sure that this is exactly the value of PH_MSGNO as a bitset.
  8025. // So, set here the rexmit flag if the peer understands it.
  8026. if (m_bPeerRexmitFlag)
  8027. {
  8028. w_packet.m_iMsgNo |= PACKET_SND_REXMIT;
  8029. }
  8030. setDataPacketTS(w_packet, tsOrigin);
  8031. #ifdef ENABLE_MAXREXMITBW
  8032. m_SndRexmitRate.addSample(time_now, 1, w_packet.getLength());
  8033. #endif
  8034. return payload;
  8035. }
  8036. return 0;
  8037. }
  8038. #if SRT_DEBUG_TRACE_SND
  8039. class snd_logger
  8040. {
  8041. typedef srt::sync::steady_clock steady_clock;
  8042. public:
  8043. snd_logger() {}
  8044. ~snd_logger()
  8045. {
  8046. ScopedLock lck(m_mtx);
  8047. m_fout.close();
  8048. }
  8049. struct
  8050. {
  8051. typedef srt::sync::steady_clock steady_clock;
  8052. long long usElapsed;
  8053. steady_clock::time_point tsNow;
  8054. int usSRTT;
  8055. int usRTTVar;
  8056. int msSndBuffSpan;
  8057. int msTimespanTh;
  8058. int msNextUniqueToSend;
  8059. long long usElapsedLastDrop;
  8060. bool canRexmit;
  8061. int iPktSeqno;
  8062. bool isRetransmitted;
  8063. } state;
  8064. void trace()
  8065. {
  8066. using namespace srt::sync;
  8067. ScopedLock lck(m_mtx);
  8068. create_file();
  8069. m_fout << state.usElapsed << ",";
  8070. m_fout << state.usSRTT << ",";
  8071. m_fout << state.usRTTVar << ",";
  8072. m_fout << state.msSndBuffSpan << ",";
  8073. m_fout << state.msTimespanTh << ",";
  8074. m_fout << state.msNextUniqueToSend << ",";
  8075. m_fout << state.usElapsedLastDrop << ",";
  8076. m_fout << state.canRexmit << ",";
  8077. m_fout << state.iPktSeqno << ',';
  8078. m_fout << state.isRetransmitted << '\n';
  8079. m_fout.flush();
  8080. }
  8081. private:
  8082. void print_header()
  8083. {
  8084. m_fout << "usElapsed,usSRTT,usRTTVar,msSndBuffTimespan,msTimespanTh,msNextUniqueToSend,usDLastDrop,canRexmit,sndPktSeqno,isRexmit";
  8085. m_fout << "\n";
  8086. }
  8087. void create_file()
  8088. {
  8089. if (m_fout.is_open())
  8090. return;
  8091. m_start_time = srt::sync::steady_clock::now();
  8092. std::string str_tnow = srt::sync::FormatTimeSys(m_start_time);
  8093. str_tnow.resize(str_tnow.size() - 7); // remove trailing ' [SYST]' part
  8094. while (str_tnow.find(':') != std::string::npos)
  8095. {
  8096. str_tnow.replace(str_tnow.find(':'), 1, 1, '_');
  8097. }
  8098. const std::string fname = "snd_trace_" + str_tnow + ".csv";
  8099. m_fout.open(fname, std::ofstream::out);
  8100. if (!m_fout)
  8101. std::cerr << "IPE: Failed to open " << fname << "!!!\n";
  8102. print_header();
  8103. }
  8104. private:
  8105. srt::sync::Mutex m_mtx;
  8106. std::ofstream m_fout;
  8107. srt::sync::steady_clock::time_point m_start_time;
  8108. };
  8109. snd_logger g_snd_logger;
  8110. #endif // SRT_DEBUG_TRACE_SND
  8111. void srt::CUDT::setPacketTS(CPacket& p, const time_point& ts)
  8112. {
  8113. enterCS(m_StatsLock);
  8114. const time_point tsStart = m_stats.tsStartTime;
  8115. leaveCS(m_StatsLock);
  8116. p.m_iTimeStamp = makeTS(ts, tsStart);
  8117. }
  8118. void srt::CUDT::setDataPacketTS(CPacket& p, const time_point& ts)
  8119. {
  8120. enterCS(m_StatsLock);
  8121. const time_point tsStart = m_stats.tsStartTime;
  8122. leaveCS(m_StatsLock);
  8123. if (!m_bPeerTsbPd)
  8124. {
  8125. // If TSBPD is disabled, use the current time as the source (timestamp using the sending time).
  8126. p.m_iTimeStamp = makeTS(steady_clock::now(), tsStart);
  8127. return;
  8128. }
  8129. // TODO: Might be better for performance to ensure this condition is always false, and just use SRT_ASSERT here.
  8130. if (ts < tsStart)
  8131. {
  8132. p.m_iTimeStamp = makeTS(steady_clock::now(), tsStart);
  8133. LOGC(qslog.Warn,
  8134. log << CONID() << "setPacketTS: reference time=" << FormatTime(ts)
  8135. << " is in the past towards start time=" << FormatTime(tsStart)
  8136. << " - setting NOW as reference time for the data packet");
  8137. return;
  8138. }
  8139. // Use the provided source time for the timestamp.
  8140. p.m_iTimeStamp = makeTS(ts, tsStart);
  8141. }
  8142. bool srt::CUDT::isRetransmissionAllowed(const time_point& tnow SRT_ATR_UNUSED)
  8143. {
  8144. // Prioritization of original packets only applies to Live CC.
  8145. if (!m_bPeerTLPktDrop || !m_config.bMessageAPI)
  8146. return true;
  8147. // TODO: lock sender buffer?
  8148. const time_point tsNextPacket = m_pSndBuffer->peekNextOriginal();
  8149. #if SRT_DEBUG_TRACE_SND
  8150. const int buffdelay_ms = count_milliseconds(m_pSndBuffer->getBufferingDelay(tnow));
  8151. // If there is a small loss, still better to retransmit. If timespan is already big,
  8152. // then consider sending original packets.
  8153. const int threshold_ms_min = (2 * m_iSRTT + 4 * m_iRTTVar + COMM_SYN_INTERVAL_US) / 1000;
  8154. const int msNextUniqueToSend = count_milliseconds(tnow - tsNextPacket) + m_iPeerTsbPdDelay_ms;
  8155. g_snd_logger.state.tsNow = tnow;
  8156. g_snd_logger.state.usElapsed = count_microseconds(tnow - m_stats.tsStartTime);
  8157. g_snd_logger.state.usSRTT = m_iSRTT;
  8158. g_snd_logger.state.usRTTVar = m_iRTTVar;
  8159. g_snd_logger.state.msSndBuffSpan = buffdelay_ms;
  8160. g_snd_logger.state.msTimespanTh = threshold_ms_min;
  8161. g_snd_logger.state.msNextUniqueToSend = msNextUniqueToSend;
  8162. g_snd_logger.state.usElapsedLastDrop = count_microseconds(tnow - m_tsLastTLDrop);
  8163. g_snd_logger.state.canRexmit = false;
  8164. #endif
  8165. if (tsNextPacket != time_point())
  8166. {
  8167. // Can send original packet, so just send it
  8168. return false;
  8169. }
  8170. #ifdef ENABLE_MAXREXMITBW
  8171. m_SndRexmitRate.addSample(tnow, 0, 0); // Update the estimation.
  8172. const int64_t iRexmitRateBps = m_SndRexmitRate.getRate();
  8173. const int64_t iRexmitRateLimitBps = m_config.llMaxRexmitBW;
  8174. if (iRexmitRateLimitBps >= 0 && iRexmitRateBps > iRexmitRateLimitBps)
  8175. {
  8176. // Too many retransmissions, so don't send anything.
  8177. // TODO: When to wake up next time?
  8178. return false;
  8179. }
  8180. #endif
  8181. #if SRT_DEBUG_TRACE_SND
  8182. g_snd_logger.state.canRexmit = true;
  8183. #endif
  8184. return true;
  8185. }
  8186. bool srt::CUDT::packData(CPacket& w_packet, steady_clock::time_point& w_nexttime, sockaddr_any& w_src_addr)
  8187. {
  8188. int payload = 0;
  8189. bool probe = false;
  8190. bool new_packet_packed = false;
  8191. const steady_clock::time_point enter_time = steady_clock::now();
  8192. w_nexttime = enter_time;
  8193. if (!is_zero(m_tsNextSendTime) && enter_time > m_tsNextSendTime)
  8194. {
  8195. m_tdSendTimeDiff = m_tdSendTimeDiff.load() + (enter_time - m_tsNextSendTime);
  8196. }
  8197. ScopedLock connectguard(m_ConnectionLock);
  8198. // If a closing action is done simultaneously, then
  8199. // m_bOpened should already be false, and it's set
  8200. // just before releasing this lock.
  8201. //
  8202. // If this lock is caught BEFORE the closing could
  8203. // start the dissolving process, this process will
  8204. // not be started until this function is finished.
  8205. if (!m_bOpened)
  8206. return false;
  8207. payload = isRetransmissionAllowed(enter_time)
  8208. ? packLostData((w_packet))
  8209. : 0;
  8210. IF_HEAVY_LOGGING(const char* reason); // The source of the data packet (normal/rexmit/filter)
  8211. if (payload > 0)
  8212. {
  8213. IF_HEAVY_LOGGING(reason = "reXmit");
  8214. }
  8215. else if (m_PacketFilter &&
  8216. m_PacketFilter.packControlPacket(m_iSndCurrSeqNo, m_pCryptoControl->getSndCryptoFlags(), (w_packet)))
  8217. {
  8218. HLOGC(qslog.Debug, log << CONID() << "filter: filter/CTL packet ready - packing instead of data.");
  8219. payload = (int) w_packet.getLength();
  8220. IF_HEAVY_LOGGING(reason = "filter");
  8221. // Stats
  8222. ScopedLock lg(m_StatsLock);
  8223. m_stats.sndr.sentFilterExtra.count(1);
  8224. }
  8225. else
  8226. {
  8227. if (!packUniqueData(w_packet))
  8228. {
  8229. m_tsNextSendTime = steady_clock::time_point();
  8230. m_tdSendTimeDiff = steady_clock::duration();
  8231. return false;
  8232. }
  8233. new_packet_packed = true;
  8234. // every 16 (0xF) packets, a packet pair is sent
  8235. if ((w_packet.m_iSeqNo & PUMASK_SEQNO_PROBE) == 0)
  8236. probe = true;
  8237. payload = (int) w_packet.getLength();
  8238. IF_HEAVY_LOGGING(reason = "normal");
  8239. }
  8240. w_packet.m_iID = m_PeerID; // Set the destination SRT socket ID.
  8241. if (new_packet_packed && m_PacketFilter)
  8242. {
  8243. HLOGC(qslog.Debug, log << CONID() << "filter: Feeding packet for source clip");
  8244. m_PacketFilter.feedSource((w_packet));
  8245. }
  8246. #if ENABLE_HEAVY_LOGGING // Required because of referring to MessageFlagStr()
  8247. HLOGC(qslog.Debug,
  8248. log << CONID() << "packData: " << reason << " packet seq=" << w_packet.m_iSeqNo << " (ACK=" << m_iSndLastAck
  8249. << " ACKDATA=" << m_iSndLastDataAck << " MSG/FLAGS: " << w_packet.MessageFlagStr() << ")");
  8250. #endif
  8251. // Fix keepalive
  8252. m_tsLastSndTime.store(enter_time);
  8253. considerLegacySrtHandshake(steady_clock::time_point());
  8254. // WARNING: TEV_SEND is the only event that is reported from
  8255. // the CSndQueue::worker thread. All others are reported from
  8256. // CRcvQueue::worker. If you connect to this signal, make sure
  8257. // that you are aware of prospective simultaneous access.
  8258. updateCC(TEV_SEND, EventVariant(&w_packet));
  8259. // XXX This was a blocked code also originally in UDT. Probably not required.
  8260. // Left untouched for historical reasons.
  8261. // Might be possible that it was because of that this is send from
  8262. // different thread than the rest of the signals.
  8263. // m_pSndTimeWindow->onPktSent(w_packet.m_iTimeStamp);
  8264. enterCS(m_StatsLock);
  8265. m_stats.sndr.sent.count(payload);
  8266. if (new_packet_packed)
  8267. m_stats.sndr.sentUnique.count(payload);
  8268. leaveCS(m_StatsLock);
  8269. const duration sendint = m_tdSendInterval;
  8270. if (probe)
  8271. {
  8272. // sends out probing packet pair
  8273. m_tsNextSendTime = enter_time;
  8274. // Sending earlier, need to adjust the pace later on.
  8275. m_tdSendTimeDiff = m_tdSendTimeDiff.load() - sendint;
  8276. probe = false;
  8277. }
  8278. else
  8279. {
  8280. #if USE_BUSY_WAITING
  8281. m_tsNextSendTime = enter_time + m_tdSendInterval.load();
  8282. #else
  8283. const duration sendbrw = m_tdSendTimeDiff;
  8284. if (sendbrw >= sendint)
  8285. {
  8286. // Send immediately
  8287. m_tsNextSendTime = enter_time;
  8288. // ATOMIC NOTE: this is the only thread that
  8289. // modifies this field
  8290. m_tdSendTimeDiff = sendbrw - sendint;
  8291. }
  8292. else
  8293. {
  8294. m_tsNextSendTime = enter_time + (sendint - sendbrw);
  8295. m_tdSendTimeDiff = duration();
  8296. }
  8297. #endif
  8298. }
  8299. HLOGC(qslog.Debug, log << "packData: Setting source address: " << m_SourceAddr.str());
  8300. w_src_addr = m_SourceAddr;
  8301. w_nexttime = m_tsNextSendTime;
  8302. return payload >= 0; // XXX shouldn't be > 0 ? == 0 is only when buffer range exceeded.
  8303. }
  8304. bool srt::CUDT::packUniqueData(CPacket& w_packet)
  8305. {
  8306. // Check the congestion/flow window limit
  8307. const int cwnd = std::min(int(m_iFlowWindowSize), int(m_dCongestionWindow));
  8308. const int flightspan = getFlightSpan();
  8309. if (cwnd <= flightspan)
  8310. {
  8311. HLOGC(qslog.Debug,
  8312. log << CONID() << "packUniqueData: CONGESTED: cwnd=min(" << m_iFlowWindowSize << "," << m_dCongestionWindow
  8313. << ")=" << cwnd << " seqlen=(" << m_iSndLastAck << "-" << m_iSndCurrSeqNo << ")=" << flightspan);
  8314. return false;
  8315. }
  8316. // XXX Here it's needed to set kflg to msgno_bitset in the block stored in the
  8317. // send buffer. This should be somehow avoided, the crypto flags should be set
  8318. // together with encrypting, and the packet should be sent as is, when rexmitting.
  8319. // It would be nice to research as to whether CSndBuffer::Block::m_iMsgNoBitset field
  8320. // isn't a useless redundant state copy. If it is, then taking the flags here can be removed.
  8321. const int kflg = m_pCryptoControl->getSndCryptoFlags();
  8322. int pktskipseqno = 0;
  8323. time_point tsOrigin;
  8324. const int pld_size = m_pSndBuffer->readData((w_packet), (tsOrigin), kflg, (pktskipseqno));
  8325. if (pktskipseqno)
  8326. {
  8327. // Some packets were skipped due to TTL expiry.
  8328. m_iSndCurrSeqNo = CSeqNo::incseq(m_iSndCurrSeqNo, pktskipseqno);
  8329. HLOGC(qslog.Debug, log << "packUniqueData: reading skipped " << pktskipseqno << " seq up to %" << m_iSndCurrSeqNo
  8330. << " due to TTL expiry");
  8331. }
  8332. if (pld_size == 0)
  8333. {
  8334. HLOGC(qslog.Debug, log << "packUniqueData: nothing extracted from the buffer");
  8335. return false;
  8336. }
  8337. // A CHANGE. The sequence number is currently added to the packet
  8338. // when scheduling, not when extracting. This is a inter-migration form,
  8339. // only override extraction sequence with scheduling sequence in group mode.
  8340. m_iSndCurrSeqNo = CSeqNo::incseq(m_iSndCurrSeqNo);
  8341. #if ENABLE_BONDING
  8342. // Fortunately the group itself isn't being accessed.
  8343. if (m_parent->m_GroupOf)
  8344. {
  8345. const int packetspan = CSeqNo::seqoff(m_iSndCurrSeqNo, w_packet.m_iSeqNo);
  8346. if (packetspan > 0)
  8347. {
  8348. // After increasing by 1, but being previously set as ISN-1, this should be == ISN,
  8349. // if this is the very first packet to send.
  8350. if (m_iSndCurrSeqNo == m_iISN)
  8351. {
  8352. // This is the very first packet to be sent; so there's nothing in
  8353. // the sending buffer yet, and therefore we are in a situation as just
  8354. // after connection. No packets in the buffer, no packets are sent,
  8355. // no ACK to be awaited. We can screw up all the variables that are
  8356. // initialized from ISN just after connection.
  8357. LOGC(qslog.Note,
  8358. log << CONID() << "packUniqueData: Fixing EXTRACTION sequence " << m_iSndCurrSeqNo
  8359. << " from SCHEDULING sequence " << w_packet.m_iSeqNo << " for the first packet: DIFF="
  8360. << packetspan << " STAMP=" << BufferStamp(w_packet.m_pcData, w_packet.getLength()));
  8361. }
  8362. else
  8363. {
  8364. // There will be a serious data discrepancy between the agent and the peer.
  8365. LOGC(qslog.Error,
  8366. log << CONID() << "IPE: packUniqueData: Fixing EXTRACTION sequence " << m_iSndCurrSeqNo
  8367. << " from SCHEDULING sequence " << w_packet.m_iSeqNo << " in the middle of transition: DIFF="
  8368. << packetspan << " STAMP=" << BufferStamp(w_packet.m_pcData, w_packet.getLength()));
  8369. }
  8370. // Additionally send the drop request to the peer so that it
  8371. // won't stupidly request the packets to be retransmitted.
  8372. // Don't do it if the difference isn't positive or exceeds the threshold.
  8373. int32_t seqpair[2];
  8374. seqpair[0] = m_iSndCurrSeqNo;
  8375. seqpair[1] = CSeqNo::decseq(w_packet.m_iSeqNo);
  8376. const int32_t no_msgno = 0;
  8377. LOGC(qslog.Debug,
  8378. log << CONID() << "packUniqueData: Sending DROPREQ: SEQ: " << seqpair[0] << " - " << seqpair[1] << " ("
  8379. << packetspan << " packets)");
  8380. sendCtrl(UMSG_DROPREQ, &no_msgno, seqpair, sizeof(seqpair));
  8381. // In case when this message is lost, the peer will still get the
  8382. // UMSG_DROPREQ message when the agent realizes that the requested
  8383. // packet are not present in the buffer (preadte the send buffer).
  8384. // Override extraction sequence with scheduling sequence.
  8385. m_iSndCurrSeqNo = w_packet.m_iSeqNo;
  8386. ScopedLock ackguard(m_RecvAckLock);
  8387. m_iSndLastAck = w_packet.m_iSeqNo;
  8388. m_iSndLastDataAck = w_packet.m_iSeqNo;
  8389. m_iSndLastFullAck = w_packet.m_iSeqNo;
  8390. m_iSndLastAck2 = w_packet.m_iSeqNo;
  8391. }
  8392. else if (packetspan < 0)
  8393. {
  8394. LOGC(qslog.Error,
  8395. log << CONID() << "IPE: packData: SCHEDULING sequence " << w_packet.m_iSeqNo
  8396. << " is behind of EXTRACTION sequence " << m_iSndCurrSeqNo << ", dropping this packet: DIFF="
  8397. << packetspan << " STAMP=" << BufferStamp(w_packet.m_pcData, w_packet.getLength()));
  8398. // XXX: Probably also change the socket state to broken?
  8399. return false;
  8400. }
  8401. }
  8402. else
  8403. #endif
  8404. {
  8405. HLOGC(qslog.Debug,
  8406. log << CONID() << "packUniqueData: Applying EXTRACTION sequence " << m_iSndCurrSeqNo
  8407. << " over SCHEDULING sequence " << w_packet.m_iSeqNo << " for socket not in group:"
  8408. << " DIFF=" << CSeqNo::seqcmp(m_iSndCurrSeqNo, w_packet.m_iSeqNo)
  8409. << " STAMP=" << BufferStamp(w_packet.m_pcData, w_packet.getLength()));
  8410. // Do this always when not in a group.
  8411. w_packet.m_iSeqNo = m_iSndCurrSeqNo;
  8412. }
  8413. // Set missing fields before encrypting the packet, because those fields might be used for encryption.
  8414. w_packet.m_iID = m_PeerID; // Destination SRT Socket ID
  8415. setDataPacketTS(w_packet, tsOrigin);
  8416. if (kflg != EK_NOENC)
  8417. {
  8418. // Note that the packet header must have a valid seqno set, as it is used as a counter for encryption.
  8419. // Other fields of the data packet header (e.g. timestamp, destination socket ID) are not used for the counter.
  8420. // Cypher may change packet length!
  8421. if (m_pCryptoControl->encrypt((w_packet)) != ENCS_CLEAR)
  8422. {
  8423. // Encryption failed
  8424. //>>Add stats for crypto failure
  8425. LOGC(qslog.Warn, log << CONID() << "ENCRYPT FAILED - packet won't be sent, size=" << pld_size);
  8426. return false;
  8427. }
  8428. checkSndKMRefresh();
  8429. }
  8430. #if SRT_DEBUG_TRACE_SND
  8431. g_snd_logger.state.iPktSeqno = w_packet.m_iSeqNo;
  8432. g_snd_logger.state.isRetransmitted = w_packet.getRexmitFlag();
  8433. g_snd_logger.trace();
  8434. #endif
  8435. return true;
  8436. }
  8437. // This is a close request, but called from the
  8438. void srt::CUDT::processClose()
  8439. {
  8440. sendCtrl(UMSG_SHUTDOWN);
  8441. m_bShutdown = true;
  8442. m_bClosing = true;
  8443. m_bBroken = true;
  8444. m_iBrokenCounter = 60;
  8445. HLOGP(smlog.Debug, "processClose: sent message and set flags");
  8446. if (m_bTsbPd)
  8447. {
  8448. HLOGP(smlog.Debug, "processClose: lock-and-signal TSBPD");
  8449. CSync::lock_notify_one(m_RcvTsbPdCond, m_RecvLock);
  8450. }
  8451. // Signal the sender and recver if they are waiting for data.
  8452. releaseSynch();
  8453. // Unblock any call so they learn the connection_broken error
  8454. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_ERR, true);
  8455. HLOGP(smlog.Debug, "processClose: triggering timer event to spread the bad news");
  8456. CGlobEvent::triggerEvent();
  8457. }
  8458. void srt::CUDT::sendLossReport(const std::vector<std::pair<int32_t, int32_t> > &loss_seqs)
  8459. {
  8460. vector<int32_t> seqbuffer;
  8461. seqbuffer.reserve(2 * loss_seqs.size()); // pessimistic
  8462. for (loss_seqs_t::const_iterator i = loss_seqs.begin(); i != loss_seqs.end(); ++i)
  8463. {
  8464. if (i->first == i->second)
  8465. {
  8466. seqbuffer.push_back(i->first);
  8467. HLOGC(qrlog.Debug, log << "lost packet " << i->first << ": sending LOSSREPORT");
  8468. }
  8469. else
  8470. {
  8471. seqbuffer.push_back(i->first | LOSSDATA_SEQNO_RANGE_FIRST);
  8472. seqbuffer.push_back(i->second);
  8473. HLOGC(qrlog.Debug, log << "lost packets " << i->first << "-" << i->second
  8474. << " (" << (1 + CSeqNo::seqcmp(i->second, i->first)) << " packets): sending LOSSREPORT");
  8475. }
  8476. }
  8477. if (!seqbuffer.empty())
  8478. {
  8479. sendCtrl(UMSG_LOSSREPORT, NULL, &seqbuffer[0], (int) seqbuffer.size());
  8480. }
  8481. }
  8482. bool srt::CUDT::overrideSndSeqNo(int32_t seq)
  8483. {
  8484. // This function is intended to be called from the socket
  8485. // group management functions to synchronize the sequnece in
  8486. // all sockes in the bonding group. THIS sequence given
  8487. // here is the sequence TO BE STAMPED AT THE EXACTLY NEXT
  8488. // sent payload. Therefore, screw up the ISN to exactly this
  8489. // value, and the send sequence to the value one less - because
  8490. // the m_iSndCurrSeqNo is increased by one immediately before
  8491. // stamping it to the packet.
  8492. // This function can only be called:
  8493. // - from the operation on an idle socket in the socket group
  8494. // - IMMEDIATELY after connection established and BEFORE the first payload
  8495. // - The corresponding socket at the peer side must be also
  8496. // in this idle state!
  8497. ScopedLock cg (m_RecvAckLock);
  8498. // Both the scheduling and sending sequences should be fixed.
  8499. // The new sequence normally should jump over several sequence numbers
  8500. // towards what is currently in m_iSndCurrSeqNo.
  8501. // Therefore it's not allowed that:
  8502. // - the jump go backward: backward packets should be already there
  8503. // - the jump go forward by a value larger than half the period: DISCREPANCY.
  8504. const int diff = CSeqNo(seq) - CSeqNo(m_iSndCurrSeqNo);
  8505. if (diff < 0 || diff > CSeqNo::m_iSeqNoTH)
  8506. {
  8507. LOGC(gslog.Error, log << CONID() << "IPE: Overriding with seq %" << seq << " DISCREPANCY against current %"
  8508. << m_iSndCurrSeqNo << " and next sched %" << m_iSndNextSeqNo << " - diff=" << diff);
  8509. return false;
  8510. }
  8511. //
  8512. // The peer will have to do the same, as a reaction on perceived
  8513. // packet loss. When it recognizes that this initial screwing up
  8514. // has happened, it should simply ignore the loss and go on.
  8515. // ISN isn't being changed here - it doesn't make much sense now.
  8516. setInitialSndSeq(seq);
  8517. // m_iSndCurrSeqNo will be most likely lower than m_iSndNextSeqNo because
  8518. // the latter is ahead with the number of packets already scheduled, but
  8519. // not yet sent.
  8520. HLOGC(gslog.Debug,
  8521. log << CONID() << "overrideSndSeqNo: sched-seq=" << m_iSndNextSeqNo << " send-seq=" << m_iSndCurrSeqNo
  8522. << " (unchanged)");
  8523. return true;
  8524. }
  8525. int srt::CUDT::checkLazySpawnTsbPdThread()
  8526. {
  8527. const bool need_tsbpd = m_bTsbPd || m_bGroupTsbPd;
  8528. if (need_tsbpd && !m_RcvTsbPdThread.joinable())
  8529. {
  8530. ScopedLock lock(m_RcvTsbPdStartupLock);
  8531. if (m_bClosing) // Check again to protect join() in CUDT::releaseSync()
  8532. return -1;
  8533. HLOGP(qrlog.Debug, "Spawning Socket TSBPD thread");
  8534. #if ENABLE_HEAVY_LOGGING
  8535. std::ostringstream tns1, tns2;
  8536. // Take the last 2 ciphers from the socket ID.
  8537. tns1 << setfill('0') << setw(2) << m_SocketID;
  8538. std::string s = tns1.str();
  8539. tns2 << "SRT:TsbPd:@" << s.substr(s.size()-2, 2);
  8540. const string thname = tns2.str();
  8541. #else
  8542. const string thname = "SRT:TsbPd";
  8543. #endif
  8544. if (!StartThread(m_RcvTsbPdThread, CUDT::tsbpd, this, thname))
  8545. return -1;
  8546. }
  8547. return 0;
  8548. }
  8549. CUDT::time_point srt::CUDT::getPktTsbPdTime(void*, const CPacket& packet)
  8550. {
  8551. return m_pRcvBuffer->getPktTsbPdTime(packet.getMsgTimeStamp());
  8552. }
  8553. SRT_ATR_UNUSED static const char *const s_rexmitstat_str[] = {"ORIGINAL", "REXMITTED", "RXS-UNKNOWN"};
  8554. // [[using locked(m_RcvBufferLock)]]
  8555. int srt::CUDT::handleSocketPacketReception(const vector<CUnit*>& incoming, bool& w_new_inserted, bool& w_was_sent_in_order, CUDT::loss_seqs_t& w_srt_loss_seqs)
  8556. {
  8557. bool excessive SRT_ATR_UNUSED = true; // stays true unless it was successfully added
  8558. w_new_inserted = false;
  8559. const int32_t bufseq = m_pRcvBuffer->getStartSeqNo();
  8560. // Loop over all incoming packets that were filtered out.
  8561. // In case when there is no filter, there's just one packet in 'incoming',
  8562. // the one that came in the input of this function.
  8563. for (vector<CUnit *>::const_iterator unitIt = incoming.begin(); unitIt != incoming.end(); ++unitIt)
  8564. {
  8565. CUnit * u = *unitIt;
  8566. CPacket &rpkt = u->m_Packet;
  8567. const int pktrexmitflag = m_bPeerRexmitFlag ? (rpkt.getRexmitFlag() ? 1 : 0) : 2;
  8568. const bool retransmitted = pktrexmitflag == 1;
  8569. bool adding_successful = true;
  8570. const int32_t bufidx = CSeqNo::seqoff(bufseq, rpkt.m_iSeqNo);
  8571. IF_HEAVY_LOGGING(const char *exc_type = "EXPECTED");
  8572. // bufidx < 0: the packet is in the past for the buffer
  8573. // seqno <% m_iRcvLastAck : the sequence may be within the buffer,
  8574. // but if so, it is in the acknowledged-but-not-retrieved area.
  8575. // NOTE: if we have a situation when there are any packets in the
  8576. // acknowledged area, but they aren't retrieved, this area DOES NOT
  8577. // contain any losses. So a packet in this area is at best a duplicate.
  8578. // In case when a loss would be abandoned (TLPKTDROP), there must at
  8579. // some point happen to be an empty first cell in the buffer, followed
  8580. // somewhere by a valid packet. If this state is achieved at some point,
  8581. // the acknowledgement sequence should be equal to the beginning of the
  8582. // buffer. Then, when TSBPD decides to drop these initial empty cells,
  8583. // we'll have: (m_iRcvLastAck <% buffer->getStartSeqNo()) - and in this
  8584. // case (bufidx < 0) condition will be satisfied also for this case.
  8585. //
  8586. // The only case when bufidx > 0, but packet seq is <% m_iRcvLastAck
  8587. // is when the packet sequence is within the initial contiguous area,
  8588. // which never contains losses, so discarding this packet does not
  8589. // discard a loss coverage, even if this were past ACK.
  8590. if (bufidx < 0 || CSeqNo::seqcmp(rpkt.m_iSeqNo, m_iRcvLastAck) < 0)
  8591. {
  8592. time_point pts = getPktTsbPdTime(NULL, rpkt);
  8593. enterCS(m_StatsLock);
  8594. const double bltime = (double) CountIIR<uint64_t>(
  8595. uint64_t(m_stats.traceBelatedTime) * 1000,
  8596. count_microseconds(steady_clock::now() - pts), 0.2);
  8597. m_stats.traceBelatedTime = bltime / 1000.0;
  8598. m_stats.rcvr.recvdBelated.count(rpkt.getLength());
  8599. leaveCS(m_StatsLock);
  8600. HLOGC(qrlog.Debug,
  8601. log << CONID() << "RECEIVED: %" << rpkt.m_iSeqNo << " bufidx=" << bufidx << " (BELATED/"
  8602. << s_rexmitstat_str[pktrexmitflag] << ") with ACK %" << m_iRcvLastAck
  8603. << " FLAGS: " << rpkt.MessageFlagStr());
  8604. continue;
  8605. }
  8606. if (bufidx >= int(m_pRcvBuffer->capacity()))
  8607. {
  8608. // This is already a sequence discrepancy. Probably there could be found
  8609. // some way to make it continue reception by overriding the sequence and
  8610. // make a kinda TLKPTDROP, but there has been found no reliable way to do this.
  8611. if (m_bTsbPd && m_bTLPktDrop && m_pRcvBuffer->empty())
  8612. {
  8613. // Only in live mode. In File mode this shall not be possible
  8614. // because the sender should stop sending in this situation.
  8615. // In Live mode this means that there is a gap between the
  8616. // lowest sequence in the empty buffer and the incoming sequence
  8617. // that exceeds the buffer size. Receiving data in this situation
  8618. // is no longer possible and this is a point of no return.
  8619. LOGC(qrlog.Error, log << CONID() <<
  8620. "SEQUENCE DISCREPANCY. BREAKING CONNECTION."
  8621. " %" << rpkt.m_iSeqNo
  8622. << " buffer=(%" << bufseq
  8623. << ":%" << m_iRcvCurrSeqNo // -1 = size to last index
  8624. << "+%" << CSeqNo::incseq(bufseq, int(m_pRcvBuffer->capacity()) - 1)
  8625. << "), " << (m_pRcvBuffer->capacity() - bufidx + 1)
  8626. << " past max. Reception no longer possible. REQUESTING TO CLOSE.");
  8627. return -2;
  8628. }
  8629. else
  8630. {
  8631. LOGC(qrlog.Warn, log << CONID() << "No room to store incoming packet seqno " << rpkt.m_iSeqNo
  8632. << ", insert offset " << bufidx << ". "
  8633. << m_pRcvBuffer->strFullnessState(m_iRcvLastAck, steady_clock::now())
  8634. );
  8635. return -1;
  8636. }
  8637. }
  8638. const int buffer_add_result = m_pRcvBuffer->insert(u);
  8639. if (buffer_add_result < 0)
  8640. {
  8641. // The insert() result is -1 if at the position evaluated from this packet's
  8642. // sequence number there already is a packet.
  8643. // So this packet is "redundant".
  8644. IF_HEAVY_LOGGING(exc_type = "UNACKED");
  8645. adding_successful = false;
  8646. }
  8647. else
  8648. {
  8649. w_new_inserted = true;
  8650. IF_HEAVY_LOGGING(exc_type = "ACCEPTED");
  8651. excessive = false;
  8652. if (u->m_Packet.getMsgCryptoFlags() != EK_NOENC)
  8653. {
  8654. // TODO: reset and restore the timestamp if TSBPD is disabled.
  8655. // Reset retransmission flag (must be excluded from GCM auth tag).
  8656. u->m_Packet.setRexmitFlag(false);
  8657. const EncryptionStatus rc = m_pCryptoControl ? m_pCryptoControl->decrypt((u->m_Packet)) : ENCS_NOTSUP;
  8658. u->m_Packet.setRexmitFlag(retransmitted); // Recover the flag.
  8659. if (rc != ENCS_CLEAR)
  8660. {
  8661. adding_successful = false;
  8662. IF_HEAVY_LOGGING(exc_type = "UNDECRYPTED");
  8663. // If TSBPD is disabled, then SRT either operates in buffer mode, of in message API without a restriction
  8664. // of a single message packet. In that case just dropping a packet is not enough.
  8665. // In message mode the whole message has to be dropped.
  8666. // However, when decryption fails the message number in the packet cannot be trusted.
  8667. // The packet has to be removed from the RCV buffer based on that pkt sequence number,
  8668. // and the sequence number itself must go into the RCV loss list.
  8669. // See issue ##2626.
  8670. SRT_ASSERT(m_bTsbPd);
  8671. // Drop the packet from the receiver buffer.
  8672. // The packet was added to the buffer based on the sequence number, therefore sequence number should be used to drop it from the buffer.
  8673. // A drawback is that it would prevent a valid packet with the same sequence number, if it happens to arrive later, to end up in the buffer.
  8674. const int iDropCnt = m_pRcvBuffer->dropMessage(u->m_Packet.getSeqNo(), u->m_Packet.getSeqNo(), SRT_MSGNO_NONE, CRcvBuffer::DROP_EXISTING);
  8675. const steady_clock::time_point tnow = steady_clock::now();
  8676. ScopedLock lg(m_StatsLock);
  8677. m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * rpkt.getLength(), iDropCnt));
  8678. m_stats.rcvr.undecrypted.count(stats::BytesPackets(rpkt.getLength(), 1));
  8679. if (frequentLogAllowed(tnow))
  8680. {
  8681. LOGC(qrlog.Warn, log << CONID() << "Decryption failed (seqno %" << u->m_Packet.getSeqNo() << "), dropped "
  8682. << iDropCnt << ". pktRcvUndecryptTotal=" << m_stats.rcvr.undecrypted.total.count() << ".");
  8683. m_tsLogSlowDown = tnow;
  8684. }
  8685. }
  8686. }
  8687. else if (m_pCryptoControl && m_pCryptoControl->getCryptoMode() == CSrtConfig::CIPHER_MODE_AES_GCM)
  8688. {
  8689. // Unencrypted packets are not allowed.
  8690. const int iDropCnt = m_pRcvBuffer->dropMessage(u->m_Packet.getSeqNo(), u->m_Packet.getSeqNo(), SRT_MSGNO_NONE, CRcvBuffer::DROP_EXISTING);
  8691. const steady_clock::time_point tnow = steady_clock::now();
  8692. ScopedLock lg(m_StatsLock);
  8693. m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt* rpkt.getLength(), iDropCnt));
  8694. m_stats.rcvr.undecrypted.count(stats::BytesPackets(rpkt.getLength(), 1));
  8695. if (frequentLogAllowed(tnow))
  8696. {
  8697. LOGC(qrlog.Warn, log << CONID() << "Packet not encrypted (seqno %" << u->m_Packet.getSeqNo() << "), dropped "
  8698. << iDropCnt << ". pktRcvUndecryptTotal=" << m_stats.rcvr.undecrypted.total.count() << ".");
  8699. m_tsLogSlowDown = tnow;
  8700. }
  8701. }
  8702. }
  8703. if (adding_successful)
  8704. {
  8705. ScopedLock statslock(m_StatsLock);
  8706. m_stats.rcvr.recvdUnique.count(u->m_Packet.getLength());
  8707. }
  8708. #if ENABLE_HEAVY_LOGGING
  8709. std::ostringstream expectspec;
  8710. if (excessive)
  8711. expectspec << "EXCESSIVE(" << exc_type << ")";
  8712. else
  8713. expectspec << "ACCEPTED";
  8714. std::ostringstream bufinfo;
  8715. if (m_pRcvBuffer)
  8716. {
  8717. // XXX Fix this when the end of contiguous region detection is added.
  8718. const int ackidx = std::max(0, CSeqNo::seqoff(m_pRcvBuffer->getStartSeqNo(), m_iRcvLastAck));
  8719. bufinfo << " BUF.s=" << m_pRcvBuffer->capacity()
  8720. << " avail=" << (int(m_pRcvBuffer->capacity()) - ackidx)
  8721. << " buffer=(%" << bufseq
  8722. << ":%" << m_iRcvCurrSeqNo // -1 = size to last index
  8723. << "+%" << CSeqNo::incseq(bufseq, int(m_pRcvBuffer->capacity()) - 1)
  8724. << ")";
  8725. }
  8726. // Empty buffer info in case of groupwise receiver.
  8727. // There's no way to obtain this information here.
  8728. LOGC(qrlog.Debug, log << CONID() << "RECEIVED: %" << rpkt.m_iSeqNo
  8729. << bufinfo.str()
  8730. << " RSL=" << expectspec.str()
  8731. << " SN=" << s_rexmitstat_str[pktrexmitflag]
  8732. << " FLAGS: "
  8733. << rpkt.MessageFlagStr());
  8734. #endif
  8735. // Decryption should have made the crypto flags EK_NOENC.
  8736. // Otherwise it's an error.
  8737. if (adding_successful)
  8738. {
  8739. HLOGC(qrlog.Debug,
  8740. log << CONID()
  8741. << "CONTIGUITY CHECK: sequence distance: " << CSeqNo::seqoff(m_iRcvCurrSeqNo, rpkt.m_iSeqNo));
  8742. if (CSeqNo::seqcmp(rpkt.m_iSeqNo, CSeqNo::incseq(m_iRcvCurrSeqNo)) > 0) // Loss detection.
  8743. {
  8744. int32_t seqlo = CSeqNo::incseq(m_iRcvCurrSeqNo);
  8745. int32_t seqhi = CSeqNo::decseq(rpkt.m_iSeqNo);
  8746. w_srt_loss_seqs.push_back(make_pair(seqlo, seqhi));
  8747. HLOGC(qrlog.Debug, log << "pkt/LOSS DETECTED: %" << seqlo << " - %" << seqhi);
  8748. }
  8749. }
  8750. // Update the current largest sequence number that has been received.
  8751. // Or it is a retransmitted packet, remove it from receiver loss list.
  8752. if (CSeqNo::seqcmp(rpkt.m_iSeqNo, m_iRcvCurrSeqNo) > 0)
  8753. {
  8754. m_iRcvCurrSeqNo = rpkt.m_iSeqNo; // Latest possible received
  8755. }
  8756. else
  8757. {
  8758. unlose(rpkt); // was BELATED or RETRANSMITTED
  8759. w_was_sent_in_order &= 0 != pktrexmitflag;
  8760. }
  8761. }
  8762. return 0;
  8763. }
  8764. int srt::CUDT::processData(CUnit* in_unit)
  8765. {
  8766. if (m_bClosing)
  8767. return -1;
  8768. CPacket &packet = in_unit->m_Packet;
  8769. // Just heard from the peer, reset the expiration count.
  8770. m_iEXPCount = 1;
  8771. m_tsLastRspTime.store(steady_clock::now());
  8772. // We are receiving data, start tsbpd thread if TsbPd is enabled
  8773. if (-1 == checkLazySpawnTsbPdThread())
  8774. {
  8775. return -1;
  8776. }
  8777. const int pktrexmitflag = m_bPeerRexmitFlag ? (packet.getRexmitFlag() ? 1 : 0) : 2;
  8778. const bool retransmitted = pktrexmitflag == 1;
  8779. #if ENABLE_HEAVY_LOGGING
  8780. string rexmit_reason;
  8781. #endif
  8782. if (retransmitted)
  8783. {
  8784. // This packet was retransmitted
  8785. enterCS(m_StatsLock);
  8786. m_stats.rcvr.recvdRetrans.count(packet.getLength());
  8787. leaveCS(m_StatsLock);
  8788. #if ENABLE_HEAVY_LOGGING
  8789. // Check if packet was retransmitted on request or on ack timeout
  8790. // Search the sequence in the loss record.
  8791. rexmit_reason = " by ";
  8792. ScopedLock lock(m_RcvLossLock);
  8793. if (!m_pRcvLossList->find(packet.m_iSeqNo, packet.m_iSeqNo))
  8794. rexmit_reason += "BLIND";
  8795. else
  8796. rexmit_reason += "NAKREPORT";
  8797. #endif
  8798. }
  8799. #if ENABLE_HEAVY_LOGGING
  8800. {
  8801. steady_clock::duration tsbpddelay = milliseconds_from(m_iTsbPdDelay_ms); // (value passed to CRcvBuffer::setRcvTsbPdMode)
  8802. // It's easier to remove the latency factor from this value than to add a function
  8803. // that exposes the details basing on which this value is calculated.
  8804. steady_clock::time_point pts = m_pRcvBuffer->getPktTsbPdTime(packet.getMsgTimeStamp());
  8805. steady_clock::time_point ets = pts - tsbpddelay;
  8806. HLOGC(qrlog.Debug, log << CONID() << "processData: RECEIVED DATA: size=" << packet.getLength()
  8807. << " seq=" << packet.getSeqNo()
  8808. // XXX FIX IT. OTS should represent the original sending time, but it's relative.
  8809. //<< " OTS=" << FormatTime(packet.getMsgTimeStamp())
  8810. << " ETS=" << FormatTime(ets)
  8811. << " PTS=" << FormatTime(pts));
  8812. }
  8813. #endif
  8814. updateCC(TEV_RECEIVE, EventVariant(&packet));
  8815. ++m_iPktCount;
  8816. const int pktsz = (int) packet.getLength();
  8817. // Update time information
  8818. // XXX Note that this adds the byte size of a packet
  8819. // of which we don't yet know as to whether this has
  8820. // carried out some useful data or some excessive data
  8821. // that will be later discarded.
  8822. // FIXME: before adding this on the rcv time window,
  8823. // make sure that this packet isn't going to be
  8824. // effectively discarded, as repeated retransmission,
  8825. // for example, burdens the link, but doesn't better the speed.
  8826. m_RcvTimeWindow.onPktArrival(pktsz);
  8827. // Probe the packet pair if needed.
  8828. // Conditions and any extra data required for the packet
  8829. // this function will extract and test as needed.
  8830. const bool unordered = CSeqNo::seqcmp(packet.m_iSeqNo, m_iRcvCurrSeqNo) <= 0;
  8831. // Retransmitted and unordered packets do not provide expected measurement.
  8832. // We expect the 16th and 17th packet to be sent regularly,
  8833. // otherwise measurement must be rejected.
  8834. m_RcvTimeWindow.probeArrival(packet, unordered || retransmitted);
  8835. enterCS(m_StatsLock);
  8836. m_stats.rcvr.recvd.count(pktsz);
  8837. leaveCS(m_StatsLock);
  8838. loss_seqs_t filter_loss_seqs;
  8839. loss_seqs_t srt_loss_seqs;
  8840. vector<CUnit *> incoming;
  8841. bool was_sent_in_order = true;
  8842. // If the peer doesn't understand REXMIT flag, send rexmit request
  8843. // always immediately.
  8844. int initial_loss_ttl = 0;
  8845. if (m_bPeerRexmitFlag)
  8846. initial_loss_ttl = m_iReorderTolerance;
  8847. // Track packet loss in statistics early, because a packet filter (e.g. FEC) might recover it later on,
  8848. // supply the missing packet(s), and the loss will no longer be visible for the code that follows.
  8849. if (packet.getMsgSeq(m_bPeerRexmitFlag) != SRT_MSGNO_CONTROL) // disregard filter-control packets, their seq may mean nothing
  8850. {
  8851. const int diff = CSeqNo::seqoff(m_iRcvCurrPhySeqNo, packet.m_iSeqNo);
  8852. // Difference between these two sequence numbers is expected to be:
  8853. // 0 - duplicated last packet (theory only)
  8854. // 1 - subsequent packet (alright)
  8855. // <0 - belated or recovered packet
  8856. // >1 - jump over a packet loss (loss = seqdiff-1)
  8857. if (diff > 1)
  8858. {
  8859. const int loss = diff - 1; // loss is all that is above diff == 1
  8860. ScopedLock lg(m_StatsLock);
  8861. const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize();
  8862. m_stats.rcvr.lost.count(stats::BytesPackets(loss * avgpayloadsz, (uint32_t) loss));
  8863. HLOGC(qrlog.Debug,
  8864. log << CONID() << "LOSS STATS: n=" << loss << " SEQ: [" << CSeqNo::incseq(m_iRcvCurrPhySeqNo) << " "
  8865. << CSeqNo::decseq(packet.m_iSeqNo) << "]");
  8866. }
  8867. if (diff > 0)
  8868. {
  8869. // Record if it was further than latest
  8870. m_iRcvCurrPhySeqNo = packet.m_iSeqNo;
  8871. }
  8872. }
  8873. // [[using locked()]]; // (NOTHING locked)
  8874. #if ENABLE_BONDING
  8875. // Switch to RUNNING even if there was a discrepancy, unless
  8876. // it was long way forward.
  8877. // XXX Important: This code is in the dead function defaultPacketArrival
  8878. // but normally it should be called here regardless if the packet was
  8879. // accepted or rejected because if it was belated it may result in a
  8880. // "runaway train" problem as the IDLE links are being updated the base
  8881. // reception sequence pointer stating that this link is not receiving.
  8882. if (m_parent->m_GroupOf)
  8883. {
  8884. ScopedLock protect_group_existence (uglobal().m_GlobControlLock);
  8885. groups::SocketData* gi = m_parent->m_GroupMemberData;
  8886. // This check is needed as after getting the lock the socket
  8887. // could be potentially removed. It is however granted that as long
  8888. // as gi is non-NULL iterator, the group does exist and it does contain
  8889. // this socket as member (that is, 'gi' cannot be a dangling pointer).
  8890. if (gi != NULL)
  8891. {
  8892. if (gi->rcvstate < SRT_GST_RUNNING) // PENDING or IDLE, tho PENDING is unlikely
  8893. {
  8894. HLOGC(qrlog.Debug,
  8895. log << CONID() << "processData: IN-GROUP rcv state transition " << srt_log_grp_state[gi->rcvstate]
  8896. << " -> RUNNING.");
  8897. gi->rcvstate = SRT_GST_RUNNING;
  8898. }
  8899. else
  8900. {
  8901. HLOGC(qrlog.Debug,
  8902. log << CONID() << "processData: IN-GROUP rcv state transition NOT DONE - state:"
  8903. << srt_log_grp_state[gi->rcvstate]);
  8904. }
  8905. }
  8906. }
  8907. #endif
  8908. bool new_inserted = false;
  8909. if (m_PacketFilter)
  8910. {
  8911. // Stuff this data into the filter
  8912. m_PacketFilter.receive(in_unit, (incoming), (filter_loss_seqs));
  8913. HLOGC(qrlog.Debug,
  8914. log << CONID() << "(FILTER) fed data, received " << incoming.size() << " pkts, " << Printable(filter_loss_seqs)
  8915. << " loss to report, "
  8916. << (m_PktFilterRexmitLevel == SRT_ARQ_ALWAYS ? "FIND & REPORT LOSSES YOURSELF"
  8917. : "REPORT ONLY THOSE"));
  8918. }
  8919. else
  8920. {
  8921. // Stuff in just one packet that has come in.
  8922. incoming.push_back(in_unit);
  8923. }
  8924. {
  8925. // Start of offset protected section
  8926. // Prevent TsbPd thread from modifying Ack position while adding data
  8927. // offset from RcvLastAck in RcvBuffer must remain valid between seqoff() and addData()
  8928. UniqueLock recvbuf_acklock(m_RcvBufferLock);
  8929. // Needed for possibly check for needsQuickACK.
  8930. const bool incoming_belated = (CSeqNo::seqcmp(in_unit->m_Packet.m_iSeqNo, m_pRcvBuffer->getStartSeqNo()) < 0);
  8931. const int res = handleSocketPacketReception(incoming,
  8932. (new_inserted),
  8933. (was_sent_in_order),
  8934. (srt_loss_seqs));
  8935. if (res == -2)
  8936. {
  8937. // This is a scoped lock with AckLock, but for the moment
  8938. // when processClose() is called this lock must be taken out,
  8939. // otherwise this will cause a deadlock. We don't need this
  8940. // lock anymore, and at 'return' it will be unlocked anyway.
  8941. recvbuf_acklock.unlock();
  8942. processClose();
  8943. return -1;
  8944. }
  8945. if (res == -1)
  8946. {
  8947. return -1;
  8948. }
  8949. if (!srt_loss_seqs.empty())
  8950. {
  8951. ScopedLock lock(m_RcvLossLock);
  8952. HLOGC(qrlog.Debug,
  8953. log << CONID() << "processData: RECORDING LOSS: " << Printable(srt_loss_seqs)
  8954. << " tolerance=" << initial_loss_ttl);
  8955. for (loss_seqs_t::iterator i = srt_loss_seqs.begin(); i != srt_loss_seqs.end(); ++i)
  8956. {
  8957. m_pRcvLossList->insert(i->first, i->second);
  8958. if (initial_loss_ttl)
  8959. {
  8960. // The LOSSREPORT will be sent after initial_loss_ttl.
  8961. m_FreshLoss.push_back(CRcvFreshLoss(i->first, i->second, initial_loss_ttl));
  8962. }
  8963. }
  8964. }
  8965. // This is moved earlier after introducing filter because it shouldn't
  8966. // be executed in case when the packet was rejected by the receiver buffer.
  8967. // However now the 'excessive' condition may be true also in case when
  8968. // a truly non-excessive packet has been received, just it has been temporarily
  8969. // stored for better times by the filter module. This way 'excessive' is also true,
  8970. // although the old condition that a packet with a newer sequence number has arrived
  8971. // or arrived out of order may still be satisfied.
  8972. if (!incoming_belated && was_sent_in_order)
  8973. {
  8974. // Basing on some special case in the packet, it might be required
  8975. // to enforce sending ACK immediately (earlier than normally after
  8976. // a given period).
  8977. if (m_CongCtl->needsQuickACK(packet))
  8978. {
  8979. m_tsNextACKTime.store(steady_clock::now());
  8980. }
  8981. }
  8982. if (!new_inserted)
  8983. {
  8984. return -1;
  8985. }
  8986. } // End of recvbuf_acklock
  8987. if (m_bClosing)
  8988. {
  8989. // RcvQueue worker thread can call processData while closing (or close while processData)
  8990. // This race condition exists in the UDT design but the protection against TsbPd thread
  8991. // (with AckLock) and decryption enlarged the probability window.
  8992. // Application can crash deep in decrypt stack since crypto context is deleted in close.
  8993. // RcvQueue worker thread will not necessarily be deleted with this connection as it can be
  8994. // used by others (socket multiplexer).
  8995. return -1;
  8996. }
  8997. if (incoming.empty())
  8998. {
  8999. // Treat as excessive. This is when a filter cumulates packets
  9000. // until the loss is rebuilt, or eats up a filter control packet
  9001. return -1;
  9002. }
  9003. if (!srt_loss_seqs.empty())
  9004. {
  9005. const bool report_recorded_loss = !m_PacketFilter || m_PktFilterRexmitLevel == SRT_ARQ_ALWAYS;
  9006. if (!initial_loss_ttl && report_recorded_loss)
  9007. {
  9008. HLOGC(qrlog.Debug, log << CONID() << "WILL REPORT LOSSES (SRT): " << Printable(srt_loss_seqs));
  9009. sendLossReport(srt_loss_seqs);
  9010. }
  9011. if (m_bTsbPd)
  9012. {
  9013. HLOGC(qrlog.Debug, log << CONID() << "loss: signaling TSBPD cond");
  9014. CSync::lock_notify_one(m_RcvTsbPdCond, m_RecvLock);
  9015. }
  9016. else
  9017. {
  9018. HLOGC(qrlog.Debug, log << CONID() << "loss: socket is not TSBPD, not signaling");
  9019. }
  9020. }
  9021. // Separately report loss records of those reported by a filter.
  9022. // ALWAYS report whatever has been reported back by a filter. Note that
  9023. // the filter never reports anything when rexmit fallback level is ALWAYS or NEVER.
  9024. // With ALWAYS only those are reported that were recorded here by SRT.
  9025. // With NEVER, nothing is to be reported.
  9026. if (!filter_loss_seqs.empty())
  9027. {
  9028. HLOGC(qrlog.Debug, log << CONID() << "WILL REPORT LOSSES (filter): " << Printable(filter_loss_seqs));
  9029. sendLossReport(filter_loss_seqs);
  9030. if (m_bTsbPd)
  9031. {
  9032. HLOGC(qrlog.Debug, log << CONID() << "loss: signaling TSBPD cond");
  9033. CSync::lock_notify_one(m_RcvTsbPdCond, m_RecvLock);
  9034. }
  9035. }
  9036. // Now review the list of FreshLoss to see if there's any "old enough" to send UMSG_LOSSREPORT to it.
  9037. // PERFORMANCE CONSIDERATIONS:
  9038. // This list is quite inefficient as a data type and finding the candidate to send UMSG_LOSSREPORT
  9039. // is linear time. On the other hand, there are some special cases that are important for performance:
  9040. // - only the first (plus some following) could have had TTL drown to 0
  9041. // - the only (little likely) possibility that the next-to-first record has TTL=0 is when there was
  9042. // a loss range split (due to dropFromLossLists() of one sequence)
  9043. // - first found record with TTL>0 means end of "ready to LOSSREPORT" records
  9044. // So:
  9045. // All you have to do is:
  9046. // - start with first element and continue with next elements, as long as they have TTL=0
  9047. // If so, send the loss report and remove this element.
  9048. // - Since the first element that has TTL>0, iterate until the end of container and decrease TTL.
  9049. //
  9050. // This will be efficient becase the loop to increment one field (without any condition check)
  9051. // can be quite well optimized.
  9052. vector<int32_t> lossdata;
  9053. {
  9054. ScopedLock lg(m_RcvLossLock);
  9055. // XXX There was a mysterious crash around m_FreshLoss. When the initial_loss_ttl is 0
  9056. // (that is, "belated loss report" feature is off), don't even touch m_FreshLoss.
  9057. if (initial_loss_ttl && !m_FreshLoss.empty())
  9058. {
  9059. deque<CRcvFreshLoss>::iterator i = m_FreshLoss.begin();
  9060. // Phase 1: take while TTL <= 0.
  9061. // There can be more than one record with the same TTL, if it has happened before
  9062. // that there was an 'unlost' (@c dropFromLossLists) sequence that has split one detected loss
  9063. // into two records.
  9064. for (; i != m_FreshLoss.end() && i->ttl <= 0; ++i)
  9065. {
  9066. HLOGC(qrlog.Debug, log << "Packet seq " << i->seq[0] << "-" << i->seq[1]
  9067. << " (" << (CSeqNo::seqoff(i->seq[0], i->seq[1]) + 1) << " packets) considered lost - sending LOSSREPORT");
  9068. addLossRecord(lossdata, i->seq[0], i->seq[1]);
  9069. }
  9070. // Remove elements that have been processed and prepared for lossreport.
  9071. if (i != m_FreshLoss.begin())
  9072. {
  9073. m_FreshLoss.erase(m_FreshLoss.begin(), i);
  9074. i = m_FreshLoss.begin();
  9075. }
  9076. if (m_FreshLoss.empty())
  9077. {
  9078. HLOGP(qrlog.Debug, "NO MORE FRESH LOSS RECORDS.");
  9079. }
  9080. else
  9081. {
  9082. HLOGC(qrlog.Debug, log << "STILL " << m_FreshLoss.size() << " FRESH LOSS RECORDS, FIRST: "
  9083. << i->seq[0] << "-" << i->seq[1]
  9084. << " (" << (1 + CSeqNo::seqoff(i->seq[0], i->seq[1])) << ") TTL: " << i->ttl);
  9085. }
  9086. // Phase 2: rest of the records should have TTL decreased.
  9087. for (; i != m_FreshLoss.end(); ++i)
  9088. --i->ttl;
  9089. }
  9090. }
  9091. if (!lossdata.empty())
  9092. {
  9093. sendCtrl(UMSG_LOSSREPORT, NULL, &lossdata[0], (int) lossdata.size());
  9094. }
  9095. // was_sent_in_order means either of:
  9096. // - packet was sent in order (first if branch above)
  9097. // - packet was sent as old, but was a retransmitted packet
  9098. if (m_bPeerRexmitFlag && was_sent_in_order)
  9099. {
  9100. ++m_iConsecOrderedDelivery;
  9101. if (m_iConsecOrderedDelivery >= 50)
  9102. {
  9103. m_iConsecOrderedDelivery = 0;
  9104. if (m_iReorderTolerance > 0)
  9105. {
  9106. m_iReorderTolerance--;
  9107. enterCS(m_StatsLock);
  9108. m_stats.traceReorderDistance--;
  9109. leaveCS(m_StatsLock);
  9110. HLOGC(qrlog.Debug, log << "ORDERED DELIVERY of 50 packets in a row - decreasing tolerance to "
  9111. << m_iReorderTolerance);
  9112. }
  9113. }
  9114. }
  9115. return 0;
  9116. }
  9117. #if ENABLE_BONDING
  9118. // NOTE: this is updated from the value of m_iRcvLastAck,
  9119. // which might be past the buffer and potentially cause setting
  9120. // the value to the last received and re-requiring retransmission.
  9121. // Worst case is that there could be a few packets to tear the transmission
  9122. // even more (as there will be likely no time to recover them), but
  9123. // if the transmission was already torn in the previously active link
  9124. // this shouldn't be a problem that these packets won't be recovered
  9125. // after activating the second link, although will be retried this way.
  9126. void srt::CUDT::updateIdleLinkFrom(CUDT* source)
  9127. {
  9128. int bufseq;
  9129. {
  9130. ScopedLock lg (m_RcvBufferLock);
  9131. bufseq = source->m_pRcvBuffer->getStartSeqNo();
  9132. }
  9133. ScopedLock lg (m_RecvLock);
  9134. if (!m_pRcvBuffer->empty())
  9135. {
  9136. HLOGC(grlog.Debug, log << "grp: NOT updating rcv-seq in @" << m_SocketID << ": receiver buffer not empty");
  9137. return;
  9138. }
  9139. int32_t new_last_rcv = source->m_iRcvLastAck;
  9140. if (CSeqNo::seqcmp(new_last_rcv, bufseq) < 0)
  9141. {
  9142. // Emergency check whether the last ACK was behind the
  9143. // buffer. This may happen when TSBPD dropped empty cells.
  9144. // This may cause that the newly activated link may derive
  9145. // these empty cells which will never be recovered.
  9146. new_last_rcv = bufseq;
  9147. }
  9148. // if (new_last_rcv <=% m_iRcvCurrSeqNo)
  9149. if (CSeqNo::seqcmp(new_last_rcv, m_iRcvCurrSeqNo) <= 0)
  9150. {
  9151. // Reject the change because that would shift the reception pointer backwards.
  9152. HLOGC(grlog.Debug, log << "grp: NOT updating rcv-seq in @" << m_SocketID
  9153. << ": backward setting rejected: %" << m_iRcvCurrSeqNo
  9154. << " -> %" << new_last_rcv);
  9155. return;
  9156. }
  9157. HLOGC(grlog.Debug, log << "grp: updating rcv-seq in @" << m_SocketID
  9158. << " from @" << source->m_SocketID << ": %" << new_last_rcv);
  9159. setInitialRcvSeq(new_last_rcv);
  9160. }
  9161. #endif
  9162. /// This function is called when a packet has arrived, which was behind the current
  9163. /// received sequence - that is, belated or retransmitted. Try to remove the packet
  9164. /// from both loss records: the general loss record and the fresh loss record.
  9165. ///
  9166. /// Additionally, check - if supported by the peer - whether the "latecoming" packet
  9167. /// has been sent due to retransmission or due to reordering, by checking the rexmit
  9168. /// support flag and rexmit flag itself. If this packet was surely ORIGINALLY SENT
  9169. /// it means that the current network connection suffers of packet reordering. This
  9170. /// way try to introduce a dynamic tolerance by calculating the difference between
  9171. /// the current packet reception sequence and this packet's sequence. This value
  9172. /// will be set to the tolerance value, which means that later packet retransmission
  9173. /// will not be required immediately, but only after receiving N next packets that
  9174. /// do not include the lacking packet.
  9175. /// The tolerance is not increased infinitely - it's bordered by iMaxReorderTolerance.
  9176. /// This value can be set in options - SRT_LOSSMAXTTL.
  9177. void srt::CUDT::unlose(const CPacket &packet)
  9178. {
  9179. ScopedLock lg(m_RcvLossLock);
  9180. int32_t sequence = packet.m_iSeqNo;
  9181. m_pRcvLossList->remove(sequence);
  9182. // Rest of this code concerns only the "belated lossreport" feature.
  9183. bool has_increased_tolerance = false;
  9184. bool was_reordered = false;
  9185. if (m_bPeerRexmitFlag)
  9186. {
  9187. // If the peer understands the REXMIT flag, it means that the REXMIT flag is contained
  9188. // in the PH_MSGNO field.
  9189. // The packet is considered coming originally (just possibly out of order), if REXMIT
  9190. // flag is NOT set.
  9191. was_reordered = !packet.getRexmitFlag();
  9192. if (was_reordered)
  9193. {
  9194. HLOGC(qrlog.Debug, log << "received out-of-band packet %" << sequence);
  9195. const int seqdiff = abs(CSeqNo::seqcmp(m_iRcvCurrSeqNo, packet.m_iSeqNo));
  9196. enterCS(m_StatsLock);
  9197. m_stats.traceReorderDistance = max(seqdiff, m_stats.traceReorderDistance);
  9198. leaveCS(m_StatsLock);
  9199. if (seqdiff > m_iReorderTolerance)
  9200. {
  9201. const int new_tolerance = min(seqdiff, m_config.iMaxReorderTolerance);
  9202. HLOGC(qrlog.Debug, log << "Belated by " << seqdiff << " seqs - Reorder tolerance "
  9203. << (new_tolerance == m_iReorderTolerance ? "REMAINS with " : "increased to ") << new_tolerance);
  9204. m_iReorderTolerance = new_tolerance;
  9205. has_increased_tolerance =
  9206. true; // Yes, even if reorder tolerance is already at maximum - this prevents decreasing tolerance.
  9207. }
  9208. }
  9209. else
  9210. {
  9211. HLOGC(qrlog.Debug, log << CONID() << "received reXmitted packet seq=" << sequence);
  9212. }
  9213. }
  9214. else
  9215. {
  9216. HLOGC(qrlog.Debug, log << "received reXmitted or belated packet seq " << sequence << " (distinction not supported by peer)");
  9217. }
  9218. // Don't do anything if "belated loss report" feature is not used.
  9219. // In that case the FreshLoss list isn't being filled in at all, the
  9220. // loss report is sent directly.
  9221. // Note that this condition blocks two things being done in this function:
  9222. // - remove given sequence from the fresh loss record
  9223. // (in this case it's empty anyway)
  9224. // - decrease current reorder tolerance based on whether packets come in order
  9225. // (current reorder tolerance is 0 anyway)
  9226. if (m_bPeerRexmitFlag == 0 || m_iReorderTolerance == 0)
  9227. return;
  9228. int had_ttl = 0;
  9229. if (CRcvFreshLoss::removeOne((m_FreshLoss), sequence, (&had_ttl)))
  9230. {
  9231. HLOGC(qrlog.Debug, log << "sequence " << sequence << " removed from belated lossreport record");
  9232. }
  9233. if (was_reordered)
  9234. {
  9235. m_iConsecOrderedDelivery = 0;
  9236. if (has_increased_tolerance)
  9237. {
  9238. m_iConsecEarlyDelivery = 0; // reset counter
  9239. }
  9240. else if (had_ttl > 2)
  9241. {
  9242. ++m_iConsecEarlyDelivery; // otherwise, and if it arrived quite earlier, increase counter
  9243. HLOGC(qrlog.Debug, log << "... arrived at TTL " << had_ttl << " case " << m_iConsecEarlyDelivery);
  9244. // After 10 consecutive
  9245. if (m_iConsecEarlyDelivery >= 10)
  9246. {
  9247. m_iConsecEarlyDelivery = 0;
  9248. if (m_iReorderTolerance > 0)
  9249. {
  9250. m_iReorderTolerance--;
  9251. enterCS(m_StatsLock);
  9252. m_stats.traceReorderDistance--;
  9253. leaveCS(m_StatsLock);
  9254. HLOGC(qrlog.Debug, log << "... reached " << m_iConsecEarlyDelivery
  9255. << " times - decreasing tolerance to " << m_iReorderTolerance);
  9256. }
  9257. }
  9258. }
  9259. // If hasn't increased tolerance, but the packet appeared at TTL less than 2, do nothing.
  9260. }
  9261. }
  9262. void srt::CUDT::dropFromLossLists(int32_t from, int32_t to)
  9263. {
  9264. ScopedLock lg(m_RcvLossLock);
  9265. IF_HEAVY_LOGGING(bool autodetected = false);
  9266. int32_t begin SRT_ATR_UNUSED;
  9267. if (from == SRT_SEQNO_NONE)
  9268. {
  9269. begin = m_pRcvLossList->removeUpTo(to);
  9270. IF_HEAVY_LOGGING(autodetected = true);
  9271. }
  9272. else
  9273. {
  9274. begin = from;
  9275. m_pRcvLossList->remove(from, to);
  9276. }
  9277. #if ENABLE_HEAVY_LOGGING
  9278. ostringstream range;
  9279. if (begin == SRT_SEQNO_NONE)
  9280. {
  9281. range << "no";
  9282. }
  9283. else
  9284. {
  9285. int off = CSeqNo::seqoff(begin, to);
  9286. if (off < 0)
  9287. {
  9288. range << "WEIRD NUMBER OF";
  9289. }
  9290. else
  9291. {
  9292. range << (off + 1);
  9293. }
  9294. }
  9295. static const char* const beginwhere[2] = {"explicit", "detected"};
  9296. const char* const reqtype = (from == SRT_SEQNO_NONE) ? "TLPKTDROP" : "DROPREQ";
  9297. HLOGC(qrlog.Debug, log << CONID() << "DROP PER " << reqtype << " %" << begin
  9298. << "[" << beginwhere[1*autodetected] << "]-" << to << " ("
  9299. << range.str() << " packets)");
  9300. #endif
  9301. if (m_bPeerRexmitFlag == 0 || m_iReorderTolerance == 0)
  9302. return;
  9303. // All code below concerns only "belated lossreport" feature.
  9304. // It's highly unlikely that this is waiting to send a belated UMSG_LOSSREPORT,
  9305. // so treat it rather as a sanity check.
  9306. // It's enough to check if the first element of the list starts with a sequence older than 'to'.
  9307. // If not, just do nothing.
  9308. size_t delete_index = 0;
  9309. for (size_t i = 0; i < m_FreshLoss.size(); ++i)
  9310. {
  9311. CRcvFreshLoss::Emod result = m_FreshLoss[i].revoke(from, to);
  9312. switch (result)
  9313. {
  9314. case CRcvFreshLoss::DELETE:
  9315. delete_index = i + 1; // PAST THE END
  9316. continue; // There may be further ranges that are included in this one, so check on.
  9317. case CRcvFreshLoss::NONE:
  9318. case CRcvFreshLoss::STRIPPED:
  9319. break; // THIS BREAKS ONLY 'switch', not 'for'!
  9320. case CRcvFreshLoss::SPLIT:; // This function never returns it. It's only a compiler shut-up.
  9321. }
  9322. break; // Now this breaks also FOR.
  9323. }
  9324. m_FreshLoss.erase(m_FreshLoss.begin(),
  9325. m_FreshLoss.begin() + delete_index); // with delete_index == 0 will do nothing
  9326. }
  9327. // This function, as the name states, should bake a new cookie.
  9328. int32_t srt::CUDT::bake(const sockaddr_any& addr, int32_t current_cookie, int correction)
  9329. {
  9330. static unsigned int distractor = 0;
  9331. unsigned int rollover = distractor + 10;
  9332. for (;;)
  9333. {
  9334. // SYN cookie
  9335. char clienthost[NI_MAXHOST];
  9336. char clientport[NI_MAXSERV];
  9337. getnameinfo(addr.get(),
  9338. addr.size(),
  9339. clienthost,
  9340. sizeof(clienthost),
  9341. clientport,
  9342. sizeof(clientport),
  9343. NI_NUMERICHOST | NI_NUMERICSERV);
  9344. int64_t timestamp = (count_microseconds(steady_clock::now() - m_stats.tsStartTime) / 60000000) + distractor +
  9345. correction; // secret changes every one minute
  9346. stringstream cookiestr;
  9347. cookiestr << clienthost << ":" << clientport << ":" << timestamp;
  9348. union {
  9349. unsigned char cookie[16];
  9350. int32_t cookie_val;
  9351. };
  9352. CMD5::compute(cookiestr.str().c_str(), cookie);
  9353. if (cookie_val != current_cookie)
  9354. return cookie_val;
  9355. ++distractor;
  9356. // This is just to make the loop formally breakable,
  9357. // but this is virtually impossible to happen.
  9358. if (distractor == rollover)
  9359. return cookie_val;
  9360. }
  9361. }
  9362. // XXX This is quite a mystery, why this function has a return value
  9363. // and what the purpose for it was. There's just one call of this
  9364. // function in the whole code and in that call the return value is
  9365. // ignored. Actually this call happens in the CRcvQueue::worker thread,
  9366. // where it makes a response for incoming UDP packet that might be
  9367. // a connection request. Should any error occur in this process, there
  9368. // is no way to "report error" that happened here. Basing on that
  9369. // these values in original UDT code were quite like the values
  9370. // for m_iReqType, they have been changed to URQ_* symbols, which
  9371. // may mean that the intent for the return value was to send this
  9372. // value back as a control packet back to the connector.
  9373. //
  9374. // This function is run when the CRcvQueue object is reading packets
  9375. // from the multiplexer (@c CRcvQueue::worker_RetrieveUnit) and the
  9376. // target socket ID is 0.
  9377. //
  9378. // XXX Make this function return EConnectStatus enum type (extend if needed),
  9379. // and this will be directly passed to the caller.
  9380. // [[using locked(m_pRcvQueue->m_LSLock)]];
  9381. int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet)
  9382. {
  9383. // XXX ASSUMPTIONS:
  9384. // [[using assert(packet.m_iID == 0)]]
  9385. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: received a connection request");
  9386. if (m_bClosing)
  9387. {
  9388. m_RejectReason = SRT_REJ_CLOSE;
  9389. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ... NOT. Rejecting because closing.");
  9390. return m_RejectReason;
  9391. }
  9392. /*
  9393. * Closing a listening socket only set bBroken
  9394. * If a connect packet is received while closing it gets through
  9395. * processing and crashes later.
  9396. */
  9397. if (m_bBroken)
  9398. {
  9399. m_RejectReason = SRT_REJ_CLOSE;
  9400. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ... NOT. Rejecting because broken.");
  9401. return m_RejectReason;
  9402. }
  9403. // When CHandShake::m_iContentSize is used in log, the file fails to link!
  9404. size_t exp_len = CHandShake::m_iContentSize;
  9405. // NOTE!!! Old version of SRT code checks if the size of the HS packet
  9406. // is EQUAL to the above CHandShake::m_iContentSize.
  9407. // Changed to < exp_len because we actually need that the packet
  9408. // be at least of a size for handshake, although it may contain
  9409. // more data, depending on what's inside.
  9410. if (packet.getLength() < exp_len)
  9411. {
  9412. m_RejectReason = SRT_REJ_ROGUE;
  9413. HLOGC(cnlog.Debug,
  9414. log << CONID() << "processConnectRequest: ... NOT. Wrong size: " << packet.getLength()
  9415. << " (expected: " << exp_len << ")");
  9416. return m_RejectReason;
  9417. }
  9418. // Dunno why the original UDT4 code only MUCH LATER was checking if the packet was UMSG_HANDSHAKE.
  9419. // It doesn't seem to make sense to deserialize it into the handshake structure if we are not
  9420. // sure that the packet contains the handshake at all!
  9421. if (!packet.isControl(UMSG_HANDSHAKE))
  9422. {
  9423. m_RejectReason = SRT_REJ_ROGUE;
  9424. LOGC(cnlog.Error,
  9425. log << CONID() << "processConnectRequest: the packet received as handshake is not a handshake message");
  9426. return m_RejectReason;
  9427. }
  9428. CHandShake hs;
  9429. hs.load_from(packet.m_pcData, packet.getLength());
  9430. // XXX MOST LIKELY this hs should be now copied into m_ConnRes field, which holds
  9431. // the handshake structure sent from the peer (no matter the role or mode).
  9432. // This should simplify the createSrtHandshake() function which can this time
  9433. // simply write the crafted handshake structure into m_ConnReq, which needs no
  9434. // participation of the local handshake and passing it as a parameter through
  9435. // newConnection() -> acceptAndRespond() -> createSrtHandshake(). This is also
  9436. // required as a source of the peer's information used in processing in other
  9437. // structures.
  9438. int32_t cookie_val = bake(addr);
  9439. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: new cookie: " << hex << cookie_val);
  9440. // Remember the incoming destination address here and use it as a source
  9441. // address when responding. It's not possible to record this address yet
  9442. // because this happens still in the frames of the listener socket. Only
  9443. // when processing switches to the newly spawned accepted socket can the
  9444. // address be recorded in its m_SourceAddr field.
  9445. sockaddr_any use_source_addr = packet.udpDestAddr();
  9446. // REQUEST:INDUCTION.
  9447. // Set a cookie, a target ID, and send back the same as
  9448. // RESPONSE:INDUCTION.
  9449. if (hs.m_iReqType == URQ_INDUCTION)
  9450. {
  9451. HLOGC(cnlog.Debug,
  9452. log << CONID() << "processConnectRequest: received type=induction, sending back with cookie+socket");
  9453. // XXX That looks weird - the calculated md5 sum out of the given host/port/timestamp
  9454. // is 16 bytes long, but CHandShake::m_iCookie has 4 bytes. This then effectively copies
  9455. // only the first 4 bytes. Moreover, it's dangerous on some platforms because the char
  9456. // array need not be aligned to int32_t - changed to union in a hope that using int32_t
  9457. // inside a union will enforce whole union to be aligned to int32_t.
  9458. hs.m_iCookie = cookie_val;
  9459. packet.m_iID = hs.m_iID;
  9460. // Ok, now's the time. The listener sets here the version 5 handshake,
  9461. // even though the request was 4. This is because the old client would
  9462. // simply return THE SAME version, not even looking into it, giving the
  9463. // listener false impression as if it supported version 5.
  9464. //
  9465. // If the caller was really HSv4, it will simply ignore the version 5 in INDUCTION;
  9466. // it will respond with CONCLUSION, but with its own set version, which is version 4.
  9467. //
  9468. // If the caller was really HSv5, it will RECOGNIZE this version 5 in INDUCTION, so
  9469. // it will respond with version 5 when sending CONCLUSION.
  9470. hs.m_iVersion = HS_VERSION_SRT1;
  9471. // Additionally, set this field to a MAGIC value. This field isn't used during INDUCTION
  9472. // by HSv4 client, HSv5 client can use it to additionally verify that this is a HSv5 listener.
  9473. // In this field we also advertise the PBKEYLEN value. When 0, it's considered not advertised.
  9474. hs.m_iType = SrtHSRequest::wrapFlags(true /*put SRT_MAGIC_CODE in HSFLAGS*/, m_config.iSndCryptoKeyLen);
  9475. bool whether SRT_ATR_UNUSED = m_config.iSndCryptoKeyLen != 0;
  9476. HLOGC(cnlog.Debug,
  9477. log << CONID() << "processConnectRequest: " << (whether ? "" : "NOT ")
  9478. << " Advertising PBKEYLEN - value = " << m_config.iSndCryptoKeyLen);
  9479. size_t size = packet.getLength();
  9480. hs.store_to((packet.m_pcData), (size));
  9481. setPacketTS(packet, steady_clock::now());
  9482. // Display the HS before sending it to peer
  9483. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: SENDING HS (i): " << hs.show());
  9484. m_pSndQueue->sendto(addr, packet, use_source_addr);
  9485. return SRT_REJ_UNKNOWN; // EXCEPTION: this is a "no-error" code.
  9486. }
  9487. // Otherwise this should be REQUEST:CONCLUSION.
  9488. // Should then come with the correct cookie that was
  9489. // set in the above INDUCTION, in the HS_VERSION_SRT1
  9490. // should also contain extra data.
  9491. if (!hs.valid())
  9492. {
  9493. LOGC(cnlog.Error, log << CONID() << "processConnectRequest: ROGUE HS RECEIVED. Rejecting");
  9494. m_RejectReason = SRT_REJ_ROGUE;
  9495. return SRT_REJ_ROGUE;
  9496. }
  9497. HLOGC(cnlog.Debug,
  9498. log << CONID() << "processConnectRequest: received type=" << RequestTypeStr(hs.m_iReqType)
  9499. << " - checking cookie...");
  9500. if (hs.m_iCookie != cookie_val)
  9501. {
  9502. cookie_val = bake(addr, cookie_val, -1); // SHOULD generate an earlier, distracted cookie
  9503. if (hs.m_iCookie != cookie_val)
  9504. {
  9505. m_RejectReason = SRT_REJ_RDVCOOKIE;
  9506. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ...wrong cookie " << hex << cookie_val << ". Ignoring.");
  9507. return m_RejectReason;
  9508. }
  9509. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ... correct (FIXED) cookie. Proceeding.");
  9510. }
  9511. else
  9512. {
  9513. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: ... correct (ORIGINAL) cookie. Proceeding.");
  9514. }
  9515. int32_t id = hs.m_iID;
  9516. // HANDSHAKE: The old client sees the version that does not match HS_VERSION_UDT4 (5).
  9517. // In this case it will respond with URQ_ERROR_REJECT. Rest of the data are the same
  9518. // as in the handshake request. When this message is received, the connector side should
  9519. // switch itself to the version number HS_VERSION_UDT4 and continue the old way (that is,
  9520. // continue sending URQ_INDUCTION, but this time with HS_VERSION_UDT4).
  9521. bool accepted_hs = true;
  9522. if (hs.m_iVersion == HS_VERSION_SRT1)
  9523. {
  9524. // No further check required.
  9525. // The m_iType contains handshake extension flags.
  9526. }
  9527. else if (hs.m_iVersion == HS_VERSION_UDT4)
  9528. {
  9529. // In UDT, and so in older SRT version, the hs.m_iType field should contain
  9530. // the socket type, although SRT only allowed this field to be UDT_DGRAM.
  9531. // Older SRT version contained that value in a field, but now that this can
  9532. // only contain UDT_DGRAM the field itself has been abandoned.
  9533. // For the sake of any old client that reports version 4 handshake, interpret
  9534. // this hs.m_iType field as a socket type and check if it's UDT_DGRAM.
  9535. // Note that in HSv5 hs.m_iType contains extension flags.
  9536. if (hs.m_iType != UDT_DGRAM)
  9537. {
  9538. m_RejectReason = SRT_REJ_ROGUE;
  9539. accepted_hs = false;
  9540. }
  9541. }
  9542. else
  9543. {
  9544. // Unsupported version
  9545. // (NOTE: This includes "version=0" which is a rejection flag).
  9546. m_RejectReason = SRT_REJ_VERSION;
  9547. accepted_hs = false;
  9548. }
  9549. if (!accepted_hs)
  9550. {
  9551. HLOGC(cnlog.Debug,
  9552. log << CONID() << "processConnectRequest: version/type mismatch. Sending REJECT code:" << m_RejectReason
  9553. << " MSG: " << srt_rejectreason_str(m_RejectReason));
  9554. // mismatch, reject the request
  9555. hs.m_iReqType = URQFailure(m_RejectReason);
  9556. size_t size = CHandShake::m_iContentSize;
  9557. hs.store_to((packet.m_pcData), (size));
  9558. packet.m_iID = id;
  9559. setPacketTS(packet, steady_clock::now());
  9560. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: SENDING HS (e): " << hs.show());
  9561. m_pSndQueue->sendto(addr, packet, use_source_addr);
  9562. }
  9563. else
  9564. {
  9565. // IMPORTANT!!!
  9566. // If the newConnection() detects there is already a socket connection associated with the remote peer,
  9567. // it returns the socket via `acpu`, and the `result` returned is 0.
  9568. // Else if a new connection is successfully created, the conclusion handshake response
  9569. // is sent by the function itself (it calls the acceptAndRespond(..)), the `acpu` remains null, the `result` is 1.
  9570. int error = SRT_REJ_UNKNOWN;
  9571. CUDT* acpu = NULL;
  9572. int result = uglobal().newConnection(m_SocketID, addr, packet, (hs), (error), (acpu));
  9573. // This is listener - m_RejectReason need not be set
  9574. // because listener has no functionality of giving the app
  9575. // insight into rejected callers.
  9576. // --->
  9577. // (global.) CUDTUnited::updateListenerMux
  9578. // (new Socket.) CUDT::acceptAndRespond
  9579. if (result == -1)
  9580. {
  9581. hs.m_iReqType = URQFailure(error);
  9582. LOGC(cnlog.Warn, log << "processConnectRequest: rsp(REJECT): " << hs.m_iReqType << " - " << srt_rejectreason_str(error));
  9583. }
  9584. // The `acpu` not NULL means connection exists, the `result` should be 0. It is not checked here though.
  9585. // The `newConnection(..)` only sends response for newly created connection.
  9586. // The connection already exists (no new connection has been created, no response sent).
  9587. // Send the conclusion response manually here in case the peer has missed the first one.
  9588. // The value `result` here should be 0.
  9589. if (acpu)
  9590. {
  9591. // This is an existing connection, so the handshake is only needed
  9592. // because of the rule that every handshake request must be covered
  9593. // by the handshake response. It wouldn't be good to call interpretSrtHandshake
  9594. // here because the data from the handshake have been already interpreted
  9595. // and recorded. We just need to craft a response.
  9596. HLOGC(cnlog.Debug,
  9597. log << CONID() << "processConnectRequest: sending REPEATED handshake response req="
  9598. << RequestTypeStr(hs.m_iReqType));
  9599. // Rewrite already updated previously data in acceptAndRespond
  9600. acpu->rewriteHandshakeData(acpu->m_PeerAddr, (hs));
  9601. uint32_t kmdata[SRTDATA_MAXSIZE];
  9602. size_t kmdatasize = SRTDATA_MAXSIZE;
  9603. EConnectStatus conn = CONN_ACCEPT;
  9604. if (hs.m_iVersion >= HS_VERSION_SRT1)
  9605. {
  9606. // Always attach extension.
  9607. hs.m_extension = true;
  9608. conn = acpu->craftKmResponse((kmdata), (kmdatasize));
  9609. }
  9610. else
  9611. {
  9612. kmdatasize = 0;
  9613. }
  9614. if (conn != CONN_ACCEPT)
  9615. return conn;
  9616. packet.setLength(m_iMaxSRTPayloadSize);
  9617. if (!acpu->createSrtHandshake(SRT_CMD_HSRSP, SRT_CMD_KMRSP,
  9618. kmdata, kmdatasize,
  9619. (packet), (hs)))
  9620. {
  9621. HLOGC(cnlog.Debug,
  9622. log << CONID() << "processConnectRequest: rejecting due to problems in createSrtHandshake.");
  9623. result = -1; // enforce fallthrough for the below condition!
  9624. hs.m_iReqType = URQFailure(m_RejectReason == SRT_REJ_UNKNOWN ? int(SRT_REJ_IPE) : m_RejectReason.load());
  9625. }
  9626. else
  9627. {
  9628. // Send the crafted handshake
  9629. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: SENDING (repeated) HS (a): " << hs.show());
  9630. acpu->addressAndSend((packet));
  9631. }
  9632. }
  9633. if (result == 1)
  9634. {
  9635. // BUG! There is no need to update write-readiness on the listener socket once new connection is accepted.
  9636. // Only read-readiness has to be updated, but it is done so in the newConnection(..) function.
  9637. // See PR #1831 and issue #1667.
  9638. HLOGC(cnlog.Debug,
  9639. log << CONID() << "processConnectRequest: accepted connection, updating epoll to write-ready");
  9640. // New connection has been accepted or an existing one has been found. Update epoll write-readiness.
  9641. // a new connection has been created, enable epoll for write
  9642. // Note: not using SRT_EPOLL_CONNECT symbol because this is a procedure
  9643. // executed for the accepted socket.
  9644. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true);
  9645. }
  9646. else if (result == -1)
  9647. {
  9648. // The new connection failed
  9649. // or the connection already existed, but manually sending the HS response above has failed.
  9650. // HSv4: Send the SHUTDOWN message to the peer (see PR #2010) in order to disallow the peer to connect.
  9651. // The HSv4 clients do not interpret the error handshake response correctly.
  9652. // HSv5: Send a handshake with an error code (hs.m_iReqType set earlier) to the peer.
  9653. if (hs.m_iVersion < HS_VERSION_SRT1)
  9654. {
  9655. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: HSv4 caller, sending SHUTDOWN after rejection with "
  9656. << RequestTypeStr(hs.m_iReqType));
  9657. CPacket rsp;
  9658. setPacketTS((rsp), steady_clock::now());
  9659. rsp.pack(UMSG_SHUTDOWN);
  9660. rsp.m_iID = m_PeerID;
  9661. m_pSndQueue->sendto(addr, rsp, use_source_addr);
  9662. }
  9663. else
  9664. {
  9665. HLOGC(cnlog.Debug,
  9666. log << CONID() << "processConnectRequest: sending ABNORMAL handshake info req="
  9667. << RequestTypeStr(hs.m_iReqType));
  9668. size_t size = CHandShake::m_iContentSize;
  9669. hs.store_to((packet.m_pcData), (size));
  9670. packet.setLength(size);
  9671. packet.m_iID = id;
  9672. setPacketTS(packet, steady_clock::now());
  9673. HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: SENDING HS (a): " << hs.show());
  9674. m_pSndQueue->sendto(addr, packet, use_source_addr);
  9675. }
  9676. }
  9677. }
  9678. LOGC(cnlog.Note, log << CONID() << "listen ret: " << hs.m_iReqType << " - " << RequestTypeStr(hs.m_iReqType));
  9679. return RejectReasonForURQ(hs.m_iReqType);
  9680. }
  9681. void srt::CUDT::addLossRecord(std::vector<int32_t> &lr, int32_t lo, int32_t hi)
  9682. {
  9683. if (lo == hi)
  9684. lr.push_back(lo);
  9685. else
  9686. {
  9687. lr.push_back(lo | LOSSDATA_SEQNO_RANGE_FIRST);
  9688. lr.push_back(hi);
  9689. }
  9690. }
  9691. int srt::CUDT::checkACKTimer(const steady_clock::time_point &currtime)
  9692. {
  9693. int because_decision = BECAUSE_NO_REASON;
  9694. if (currtime > m_tsNextACKTime.load() // ACK time has come
  9695. // OR the number of sent packets since last ACK has reached
  9696. // the congctl-defined value of ACK Interval
  9697. // (note that none of the builtin congctls defines ACK Interval)
  9698. || (m_CongCtl->ACKMaxPackets() > 0 && m_iPktCount >= m_CongCtl->ACKMaxPackets()))
  9699. {
  9700. // ACK timer expired or ACK interval is reached
  9701. sendCtrl(UMSG_ACK);
  9702. const steady_clock::duration ack_interval = m_CongCtl->ACKTimeout_us() > 0
  9703. ? microseconds_from(m_CongCtl->ACKTimeout_us())
  9704. : m_tdACKInterval;
  9705. m_tsNextACKTime.store(currtime + ack_interval);
  9706. m_iPktCount = 0;
  9707. m_iLightACKCount = 1;
  9708. because_decision = BECAUSE_ACK;
  9709. }
  9710. // Or the transfer rate is so high that the number of packets
  9711. // have reached the value of SelfClockInterval * LightACKCount before
  9712. // the time has come according to m_tsNextACKTime. In this case a "lite ACK"
  9713. // is sent, which doesn't contain statistical data and nothing more
  9714. // than just the ACK number. The "fat ACK" packets will be still sent
  9715. // normally according to the timely rules.
  9716. else if (m_iPktCount >= SELF_CLOCK_INTERVAL * m_iLightACKCount)
  9717. {
  9718. // send a "light" ACK
  9719. sendCtrl(UMSG_ACK, NULL, NULL, SEND_LITE_ACK);
  9720. ++m_iLightACKCount;
  9721. because_decision = BECAUSE_LITEACK;
  9722. }
  9723. return because_decision;
  9724. }
  9725. int srt::CUDT::checkNAKTimer(const steady_clock::time_point& currtime)
  9726. {
  9727. // XXX The problem with working NAKREPORT with SRT_ARQ_ONREQ
  9728. // is not that it would be inappropriate, but because it's not
  9729. // implemented. The reason for it is that the structure of the
  9730. // loss list container (m_pRcvLossList) is such that it is expected
  9731. // that the loss records are ordered by sequence numbers (so
  9732. // that two ranges sticking together are merged in place).
  9733. // Unfortunately in case of SRT_ARQ_ONREQ losses must be recorded
  9734. // as before, but they should not be reported, until confirmed
  9735. // by the filter. By this reason they appear often out of order
  9736. // and for adding them properly the loss list container wasn't
  9737. // prepared. This then requires some more effort to implement.
  9738. if (!m_config.bRcvNakReport || m_PktFilterRexmitLevel != SRT_ARQ_ALWAYS)
  9739. return BECAUSE_NO_REASON;
  9740. /*
  9741. * m_config.bRcvNakReport enables NAK reports for SRT.
  9742. * Retransmission based on timeout is bandwidth consuming,
  9743. * not knowing what to retransmit when the only NAK sent by receiver is lost,
  9744. * all packets past last ACK are retransmitted (rexmitMethod() == SRM_FASTREXMIT).
  9745. */
  9746. enterCS(m_RcvLossLock);
  9747. const int loss_len = m_pRcvLossList->getLossLength();
  9748. leaveCS(m_RcvLossLock);
  9749. SRT_ASSERT(loss_len >= 0);
  9750. int debug_decision = BECAUSE_NO_REASON;
  9751. if (loss_len > 0)
  9752. {
  9753. if (currtime <= m_tsNextNAKTime.load())
  9754. return BECAUSE_NO_REASON; // wait for next NAK time
  9755. sendCtrl(UMSG_LOSSREPORT);
  9756. debug_decision = BECAUSE_NAKREPORT;
  9757. }
  9758. m_tsNextNAKTime.store(currtime + m_tdNAKInterval);
  9759. return debug_decision;
  9760. }
  9761. bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int check_reason SRT_ATR_UNUSED)
  9762. {
  9763. // VERY HEAVY LOGGING
  9764. #if ENABLE_HEAVY_LOGGING & 1
  9765. static const char* const decisions [] = {
  9766. "ACK",
  9767. "LITE-ACK",
  9768. "NAKREPORT"
  9769. };
  9770. string decision = "NOTHING";
  9771. if (check_reason)
  9772. {
  9773. ostringstream decd;
  9774. decision = "";
  9775. for (int i = 0; i < LAST_BECAUSE_BIT; ++i)
  9776. {
  9777. int flag = 1 << i;
  9778. if (check_reason & flag)
  9779. decd << decisions[i] << " ";
  9780. }
  9781. decision = decd.str();
  9782. }
  9783. HLOGC(xtlog.Debug, log << CONID() << "checkTimer: ACTIVITIES PERFORMED: " << decision);
  9784. #endif
  9785. // In UDT the m_bUserDefinedRTO and m_iRTO were in CCC class.
  9786. // There's nothing in the original code that alters these values.
  9787. steady_clock::time_point next_exp_time;
  9788. if (m_CongCtl->RTO())
  9789. {
  9790. next_exp_time = m_tsLastRspTime.load() + microseconds_from(m_CongCtl->RTO());
  9791. }
  9792. else
  9793. {
  9794. steady_clock::duration exp_timeout =
  9795. microseconds_from(m_iEXPCount * (m_iSRTT + 4 * m_iRTTVar) + COMM_SYN_INTERVAL_US);
  9796. if (exp_timeout < (m_iEXPCount * m_tdMinExpInterval))
  9797. exp_timeout = m_iEXPCount * m_tdMinExpInterval;
  9798. next_exp_time = m_tsLastRspTime.load() + exp_timeout;
  9799. }
  9800. if (currtime <= next_exp_time && !m_bBreakAsUnstable)
  9801. return false;
  9802. // ms -> us
  9803. const int PEER_IDLE_TMO_US = m_config.iPeerIdleTimeout_ms * 1000;
  9804. // Haven't received any information from the peer, is it dead?!
  9805. // timeout: at least 16 expirations and must be greater than 5 seconds
  9806. time_point last_rsp_time = m_tsLastRspTime.load();
  9807. if (m_bBreakAsUnstable || ((m_iEXPCount > COMM_RESPONSE_MAX_EXP) &&
  9808. (currtime - last_rsp_time > microseconds_from(PEER_IDLE_TMO_US))))
  9809. {
  9810. //
  9811. // Connection is broken.
  9812. // UDT does not signal any information about this instead of to stop quietly.
  9813. // Application will detect this when it calls any UDT methods next time.
  9814. //
  9815. HLOGC(xtlog.Debug,
  9816. log << CONID() << "CONNECTION EXPIRED after " << count_milliseconds(currtime - last_rsp_time) << "ms");
  9817. m_bClosing = true;
  9818. m_bBroken = true;
  9819. m_iBrokenCounter = 30;
  9820. // update snd U list to remove this socket
  9821. m_pSndQueue->m_pSndUList->update(this, CSndUList::DO_RESCHEDULE);
  9822. updateBrokenConnection();
  9823. completeBrokenConnectionDependencies(SRT_ECONNLOST); // LOCKS!
  9824. return true;
  9825. }
  9826. HLOGC(xtlog.Debug,
  9827. log << CONID() << "EXP TIMER: count=" << m_iEXPCount << "/" << (+COMM_RESPONSE_MAX_EXP)
  9828. << " elapsed=" << (count_microseconds(currtime - last_rsp_time)) << "/" << (+PEER_IDLE_TMO_US) << "us");
  9829. ++m_iEXPCount;
  9830. /*
  9831. * (keepalive fix)
  9832. * duB:
  9833. * It seems there is confusion of the direction of the Response here.
  9834. * lastRspTime is supposed to be when receiving (data/ctrl) from peer
  9835. * as shown in processCtrl and processData,
  9836. * Here we set because we sent something?
  9837. *
  9838. * Disabling this code that prevent quick reconnection when peer disappear
  9839. */
  9840. // Reset last response time since we've just sent a heart-beat.
  9841. // (fixed) m_tsLastRspTime = currtime_tk;
  9842. return false;
  9843. }
  9844. void srt::CUDT::checkRexmitTimer(const steady_clock::time_point& currtime)
  9845. {
  9846. // Check if HSv4 should be retransmitted, and if KM_REQ should be resent if the side is INITIATOR.
  9847. checkSndTimers();
  9848. // There are two algorithms of blind packet retransmission: LATEREXMIT and FASTREXMIT.
  9849. //
  9850. // LATEREXMIT is only used with FileCC.
  9851. // The RTO is triggered when some time has passed since the last ACK from
  9852. // the receiver, while there is still some unacknowledged data in the sender's buffer,
  9853. // and the loss list is empty at the moment of RTO (nothing to retransmit yet).
  9854. //
  9855. // FASTREXMIT is only used with LiveCC.
  9856. // The RTO is triggered if the receiver is not configured to send periodic NAK reports,
  9857. // when some time has passed since the last ACK from the receiver,
  9858. // while there is still some unacknowledged data in the sender's buffer.
  9859. //
  9860. // In case the above conditions are met, the unacknowledged packets
  9861. // in the sender's buffer will be added to the SND loss list and retransmitted.
  9862. //
  9863. {
  9864. ScopedLock ack_lock(m_RecvAckLock);
  9865. const uint64_t rtt_syn = (m_iSRTT + 4 * m_iRTTVar + 2 * COMM_SYN_INTERVAL_US);
  9866. const uint64_t exp_int_us = (m_iReXmitCount * rtt_syn + COMM_SYN_INTERVAL_US);
  9867. if (currtime <= (m_tsLastRspAckTime + microseconds_from(exp_int_us)))
  9868. return;
  9869. }
  9870. // If there is no unacknowledged data in the sending buffer,
  9871. // then there is nothing to retransmit.
  9872. if (m_pSndBuffer->getCurrBufSize() <= 0)
  9873. return;
  9874. const bool is_laterexmit = m_CongCtl->rexmitMethod() == SrtCongestion::SRM_LATEREXMIT; // FileCC
  9875. const bool is_fastrexmit = m_CongCtl->rexmitMethod() == SrtCongestion::SRM_FASTREXMIT; // LiveCC
  9876. // If the receiver will send periodic NAK reports, then FASTREXMIT (live) is inactive.
  9877. // TODO: Probably some method of "blind rexmit" MUST BE DONE, when TLPKTDROP is off.
  9878. if (is_fastrexmit && m_bPeerNakReport)
  9879. return;
  9880. // Schedule a retransmission IF:
  9881. // - there are packets in flight (getFlightSpan() > 0);
  9882. // - in case of LATEREXMIT (File Mode): the sender loss list is empty
  9883. // (the receiver didn't send any LOSSREPORT, or LOSSREPORT was lost on track).
  9884. // - in case of FASTREXMIT (Live Mode): the RTO (rtt_syn) was triggered, therefore
  9885. // schedule unacknowledged packets for retransmission regardless of the loss list emptiness.
  9886. if (getFlightSpan() > 0 && (!is_laterexmit || m_pSndLossList->getLossLength() == 0))
  9887. {
  9888. // Sender: Insert all the packets sent after last received acknowledgement into the sender loss list.
  9889. ScopedLock acklock(m_RecvAckLock); // Protect packet retransmission
  9890. // Resend all unacknowledged packets on timeout, but only if there is no packet in the loss list
  9891. const int32_t csn = m_iSndCurrSeqNo;
  9892. const int num = m_pSndLossList->insert(m_iSndLastAck, csn);
  9893. if (num > 0)
  9894. {
  9895. enterCS(m_StatsLock);
  9896. m_stats.sndr.lost.count(num);
  9897. leaveCS(m_StatsLock);
  9898. HLOGC(xtlog.Debug,
  9899. log << CONID() << "ENFORCED " << (is_laterexmit ? "LATEREXMIT" : "FASTREXMIT")
  9900. << " by ACK-TMOUT (scheduling): " << CSeqNo::incseq(m_iSndLastAck) << "-" << csn << " ("
  9901. << CSeqNo::seqoff(m_iSndLastAck, csn) << " packets)");
  9902. }
  9903. }
  9904. ++m_iReXmitCount;
  9905. const ECheckTimerStage stage = is_fastrexmit ? TEV_CHT_FASTREXMIT : TEV_CHT_REXMIT;
  9906. updateCC(TEV_CHECKTIMER, EventVariant(stage));
  9907. // schedule sending if not scheduled already
  9908. m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);
  9909. }
  9910. void srt::CUDT::checkTimers()
  9911. {
  9912. // update CC parameters
  9913. updateCC(TEV_CHECKTIMER, EventVariant(TEV_CHT_INIT));
  9914. const steady_clock::time_point currtime = steady_clock::now();
  9915. // This is a very heavy log, unblock only for temporary debugging!
  9916. #if 0
  9917. HLOGC(xtlog.Debug, log << CONID() << "checkTimers: nextacktime=" << FormatTime(m_tsNextACKTime)
  9918. << " AckInterval=" << m_iACKInterval
  9919. << " pkt-count=" << m_iPktCount << " liteack-count=" << m_iLightACKCount);
  9920. #endif
  9921. // Check if it is time to send ACK
  9922. int debug_decision = checkACKTimer(currtime);
  9923. // Check if it is time to send a loss report
  9924. debug_decision |= checkNAKTimer(currtime);
  9925. // Check if the connection is expired
  9926. if (checkExpTimer(currtime, debug_decision))
  9927. return;
  9928. // Check if FAST or LATE packet retransmission is required
  9929. checkRexmitTimer(currtime);
  9930. if (currtime > m_tsLastSndTime.load() + microseconds_from(COMM_KEEPALIVE_PERIOD_US))
  9931. {
  9932. sendCtrl(UMSG_KEEPALIVE);
  9933. #if ENABLE_BONDING
  9934. if (m_parent->m_GroupOf)
  9935. {
  9936. ScopedLock glock (uglobal().m_GlobControlLock);
  9937. if (m_parent->m_GroupOf)
  9938. {
  9939. // Pass socket ID because it's about changing group socket data
  9940. m_parent->m_GroupOf->internalKeepalive(m_parent->m_GroupMemberData);
  9941. // NOTE: GroupLock is unnecessary here because the only data read and
  9942. // modified is the target of the iterator from m_GroupMemberData. The
  9943. // iterator will be valid regardless of any container modifications.
  9944. }
  9945. }
  9946. #endif
  9947. HLOGP(xtlog.Debug, "KEEPALIVE");
  9948. }
  9949. }
  9950. void srt::CUDT::updateBrokenConnection()
  9951. {
  9952. m_bClosing = true;
  9953. releaseSynch();
  9954. // app can call any UDT API to learn the connection_broken error
  9955. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true);
  9956. CGlobEvent::triggerEvent();
  9957. }
  9958. void srt::CUDT::completeBrokenConnectionDependencies(int errorcode)
  9959. {
  9960. int token = -1;
  9961. #if ENABLE_BONDING
  9962. bool pending_broken = false;
  9963. {
  9964. ScopedLock guard_group_existence (uglobal().m_GlobControlLock);
  9965. if (m_parent->m_GroupOf)
  9966. {
  9967. token = m_parent->m_GroupMemberData->token;
  9968. if (m_parent->m_GroupMemberData->sndstate == SRT_GST_PENDING)
  9969. {
  9970. HLOGC(gmlog.Debug, log << CONID() << "updateBrokenConnection: a pending link was broken - will be removed");
  9971. pending_broken = true;
  9972. }
  9973. else
  9974. {
  9975. HLOGC(gmlog.Debug,
  9976. log << CONID() << "updateBrokenConnection: state="
  9977. << CUDTGroup::StateStr(m_parent->m_GroupMemberData->sndstate)
  9978. << " a used link was broken - not closing automatically");
  9979. }
  9980. m_parent->m_GroupMemberData->sndstate = SRT_GST_BROKEN;
  9981. m_parent->m_GroupMemberData->rcvstate = SRT_GST_BROKEN;
  9982. }
  9983. }
  9984. #endif
  9985. if (m_cbConnectHook)
  9986. {
  9987. CALLBACK_CALL(m_cbConnectHook, m_SocketID, errorcode, m_PeerAddr.get(), token);
  9988. }
  9989. #if ENABLE_BONDING
  9990. {
  9991. // Lock GlobControlLock in order to make sure that
  9992. // the state if the socket having the group and the
  9993. // existence of the group will not be changed during
  9994. // the operation. The attempt of group deletion will
  9995. // have to wait until this operation completes.
  9996. ScopedLock lock(uglobal().m_GlobControlLock);
  9997. CUDTGroup* pg = m_parent->m_GroupOf;
  9998. if (pg)
  9999. {
  10000. // Bound to one call because this requires locking
  10001. pg->updateFailedLink();
  10002. }
  10003. }
  10004. // Sockets that never succeeded to connect must be deleted
  10005. // explicitly, otherwise they will never be deleted.
  10006. if (pending_broken)
  10007. {
  10008. // XXX This somehow can cause a deadlock
  10009. // uglobal()->close(m_parent);
  10010. m_parent->setBrokenClosed();
  10011. }
  10012. #endif
  10013. }
  10014. void srt::CUDT::addEPoll(const int eid)
  10015. {
  10016. enterCS(uglobal().m_EPoll.m_EPollLock);
  10017. m_sPollID.insert(eid);
  10018. leaveCS(uglobal().m_EPoll.m_EPollLock);
  10019. if (!stillConnected())
  10020. return;
  10021. enterCS(m_RecvLock);
  10022. if (isRcvBufferReady())
  10023. {
  10024. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true);
  10025. }
  10026. leaveCS(m_RecvLock);
  10027. if (m_config.iSndBufSize > m_pSndBuffer->getCurrBufSize())
  10028. {
  10029. uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true);
  10030. }
  10031. }
  10032. void srt::CUDT::removeEPollEvents(const int eid)
  10033. {
  10034. // clear IO events notifications;
  10035. // since this happens after the epoll ID has been removed, they cannot be set again
  10036. set<int> remove;
  10037. remove.insert(eid);
  10038. uglobal().m_EPoll.update_events(m_SocketID, remove, SRT_EPOLL_IN | SRT_EPOLL_OUT, false);
  10039. }
  10040. void srt::CUDT::removeEPollID(const int eid)
  10041. {
  10042. enterCS(uglobal().m_EPoll.m_EPollLock);
  10043. m_sPollID.erase(eid);
  10044. leaveCS(uglobal().m_EPoll.m_EPollLock);
  10045. }
  10046. void srt::CUDT::ConnectSignal(ETransmissionEvent evt, EventSlot sl)
  10047. {
  10048. if (evt >= TEV_E_SIZE)
  10049. return; // sanity check
  10050. m_Slots[evt].push_back(sl);
  10051. }
  10052. void srt::CUDT::DisconnectSignal(ETransmissionEvent evt)
  10053. {
  10054. if (evt >= TEV_E_SIZE)
  10055. return; // sanity check
  10056. m_Slots[evt].clear();
  10057. }
  10058. void srt::CUDT::EmitSignal(ETransmissionEvent tev, EventVariant var)
  10059. {
  10060. for (std::vector<EventSlot>::iterator i = m_Slots[tev].begin(); i != m_Slots[tev].end(); ++i)
  10061. {
  10062. i->emit(tev, var);
  10063. }
  10064. }
  10065. int srt::CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes)
  10066. {
  10067. CUDTSocket *s = uglobal().locateSocket(u);
  10068. if (!s)
  10069. return -1;
  10070. CSndBuffer *b = s->core().m_pSndBuffer;
  10071. if (!b)
  10072. return -1;
  10073. int bytecount, timespan;
  10074. int count = b->getCurrBufSize((bytecount), (timespan));
  10075. if (blocks)
  10076. *blocks = count;
  10077. if (bytes)
  10078. *bytes = bytecount;
  10079. return std::abs(timespan);
  10080. }
  10081. int srt::CUDT::rejectReason(SRTSOCKET u)
  10082. {
  10083. CUDTSocket* s = uglobal().locateSocket(u);
  10084. if (!s)
  10085. return SRT_REJ_UNKNOWN;
  10086. return s->core().m_RejectReason;
  10087. }
  10088. int srt::CUDT::rejectReason(SRTSOCKET u, int value)
  10089. {
  10090. CUDTSocket* s = uglobal().locateSocket(u);
  10091. if (!s)
  10092. return APIError(MJ_NOTSUP, MN_SIDINVAL);
  10093. if (value < SRT_REJC_PREDEFINED)
  10094. return APIError(MJ_NOTSUP, MN_INVAL);
  10095. s->core().m_RejectReason = value;
  10096. return 0;
  10097. }
  10098. int64_t srt::CUDT::socketStartTime(SRTSOCKET u)
  10099. {
  10100. CUDTSocket* s = uglobal().locateSocket(u);
  10101. if (!s)
  10102. return APIError(MJ_NOTSUP, MN_SIDINVAL);
  10103. return count_microseconds(s->core().m_stats.tsStartTime.time_since_epoch());
  10104. }
  10105. bool srt::CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShake& hs, const CPacket& hspkt)
  10106. {
  10107. // Prepare the information for the hook.
  10108. // We need streamid.
  10109. char target[CSrtConfig::MAX_SID_LENGTH + 1];
  10110. memset((target), 0, CSrtConfig::MAX_SID_LENGTH + 1);
  10111. // Just for a case, check the length.
  10112. // This wasn't done before, and we could risk memory crash.
  10113. // In case of error, this will remain unset and the empty
  10114. // string will be passed as streamid.
  10115. int ext_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(hs.m_iType);
  10116. #if ENABLE_BONDING
  10117. bool have_group = false;
  10118. SRT_GROUP_TYPE gt = SRT_GTYPE_UNDEFINED;
  10119. #endif
  10120. // This tests if there are any extensions.
  10121. if (hspkt.getLength() > CHandShake::m_iContentSize + 4 && IsSet(ext_flags, CHandShake::HS_EXT_CONFIG))
  10122. {
  10123. uint32_t *begin = reinterpret_cast<uint32_t *>(hspkt.m_pcData + CHandShake::m_iContentSize);
  10124. size_t size = hspkt.getLength() - CHandShake::m_iContentSize; // Due to previous cond check we grant it's >0
  10125. uint32_t *next = 0;
  10126. size_t length = size / sizeof(uint32_t);
  10127. size_t blocklen = 0;
  10128. for (;;) // ONE SHOT, but continuable loop
  10129. {
  10130. int cmd = FindExtensionBlock(begin, length, (blocklen), (next));
  10131. const size_t bytelen = blocklen * sizeof(uint32_t);
  10132. if (cmd == SRT_CMD_SID)
  10133. {
  10134. if (!bytelen || bytelen > CSrtConfig::MAX_SID_LENGTH)
  10135. {
  10136. LOGC(cnlog.Error,
  10137. log << CONID() << "interpretSrtHandshake: STREAMID length " << bytelen << " is 0 or > "
  10138. << +CSrtConfig::MAX_SID_LENGTH << " - PROTOCOL ERROR, REJECTING");
  10139. return false;
  10140. }
  10141. // See comment at CUDT::interpretSrtHandshake().
  10142. memcpy((target), begin + 1, bytelen);
  10143. // Un-swap on big endian machines
  10144. ItoHLA(((uint32_t *)target), (uint32_t *)target, blocklen);
  10145. }
  10146. #if ENABLE_BONDING
  10147. else if (cmd == SRT_CMD_GROUP)
  10148. {
  10149. uint32_t* groupdata = begin + 1;
  10150. have_group = true; // Even if parse error happes
  10151. if (bytelen / sizeof(int32_t) >= GRPD_E_SIZE)
  10152. {
  10153. uint32_t gd = groupdata[GRPD_GROUPDATA];
  10154. gt = SRT_GROUP_TYPE(SrtHSRequest::HS_GROUP_TYPE::unwrap(gd));
  10155. }
  10156. }
  10157. #endif
  10158. else if (cmd == SRT_CMD_NONE)
  10159. {
  10160. // End of blocks
  10161. break;
  10162. }
  10163. // Any other kind of message extracted. Search on.
  10164. if (!NextExtensionBlock((begin), next, (length)))
  10165. break;
  10166. }
  10167. }
  10168. #if ENABLE_BONDING
  10169. if (have_group && acore->m_config.iGroupConnect == 0)
  10170. {
  10171. HLOGC(cnlog.Debug,
  10172. log << CONID() << "runAcceptHook: REJECTING connection WITHOUT calling the hook - groups not allowed");
  10173. return false;
  10174. }
  10175. // Update the groupconnect flag
  10176. acore->m_config.iGroupConnect = have_group ? 1 : 0;
  10177. acore->m_HSGroupType = gt;
  10178. #endif
  10179. // Set the default value
  10180. acore->m_RejectReason = SRT_REJX_FALLBACK;
  10181. try
  10182. {
  10183. int result = CALLBACK_CALL(m_cbAcceptHook, acore->m_SocketID, hs.m_iVersion, peer, target);
  10184. if (result == -1)
  10185. return false;
  10186. }
  10187. catch (...)
  10188. {
  10189. LOGP(cnlog.Warn, "runAcceptHook: hook interrupted by exception");
  10190. return false;
  10191. }
  10192. acore->m_RejectReason = SRT_REJ_UNKNOWN;
  10193. return true;
  10194. }
  10195. void srt::CUDT::processKeepalive(const CPacket& ctrlpkt, const time_point& tsArrival)
  10196. {
  10197. // Here can be handled some protocol definition
  10198. // for extra data sent through keepalive.
  10199. #if ENABLE_BONDING
  10200. if (m_parent->m_GroupOf)
  10201. {
  10202. // Lock GlobControlLock in order to make sure that
  10203. // the state if the socket having the group and the
  10204. // existence of the group will not be changed during
  10205. // the operation. The attempt of group deletion will
  10206. // have to wait until this operation completes.
  10207. ScopedLock lock(uglobal().m_GlobControlLock);
  10208. CUDTGroup* pg = m_parent->m_GroupOf;
  10209. if (pg)
  10210. {
  10211. // Whether anything is to be done with this socket
  10212. // about the fact that keepalive arrived, let the
  10213. // group handle it
  10214. pg->processKeepalive(m_parent->m_GroupMemberData);
  10215. }
  10216. }
  10217. #endif
  10218. ScopedLock lck(m_RcvBufferLock);
  10219. m_pRcvBuffer->updateTsbPdTimeBase(ctrlpkt.getMsgTimeStamp());
  10220. if (m_config.bDriftTracer)
  10221. m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), tsArrival, -1);
  10222. }