sockfile.cpp 267 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. // todo look at IRemoteFileServer stop
  14. #include "platform.h"
  15. #include "limits.h"
  16. #include "jlib.hpp"
  17. #include "jio.hpp"
  18. #include "jmutex.hpp"
  19. #include "jfile.hpp"
  20. #include "jmisc.hpp"
  21. #include "jthread.hpp"
  22. #include "jqueue.tpp"
  23. #include "securesocket.hpp"
  24. #include "sockfile.hpp"
  25. #include "portlist.h"
  26. #include "jsocket.hpp"
  27. #include "jencrypt.hpp"
  28. #include "jlzw.hpp"
  29. #include "jset.hpp"
  30. #include "jhtree.hpp"
  31. #include "remoteerr.hpp"
  32. #include <atomic>
  33. #include <string>
  34. #include <unordered_map>
  35. #include "rtldynfield.hpp"
  36. #include "rtlds_imp.hpp"
  37. #include "rtlread_imp.hpp"
  38. #include "rtlrecord.hpp"
  39. #include "eclhelper_dyn.hpp"
  40. #include "rtlcommon.hpp"
  41. #include "rtlformat.hpp"
  42. #include "jflz.hpp"
  43. #include "digisign.hpp"
  44. using namespace cryptohelper;
  45. #define SOCKET_CACHE_MAX 500
  46. #define MIN_KEYFILTSUPPORT_VERSION 20
  47. #ifdef _DEBUG
  48. //#define SIMULATE_PACKETLOSS 1
  49. #endif
  50. #define TREECOPYTIMEOUT (60*60*1000) // 1Hr (I guess could take longer for big file but at least will stagger)
  51. #define TREECOPYPOLLTIME (60*1000*5) // for tracing that delayed
  52. #define TREECOPYPRUNETIME (24*60*60*1000) // 1 day
  53. static const unsigned __int64 defaultFileStreamChooseNLimit = I64C(0x7fffffffffffffff); // constant should be move to common place (see eclhelper.hpp)
  54. static const unsigned __int64 defaultFileStreamSkipN = 0;
  55. static const unsigned defaultDaFSReplyLimitKB = 1024; // 1MB
  56. enum OutputFormat:byte { outFmt_Binary, outFmt_Xml, outFmt_Json };
  57. #if SIMULATE_PACKETLOSS
  58. #define TESTING_FAILURE_RATE_LOST_SEND 10 // per 1000
  59. #define TESTING_FAILURE_RATE_LOST_RECV 10 // per 1000
  60. #define DUMMY_TIMEOUT_MAX (1000*10)
  61. static bool errorSimulationOn = true;
  62. static ISocket *timeoutreadsock = NULL; // used to trigger
  63. struct dummyReadWrite
  64. {
  65. class X
  66. {
  67. dummyReadWrite *parent;
  68. public:
  69. X(dummyReadWrite *_parent)
  70. {
  71. parent = _parent;
  72. }
  73. ~X()
  74. {
  75. delete parent;
  76. }
  77. };
  78. class TimeoutSocketException: public CInterface, public IJSOCK_Exception
  79. {
  80. public:
  81. IMPLEMENT_IINTERFACE;
  82. TimeoutSocketException()
  83. {
  84. }
  85. virtual ~TimeoutSocketException()
  86. {
  87. }
  88. int errorCode() const { return JSOCKERR_timeout_expired; }
  89. StringBuffer & errorMessage(StringBuffer &str) const
  90. {
  91. return str.append("timeout expired");
  92. }
  93. MessageAudience errorAudience() const
  94. {
  95. return MSGAUD_user;
  96. }
  97. };
  98. ISocket *sock;
  99. dummyReadWrite(ISocket *_sock)
  100. {
  101. sock = _sock;
  102. }
  103. void readtms(void* buf, size32_t min_size, size32_t max_size, size32_t &size_read, time_t timeout)
  104. {
  105. X x(this);
  106. unsigned t = msTick();
  107. unsigned r = getRandom();
  108. bool timeoutread = (timeoutreadsock==sock);
  109. timeoutreadsock=NULL;
  110. if (!timeoutread)
  111. sock->readtms(buf, min_size, max_size, size_read, timeout);
  112. if (timeoutread||(errorSimulationOn&&(TESTING_FAILURE_RATE_LOST_RECV>0)&&(r%1000<TESTING_FAILURE_RATE_LOST_RECV))) {
  113. PrintStackReport();
  114. if (timeoutread)
  115. PROGLOG("** Simulate timeout");
  116. else
  117. PROGLOG("** Simulate Packet loss (size %d,%d)",min_size,max_size);
  118. if (timeout>DUMMY_TIMEOUT_MAX)
  119. timeout = DUMMY_TIMEOUT_MAX;
  120. t = msTick()-t;
  121. if (t<timeout)
  122. Sleep(timeout-t);
  123. IJSOCK_Exception *e = new TimeoutSocketException;
  124. throw e;
  125. }
  126. }
  127. size32_t write(void const* buf, size32_t size)
  128. {
  129. X x(this);
  130. timeoutreadsock=NULL;
  131. unsigned r = getRandom();
  132. if (errorSimulationOn&&(TESTING_FAILURE_RATE_LOST_SEND>0)&&(r%1000<TESTING_FAILURE_RATE_LOST_SEND)) {
  133. PrintStackReport();
  134. PROGLOG("** Simulate Packet loss (size %d)",size);
  135. timeoutreadsock=sock;
  136. return size;
  137. }
  138. return sock->write(buf,size);
  139. }
  140. };
  141. #define SOCKWRITE(sock) (new dummyReadWrite(sock))->write
  142. #define SOCKREADTMS(sock) (new dummyReadWrite(sock))->readtms
  143. #else
  144. #define SOCKWRITE(sock) sock->write
  145. #define SOCKREADTMS(sock) sock->readtms
  146. #endif
  147. // backward compatible modes
  148. typedef enum { compatIFSHnone, compatIFSHread, compatIFSHwrite, compatIFSHexec, compatIFSHall} compatIFSHmode;
  149. static const char *VERSTRING= "DS V2.4" // dont forget FILESRV_VERSION in header
  150. #ifdef _WIN32
  151. "Windows ";
  152. #else
  153. "Linux ";
  154. #endif
  155. typedef int RemoteFileIOHandle;
  156. static unsigned maxConnectTime = 0;
  157. static unsigned maxReceiveTime = 0;
  158. //Security and default port attributes
  159. static class _securitySettings
  160. {
  161. public:
  162. DAFSConnectCfg connectMethod;
  163. unsigned short daFileSrvPort;
  164. unsigned short daFileSrvSSLPort;
  165. const char * certificate;
  166. const char * privateKey;
  167. const char * passPhrase;
  168. _securitySettings()
  169. {
  170. queryDafsSecSettings(&connectMethod, &daFileSrvPort, &daFileSrvSSLPort, &certificate, &privateKey, &passPhrase);
  171. }
  172. } securitySettings;
  173. static CriticalSection secureContextCrit;
  174. static Owned<ISecureSocketContext> secureContextServer;
  175. static Owned<ISecureSocketContext> secureContextClient;
  176. #ifdef _USE_OPENSSL
  177. static ISecureSocket *createSecureSocket(ISocket *sock, SecureSocketType type)
  178. {
  179. {
  180. CriticalBlock b(secureContextCrit);
  181. if (type == ServerSocket)
  182. {
  183. if (!secureContextServer)
  184. secureContextServer.setown(createSecureSocketContextEx(securitySettings.certificate, securitySettings.privateKey, securitySettings.passPhrase, type));
  185. }
  186. else if (!secureContextClient)
  187. secureContextClient.setown(createSecureSocketContext(type));
  188. }
  189. int loglevel = SSLogNormal;
  190. #ifdef _DEBUG
  191. loglevel = SSLogMax;
  192. #endif
  193. if (type == ServerSocket)
  194. return secureContextServer->createSecureSocket(sock, loglevel);
  195. else
  196. return secureContextClient->createSecureSocket(sock, loglevel);
  197. }
  198. #else
  199. static ISecureSocket *createSecureSocket(ISocket *sock, SecureSocketType type)
  200. {
  201. throwUnexpected();
  202. }
  203. #endif
  204. void clientSetRemoteFileTimeouts(unsigned maxconnecttime,unsigned maxreadtime)
  205. {
  206. maxConnectTime = maxconnecttime;
  207. maxReceiveTime = maxreadtime;
  208. }
  209. struct sRFTM
  210. {
  211. CTimeMon *timemon;
  212. sRFTM(unsigned limit) { timemon = limit ? new CTimeMon(limit) : NULL; }
  213. ~sRFTM() { delete timemon; }
  214. };
  215. const char *remoteServerVersionString() { return VERSTRING; }
  216. static bool AuthenticationEnabled = true;
  217. bool enableDafsAuthentication(bool on)
  218. {
  219. bool ret = AuthenticationEnabled;
  220. AuthenticationEnabled = on;
  221. return ret;
  222. }
  223. #define CLIENT_TIMEOUT (1000*60*60*12) // long timeout in case zombies
  224. #define CLIENT_INACTIVEWARNING_TIMEOUT (1000*60*60*12) // time between logging inactive clients
  225. #define SERVER_TIMEOUT (1000*60*5) // timeout when waiting for dafilesrv to reply after command
  226. // (increased when waiting for large block)
  227. #define DAFS_CONNECT_FAIL_RETRY_TIME (1000*60*15)
  228. #ifdef SIMULATE_PACKETLOSS
  229. #define NORMAL_RETRIES (1)
  230. #define LENGTHY_RETRIES (1)
  231. #else
  232. #define NORMAL_RETRIES (3)
  233. #define LENGTHY_RETRIES (12)
  234. #endif
  235. #ifdef _DEBUG
  236. static byte traceFlags=0x30;
  237. #else
  238. static byte traceFlags=0x20;
  239. #endif
  240. #define TF_TRACE (traceFlags&1)
  241. #define TF_TRACE_PRE_IO (traceFlags&2)
  242. #define TF_TRACE_FULL (traceFlags&4)
  243. #define TF_TRACE_CLIENT_CONN (traceFlags&8)
  244. #define TF_TRACE_TREE_COPY (traceFlags&0x10)
  245. #define TF_TRACE_CLIENT_STATS (traceFlags&0x20)
  246. static const unsigned RFEnoerror = 0;
  247. enum
  248. {
  249. RFCopenIO, // 0
  250. RFCcloseIO,
  251. RFCread,
  252. RFCwrite,
  253. RFCsize,
  254. RFCexists,
  255. RFCremove,
  256. RFCrename,
  257. RFCgetver,
  258. RFCisfile,
  259. RFCisdirectory, // 10
  260. RFCisreadonly,
  261. RFCsetreadonly,
  262. RFCgettime,
  263. RFCsettime,
  264. RFCcreatedir,
  265. RFCgetdir,
  266. RFCstop,
  267. RFCexec, // legacy cmd removed
  268. RFCdummy1, // legacy placeholder
  269. RFCredeploy, // 20
  270. RFCgetcrc,
  271. RFCmove,
  272. // 1.5 features below
  273. RFCsetsize,
  274. RFCextractblobelements,
  275. RFCcopy,
  276. RFCappend,
  277. RFCmonitordir,
  278. RFCsettrace,
  279. RFCgetinfo,
  280. RFCfirewall, // not used currently // 30
  281. RFCunlock,
  282. RFCunlockreply,
  283. RFCinvalid,
  284. RFCcopysection,
  285. // 1.7e
  286. RFCtreecopy,
  287. // 1.7e - 1
  288. RFCtreecopytmp,
  289. // 1.8
  290. RFCsetthrottle, // legacy version
  291. // 1.9
  292. RFCsetthrottle2,
  293. RFCsetfileperms,
  294. // 2.0
  295. RFCreadfilteredindex, // No longer used // 40
  296. RFCreadfilteredindexcount,
  297. RFCreadfilteredindexblob,
  298. // 2.2
  299. RFCStreamRead, // 43
  300. // 2.4
  301. RFCStreamReadTestSocket, // 44
  302. RFCStreamReadJSON = '{',
  303. RFCmaxnormal,
  304. RFCmax,
  305. RFCunknown = 255 // 0 would have been more sensible, but can't break backward compatibility
  306. };
  307. // used by testsocket only
  308. RemoteFileCommandType queryRemoteStreamCmd()
  309. {
  310. return RFCStreamReadTestSocket;
  311. }
  312. #define RFCText(cmd) #cmd
  313. const char *RFCStrings[] =
  314. {
  315. RFCText(RFCopenIO),
  316. RFCText(RFCcloseIO),
  317. RFCText(RFCread),
  318. RFCText(RFCwrite),
  319. RFCText(RFCsize),
  320. RFCText(RFCexists),
  321. RFCText(RFCremove),
  322. RFCText(RFCrename),
  323. RFCText(RFCgetver),
  324. RFCText(RFCisfile),
  325. RFCText(RFCisdirectory),
  326. RFCText(RFCisreadonly),
  327. RFCText(RFCsetreadonly),
  328. RFCText(RFCgettime),
  329. RFCText(RFCsettime),
  330. RFCText(RFCcreatedir),
  331. RFCText(RFCgetdir),
  332. RFCText(RFCstop),
  333. RFCText(RFCexec),
  334. RFCText(RFCdummy1),
  335. RFCText(RFCredeploy),
  336. RFCText(RFCgetcrc),
  337. RFCText(RFCmove),
  338. RFCText(RFCsetsize),
  339. RFCText(RFCextractblobelements),
  340. RFCText(RFCcopy),
  341. RFCText(RFCappend),
  342. RFCText(RFCmonitordir),
  343. RFCText(RFCsettrace),
  344. RFCText(RFCgetinfo),
  345. RFCText(RFCfirewall),
  346. RFCText(RFCunlock),
  347. RFCText(RFCunlockreply),
  348. RFCText(RFCinvalid),
  349. RFCText(RFCcopysection),
  350. RFCText(RFCtreecopy),
  351. RFCText(RFCtreecopytmp),
  352. RFCText(RFCsetthrottle), // legacy version
  353. RFCText(RFCsetthrottle2),
  354. RFCText(RFCsetfileperms),
  355. RFCText(RFCreadfilteredindex),
  356. RFCText(RFCreadfilteredcount),
  357. RFCText(RFCreadfilteredblob),
  358. RFCText(RFCStreamRead),
  359. RFCText(RFCStreamReadTestSocket),
  360. };
  361. static const char *getRFCText(RemoteFileCommandType cmd)
  362. {
  363. if (cmd==RFCStreamReadJSON)
  364. return "RFCStreamReadJSON";
  365. else
  366. {
  367. unsigned elems = sizeof(RFCStrings) / sizeof(RFCStrings[0]);
  368. if (cmd >= elems)
  369. return "RFCunknown";
  370. return RFCStrings[cmd];
  371. }
  372. }
  373. static const char *getRFSERRText(unsigned err)
  374. {
  375. switch (err)
  376. {
  377. case RFSERR_InvalidCommand:
  378. return "RFSERR_InvalidCommand";
  379. case RFSERR_NullFileIOHandle:
  380. return "RFSERR_NullFileIOHandle";
  381. case RFSERR_InvalidFileIOHandle:
  382. return "RFSERR_InvalidFileIOHandle";
  383. case RFSERR_TimeoutFileIOHandle:
  384. return "RFSERR_TimeoutFileIOHandle";
  385. case RFSERR_OpenFailed:
  386. return "RFSERR_OpenFailed";
  387. case RFSERR_ReadFailed:
  388. return "RFSERR_ReadFailed";
  389. case RFSERR_WriteFailed:
  390. return "RFSERR_WriteFailed";
  391. case RFSERR_RenameFailed:
  392. return "RFSERR_RenameFailed";
  393. case RFSERR_ExistsFailed:
  394. return "RFSERR_ExistsFailed";
  395. case RFSERR_RemoveFailed:
  396. return "RFSERR_RemoveFailed";
  397. case RFSERR_CloseFailed:
  398. return "RFSERR_CloseFailed";
  399. case RFSERR_IsFileFailed:
  400. return "RFSERR_IsFileFailed";
  401. case RFSERR_IsDirectoryFailed:
  402. return "RFSERR_IsDirectoryFailed";
  403. case RFSERR_IsReadOnlyFailed:
  404. return "RFSERR_IsReadOnlyFailed";
  405. case RFSERR_SetReadOnlyFailed:
  406. return "RFSERR_SetReadOnlyFailed";
  407. case RFSERR_GetTimeFailed:
  408. return "RFSERR_GetTimeFailed";
  409. case RFSERR_SetTimeFailed:
  410. return "RFSERR_SetTimeFailed";
  411. case RFSERR_CreateDirFailed:
  412. return "RFSERR_CreateDirFailed";
  413. case RFSERR_GetDirFailed:
  414. return "RFSERR_GetDirFailed";
  415. case RFSERR_GetCrcFailed:
  416. return "RFSERR_GetCrcFailed";
  417. case RFSERR_MoveFailed:
  418. return "RFSERR_MoveFailed";
  419. case RFSERR_ExtractBlobElementsFailed:
  420. return "RFSERR_ExtractBlobElementsFailed";
  421. case RFSERR_CopyFailed:
  422. return "RFSERR_CopyFailed";
  423. case RFSERR_AppendFailed:
  424. return "RFSERR_AppendFailed";
  425. case RFSERR_AuthenticateFailed:
  426. return "RFSERR_AuthenticateFailed";
  427. case RFSERR_CopySectionFailed:
  428. return "RFSERR_CopySectionFailed";
  429. case RFSERR_TreeCopyFailed:
  430. return "RFSERR_TreeCopyFailed";
  431. case RAERR_InvalidUsernamePassword:
  432. return "RAERR_InvalidUsernamePassword";
  433. case RFSERR_MasterSeemsToHaveDied:
  434. return "RFSERR_MasterSeemsToHaveDied";
  435. case RFSERR_TimeoutWaitSlave:
  436. return "RFSERR_TimeoutWaitSlave";
  437. case RFSERR_TimeoutWaitConnect:
  438. return "RFSERR_TimeoutWaitConnect";
  439. case RFSERR_TimeoutWaitMaster:
  440. return "RFSERR_TimeoutWaitMaster";
  441. case RFSERR_NoConnectSlave:
  442. return "RFSERR_NoConnectSlave";
  443. case RFSERR_NoConnectSlaveXY:
  444. return "RFSERR_NoConnectSlaveXY";
  445. case RFSERR_VersionMismatch:
  446. return "RFSERR_VersionMismatch";
  447. case RFSERR_SetThrottleFailed:
  448. return "RFSERR_SetThrottleFailed";
  449. case RFSERR_MaxQueueRequests:
  450. return "RFSERR_MaxQueueRequests";
  451. case RFSERR_KeyIndexFailed:
  452. return "RFSERR_MaxQueueRequests";
  453. case RFSERR_StreamReadFailed:
  454. return "RFSERR_StreamReadFailed";
  455. case RFSERR_InternalError:
  456. return "Internal Error";
  457. }
  458. return "RFSERR_Unknown";
  459. }
  460. unsigned mapDafilesrvixCodes(unsigned err)
  461. {
  462. // old Solaris dali/remote/daliservix.cpp uses
  463. // different values for these error codes.
  464. switch (err)
  465. {
  466. case 8200:
  467. return RFSERR_InvalidCommand;
  468. case 8201:
  469. return RFSERR_NullFileIOHandle;
  470. case 8202:
  471. return RFSERR_InvalidFileIOHandle;
  472. case 8203:
  473. return RFSERR_TimeoutFileIOHandle;
  474. case 8204:
  475. return RFSERR_OpenFailed;
  476. case 8205:
  477. return RFSERR_ReadFailed;
  478. case 8206:
  479. return RFSERR_WriteFailed;
  480. case 8207:
  481. return RFSERR_RenameFailed;
  482. case 8208:
  483. return RFSERR_SetReadOnlyFailed;
  484. case 8209:
  485. return RFSERR_GetDirFailed;
  486. case 8210:
  487. return RFSERR_MoveFailed;
  488. }
  489. return err;
  490. }
  491. #define ThrottleText(throttleClass) #throttleClass
  492. const char *ThrottleStrings[] =
  493. {
  494. ThrottleText(ThrottleStd),
  495. ThrottleText(ThrottleSlow),
  496. };
  497. // very high upper limits that configure can't exceed
  498. #define THROTTLE_MAX_LIMIT 1000000
  499. #define THROTTLE_MAX_DELAYMS 3600000
  500. #define THROTTLE_MAX_CPUTHRESHOLD 100
  501. #define THROTTLE_MAX_QUEUELIMIT 10000000
  502. static const char *getThrottleClassText(ThrottleClass throttleClass) { return ThrottleStrings[throttleClass]; }
  503. typedef enum { ACScontinue, ACSdone, ACSerror} AsyncCommandStatus;
  504. typedef byte OnceKey[16];
  505. static void genOnce(OnceKey &key)
  506. {
  507. static __int64 inc=0;
  508. *(unsigned *)&key[0] = getRandom();
  509. *(__int64 *)&key[4] = ++inc;
  510. *(unsigned *)&key[12] = getRandom();
  511. }
  512. static void mergeOnce(OnceKey &key,size32_t sz,const void *data)
  513. {
  514. assertex(sz<=sizeof(OnceKey));
  515. const byte *p = (const byte *)data;
  516. while (sz)
  517. key[--sz] ^= *(p++);
  518. }
  519. //---------------------------------------------------------------------------
  520. class DECL_EXCEPTION CDafsException: public IDAFS_Exception, public CInterface
  521. {
  522. int errcode;
  523. StringAttr msg;
  524. public:
  525. IMPLEMENT_IINTERFACE;
  526. CDafsException(int code,const char *_msg)
  527. : errcode(code), msg(_msg)
  528. {
  529. };
  530. int errorCode() const
  531. {
  532. return errcode;
  533. }
  534. StringBuffer & errorMessage(StringBuffer &str) const
  535. {
  536. return str.append(msg);
  537. }
  538. MessageAudience errorAudience() const
  539. {
  540. return MSGAUD_user;
  541. }
  542. };
  543. static IDAFS_Exception *createDafsException(int code, const char *msg)
  544. {
  545. return new CDafsException(code, msg);
  546. }
  547. static IDAFS_Exception *createDafsExceptionVA(int code, const char *format, va_list args) __attribute__((format(printf,2,0)));
  548. static IDAFS_Exception *createDafsExceptionVA(int code, const char *format, va_list args)
  549. {
  550. StringBuffer eStr;
  551. eStr.limited_valist_appendf(1024, format, args);
  552. return new CDafsException(code, eStr);
  553. }
  554. static IDAFS_Exception *createDafsExceptionV(int code, const char *format, ...) __attribute__((format(printf,2,3)));
  555. static IDAFS_Exception *createDafsExceptionV(int code, const char *format, ...)
  556. {
  557. va_list args;
  558. va_start(args, format);
  559. IDAFS_Exception *ret = createDafsExceptionVA(code, format, args);
  560. va_end(args);
  561. return ret;
  562. }
  563. void setDafsEndpointPort(SocketEndpoint &ep)
  564. {
  565. // odd kludge (don't do this at home)
  566. byte ipb[4];
  567. if (ep.getNetAddress(sizeof(ipb),&ipb)==sizeof(ipb)) {
  568. if ((ipb[0]==255)&&(ipb[1]==255)) {
  569. ep.port = (((unsigned)ipb[2])<<8)+ipb[3];
  570. ep.ipset(queryLocalIP());
  571. }
  572. }
  573. if (ep.port==0)
  574. {
  575. if ( (securitySettings.connectMethod == SSLNone) || (securitySettings.connectMethod == UnsecureFirst) )
  576. ep.port = securitySettings.daFileSrvPort;
  577. else
  578. ep.port = securitySettings.daFileSrvSSLPort;
  579. }
  580. }
  581. inline MemoryBuffer & initSendBuffer(MemoryBuffer & buff)
  582. {
  583. buff.setEndian(__BIG_ENDIAN); // transfer as big endian...
  584. buff.append((unsigned)0); // reserve space for length prefix
  585. return buff;
  586. }
  587. inline void sendBuffer(ISocket * socket, MemoryBuffer & src, bool testSocketFlag=false)
  588. {
  589. unsigned length = src.length() - sizeof(unsigned);
  590. byte * buffer = (byte *)src.toByteArray();
  591. if (TF_TRACE_FULL)
  592. PROGLOG("sendBuffer size %d, data = %d %d %d %d",length, (int)buffer[4],(int)buffer[5],(int)buffer[6],(int)buffer[7]);
  593. if (testSocketFlag)
  594. length |= 0x80000000;
  595. _WINCPYREV(buffer, &length, sizeof(unsigned));
  596. SOCKWRITE(socket)(buffer, src.length());
  597. }
  598. inline size32_t receiveBufferSize(ISocket * socket, unsigned numtries=NORMAL_RETRIES,CTimeMon *timemon=NULL)
  599. {
  600. unsigned timeout = SERVER_TIMEOUT;
  601. if (numtries==0) {
  602. numtries = 1;
  603. timeout = 10*1000; // 10s
  604. }
  605. while (numtries--) {
  606. try {
  607. if (timemon) {
  608. unsigned remaining;
  609. if (timemon->timedout(&remaining)||(remaining<10))
  610. remaining = 10;
  611. if (remaining<timeout)
  612. timeout = remaining;
  613. }
  614. size32_t szread;
  615. size32_t gotLength;
  616. SOCKREADTMS(socket)(&gotLength, sizeof(gotLength), sizeof(gotLength), szread, timeout);
  617. _WINREV(gotLength);
  618. if (TF_TRACE_FULL)
  619. PROGLOG("receiveBufferSized %d",gotLength);
  620. return gotLength;
  621. }
  622. catch (IJSOCK_Exception *e) {
  623. if ((numtries==0)||(e->errorCode()!=JSOCKERR_timeout_expired)||(timemon&&timemon->timedout())) {
  624. throw;
  625. }
  626. StringBuffer err;
  627. char peername[256];
  628. socket->peer_name(peername,sizeof(peername)-1);
  629. WARNLOG("Remote connection %s: %s",peername,e->errorMessage(err).str()); // why no peername
  630. e->Release();
  631. Sleep(500+getRandom()%1000); // ~1s
  632. }
  633. }
  634. return 0;
  635. }
  636. static void flush(ISocket *socket)
  637. {
  638. MemoryBuffer sendbuf;
  639. initSendBuffer(sendbuf);
  640. sendbuf.append((RemoteFileCommandType)RFCgetver);
  641. sendbuf.append((unsigned)RFCgetver);
  642. MemoryBuffer reply;
  643. size32_t totread=0;
  644. try
  645. {
  646. sendBuffer(socket, sendbuf);
  647. char buf[1024];
  648. for (;;)
  649. {
  650. Sleep(1000); // breathe
  651. size32_t szread;
  652. SOCKREADTMS(socket)(buf, 1, sizeof(buf), szread, 1000*60);
  653. totread += szread;
  654. }
  655. }
  656. catch (IJSOCK_Exception *e) {
  657. if (totread)
  658. PROGLOG("%d bytes discarded",totread);
  659. if (e->errorCode()!=JSOCKERR_timeout_expired)
  660. EXCLOG(e,"flush");
  661. e->Release();
  662. }
  663. }
  664. inline void receiveBuffer(ISocket * socket, MemoryBuffer & tgt, unsigned numtries=1, size32_t maxsz=0x7fffffff)
  665. // maxsz is a guess at a resonable upper max to catch where protocol error
  666. {
  667. sRFTM tm(maxReceiveTime);
  668. size32_t gotLength = receiveBufferSize(socket, numtries,tm.timemon);
  669. if (gotLength) {
  670. size32_t origlen = tgt.length();
  671. try {
  672. if (gotLength>maxsz) {
  673. StringBuffer msg;
  674. msg.appendf("receiveBuffer maximum block size exceeded %d/%d",gotLength,maxsz);
  675. PrintStackReport();
  676. throw createDafsException(DAFSERR_protocol_failure,msg.str());
  677. }
  678. unsigned timeout = SERVER_TIMEOUT*(numtries?numtries:1);
  679. if (tm.timemon) {
  680. unsigned remaining;
  681. if (tm.timemon->timedout(&remaining)||(remaining<10))
  682. remaining = 10;
  683. if (remaining<timeout)
  684. timeout = remaining;
  685. }
  686. size32_t szread;
  687. SOCKREADTMS(socket)((gotLength<4000)?tgt.reserve(gotLength):tgt.reserveTruncate(gotLength), gotLength, gotLength, szread, timeout);
  688. }
  689. catch (IJSOCK_Exception *e) {
  690. if (e->errorCode()!=JSOCKERR_timeout_expired) {
  691. EXCLOG(e,"receiveBuffer(1)");
  692. PrintStackReport();
  693. if (!tm.timemon||!tm.timemon->timedout())
  694. flush(socket);
  695. }
  696. else {
  697. EXCLOG(e,"receiveBuffer");
  698. PrintStackReport();
  699. }
  700. tgt.setLength(origlen);
  701. throw;
  702. }
  703. catch (IException *e) {
  704. EXCLOG(e,"receiveBuffer(2)");
  705. PrintStackReport();
  706. if (!tm.timemon||!tm.timemon->timedout())
  707. flush(socket);
  708. tgt.setLength(origlen);
  709. throw;
  710. }
  711. }
  712. tgt.setEndian(__BIG_ENDIAN);
  713. }
  714. struct CConnectionRec
  715. {
  716. SocketEndpoint ep;
  717. unsigned tick;
  718. IArrayOf<ISocket> socks; // relies on isShared
  719. };
  720. //---------------------------------------------------------------------------
  721. // Local mount redirect
  722. struct CLocalMountRec: public CInterface
  723. {
  724. IpAddress ip;
  725. StringAttr dir; // dir path on remote ip
  726. StringAttr local; // local dir path
  727. };
  728. static CIArrayOf<CLocalMountRec> localMounts;
  729. static CriticalSection localMountCrit;
  730. void setDafsLocalMountRedirect(const IpAddress &ip,const char *dir,const char *mountdir)
  731. {
  732. CriticalBlock block(localMountCrit);
  733. ForEachItemInRev(i,localMounts) {
  734. CLocalMountRec &mount = localMounts.item(i);
  735. if (dir==NULL) { // remove all matching mount
  736. if (!mountdir)
  737. return;
  738. if (strcmp(mount.local,mountdir)==0)
  739. localMounts.remove(i);
  740. }
  741. else if (mount.ip.ipequals(ip)&&(strcmp(mount.dir,dir)==0)) {
  742. if (mountdir) {
  743. mount.local.set(mountdir);
  744. return;
  745. }
  746. else
  747. localMounts.remove(i);
  748. }
  749. }
  750. if (dir&&mountdir) {
  751. CLocalMountRec &mount = *new CLocalMountRec;
  752. mount.ip.ipset(ip);
  753. mount.dir.set(dir);
  754. mount.local.set(mountdir);
  755. localMounts.append(mount);
  756. }
  757. }
  758. IFile *createFileLocalMount(const IpAddress &ip, const char * filename)
  759. {
  760. CriticalBlock block(localMountCrit);
  761. ForEachItemInRev(i,localMounts) {
  762. CLocalMountRec &mount = localMounts.item(i);
  763. if (mount.ip.ipequals(ip)) {
  764. size32_t bl = mount.dir.length();
  765. if (isPathSepChar(mount.dir[bl-1]))
  766. bl--;
  767. if ((memcmp((void *)filename,(void *)mount.dir.get(),bl)==0)&&(isPathSepChar(filename[bl])||!filename[bl])) { // match
  768. StringBuffer locpath(mount.local);
  769. if (filename[bl])
  770. addPathSepChar(locpath).append(filename+bl+1);
  771. locpath.replace((PATHSEPCHAR=='\\')?'/':'\\',PATHSEPCHAR);
  772. return createIFile(locpath.str());
  773. }
  774. }
  775. }
  776. return NULL;
  777. }
  778. //---------------------------------------------------------------------------
  779. static class CConnectionTable: public SuperHashTableOf<CConnectionRec,SocketEndpoint>
  780. {
  781. void onAdd(void *) {}
  782. void onRemove(void *e)
  783. {
  784. CConnectionRec *r=(CConnectionRec *)e;
  785. delete r;
  786. }
  787. unsigned getHashFromElement(const void *e) const
  788. {
  789. const CConnectionRec &elem=*(const CConnectionRec *)e;
  790. return elem.ep.hash(0);
  791. }
  792. unsigned getHashFromFindParam(const void *fp) const
  793. {
  794. return ((const SocketEndpoint *)fp)->hash(0);
  795. }
  796. const void * getFindParam(const void *p) const
  797. {
  798. const CConnectionRec &elem=*(const CConnectionRec *)p;
  799. return (void *)&elem.ep;
  800. }
  801. bool matchesFindParam(const void * et, const void *fp, unsigned) const
  802. {
  803. return ((CConnectionRec *)et)->ep.equals(*(SocketEndpoint *)fp);
  804. }
  805. IMPLEMENT_SUPERHASHTABLEOF_REF_FIND(CConnectionRec,SocketEndpoint);
  806. unsigned numsockets;
  807. public:
  808. static CriticalSection crit;
  809. CConnectionTable()
  810. {
  811. numsockets = 0;
  812. }
  813. ~CConnectionTable() {
  814. _releaseAll();
  815. }
  816. ISocket *lookup(const SocketEndpoint &ep)
  817. {
  818. // always called from crit block
  819. CConnectionRec *r = SuperHashTableOf<CConnectionRec,SocketEndpoint>::find(&ep);
  820. if (r) {
  821. ForEachItemIn(i,r->socks) {
  822. ISocket *s = &r->socks.item(i);
  823. if (!QUERYINTERFACE(s, CInterface)->IsShared()) {
  824. r->tick = msTick();
  825. s->Link();
  826. return s;
  827. }
  828. }
  829. }
  830. return NULL;
  831. }
  832. void addLink(SocketEndpoint &ep,ISocket *sock)
  833. {
  834. // always called from crit block
  835. while (numsockets>=SOCKET_CACHE_MAX) {
  836. // find oldest
  837. CConnectionRec *c = NULL;
  838. unsigned oldest = 0;
  839. CConnectionRec *old = NULL;
  840. unsigned oldi;
  841. unsigned now = msTick();
  842. for (;;) {
  843. c = (CConnectionRec *)SuperHashTableOf<CConnectionRec,SocketEndpoint>::next(c);
  844. if (!c)
  845. break;
  846. ForEachItemIn(i,c->socks) {
  847. ISocket *s = &c->socks.item(i);
  848. if (!QUERYINTERFACE(s, CInterface)->IsShared()) { // candidate to remove
  849. unsigned t = now-c->tick;
  850. if (t>oldest) {
  851. oldest = t;
  852. old = c;
  853. oldi = i;
  854. }
  855. }
  856. }
  857. }
  858. if (!old)
  859. return;
  860. old->socks.remove(oldi);
  861. numsockets--;
  862. }
  863. CConnectionRec *r = SuperHashTableOf<CConnectionRec,SocketEndpoint>::find(&ep);
  864. if (!r) {
  865. r = new CConnectionRec;
  866. r->ep = ep;
  867. SuperHashTableOf<CConnectionRec,SocketEndpoint>::add(*r);
  868. }
  869. sock->Link();
  870. r->socks.append(*sock);
  871. numsockets++;
  872. r->tick = msTick();
  873. }
  874. void remove(SocketEndpoint &ep,ISocket *sock)
  875. {
  876. // always called from crit block
  877. CConnectionRec *r = SuperHashTableOf<CConnectionRec,SocketEndpoint>::find(&ep);
  878. if (r)
  879. if (r->socks.zap(*sock)&&numsockets)
  880. numsockets--;
  881. }
  882. } *ConnectionTable = NULL;
  883. CriticalSection CConnectionTable::crit;
  884. void clientSetDaliServixSocketCaching(bool on)
  885. {
  886. CriticalBlock block(CConnectionTable::crit);
  887. if (on) {
  888. if (!ConnectionTable)
  889. ConnectionTable = new CConnectionTable;
  890. }
  891. else {
  892. delete ConnectionTable;
  893. ConnectionTable = NULL;
  894. }
  895. }
  896. //---------------------------------------------------------------------------
  897. // TreeCopy
  898. #define TREECOPY_CACHE_SIZE 50
  899. struct CTreeCopyItem: public CInterface
  900. {
  901. StringAttr net;
  902. StringAttr mask;
  903. offset_t sz; // original size
  904. CDateTime dt; // original date
  905. RemoteFilenameArray loc; // locations for file - 0 is original
  906. Owned<IBitSet> busy;
  907. unsigned lastused;
  908. CTreeCopyItem(RemoteFilename &orig, const char *_net, const char *_mask, offset_t _sz, CDateTime &_dt)
  909. : net(_net), mask(_mask)
  910. {
  911. loc.append(orig);
  912. dt.set(_dt);
  913. sz = _sz;
  914. busy.setown(createThreadSafeBitSet());
  915. lastused = msTick();
  916. }
  917. bool equals(const RemoteFilename &orig, const char *_net, const char *_mask, offset_t _sz, CDateTime &_dt)
  918. {
  919. if (!orig.equals(loc.item(0)))
  920. return false;
  921. if (strcmp(_net,net)!=0)
  922. return false;
  923. if (strcmp(_mask,mask)!=0)
  924. return false;
  925. if (sz!=_sz)
  926. return false;
  927. return (dt.equals(_dt,false));
  928. }
  929. };
  930. static CIArrayOf<CTreeCopyItem> treeCopyArray;
  931. static CriticalSection treeCopyCrit;
  932. static unsigned treeCopyWaiting=0;
  933. static Semaphore treeCopySem;
  934. #define DEBUGSAMEIP false
  935. static void cleanupSocket(ISocket *sock)
  936. {
  937. if (!sock)
  938. return;
  939. try
  940. {
  941. sock->shutdown();
  942. }
  943. catch (IException *e)
  944. {
  945. e->Release();
  946. }
  947. try
  948. {
  949. sock->close();
  950. }
  951. catch (IException *e)
  952. {
  953. e->Release();
  954. }
  955. }
  956. //---------------------------------------------------------------------------
  957. class CRemoteBase: public CInterface
  958. {
  959. Owned<ISocket> socket;
  960. static SocketEndpoint lastfailep;
  961. static unsigned lastfailtime;
  962. DAFSConnectCfg connectMethod;
  963. void connectSocket(SocketEndpoint &ep, unsigned localConnectTime=0, unsigned localRetries=0)
  964. {
  965. unsigned retries = 3;
  966. if (localConnectTime)
  967. {
  968. if (localRetries)
  969. retries = localRetries;
  970. if (localConnectTime > maxConnectTime)
  971. localConnectTime = maxConnectTime;
  972. }
  973. else
  974. localConnectTime = maxConnectTime;
  975. sRFTM tm(localConnectTime);
  976. // called in CConnectionTable::crit
  977. if (ep.equals(lastfailep)) {
  978. if (msTick()-lastfailtime<DAFS_CONNECT_FAIL_RETRY_TIME) {
  979. StringBuffer msg("Failed to connect (host marked down) to dafilesrv/daliservix on ");
  980. ep.getUrlStr(msg);
  981. throw createDafsException(DAFSERR_connection_failed,msg.str());
  982. }
  983. lastfailep.set(NULL);
  984. retries = 1; // on probation
  985. }
  986. while(retries--) {
  987. CriticalUnblock unblock(CConnectionTable::crit); // allow others to connect
  988. StringBuffer eps;
  989. if (TF_TRACE_CLIENT_CONN) {
  990. ep.getUrlStr(eps);
  991. if (ep.port == securitySettings.daFileSrvSSLPort)
  992. PROGLOG("Connecting SECURE to %s", eps.str());
  993. else
  994. PROGLOG("Connecting to %s", eps.str());
  995. //PrintStackReport();
  996. }
  997. bool ok = true;
  998. try {
  999. if (tm.timemon) {
  1000. unsigned remaining;
  1001. if (tm.timemon->timedout(&remaining))
  1002. throwJSocketException(JSOCKERR_connection_failed);
  1003. socket.setown(ISocket::connect_timeout(ep,remaining));
  1004. }
  1005. else
  1006. socket.setown(ISocket::connect(ep));
  1007. if (ep.port == securitySettings.daFileSrvSSLPort)
  1008. {
  1009. #ifdef _USE_OPENSSL
  1010. Owned<ISecureSocket> ssock;
  1011. try
  1012. {
  1013. ssock.setown(createSecureSocket(socket.getClear(), ClientSocket));
  1014. int status = ssock->secure_connect();
  1015. if (status < 0)
  1016. throw createDafsException(DAFSERR_connection_failed, "Failure to establish secure connection");
  1017. socket.setown(ssock.getLink());
  1018. }
  1019. catch (IException *e)
  1020. {
  1021. cleanupSocket(ssock);
  1022. ssock.clear();
  1023. cleanupSocket(socket);
  1024. socket.clear();
  1025. StringBuffer eMsg;
  1026. e->errorMessage(eMsg);
  1027. e->Release();
  1028. throw createDafsException(DAFSERR_connection_failed, eMsg.str());
  1029. }
  1030. #else
  1031. throw createDafsException(DAFSERR_connection_failed,"Failure to establish secure connection: OpenSSL disabled in build");
  1032. #endif
  1033. }
  1034. }
  1035. catch (IJSOCK_Exception *e) {
  1036. ok = false;
  1037. if (!retries||(tm.timemon&&tm.timemon->timedout())) {
  1038. if (e->errorCode()==JSOCKERR_connection_failed) {
  1039. lastfailep.set(ep);
  1040. lastfailtime = msTick();
  1041. e->Release();
  1042. StringBuffer msg("Failed to connect (setting host down) to dafilesrv/daliservix on ");
  1043. ep.getUrlStr(msg);
  1044. throw createDafsException(DAFSERR_connection_failed,msg.str());
  1045. }
  1046. throw;
  1047. }
  1048. StringBuffer err;
  1049. WARNLOG("Remote file connect %s",e->errorMessage(err).str());
  1050. e->Release();
  1051. }
  1052. if (ok) {
  1053. if (TF_TRACE_CLIENT_CONN) {
  1054. PROGLOG("Connected to %s",eps.str());
  1055. }
  1056. if (AuthenticationEnabled) {
  1057. try {
  1058. sendAuthentication(ep); // this will log error
  1059. break;
  1060. }
  1061. catch (IJSOCK_Exception *e) {
  1062. StringBuffer err;
  1063. WARNLOG("Remote file authenticate %s for %s ",e->errorMessage(err).str(),ep.getUrlStr(eps.clear()).str());
  1064. e->Release();
  1065. if (!retries)
  1066. break; // MCK - is this a warning or an error ? If an error, should we close and throw here ?
  1067. }
  1068. }
  1069. else
  1070. break;
  1071. }
  1072. bool timeExpired = false;
  1073. unsigned sleeptime = getRandom()%3000+1000;
  1074. if (tm.timemon)
  1075. {
  1076. unsigned remaining;
  1077. if (tm.timemon->timedout(&remaining))
  1078. timeExpired = true;
  1079. else
  1080. {
  1081. if (remaining/2<sleeptime)
  1082. sleeptime = remaining/2;
  1083. }
  1084. }
  1085. if (!timeExpired)
  1086. {
  1087. Sleep(sleeptime); // prevent multiple retries beating
  1088. if (ep.port == securitySettings.daFileSrvSSLPort)
  1089. PROGLOG("Retrying SECURE connect");
  1090. else
  1091. PROGLOG("Retrying connect");
  1092. }
  1093. }
  1094. if (ConnectionTable)
  1095. ConnectionTable->addLink(ep,socket);
  1096. }
  1097. void killSocket(SocketEndpoint &tep)
  1098. {
  1099. CriticalBlock block2(CConnectionTable::crit); // this is nested with crit
  1100. if (socket) {
  1101. try {
  1102. Owned<ISocket> s = socket.getClear();
  1103. if (ConnectionTable)
  1104. ConnectionTable->remove(tep,s);
  1105. }
  1106. catch (IJSOCK_Exception *e) {
  1107. e->Release(); // ignore errors closing
  1108. }
  1109. Sleep(getRandom()%1000*5+500); // prevent multiple beating
  1110. }
  1111. }
  1112. protected: friend class CRemoteFileIO;
  1113. StringAttr filename;
  1114. CriticalSection crit;
  1115. SocketEndpoint ep;
  1116. void sendRemoteCommand(MemoryBuffer & src, MemoryBuffer & reply, bool retry=true, bool lengthy=false, bool handleErrCode=true)
  1117. {
  1118. CriticalBlock block(crit); // serialize commands on same file
  1119. SocketEndpoint tep(ep);
  1120. setDafsEndpointPort(tep);
  1121. unsigned nretries = retry?3:0;
  1122. Owned<IJSOCK_Exception> firstexc; // when retrying return first error if fails
  1123. for (;;)
  1124. {
  1125. try
  1126. {
  1127. if (socket)
  1128. {
  1129. sendBuffer(socket, src);
  1130. receiveBuffer(socket, reply, lengthy?LENGTHY_RETRIES:NORMAL_RETRIES);
  1131. break;
  1132. }
  1133. }
  1134. catch (IJSOCK_Exception *e)
  1135. {
  1136. if (!nretries--)
  1137. {
  1138. if (firstexc)
  1139. {
  1140. e->Release();
  1141. e = firstexc.getClear();
  1142. }
  1143. killSocket(tep);
  1144. throw e;
  1145. }
  1146. StringBuffer str;
  1147. e->errorMessage(str);
  1148. WARNLOG("Remote File: %s, retrying (%d)",str.str(),nretries);
  1149. if (firstexc)
  1150. e->Release();
  1151. else
  1152. firstexc.setown(e);
  1153. killSocket(tep);
  1154. }
  1155. CriticalBlock block2(CConnectionTable::crit); // this is nested with crit
  1156. if (ConnectionTable)
  1157. {
  1158. socket.setown(ConnectionTable->lookup(tep));
  1159. if (socket)
  1160. {
  1161. // validate existing socket by sending an 'exists' command with short time out
  1162. // (use exists for backward compatibility)
  1163. bool ok = false;
  1164. try
  1165. {
  1166. MemoryBuffer sendbuf;
  1167. initSendBuffer(sendbuf);
  1168. MemoryBuffer replybuf;
  1169. sendbuf.append((RemoteFileCommandType)RFCexists).append(filename);
  1170. sendBuffer(socket, sendbuf);
  1171. receiveBuffer(socket, replybuf, 0, 1024);
  1172. ok = true;
  1173. }
  1174. catch (IException *e) {
  1175. e->Release();
  1176. }
  1177. if (!ok)
  1178. killSocket(tep);
  1179. }
  1180. }
  1181. if (!socket)
  1182. {
  1183. bool doConnect = true;
  1184. if (connectMethod == SSLFirst || connectMethod == UnsecureFirst)
  1185. {
  1186. // MCK - could maintain a list of 100 or so previous endpoints and if connection failed
  1187. // then mark port down for a delay (like 15 min above) to avoid having to try every time ...
  1188. try
  1189. {
  1190. connectSocket(tep, 5000, 1);
  1191. doConnect = false;
  1192. }
  1193. catch (IDAFS_Exception *e)
  1194. {
  1195. if (e->errorCode() == DAFSERR_connection_failed)
  1196. {
  1197. unsigned prevPort = tep.port;
  1198. if (prevPort == securitySettings.daFileSrvSSLPort)
  1199. tep.port = securitySettings.daFileSrvPort;
  1200. else
  1201. tep.port = securitySettings.daFileSrvSSLPort;
  1202. WARNLOG("Connect failed on port %d, retrying on port %d", prevPort, tep.port);
  1203. doConnect = true;
  1204. e->Release();
  1205. }
  1206. else
  1207. throw e;
  1208. }
  1209. }
  1210. if (doConnect)
  1211. connectSocket(tep);
  1212. }
  1213. }
  1214. if (!handleErrCode)
  1215. return;
  1216. unsigned errCode;
  1217. reply.read(errCode);
  1218. if (errCode)
  1219. {
  1220. // old Solaris daliservix.cpp error code conversion
  1221. if ( (errCode >= 8200) && (errCode <= 8210) )
  1222. errCode = mapDafilesrvixCodes(errCode);
  1223. StringBuffer msg;
  1224. if (filename.get())
  1225. msg.append(filename);
  1226. ep.getUrlStr(msg.append('[')).append("] ");
  1227. size32_t pos = reply.getPos();
  1228. if (pos<reply.length())
  1229. {
  1230. size32_t len = reply.length()-pos;
  1231. const byte *rest = reply.readDirect(len);
  1232. if (errCode==RFSERR_InvalidCommand)
  1233. {
  1234. const char *s = (const char *)rest;
  1235. const char *e = (const char *)rest+len;
  1236. while (*s&&(s!=e))
  1237. s++;
  1238. msg.append(s-(const char *)rest,(const char *)rest);
  1239. }
  1240. else if (len&&(rest[len-1]==0))
  1241. msg.append((const char *)rest);
  1242. else
  1243. {
  1244. msg.appendf("extra data[%d]",len);
  1245. for (unsigned i=0;(i<16)&&(i<len);i++)
  1246. msg.appendf(" %2x",(int)rest[i]);
  1247. }
  1248. }
  1249. // NB: could append getRFSERRText for all error codes
  1250. else if (errCode == RFSERR_GetDirFailed)
  1251. msg.append(RFSERR_GetDirFailed_Text);
  1252. else
  1253. msg.append("ERROR #").append(errCode);
  1254. #ifdef _DEBUG
  1255. ERRLOG("%s",msg.str());
  1256. PrintStackReport();
  1257. #endif
  1258. throw createDafsException(errCode,msg.str());
  1259. }
  1260. }
  1261. void sendRemoteCommand(MemoryBuffer & src, bool retry)
  1262. {
  1263. MemoryBuffer reply;
  1264. sendRemoteCommand(src, reply, retry);
  1265. }
  1266. void throwUnauthenticated(const IpAddress &ip,const char *user,unsigned err=0)
  1267. {
  1268. if (err==0)
  1269. err = RFSERR_AuthenticateFailed;
  1270. StringBuffer msg;
  1271. msg.appendf("Authentication for %s on ",user);
  1272. ip.getIpText(msg);
  1273. msg.append(" failed");
  1274. throw createDafsException(err, msg.str());
  1275. }
  1276. void sendAuthentication(const IpAddress &serverip)
  1277. {
  1278. // send my sig
  1279. // first send my sig which if stream unencrypted will get returned as a bad command
  1280. OnceKey oncekey;
  1281. genOnce(oncekey);
  1282. MemoryBuffer sendbuf;
  1283. initSendBuffer(sendbuf);
  1284. MemoryBuffer replybuf;
  1285. MemoryBuffer encbuf; // because aesEncrypt clears input
  1286. sendbuf.append((RemoteFileCommandType)RFCunlock).append(sizeof(oncekey),&oncekey);
  1287. try
  1288. {
  1289. sendBuffer(socket, sendbuf);
  1290. receiveBuffer(socket, replybuf, NORMAL_RETRIES, 1024);
  1291. }
  1292. catch (IException *e)
  1293. {
  1294. EXCLOG(e,"Remote file - sendAuthentication(1)");
  1295. throw;
  1296. }
  1297. unsigned errCode;
  1298. replybuf.read(errCode);
  1299. if (errCode!=0) // no authentication required
  1300. return;
  1301. SocketEndpoint ep;
  1302. ep.setLocalHost(0);
  1303. byte ipdata[16];
  1304. size32_t ipds = ep.getNetAddress(sizeof(ipdata),&ipdata);
  1305. mergeOnce(oncekey,ipds,&ipdata);
  1306. StringBuffer username;
  1307. StringBuffer password;
  1308. IPasswordProvider * pp = queryPasswordProvider();
  1309. if (pp)
  1310. pp->getPassword(serverip, username, password);
  1311. if (!username.length())
  1312. username.append("sds_system"); // default account (note if exists should have restricted access!)
  1313. if (!password.length())
  1314. password.append("sds_man");
  1315. if (replybuf.remaining()<=sizeof(size32_t))
  1316. throwUnauthenticated(serverip,username.str());
  1317. size32_t bs;
  1318. replybuf.read(bs);
  1319. if (replybuf.remaining()<bs)
  1320. throwUnauthenticated(serverip,username.str());
  1321. MemoryBuffer skeybuf;
  1322. aesDecrypt(&oncekey,sizeof(oncekey),replybuf.readDirect(bs),bs,skeybuf);
  1323. if (skeybuf.remaining()<sizeof(OnceKey))
  1324. throwUnauthenticated(serverip,username.str());
  1325. OnceKey sokey;
  1326. skeybuf.read(sizeof(OnceKey),&sokey);
  1327. // now we have the key to use to send user/password
  1328. MemoryBuffer tosend;
  1329. tosend.append((byte)2).append(username).append(password);
  1330. initSendBuffer(sendbuf.clear());
  1331. sendbuf.append((RemoteFileCommandType)RFCunlockreply);
  1332. aesEncrypt(&sokey, sizeof(oncekey), tosend.toByteArray(), tosend.length(), encbuf);
  1333. sendbuf.append(encbuf.length());
  1334. sendbuf.append(encbuf);
  1335. try
  1336. {
  1337. sendBuffer(socket, sendbuf);
  1338. receiveBuffer(socket, replybuf.clear(), NORMAL_RETRIES, 1024);
  1339. }
  1340. catch (IException *e)
  1341. {
  1342. EXCLOG(e,"Remote file - sendAuthentication(2)");
  1343. throw;
  1344. }
  1345. replybuf.read(errCode);
  1346. if (errCode==0) // suceeded!
  1347. return;
  1348. throwUnauthenticated(serverip,username.str(),errCode);
  1349. }
  1350. public:
  1351. SocketEndpoint &queryEp() { return ep; };
  1352. CRemoteBase(const SocketEndpoint &_ep, const char * _filename)
  1353. : filename(_filename)
  1354. {
  1355. ep = _ep;
  1356. connectMethod = securitySettings.connectMethod;
  1357. }
  1358. void disconnect()
  1359. {
  1360. CriticalBlock block(crit);
  1361. CriticalBlock block2(CConnectionTable::crit); // this shouldn't ever block
  1362. if (socket)
  1363. {
  1364. ISocket *s = socket.getClear();
  1365. if (ConnectionTable)
  1366. {
  1367. SocketEndpoint tep(ep);
  1368. setDafsEndpointPort(tep);
  1369. ConnectionTable->remove(tep,s);
  1370. }
  1371. ::Release(s);
  1372. }
  1373. }
  1374. const char *queryLocalName()
  1375. {
  1376. return filename;
  1377. }
  1378. };
  1379. SocketEndpoint CRemoteBase::lastfailep;
  1380. unsigned CRemoteBase::lastfailtime;
  1381. //---------------------------------------------------------------------------
  1382. class CRemoteDirectoryIterator : implements IDirectoryDifferenceIterator, public CInterface
  1383. {
  1384. Owned<IFile> cur;
  1385. bool curvalid;
  1386. bool curisdir;
  1387. StringAttr curname;
  1388. CDateTime curdt;
  1389. __int64 cursize;
  1390. StringAttr dir;
  1391. SocketEndpoint ep;
  1392. byte *flags;
  1393. unsigned numflags;
  1394. unsigned curidx;
  1395. unsigned mask;
  1396. MemoryBuffer buf;
  1397. public:
  1398. static CriticalSection crit;
  1399. CRemoteDirectoryIterator(SocketEndpoint &_ep,const char *_dir)
  1400. : dir(_dir)
  1401. {
  1402. // an extended difference iterator starts with 2 (for bwd compatibility)
  1403. ep = _ep;
  1404. curisdir = false;
  1405. curvalid = false;
  1406. cursize = 0;
  1407. curidx = (unsigned)-1;
  1408. mask = 0;
  1409. numflags = 0;
  1410. flags = NULL;
  1411. }
  1412. bool appendBuf(MemoryBuffer &_buf)
  1413. {
  1414. buf.setSwapEndian(_buf.needSwapEndian());
  1415. byte hdr;
  1416. _buf.read(hdr);
  1417. if (hdr==2) {
  1418. _buf.read(numflags);
  1419. flags = (byte *)malloc(numflags);
  1420. _buf.read(numflags,flags);
  1421. }
  1422. else {
  1423. buf.append(hdr);
  1424. flags = NULL;
  1425. numflags = 0;
  1426. }
  1427. size32_t rest = _buf.length()-_buf.getPos();
  1428. const byte *rb = (const byte *)_buf.readDirect(rest);
  1429. bool ret = true;
  1430. // At the last byte of the rb (rb[rest-1]) is the stream live flag
  1431. // True if the stream has more data
  1432. // False at the end of stream
  1433. // The previous byte (rb[rest-2]) is the flag to signal there are more
  1434. // valid entries in this block
  1435. // True if there are valid directory entry follows this flag
  1436. // False if there are no more valid entry in this block aka end of block
  1437. // If there is more data in the stream, the end of block flag should be removed
  1438. if (rest&&(rb[rest-1]!=0))
  1439. {
  1440. rest--; // remove stream live flag
  1441. if(rest && (0 == rb[rest-1]))
  1442. rest--; //Remove end of block flag
  1443. ret = false; // continuation
  1444. }
  1445. buf.append(rest,rb);
  1446. return ret;
  1447. }
  1448. ~CRemoteDirectoryIterator()
  1449. {
  1450. free(flags);
  1451. }
  1452. IMPLEMENT_IINTERFACE
  1453. bool first()
  1454. {
  1455. curidx = (unsigned)-1;
  1456. buf.reset();
  1457. return next();
  1458. }
  1459. bool next()
  1460. {
  1461. for (;;) {
  1462. curidx++;
  1463. cur.clear();
  1464. curdt.clear();
  1465. curname.clear();
  1466. cursize = 0;
  1467. curisdir = false;
  1468. if (buf.getPos()>=buf.length())
  1469. return false;
  1470. byte isValidEntry;
  1471. buf.read(isValidEntry);
  1472. curvalid = isValidEntry!=0;
  1473. if (!curvalid)
  1474. return false;
  1475. buf.read(curisdir);
  1476. buf.read(cursize);
  1477. curdt.deserialize(buf);
  1478. buf.read(curname);
  1479. // kludge for bug in old linux jlibs
  1480. if (strchr(curname,'\\')&&(getPathSepChar(dir)=='/')) {
  1481. StringBuffer temp(curname);
  1482. temp.replace('\\','/');
  1483. curname.set(temp.str());
  1484. }
  1485. if ((mask==0)||(getFlags()&mask))
  1486. break;
  1487. }
  1488. return true;
  1489. }
  1490. bool isValid()
  1491. {
  1492. return curvalid;
  1493. }
  1494. IFile & query()
  1495. {
  1496. if (!cur) {
  1497. StringBuffer full(dir);
  1498. addPathSepChar(full).append(curname);
  1499. if (ep.isNull())
  1500. cur.setown(createIFile(full.str()));
  1501. else {
  1502. RemoteFilename rfn;
  1503. rfn.setPath(ep,full.str());
  1504. cur.setown(createIFile(rfn));
  1505. }
  1506. }
  1507. return *cur;
  1508. }
  1509. StringBuffer &getName(StringBuffer &buf)
  1510. {
  1511. return buf.append(curname);
  1512. }
  1513. bool isDir()
  1514. {
  1515. return curisdir;
  1516. }
  1517. __int64 getFileSize()
  1518. {
  1519. if (curisdir)
  1520. return -1;
  1521. return cursize;
  1522. }
  1523. bool getModifiedTime(CDateTime &ret)
  1524. {
  1525. ret = curdt;
  1526. return true;
  1527. }
  1528. void setMask(unsigned _mask)
  1529. {
  1530. mask = _mask;
  1531. }
  1532. virtual unsigned getFlags()
  1533. {
  1534. if (flags&&(curidx<numflags))
  1535. return flags[curidx];
  1536. return 0;
  1537. }
  1538. static bool serialize(MemoryBuffer &mb,IDirectoryIterator *iter, size32_t bufsize, bool first)
  1539. {
  1540. bool ret = true;
  1541. byte b=1;
  1542. StringBuffer tmp;
  1543. if (first ? iter->first() : iter->next()) {
  1544. for (;;) {
  1545. mb.append(b);
  1546. bool isdir = iter->isDir();
  1547. __int64 sz = isdir?0:iter->getFileSize();
  1548. CDateTime dt;
  1549. iter->getModifiedTime(dt);
  1550. iter->getName(tmp.clear());
  1551. mb.append(isdir).append(sz);
  1552. dt.serialize(mb);
  1553. mb.append(tmp.str());
  1554. if (bufsize&&(mb.length()>=bufsize-1)) {
  1555. ret = false;
  1556. break;
  1557. }
  1558. if (!iter->next())
  1559. break;
  1560. }
  1561. }
  1562. b = 0;
  1563. mb.append(b);
  1564. return ret;
  1565. }
  1566. static void serializeDiff(MemoryBuffer &mb,IDirectoryDifferenceIterator *iter)
  1567. {
  1568. // bit slow
  1569. MemoryBuffer flags;
  1570. ForEach(*iter)
  1571. flags.append((byte)iter->getFlags());
  1572. if (flags.length()) {
  1573. byte b = 2;
  1574. mb.append(b).append((unsigned)flags.length()).append(flags);
  1575. }
  1576. serialize(mb,iter,0,true);
  1577. }
  1578. void serialize(MemoryBuffer &mb,bool isdiff)
  1579. {
  1580. byte b;
  1581. if (isdiff&&numflags&&flags) {
  1582. b = 2;
  1583. mb.append(b).append(numflags).append(numflags,flags);
  1584. }
  1585. serialize(mb,this,0,true);
  1586. }
  1587. };
  1588. class CCritTable;
  1589. class CEndpointCS : public CriticalSection, public CInterface
  1590. {
  1591. CCritTable &table;
  1592. const SocketEndpoint ep;
  1593. public:
  1594. CEndpointCS(CCritTable &_table, const SocketEndpoint &_ep) : table(_table), ep(_ep) { }
  1595. const void *queryFindParam() const { return &ep; }
  1596. virtual void beforeDispose();
  1597. };
  1598. class CCritTable : private SimpleHashTableOf<CEndpointCS, const SocketEndpoint>
  1599. {
  1600. typedef SimpleHashTableOf<CEndpointCS, const SocketEndpoint> PARENT;
  1601. CriticalSection crit;
  1602. public:
  1603. CEndpointCS *getCrit(const SocketEndpoint &ep)
  1604. {
  1605. CriticalBlock b(crit);
  1606. Linked<CEndpointCS> clientCrit = find(ep);
  1607. if (!clientCrit || !clientCrit->isAlive()) // if !isAlive(), then it is in the process of being destroyed/removed.
  1608. {
  1609. clientCrit.setown(new CEndpointCS(*this, ep));
  1610. replace(*clientCrit); // NB table doesn't own
  1611. }
  1612. return clientCrit.getClear();
  1613. }
  1614. unsigned getHashFromElement(const void *e) const
  1615. {
  1616. const CEndpointCS &elem=*(const CEndpointCS *)e;
  1617. return getHashFromFindParam(elem.queryFindParam());
  1618. }
  1619. unsigned getHashFromFindParam(const void *fp) const
  1620. {
  1621. return ((const SocketEndpoint *)fp)->hash(0);
  1622. }
  1623. void removeExact(CEndpointCS *clientCrit)
  1624. {
  1625. CriticalBlock b(crit);
  1626. PARENT::removeExact(clientCrit); // NB may not exist, could have been replaced if detected !isAlive() in getCrit()
  1627. }
  1628. } *dirCSTable;
  1629. MODULE_INIT(INIT_PRIORITY_STANDARD)
  1630. {
  1631. dirCSTable = new CCritTable;
  1632. return true;
  1633. }
  1634. MODULE_EXIT()
  1635. {
  1636. delete dirCSTable;
  1637. }
  1638. void CEndpointCS::beforeDispose()
  1639. {
  1640. table.removeExact(this);
  1641. }
  1642. class CRemoteFilteredFileIOBase : public CRemoteBase, implements IRemoteFileIO
  1643. {
  1644. public:
  1645. IMPLEMENT_IINTERFACE;
  1646. // Really a stream, but life (maybe) easier elsewhere if looks like a file
  1647. // Sometime should refactor to be based on ISerialStream instead - or maybe IRowStream.
  1648. CRemoteFilteredFileIOBase(SocketEndpoint &ep, const char *filename, IOutputMetaData *actual, IOutputMetaData *projected, const RowFilter &fieldFilters, unsigned __int64 chooseN)
  1649. : CRemoteBase(ep, filename)
  1650. {
  1651. // NB: inputGrouped == outputGrouped for now, but may want output to be ungrouped
  1652. openRequest();
  1653. if (queryOutputCompressionDefault())
  1654. {
  1655. expander.setown(getExpander(queryOutputCompressionDefault()));
  1656. if (expander)
  1657. {
  1658. expandMb.setEndian(__BIG_ENDIAN);
  1659. request.appendf("\"outputCompression\" : \"%s\",\n", queryOutputCompressionDefault());
  1660. }
  1661. else
  1662. WARNLOG("Failed to created compression decompressor for: %s", queryOutputCompressionDefault());
  1663. }
  1664. request.appendf("\"format\" : \"binary\",\n"
  1665. "\"node\" : {\n"
  1666. " \"fileName\" : \"%s\"", filename);
  1667. if (chooseN)
  1668. request.appendf(",\n \"chooseN\" : \"%" I64F "u\"", chooseN);
  1669. if (fieldFilters.numFilterFields())
  1670. {
  1671. request.append(",\n \"keyFilter\" : [\n ");
  1672. for (unsigned idx=0; idx < fieldFilters.numFilterFields(); idx++)
  1673. {
  1674. auto &filter = fieldFilters.queryFilter(idx);
  1675. StringBuffer filterString;
  1676. filter.serialize(filterString);
  1677. if (idx)
  1678. request.append(",\n ");
  1679. request.append("\"");
  1680. encodeJSON(request, filterString.length(), filterString.str());
  1681. request.append("\"");
  1682. }
  1683. request.append("\n ]");
  1684. }
  1685. MemoryBuffer actualTypeInfo;
  1686. if (!dumpTypeInfo(actualTypeInfo, actual->querySerializedDiskMeta()->queryTypeInfo()))
  1687. throw createDafsException(DAFSERR_cmdstream_unsupported_recfmt, "Format not supported by remote read");
  1688. request.append(",\n \"inputBin\" : \"");
  1689. JBASE64_Encode(actualTypeInfo.toByteArray(), actualTypeInfo.length(), request, false);
  1690. request.append("\"");
  1691. if (actual != projected)
  1692. {
  1693. MemoryBuffer projectedTypeInfo;
  1694. dumpTypeInfo(projectedTypeInfo, projected->querySerializedDiskMeta()->queryTypeInfo());
  1695. if (actualTypeInfo.length() != projectedTypeInfo.length() ||
  1696. memcmp(actualTypeInfo.toByteArray(), projectedTypeInfo.toByteArray(), actualTypeInfo.length()))
  1697. {
  1698. request.append(",\n \"outputBin\": \"");
  1699. JBASE64_Encode(projectedTypeInfo.toByteArray(), projectedTypeInfo.length(), request, false);
  1700. request.append("\"");
  1701. }
  1702. }
  1703. bufPos = 0;
  1704. }
  1705. virtual size32_t read(offset_t pos, size32_t len, void * data) override
  1706. {
  1707. assertex(pos == bufPos); // Must read sequentially
  1708. if (!bufRemaining && !eof)
  1709. refill();
  1710. if (eof)
  1711. return 0;
  1712. if (len > bufRemaining)
  1713. len = bufRemaining;
  1714. bufPos += len;
  1715. bufRemaining -= len;
  1716. memcpy(data, reply.readDirect(len), len);
  1717. return len;
  1718. }
  1719. virtual offset_t size() override { return -1; }
  1720. virtual size32_t write(offset_t pos, size32_t len, const void * data) override { throwUnexpected(); }
  1721. virtual offset_t appendFile(IFile *file,offset_t pos=0,offset_t len=(offset_t)-1) override { throwUnexpected(); }
  1722. virtual void setSize(offset_t size) override { throwUnexpected(); }
  1723. virtual void flush() override { throwUnexpected(); }
  1724. virtual void close() override
  1725. {
  1726. if (handle)
  1727. {
  1728. try
  1729. {
  1730. MemoryBuffer sendBuffer;
  1731. initSendBuffer(sendBuffer);
  1732. sendBuffer.append((RemoteFileCommandType)RFCcloseIO).append(handle);
  1733. sendRemoteCommand(sendBuffer,false);
  1734. }
  1735. catch (IDAFS_Exception *e)
  1736. {
  1737. if ((e->errorCode()!=RFSERR_InvalidFileIOHandle)&&(e->errorCode()!=RFSERR_NullFileIOHandle))
  1738. throw;
  1739. e->Release();
  1740. }
  1741. handle = 0;
  1742. }
  1743. }
  1744. virtual unsigned __int64 getStatistic(StatisticKind kind) override
  1745. {
  1746. /* NB: Would need new stat. categories added for this to make sense,
  1747. * but this class is implemented as a IFileIO for convenience for now,
  1748. * it may be refactored into another form later.
  1749. */
  1750. return 0;
  1751. }
  1752. // IRemoteFileIO
  1753. virtual void addVirtualFieldMapping(const char *fieldName, const char *fieldValue) override
  1754. {
  1755. virtualFields[fieldName] = fieldValue;
  1756. }
  1757. virtual void ensureAvailable() override
  1758. {
  1759. if (firstRequest)
  1760. handleFirstRequest();
  1761. }
  1762. protected:
  1763. StringBuffer &openRequest()
  1764. {
  1765. return request.append("{\n");
  1766. }
  1767. StringBuffer &closeRequest()
  1768. {
  1769. return request.append("\n }\n");
  1770. }
  1771. void addVirtualFields()
  1772. {
  1773. request.append(", \n \"virtualFields\" : {\n");
  1774. bool first=true;
  1775. for (auto &e : virtualFields)
  1776. {
  1777. if (!first)
  1778. request.append(",\n");
  1779. request.appendf(" \"%s\" : \"%s\"", e.first.c_str(), e.second.c_str());
  1780. first = false;
  1781. }
  1782. request.append(" }");
  1783. }
  1784. void handleFirstRequest()
  1785. {
  1786. firstRequest = false;
  1787. addVirtualFields();
  1788. closeRequest();
  1789. sendRequest(0, nullptr);
  1790. }
  1791. void refill()
  1792. {
  1793. if (firstRequest)
  1794. {
  1795. handleFirstRequest();
  1796. return;
  1797. }
  1798. size32_t cursorLength;
  1799. reply.read(cursorLength);
  1800. if (!cursorLength)
  1801. {
  1802. eof = true;
  1803. return;
  1804. }
  1805. MemoryBuffer mrequest;
  1806. MemoryBuffer newReply;
  1807. initSendBuffer(mrequest);
  1808. mrequest.append((RemoteFileCommandType)RFCStreamRead);
  1809. VStringBuffer json("{ \"handle\" : %u }", handle);
  1810. mrequest.append(json.length(), json.str());
  1811. sendRemoteCommand(mrequest, newReply);
  1812. unsigned newHandle;
  1813. newReply.read(newHandle);
  1814. if (newHandle == handle)
  1815. {
  1816. reply.swapWith(newReply);
  1817. reply.read(bufRemaining);
  1818. eof = (bufRemaining == 0);
  1819. if (expander)
  1820. {
  1821. size32_t expandedSz = expander->init(reply.bytes()+reply.getPos());
  1822. expandMb.clear().reserve(expandedSz);
  1823. expander->expand(expandMb.bufferBase());
  1824. expandMb.swapWith(reply);
  1825. }
  1826. }
  1827. else
  1828. {
  1829. assertex(newHandle == 0);
  1830. sendRequest(cursorLength, reply.readDirect(cursorLength));
  1831. }
  1832. }
  1833. void sendRequest(unsigned cursorLen, const void *cursorData)
  1834. {
  1835. MemoryBuffer mrequest;
  1836. initSendBuffer(mrequest);
  1837. mrequest.append((RemoteFileCommandType)RFCStreamRead);
  1838. mrequest.append(request.length(), request.str());
  1839. if (cursorLen)
  1840. {
  1841. StringBuffer cursorInfo;
  1842. cursorInfo.append(",\"cursorBin\": \"");
  1843. JBASE64_Encode(cursorData, cursorLen, cursorInfo, false);
  1844. cursorInfo.append("\"\n");
  1845. mrequest.append(cursorInfo.length(), cursorInfo.str());
  1846. }
  1847. if (TF_TRACE_FULL)
  1848. PROGLOG("req = <%s}>", request.str());
  1849. mrequest.append(3, " \n}");
  1850. sendRemoteCommand(mrequest, reply);
  1851. reply.read(handle);
  1852. reply.read(bufRemaining);
  1853. eof = (bufRemaining == 0);
  1854. if (expander)
  1855. {
  1856. size32_t expandedSz = expander->init(reply.bytes()+reply.getPos());
  1857. expandMb.clear().reserve(expandedSz);
  1858. expander->expand(expandMb.bufferBase());
  1859. expandMb.swapWith(reply);
  1860. }
  1861. }
  1862. StringBuffer request;
  1863. MemoryBuffer reply;
  1864. unsigned handle = 0;
  1865. size32_t bufRemaining = 0;
  1866. offset_t bufPos = 0;
  1867. bool eof = false;
  1868. bool firstRequest = true;
  1869. std::unordered_map<std::string, std::string> virtualFields;
  1870. Owned<IExpander> expander;
  1871. MemoryBuffer expandMb;
  1872. };
  1873. class CRemoteFilteredFileIO : public CRemoteFilteredFileIOBase
  1874. {
  1875. public:
  1876. // Really a stream, but life (maybe) easier elsewhere if looks like a file
  1877. // Sometime should refactor to be based on ISerialStream instead - or maybe IRowStream.
  1878. CRemoteFilteredFileIO(SocketEndpoint &ep, const char *filename, IOutputMetaData *actual, IOutputMetaData *projected, const RowFilter &fieldFilters, bool compressed, bool grouped, unsigned __int64 chooseN)
  1879. : CRemoteFilteredFileIOBase(ep, filename, actual, projected, fieldFilters, chooseN)
  1880. {
  1881. // NB: inputGrouped == outputGrouped for now, but may want output to be ungrouped
  1882. request.appendf(",\n \"kind\" : \"diskread\",\n"
  1883. " \"compressed\" : \"%s\",\n"
  1884. " \"inputGrouped\" : \"%s\",\n"
  1885. " \"outputGrouped\" : \"%s\"", boolToStr(compressed), boolToStr(grouped), boolToStr(grouped));
  1886. }
  1887. };
  1888. class CRemoteFilteredRowStream : public CRemoteFilteredFileIO, implements IRowStream
  1889. {
  1890. public:
  1891. CRemoteFilteredRowStream(const RtlRecord &_recInfo, SocketEndpoint &ep, const char * filename, IOutputMetaData *actual, IOutputMetaData *projected, const RowFilter &fieldFilters, bool compressed, bool grouped)
  1892. : CRemoteFilteredFileIO(ep, filename, actual, projected, fieldFilters, compressed, grouped, 0), recInfo(_recInfo)
  1893. {
  1894. }
  1895. virtual const byte *queryNextRow() // NOTE - rows returned must NOT be freed
  1896. {
  1897. if (!bufRemaining && !eof)
  1898. refill();
  1899. if (eof)
  1900. return nullptr;
  1901. unsigned len = recInfo.getRecordSize(reply.readDirect(0));
  1902. bufPos += len;
  1903. bufRemaining -= len;
  1904. return reply.readDirect(len);
  1905. }
  1906. virtual void stop() override
  1907. {
  1908. close();
  1909. eof = true;
  1910. }
  1911. protected:
  1912. const RtlRecord &recInfo;
  1913. };
  1914. static StringAttr remoteOutputCompressionDefault;
  1915. void setRemoteOutputCompressionDefault(const char *type)
  1916. {
  1917. if (!isEmptyString(type))
  1918. remoteOutputCompressionDefault.set(type);
  1919. }
  1920. const char *queryOutputCompressionDefault() { return remoteOutputCompressionDefault; }
  1921. extern IRemoteFileIO *createRemoteFilteredFile(SocketEndpoint &ep, const char * filename, IOutputMetaData *actual, IOutputMetaData *projected, const RowFilter &fieldFilters, bool compressed, bool grouped, unsigned __int64 chooseN)
  1922. {
  1923. try
  1924. {
  1925. return new CRemoteFilteredFileIO(ep, filename, actual, projected, fieldFilters, compressed, grouped, chooseN);
  1926. }
  1927. catch (IException *e)
  1928. {
  1929. EXCLOG(e, nullptr);
  1930. e->Release();
  1931. }
  1932. return nullptr;
  1933. }
  1934. class CRemoteFilteredKeyIO : public CRemoteFilteredFileIOBase
  1935. {
  1936. public:
  1937. // Really a stream, but life (maybe) easier elsewhere if looks like a file
  1938. // Sometime should refactor to be based on ISerialStream instead - or maybe IRowStream.
  1939. CRemoteFilteredKeyIO(SocketEndpoint &ep, const char *filename, unsigned crc, IOutputMetaData *actual, IOutputMetaData *projected, const RowFilter &fieldFilters, unsigned __int64 chooseN)
  1940. : CRemoteFilteredFileIOBase(ep, filename, actual, projected, fieldFilters, chooseN)
  1941. {
  1942. request.appendf(",\n \"kind\" : \"indexread\"");
  1943. request.appendf(",\n \"crc\" : \"%u\"", crc);
  1944. }
  1945. };
  1946. class CRemoteFilteredKeyCountIO : public CRemoteFilteredFileIOBase
  1947. {
  1948. public:
  1949. // Really a stream, but life (maybe) easier elsewhere if looks like a file
  1950. // Sometime should refactor to be based on ISerialStream instead - or maybe IRowStream.
  1951. CRemoteFilteredKeyCountIO(SocketEndpoint &ep, const char *filename, unsigned crc, IOutputMetaData *actual, const RowFilter &fieldFilters, unsigned __int64 rowLimit)
  1952. : CRemoteFilteredFileIOBase(ep, filename, actual, actual, fieldFilters, rowLimit)
  1953. {
  1954. request.appendf(",\n \"kind\" : \"indexcount\"");
  1955. request.appendf(",\n \"crc\" : \"%u\"", crc);
  1956. }
  1957. };
  1958. class CRemoteKey : public CSimpleInterfaceOf<IIndexLookup>
  1959. {
  1960. Owned<IRemoteFileIO> iRemoteFileIO;
  1961. offset_t pos = 0;
  1962. Owned<ISourceRowPrefetcher> prefetcher;
  1963. CThorContiguousRowBuffer prefetchBuffer;
  1964. Owned<ISerialStream> strm;
  1965. bool pending = false;
  1966. SocketEndpoint ep;
  1967. StringAttr filename;
  1968. unsigned crc;
  1969. Linked<IOutputMetaData> actual, projected;
  1970. RowFilter fieldFilters;
  1971. public:
  1972. CRemoteKey(SocketEndpoint &_ep, const char *_filename, unsigned _crc, IOutputMetaData *_actual, IOutputMetaData *_projected, const RowFilter &_fieldFilters, unsigned __int64 rowLimit)
  1973. : ep(_ep), filename(_filename), crc(_crc), actual(_actual), projected(_projected)
  1974. {
  1975. for (unsigned f=0; f<_fieldFilters.numFilterFields(); f++)
  1976. fieldFilters.addFilter(OLINK(_fieldFilters.queryFilter(f)));
  1977. iRemoteFileIO.setown(new CRemoteFilteredKeyIO(ep, filename, crc, actual, projected, fieldFilters, rowLimit));
  1978. if (!iRemoteFileIO)
  1979. throwStringExceptionV(DAFSERR_cmdstream_openfailure, "Unable to open remote key part: '%s'", filename.get());
  1980. strm.setown(createFileSerialStream(iRemoteFileIO));
  1981. prefetcher.setown(projected->createDiskPrefetcher());
  1982. assertex(prefetcher);
  1983. prefetchBuffer.setStream(strm);
  1984. }
  1985. // IIndexLookup
  1986. virtual void ensureAvailable() override
  1987. {
  1988. iRemoteFileIO->ensureAvailable(); // will throw an exception if fails
  1989. }
  1990. virtual unsigned __int64 getCount() override
  1991. {
  1992. return checkCount(0);
  1993. }
  1994. virtual unsigned __int64 checkCount(unsigned __int64 limit) override
  1995. {
  1996. Owned<IFileIO> iFileIO = new CRemoteFilteredKeyCountIO(ep, filename, crc, actual, fieldFilters, limit);
  1997. unsigned __int64 result;
  1998. iFileIO->read(0, sizeof(result), &result);
  1999. return result;
  2000. }
  2001. virtual const void *nextKey() override
  2002. {
  2003. if (pending)
  2004. prefetchBuffer.finishedRow();
  2005. if (prefetchBuffer.eos())
  2006. return nullptr;
  2007. prefetcher->readAhead(prefetchBuffer);
  2008. pending = true;
  2009. return prefetchBuffer.queryRow();
  2010. }
  2011. virtual unsigned querySeeks() const override { return 0; } // not sure how best to handle these, perhaps should log/record somewhere on server-side
  2012. virtual unsigned queryScans() const override { return 0; }
  2013. virtual unsigned querySkips() const override { return 0; }
  2014. };
  2015. extern IIndexLookup *createRemoteFilteredKey(SocketEndpoint &ep, const char * filename, unsigned crc, IOutputMetaData *actual, IOutputMetaData *projected, const RowFilter &fieldFilters, unsigned __int64 chooseN)
  2016. {
  2017. try
  2018. {
  2019. return new CRemoteKey(ep, filename, crc, actual, projected, fieldFilters, chooseN);
  2020. }
  2021. catch (IException *e)
  2022. {
  2023. EXCLOG(e, nullptr);
  2024. e->Release();
  2025. }
  2026. return nullptr;
  2027. }
  2028. class CRemoteFile : public CRemoteBase, implements IFile
  2029. {
  2030. StringAttr remotefilename;
  2031. unsigned flags;
  2032. bool isShareSet;
  2033. public:
  2034. IMPLEMENT_IINTERFACE
  2035. CRemoteFile(const SocketEndpoint &_ep, const char * _filename)
  2036. : CRemoteBase(_ep, _filename)
  2037. {
  2038. flags = ((unsigned)IFSHread)|((S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)<<16);
  2039. isShareSet = false;
  2040. if (filename.length()>2 && isPathSepChar(filename[0]) && isShareChar(filename[2]))
  2041. {
  2042. VStringBuffer winDriveFilename("%c:%s", filename[1], filename+3);
  2043. filename.set(winDriveFilename);
  2044. }
  2045. }
  2046. bool exists()
  2047. {
  2048. MemoryBuffer sendBuffer;
  2049. initSendBuffer(sendBuffer);
  2050. MemoryBuffer replyBuffer;
  2051. sendBuffer.append((RemoteFileCommandType)RFCexists).append(filename);
  2052. sendRemoteCommand(sendBuffer, replyBuffer);
  2053. bool ok;
  2054. replyBuffer.read(ok);
  2055. return ok;
  2056. }
  2057. bool getTime(CDateTime * createTime, CDateTime * modifiedTime, CDateTime * accessedTime)
  2058. {
  2059. CDateTime dummyTime;
  2060. if (!createTime)
  2061. createTime = &dummyTime;
  2062. if (!modifiedTime)
  2063. modifiedTime = &dummyTime;
  2064. if (!accessedTime)
  2065. accessedTime = &dummyTime;
  2066. MemoryBuffer sendBuffer;
  2067. initSendBuffer(sendBuffer);
  2068. MemoryBuffer replyBuffer;
  2069. sendBuffer.append((RemoteFileCommandType)RFCgettime).append(filename);
  2070. sendRemoteCommand(sendBuffer, replyBuffer);
  2071. bool ok;
  2072. replyBuffer.read(ok);
  2073. if (ok) {
  2074. createTime->deserialize(replyBuffer);
  2075. modifiedTime->deserialize(replyBuffer);
  2076. accessedTime->deserialize(replyBuffer);
  2077. }
  2078. return ok;
  2079. }
  2080. bool setTime(const CDateTime * createTime, const CDateTime * modifiedTime, const CDateTime * accessedTime)
  2081. {
  2082. MemoryBuffer sendBuffer;
  2083. initSendBuffer(sendBuffer);
  2084. MemoryBuffer replyBuffer;
  2085. sendBuffer.append((RemoteFileCommandType)RFCsettime).append(filename);
  2086. if (createTime)
  2087. {
  2088. sendBuffer.append((bool)true);
  2089. createTime->serialize(sendBuffer);
  2090. }
  2091. else
  2092. sendBuffer.append((bool)false);
  2093. if (modifiedTime)
  2094. {
  2095. sendBuffer.append((bool)true);
  2096. modifiedTime->serialize(sendBuffer);
  2097. }
  2098. else
  2099. sendBuffer.append((bool)false);
  2100. if (accessedTime)
  2101. {
  2102. sendBuffer.append((bool)true);
  2103. accessedTime->serialize(sendBuffer);
  2104. }
  2105. else
  2106. sendBuffer.append((bool)false);
  2107. sendRemoteCommand(sendBuffer, replyBuffer);
  2108. bool ok;
  2109. replyBuffer.read(ok);
  2110. return ok;
  2111. }
  2112. fileBool isDirectory()
  2113. {
  2114. MemoryBuffer sendBuffer;
  2115. initSendBuffer(sendBuffer);
  2116. MemoryBuffer replyBuffer;
  2117. sendBuffer.append((RemoteFileCommandType)RFCisdirectory).append(filename);
  2118. sendRemoteCommand(sendBuffer, replyBuffer);
  2119. unsigned ret;
  2120. replyBuffer.read(ret);
  2121. return (fileBool)ret;
  2122. }
  2123. fileBool isFile()
  2124. {
  2125. MemoryBuffer sendBuffer;
  2126. initSendBuffer(sendBuffer);
  2127. MemoryBuffer replyBuffer;
  2128. sendBuffer.append((RemoteFileCommandType)RFCisfile).append(filename);
  2129. sendRemoteCommand(sendBuffer, replyBuffer);
  2130. unsigned ret;
  2131. replyBuffer.read(ret);
  2132. return (fileBool)ret;
  2133. }
  2134. fileBool isReadOnly()
  2135. {
  2136. MemoryBuffer sendBuffer;
  2137. initSendBuffer(sendBuffer);
  2138. MemoryBuffer replyBuffer;
  2139. sendBuffer.append((RemoteFileCommandType)RFCisreadonly).append(filename);
  2140. sendRemoteCommand(sendBuffer, replyBuffer);
  2141. unsigned ret;
  2142. replyBuffer.read(ret);
  2143. return (fileBool)ret;
  2144. }
  2145. IFileIO * open(IFOmode mode,IFEflags extraFlags=IFEnone);
  2146. IFileIO * openShared(IFOmode mode,IFSHmode shmode,IFEflags extraFlags=IFEnone);
  2147. IFileAsyncIO * openAsync(IFOmode mode) { return NULL; } // not supported
  2148. const char * queryFilename()
  2149. {
  2150. if (remotefilename.isEmpty()) {
  2151. RemoteFilename rfn;
  2152. rfn.setPath(ep,filename);
  2153. StringBuffer path;
  2154. rfn.getRemotePath(path);
  2155. remotefilename.set(path);
  2156. }
  2157. return remotefilename.get();
  2158. }
  2159. void resetLocalFilename(const char *name)
  2160. {
  2161. remotefilename.clear();
  2162. filename.set(name);
  2163. }
  2164. bool remove()
  2165. {
  2166. MemoryBuffer sendBuffer;
  2167. initSendBuffer(sendBuffer);
  2168. MemoryBuffer replyBuffer;
  2169. sendBuffer.append((RemoteFileCommandType)RFCremove).append(filename);
  2170. sendRemoteCommand(sendBuffer, replyBuffer);
  2171. bool ok;
  2172. replyBuffer.read(ok);
  2173. return ok;
  2174. }
  2175. void rename(const char *newname)
  2176. {
  2177. // currently ignores directory on newname (in future versions newname will be required to be tail only and not full path)
  2178. StringBuffer path;
  2179. splitDirTail(filename,path);
  2180. StringBuffer newdir;
  2181. path.append(splitDirTail(newname,newdir));
  2182. if (newdir.length()&&(strcmp(newdir.str(),path.str())!=0))
  2183. WARNLOG("CRemoteFile::rename passed full path '%s' that may not to match original directory '%s'",newname,path.str());
  2184. MemoryBuffer sendBuffer;
  2185. initSendBuffer(sendBuffer);
  2186. MemoryBuffer replyBuffer;
  2187. sendBuffer.append((RemoteFileCommandType)RFCrename).append(filename).append(path);
  2188. sendRemoteCommand(sendBuffer, replyBuffer);
  2189. filename.set(path);
  2190. remotefilename.clear();
  2191. }
  2192. void move(const char *newname)
  2193. {
  2194. // like rename except between directories
  2195. // first create replote path
  2196. if (!newname||!*newname)
  2197. return;
  2198. RemoteFilename destrfn;
  2199. if (isPathSepChar(newname[0])&&isPathSepChar(newname[1])) {
  2200. destrfn.setRemotePath(newname);
  2201. if (!destrfn.queryEndpoint().ipequals(ep)) {
  2202. StringBuffer msg;
  2203. msg.appendf("IFile::move %s to %s, destination node must match source node", queryFilename(), newname);
  2204. throw createDafsException(RFSERR_MoveFailed,msg.str());
  2205. }
  2206. }
  2207. else
  2208. destrfn.setPath(ep,newname);
  2209. StringBuffer dest;
  2210. newname = destrfn.getLocalPath(dest).str();
  2211. MemoryBuffer sendBuffer;
  2212. initSendBuffer(sendBuffer);
  2213. MemoryBuffer replyBuffer;
  2214. StringBuffer path;
  2215. splitDirTail(filename,path);
  2216. StringBuffer newdir;
  2217. const char *newtail = splitDirTail(newname,newdir);
  2218. if (strcmp(newdir.str(),path.str())==0)
  2219. {
  2220. path.append(newtail);
  2221. newname = path;
  2222. sendBuffer.append((RemoteFileCommandType)RFCrename); // use rename if we can (supported on older dafilesrv)
  2223. }
  2224. else
  2225. sendBuffer.append((RemoteFileCommandType)RFCmove);
  2226. sendBuffer.append(filename).append(newname);
  2227. sendRemoteCommand(sendBuffer, replyBuffer);
  2228. filename.set(newname);
  2229. remotefilename.clear();
  2230. }
  2231. void setReadOnly(bool set)
  2232. {
  2233. MemoryBuffer sendBuffer;
  2234. initSendBuffer(sendBuffer);
  2235. MemoryBuffer replyBuffer;
  2236. sendBuffer.append((RemoteFileCommandType)RFCsetreadonly).append(filename).append(set);
  2237. sendRemoteCommand(sendBuffer, replyBuffer);
  2238. }
  2239. void setFilePermissions(unsigned fPerms)
  2240. {
  2241. MemoryBuffer sendBuffer;
  2242. initSendBuffer(sendBuffer);
  2243. MemoryBuffer replyBuffer;
  2244. sendBuffer.append((RemoteFileCommandType)RFCsetfileperms).append(filename).append(fPerms);
  2245. try
  2246. {
  2247. sendRemoteCommand(sendBuffer, replyBuffer);
  2248. }
  2249. catch (IDAFS_Exception *e)
  2250. {
  2251. if (e->errorCode() == RFSERR_InvalidCommand)
  2252. {
  2253. WARNLOG("umask setFilePermissions (0%o) not supported on remote server", fPerms);
  2254. e->Release();
  2255. }
  2256. else
  2257. throw;
  2258. }
  2259. }
  2260. offset_t size()
  2261. {
  2262. #if 1 // faster method (consistant with IFile)
  2263. // do this by using dir call (could be improved with new function but this not *too* bad)
  2264. if (isSpecialPath(filename))
  2265. return 0; // queries deemed to always exist (though don't know size).
  2266. // if needed to get size I guess could use IFileIO method and cache (bit of pain though)
  2267. StringBuffer dir;
  2268. const char *tail = splitDirTail(filename,dir);
  2269. if (!dir.length())
  2270. return false;
  2271. MemoryBuffer sendBuffer;
  2272. initSendBuffer(sendBuffer);
  2273. MemoryBuffer replyBuffer;
  2274. bool includedirs = true;
  2275. bool sub=false;
  2276. {
  2277. //Could be removed with new dafilesrv change [ (stream != 0) ], since this is not streaming.
  2278. Owned<CEndpointCS> crit = dirCSTable->getCrit(ep); // NB dirCSTable doesn't own, last reference will remove from table
  2279. CriticalBlock block(*crit);
  2280. sendBuffer.append((RemoteFileCommandType)RFCgetdir).append(dir).append(tail).append(includedirs).append(sub);
  2281. try
  2282. {
  2283. sendRemoteCommand(sendBuffer, replyBuffer);
  2284. }
  2285. catch (IDAFS_Exception * e)
  2286. {
  2287. if (e->errorCode() == RFSERR_GetDirFailed)
  2288. {
  2289. e->Release();
  2290. return (offset_t)-1;
  2291. }
  2292. else
  2293. throw e;
  2294. }
  2295. }
  2296. // now should be 0 or 1 files returned
  2297. Owned<CRemoteDirectoryIterator> iter = new CRemoteDirectoryIterator(ep, dir.str());
  2298. iter->appendBuf(replyBuffer);
  2299. if (!iter->first())
  2300. return (offset_t)-1;
  2301. return (offset_t) iter->getFileSize();
  2302. #else
  2303. IFileIO * io = open(IFOread);
  2304. offset_t length = (offset_t)-1;
  2305. if (io)
  2306. {
  2307. length = io->size();
  2308. io->Release();
  2309. }
  2310. return length;
  2311. #endif
  2312. }
  2313. bool createDirectory()
  2314. {
  2315. MemoryBuffer sendBuffer;
  2316. initSendBuffer(sendBuffer);
  2317. MemoryBuffer replyBuffer;
  2318. sendBuffer.append((RemoteFileCommandType)RFCcreatedir).append(filename);
  2319. sendRemoteCommand(sendBuffer, replyBuffer);
  2320. bool ok;
  2321. replyBuffer.read(ok);
  2322. return ok;
  2323. }
  2324. virtual IDirectoryIterator *directoryFiles(const char *mask,bool sub,bool includedirs)
  2325. {
  2326. if (mask&&!*mask)
  2327. return createDirectoryIterator("",""); // NULL iterator
  2328. CRemoteDirectoryIterator *ret = new CRemoteDirectoryIterator(ep, filename);
  2329. byte stream = (sub || !mask || containsFileWildcard(mask)) ? 1 : 0; // no point in streaming if mask without wildcards or sub, as will only be <= 1 match.
  2330. Owned<CEndpointCS> crit = dirCSTable->getCrit(ep); // NB dirCSTable doesn't own, last reference will remove from table
  2331. CriticalBlock block(*crit);
  2332. for (;;)
  2333. {
  2334. MemoryBuffer sendBuffer;
  2335. initSendBuffer(sendBuffer);
  2336. MemoryBuffer replyBuffer;
  2337. sendBuffer.append((RemoteFileCommandType)RFCgetdir).append(filename).append(mask?mask:"").append(includedirs).append(sub).append(stream);
  2338. sendRemoteCommand(sendBuffer, replyBuffer);
  2339. if (ret->appendBuf(replyBuffer))
  2340. break;
  2341. stream = 2; // NB: will never get here if streaming was off (if stream==0 above)
  2342. }
  2343. return ret;
  2344. }
  2345. IDirectoryDifferenceIterator *monitorDirectory(
  2346. IDirectoryIterator *prev=NULL, // in (NULL means use current as baseline)
  2347. const char *mask=NULL,
  2348. bool sub=false,
  2349. bool includedirs=false,
  2350. unsigned checkinterval=60*1000,
  2351. unsigned timeout=(unsigned)-1,
  2352. Semaphore *abortsem=NULL) // returns NULL if timed out
  2353. {
  2354. // abortsem not yet supported
  2355. MemoryBuffer sendBuffer;
  2356. initSendBuffer(sendBuffer);
  2357. MemoryBuffer replyBuffer;
  2358. sendBuffer.append((RemoteFileCommandType)RFCmonitordir).append(filename).append(mask?mask:"").append(includedirs).append(sub);
  2359. sendBuffer.append(checkinterval).append(timeout);
  2360. __int64 cancelid=0; // not yet used
  2361. sendBuffer.append(cancelid);
  2362. byte isprev=(prev!=NULL)?1:0;
  2363. sendBuffer.append(isprev);
  2364. if (prev)
  2365. CRemoteDirectoryIterator::serialize(sendBuffer,prev,0,true);
  2366. sendRemoteCommand(sendBuffer, replyBuffer);
  2367. byte status;
  2368. replyBuffer.read(status);
  2369. if (status==1)
  2370. {
  2371. CRemoteDirectoryIterator *iter = new CRemoteDirectoryIterator(ep, filename);
  2372. iter->appendBuf(replyBuffer);
  2373. return iter;
  2374. }
  2375. return NULL;
  2376. }
  2377. bool getInfo(bool &isdir,offset_t &size,CDateTime &modtime)
  2378. {
  2379. // do this by using dir call (could be improved with new function but this not *too* bad)
  2380. StringBuffer dir;
  2381. const char *tail = splitDirTail(filename,dir);
  2382. if (!dir.length())
  2383. return false;
  2384. MemoryBuffer sendBuffer;
  2385. initSendBuffer(sendBuffer);
  2386. MemoryBuffer replyBuffer;
  2387. bool includedirs = true;
  2388. bool sub=false;
  2389. {
  2390. //Could be removed with new dafilesrv change [ (stream != 0) ], since this is not streaming.
  2391. Owned<CEndpointCS> crit = dirCSTable->getCrit(ep); // NB dirCSTable doesn't own, last reference will remove from table
  2392. CriticalBlock block(*crit);
  2393. sendBuffer.append((RemoteFileCommandType)RFCgetdir).append(dir).append(tail).append(includedirs).append(sub);
  2394. sendRemoteCommand(sendBuffer, replyBuffer);
  2395. }
  2396. // now should be 0 or 1 files returned
  2397. Owned<CRemoteDirectoryIterator> iter = new CRemoteDirectoryIterator(ep, dir.str());
  2398. iter->appendBuf(replyBuffer);
  2399. if (!iter->first())
  2400. return false;
  2401. isdir = iter->isDir();
  2402. size = (offset_t) iter->getFileSize();
  2403. iter->getModifiedTime(modtime);
  2404. return true;
  2405. }
  2406. bool setCompression(bool set)
  2407. {
  2408. assertex(!"Need to implement compress()");
  2409. return false;
  2410. }
  2411. offset_t compressedSize()
  2412. {
  2413. assertex(!"Need to implement actualSize()");
  2414. return (offset_t)-1;
  2415. }
  2416. void serialize(MemoryBuffer &tgt)
  2417. {
  2418. throwUnexpected();
  2419. }
  2420. void deserialize(MemoryBuffer &src)
  2421. {
  2422. throwUnexpected();
  2423. }
  2424. unsigned getCRC()
  2425. {
  2426. MemoryBuffer sendBuffer;
  2427. initSendBuffer(sendBuffer);
  2428. MemoryBuffer replyBuffer;
  2429. sendBuffer.append((RemoteFileCommandType)RFCgetcrc).append(filename);
  2430. sendRemoteCommand(sendBuffer, replyBuffer, true, true);
  2431. unsigned crc;
  2432. replyBuffer.read(crc);
  2433. return crc;
  2434. }
  2435. void setCreateFlags(unsigned short cflags)
  2436. {
  2437. flags &= 0xffff;
  2438. flags |= ((unsigned)cflags<<16);
  2439. }
  2440. unsigned short getCreateFlags()
  2441. {
  2442. return (unsigned short)(flags>>16);
  2443. }
  2444. void setShareMode(IFSHmode shmode)
  2445. {
  2446. flags &= ~(IFSHfull|IFSHread);
  2447. flags |= (unsigned)(shmode&(IFSHfull|IFSHread));
  2448. isShareSet = true;
  2449. }
  2450. unsigned short getShareMode()
  2451. {
  2452. return (unsigned short)(flags&0xffff);
  2453. }
  2454. bool getIsShareSet()
  2455. {
  2456. return isShareSet;
  2457. }
  2458. void remoteExtractBlobElements(const char * prefix, ExtractedBlobArray & extracted)
  2459. {
  2460. MemoryBuffer sendBuffer;
  2461. initSendBuffer(sendBuffer);
  2462. sendBuffer.append((RemoteFileCommandType)RFCextractblobelements).append(prefix).append(filename);
  2463. MemoryBuffer replyBuffer;
  2464. sendRemoteCommand(sendBuffer, replyBuffer, true, true); // handles error code
  2465. unsigned n;
  2466. replyBuffer.read(n);
  2467. for (unsigned i=0;i<n;i++) {
  2468. ExtractedBlobInfo *item = new ExtractedBlobInfo;
  2469. item->deserialize(replyBuffer);
  2470. extracted.append(*item);
  2471. }
  2472. }
  2473. bool copySectionAsync(const char *uuid,const RemoteFilename &dest, offset_t toOfs, offset_t fromOfs, offset_t size, ICopyFileProgress *progress, unsigned timeout)
  2474. {
  2475. // now if we get here is it can be assumed the source file is local to where we send the command
  2476. StringBuffer tos;
  2477. dest.getRemotePath(tos);
  2478. MemoryBuffer sendBuffer;
  2479. initSendBuffer(sendBuffer);
  2480. MemoryBuffer replyBuffer;
  2481. sendBuffer.append((RemoteFileCommandType)RFCcopysection).append(uuid).append(queryLocalName()).append(tos).append(toOfs).append(fromOfs).append(size).append(timeout);
  2482. sendRemoteCommand(sendBuffer, replyBuffer);
  2483. unsigned status;
  2484. replyBuffer.read(status);
  2485. if (progress)
  2486. {
  2487. offset_t sizeDone;
  2488. offset_t totalSize;
  2489. replyBuffer.read(sizeDone).read(totalSize);
  2490. progress->onProgress(sizeDone,totalSize);
  2491. }
  2492. return (AsyncCommandStatus)status!=ACScontinue; // should only otherwise be done as errors raised by exception
  2493. }
  2494. void copySection(const RemoteFilename &dest, offset_t toOfs, offset_t fromOfs, offset_t size, ICopyFileProgress *progress, CFflags copyFlags=CFnone)
  2495. {
  2496. StringBuffer uuid;
  2497. genUUID(uuid,true);
  2498. unsigned timeout = 60*1000; // check every minute
  2499. while(!copySectionAsync(uuid.str(),dest,toOfs,fromOfs,size,progress,timeout));
  2500. }
  2501. void copyTo(IFile *dest, size32_t buffersize, ICopyFileProgress *progress, bool usetmp, CFflags copyFlags=CFnone);
  2502. virtual IMemoryMappedFile *openMemoryMapped(offset_t ofs, memsize_t len, bool write)
  2503. {
  2504. return NULL;
  2505. }
  2506. };
  2507. void clientAddSocketToCache(SocketEndpoint &ep,ISocket *socket)
  2508. {
  2509. CriticalBlock block(CConnectionTable::crit);
  2510. if (ConnectionTable)
  2511. ConnectionTable->addLink(ep,socket);
  2512. }
  2513. IFile * createRemoteFile(SocketEndpoint &ep, const char * filename)
  2514. {
  2515. IFile *ret = createFileLocalMount(ep,filename);
  2516. if (ret)
  2517. return ret;
  2518. return new CRemoteFile(ep, filename);
  2519. }
  2520. void clientDisconnectRemoteFile(IFile *file)
  2521. {
  2522. CRemoteFile *cfile = QUERYINTERFACE(file,CRemoteFile);
  2523. if (cfile)
  2524. cfile->disconnect();
  2525. }
  2526. bool clientResetFilename(IFile *file, const char *newname) // returns false if not remote
  2527. {
  2528. CRemoteFile *cfile = QUERYINTERFACE(file,CRemoteFile);
  2529. if (!cfile)
  2530. return false;
  2531. cfile->resetLocalFilename(newname);
  2532. return true;
  2533. }
  2534. extern bool clientAsyncCopyFileSection(const char *uuid,
  2535. IFile *from, // expected to be remote
  2536. RemoteFilename &to,
  2537. offset_t toOfs, // -1 created file and copies to start
  2538. offset_t fromOfs,
  2539. offset_t size,
  2540. ICopyFileProgress *progress,
  2541. unsigned timeout) // returns true when done
  2542. {
  2543. CRemoteFile *cfile = QUERYINTERFACE(from,CRemoteFile);
  2544. if (!cfile) {
  2545. // local - do sync
  2546. from->copySection(to,toOfs,fromOfs,size,progress);
  2547. return true;
  2548. }
  2549. return cfile->copySectionAsync(uuid,to,toOfs,fromOfs, size, progress, timeout);
  2550. }
  2551. //---------------------------------------------------------------------------
  2552. class CRemoteFileIO : implements IFileIO, public CInterface
  2553. {
  2554. protected:
  2555. Linked<CRemoteFile> parent;
  2556. RemoteFileIOHandle handle;
  2557. std::atomic<cycle_t> ioReadCycles;
  2558. std::atomic<cycle_t> ioWriteCycles;
  2559. std::atomic<__uint64> ioReadBytes;
  2560. std::atomic<__uint64> ioWriteBytes;
  2561. std::atomic<__uint64> ioReads;
  2562. std::atomic<__uint64> ioWrites;
  2563. std::atomic<unsigned> ioRetries;
  2564. IFOmode mode;
  2565. compatIFSHmode compatmode;
  2566. IFEflags extraFlags;
  2567. bool disconnectonexit;
  2568. public:
  2569. IMPLEMENT_IINTERFACE
  2570. CRemoteFileIO(CRemoteFile *_parent)
  2571. : parent(_parent), ioReadCycles(0), ioWriteCycles(0), ioReadBytes(0), ioWriteBytes(0), ioReads(0), ioWrites(0), ioRetries(0)
  2572. {
  2573. handle = 0;
  2574. disconnectonexit = false;
  2575. }
  2576. ~CRemoteFileIO()
  2577. {
  2578. if (handle) {
  2579. try {
  2580. close();
  2581. }
  2582. catch (IException *e) {
  2583. StringBuffer s;
  2584. e->errorMessage(s);
  2585. WARNLOG("CRemoteFileIO close file: %s",s.str());
  2586. e->Release();
  2587. }
  2588. }
  2589. if (disconnectonexit)
  2590. parent->disconnect();
  2591. }
  2592. void close()
  2593. {
  2594. if (handle)
  2595. {
  2596. try
  2597. {
  2598. MemoryBuffer sendBuffer;
  2599. initSendBuffer(sendBuffer);
  2600. sendBuffer.append((RemoteFileCommandType)RFCcloseIO).append(handle);
  2601. parent->sendRemoteCommand(sendBuffer,false);
  2602. }
  2603. catch (IDAFS_Exception *e)
  2604. {
  2605. if ((e->errorCode()!=RFSERR_InvalidFileIOHandle)&&(e->errorCode()!=RFSERR_NullFileIOHandle))
  2606. throw;
  2607. e->Release();
  2608. }
  2609. handle = 0;
  2610. }
  2611. }
  2612. RemoteFileIOHandle getHandle() const { return handle; }
  2613. bool open(IFOmode _mode,compatIFSHmode _compatmode,IFEflags _extraFlags=IFEnone)
  2614. {
  2615. MemoryBuffer sendBuffer;
  2616. initSendBuffer(sendBuffer);
  2617. MemoryBuffer replyBuffer;
  2618. const char *localname = parent->queryLocalName();
  2619. localname = skipSpecialPath(localname);
  2620. // also send _extraFlags
  2621. // then also send sMode, cFlags
  2622. unsigned short sMode = parent->getShareMode();
  2623. unsigned short cFlags = parent->getCreateFlags();
  2624. if (!(parent->getIsShareSet()))
  2625. {
  2626. switch ((compatIFSHmode)_compatmode)
  2627. {
  2628. case compatIFSHnone:
  2629. sMode = IFSHnone;
  2630. break;
  2631. case compatIFSHread:
  2632. sMode = IFSHread;
  2633. break;
  2634. case compatIFSHwrite:
  2635. sMode = IFSHfull;
  2636. break;
  2637. case compatIFSHall:
  2638. sMode = IFSHfull;
  2639. break;
  2640. }
  2641. }
  2642. sendBuffer.append((RemoteFileCommandType)RFCopenIO).append(localname).append((byte)_mode).append((byte)_compatmode).append((byte)_extraFlags).append(sMode).append(cFlags);
  2643. parent->sendRemoteCommand(sendBuffer, replyBuffer);
  2644. replyBuffer.read(handle);
  2645. if (!handle)
  2646. return false;
  2647. switch (_mode) {
  2648. case IFOcreate:
  2649. mode = IFOwrite;
  2650. break;
  2651. case IFOcreaterw:
  2652. mode = IFOreadwrite;
  2653. break;
  2654. default:
  2655. mode = _mode;
  2656. break;
  2657. }
  2658. compatmode = _compatmode;
  2659. extraFlags = _extraFlags;
  2660. return true;
  2661. }
  2662. bool reopen()
  2663. {
  2664. StringBuffer s;
  2665. PROGLOG("Attempting reopen of %s on %s",parent->queryLocalName(),parent->queryEp().getUrlStr(s).str());
  2666. if (open(mode,compatmode,extraFlags))
  2667. return true;
  2668. return false;
  2669. }
  2670. offset_t size()
  2671. {
  2672. MemoryBuffer sendBuffer;
  2673. initSendBuffer(sendBuffer);
  2674. MemoryBuffer replyBuffer;
  2675. sendBuffer.append((RemoteFileCommandType)RFCsize).append(handle);
  2676. parent->sendRemoteCommand(sendBuffer, replyBuffer, false);
  2677. // Retry using reopen TBD
  2678. offset_t ret;
  2679. replyBuffer.read(ret);
  2680. return ret;
  2681. }
  2682. virtual unsigned __int64 getStatistic(StatisticKind kind)
  2683. {
  2684. switch (kind)
  2685. {
  2686. case StCycleDiskReadIOCycles:
  2687. return ioReadCycles.load(std::memory_order_relaxed);
  2688. case StCycleDiskWriteIOCycles:
  2689. return ioWriteCycles.load(std::memory_order_relaxed);
  2690. case StTimeDiskReadIO:
  2691. return cycle_to_nanosec(ioReadCycles.load(std::memory_order_relaxed));
  2692. case StTimeDiskWriteIO:
  2693. return cycle_to_nanosec(ioWriteCycles.load(std::memory_order_relaxed));
  2694. case StSizeDiskRead:
  2695. return ioReadBytes.load(std::memory_order_relaxed);
  2696. case StSizeDiskWrite:
  2697. return ioWriteBytes.load(std::memory_order_relaxed);
  2698. case StNumDiskReads:
  2699. return ioReads.load(std::memory_order_relaxed);
  2700. case StNumDiskWrites:
  2701. return ioWrites.load(std::memory_order_relaxed);
  2702. case StNumDiskRetries:
  2703. return ioRetries.load(std::memory_order_relaxed);
  2704. }
  2705. return 0;
  2706. }
  2707. size32_t read(offset_t pos, size32_t len, void * data)
  2708. {
  2709. size32_t got;
  2710. MemoryBuffer replyBuffer;
  2711. CCycleTimer timer;
  2712. const void *b;
  2713. try
  2714. {
  2715. b = doRead(pos,len,replyBuffer,got,data);
  2716. }
  2717. catch (...)
  2718. {
  2719. ioReadCycles.fetch_add(timer.elapsedCycles());
  2720. throw;
  2721. }
  2722. ioReadCycles.fetch_add(timer.elapsedCycles());
  2723. ioReadBytes.fetch_add(got);
  2724. ++ioReads;
  2725. if (b!=data)
  2726. memcpy(data,b,got);
  2727. return got;
  2728. }
  2729. virtual void flush()
  2730. {
  2731. }
  2732. const void *doRead(offset_t pos, size32_t len, MemoryBuffer &replyBuffer, size32_t &got, void *dstbuf)
  2733. {
  2734. unsigned tries=0;
  2735. for (;;)
  2736. {
  2737. try
  2738. {
  2739. MemoryBuffer sendBuffer;
  2740. initSendBuffer(sendBuffer);
  2741. replyBuffer.clear();
  2742. sendBuffer.append((RemoteFileCommandType)RFCread).append(handle).append(pos).append(len);
  2743. parent->sendRemoteCommand(sendBuffer, replyBuffer,false);
  2744. // kludge dafilesrv versions <= 1.5e don't return error correctly
  2745. if (replyBuffer.length()>len+sizeof(size32_t)+sizeof(unsigned))
  2746. {
  2747. size32_t save = replyBuffer.getPos();
  2748. replyBuffer.reset(len+sizeof(size32_t)+sizeof(unsigned));
  2749. unsigned errCode;
  2750. replyBuffer.read(errCode);
  2751. if (errCode)
  2752. {
  2753. StringBuffer msg;
  2754. parent->ep.getUrlStr(msg.append('[')).append("] ");
  2755. if (replyBuffer.getPos()<replyBuffer.length())
  2756. {
  2757. StringAttr s;
  2758. replyBuffer.read(s);
  2759. msg.append(s);
  2760. }
  2761. else
  2762. msg.append("ERROR #").append(errCode);
  2763. throw createDafsException(errCode, msg.str());
  2764. }
  2765. else
  2766. replyBuffer.reset(save);
  2767. }
  2768. replyBuffer.read(got);
  2769. if ((got>replyBuffer.remaining())||(got>len))
  2770. {
  2771. PROGLOG("Read beyond buffer %d,%d,%d",got,replyBuffer.remaining(),len);
  2772. throw createDafsException(RFSERR_ReadFailed, "Read beyond buffer");
  2773. }
  2774. return replyBuffer.readDirect(got);
  2775. }
  2776. catch (IJSOCK_Exception *e)
  2777. {
  2778. EXCLOG(e,"CRemoteFileIO::read");
  2779. if (++tries > 3)
  2780. {
  2781. ioRetries.fetch_add(tries);
  2782. throw;
  2783. }
  2784. WARNLOG("Retrying read of %s (%d)",parent->queryLocalName(),tries);
  2785. Owned<IException> exc = e;
  2786. if (!reopen())
  2787. {
  2788. ioRetries.fetch_add(tries);
  2789. throw exc.getClear();
  2790. }
  2791. }
  2792. }
  2793. if (tries)
  2794. ioRetries.fetch_add(tries);
  2795. got = 0;
  2796. return NULL;
  2797. }
  2798. size32_t write(offset_t pos, size32_t len, const void * data)
  2799. {
  2800. unsigned tries=0;
  2801. size32_t ret = 0;
  2802. CCycleTimer timer;
  2803. for (;;)
  2804. {
  2805. try
  2806. {
  2807. MemoryBuffer replyBuffer;
  2808. MemoryBuffer sendBuffer;
  2809. initSendBuffer(sendBuffer);
  2810. sendBuffer.append((RemoteFileCommandType)RFCwrite).append(handle).append(pos).append(len).append(len, data);
  2811. parent->sendRemoteCommand(sendBuffer, replyBuffer, false, true);
  2812. replyBuffer.read(ret);
  2813. break;
  2814. }
  2815. catch (IJSOCK_Exception *e)
  2816. {
  2817. EXCLOG(e,"CRemoteFileIO::write");
  2818. if (++tries > 3)
  2819. {
  2820. ioRetries.fetch_add(tries);
  2821. ioWriteCycles.fetch_add(timer.elapsedCycles());
  2822. throw;
  2823. }
  2824. WARNLOG("Retrying write(%" I64F "d,%d) of %s (%d)",pos,len,parent->queryLocalName(),tries);
  2825. Owned<IException> exc = e;
  2826. if (!reopen())
  2827. {
  2828. ioRetries.fetch_add(tries);
  2829. ioWriteCycles.fetch_add(timer.elapsedCycles());
  2830. throw exc.getClear();
  2831. }
  2832. }
  2833. }
  2834. if (tries)
  2835. ioRetries.fetch_add(tries);
  2836. ioWriteCycles.fetch_add(timer.elapsedCycles());
  2837. ioWriteBytes.fetch_add(ret);
  2838. ++ioWrites;
  2839. if ((ret==(size32_t)-1) || (ret < len))
  2840. throw createDafsException(DISK_FULL_EXCEPTION_CODE,"write failed, disk full?");
  2841. return ret;
  2842. }
  2843. offset_t appendFile(IFile *file,offset_t pos,offset_t len)
  2844. {
  2845. MemoryBuffer sendBuffer;
  2846. initSendBuffer(sendBuffer);
  2847. MemoryBuffer replyBuffer;
  2848. const char * fname = file->queryFilename();
  2849. sendBuffer.append((RemoteFileCommandType)RFCappend).append(handle).append(fname).append(pos).append(len);
  2850. parent->sendRemoteCommand(sendBuffer, replyBuffer, false, true); // retry not safe
  2851. offset_t ret;
  2852. replyBuffer.read(ret);
  2853. if ((ret==(offset_t)-1) || ((len != ((offset_t)-1)) && (ret < len)))
  2854. throw createDafsException(DISK_FULL_EXCEPTION_CODE,"append failed, disk full?"); // though could be file missing TBD
  2855. return ret;
  2856. }
  2857. void setSize(offset_t size)
  2858. {
  2859. MemoryBuffer sendBuffer;
  2860. initSendBuffer(sendBuffer);
  2861. MemoryBuffer replyBuffer;
  2862. sendBuffer.append((RemoteFileCommandType)RFCsetsize).append(handle).append(size);
  2863. parent->sendRemoteCommand(sendBuffer, replyBuffer, false, true);
  2864. // retry using reopen TBD
  2865. }
  2866. void setDisconnectOnExit(bool set) { disconnectonexit = set; }
  2867. void sendRemoteCommand(MemoryBuffer & sendBuffer, MemoryBuffer & replyBuffer, bool retry=true, bool lengthy=false, bool handleErrCode=true)
  2868. {
  2869. parent->sendRemoteCommand(sendBuffer, replyBuffer, retry, lengthy, handleErrCode);
  2870. }
  2871. };
  2872. void clientDisconnectRemoteIoOnExit(IFileIO *fileio,bool set)
  2873. {
  2874. CRemoteFileIO *cfileio = QUERYINTERFACE(fileio,CRemoteFileIO);
  2875. if (cfileio)
  2876. cfileio->setDisconnectOnExit(set);
  2877. }
  2878. IFileIO * CRemoteFile::openShared(IFOmode mode,IFSHmode shmode,IFEflags extraFlags)
  2879. {
  2880. // 0x0, 0x8, 0x10 and 0x20 are only share modes supported in this assert
  2881. // currently only 0x0 (IFSHnone), 0x8 (IFSHread) and 0x10 (IFSHfull) are used so this could be 0xffffffe7
  2882. // note: IFSHfull also includes read sharing (ie write|read)
  2883. assertex(((unsigned)shmode&0xffffffc7)==0);
  2884. compatIFSHmode compatmode;
  2885. unsigned fileflags = (flags>>16) & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
  2886. if (fileflags&S_IXUSR) // this is bit hit and miss but backward compatible
  2887. compatmode = compatIFSHexec;
  2888. else if (fileflags&(S_IWGRP|S_IWOTH))
  2889. compatmode = compatIFSHall;
  2890. else if (shmode&IFSHfull)
  2891. compatmode = compatIFSHwrite;
  2892. else if (((shmode&(IFSHread|IFSHfull))==0) && ((fileflags&(S_IRGRP|S_IROTH))==0))
  2893. compatmode = compatIFSHnone;
  2894. else
  2895. compatmode = compatIFSHread;
  2896. Owned<CRemoteFileIO> res = new CRemoteFileIO(this);
  2897. if (res->open(mode,compatmode,extraFlags))
  2898. return res.getClear();
  2899. return NULL;
  2900. }
  2901. IFileIO * CRemoteFile::open(IFOmode mode,IFEflags extraFlags)
  2902. {
  2903. return openShared(mode,(IFSHmode)(flags&(IFSHread|IFSHfull)),extraFlags);
  2904. }
  2905. //---------------------------------------------------------------------------
  2906. void CRemoteFile::copyTo(IFile *dest, size32_t buffersize, ICopyFileProgress *progress, bool usetmp, CFflags copyFlags)
  2907. {
  2908. CRemoteFile *dstfile = QUERYINTERFACE(dest,CRemoteFile);
  2909. if (dstfile&&!dstfile->queryEp().isLocal()) {
  2910. StringBuffer tmpname;
  2911. Owned<IFile> destf;
  2912. RemoteFilename dest;
  2913. if (usetmp) {
  2914. makeTempCopyName(tmpname,dstfile->queryLocalName());
  2915. dest.setPath(dstfile->queryEp(),tmpname.str());
  2916. }
  2917. else
  2918. dest.setPath(dstfile->queryEp(),dstfile->queryLocalName());
  2919. destf.setown(createIFile(dest));
  2920. try {
  2921. // following may fail if new dafilesrv not deployed on src
  2922. copySection(dest,(offset_t)-1,0,(offset_t)-1,progress,copyFlags);
  2923. if (usetmp) {
  2924. StringAttr tail(pathTail(dstfile->queryLocalName()));
  2925. dstfile->remove();
  2926. destf->rename(tail);
  2927. }
  2928. return;
  2929. }
  2930. catch (IException *e)
  2931. {
  2932. StringBuffer s;
  2933. s.appendf("Remote File Copy (%d): ",e->errorCode());
  2934. e->errorMessage(s);
  2935. s.append(", retrying local");
  2936. WARNLOG("%s",s.str());
  2937. e->Release();
  2938. }
  2939. // delete dest
  2940. try {
  2941. destf->remove();
  2942. }
  2943. catch (IException *e)
  2944. {
  2945. EXCLOG(e,"Remote File Copy, Deleting temporary file");
  2946. e->Release();
  2947. }
  2948. }
  2949. // assumption if we get here that source remote, dest local (or equiv)
  2950. class cIntercept: implements ICopyFileIntercept
  2951. {
  2952. MemoryAttr ma;
  2953. MemoryBuffer mb;
  2954. virtual offset_t copy(IFileIO *from, IFileIO *to, offset_t ofs, size32_t sz)
  2955. {
  2956. if (ma.length()<sz)
  2957. ma.allocate(sz); // may be not used
  2958. void *buf = ma.bufferBase();
  2959. size32_t got;
  2960. CRemoteFileIO *srcio = QUERYINTERFACE(from,CRemoteFileIO);
  2961. const void *dst;
  2962. if (srcio)
  2963. dst = srcio->doRead(ofs,sz,mb.clear(),got,buf);
  2964. else {
  2965. // shouldn't ever get here if source remote
  2966. got = from->read(ofs, sz, buf);
  2967. dst = buf;
  2968. }
  2969. if (got != 0)
  2970. to->write(ofs, got, dst);
  2971. return got;
  2972. }
  2973. } intercept;
  2974. doCopyFile(dest,this,buffersize,progress,&intercept,usetmp,copyFlags);
  2975. }
  2976. /////////////////////////
  2977. ISocket *checkSocketSecure(ISocket *socket)
  2978. {
  2979. if (securitySettings.connectMethod == SSLNone)
  2980. return LINK(socket);
  2981. char pname[256];
  2982. pname[0] = 0;
  2983. int pport = socket->peer_name(pname, sizeof(pname)-1);
  2984. if ( (pport == securitySettings.daFileSrvSSLPort) && (!socket->isSecure()) )
  2985. {
  2986. #ifdef _USE_OPENSSL
  2987. Owned<ISecureSocket> ssock;
  2988. try
  2989. {
  2990. ssock.setown(createSecureSocket(LINK(socket), ClientSocket));
  2991. int status = ssock->secure_connect();
  2992. if (status < 0)
  2993. throw createDafsException(DAFSERR_connection_failed, "Failure to establish secure connection");
  2994. return ssock.getClear();
  2995. }
  2996. catch (IException *e)
  2997. {
  2998. cleanupSocket(ssock);
  2999. ssock.clear();
  3000. cleanupSocket(socket);
  3001. StringBuffer eMsg;
  3002. e->errorMessage(eMsg);
  3003. e->Release();
  3004. throw createDafsException(DAFSERR_connection_failed, eMsg.str());
  3005. }
  3006. #else
  3007. throw createDafsException(DAFSERR_connection_failed,"Failure to establish secure connection: OpenSSL disabled in build");
  3008. #endif
  3009. }
  3010. return LINK(socket);
  3011. }
  3012. ISocket *connectDafs(SocketEndpoint &ep, unsigned timeoutms)
  3013. {
  3014. Owned<ISocket> socket;
  3015. if ( (securitySettings.connectMethod == SSLNone) || (securitySettings.connectMethod == SSLOnly) )
  3016. {
  3017. socket.setown(ISocket::connect_timeout(ep, timeoutms));
  3018. return checkSocketSecure(socket);
  3019. }
  3020. // SSLFirst or UnsecureFirst ...
  3021. unsigned newtimeout = timeoutms;
  3022. if (newtimeout > 5000)
  3023. newtimeout = 5000;
  3024. int conAttempts = 2;
  3025. while (conAttempts > 0)
  3026. {
  3027. conAttempts--;
  3028. bool connected = false;
  3029. try
  3030. {
  3031. socket.setown(ISocket::connect_timeout(ep, newtimeout));
  3032. connected = true;
  3033. newtimeout = timeoutms;
  3034. }
  3035. catch (IJSOCK_Exception *e)
  3036. {
  3037. if (e->errorCode() == JSOCKERR_connection_failed)
  3038. {
  3039. e->Release();
  3040. if (ep.port == securitySettings.daFileSrvSSLPort)
  3041. ep.port = securitySettings.daFileSrvPort;
  3042. else
  3043. ep.port = securitySettings.daFileSrvSSLPort;
  3044. if (!conAttempts)
  3045. throw;
  3046. }
  3047. else
  3048. throw;
  3049. }
  3050. if (connected)
  3051. {
  3052. if (ep.port == securitySettings.daFileSrvSSLPort)
  3053. {
  3054. try
  3055. {
  3056. return checkSocketSecure(socket);
  3057. }
  3058. catch (IDAFS_Exception *e)
  3059. {
  3060. connected = false;
  3061. if (e->errorCode() == DAFSERR_connection_failed)
  3062. {
  3063. // worth logging to help identify any ssl config issues ...
  3064. StringBuffer errmsg;
  3065. e->errorMessage(errmsg);
  3066. WARNLOG("%s", errmsg.str());
  3067. e->Release();
  3068. ep.port = securitySettings.daFileSrvPort;
  3069. if (!conAttempts)
  3070. throw;
  3071. }
  3072. else
  3073. throw;
  3074. }
  3075. }
  3076. else
  3077. return socket.getClear();
  3078. }
  3079. }
  3080. throw createDafsException(DAFSERR_connection_failed, "Failed to establish connection with DaFileSrv");
  3081. }
  3082. unsigned getRemoteVersion(CRemoteFileIO &remoteFileIO, StringBuffer &ver)
  3083. {
  3084. unsigned ret;
  3085. MemoryBuffer sendBuffer;
  3086. initSendBuffer(sendBuffer);
  3087. sendBuffer.append((RemoteFileCommandType)RFCgetver);
  3088. sendBuffer.append((unsigned)RFCgetver);
  3089. MemoryBuffer replyBuffer;
  3090. try
  3091. {
  3092. remoteFileIO.sendRemoteCommand(sendBuffer, replyBuffer, true, false, false);
  3093. }
  3094. catch (IException *e)
  3095. {
  3096. EXCLOG(e);
  3097. ::Release(e);
  3098. return 0;
  3099. }
  3100. unsigned errCode;
  3101. replyBuffer.read(errCode);
  3102. if (errCode==RFSERR_InvalidCommand)
  3103. {
  3104. ver.append("DS V1.0");
  3105. return 10;
  3106. }
  3107. else if (errCode==0)
  3108. ret = 11;
  3109. else if (errCode<0x10000)
  3110. return 0;
  3111. else
  3112. ret = errCode-0x10000;
  3113. StringAttr vers;
  3114. replyBuffer.read(vers);
  3115. ver.append(vers);
  3116. return ret;
  3117. }
  3118. unsigned getRemoteVersion(ISocket *origSock, StringBuffer &ver)
  3119. {
  3120. // used to have a global critical section here
  3121. if (!origSock)
  3122. return 0;
  3123. Owned<ISocket> socket = checkSocketSecure(origSock);
  3124. unsigned ret;
  3125. MemoryBuffer sendbuf;
  3126. initSendBuffer(sendbuf);
  3127. sendbuf.append((RemoteFileCommandType)RFCgetver);
  3128. sendbuf.append((unsigned)RFCgetver);
  3129. MemoryBuffer reply;
  3130. try
  3131. {
  3132. sendBuffer(socket, sendbuf);
  3133. receiveBuffer(socket, reply, 1 ,4096);
  3134. unsigned errCode;
  3135. reply.read(errCode);
  3136. if (errCode==RFSERR_InvalidCommand)
  3137. {
  3138. ver.append("DS V1.0");
  3139. return 10;
  3140. }
  3141. else if (errCode==0)
  3142. ret = 11;
  3143. else if (errCode<0x10000)
  3144. return 0;
  3145. else
  3146. ret = errCode-0x10000;
  3147. }
  3148. catch (IException *e)
  3149. {
  3150. EXCLOG(e);
  3151. ::Release(e);
  3152. return 0;
  3153. }
  3154. StringAttr vers;
  3155. reply.read(vers);
  3156. ver.append(vers);
  3157. return ret;
  3158. }
  3159. /////////////////////////
  3160. //////////////
  3161. extern unsigned stopRemoteServer(ISocket * socket)
  3162. {
  3163. // used to have a global critical section here
  3164. if (!socket)
  3165. return 0;
  3166. MemoryBuffer sendbuf;
  3167. initSendBuffer(sendbuf);
  3168. sendbuf.append((RemoteFileCommandType)RFCstop);
  3169. sendbuf.append((unsigned)RFCstop);
  3170. MemoryBuffer replybuf;
  3171. unsigned errCode = RFSERR_InvalidCommand;
  3172. try
  3173. {
  3174. sendBuffer(socket, sendbuf);
  3175. receiveBuffer(socket, replybuf, NORMAL_RETRIES, 1024);
  3176. replybuf.read(errCode);
  3177. }
  3178. catch (IJSOCK_Exception *e)
  3179. {
  3180. if ((e->errorCode()!=JSOCKERR_broken_pipe)&&(e->errorCode()!=JSOCKERR_graceful_close))
  3181. EXCLOG(e);
  3182. else
  3183. errCode = 0;
  3184. }
  3185. catch (IException *e)
  3186. {
  3187. EXCLOG(e);
  3188. ::Release(e);
  3189. }
  3190. return errCode;
  3191. }
  3192. int setDafsTrace(ISocket * socket,byte flags)
  3193. {
  3194. if (!socket)
  3195. {
  3196. byte ret = traceFlags;
  3197. traceFlags = flags;
  3198. return ret;
  3199. }
  3200. MemoryBuffer sendbuf;
  3201. initSendBuffer(sendbuf);
  3202. sendbuf.append((RemoteFileCommandType)RFCsettrace).append(flags);
  3203. MemoryBuffer replybuf;
  3204. try
  3205. {
  3206. sendBuffer(socket, sendbuf);
  3207. receiveBuffer(socket, replybuf, NORMAL_RETRIES, 1024);
  3208. int retcode;
  3209. replybuf.read(retcode);
  3210. return retcode;
  3211. }
  3212. catch (IException *e)
  3213. {
  3214. EXCLOG(e);
  3215. ::Release(e);
  3216. }
  3217. return -1;
  3218. }
  3219. int setDafsThrottleLimit(ISocket * socket, ThrottleClass throttleClass, unsigned throttleLimit, unsigned throttleDelayMs, unsigned throttleCPULimit, unsigned queueLimit, StringBuffer *errMsg)
  3220. {
  3221. assertex(socket);
  3222. MemoryBuffer sendbuf;
  3223. initSendBuffer(sendbuf);
  3224. sendbuf.append((RemoteFileCommandType)RFCsetthrottle2).append((unsigned)throttleClass).append(throttleLimit);
  3225. sendbuf.append(throttleDelayMs).append(throttleCPULimit).append(queueLimit);
  3226. MemoryBuffer replybuf;
  3227. try
  3228. {
  3229. sendBuffer(socket, sendbuf);
  3230. receiveBuffer(socket, replybuf, NORMAL_RETRIES, 1024);
  3231. int retcode;
  3232. replybuf.read(retcode);
  3233. if (retcode && errMsg && replybuf.remaining())
  3234. replybuf.read(*errMsg);
  3235. return retcode;
  3236. }
  3237. catch (IException *e)
  3238. {
  3239. EXCLOG(e);
  3240. ::Release(e);
  3241. }
  3242. return -1;
  3243. }
  3244. int getDafsInfo(ISocket * socket, unsigned level, StringBuffer &retstr)
  3245. {
  3246. if (!socket)
  3247. {
  3248. retstr.append(VERSTRING);
  3249. return 0;
  3250. }
  3251. MemoryBuffer sendbuf;
  3252. initSendBuffer(sendbuf);
  3253. sendbuf.append((RemoteFileCommandType)RFCgetinfo).append(level);
  3254. MemoryBuffer replybuf;
  3255. try
  3256. {
  3257. sendBuffer(socket, sendbuf);
  3258. receiveBuffer(socket, replybuf, 1);
  3259. int retcode;
  3260. replybuf.read(retcode);
  3261. if (retcode==0)
  3262. {
  3263. StringAttr s;
  3264. replybuf.read(s);
  3265. retstr.append(s);
  3266. }
  3267. return retcode;
  3268. }
  3269. catch (IException *e)
  3270. {
  3271. EXCLOG(e);
  3272. ::Release(e);
  3273. }
  3274. return -1;
  3275. }
  3276. void remoteExtractBlobElements(const SocketEndpoint &ep,const char * prefix, const char * filename, ExtractedBlobArray & extracted)
  3277. {
  3278. Owned<CRemoteFile> file = new CRemoteFile (ep,filename);
  3279. file->remoteExtractBlobElements(prefix, extracted);
  3280. }
  3281. //====================================================================================================
  3282. class CAsyncCommandManager
  3283. {
  3284. class CAsyncJob: public CInterface
  3285. {
  3286. class cThread: public Thread
  3287. {
  3288. CAsyncJob *parent;
  3289. public:
  3290. cThread(CAsyncJob *_parent)
  3291. : Thread("CAsyncJob")
  3292. {
  3293. parent = _parent;
  3294. }
  3295. int run()
  3296. {
  3297. int ret = -1;
  3298. try {
  3299. ret = parent->run();
  3300. parent->setDone();
  3301. }
  3302. catch (IException *e)
  3303. {
  3304. parent->setException(e);
  3305. }
  3306. parent->signal();
  3307. return ret;
  3308. }
  3309. } *thread;
  3310. StringAttr uuid;
  3311. CAsyncCommandManager &parent;
  3312. public:
  3313. CAsyncJob(CAsyncCommandManager &_parent, const char *_uuid)
  3314. : uuid(_uuid), parent(_parent)
  3315. {
  3316. thread = new cThread(this);
  3317. hash = hashc((const byte *)uuid.get(),uuid.length(),~0U);
  3318. }
  3319. ~CAsyncJob()
  3320. {
  3321. thread->join();
  3322. thread->Release();
  3323. }
  3324. static void destroy(CAsyncJob *j)
  3325. {
  3326. j->Release();
  3327. }
  3328. void signal()
  3329. {
  3330. parent.signal();
  3331. }
  3332. void start()
  3333. {
  3334. parent.wait();
  3335. thread->start();
  3336. }
  3337. void join()
  3338. {
  3339. thread->join();
  3340. }
  3341. static unsigned getHash(const char *key)
  3342. {
  3343. return hashc((const byte *)key,strlen(key),~0U);
  3344. }
  3345. static CAsyncJob* create(const char *key) { assertex(!"CAsyncJob::create not implemented"); return NULL; }
  3346. unsigned hash;
  3347. bool eq(const char *key)
  3348. {
  3349. return stricmp(key,uuid.get())==0;
  3350. }
  3351. virtual int run()=0;
  3352. virtual void setException(IException *e)=0;
  3353. virtual void setDone()=0;
  3354. };
  3355. class CAsyncCopySection: public CAsyncJob
  3356. {
  3357. Owned<IFile> src;
  3358. RemoteFilename dst;
  3359. offset_t toOfs;
  3360. offset_t fromOfs;
  3361. offset_t size;
  3362. CFPmode mode; // not yet supported
  3363. CriticalSection sect;
  3364. offset_t done;
  3365. offset_t total;
  3366. Semaphore finished;
  3367. AsyncCommandStatus status;
  3368. Owned<IException> exc;
  3369. public:
  3370. CAsyncCopySection(CAsyncCommandManager &parent, const char *_uuid, const char *fromFile, const char *toFile, offset_t _toOfs, offset_t _fromOfs, offset_t _size)
  3371. : CAsyncJob(parent, _uuid)
  3372. {
  3373. status = ACScontinue;
  3374. src.setown(createIFile(fromFile));
  3375. dst.setRemotePath(toFile);
  3376. toOfs = _toOfs;
  3377. fromOfs = _fromOfs;
  3378. size = _size;
  3379. mode = CFPcontinue;
  3380. done = 0;
  3381. total = (offset_t)-1;
  3382. }
  3383. AsyncCommandStatus poll(offset_t &_done, offset_t &_total,unsigned timeout)
  3384. {
  3385. if (timeout&&finished.wait(timeout))
  3386. finished.signal(); // may need to call again
  3387. CriticalBlock block(sect);
  3388. if (exc)
  3389. throw exc.getClear();
  3390. _done = done;
  3391. _total = total;
  3392. return status;
  3393. }
  3394. int run()
  3395. {
  3396. class cProgress: implements ICopyFileProgress
  3397. {
  3398. CriticalSection &sect;
  3399. CFPmode &mode;
  3400. offset_t &done;
  3401. offset_t &total;
  3402. public:
  3403. cProgress(CriticalSection &_sect,offset_t &_done,offset_t &_total,CFPmode &_mode)
  3404. : sect(_sect), mode(_mode), done(_done), total(_total)
  3405. {
  3406. }
  3407. CFPmode onProgress(offset_t sizeDone, offset_t totalSize)
  3408. {
  3409. CriticalBlock block(sect);
  3410. done = sizeDone;
  3411. total = totalSize;
  3412. return mode;
  3413. }
  3414. } progress(sect,total,done,mode);
  3415. src->copySection(dst,toOfs, fromOfs, size, &progress); // exceptions will be handled by base class
  3416. return 0;
  3417. }
  3418. void setException(IException *e)
  3419. {
  3420. EXCLOG(e,"CAsyncCommandManager::CAsyncJob");
  3421. CriticalBlock block(sect);
  3422. if (exc.get())
  3423. e->Release();
  3424. else
  3425. exc.setown(e);
  3426. status = ACSerror;
  3427. }
  3428. void setDone()
  3429. {
  3430. CriticalBlock block(sect);
  3431. finished.signal();
  3432. status = ACSdone;
  3433. }
  3434. };
  3435. CMinHashTable<CAsyncJob> jobtable;
  3436. CriticalSection sect;
  3437. Semaphore threadsem;
  3438. unsigned limit;
  3439. public:
  3440. CAsyncCommandManager(unsigned _limit) : limit(_limit)
  3441. {
  3442. if (limit) // 0 == unbound
  3443. threadsem.signal(limit); // max number of async jobs
  3444. }
  3445. void join()
  3446. {
  3447. CriticalBlock block(sect);
  3448. unsigned i;
  3449. CAsyncJob *j=jobtable.first(i);
  3450. while (j) {
  3451. j->join();
  3452. j=jobtable.next(i);
  3453. }
  3454. }
  3455. void signal()
  3456. {
  3457. if (limit)
  3458. threadsem.signal();
  3459. }
  3460. void wait()
  3461. {
  3462. if (limit)
  3463. threadsem.wait();
  3464. }
  3465. AsyncCommandStatus copySection(const char *uuid, const char *fromFile, const char *toFile, offset_t toOfs, offset_t fromOfs, offset_t size, offset_t &done, offset_t &total, unsigned timeout)
  3466. {
  3467. // return 0 if continuing, 1 if done
  3468. CAsyncCopySection * job;
  3469. Linked<CAsyncJob> cjob;
  3470. {
  3471. CriticalBlock block(sect);
  3472. cjob.set(jobtable.find(uuid,false));
  3473. if (cjob) {
  3474. job = QUERYINTERFACE(cjob.get(),CAsyncCopySection);
  3475. if (!job) {
  3476. throw MakeStringException(-1,"Async job ID mismatch");
  3477. }
  3478. }
  3479. else {
  3480. job = new CAsyncCopySection(*this, uuid, fromFile, toFile, toOfs, fromOfs, size);
  3481. cjob.setown(job);
  3482. jobtable.add(cjob.getLink());
  3483. cjob->start();
  3484. }
  3485. }
  3486. AsyncCommandStatus ret = ACSerror;
  3487. Owned<IException> rete;
  3488. try {
  3489. ret = job->poll(done,total,timeout);
  3490. }
  3491. catch (IException * e) {
  3492. rete.setown(e);
  3493. }
  3494. if ((ret!=ACScontinue)||rete.get()) {
  3495. job->join();
  3496. CriticalBlock block(sect);
  3497. jobtable.remove(job);
  3498. if (rete.get())
  3499. throw rete.getClear();
  3500. }
  3501. return ret;
  3502. }
  3503. };
  3504. //====================================================================================================
  3505. inline void appendErr(MemoryBuffer &reply, unsigned e)
  3506. {
  3507. reply.append(e).append(getRFSERRText(e));
  3508. }
  3509. #define MAPCOMMAND(c,p) case c: { this->p(msg, reply) ; break; }
  3510. #define MAPCOMMANDCLIENT(c,p,client) case c: { this->p(msg, reply, client); break; }
  3511. #define MAPCOMMANDCLIENTTESTSOCKET(c,p,client) case c: { testSocketFlag = true; this->p(msg, reply, client); break; }
  3512. #define MAPCOMMANDCLIENTTHROTTLE(c,p,client,throttler) case c: { this->p(msg, reply, client, throttler); break; }
  3513. #define MAPCOMMANDSTATS(c,p,stats) case c: { this->p(msg, reply, stats); break; }
  3514. #define MAPCOMMANDCLIENTSTATS(c,p,client,stats) case c: { this->p(msg, reply, client, stats); break; }
  3515. static unsigned ClientCount = 0;
  3516. static unsigned MaxClientCount = 0;
  3517. static CriticalSection ClientCountSect;
  3518. #define DEFAULT_THROTTLOG_LOG_INTERVAL_SECS 60 // log total throttled delay period
  3519. class CClientStats : public CInterface
  3520. {
  3521. public:
  3522. CClientStats(const char *_client) : client(_client), count(0), bRead(0), bWritten(0) { }
  3523. const char *queryFindString() const { return client; }
  3524. inline void addRead(unsigned __int64 len)
  3525. {
  3526. bRead += len;
  3527. }
  3528. inline void addWrite(unsigned __int64 len)
  3529. {
  3530. bWritten += len;
  3531. }
  3532. void getStatus(StringBuffer & info) const
  3533. {
  3534. info.appendf("Client %s - %" I64F "d requests handled, bytes read = %" I64F "d, bytes written = % " I64F "d",
  3535. client.get(), count, bRead.load(), bWritten.load()).newline();
  3536. }
  3537. StringAttr client;
  3538. unsigned __int64 count;
  3539. std::atomic<unsigned __int64> bRead;
  3540. std::atomic<unsigned __int64> bWritten;
  3541. };
  3542. class CClientStatsTable : public OwningStringSuperHashTableOf<CClientStats>
  3543. {
  3544. typedef OwningStringSuperHashTableOf<CClientStats> PARENT;
  3545. CriticalSection crit;
  3546. unsigned cmdStats[RFCmax];
  3547. static int compareElement(void* const *ll, void* const *rr)
  3548. {
  3549. const CClientStats *l = (const CClientStats *) *ll;
  3550. const CClientStats *r = (const CClientStats *) *rr;
  3551. if (l->count == r->count)
  3552. return 0;
  3553. else if (l->count<r->count)
  3554. return 1;
  3555. else
  3556. return -1;
  3557. }
  3558. public:
  3559. CClientStatsTable()
  3560. {
  3561. memset(&cmdStats[0], 0, sizeof(cmdStats));
  3562. }
  3563. ~CClientStatsTable()
  3564. {
  3565. _releaseAll();
  3566. }
  3567. CClientStats *getClientReference(RemoteFileCommandType cmd, const char *client)
  3568. {
  3569. CriticalBlock b(crit);
  3570. CClientStats *stats = PARENT::find(client);
  3571. if (!stats)
  3572. {
  3573. stats = new CClientStats(client);
  3574. PARENT::replace(*stats);
  3575. }
  3576. if (cmd<RFCmax) // i.e. ignore duff command (which will be traced), but still record client connected
  3577. cmdStats[cmd]++;
  3578. ++stats->count;
  3579. return LINK(stats);
  3580. }
  3581. StringBuffer &getInfo(StringBuffer &info, unsigned level=1)
  3582. {
  3583. CriticalBlock b(crit);
  3584. unsigned __int64 totalCmds = 0;
  3585. for (unsigned c=0; c<RFCmax; c++)
  3586. totalCmds += cmdStats[c];
  3587. unsigned totalClients = PARENT::ordinality();
  3588. info.appendf("Commands processed = %" I64F "u, unique clients = %u", totalCmds, totalClients);
  3589. if (totalCmds)
  3590. {
  3591. info.append("Command stats:").newline();
  3592. for (unsigned c=0; c<RFCmax; c++)
  3593. {
  3594. unsigned __int64 count = cmdStats[c];
  3595. if (count)
  3596. info.append(getRFCText(c)).append(": ").append(count).newline();
  3597. }
  3598. }
  3599. if (totalClients)
  3600. {
  3601. SuperHashIteratorOf<CClientStats> iter(*this);
  3602. PointerArrayOf<CClientStats> elements;
  3603. ForEach(iter)
  3604. {
  3605. CClientStats &elem = iter.query();
  3606. elements.append(&elem);
  3607. }
  3608. elements.sort(&compareElement);
  3609. if (level < 10)
  3610. {
  3611. // list up to 10 clients ordered by # of commands processed
  3612. unsigned max=elements.ordinality();
  3613. if (max>10)
  3614. max = 10; // cap
  3615. info.append("Top 10 clients:").newline();
  3616. for (unsigned e=0; e<max; e++)
  3617. {
  3618. const CClientStats &element = *elements.item(e);
  3619. element.getStatus(info);
  3620. }
  3621. }
  3622. else // list all
  3623. {
  3624. info.append("All clients:").newline();
  3625. ForEachItemIn(e, elements)
  3626. {
  3627. const CClientStats &element = *elements.item(e);
  3628. element.getStatus(info);
  3629. }
  3630. }
  3631. }
  3632. return info;
  3633. }
  3634. void reset()
  3635. {
  3636. CriticalBlock b(crit);
  3637. memset(&cmdStats[0], 0, sizeof(cmdStats));
  3638. kill();
  3639. }
  3640. };
  3641. interface IRemoteActivity : extends IInterface
  3642. {
  3643. virtual const void *nextRow(MemoryBufferBuilder &outBuilder, size32_t &sz) = 0;
  3644. virtual unsigned __int64 queryProcessed() const = 0;
  3645. virtual IOutputMetaData *queryOutputMeta() const = 0;
  3646. virtual StringBuffer &getInfoStr(StringBuffer &out) const = 0;
  3647. virtual void serializeCursor(MemoryBuffer &tgt) const = 0;
  3648. virtual void restoreCursor(MemoryBuffer &src) = 0;
  3649. virtual bool isGrouped() const = 0;
  3650. };
  3651. class CRemoteRequest : public CSimpleInterfaceOf<IInterface>
  3652. {
  3653. OutputFormat format;
  3654. unsigned __int64 replyLimit;
  3655. Linked<IRemoteActivity> activity;
  3656. Linked<ICompressor> compressor;
  3657. public:
  3658. CRemoteRequest(OutputFormat _format, ICompressor *_compressor, unsigned __int64 _replyLimit, IRemoteActivity *_activity)
  3659. : format(_format), compressor(_compressor), replyLimit(_replyLimit), activity(_activity)
  3660. {
  3661. }
  3662. OutputFormat queryFormat() const { return format; }
  3663. unsigned __int64 queryReplyLimit() const { return replyLimit; }
  3664. IRemoteActivity *queryActivity() const { return activity; }
  3665. ICompressor *queryCompressor() const { return compressor; }
  3666. };
  3667. enum OpenFileFlag { of_null=0x0, of_key=0x01 };
  3668. struct OpenFileInfo
  3669. {
  3670. OpenFileInfo() { }
  3671. OpenFileInfo(int _handle, IFileIO *_fileIO, StringAttrItem *_filename) : handle(_handle), fileIO(_fileIO), filename(_filename) { }
  3672. OpenFileInfo(int _handle, CRemoteRequest *_remoteRequest, StringAttrItem *_filename)
  3673. : handle(_handle), remoteRequest(_remoteRequest), filename(_filename) { }
  3674. Linked<IFileIO> fileIO;
  3675. Linked<CRemoteRequest> remoteRequest;
  3676. Linked<StringAttrItem> filename; // for debug
  3677. int handle = 0;
  3678. unsigned flags = 0;
  3679. };
  3680. static IOutputMetaData *getTypeInfoOutputMetaData(IPropertyTree &actNode, const char *typePropName, bool grouped)
  3681. {
  3682. IPropertyTree *json = actNode.queryPropTree(typePropName);
  3683. if (json)
  3684. return createTypeInfoOutputMetaData(*json, grouped);
  3685. else
  3686. {
  3687. StringBuffer binTypePropName(typePropName);
  3688. const char *jsonBin = actNode.queryProp(binTypePropName.append("Bin"));
  3689. if (!jsonBin)
  3690. return nullptr;
  3691. MemoryBuffer mb;
  3692. JBASE64_Decode(jsonBin, mb);
  3693. return createTypeInfoOutputMetaData(mb, grouped);
  3694. }
  3695. }
  3696. class CRemoteDiskBaseActivity : public CSimpleInterfaceOf<IRemoteActivity>, implements IVirtualFieldCallback
  3697. {
  3698. protected:
  3699. StringAttr fileName; // physical filename
  3700. Linked<IOutputMetaData> inMeta, outMeta;
  3701. unsigned __int64 processed = 0;
  3702. Owned<const IDynamicTransform> translator;
  3703. bool outputGrouped = false;
  3704. bool opened = false;
  3705. bool eofSeen = false;
  3706. const RtlRecord *record = nullptr;
  3707. RowFilter filters;
  3708. // virtual field values
  3709. StringAttr logicalFilename;
  3710. void initCommon(IPropertyTree &config)
  3711. {
  3712. fileName.set(config.queryProp("fileName"));
  3713. if (isEmptyString(fileName))
  3714. throw createDafsException(DAFSERR_cmdstream_protocol_failure, "CRemoteDiskBaseActivity: fileName missing");
  3715. record = &inMeta->queryRecordAccessor(true);
  3716. translator.setown(createRecordTranslator(outMeta->queryRecordAccessor(true), *record));
  3717. Owned<IPropertyTreeIterator> filterIter = config.getElements("keyFilter");
  3718. ForEach(*filterIter)
  3719. filters.addFilter(*record, filterIter->query().queryProp(nullptr));
  3720. logicalFilename.set(config.queryProp("virtualFields/logicalFilename"));
  3721. }
  3722. public:
  3723. IMPLEMENT_IINTERFACE_USING(CSimpleInterfaceOf<IRemoteActivity>)
  3724. CRemoteDiskBaseActivity(IPropertyTree &config)
  3725. {
  3726. }
  3727. // IRemoteActivity impl.
  3728. virtual unsigned __int64 queryProcessed() const override
  3729. {
  3730. return processed;
  3731. }
  3732. virtual IOutputMetaData *queryOutputMeta() const override
  3733. {
  3734. return outMeta;
  3735. }
  3736. virtual bool isGrouped() const override
  3737. {
  3738. return outputGrouped;
  3739. }
  3740. virtual void serializeCursor(MemoryBuffer &tgt) const override
  3741. {
  3742. throwUnexpected();
  3743. }
  3744. virtual void restoreCursor(MemoryBuffer &src) override
  3745. {
  3746. throwUnexpected();
  3747. }
  3748. //interface IVirtualFieldCallback
  3749. virtual const char * queryLogicalFilename(const void * row) override
  3750. {
  3751. return logicalFilename.str();
  3752. }
  3753. virtual unsigned __int64 getFilePosition(const void * row) override
  3754. {
  3755. throwUnexpected();
  3756. }
  3757. virtual unsigned __int64 getLocalFilePosition(const void * row) override
  3758. {
  3759. throwUnexpected();
  3760. }
  3761. virtual const byte * lookupBlob(unsigned __int64 id) override
  3762. {
  3763. throwUnexpected();
  3764. }
  3765. };
  3766. class CRemoteDiskReadActivity : public CRemoteDiskBaseActivity
  3767. {
  3768. typedef CRemoteDiskBaseActivity PARENT;
  3769. CThorContiguousRowBuffer prefetchBuffer;
  3770. Owned<ISourceRowPrefetcher> prefetcher;
  3771. Owned<ISerialStream> inputStream;
  3772. Owned<IFileIO> iFileIO;
  3773. unsigned __int64 chooseN = 0;
  3774. unsigned __int64 startPos = 0;
  3775. bool compressed = false;
  3776. bool inputGrouped = false;
  3777. bool cursorDirty = false;
  3778. mutable bool eogPending = false;
  3779. mutable bool someInGroup = false;
  3780. RtlDynRow *filterRow = nullptr;
  3781. // virtual field values
  3782. unsigned partNum = 0;
  3783. offset_t baseFpos = 0;
  3784. void checkOpen()
  3785. {
  3786. if (opened)
  3787. {
  3788. if (!cursorDirty)
  3789. return;
  3790. if (prefetchBuffer.tell() != startPos)
  3791. {
  3792. inputStream->reset(startPos);
  3793. prefetchBuffer.clearStream();
  3794. prefetchBuffer.setStream(inputStream);
  3795. }
  3796. eofSeen = false;
  3797. cursorDirty = false;
  3798. return;
  3799. }
  3800. OwnedIFile iFile = createIFile(fileName);
  3801. assertex(iFile);
  3802. iFileIO.setown(createCompressedFileReader(iFile));
  3803. if (iFileIO)
  3804. {
  3805. if (!compressed)
  3806. {
  3807. WARNLOG("meta info did not mark file '%s' as compressed, but detected file as compressed", fileName.get());
  3808. compressed = true;
  3809. }
  3810. }
  3811. else
  3812. {
  3813. iFileIO.setown(iFile->open(IFOread));
  3814. if (!iFileIO)
  3815. throw createDafsExceptionV(DAFSERR_cmdstream_protocol_failure, "Failed to open: '%s'", fileName.get());
  3816. if (compressed)
  3817. {
  3818. WARNLOG("meta info marked file '%s' as compressed, but detected file as uncompressed", fileName.get());
  3819. compressed = false;
  3820. }
  3821. }
  3822. inputStream.setown(createFileSerialStream(iFileIO, startPos));
  3823. prefetchBuffer.setStream(inputStream);
  3824. prefetcher.setown(inMeta->createDiskPrefetcher());
  3825. opened = true;
  3826. eofSeen = false;
  3827. }
  3828. void close()
  3829. {
  3830. iFileIO.clear();
  3831. opened = false;
  3832. eofSeen = true;
  3833. }
  3834. inline bool fieldFilterMatch(const void * buffer)
  3835. {
  3836. if (filters.numFilterFields())
  3837. {
  3838. filterRow->setRow(buffer, 0);
  3839. return filters.matches(*filterRow);
  3840. }
  3841. else
  3842. return true;
  3843. }
  3844. public:
  3845. CRemoteDiskReadActivity(IPropertyTree &config) : PARENT(config), prefetchBuffer(nullptr)
  3846. {
  3847. compressed = config.getPropBool("compressed");
  3848. inputGrouped = config.getPropBool("inputGrouped", false);
  3849. outputGrouped = config.getPropBool("outputGrouped", false);
  3850. chooseN = config.getPropInt64("chooseN", defaultFileStreamChooseNLimit);
  3851. if (!inputGrouped && outputGrouped)
  3852. outputGrouped = false; // perhaps should fire error
  3853. inMeta.setown(getTypeInfoOutputMetaData(config, "input", inputGrouped));
  3854. outMeta.setown(getTypeInfoOutputMetaData(config, "output", outputGrouped));
  3855. if (!outMeta)
  3856. outMeta.set(inMeta);
  3857. partNum = config.getPropInt("virtualFields/partNum");
  3858. baseFpos = (offset_t)config.getPropInt64("virtualFields/baseFpos");
  3859. initCommon(config);
  3860. if (config.hasProp("keyFilter"))
  3861. filterRow = new RtlDynRow(*record);
  3862. }
  3863. ~CRemoteDiskReadActivity()
  3864. {
  3865. delete filterRow;
  3866. }
  3867. // IRemoteActivity impl.
  3868. virtual const void *nextRow(MemoryBufferBuilder &outBuilder, size32_t &retSz) override
  3869. {
  3870. if (eogPending || eofSeen)
  3871. {
  3872. eogPending = false;
  3873. someInGroup = false;
  3874. return nullptr;
  3875. }
  3876. checkOpen();
  3877. while (!eofSeen && (processed < chooseN))
  3878. {
  3879. while (!prefetchBuffer.eos())
  3880. {
  3881. prefetcher->readAhead(prefetchBuffer);
  3882. bool eog = false;
  3883. if (inputGrouped)
  3884. prefetchBuffer.read(sizeof(eog), &eog);
  3885. const byte *next = prefetchBuffer.queryRow();
  3886. size32_t rowSz; // use local var instead of reference param for efficiency
  3887. if (fieldFilterMatch(next))
  3888. rowSz = translator->translate(outBuilder, *this, next);
  3889. else
  3890. rowSz = 0;
  3891. prefetchBuffer.finishedRow();
  3892. const void *ret = outBuilder.getSelf();
  3893. outBuilder.finishRow(rowSz);
  3894. if (rowSz)
  3895. {
  3896. processed++;
  3897. eogPending = eog;
  3898. someInGroup = true;
  3899. retSz = rowSz;
  3900. return ret;
  3901. }
  3902. else if (eog)
  3903. {
  3904. eogPending = false;
  3905. if (someInGroup)
  3906. {
  3907. someInGroup = false;
  3908. return nullptr;
  3909. }
  3910. }
  3911. }
  3912. eofSeen = true;
  3913. }
  3914. close();
  3915. retSz = 0;
  3916. return nullptr;
  3917. }
  3918. virtual void serializeCursor(MemoryBuffer &tgt) const override
  3919. {
  3920. tgt.append(prefetchBuffer.tell());
  3921. tgt.append(processed);
  3922. tgt.append(someInGroup);
  3923. tgt.append(eogPending);
  3924. }
  3925. virtual void restoreCursor(MemoryBuffer &src) override
  3926. {
  3927. cursorDirty = true;
  3928. src.read(startPos);
  3929. src.read(processed);
  3930. src.read(someInGroup);
  3931. src.read(eogPending);
  3932. }
  3933. virtual StringBuffer &getInfoStr(StringBuffer &out) const override
  3934. {
  3935. return out.appendf("diskread[%s]", fileName.get());
  3936. }
  3937. virtual bool isGrouped() const override
  3938. {
  3939. return outputGrouped;
  3940. }
  3941. //interface IVirtualFieldCallback
  3942. virtual unsigned __int64 getFilePosition(const void * row) override
  3943. {
  3944. return prefetchBuffer.tell() + baseFpos;
  3945. }
  3946. virtual unsigned __int64 getLocalFilePosition(const void * row) override
  3947. {
  3948. return makeLocalFposOffset(partNum, prefetchBuffer.tell());
  3949. }
  3950. virtual const byte * lookupBlob(unsigned __int64 id) override
  3951. {
  3952. throwUnexpected();
  3953. }
  3954. };
  3955. IRemoteActivity *createRemoteDiskRead(IPropertyTree &actNode)
  3956. {
  3957. return new CRemoteDiskReadActivity(actNode);
  3958. }
  3959. class CRemoteIndexBaseActivity : public CRemoteDiskBaseActivity
  3960. {
  3961. typedef CRemoteDiskBaseActivity PARENT;
  3962. protected:
  3963. bool isTlk = false;
  3964. bool allowPreload = false;
  3965. unsigned fileCrc = 0;
  3966. Owned<IKeyIndex> keyIndex;
  3967. Owned<IKeyManager> keyManager;
  3968. void checkOpen()
  3969. {
  3970. if (opened)
  3971. return;
  3972. Owned<IFile> indexFile = createIFile(fileName);
  3973. CDateTime modTime;
  3974. indexFile->getTime(nullptr, &modTime, nullptr);
  3975. time_t modTimeTT = modTime.getSimple();
  3976. CRC32 crc32(fileCrc);
  3977. crc32.tally(sizeof(time_t), &modTimeTT);
  3978. unsigned crc = crc32.get();
  3979. keyIndex.setown(createKeyIndex(fileName, crc, isTlk, allowPreload));
  3980. keyManager.setown(createLocalKeyManager(*record, keyIndex, nullptr, true));
  3981. filters.createSegmentMonitors(keyManager);
  3982. keyManager->finishSegmentMonitors();
  3983. keyManager->reset();
  3984. opened = true;
  3985. }
  3986. void close()
  3987. {
  3988. keyManager.clear();
  3989. keyIndex.clear();
  3990. opened = false;
  3991. eofSeen = true;
  3992. }
  3993. public:
  3994. CRemoteIndexBaseActivity(IPropertyTree &config) : PARENT(config)
  3995. {
  3996. isTlk = config.getPropBool("isTlk");
  3997. allowPreload = config.getPropBool("allowPreload");
  3998. fileCrc = config.getPropInt("crc");
  3999. }
  4000. };
  4001. class CRemoteIndexReadActivity : public CRemoteIndexBaseActivity
  4002. {
  4003. typedef CRemoteIndexBaseActivity PARENT;
  4004. unsigned __int64 chooseN = 0;
  4005. public:
  4006. CRemoteIndexReadActivity(IPropertyTree &config) : PARENT(config)
  4007. {
  4008. chooseN = config.getPropInt64("chooseN", defaultFileStreamChooseNLimit);
  4009. inMeta.setown(getTypeInfoOutputMetaData(config, "input", false));
  4010. outMeta.setown(getTypeInfoOutputMetaData(config, "output", false));
  4011. if (!outMeta)
  4012. outMeta.set(inMeta);
  4013. initCommon(config);
  4014. }
  4015. // IRemoteActivity impl.
  4016. virtual const void *nextRow(MemoryBufferBuilder &outBuilder, size32_t &retSz) override
  4017. {
  4018. if (eofSeen)
  4019. return nullptr;
  4020. checkOpen();
  4021. if (!eofSeen)
  4022. {
  4023. if (processed < chooseN)
  4024. {
  4025. while (keyManager->lookup(true))
  4026. {
  4027. const byte *keyRow = keyManager->queryKeyBuffer();
  4028. retSz = translator->translate(outBuilder, *this, keyRow);
  4029. if (retSz)
  4030. {
  4031. const void *ret = outBuilder.getSelf();
  4032. outBuilder.finishRow(retSz);
  4033. ++processed;
  4034. return ret;
  4035. }
  4036. }
  4037. retSz = 0;
  4038. }
  4039. eofSeen = true;
  4040. }
  4041. close();
  4042. return nullptr;
  4043. }
  4044. virtual void serializeCursor(MemoryBuffer &tgt) const override
  4045. {
  4046. keyManager->serializeCursorPos(tgt);
  4047. tgt.append(processed);
  4048. /* JCSMORE (see HPCC-19640), serialize seek/scan data to client
  4049. tgt.append(keyManager->querySeeks());
  4050. tgt.append(keyManager->queryScans());
  4051. */
  4052. }
  4053. virtual void restoreCursor(MemoryBuffer &src) override
  4054. {
  4055. checkOpen();
  4056. eofSeen = false;
  4057. keyManager->deserializeCursorPos(src);
  4058. src.read(processed);
  4059. }
  4060. virtual StringBuffer &getInfoStr(StringBuffer &out) const override
  4061. {
  4062. return out.appendf("indexread[%s]", fileName.get());
  4063. }
  4064. };
  4065. IRemoteActivity *createRemoteIndexRead(IPropertyTree &actNode)
  4066. {
  4067. return new CRemoteIndexReadActivity(actNode);
  4068. }
  4069. // create a { unsigned8 } output meta for the count
  4070. static const RtlIntTypeInfo indexCountFieldType(type_unsigned|type_int, 8);
  4071. static const RtlFieldStrInfo indexCountField("count", nullptr, &indexCountFieldType);
  4072. static const RtlFieldInfo * const indexCountFields[2] = { &indexCountField, nullptr };
  4073. static const RtlRecordTypeInfo indexCountRecord(type_record, 2, indexCountFields);
  4074. class CRemoteIndexCountActivity : public CRemoteIndexBaseActivity
  4075. {
  4076. typedef CRemoteIndexBaseActivity PARENT;
  4077. unsigned __int64 rowLimit = 0;
  4078. public:
  4079. CRemoteIndexCountActivity(IPropertyTree &config) : PARENT(config)
  4080. {
  4081. rowLimit = config.getPropInt64("chooseN");
  4082. inMeta.setown(getTypeInfoOutputMetaData(config, "input", false));
  4083. outMeta.setown(new CDynamicOutputMetaData(indexCountRecord));
  4084. initCommon(config);
  4085. }
  4086. // IRemoteActivity impl.
  4087. virtual const void *nextRow(MemoryBufferBuilder &outBuilder, size32_t &retSz) override
  4088. {
  4089. if (eofSeen)
  4090. return nullptr;
  4091. checkOpen();
  4092. unsigned __int64 count = 0;
  4093. if (!eofSeen)
  4094. {
  4095. if (rowLimit)
  4096. count = keyManager->checkCount(rowLimit);
  4097. else
  4098. count = keyManager->getCount();
  4099. }
  4100. void *tgt = outBuilder.ensureCapacity(sizeof(count), "count");
  4101. const void *ret = outBuilder.getSelf();
  4102. memcpy(tgt, &count, sizeof(count));
  4103. outBuilder.finishRow(sizeof(count));
  4104. close();
  4105. return ret;
  4106. }
  4107. virtual StringBuffer &getInfoStr(StringBuffer &out) const override
  4108. {
  4109. return out.appendf("indexcount[%s]", fileName.get());
  4110. }
  4111. };
  4112. IRemoteActivity *createRemoteIndexCount(IPropertyTree &actNode)
  4113. {
  4114. return new CRemoteIndexCountActivity(actNode);
  4115. }
  4116. void checkExpiryTime(IPropertyTree &metaInfo)
  4117. {
  4118. const char *expiryTime = metaInfo.queryProp("expiryTime");
  4119. if (isEmptyString(expiryTime))
  4120. throw createDafsException(DAFSERR_cmdstream_invalidexpiry, "createRemoteActivity: invalid expiry specification");
  4121. CDateTime expiryTimeDt;
  4122. try
  4123. {
  4124. expiryTimeDt.setString(expiryTime);
  4125. }
  4126. catch (IException *e)
  4127. {
  4128. throw createDafsException(DAFSERR_cmdstream_invalidexpiry, "createRemoteActivity: invalid expiry specification");
  4129. }
  4130. CDateTime nowDt;
  4131. nowDt.setNow();
  4132. if (nowDt >= expiryTimeDt)
  4133. throw createDafsException(DAFSERR_cmdstream_authexpired, "createRemoteActivity: authorization expired");
  4134. }
  4135. void verifyMetaInfo(IPropertyTree &actNode, bool authorizedOnly, const IPropertyTree *keyPairInfo)
  4136. {
  4137. if (!authorizedOnly) // if configured false, allows unencrypted meta info
  4138. {
  4139. if (actNode.hasProp("fileName"))
  4140. return;
  4141. }
  4142. StringBuffer metaInfoB64;
  4143. actNode.getProp("metaInfo", metaInfoB64);
  4144. if (0 == metaInfoB64.length())
  4145. throw createDafsException(DAFSERR_cmdstream_protocol_failure, "createRemoteActivity: missing metaInfo");
  4146. MemoryBuffer compressedMetaInfoMb;
  4147. JBASE64_Decode(metaInfoB64.str(), compressedMetaInfoMb);
  4148. MemoryBuffer decompressedMetaInfoMb;
  4149. fastLZDecompressToBuffer(decompressedMetaInfoMb, compressedMetaInfoMb);
  4150. Owned<IPropertyTree> metaInfoEnvelope = createPTree(decompressedMetaInfoMb);
  4151. Owned<IPropertyTree> metaInfo;
  4152. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  4153. MemoryBuffer metaInfoBlob;
  4154. metaInfoEnvelope->getPropBin("metaInfoBlob", metaInfoBlob);
  4155. bool isSigned = metaInfoBlob.length() != 0;
  4156. if (authorizedOnly && !isSigned)
  4157. throw createDafsException(DAFSERR_cmdstream_unauthorized, "createRemoteActivity: unathorized");
  4158. if (isSigned)
  4159. {
  4160. metaInfo.setown(createPTree(metaInfoBlob));
  4161. // version for future use
  4162. unsigned securityVersion = metaInfo->getPropInt("version");
  4163. const char *keyPairName = metaInfo->queryProp("keyPairName");
  4164. StringBuffer metaInfoSignature;
  4165. if (!metaInfoEnvelope->getProp("signature", metaInfoSignature))
  4166. throw createDafsException(DAFSERR_cmdstream_unauthorized, "createRemoteActivity: missing signature");
  4167. VStringBuffer keyPairPath("KeyPair[@name=\"%s\"]", keyPairName);
  4168. IPropertyTree *keyPair = keyPairInfo->queryPropTree(keyPairPath);
  4169. if (!keyPair)
  4170. throw createDafsException(DAFSERR_cmdstream_unauthorized, "createRemoteActivity: missing key pair definition");
  4171. const char *publicKeyFName = keyPair->queryProp("@publicKey");
  4172. if (isEmptyString(publicKeyFName))
  4173. throw createDafsException(DAFSERR_cmdstream_unauthorized, "createRemoteActivity: missing public key definition");
  4174. Owned<CLoadedKey> publicKey = loadPublicKeyFromFile(publicKeyFName, nullptr); // NB: if cared could cache loaded keys
  4175. if (!digiVerify(metaInfoSignature, metaInfoBlob.length(), metaInfoBlob.bytes(), *publicKey))
  4176. throw createDafsException(DAFSERR_cmdstream_unauthorized, "createRemoteActivity: signature verification failed");
  4177. checkExpiryTime(*metaInfo);
  4178. }
  4179. else
  4180. #endif
  4181. metaInfo.set(metaInfoEnvelope);
  4182. IPropertyTree *fileInfo = metaInfo->queryPropTree("FileInfo");
  4183. assertex(fileInfo);
  4184. // extra filename based on part/copy.
  4185. assertex(actNode.hasProp("filePart"));
  4186. unsigned partNum = actNode.getPropInt("filePart");
  4187. assertex(partNum);
  4188. unsigned partCopy = actNode.getPropInt("filePartCopy", 1);
  4189. VStringBuffer xpath("Part[%u]/Copy[%u]/@filePath", partNum, partCopy);
  4190. StringBuffer partFileName;
  4191. fileInfo->getProp(xpath, partFileName);
  4192. if (!partFileName.length())
  4193. throw createDafsException(DAFSERR_cmdstream_protocol_failure, "createRemoteActivity: invalid file info");
  4194. actNode.setProp("fileName", partFileName.str());
  4195. verifyex(actNode.removeProp("metaInfo")); // no longer needed
  4196. }
  4197. IRemoteActivity *createRemoteActivity(IPropertyTree &actNode, bool authorizedOnly, const IPropertyTree *keyPairInfo)
  4198. {
  4199. verifyMetaInfo(actNode, authorizedOnly, keyPairInfo);
  4200. const char *partFileName = actNode.queryProp("fileName");
  4201. const char *kindStr = actNode.queryProp("kind");
  4202. ThorActivityKind kind = TAKnone;
  4203. if (kindStr)
  4204. {
  4205. if (strieq("diskread", kindStr))
  4206. kind = TAKdiskread;
  4207. else if (strieq("indexread", kindStr))
  4208. kind = TAKindexread;
  4209. else if (strieq("indexcount", kindStr))
  4210. kind = TAKindexcount;
  4211. // else - auto-detect
  4212. }
  4213. Owned<IRemoteActivity> activity;
  4214. switch (kind)
  4215. {
  4216. case TAKdiskread:
  4217. {
  4218. activity.setown(createRemoteDiskRead(actNode));
  4219. break;
  4220. }
  4221. case TAKindexread:
  4222. {
  4223. activity.setown(createRemoteIndexRead(actNode));
  4224. break;
  4225. }
  4226. case TAKindexcount:
  4227. {
  4228. activity.setown(createRemoteIndexCount(actNode));
  4229. break;
  4230. }
  4231. default: // auto-detect file format
  4232. {
  4233. const char *action = actNode.queryProp("action");
  4234. if (isIndexFile(partFileName))
  4235. {
  4236. if (!isEmptyString(action))
  4237. {
  4238. if (streq("count", action))
  4239. activity.setown(createRemoteIndexCount(actNode));
  4240. else
  4241. throw createDafsExceptionV(DAFSERR_cmdstream_protocol_failure, "Unknown action '%s' on index '%s'", action, partFileName);
  4242. }
  4243. else
  4244. activity.setown(createRemoteIndexRead(actNode));
  4245. }
  4246. else // flat file
  4247. {
  4248. if (!isEmptyString(action))
  4249. {
  4250. if (streq("count", action))
  4251. throw createDafsException(DAFSERR_cmdstream_protocol_failure, "Remote Disk Counts currently unsupported");
  4252. else
  4253. throw createDafsExceptionV(DAFSERR_cmdstream_protocol_failure, "Unknown action '%s' on flat file '%s'", action, partFileName);
  4254. }
  4255. else
  4256. activity.setown(createRemoteDiskRead(actNode));
  4257. }
  4258. break;
  4259. }
  4260. }
  4261. return activity.getClear();
  4262. }
  4263. IRemoteActivity *createOutputActivity(IPropertyTree &requestTree, bool authorizedOnly, const IPropertyTree *keyPairInfo)
  4264. {
  4265. IPropertyTree *actNode = requestTree.queryPropTree("node");
  4266. assertex(actNode);
  4267. return createRemoteActivity(*actNode, authorizedOnly, keyPairInfo);
  4268. }
  4269. #define MAX_KEYDATA_SZ 0x10000
  4270. class CRemoteFileServer : implements IRemoteFileServer, public CInterface
  4271. {
  4272. class CThrottler;
  4273. class CRemoteClientHandler : implements ISocketSelectNotify, public CInterface
  4274. {
  4275. bool calledByRowService;
  4276. public:
  4277. CRemoteFileServer *parent;
  4278. Owned<ISocket> socket;
  4279. StringAttr peerName;
  4280. Owned<IAuthenticatedUser> user;
  4281. MemoryBuffer msg;
  4282. bool selecthandled;
  4283. size32_t left;
  4284. StructArrayOf<OpenFileInfo> openFiles;
  4285. Owned<IDirectoryIterator> opendir;
  4286. unsigned lasttick, lastInactiveTick;
  4287. atomic_t &globallasttick;
  4288. unsigned previdx; // for debug
  4289. IMPLEMENT_IINTERFACE;
  4290. CRemoteClientHandler(CRemoteFileServer *_parent,ISocket *_socket,IAuthenticatedUser *_user,atomic_t &_globallasttick, bool _calledByRowService)
  4291. : socket(_socket), user(_user), globallasttick(_globallasttick), calledByRowService(_calledByRowService)
  4292. {
  4293. previdx = (unsigned)-1;
  4294. StringBuffer peerBuf;
  4295. char name[256];
  4296. name[0] = 0;
  4297. int port = socket->peer_name(name,sizeof(name)-1);
  4298. if (port>=0)
  4299. {
  4300. peerBuf.append(name);
  4301. if (port)
  4302. peerBuf.append(':').append(port);
  4303. peerName.set(peerBuf);
  4304. }
  4305. else
  4306. {
  4307. /* There's a possibility the socket closed before got here, in which case, peer name is unavailable
  4308. * May potentially be unavailable for other reasons also.
  4309. * Must be set, as used in client stats HT.
  4310. * If socket closed, the handler will start up but notice closed and quit
  4311. */
  4312. peerName.set("UNKNOWN PEER NAME");
  4313. }
  4314. {
  4315. CriticalBlock block(ClientCountSect);
  4316. if (++ClientCount>MaxClientCount)
  4317. MaxClientCount = ClientCount;
  4318. if (TF_TRACE_CLIENT_CONN)
  4319. {
  4320. StringBuffer s;
  4321. s.appendf("Connecting(%p) [%d,%d] to ",this,ClientCount,MaxClientCount);
  4322. s.append(peerName);
  4323. PROGLOG("%s", s.str());
  4324. }
  4325. }
  4326. parent = _parent;
  4327. left = 0;
  4328. msg.setEndian(__BIG_ENDIAN);
  4329. selecthandled = false;
  4330. touch();
  4331. }
  4332. ~CRemoteClientHandler()
  4333. {
  4334. {
  4335. CriticalBlock block(ClientCountSect);
  4336. ClientCount--;
  4337. if (TF_TRACE_CLIENT_CONN) {
  4338. PROGLOG("Disconnecting(%p) [%d,%d] ",this,ClientCount,MaxClientCount);
  4339. }
  4340. }
  4341. ISocket *sock = socket.getClear();
  4342. try {
  4343. sock->Release();
  4344. }
  4345. catch (IException *e) {
  4346. EXCLOG(e,"~CRemoteClientHandler");
  4347. e->Release();
  4348. }
  4349. }
  4350. bool isRowServiceClient() const { return calledByRowService; }
  4351. bool notifySelected(ISocket *sock,unsigned selected)
  4352. {
  4353. if (TF_TRACE_FULL)
  4354. PROGLOG("notifySelected(%p)",this);
  4355. if (sock!=socket)
  4356. WARNLOG("notifySelected - invalid socket passed");
  4357. size32_t avail = (size32_t)socket->avail_read();
  4358. if (avail)
  4359. touch();
  4360. else if (left)
  4361. {
  4362. WARNLOG("notifySelected: Closing mid packet, %d remaining", left);
  4363. msg.clear();
  4364. parent->notify(this, msg); // notifying of graceful close
  4365. return false;
  4366. }
  4367. if (left==0)
  4368. {
  4369. try
  4370. {
  4371. left = avail?receiveBufferSize(socket):0;
  4372. }
  4373. catch (IException *e)
  4374. {
  4375. EXCLOG(e,"notifySelected(1)");
  4376. e->Release();
  4377. left = 0;
  4378. }
  4379. if (left)
  4380. {
  4381. avail = (size32_t)socket->avail_read();
  4382. try
  4383. {
  4384. msg.ensureCapacity(left);
  4385. }
  4386. catch (IException *e)
  4387. {
  4388. EXCLOG(e,"notifySelected(2)");
  4389. e->Release();
  4390. left = 0;
  4391. // if too big then corrupted packet so read avail to try and consume
  4392. char fbuf[1024];
  4393. while (avail)
  4394. {
  4395. size32_t rd = avail>sizeof(fbuf)?sizeof(fbuf):avail;
  4396. try
  4397. {
  4398. socket->read(fbuf, rd); // don't need timeout here
  4399. avail -= rd;
  4400. }
  4401. catch (IException *e)
  4402. {
  4403. EXCLOG(e,"notifySelected(2) flush");
  4404. e->Release();
  4405. break;
  4406. }
  4407. }
  4408. avail = 0;
  4409. left = 0;
  4410. }
  4411. }
  4412. }
  4413. size32_t toread = left>avail?avail:left;
  4414. if (toread)
  4415. {
  4416. try
  4417. {
  4418. socket->read(msg.reserve(toread), toread); // don't need timeout here
  4419. }
  4420. catch (IException *e)
  4421. {
  4422. EXCLOG(e,"notifySelected(3)");
  4423. e->Release();
  4424. toread = left;
  4425. msg.clear();
  4426. }
  4427. }
  4428. if (TF_TRACE_FULL)
  4429. PROGLOG("notifySelected %d,%d",toread,left);
  4430. left -= toread;
  4431. if (left==0)
  4432. {
  4433. // DEBUG
  4434. parent->notify(this, msg); // consumes msg
  4435. }
  4436. return false;
  4437. }
  4438. void logPrevHandle()
  4439. {
  4440. if (previdx<openFiles.ordinality())
  4441. {
  4442. const OpenFileInfo &fileInfo = openFiles.item(previdx);
  4443. PROGLOG("Previous handle(%d): %s", fileInfo.handle, fileInfo.filename->text.get());
  4444. }
  4445. }
  4446. bool throttleCommand(MemoryBuffer &msg)
  4447. {
  4448. RemoteFileCommandType cmd = RFCunknown;
  4449. Owned<IException> e;
  4450. try
  4451. {
  4452. msg.read(cmd);
  4453. parent->throttleCommand(cmd, msg, this);
  4454. return true;
  4455. }
  4456. catch (IException *_e)
  4457. {
  4458. e.setown(_e);
  4459. }
  4460. /* processCommand() will handle most exception and replies,
  4461. * but if throttleCommand fails before it gets that far, this will handle
  4462. */
  4463. MemoryBuffer reply;
  4464. initSendBuffer(reply);
  4465. unsigned err = (cmd == RFCopenIO) ? RFSERR_OpenFailed : 0;
  4466. parent->formatException(reply, e, cmd, false, err, this);
  4467. sendBuffer(socket, reply);
  4468. return false;
  4469. }
  4470. void processCommand(RemoteFileCommandType cmd, MemoryBuffer &msg, CThrottler *throttler)
  4471. {
  4472. MemoryBuffer reply;
  4473. bool testSocketFlag = parent->processCommand(cmd, msg, initSendBuffer(reply), this, throttler);
  4474. sendBuffer(socket, reply, testSocketFlag);
  4475. }
  4476. bool immediateCommand() // returns false if socket closed or failure
  4477. {
  4478. MemoryBuffer msg;
  4479. msg.setEndian(__BIG_ENDIAN);
  4480. touch();
  4481. size32_t avail = (size32_t)socket->avail_read();
  4482. if (avail==0)
  4483. return false;
  4484. receiveBuffer(socket, msg, 5); // shouldn't timeout as data is available
  4485. touch();
  4486. if (msg.length()==0)
  4487. return false;
  4488. return throttleCommand(msg);
  4489. }
  4490. void process(MemoryBuffer &msg)
  4491. {
  4492. if (selecthandled)
  4493. throttleCommand(msg);
  4494. else
  4495. {
  4496. // msg only used/filled if process() has been triggered by notify()
  4497. while (parent->threadRunningCount()<=parent->targetActiveThreads) // if too many threads add to select handler
  4498. {
  4499. int w;
  4500. try
  4501. {
  4502. w = socket->wait_read(1000);
  4503. }
  4504. catch (IException *e)
  4505. {
  4506. EXCLOG(e, "CRemoteClientHandler::main wait_read error");
  4507. e->Release();
  4508. parent->onCloseSocket(this,1);
  4509. return;
  4510. }
  4511. if (w==0)
  4512. break;
  4513. if ((w<0)||!immediateCommand())
  4514. {
  4515. if (w<0)
  4516. WARNLOG("CRemoteClientHandler::main wait_read error");
  4517. parent->onCloseSocket(this,1);
  4518. return;
  4519. }
  4520. }
  4521. /* This is a bit confusing..
  4522. * The addClient below, adds this request to a selecthandler handled by another thread
  4523. * and passes ownership of 'this' (CRemoteClientHandler)
  4524. *
  4525. * When notified, the selecthandler will launch a new pool thread to handle the request
  4526. * If the pool thread limit is hit, the selecthandler will be blocked [ see comment in CRemoteFileServer::notify() ]
  4527. *
  4528. * Either way, a thread pool slot is occupied when processing a request.
  4529. * Blocked threads, will be blocked for up to 1 minute (as defined by createThreadPool call)
  4530. * IOW, if there are lots of incoming clients that can't be serviced by the CThrottler limit,
  4531. * a large number of pool threads will build up after a while.
  4532. *
  4533. * The CThrottler mechanism, imposes a further hard limit on how many concurrent request threads can be active.
  4534. * If the thread pool had an absolute limit (instead of just introducing a delay), then I don't see the point
  4535. * in this additional layer of throttling..
  4536. */
  4537. selecthandled = true;
  4538. parent->addClient(this); // add to select handler
  4539. // NB: this (CRemoteClientHandler) is now linked by the selecthandler and owned by the 'clients' list
  4540. }
  4541. }
  4542. bool timedOut()
  4543. {
  4544. return (msTick()-lasttick)>CLIENT_TIMEOUT;
  4545. }
  4546. bool inactiveTimedOut()
  4547. {
  4548. unsigned ms = msTick();
  4549. if ((ms-lastInactiveTick)>CLIENT_INACTIVEWARNING_TIMEOUT)
  4550. {
  4551. lastInactiveTick = ms;
  4552. return true;
  4553. }
  4554. return false;
  4555. }
  4556. void touch()
  4557. {
  4558. lastInactiveTick = lasttick = msTick();
  4559. atomic_set(&globallasttick,lasttick);
  4560. }
  4561. const char *queryPeerName()
  4562. {
  4563. return peerName;
  4564. }
  4565. bool getInfo(StringBuffer &str)
  4566. {
  4567. str.append("client(");
  4568. const char *name = queryPeerName();
  4569. bool ok;
  4570. if (name)
  4571. {
  4572. ok = true;
  4573. str.append(name);
  4574. }
  4575. else
  4576. ok = false;
  4577. unsigned ms = msTick();
  4578. str.appendf("): last touch %d ms ago (%d, %d)",ms-lasttick,lasttick,ms);
  4579. ForEachItemIn(i, openFiles)
  4580. {
  4581. const OpenFileInfo &fileInfo = openFiles.item(i);
  4582. str.appendf("\n %d: ", fileInfo.handle);
  4583. str.append(fileInfo.filename->text.get());
  4584. }
  4585. return ok;
  4586. }
  4587. };
  4588. class CThrottleQueueItem : public CSimpleInterface
  4589. {
  4590. public:
  4591. RemoteFileCommandType cmd;
  4592. Linked<CRemoteClientHandler> client;
  4593. MemoryBuffer msg;
  4594. CCycleTimer timer;
  4595. CThrottleQueueItem(RemoteFileCommandType _cmd, MemoryBuffer &_msg, CRemoteClientHandler *_client) : cmd(_cmd), client(_client)
  4596. {
  4597. msg.swapWith(_msg);
  4598. }
  4599. };
  4600. class CThrottler
  4601. {
  4602. Semaphore sem;
  4603. CriticalSection crit, configureCrit;
  4604. StringAttr title;
  4605. unsigned limit, delayMs, cpuThreshold, queueLimit;
  4606. unsigned disabledLimit;
  4607. unsigned __int64 totalThrottleDelay;
  4608. CCycleTimer totalThrottleDelayTimer;
  4609. QueueOf<CThrottleQueueItem, false> queue;
  4610. unsigned statsIntervalSecs;
  4611. public:
  4612. CThrottler(const char *_title) : title(_title)
  4613. {
  4614. totalThrottleDelay = 0;
  4615. limit = 0;
  4616. delayMs = DEFAULT_STDCMD_THROTTLEDELAYMS;
  4617. cpuThreshold = DEFAULT_STDCMD_THROTTLECPULIMIT;
  4618. disabledLimit = 0;
  4619. queueLimit = DEFAULT_STDCMD_THROTTLEQUEUELIMIT;
  4620. statsIntervalSecs = DEFAULT_STDCMD_THROTTLECPULIMIT;
  4621. }
  4622. ~CThrottler()
  4623. {
  4624. for (;;)
  4625. {
  4626. Owned<CThrottleQueueItem> item = queue.dequeue();
  4627. if (!item)
  4628. break;
  4629. }
  4630. }
  4631. unsigned queryLimit() const { return limit; }
  4632. unsigned queryDelayMs() const { return delayMs; };;
  4633. unsigned queryCpuThreshold() const { return cpuThreshold; }
  4634. unsigned queryQueueLimit() const { return queueLimit; }
  4635. StringBuffer &getInfoSummary(StringBuffer &info)
  4636. {
  4637. info.appendf("Throttler(%s) - limit=%u, delayMs=%u, cpuThreshold=%u, queueLimit=%u", title.get(), limit, delayMs, cpuThreshold, queueLimit).newline();
  4638. unsigned elapsedSecs = totalThrottleDelayTimer.elapsedMs()/1000;
  4639. time_t simple;
  4640. time(&simple);
  4641. simple -= elapsedSecs;
  4642. CDateTime dt;
  4643. dt.set(simple);
  4644. StringBuffer dateStr;
  4645. dt.getTimeString(dateStr, true);
  4646. info.appendf("Throttler(%s): statistics since %s", title.get(), dateStr.str()).newline();
  4647. info.appendf("Total delay of %0.2f seconds", ((double)totalThrottleDelay)/1000).newline();
  4648. info.appendf("Requests currently queued: %u", queue.ordinality());
  4649. return info;
  4650. }
  4651. void getInfo(StringBuffer &info)
  4652. {
  4653. CriticalBlock b(crit);
  4654. getInfoSummary(info).newline();
  4655. }
  4656. void configure(unsigned _limit, unsigned _delayMs, unsigned _cpuThreshold, unsigned _queueLimit)
  4657. {
  4658. if (_limit > THROTTLE_MAX_LIMIT || _delayMs > THROTTLE_MAX_DELAYMS || _cpuThreshold > THROTTLE_MAX_CPUTHRESHOLD || _queueLimit > THROTTLE_MAX_QUEUELIMIT)
  4659. throw MakeStringException(0, "Throttler(%s), rejecting configure command: limit=%u (max permitted=%u), delayMs=%u (max permitted=%u), cpuThreshold=%u (max permitted=%u), queueLimit=%u (max permitted=%u)",
  4660. title.str(), _limit, THROTTLE_MAX_LIMIT, _delayMs, THROTTLE_MAX_DELAYMS, _cpuThreshold,
  4661. THROTTLE_MAX_CPUTHRESHOLD, _queueLimit, THROTTLE_MAX_QUEUELIMIT);
  4662. CriticalBlock b(configureCrit);
  4663. int delta = 0;
  4664. if (_limit)
  4665. {
  4666. if (disabledLimit) // if transitioning from disabled to some throttling
  4667. {
  4668. assertex(0 == limit);
  4669. delta = _limit - disabledLimit; // + or -
  4670. disabledLimit = 0;
  4671. }
  4672. else
  4673. delta = _limit - limit; // + or -
  4674. }
  4675. else if (0 == disabledLimit)
  4676. {
  4677. PROGLOG("Throttler(%s): disabled, previous limit: %u", title.get(), limit);
  4678. /* disabling - set limit immediately to let all new transaction through.
  4679. * NB: the semaphore signals are not consumed in this case, because transactions could be waiting on it.
  4680. * Instead the existing 'limit' is kept in 'disabledLimit', so that if/when throttling is
  4681. * re-enabled, it is used as a basis for increasing or consuming the semaphore signal count.
  4682. */
  4683. disabledLimit = limit;
  4684. limit = 0;
  4685. }
  4686. if (delta > 0)
  4687. {
  4688. PROGLOG("Throttler(%s): Increasing limit from %u to %u", title.get(), limit, _limit);
  4689. sem.signal(delta);
  4690. limit = _limit;
  4691. // NB: If throttling was off, this doesn't effect transactions in progress, i.e. will only throttle new transactions coming in.
  4692. }
  4693. else if (delta < 0)
  4694. {
  4695. PROGLOG("Throttler(%s): Reducing limit from %u to %u", title.get(), limit, _limit);
  4696. // NB: This is not expected to take long
  4697. CCycleTimer timer;
  4698. while (delta < 0)
  4699. {
  4700. if (sem.wait(1000))
  4701. ++delta;
  4702. else
  4703. PROGLOG("Throttler(%s): Waited %0.2f seconds so far for up to a maximum of %u (previous limit) transactions to complete, %u completed", title.get(), ((double)timer.elapsedMs())/1000, limit, -delta);
  4704. }
  4705. limit = _limit;
  4706. // NB: doesn't include transactions in progress, i.e. will only throttle new transactions coming in.
  4707. }
  4708. if (_delayMs != delayMs)
  4709. {
  4710. PROGLOG("Throttler(%s): New delayMs=%u, previous: %u", title.get(), _delayMs, delayMs);
  4711. delayMs = _delayMs;
  4712. }
  4713. if (_cpuThreshold != cpuThreshold)
  4714. {
  4715. PROGLOG("Throttler(%s): New cpuThreshold=%u, previous: %u", title.get(), _cpuThreshold, cpuThreshold);
  4716. cpuThreshold = _cpuThreshold;
  4717. }
  4718. if (((unsigned)-1) != _queueLimit && _queueLimit != queueLimit)
  4719. {
  4720. PROGLOG("Throttler(%s): New queueLimit=%u%s, previous: %u", title.get(), _queueLimit, 0==_queueLimit?"(disabled)":"", queueLimit);
  4721. queueLimit = _queueLimit;
  4722. }
  4723. }
  4724. void setStatsInterval(unsigned _statsIntervalSecs)
  4725. {
  4726. if (_statsIntervalSecs != statsIntervalSecs)
  4727. {
  4728. PROGLOG("Throttler(%s): New statsIntervalSecs=%u, previous: %u", title.get(), _statsIntervalSecs, statsIntervalSecs);
  4729. statsIntervalSecs = _statsIntervalSecs;
  4730. }
  4731. }
  4732. void take(RemoteFileCommandType cmd) // cmd for info. only
  4733. {
  4734. for (;;)
  4735. {
  4736. if (sem.wait(delayMs))
  4737. return;
  4738. PROGLOG("Throttler(%s): transaction delayed [cmd=%s]", title.get(), getRFCText(cmd));
  4739. }
  4740. }
  4741. void release()
  4742. {
  4743. sem.signal();
  4744. }
  4745. StringBuffer &getStats(StringBuffer &stats, bool reset)
  4746. {
  4747. CriticalBlock b(crit);
  4748. getInfoSummary(stats);
  4749. if (reset)
  4750. {
  4751. totalThrottleDelayTimer.reset();
  4752. totalThrottleDelay = 0;
  4753. }
  4754. return stats;
  4755. }
  4756. void addCommand(RemoteFileCommandType cmd, MemoryBuffer &msg, CRemoteClientHandler *client)
  4757. {
  4758. CCycleTimer timer;
  4759. Owned<IException> exception;
  4760. bool hadSem = true;
  4761. if (!sem.wait(delayMs))
  4762. {
  4763. CriticalBlock b(crit);
  4764. if (!sem.wait(0)) // check hasn't become available
  4765. {
  4766. unsigned cpu = getLatestCPUUsage();
  4767. if (getLatestCPUUsage()<cpuThreshold)
  4768. {
  4769. /* Allow to proceed, despite hitting throttle limit because CPU < threshold
  4770. * NB: The overall number of threads is still capped by the thread pool.
  4771. */
  4772. unsigned ms = timer.elapsedMs();
  4773. totalThrottleDelay += ms;
  4774. PROGLOG("Throttler(%s): transaction delayed [cmd=%s] for : %u milliseconds, proceeding as cpu(%u)<throttleCPULimit(%u)", title.get(), getRFCText(cmd), cpu, ms, cpuThreshold);
  4775. hadSem = false;
  4776. }
  4777. else
  4778. {
  4779. if (queueLimit && queue.ordinality()>=queueLimit)
  4780. throw MakeStringException(0, "Throttler(%s), the maxiumum number of items are queued (%u), rejecting new command[%s]", title.str(), queue.ordinality(), getRFCText(cmd));
  4781. queue.enqueue(new CThrottleQueueItem(cmd, msg, client)); // NB: takes over ownership of 'client' from running thread
  4782. PROGLOG("Throttler(%s): transaction delayed [cmd=%s], queuing (%u queueud), [client=%p, sock=%u]", title.get(), getRFCText(cmd), queue.ordinality(), client, client->socket->OShandle());
  4783. return;
  4784. }
  4785. }
  4786. }
  4787. /* Guarantee that sem is released.
  4788. * Should normally release on clean exit when queue is empty.
  4789. */
  4790. struct ReleaseSem
  4791. {
  4792. Semaphore *sem;
  4793. ReleaseSem(Semaphore *_sem) { sem = _sem; }
  4794. ~ReleaseSem() { if (sem) sem->signal(); }
  4795. } releaseSem(hadSem?&sem:NULL);
  4796. /* Whilst holding on this throttle slot (i.e. before signalling semaphore back), process
  4797. * queued items. NB: other threads that are finishing will do also.
  4798. * Queued items are processed 1st, then the current request, then anything that was queued when handling current request
  4799. * Throttle slot (semaphore) is only given back when no more to do.
  4800. */
  4801. Linked<CRemoteClientHandler> currentClient;
  4802. MemoryBuffer currentMsg;
  4803. unsigned ms;
  4804. for (;;)
  4805. {
  4806. RemoteFileCommandType currentCmd;
  4807. {
  4808. CriticalBlock b(crit);
  4809. Owned<CThrottleQueueItem> item = queue.dequeue();
  4810. if (item)
  4811. {
  4812. currentCmd = item->cmd;
  4813. currentClient.setown(item->client.getClear());
  4814. currentMsg.swapWith(item->msg);
  4815. ms = item->timer.elapsedMs();
  4816. }
  4817. else
  4818. {
  4819. if (NULL == client) // previously handled and queue empty
  4820. {
  4821. /* Commands are only queued if semaphore is exhaused (checked inside crit)
  4822. * so only signal the semaphore inside the crit, after checking if there are no queued items
  4823. */
  4824. if (hadSem)
  4825. {
  4826. releaseSem.sem = NULL;
  4827. sem.signal();
  4828. }
  4829. break;
  4830. }
  4831. currentCmd = cmd;
  4832. currentClient.set(client); // process current request after dealing with queue
  4833. currentMsg.swapWith(msg);
  4834. ms = timer.elapsedMs();
  4835. client = NULL;
  4836. }
  4837. }
  4838. if (ms >= 1000)
  4839. {
  4840. if (ms>delayMs)
  4841. PROGLOG("Throttler(%s): transaction delayed [cmd=%s] for : %u seconds", title.get(), getRFCText(currentCmd), ms/1000);
  4842. }
  4843. {
  4844. CriticalBlock b(crit);
  4845. totalThrottleDelay += ms;
  4846. }
  4847. try
  4848. {
  4849. currentClient->processCommand(currentCmd, currentMsg, this);
  4850. }
  4851. catch (IException *e)
  4852. {
  4853. EXCLOG(e, "addCommand: processCommand failed");
  4854. e->Release();
  4855. }
  4856. }
  4857. }
  4858. };
  4859. // temporarily release a throttler slot
  4860. class CThrottleReleaseBlock
  4861. {
  4862. CThrottler &throttler;
  4863. RemoteFileCommandType cmd;
  4864. public:
  4865. CThrottleReleaseBlock(CThrottler &_throttler, RemoteFileCommandType _cmd) : throttler(_throttler), cmd(_cmd)
  4866. {
  4867. throttler.release();
  4868. }
  4869. ~CThrottleReleaseBlock()
  4870. {
  4871. throttler.take(cmd);
  4872. }
  4873. };
  4874. int lasthandle;
  4875. CriticalSection sect;
  4876. Owned<ISocket> acceptsock;
  4877. Owned<ISocket> securesock;
  4878. Owned<ISocket> rowServiceSock;
  4879. bool rowServiceOnStdPort = true; // should row service commands be processed on std. service port
  4880. bool rowServiceSSL = false;
  4881. Owned<ISocketSelectHandler> selecthandler;
  4882. Owned<IThreadPool> threads; // for commands
  4883. bool stopping;
  4884. unsigned clientcounttick;
  4885. unsigned closedclients;
  4886. CAsyncCommandManager asyncCommandManager;
  4887. CThrottler stdCmdThrottler, slowCmdThrottler;
  4888. CClientStatsTable clientStatsTable;
  4889. atomic_t globallasttick;
  4890. unsigned targetActiveThreads;
  4891. Owned<IPropertyTree> keyPairInfo;
  4892. int getNextHandle()
  4893. {
  4894. // called in sect critical block
  4895. for (;;) {
  4896. if (lasthandle==INT_MAX)
  4897. lasthandle = 1;
  4898. else
  4899. lasthandle++;
  4900. unsigned idx1;
  4901. unsigned idx2;
  4902. if (!findHandle(lasthandle,idx1,idx2))
  4903. return lasthandle;
  4904. }
  4905. }
  4906. bool findHandle(int handle,unsigned &clientidx,unsigned &handleidx)
  4907. {
  4908. // called in sect critical block
  4909. clientidx = (unsigned)-1;
  4910. handleidx = (unsigned)-1;
  4911. ForEachItemIn(i,clients) {
  4912. CRemoteClientHandler &client = clients.item(i);
  4913. ForEachItemIn(j, client.openFiles)
  4914. {
  4915. if (client.openFiles.item(j).handle==handle)
  4916. {
  4917. handleidx = j;
  4918. clientidx = i;
  4919. return true;
  4920. }
  4921. }
  4922. }
  4923. return false;
  4924. }
  4925. unsigned readKeyData(IKeyManager *keyManager, unsigned maxRecs, MemoryBuffer &reply, bool &maxHit)
  4926. {
  4927. DelayedSizeMarker keyDataSzReturned(reply);
  4928. unsigned numRecs = 0;
  4929. maxHit = false;
  4930. unsigned pos = reply.length();
  4931. while (keyManager->lookup(true))
  4932. {
  4933. unsigned size = keyManager->queryRowSize();
  4934. const byte *result = keyManager->queryKeyBuffer();
  4935. reply.append(size);
  4936. reply.append(size, result);
  4937. ++numRecs;
  4938. if (maxRecs && (0 == --maxRecs))
  4939. {
  4940. maxHit = true;
  4941. break;
  4942. }
  4943. if (reply.length()-pos >= MAX_KEYDATA_SZ)
  4944. {
  4945. maxHit = true;
  4946. break;
  4947. }
  4948. }
  4949. keyDataSzReturned.write();
  4950. return numRecs;
  4951. }
  4952. class cCommandProcessor: public CInterface, implements IPooledThread
  4953. {
  4954. Owned<CRemoteClientHandler> client;
  4955. MemoryBuffer msg;
  4956. public:
  4957. IMPLEMENT_IINTERFACE;
  4958. struct cCommandProcessorParams
  4959. {
  4960. cCommandProcessorParams() { msg.setEndian(__BIG_ENDIAN); }
  4961. CRemoteClientHandler *client;
  4962. MemoryBuffer msg;
  4963. };
  4964. virtual void init(void *_params) override
  4965. {
  4966. cCommandProcessorParams &params = *(cCommandProcessorParams *)_params;
  4967. client.setown(params.client);
  4968. msg.swapWith(params.msg);
  4969. }
  4970. virtual void threadmain() override
  4971. {
  4972. // idea is that initially we process commands inline then pass over to select handler
  4973. try
  4974. {
  4975. client->process(msg);
  4976. }
  4977. catch (IException *e)
  4978. {
  4979. // suppress some errors
  4980. EXCLOG(e,"cCommandProcessor::threadmain");
  4981. e->Release();
  4982. }
  4983. try
  4984. {
  4985. client.clear();
  4986. }
  4987. catch (IException *e)
  4988. {
  4989. // suppress some more errors clearing client
  4990. EXCLOG(e,"cCommandProcessor::threadmain(2)");
  4991. e->Release();
  4992. }
  4993. }
  4994. virtual bool stop() override
  4995. {
  4996. return true;
  4997. }
  4998. virtual bool canReuse() const override
  4999. {
  5000. return false; // want to free owned socket
  5001. }
  5002. };
  5003. IArrayOf<CRemoteClientHandler> clients;
  5004. class cImpersonateBlock
  5005. {
  5006. CRemoteClientHandler &client;
  5007. public:
  5008. cImpersonateBlock(CRemoteClientHandler &_client)
  5009. : client(_client)
  5010. {
  5011. if (client.user.get()) {
  5012. if (TF_TRACE)
  5013. PROGLOG("Impersonate user: %s",client.user->username());
  5014. client.user->impersonate();
  5015. }
  5016. }
  5017. ~cImpersonateBlock()
  5018. {
  5019. if (client.user.get()) {
  5020. if (TF_TRACE)
  5021. PROGLOG("Stop impersonating user: %s",client.user->username());
  5022. client.user->revert();
  5023. }
  5024. }
  5025. };
  5026. #define IMPERSONATE_USER(client) cImpersonateBlock ublock(client)
  5027. bool handleFull(MemoryBuffer &inMb, size32_t inPos, MemoryBuffer &compressMb, ICompressor *compressor, size32_t replyLimit, size32_t &totalSz)
  5028. {
  5029. size32_t sz = inMb.length()-inPos;
  5030. if (sz < replyLimit)
  5031. return false;
  5032. if (!compressor)
  5033. return true;
  5034. // consumes data from inMb into compressor
  5035. totalSz += sz;
  5036. const void *data = inMb.bytes()+inPos;
  5037. assertex(compressor->write(data, sz) == sz);
  5038. inMb.setLength(inPos);
  5039. return compressMb.capacity() > replyLimit;
  5040. }
  5041. void validateSSLSetup()
  5042. {
  5043. if (!securitySettings.certificate)
  5044. throw createDafsException(DAFSERR_serverinit_failed, "SSL Certificate information not found in environment.conf");
  5045. if (!checkFileExists(securitySettings.certificate))
  5046. throw createDafsException(DAFSERR_serverinit_failed, "SSL Certificate File not found in environment.conf");
  5047. if (!securitySettings.privateKey)
  5048. throw createDafsException(DAFSERR_serverinit_failed, "SSL Key information not found in environment.conf");
  5049. if (!checkFileExists(securitySettings.privateKey))
  5050. throw createDafsException(DAFSERR_serverinit_failed, "SSL Key File not found in environment.conf");
  5051. }
  5052. public:
  5053. IMPLEMENT_IINTERFACE
  5054. CRemoteFileServer(unsigned maxThreads, unsigned maxThreadsDelayMs, unsigned maxAsyncCopy, IPropertyTree *_keyPairInfo)
  5055. : asyncCommandManager(maxAsyncCopy), stdCmdThrottler("stdCmdThrotlter"), slowCmdThrottler("slowCmdThrotlter"), keyPairInfo(_keyPairInfo)
  5056. {
  5057. lasthandle = 0;
  5058. selecthandler.setown(createSocketSelectHandler(NULL));
  5059. stdCmdThrottler.configure(DEFAULT_STDCMD_PARALLELREQUESTLIMIT, DEFAULT_STDCMD_THROTTLEDELAYMS, DEFAULT_STDCMD_THROTTLECPULIMIT, DEFAULT_STDCMD_THROTTLEQUEUELIMIT);
  5060. slowCmdThrottler.configure(DEFAULT_SLOWCMD_PARALLELREQUESTLIMIT, DEFAULT_SLOWCMD_THROTTLEDELAYMS, DEFAULT_SLOWCMD_THROTTLECPULIMIT, DEFAULT_SLOWCMD_THROTTLEQUEUELIMIT);
  5061. unsigned targetMinThreads=maxThreads*20/100; // 20%
  5062. if (0 == targetMinThreads) targetMinThreads = 1;
  5063. targetActiveThreads=maxThreads*80/100; // 80%
  5064. if (0 == targetActiveThreads) targetActiveThreads = 1;
  5065. class CCommandFactory : public CSimpleInterfaceOf<IThreadFactory>
  5066. {
  5067. CRemoteFileServer &parent;
  5068. public:
  5069. CCommandFactory(CRemoteFileServer &_parent) : parent(_parent) { }
  5070. virtual IPooledThread *createNew()
  5071. {
  5072. return parent.createCommandProcessor();
  5073. }
  5074. };
  5075. Owned<IThreadFactory> factory = new CCommandFactory(*this); // NB: pool links factory, so takes ownership
  5076. threads.setown(createThreadPool("CRemoteFileServerPool", factory, NULL, maxThreads, maxThreadsDelayMs,
  5077. #ifdef __64BIT__
  5078. 0, // Unlimited stack size
  5079. #else
  5080. 0x10000,
  5081. #endif
  5082. INFINITE,targetMinThreads));
  5083. threads->setStartDelayTracing(60); // trace amount delayed every minute.
  5084. PROGLOG("CRemoteFileServer: maxThreads = %u, maxThreadsDelayMs = %u, maxAsyncCopy = %u", maxThreads, maxThreadsDelayMs, maxAsyncCopy);
  5085. stopping = false;
  5086. clientcounttick = msTick();
  5087. closedclients = 0;
  5088. atomic_set(&globallasttick,msTick());
  5089. }
  5090. ~CRemoteFileServer()
  5091. {
  5092. #ifdef _DEBUG
  5093. PROGLOG("Exiting CRemoteFileServer");
  5094. #endif
  5095. asyncCommandManager.join();
  5096. clients.kill();
  5097. #ifdef _DEBUG
  5098. PROGLOG("Exited CRemoteFileServer");
  5099. #endif
  5100. }
  5101. bool lookupFileIOHandle(int handle, OpenFileInfo &fileInfo, unsigned newFlags=0)
  5102. {
  5103. if (handle<=0)
  5104. return false;
  5105. CriticalBlock block(sect);
  5106. unsigned clientidx;
  5107. unsigned handleidx;
  5108. if (!findHandle(handle,clientidx,handleidx))
  5109. return false;
  5110. CRemoteClientHandler &client = clients.item(clientidx);
  5111. OpenFileInfo &openFileInfo = client.openFiles.element(handleidx); // NB: links members
  5112. openFileInfo.flags |= newFlags;
  5113. fileInfo = openFileInfo;
  5114. client.previdx = handleidx;
  5115. return true;
  5116. }
  5117. //MORE: The file handles should timeout after a while, and accessing an old (invalid handle)
  5118. // should throw a different exception
  5119. bool checkFileIOHandle(int handle, IFileIO *&fileio, bool del=false)
  5120. {
  5121. fileio = NULL;
  5122. if (handle<=0)
  5123. return false;
  5124. CriticalBlock block(sect);
  5125. unsigned clientidx;
  5126. unsigned handleidx;
  5127. if (findHandle(handle,clientidx,handleidx))
  5128. {
  5129. CRemoteClientHandler &client = clients.item(clientidx);
  5130. const OpenFileInfo &fileInfo = client.openFiles.item(handleidx);
  5131. if (del)
  5132. {
  5133. if (fileInfo.flags & of_key)
  5134. clearKeyStoreCacheEntry(fileInfo.fileIO);
  5135. client.openFiles.remove(handleidx);
  5136. client.previdx = (unsigned)-1;
  5137. }
  5138. else
  5139. {
  5140. fileio = client.openFiles.item(handleidx).fileIO;
  5141. client.previdx = handleidx;
  5142. }
  5143. return true;
  5144. }
  5145. return false;
  5146. }
  5147. void checkFileIOHandle(MemoryBuffer &reply, int handle, IFileIO *&fileio, bool del=false)
  5148. {
  5149. if (!checkFileIOHandle(handle, fileio, del))
  5150. throw createDafsException(RFSERR_InvalidFileIOHandle, nullptr);
  5151. }
  5152. void onCloseSocket(CRemoteClientHandler *client, int which)
  5153. {
  5154. if (!client)
  5155. return;
  5156. CriticalBlock block(sect);
  5157. #ifdef _DEBUG
  5158. StringBuffer s(client->queryPeerName());
  5159. PROGLOG("onCloseSocket(%d) %s",which,s.str());
  5160. #endif
  5161. if (client->socket)
  5162. {
  5163. try
  5164. {
  5165. /* JCSMORE - shouldn't this really be dependent on whether selecthandled=true
  5166. * It has not been added to the selecthandler
  5167. * Harmless, but wasteful if so.
  5168. */
  5169. selecthandler->remove(client->socket);
  5170. }
  5171. catch (IException *e) {
  5172. EXCLOG(e,"CRemoteFileServer::onCloseSocket.1");
  5173. e->Release();
  5174. }
  5175. }
  5176. try {
  5177. clients.zap(*client);
  5178. }
  5179. catch (IException *e) {
  5180. EXCLOG(e,"CRemoteFileServer::onCloseSocket.2");
  5181. e->Release();
  5182. }
  5183. }
  5184. bool cmdOpenFileIO(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  5185. {
  5186. IMPERSONATE_USER(client);
  5187. Owned<StringAttrItem> name = new StringAttrItem;
  5188. byte mode;
  5189. byte share;
  5190. msg.read(name->text).read(mode).read(share);
  5191. // also try to recv extra byte
  5192. byte extra = 0;
  5193. unsigned short sMode = IFUnone;
  5194. unsigned short cFlags = IFUnone;
  5195. if (msg.remaining() >= sizeof(byte))
  5196. {
  5197. msg.read(extra);
  5198. // and then try to recv extra sMode, cFlags (always sent together)
  5199. if (msg.remaining() >= (sizeof(sMode) + sizeof(cFlags)))
  5200. msg.read(sMode).read(cFlags);
  5201. }
  5202. IFEflags extraFlags = (IFEflags)extra;
  5203. // none => nocache for remote (hint)
  5204. // can revert to previous behavior with conf file setting "allow_pgcache_flush=false"
  5205. if (extraFlags == IFEnone)
  5206. extraFlags = IFEnocache;
  5207. Owned<IFile> file = createIFile(name->text);
  5208. switch ((compatIFSHmode)share) {
  5209. case compatIFSHnone:
  5210. file->setCreateFlags(S_IRUSR|S_IWUSR);
  5211. file->setShareMode(IFSHnone);
  5212. break;
  5213. case compatIFSHread:
  5214. file->setShareMode(IFSHread);
  5215. break;
  5216. case compatIFSHwrite:
  5217. file->setShareMode(IFSHfull);
  5218. break;
  5219. case compatIFSHexec:
  5220. file->setCreateFlags(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
  5221. break;
  5222. case compatIFSHall:
  5223. file->setCreateFlags(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); // bit excessive
  5224. file->setShareMode(IFSHfull);
  5225. break;
  5226. }
  5227. // use sMode, cFlags if sent
  5228. if (sMode != IFUnone && cFlags != IFUnone)
  5229. {
  5230. file->setCreateFlags(cFlags);
  5231. file->setShareMode((IFSHmode)sMode);
  5232. }
  5233. if (TF_TRACE_PRE_IO)
  5234. PROGLOG("before open file '%s', (%d,%d,%d,%d,0%o)",name->text.get(),(int)mode,(int)share,extraFlags,sMode,cFlags);
  5235. Owned<IFileIO> fileio = file->open((IFOmode)mode,extraFlags);
  5236. int handle;
  5237. if (fileio)
  5238. {
  5239. CriticalBlock block(sect);
  5240. handle = getNextHandle();
  5241. client.previdx = client.openFiles.ordinality();
  5242. client.openFiles.append(OpenFileInfo(handle, fileio, name));
  5243. }
  5244. else
  5245. handle = 0;
  5246. reply.append(RFEnoerror);
  5247. reply.append(handle);
  5248. if (TF_TRACE)
  5249. PROGLOG("open file '%s', (%d,%d) handle = %d",name->text.get(),(int)mode,(int)share,handle);
  5250. return true;
  5251. }
  5252. bool cmdCloseFileIO(MemoryBuffer & msg, MemoryBuffer & reply)
  5253. {
  5254. int handle;
  5255. msg.read(handle);
  5256. IFileIO *fileio;
  5257. checkFileIOHandle(reply, handle, fileio, true);
  5258. if (TF_TRACE)
  5259. PROGLOG("close file, handle = %d",handle);
  5260. reply.append(RFEnoerror);
  5261. return true;
  5262. }
  5263. void cmdRead(MemoryBuffer & msg, MemoryBuffer & reply, CClientStats &stats)
  5264. {
  5265. int handle;
  5266. __int64 pos;
  5267. size32_t len;
  5268. msg.read(handle).read(pos).read(len);
  5269. IFileIO *fileio;
  5270. checkFileIOHandle(reply, handle, fileio);
  5271. //arrange it so we read directly into the reply buffer...
  5272. unsigned posOfErr = reply.length();
  5273. reply.append((unsigned)RFEnoerror);
  5274. size32_t numRead;
  5275. unsigned posOfLength = reply.length();
  5276. if (TF_TRACE_PRE_IO)
  5277. PROGLOG("before read file, handle = %d, toread = %d",handle,len);
  5278. reply.reserve(sizeof(numRead));
  5279. void *data = reply.reserve(len);
  5280. numRead = fileio->read(pos,len,data);
  5281. stats.addRead(len);
  5282. if (TF_TRACE)
  5283. PROGLOG("read file, handle = %d, pos = %" I64F "d, toread = %d, read = %d",handle,pos,len,numRead);
  5284. reply.setLength(posOfLength + sizeof(numRead) + numRead);
  5285. reply.writeEndianDirect(posOfLength,sizeof(numRead),&numRead);
  5286. }
  5287. void cmdSize(MemoryBuffer & msg, MemoryBuffer & reply)
  5288. {
  5289. int handle;
  5290. msg.read(handle);
  5291. IFileIO *fileio;
  5292. checkFileIOHandle(reply, handle, fileio);
  5293. __int64 size = fileio->size();
  5294. reply.append((unsigned)RFEnoerror).append(size);
  5295. if (TF_TRACE)
  5296. PROGLOG("size file, handle = %d, size = %" I64F "d",handle,size);
  5297. }
  5298. void cmdSetSize(MemoryBuffer & msg, MemoryBuffer & reply)
  5299. {
  5300. int handle;
  5301. offset_t size;
  5302. msg.read(handle).read(size);
  5303. IFileIO *fileio;
  5304. if (TF_TRACE)
  5305. PROGLOG("set size file, handle = %d, size = %" I64F "d",handle,size);
  5306. checkFileIOHandle(reply, handle, fileio);
  5307. fileio->setSize(size);
  5308. reply.append((unsigned)RFEnoerror);
  5309. }
  5310. void cmdWrite(MemoryBuffer & msg, MemoryBuffer & reply, CClientStats &stats)
  5311. {
  5312. int handle;
  5313. __int64 pos;
  5314. size32_t len;
  5315. msg.read(handle).read(pos).read(len);
  5316. IFileIO *fileio;
  5317. checkFileIOHandle(reply, handle, fileio);
  5318. const byte *data = (const byte *)msg.readDirect(len);
  5319. if (TF_TRACE_PRE_IO)
  5320. PROGLOG("before write file, handle = %d, towrite = %d",handle,len);
  5321. size32_t numWritten = fileio->write(pos,len,data);
  5322. stats.addWrite(numWritten);
  5323. if (TF_TRACE)
  5324. PROGLOG("write file, handle = %d, towrite = %d, written = %d",handle,len,numWritten);
  5325. reply.append((unsigned)RFEnoerror).append(numWritten);
  5326. }
  5327. void cmdExists(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  5328. {
  5329. IMPERSONATE_USER(client);
  5330. StringAttr name;
  5331. msg.read(name);
  5332. if (TF_TRACE)
  5333. PROGLOG("exists, '%s'",name.get());
  5334. Owned<IFile> file=createIFile(name);
  5335. bool e = file->exists();
  5336. reply.append((unsigned)RFEnoerror).append(e);
  5337. }
  5338. void cmdRemove(MemoryBuffer & msg, MemoryBuffer & reply,CRemoteClientHandler &client)
  5339. {
  5340. IMPERSONATE_USER(client);
  5341. StringAttr name;
  5342. msg.read(name);
  5343. if (TF_TRACE)
  5344. PROGLOG("remove, '%s'",name.get());
  5345. Owned<IFile> file=createIFile(name);
  5346. bool e = file->remove();
  5347. reply.append((unsigned)RFEnoerror).append(e);
  5348. }
  5349. void cmdGetVer(MemoryBuffer & msg, MemoryBuffer & reply)
  5350. {
  5351. if (TF_TRACE)
  5352. PROGLOG("getVer");
  5353. if (msg.getPos()+sizeof(unsigned)>msg.length())
  5354. reply.append((unsigned)RFEnoerror);
  5355. else
  5356. reply.append((unsigned)FILESRV_VERSION+0x10000);
  5357. reply.append(VERSTRING);
  5358. }
  5359. void cmdRename(MemoryBuffer & msg, MemoryBuffer & reply,CRemoteClientHandler &client)
  5360. {
  5361. IMPERSONATE_USER(client);
  5362. StringAttr fromname;
  5363. msg.read(fromname);
  5364. StringAttr toname;
  5365. msg.read(toname);
  5366. if (TF_TRACE)
  5367. PROGLOG("rename, '%s' to '%s'",fromname.get(),toname.get());
  5368. Owned<IFile> file=createIFile(fromname);
  5369. file->rename(toname);
  5370. reply.append((unsigned)RFEnoerror);
  5371. }
  5372. void cmdMove(MemoryBuffer & msg, MemoryBuffer & reply,CRemoteClientHandler &client)
  5373. {
  5374. IMPERSONATE_USER(client);
  5375. StringAttr fromname;
  5376. msg.read(fromname);
  5377. StringAttr toname;
  5378. msg.read(toname);
  5379. if (TF_TRACE)
  5380. PROGLOG("move, '%s' to '%s'",fromname.get(),toname.get());
  5381. Owned<IFile> file=createIFile(fromname);
  5382. file->move(toname);
  5383. reply.append((unsigned)RFEnoerror);
  5384. }
  5385. void cmdCopy(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  5386. {
  5387. IMPERSONATE_USER(client);
  5388. StringAttr fromname;
  5389. msg.read(fromname);
  5390. StringAttr toname;
  5391. msg.read(toname);
  5392. if (TF_TRACE)
  5393. PROGLOG("copy, '%s' to '%s'",fromname.get(),toname.get());
  5394. copyFile(toname, fromname);
  5395. reply.append((unsigned)RFEnoerror);
  5396. }
  5397. void cmdAppend(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client, CClientStats &stats)
  5398. {
  5399. IMPERSONATE_USER(client);
  5400. int handle;
  5401. __int64 pos;
  5402. __int64 len;
  5403. StringAttr srcname;
  5404. msg.read(handle).read(srcname).read(pos).read(len);
  5405. IFileIO *fileio;
  5406. checkFileIOHandle(reply, handle, fileio);
  5407. Owned<IFile> file = createIFile(srcname.get());
  5408. __int64 written = fileio->appendFile(file,pos,len);
  5409. stats.addWrite(written);
  5410. if (TF_TRACE)
  5411. PROGLOG("append file, handle = %d, file=%s, pos = %" I64F "d len = %" I64F "d written = %" I64F "d",handle,srcname.get(),pos,len,written);
  5412. reply.append((unsigned)RFEnoerror).append(written);
  5413. }
  5414. void cmdIsFile(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5415. {
  5416. IMPERSONATE_USER(client);
  5417. StringAttr name;
  5418. msg.read(name);
  5419. if (TF_TRACE)
  5420. PROGLOG("isFile, '%s'",name.get());
  5421. Owned<IFile> file=createIFile(name);
  5422. unsigned ret = (unsigned)file->isFile();
  5423. reply.append((unsigned)RFEnoerror).append(ret);
  5424. }
  5425. void cmdIsDir(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5426. {
  5427. IMPERSONATE_USER(client);
  5428. StringAttr name;
  5429. msg.read(name);
  5430. if (TF_TRACE)
  5431. PROGLOG("isDir, '%s'",name.get());
  5432. Owned<IFile> file=createIFile(name);
  5433. unsigned ret = (unsigned)file->isDirectory();
  5434. reply.append((unsigned)RFEnoerror).append(ret);
  5435. }
  5436. void cmdIsReadOnly(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5437. {
  5438. IMPERSONATE_USER(client);
  5439. StringAttr name;
  5440. msg.read(name);
  5441. if (TF_TRACE)
  5442. PROGLOG("isReadOnly, '%s'",name.get());
  5443. Owned<IFile> file=createIFile(name);
  5444. unsigned ret = (unsigned)file->isReadOnly();
  5445. reply.append((unsigned)RFEnoerror).append(ret);
  5446. }
  5447. void cmdSetReadOnly(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5448. {
  5449. IMPERSONATE_USER(client);
  5450. StringAttr name;
  5451. bool set;
  5452. msg.read(name).read(set);
  5453. if (TF_TRACE)
  5454. PROGLOG("setReadOnly, '%s' %d",name.get(),(int)set);
  5455. Owned<IFile> file=createIFile(name);
  5456. file->setReadOnly(set);
  5457. reply.append((unsigned)RFEnoerror);
  5458. }
  5459. void cmdSetFilePerms(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5460. {
  5461. IMPERSONATE_USER(client);
  5462. StringAttr name;
  5463. unsigned fPerms;
  5464. msg.read(name).read(fPerms);
  5465. if (TF_TRACE)
  5466. PROGLOG("setFilePerms, '%s' 0%o",name.get(),fPerms);
  5467. Owned<IFile> file=createIFile(name);
  5468. file->setFilePermissions(fPerms);
  5469. reply.append((unsigned)RFEnoerror);
  5470. }
  5471. void cmdGetTime(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5472. {
  5473. IMPERSONATE_USER(client);
  5474. StringAttr name;
  5475. msg.read(name);
  5476. if (TF_TRACE)
  5477. PROGLOG("getTime, '%s'",name.get());
  5478. Owned<IFile> file=createIFile(name);
  5479. CDateTime createTime;
  5480. CDateTime modifiedTime;
  5481. CDateTime accessedTime;
  5482. bool ret = file->getTime(&createTime,&modifiedTime,&accessedTime);
  5483. reply.append((unsigned)RFEnoerror).append(ret);
  5484. if (ret)
  5485. {
  5486. createTime.serialize(reply);
  5487. modifiedTime.serialize(reply);
  5488. accessedTime.serialize(reply);
  5489. }
  5490. }
  5491. void cmdSetTime(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5492. {
  5493. IMPERSONATE_USER(client);
  5494. StringAttr name;
  5495. bool creategot;
  5496. CDateTime createTime;
  5497. bool modifiedgot;
  5498. CDateTime modifiedTime;
  5499. bool accessedgot;
  5500. CDateTime accessedTime;
  5501. msg.read(name);
  5502. msg.read(creategot);
  5503. if (creategot)
  5504. createTime.deserialize(msg);
  5505. msg.read(modifiedgot);
  5506. if (modifiedgot)
  5507. modifiedTime.deserialize(msg);
  5508. msg.read(accessedgot);
  5509. if (accessedgot)
  5510. accessedTime.deserialize(msg);
  5511. if (TF_TRACE)
  5512. PROGLOG("setTime, '%s'",name.get());
  5513. Owned<IFile> file=createIFile(name);
  5514. bool ret = file->setTime(creategot?&createTime:NULL,modifiedgot?&modifiedTime:NULL,accessedgot?&accessedTime:NULL);
  5515. reply.append((unsigned)RFEnoerror).append(ret);
  5516. }
  5517. void cmdCreateDir(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5518. {
  5519. IMPERSONATE_USER(client);
  5520. StringAttr name;
  5521. msg.read(name);
  5522. if (TF_TRACE)
  5523. PROGLOG("CreateDir, '%s'",name.get());
  5524. Owned<IFile> dir=createIFile(name);
  5525. bool ret = dir->createDirectory();
  5526. reply.append((unsigned)RFEnoerror).append(ret);
  5527. }
  5528. void cmdGetDir(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5529. {
  5530. IMPERSONATE_USER(client);
  5531. StringAttr name;
  5532. StringAttr mask;
  5533. bool includedir;
  5534. bool sub;
  5535. byte stream = 0;
  5536. msg.read(name).read(mask).read(includedir).read(sub);
  5537. if (msg.remaining()>=sizeof(byte))
  5538. {
  5539. msg.read(stream);
  5540. if (stream==1)
  5541. client.opendir.clear();
  5542. }
  5543. if (TF_TRACE)
  5544. PROGLOG("GetDir, '%s', '%s', stream='%u'",name.get(),mask.get(),stream);
  5545. if (!stream && !containsFileWildcard(mask))
  5546. {
  5547. // if no streaming, and mask contains no wildcard, it is much more efficient to get the info without a directory iterator!
  5548. StringBuffer fullFilename(name);
  5549. addPathSepChar(fullFilename).append(mask);
  5550. Owned<IFile> iFile = createIFile(fullFilename);
  5551. // NB: This must preserve same serialization format as CRemoteDirectoryIterator::serialize produces for <=1 file.
  5552. reply.append((unsigned)RFEnoerror);
  5553. if (!iFile->exists())
  5554. reply.append((byte)0);
  5555. else
  5556. {
  5557. byte b=1;
  5558. reply.append(b);
  5559. bool isDir = foundYes == iFile->isDirectory();
  5560. reply.append(isDir);
  5561. reply.append(isDir ? 0 : iFile->size());
  5562. CDateTime dt;
  5563. iFile->getTime(nullptr, &dt, nullptr);
  5564. dt.serialize(reply);
  5565. reply.append(mask);
  5566. b = 0;
  5567. reply.append(b);
  5568. }
  5569. }
  5570. else
  5571. {
  5572. Owned<IFile> dir=createIFile(name);
  5573. Owned<IDirectoryIterator> iter;
  5574. if (stream>1)
  5575. iter.set(client.opendir);
  5576. else
  5577. {
  5578. iter.setown(dir->directoryFiles(mask.length()?mask.get():NULL,sub,includedir));
  5579. if (stream != 0)
  5580. client.opendir.set(iter);
  5581. }
  5582. if (!iter)
  5583. throw createDafsException(RFSERR_GetDirFailed, nullptr);
  5584. reply.append((unsigned)RFEnoerror);
  5585. if (CRemoteDirectoryIterator::serialize(reply,iter,stream?0x100000:0,stream<2))
  5586. {
  5587. if (stream != 0)
  5588. client.opendir.clear();
  5589. }
  5590. else
  5591. {
  5592. bool cont=true;
  5593. reply.append(cont);
  5594. }
  5595. }
  5596. }
  5597. void cmdMonitorDir(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5598. {
  5599. IMPERSONATE_USER(client);
  5600. StringAttr name;
  5601. StringAttr mask;
  5602. bool includedir;
  5603. bool sub;
  5604. unsigned checkinterval;
  5605. unsigned timeout;
  5606. __int64 cancelid; // not yet used
  5607. msg.read(name).read(mask).read(includedir).read(sub).read(checkinterval).read(timeout).read(cancelid);
  5608. byte isprev;
  5609. msg.read(isprev);
  5610. Owned<IDirectoryIterator> prev;
  5611. if (isprev==1)
  5612. {
  5613. SocketEndpoint ep;
  5614. CRemoteDirectoryIterator *di = new CRemoteDirectoryIterator(ep,name);
  5615. di->appendBuf(msg);
  5616. prev.setown(di);
  5617. }
  5618. if (TF_TRACE)
  5619. PROGLOG("MonitorDir, '%s' '%s'",name.get(),mask.get());
  5620. Owned<IFile> dir=createIFile(name);
  5621. Owned<IDirectoryDifferenceIterator> iter=dir->monitorDirectory(prev,mask.length()?mask.get():NULL,sub,includedir,checkinterval,timeout);
  5622. reply.append((unsigned)RFEnoerror);
  5623. byte state = (iter.get()==NULL)?0:1;
  5624. reply.append(state);
  5625. if (state==1)
  5626. CRemoteDirectoryIterator::serializeDiff(reply,iter);
  5627. }
  5628. void cmdCopySection(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5629. {
  5630. IMPERSONATE_USER(client);
  5631. StringAttr uuid;
  5632. StringAttr fromFile;
  5633. StringAttr toFile;
  5634. offset_t toOfs;
  5635. offset_t fromOfs;
  5636. offset_t size;
  5637. offset_t sizeDone=0;
  5638. offset_t totalSize=(offset_t)-1;
  5639. unsigned timeout;
  5640. msg.read(uuid).read(fromFile).read(toFile).read(toOfs).read(fromOfs).read(size).read(timeout);
  5641. AsyncCommandStatus status = asyncCommandManager.copySection(uuid,fromFile,toFile,toOfs,fromOfs,size,sizeDone,totalSize,timeout);
  5642. reply.append((unsigned)RFEnoerror).append((unsigned)status).append(sizeDone).append(totalSize);
  5643. }
  5644. static void treeCopyFile(RemoteFilename &srcfn, RemoteFilename &dstfn, const char *net, const char *mask, IpAddress &ip, bool usetmp, CThrottler *throttler, CFflags copyFlags=CFnone)
  5645. {
  5646. unsigned start = msTick();
  5647. Owned<IFile> dstfile = createIFile(dstfn);
  5648. // the following is really to check the dest node is up and working (otherwise not much point in continuing!)
  5649. if (dstfile->exists())
  5650. PROGLOG("TREECOPY overwriting '%s'",dstfile->queryFilename());
  5651. Owned<IFile> srcfile = createIFile(srcfn);
  5652. unsigned lastmin = 0;
  5653. if (!srcfn.queryIP().ipequals(dstfn.queryIP())) {
  5654. CriticalBlock block(treeCopyCrit);
  5655. for (;;) {
  5656. CDateTime dt;
  5657. offset_t sz;
  5658. try {
  5659. sz = srcfile->size();
  5660. if (sz==(offset_t)-1) {
  5661. if (TF_TRACE_TREE_COPY)
  5662. PROGLOG("TREECOPY source not found '%s'",srcfile->queryFilename());
  5663. break;
  5664. }
  5665. srcfile->getTime(NULL,&dt,NULL);
  5666. }
  5667. catch (IException *e) {
  5668. EXCLOG(e,"treeCopyFile(1)");
  5669. e->Release();
  5670. break;
  5671. }
  5672. Linked<CTreeCopyItem> tc;
  5673. unsigned now = msTick();
  5674. ForEachItemInRev(i1,treeCopyArray) {
  5675. CTreeCopyItem &item = treeCopyArray.item(i1);
  5676. // prune old entries (not strictly needed buf I think better)
  5677. if (now-item.lastused>TREECOPYPRUNETIME)
  5678. treeCopyArray.remove(i1);
  5679. else if (!tc.get()&&item.equals(srcfn,net,mask,sz,dt)) {
  5680. tc.set(&item);
  5681. item.lastused = now;
  5682. }
  5683. }
  5684. if (!tc.get()) {
  5685. if (treeCopyArray.ordinality()>=TREECOPY_CACHE_SIZE)
  5686. treeCopyArray.remove(0);
  5687. tc.setown(new CTreeCopyItem(srcfn,net,mask,sz,dt));
  5688. treeCopyArray.append(*tc.getLink());
  5689. }
  5690. ForEachItemInRev(cand,tc->loc) { // rev to choose copied locations first (maybe optional?)
  5691. if (!tc->busy->testSet(cand)) {
  5692. // check file accessible and matches
  5693. if (!cand&&dstfn.equals(tc->loc.item(cand))) // hmm trying to overwrite existing, better humor
  5694. continue;
  5695. bool ok = true;
  5696. Owned<IFile> rmtfile = createIFile(tc->loc.item(cand));
  5697. if (cand) { // only need to check if remote
  5698. try {
  5699. if (rmtfile->size()!=sz)
  5700. ok = false;
  5701. else {
  5702. CDateTime fdt;
  5703. rmtfile->getTime(NULL,&fdt,NULL);
  5704. ok = fdt.equals(dt);
  5705. }
  5706. }
  5707. catch (IException *e) {
  5708. EXCLOG(e,"treeCopyFile(2)");
  5709. e->Release();
  5710. ok = false;
  5711. }
  5712. }
  5713. if (ok) { // if not ok leave 'busy'
  5714. // finally lets try and copy!
  5715. try {
  5716. if (TF_TRACE_TREE_COPY)
  5717. PROGLOG("TREECOPY(started) %s to %s",rmtfile->queryFilename(),dstfile->queryFilename());
  5718. {
  5719. CriticalUnblock unblock(treeCopyCrit); // note we have tc linked
  5720. rmtfile->copyTo(dstfile,DEFAULT_COPY_BLKSIZE,NULL,usetmp,copyFlags);
  5721. }
  5722. if (TF_TRACE_TREE_COPY)
  5723. PROGLOG("TREECOPY(done) %s to %s",rmtfile->queryFilename(),dstfile->queryFilename());
  5724. tc->busy->set(cand,false);
  5725. if (treeCopyWaiting)
  5726. treeCopySem.signal((treeCopyWaiting>1)?2:1);
  5727. // add to known locations
  5728. tc->busy->set(tc->loc.ordinality(),false); // prob already is clear
  5729. tc->loc.append(dstfn);
  5730. ip.ipset(tc->loc.item(cand).queryIP());
  5731. return;
  5732. }
  5733. catch (IException *e) {
  5734. if (cand==0) {
  5735. tc->busy->set(0,false); // don't leave busy
  5736. if (treeCopyWaiting)
  5737. treeCopySem.signal();
  5738. throw; // what more can we do!
  5739. }
  5740. EXCLOG(e,"treeCopyFile(3)");
  5741. e->Release();
  5742. }
  5743. }
  5744. }
  5745. }
  5746. // all locations busy
  5747. if (msTick()-start>TREECOPYTIMEOUT) {
  5748. WARNLOG("Treecopy %s wait timed out", srcfile->queryFilename());
  5749. break;
  5750. }
  5751. treeCopyWaiting++; // note this isn't precise - just indication
  5752. {
  5753. CriticalUnblock unblock(treeCopyCrit);
  5754. if (throttler)
  5755. {
  5756. CThrottleReleaseBlock block(*throttler, RFCtreecopy);
  5757. treeCopySem.wait(TREECOPYPOLLTIME);
  5758. }
  5759. else
  5760. treeCopySem.wait(TREECOPYPOLLTIME);
  5761. }
  5762. treeCopyWaiting--;
  5763. if ((msTick()-start)/10*1000!=lastmin) {
  5764. lastmin = (msTick()-start)/10*1000;
  5765. PROGLOG("treeCopyFile delayed: %s to %s",srcfile->queryFilename(),dstfile->queryFilename());
  5766. }
  5767. }
  5768. }
  5769. else if (TF_TRACE_TREE_COPY)
  5770. PROGLOG("TREECOPY source on same node as destination");
  5771. if (TF_TRACE_TREE_COPY)
  5772. PROGLOG("TREECOPY(started,fallback) %s to %s",srcfile->queryFilename(),dstfile->queryFilename());
  5773. try {
  5774. GetHostIp(ip);
  5775. srcfile->copyTo(dstfile,DEFAULT_COPY_BLKSIZE,NULL,usetmp,copyFlags);
  5776. }
  5777. catch (IException *e) {
  5778. EXCLOG(e,"TREECOPY(done,fallback)");
  5779. throw;
  5780. }
  5781. if (TF_TRACE_TREE_COPY)
  5782. PROGLOG("TREECOPY(done,fallback) %s to %s",srcfile->queryFilename(),dstfile->queryFilename());
  5783. }
  5784. void cmdTreeCopy(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client, CThrottler *throttler, bool usetmp=false)
  5785. {
  5786. IMPERSONATE_USER(client);
  5787. RemoteFilename src;
  5788. src.deserialize(msg);
  5789. RemoteFilename dst;
  5790. dst.deserialize(msg);
  5791. StringAttr net;
  5792. StringAttr mask;
  5793. msg.read(net).read(mask);
  5794. IpAddress ip;
  5795. treeCopyFile(src,dst,net,mask,ip,usetmp,throttler);
  5796. unsigned status = 0;
  5797. reply.append((unsigned)RFEnoerror).append((unsigned)status);
  5798. ip.ipserialize(reply);
  5799. }
  5800. void cmdTreeCopyTmp(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client, CThrottler *throttler)
  5801. {
  5802. cmdTreeCopy(msg, reply, client, throttler, true);
  5803. }
  5804. void cmdGetCRC(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5805. {
  5806. IMPERSONATE_USER(client);
  5807. StringAttr name;
  5808. msg.read(name);
  5809. if (TF_TRACE)
  5810. PROGLOG("getCRC, '%s'",name.get());
  5811. Owned<IFile> file=createIFile(name);
  5812. unsigned ret = file->getCRC();
  5813. reply.append((unsigned)RFEnoerror).append(ret);
  5814. }
  5815. void cmdStop(MemoryBuffer &msg, MemoryBuffer &reply)
  5816. {
  5817. PROGLOG("Abort request received");
  5818. stopping = true;
  5819. if (acceptsock)
  5820. acceptsock->cancel_accept();
  5821. if (securesock)
  5822. securesock->cancel_accept();
  5823. if (rowServiceSock)
  5824. rowServiceSock->cancel_accept();
  5825. reply.append((unsigned)RFEnoerror);
  5826. }
  5827. void cmdExec(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5828. {
  5829. StringAttr cmdLine;
  5830. msg.read(cmdLine);
  5831. // NB: legacy remoteExec used to simply pass error code and buffer back to caller.
  5832. VStringBuffer errMsg("Remote command execution no longer supported. Trying to execute cmdline=%s", cmdLine.get());
  5833. WARNLOG("%s", errMsg.str());
  5834. size32_t outSz = errMsg.length()+1; // reply with null terminated string
  5835. // reply with error code -1
  5836. reply.append((unsigned)-1).append((unsigned)0).append(outSz).append(outSz, errMsg.str());
  5837. }
  5838. void cmdSetTrace(MemoryBuffer &msg, MemoryBuffer &reply)
  5839. {
  5840. byte flags;
  5841. msg.read(flags);
  5842. int retcode=-1;
  5843. if (flags!=255) // escape
  5844. {
  5845. retcode = traceFlags;
  5846. traceFlags = flags;
  5847. }
  5848. reply.append(retcode);
  5849. }
  5850. void cmdGetInfo(MemoryBuffer &msg, MemoryBuffer &reply)
  5851. {
  5852. unsigned level=1;
  5853. if (msg.remaining() >= sizeof(unsigned))
  5854. msg.read(level);
  5855. StringBuffer retstr;
  5856. getInfo(retstr, level);
  5857. reply.append(RFEnoerror).append(retstr.str());
  5858. }
  5859. void cmdFirewall(MemoryBuffer &msg, MemoryBuffer &reply)
  5860. {
  5861. // TBD
  5862. StringBuffer retstr;
  5863. getInfo(retstr);
  5864. reply.append(RFEnoerror).append(retstr.str());
  5865. }
  5866. void cmdExtractBlobElements(MemoryBuffer &msg, MemoryBuffer &reply, CRemoteClientHandler &client)
  5867. {
  5868. IMPERSONATE_USER(client);
  5869. StringAttr prefix;
  5870. StringAttr filename;
  5871. msg.read(prefix).read(filename);
  5872. RemoteFilename rfn;
  5873. rfn.setLocalPath(filename);
  5874. ExtractedBlobArray extracted;
  5875. extractBlobElements(prefix, rfn, extracted);
  5876. unsigned n = extracted.ordinality();
  5877. reply.append((unsigned)RFEnoerror).append(n);
  5878. for (unsigned i=0;i<n;i++)
  5879. extracted.item(i).serialize(reply);
  5880. }
  5881. void cmdUnlock(MemoryBuffer & msg, MemoryBuffer & reply,CRemoteClientHandler &client)
  5882. {
  5883. // this is an attempt to authenticate when we haven't got authentication turned on
  5884. if (TF_TRACE_CLIENT_STATS)
  5885. {
  5886. StringBuffer s(client.queryPeerName());
  5887. PROGLOG("Connect from %s",s.str());
  5888. }
  5889. throw createDafsException(RFSERR_InvalidCommand, nullptr);
  5890. }
  5891. void cmdStreamReadCommon(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  5892. {
  5893. size32_t jsonSz = msg.remaining();
  5894. Owned<IPropertyTree> requestTree = createPTreeFromJSONString(jsonSz, (const char *)msg.readDirect(jsonSz));
  5895. /* Example JSON request:
  5896. * {
  5897. * "format" : "binary",
  5898. * "handle" : "1234",
  5899. * "replyLimit" : "64",
  5900. * "outputCompression" : "LZ4",
  5901. * "node" : {
  5902. * "kind" : "diskread",
  5903. * "fileName": "examplefilename",
  5904. * "keyFilter" : "f1='1 '",
  5905. * "chooseN" : 5,
  5906. * "compressed" : "false"
  5907. * "input" : {
  5908. * "f1" : "string5",
  5909. * "f2" : "string5"
  5910. * },
  5911. * "output" : {
  5912. * "f2" : "string",
  5913. * "f1" : "real"
  5914. * }
  5915. * }
  5916. * }
  5917. * {
  5918. * "format" : "xml",
  5919. * "handle" : "1234",
  5920. * "replyLimit" : "64",
  5921. * "node" : {
  5922. * "kind" : "diskread",
  5923. * "fileName": "examplefilename",
  5924. * "keyFilter" : "f1='1 '",
  5925. * "chooseN" : 5,
  5926. * "compressed" : "false"
  5927. * "input" : {
  5928. * "f1" : "string5",
  5929. * "f2" : "string5"
  5930. * },
  5931. * "output" : {
  5932. * "f2" : "string",
  5933. * "f1" : "real"
  5934. * }
  5935. * }
  5936. * }
  5937. * OR
  5938. * {
  5939. * "format" : "xml",
  5940. * "handle" : "1234",
  5941. * "node" : {
  5942. * "kind" : "indexread",
  5943. * "fileName": "examplefilename",
  5944. * "keyFilter" : "f1='1 '",
  5945. * "rowLimit" : 5,
  5946. * "input" : {
  5947. * "f1" : "string5",
  5948. * "f2" : "string5"
  5949. * },
  5950. * "output" : {
  5951. * "f2" : "string",
  5952. * "f1" : "real"
  5953. * }
  5954. * }
  5955. * }
  5956. * OR
  5957. * {
  5958. * "format" : "xml",
  5959. * "node" : {
  5960. * "action" : "count", // if present performs count with/without filter and returns count
  5961. * "fileName": "examplefilename", // can be either index or flat file
  5962. * "keyFilter" : "f1='1 '",
  5963. * "rowLimit" : 5
  5964. * "input" : {
  5965. * "f1" : "string5",
  5966. * "f2" : "string5"
  5967. * },
  5968. * }
  5969. * }
  5970. *
  5971. */
  5972. int cursorHandle = requestTree->getPropInt("handle");
  5973. OutputFormat outputFormat = outFmt_Xml;
  5974. unsigned __int64 replyLimit = 0;
  5975. Owned<ICompressor> compressor;
  5976. MemoryBuffer compressMb;
  5977. Owned<IRemoteActivity> outputActivity;
  5978. OpenFileInfo fileInfo;
  5979. if (!cursorHandle)
  5980. {
  5981. const char *outputFmtStr = requestTree->queryProp("format");
  5982. if (nullptr == outputFmtStr)
  5983. outputFormat = outFmt_Xml; // default
  5984. else if (strieq("xml", outputFmtStr))
  5985. outputFormat = outFmt_Xml;
  5986. else if (strieq("json", outputFmtStr))
  5987. outputFormat = outFmt_Json;
  5988. else if (strieq("binary", outputFmtStr))
  5989. outputFormat = outFmt_Binary;
  5990. else
  5991. throw MakeStringException(0, "Unrecognised output format: %s", outputFmtStr);
  5992. replyLimit = requestTree->getPropInt64("replyLimit", defaultDaFSReplyLimitKB) * 1024;
  5993. if (requestTree->hasProp("outputCompression"))
  5994. {
  5995. const char *outputCompressionType = requestTree->queryProp("outputCompression");
  5996. if (isEmptyString(outputCompressionType))
  5997. compressor.setown(queryDefaultCompressHandler()->getCompressor());
  5998. else if (outFmt_Binary == outputFormat)
  5999. {
  6000. compressor.setown(getCompressor(outputCompressionType));
  6001. if (!compressor)
  6002. WARNLOG("Unknown compressor type specified: %s", outputCompressionType);
  6003. }
  6004. else
  6005. WARNLOG("Output compression not supported for format: %s", outputFmtStr);
  6006. }
  6007. /* NB: unless client call is on dedicated service, allow non-authorized requests through, e.g. from engines talking to unsecured port
  6008. * In a secure setup, this service will be configured on a dedicated port, and the std. insecure dafilesrv will be unreachable.
  6009. */
  6010. bool authorizedOnly = rowServiceSock && client.isRowServiceClient();
  6011. // In future this may be passed the request and build a chain of activities and return sink.
  6012. outputActivity.setown(createOutputActivity(*requestTree, authorizedOnly, keyPairInfo));
  6013. Owned<CRemoteRequest> remoteRequest = new CRemoteRequest(outputFormat, compressor, replyLimit, outputActivity);
  6014. StringBuffer requestStr("jsonrequest:");
  6015. outputActivity->getInfoStr(requestStr);
  6016. Owned<StringAttrItem> name = new StringAttrItem(requestStr);
  6017. CriticalBlock block(sect);
  6018. cursorHandle = getNextHandle();
  6019. client.previdx = client.openFiles.ordinality();
  6020. client.openFiles.append(OpenFileInfo(cursorHandle, remoteRequest, name));
  6021. }
  6022. else if (!lookupFileIOHandle(cursorHandle, fileInfo))
  6023. cursorHandle = 0; // challenge response ..
  6024. else // known handle, continuation
  6025. {
  6026. outputActivity.set(fileInfo.remoteRequest->queryActivity());
  6027. compressor.set(fileInfo.remoteRequest->queryCompressor());
  6028. outputFormat = fileInfo.remoteRequest->queryFormat();
  6029. replyLimit = fileInfo.remoteRequest->queryReplyLimit();
  6030. }
  6031. if (outputActivity && requestTree->hasProp("cursorBin")) // use handle if one provided
  6032. {
  6033. MemoryBuffer cursorMb;
  6034. cursorMb.setEndian(__BIG_ENDIAN);
  6035. JBASE64_Decode(requestTree->queryProp("cursorBin"), cursorMb);
  6036. outputActivity->restoreCursor(cursorMb);
  6037. }
  6038. Owned<IXmlWriterExt> responseWriter; // for xml or json response
  6039. if (outFmt_Binary == outputFormat)
  6040. reply.append(cursorHandle);
  6041. else // outFmt_Xml || outFmt_Json
  6042. {
  6043. responseWriter.setown(createIXmlWriterExt(0, 0, nullptr, outFmt_Xml == outputFormat ? WTStandard : WTJSONObject));
  6044. responseWriter->outputBeginNested("Response", true);
  6045. if (outFmt_Xml == outputFormat)
  6046. responseWriter->outputCString("urn:hpcc:dfs", "@xmlns:dfs");
  6047. responseWriter->outputUInt(cursorHandle, sizeof(cursorHandle), "handle");
  6048. }
  6049. if (cursorHandle)
  6050. {
  6051. IOutputMetaData *out = outputActivity->queryOutputMeta();
  6052. bool grouped = outputActivity->isGrouped();
  6053. bool eoi=false;
  6054. MemoryBuffer resultBuffer;
  6055. MemoryBufferBuilder outBuilder(resultBuffer, out->getMinRecordSize());
  6056. if (outFmt_Binary == outputFormat)
  6057. {
  6058. if (compressor)
  6059. {
  6060. compressMb.setEndian(__BIG_ENDIAN);
  6061. compressMb.append(reply);
  6062. }
  6063. DelayedMarker<size32_t> dataLenMarker(compressor ? compressMb : reply); // data length
  6064. if (compressor)
  6065. {
  6066. size32_t initialSz = replyLimit >= 0x10000 ? 0x10000 : replyLimit;
  6067. compressor->open(compressMb, initialSz);
  6068. }
  6069. outBuilder.setBuffer(reply); // write direct to reply buffer for efficiency
  6070. unsigned __int64 numProcessedStart = outputActivity->queryProcessed();
  6071. size32_t totalDataSz = 0;
  6072. size32_t dataStartPos = reply.length();
  6073. if (grouped)
  6074. {
  6075. bool pastFirstRow = numProcessedStart>0;
  6076. do
  6077. {
  6078. size32_t eogPos = 0;
  6079. if (pastFirstRow)
  6080. {
  6081. /* this is for last row output, which might have been returned in the previous request
  6082. * The eog marker may change as a result of the next row (see writeDirect() call below);
  6083. */
  6084. eogPos = reply.length();
  6085. reply.append(false);
  6086. }
  6087. size32_t rowSz;
  6088. const void *row = outputActivity->nextRow(outBuilder, rowSz);
  6089. if (!row)
  6090. {
  6091. if (!pastFirstRow)
  6092. {
  6093. eoi = true;
  6094. break;
  6095. }
  6096. else
  6097. {
  6098. bool eog = true;
  6099. reply.writeDirect(eogPos, sizeof(eog), &eog);
  6100. row = outputActivity->nextRow(outBuilder, rowSz);
  6101. if (!row)
  6102. {
  6103. eoi = true;
  6104. break;
  6105. }
  6106. }
  6107. }
  6108. pastFirstRow = true;
  6109. }
  6110. while (!handleFull(reply, dataStartPos, compressMb, compressor, replyLimit, totalDataSz));
  6111. }
  6112. else
  6113. {
  6114. do
  6115. {
  6116. size32_t rowSz;
  6117. const void *row = outputActivity->nextRow(outBuilder, rowSz);
  6118. if (!row)
  6119. {
  6120. eoi = true;
  6121. break;
  6122. }
  6123. }
  6124. while (!handleFull(reply, dataStartPos, compressMb, compressor, replyLimit, totalDataSz));
  6125. }
  6126. // Consume any trailing data remaining
  6127. if (compressor)
  6128. {
  6129. size32_t sz = reply.length()-dataStartPos;
  6130. if (sz)
  6131. {
  6132. // consumes data built up in reply buffer into compressor
  6133. totalDataSz += sz;
  6134. const void *data = reply.bytes()+dataStartPos;
  6135. assertex(compressor->write(data, sz) == sz);
  6136. reply.setLength(dataStartPos);
  6137. }
  6138. }
  6139. // finalize reply
  6140. dataLenMarker.write(compressor ? totalDataSz : reply.length()-dataStartPos);
  6141. DelayedSizeMarker cursorLenMarker(reply); // cursor length
  6142. if (!eoi)
  6143. outputActivity->serializeCursor(reply);
  6144. cursorLenMarker.write();
  6145. if (compressor)
  6146. {
  6147. // consume cursor into compressor
  6148. size32_t sz = reply.length()-dataStartPos;
  6149. const void *data = reply.bytes()+dataStartPos;
  6150. assertex(compressor->write(data, sz) == sz);
  6151. compressor->close();
  6152. // now ready to swap compressed output into reply
  6153. reply.swapWith(compressMb);
  6154. }
  6155. }
  6156. else
  6157. {
  6158. responseWriter->outputBeginArray("Row");
  6159. if (grouped)
  6160. {
  6161. bool pastFirstRow = outputActivity->queryProcessed()>0;
  6162. bool first = true;
  6163. do
  6164. {
  6165. size32_t rowSz;
  6166. const void *row = outputActivity->nextRow(outBuilder, rowSz);
  6167. if (!row)
  6168. {
  6169. if (!pastFirstRow)
  6170. {
  6171. eoi = true;
  6172. break;
  6173. }
  6174. else
  6175. {
  6176. row = outputActivity->nextRow(outBuilder, rowSz);
  6177. if (!row)
  6178. {
  6179. eoi = true;
  6180. break;
  6181. }
  6182. if (first) // possible if eog was 1st row on next packet
  6183. responseWriter->outputBeginNested("Row", false);
  6184. responseWriter->outputBool(true, "dfs:Eog"); // field name cannot clash with an ecl field name
  6185. }
  6186. }
  6187. if (pastFirstRow)
  6188. responseWriter->outputEndNested("Row"); // close last row
  6189. responseWriter->outputBeginNested("Row", false);
  6190. out->toXML((const byte *)row, *responseWriter);
  6191. resultBuffer.clear();
  6192. pastFirstRow = true;
  6193. first = false;
  6194. }
  6195. while (responseWriter->length() < replyLimit);
  6196. if (pastFirstRow)
  6197. responseWriter->outputEndNested("Row"); // close last row
  6198. }
  6199. else
  6200. {
  6201. do
  6202. {
  6203. size32_t rowSz;
  6204. const void *row = outputActivity->nextRow(outBuilder, rowSz);
  6205. if (!row)
  6206. {
  6207. eoi = true;
  6208. break;
  6209. }
  6210. responseWriter->outputBeginNested("Row", false);
  6211. out->toXML((const byte *)row, *responseWriter);
  6212. responseWriter->outputEndNested("Row");
  6213. resultBuffer.clear();
  6214. }
  6215. while (responseWriter->length() < replyLimit);
  6216. }
  6217. responseWriter->outputEndArray("Row");
  6218. if (!eoi)
  6219. {
  6220. MemoryBuffer cursorMb;
  6221. cursorMb.setEndian(__BIG_ENDIAN);
  6222. outputActivity->serializeCursor(cursorMb);
  6223. StringBuffer cursorBinStr;
  6224. JBASE64_Encode(cursorMb.toByteArray(), cursorMb.length(), cursorBinStr);
  6225. responseWriter->outputString(cursorBinStr.length(), cursorBinStr.str(), "cursorBin");
  6226. }
  6227. }
  6228. }
  6229. if (outFmt_Binary != outputFormat)
  6230. {
  6231. responseWriter->outputEndNested("Response");
  6232. responseWriter->finalize();
  6233. PROGLOG("Response: %s", responseWriter->str());
  6234. reply.append(responseWriter->length(), responseWriter->str());
  6235. }
  6236. }
  6237. void cmdStreamReadStd(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  6238. {
  6239. reply.append(RFEnoerror);
  6240. cmdStreamReadCommon(msg, reply, client);
  6241. }
  6242. void cmdStreamReadJSON(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  6243. {
  6244. /* NB: exactly the same handling as cmdStreamReadStd(RFCStreamRead) for now,
  6245. * may want to differentiate later
  6246. * i.e. return format is { len[unsigned4-bigendian], errorcode[unsigned4-bigendian], result } - where result format depends on request output type.
  6247. * errorcode = 0 means no error
  6248. */
  6249. reply.append(RFEnoerror);
  6250. cmdStreamReadCommon(msg, reply, client);
  6251. }
  6252. void cmdStreamReadTestSocket(MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler &client)
  6253. {
  6254. reply.append('J');
  6255. cmdStreamReadCommon(msg, reply, client);
  6256. }
  6257. // legacy version
  6258. void cmdSetThrottle(MemoryBuffer & msg, MemoryBuffer & reply)
  6259. {
  6260. unsigned limit, delayMs, cpuThreshold;
  6261. msg.read(limit);
  6262. msg.read(delayMs);
  6263. msg.read(cpuThreshold);
  6264. stdCmdThrottler.configure(limit, delayMs, cpuThreshold, (unsigned)-1);
  6265. reply.append((unsigned)RFEnoerror);
  6266. }
  6267. void cmdSetThrottle2(MemoryBuffer & msg, MemoryBuffer & reply)
  6268. {
  6269. unsigned throttleClass, limit, delayMs, cpuThreshold, queueLimit;
  6270. msg.read(throttleClass);
  6271. msg.read(limit);
  6272. msg.read(delayMs);
  6273. msg.read(cpuThreshold);
  6274. msg.read(queueLimit);
  6275. setThrottle((ThrottleClass)throttleClass, limit, delayMs, cpuThreshold, queueLimit);
  6276. reply.append((unsigned)RFEnoerror);
  6277. }
  6278. void formatException(MemoryBuffer &reply, IException *e, RemoteFileCommandType cmd, bool testSocketFlag, unsigned _dfsErrorCode, CRemoteClientHandler *client)
  6279. {
  6280. unsigned dfsErrorCode = _dfsErrorCode;
  6281. if (!dfsErrorCode)
  6282. {
  6283. if (e)
  6284. dfsErrorCode = (QUERYINTERFACE(e, IDAFS_Exception)) ? e->errorCode() : RFSERR_InternalError;
  6285. else
  6286. dfsErrorCode = RFSERR_InternalError;
  6287. }
  6288. VStringBuffer errMsg("ERROR: cmd=%s, error=%s", getRFCText(cmd), getRFSERRText(dfsErrorCode));
  6289. if (e)
  6290. {
  6291. errMsg.appendf(" (%u, ", e->errorCode());
  6292. unsigned len = errMsg.length();
  6293. e->errorMessage(errMsg);
  6294. if (len == errMsg.length())
  6295. errMsg.setLength(len-2); // strip off ", " if no message in exception
  6296. errMsg.append(")");
  6297. }
  6298. if (testSocketFlag)
  6299. reply.append('-');
  6300. else
  6301. reply.append(dfsErrorCode);
  6302. reply.append(errMsg.str());
  6303. if (client && cmd!=RFCunlock)
  6304. {
  6305. const char *peer = client->queryPeerName();
  6306. if (peer)
  6307. {
  6308. VStringBuffer err("%s. Client: %s", errMsg.str(), peer);
  6309. PROGLOG("%s", err.str());
  6310. }
  6311. client->logPrevHandle();
  6312. }
  6313. }
  6314. void throttleCommand(RemoteFileCommandType cmd, MemoryBuffer &msg, CRemoteClientHandler *client)
  6315. {
  6316. switch (cmd)
  6317. {
  6318. case RFCexec:
  6319. case RFCgetcrc:
  6320. case RFCcopy:
  6321. case RFCappend:
  6322. case RFCtreecopy:
  6323. case RFCtreecopytmp:
  6324. slowCmdThrottler.addCommand(cmd, msg, client);
  6325. return;
  6326. case RFCcloseIO:
  6327. case RFCopenIO:
  6328. case RFCread:
  6329. case RFCsize:
  6330. case RFCwrite:
  6331. case RFCexists:
  6332. case RFCremove:
  6333. case RFCrename:
  6334. case RFCgetver:
  6335. case RFCisfile:
  6336. case RFCisdirectory:
  6337. case RFCisreadonly:
  6338. case RFCsetreadonly:
  6339. case RFCsetfileperms:
  6340. case RFCreadfilteredindex:
  6341. case RFCreadfilteredindexcount:
  6342. case RFCreadfilteredindexblob:
  6343. case RFCgettime:
  6344. case RFCsettime:
  6345. case RFCcreatedir:
  6346. case RFCgetdir:
  6347. case RFCmonitordir:
  6348. case RFCstop:
  6349. case RFCextractblobelements:
  6350. case RFCredeploy:
  6351. case RFCmove:
  6352. case RFCsetsize:
  6353. case RFCsettrace:
  6354. case RFCgetinfo:
  6355. case RFCfirewall:
  6356. case RFCunlock:
  6357. case RFCStreamRead:
  6358. case RFCStreamReadTestSocket:
  6359. case RFCStreamReadJSON:
  6360. stdCmdThrottler.addCommand(cmd, msg, client);
  6361. return;
  6362. // NB: The following commands are still bound by the the thread pool
  6363. case RFCsetthrottle: // legacy version
  6364. case RFCsetthrottle2:
  6365. case RFCcopysection: // slightly odd, but has it's own limit
  6366. default:
  6367. {
  6368. client->processCommand(cmd, msg, NULL);
  6369. break;
  6370. }
  6371. }
  6372. }
  6373. void checkAuthorizedStreamCommand(CRemoteClientHandler &client)
  6374. {
  6375. if (!rowServiceOnStdPort && !client.isRowServiceClient())
  6376. throw createDafsException(DAFSERR_cmdstream_unauthorized, "Unauthorized command");
  6377. }
  6378. bool processCommand(RemoteFileCommandType cmd, MemoryBuffer & msg, MemoryBuffer & reply, CRemoteClientHandler *client, CThrottler *throttler)
  6379. {
  6380. Owned<CClientStats> stats = clientStatsTable.getClientReference(cmd, client->queryPeerName());
  6381. bool testSocketFlag = false;
  6382. unsigned posOfErr = reply.length();
  6383. try
  6384. {
  6385. switch(cmd)
  6386. {
  6387. MAPCOMMANDSTATS(RFCread, cmdRead, *stats);
  6388. MAPCOMMANDSTATS(RFCwrite, cmdWrite, *stats);
  6389. MAPCOMMANDCLIENTSTATS(RFCappend, cmdAppend, *client, *stats);
  6390. MAPCOMMAND(RFCcloseIO, cmdCloseFileIO);
  6391. MAPCOMMANDCLIENT(RFCopenIO, cmdOpenFileIO, *client);
  6392. MAPCOMMAND(RFCsize, cmdSize);
  6393. MAPCOMMANDCLIENT(RFCexists, cmdExists, *client);
  6394. MAPCOMMANDCLIENT(RFCremove, cmdRemove, *client);
  6395. MAPCOMMANDCLIENT(RFCrename, cmdRename, *client);
  6396. MAPCOMMAND(RFCgetver, cmdGetVer);
  6397. MAPCOMMANDCLIENT(RFCisfile, cmdIsFile, *client);
  6398. MAPCOMMANDCLIENT(RFCisdirectory, cmdIsDir, *client);
  6399. MAPCOMMANDCLIENT(RFCisreadonly, cmdIsReadOnly, *client);
  6400. MAPCOMMANDCLIENT(RFCsetreadonly, cmdSetReadOnly, *client);
  6401. MAPCOMMANDCLIENT(RFCsetfileperms, cmdSetFilePerms, *client);
  6402. MAPCOMMANDCLIENT(RFCgettime, cmdGetTime, *client);
  6403. MAPCOMMANDCLIENT(RFCsettime, cmdSetTime, *client);
  6404. MAPCOMMANDCLIENT(RFCcreatedir, cmdCreateDir, *client);
  6405. MAPCOMMANDCLIENT(RFCgetdir, cmdGetDir, *client);
  6406. MAPCOMMANDCLIENT(RFCmonitordir, cmdMonitorDir, *client);
  6407. MAPCOMMAND(RFCstop, cmdStop);
  6408. MAPCOMMANDCLIENT(RFCexec, cmdExec, *client);
  6409. MAPCOMMANDCLIENT(RFCextractblobelements, cmdExtractBlobElements, *client);
  6410. MAPCOMMANDCLIENT(RFCgetcrc, cmdGetCRC, *client);
  6411. MAPCOMMANDCLIENT(RFCmove, cmdMove, *client);
  6412. MAPCOMMANDCLIENT(RFCcopy, cmdCopy, *client);
  6413. MAPCOMMAND(RFCsetsize, cmdSetSize);
  6414. MAPCOMMAND(RFCsettrace, cmdSetTrace);
  6415. MAPCOMMAND(RFCgetinfo, cmdGetInfo);
  6416. MAPCOMMAND(RFCfirewall, cmdFirewall);
  6417. MAPCOMMANDCLIENT(RFCunlock, cmdUnlock, *client);
  6418. MAPCOMMANDCLIENT(RFCcopysection, cmdCopySection, *client);
  6419. MAPCOMMANDCLIENTTHROTTLE(RFCtreecopy, cmdTreeCopy, *client, &slowCmdThrottler);
  6420. MAPCOMMANDCLIENTTHROTTLE(RFCtreecopytmp, cmdTreeCopyTmp, *client, &slowCmdThrottler);
  6421. MAPCOMMAND(RFCsetthrottle, cmdSetThrottle); // legacy version
  6422. MAPCOMMAND(RFCsetthrottle2, cmdSetThrottle2);
  6423. // row service commands
  6424. case RFCStreamRead:
  6425. {
  6426. checkAuthorizedStreamCommand(*client);
  6427. cmdStreamReadStd(msg, reply, *client);
  6428. break;
  6429. }
  6430. case RFCStreamReadJSON:
  6431. {
  6432. checkAuthorizedStreamCommand(*client);
  6433. cmdStreamReadJSON(msg, reply, *client);
  6434. break;
  6435. }
  6436. case RFCStreamReadTestSocket:
  6437. {
  6438. testSocketFlag = true;
  6439. checkAuthorizedStreamCommand(*client);
  6440. cmdStreamReadTestSocket(msg, reply, *client);
  6441. break;
  6442. }
  6443. default:
  6444. formatException(reply, nullptr, cmd, false, RFSERR_InvalidCommand, client);
  6445. break;
  6446. }
  6447. }
  6448. catch (IException *e)
  6449. {
  6450. reply.setWritePos(posOfErr);
  6451. formatException(reply, e, cmd, testSocketFlag, 0, client);
  6452. }
  6453. return testSocketFlag;
  6454. }
  6455. IPooledThread *createCommandProcessor()
  6456. {
  6457. return new cCommandProcessor();
  6458. }
  6459. virtual void run(DAFSConnectCfg _connectMethod, const SocketEndpoint &listenep, unsigned sslPort, const SocketEndpoint *rowServiceEp, bool _rowServiceSSL, bool _rowServiceOnStdPort) override
  6460. {
  6461. SocketEndpoint sslep(listenep);
  6462. if (sslPort)
  6463. sslep.port = sslPort;
  6464. else
  6465. sslep.port = securitySettings.daFileSrvSSLPort;
  6466. Owned<ISocket> acceptSock, secureSock, rowServiceSock;
  6467. if (_connectMethod != SSLOnly)
  6468. {
  6469. if (listenep.port == 0)
  6470. throw createDafsException(DAFSERR_serverinit_failed, "dafilesrv port not specified");
  6471. if (listenep.isNull())
  6472. acceptSock.setown(ISocket::create(listenep.port));
  6473. else
  6474. {
  6475. StringBuffer ips;
  6476. listenep.getIpText(ips);
  6477. acceptSock.setown(ISocket::create_ip(listenep.port,ips.str()));
  6478. }
  6479. }
  6480. if (_connectMethod == SSLOnly || _connectMethod == SSLFirst || _connectMethod == UnsecureFirst)
  6481. {
  6482. if (sslep.port == 0)
  6483. throw createDafsException(DAFSERR_serverinit_failed, "Secure dafilesrv port not specified");
  6484. if (_connectMethod == UnsecureFirst)
  6485. {
  6486. // don't fail, but warn - this allows for fast SSL client rejections
  6487. if (!securitySettings.certificate)
  6488. WARNLOG("SSL Certificate information not found in environment.conf, cannot accept SSL connections");
  6489. else if ( !checkFileExists(securitySettings.certificate) )
  6490. {
  6491. WARNLOG("SSL Certificate File not found in environment.conf, cannot accept SSL connections");
  6492. securitySettings.certificate = nullptr;
  6493. }
  6494. if (!securitySettings.privateKey)
  6495. WARNLOG("SSL Key information not found in environment.conf, cannot accept SSL connections");
  6496. else if ( !checkFileExists(securitySettings.privateKey) )
  6497. {
  6498. WARNLOG("SSL Key File not found in environment.conf, cannot accept SSL connections");
  6499. securitySettings.privateKey = nullptr;
  6500. }
  6501. }
  6502. else
  6503. validateSSLSetup();
  6504. if (sslep.isNull())
  6505. secureSock.setown(ISocket::create(sslep.port));
  6506. else
  6507. {
  6508. StringBuffer ips;
  6509. sslep.getIpText(ips);
  6510. secureSock.setown(ISocket::create_ip(sslep.port,ips.str()));
  6511. }
  6512. }
  6513. if (rowServiceEp)
  6514. {
  6515. rowServiceSSL = _rowServiceSSL;
  6516. rowServiceOnStdPort = _rowServiceOnStdPort;
  6517. if (rowServiceEp->isNull())
  6518. rowServiceSock.setown(ISocket::create(rowServiceEp->port));
  6519. else
  6520. {
  6521. StringBuffer ips;
  6522. rowServiceEp->getIpText(ips);
  6523. rowServiceSock.setown(ISocket::create_ip(rowServiceEp->port, ips.str()));
  6524. }
  6525. #ifdef _USE_OPENSSL
  6526. if (rowServiceSSL)
  6527. validateSSLSetup();
  6528. #else
  6529. rowServiceSSL = false;
  6530. #endif
  6531. }
  6532. run(_connectMethod, acceptSock.getClear(), secureSock.getClear(), rowServiceSock.getClear());
  6533. }
  6534. void run(DAFSConnectCfg _connectMethod, ISocket *_acceptSock, ISocket *_secureSock, ISocket *_rowServiceSock)
  6535. {
  6536. acceptsock.setown(_acceptSock);
  6537. securesock.setown(_secureSock);
  6538. rowServiceSock.setown(_rowServiceSock);
  6539. if (_connectMethod != SSLOnly)
  6540. {
  6541. if (!acceptsock)
  6542. throw createDafsException(DAFSERR_serverinit_failed, "Invalid non-secure socket");
  6543. }
  6544. if (_connectMethod == SSLOnly || _connectMethod == SSLFirst || _connectMethod == UnsecureFirst)
  6545. {
  6546. if (!securesock)
  6547. throw createDafsException(DAFSERR_serverinit_failed, "Invalid secure socket");
  6548. }
  6549. selecthandler->start();
  6550. for (;;)
  6551. {
  6552. Owned<ISocket> sock;
  6553. Owned<ISocket> sockSSL;
  6554. Owned<ISocket> acceptedRSSock;
  6555. bool sockavail = false;
  6556. bool securesockavail = false;
  6557. bool rowServiceSockAvail = false;
  6558. if (_connectMethod == SSLNone && (nullptr == rowServiceSock.get()))
  6559. sockavail = acceptsock->wait_read(1000*60*1)!=0;
  6560. else if (_connectMethod == SSLOnly && (nullptr == rowServiceSock.get()))
  6561. securesockavail = securesock->wait_read(1000*60*1)!=0;
  6562. else
  6563. {
  6564. UnsignedArray readSocks;
  6565. UnsignedArray waitingSocks;
  6566. if (acceptsock)
  6567. readSocks.append(acceptsock->OShandle());
  6568. if (securesock)
  6569. readSocks.append(securesock->OShandle());
  6570. if (rowServiceSock)
  6571. readSocks.append(rowServiceSock->OShandle());
  6572. int numReady = wait_read_multiple(readSocks, 1000*60*1, waitingSocks);
  6573. if (numReady > 0)
  6574. {
  6575. for (int idx = 0; idx < numReady; idx++)
  6576. {
  6577. unsigned waitingSock = waitingSocks.item(idx);
  6578. if (acceptsock && (waitingSock == acceptsock->OShandle()))
  6579. sockavail = true;
  6580. else if (securesock && (waitingSock == securesock->OShandle()))
  6581. securesockavail = true;
  6582. else if (rowServiceSock && (waitingSock == rowServiceSock->OShandle()))
  6583. rowServiceSockAvail = true;
  6584. }
  6585. }
  6586. }
  6587. #if 0
  6588. if (!sockavail && !securesockavail && !rowServiceSockAvail)
  6589. {
  6590. JSocketStatistics stats;
  6591. getSocketStatistics(stats);
  6592. StringBuffer s;
  6593. getSocketStatisticsString(stats,s);
  6594. PROGLOG( "Socket statistics : \n%s\n",s.str());
  6595. }
  6596. #endif
  6597. if (stopping)
  6598. break;
  6599. if (sockavail || securesockavail || rowServiceSockAvail)
  6600. {
  6601. if (sockavail)
  6602. {
  6603. try
  6604. {
  6605. sock.setown(acceptsock->accept(true));
  6606. if (!sock||stopping)
  6607. break;
  6608. }
  6609. catch (IException *e)
  6610. {
  6611. EXCLOG(e,"CRemoteFileServer");
  6612. e->Release();
  6613. break;
  6614. }
  6615. }
  6616. if (securesockavail)
  6617. {
  6618. Owned<ISecureSocket> ssock;
  6619. try
  6620. {
  6621. sockSSL.setown(securesock->accept(true));
  6622. if (!sockSSL||stopping)
  6623. break;
  6624. if ( (_connectMethod == UnsecureFirst) && (!securitySettings.certificate || !securitySettings.privateKey) )
  6625. {
  6626. // for client secure_connect() to fail quickly ...
  6627. cleanupSocket(sockSSL);
  6628. sockSSL.clear();
  6629. securesockavail = false;
  6630. }
  6631. else
  6632. {
  6633. ssock.setown(createSecureSocket(sockSSL.getClear(), ServerSocket));
  6634. int status = ssock->secure_accept();
  6635. if (status < 0)
  6636. throw createDafsException(DAFSERR_serveraccept_failed,"Failure to establish secure connection");
  6637. sockSSL.setown(ssock.getLink());
  6638. }
  6639. }
  6640. catch (IJSOCK_Exception *e)
  6641. {
  6642. // accept failed ...
  6643. EXCLOG(e,"CRemoteFileServer (secure)");
  6644. e->Release();
  6645. break;
  6646. }
  6647. catch (IException *e) // IDAFS_Exception also ...
  6648. {
  6649. EXCLOG(e,"CRemoteFileServer1 (secure)");
  6650. e->Release();
  6651. cleanupSocket(sockSSL);
  6652. sockSSL.clear();
  6653. cleanupSocket(ssock);
  6654. ssock.clear();
  6655. securesockavail = false;
  6656. }
  6657. }
  6658. if (rowServiceSockAvail)
  6659. {
  6660. Owned<ISecureSocket> ssock;
  6661. try
  6662. {
  6663. acceptedRSSock.setown(rowServiceSock->accept(true));
  6664. if (!acceptedRSSock||stopping)
  6665. break;
  6666. if (rowServiceSSL) // NB: will be disabled if !_USE_OPENSLL
  6667. {
  6668. ssock.setown(createSecureSocket(acceptedRSSock.getClear(), ServerSocket));
  6669. int status = ssock->secure_accept();
  6670. if (status < 0)
  6671. throw createDafsException(DAFSERR_serveraccept_failed,"Failure to establish SSL row service connection");
  6672. acceptedRSSock.setown(ssock.getLink());
  6673. }
  6674. }
  6675. catch (IJSOCK_Exception *e)
  6676. {
  6677. // accept failed ...
  6678. EXCLOG(e,"CRemoteFileServer (row service)");
  6679. e->Release();
  6680. break;
  6681. }
  6682. catch (IException *e) // IDAFS_Exception also ...
  6683. {
  6684. EXCLOG(e,"CRemoteFileServer1 (row service)");
  6685. e->Release();
  6686. cleanupSocket(acceptedRSSock);
  6687. sockSSL.clear();
  6688. cleanupSocket(ssock);
  6689. ssock.clear();
  6690. rowServiceSockAvail = false;
  6691. }
  6692. }
  6693. #ifdef _DEBUG
  6694. SocketEndpoint eps;
  6695. StringBuffer peerURL;
  6696. #endif
  6697. if (sockavail)
  6698. {
  6699. #ifdef _DEBUG
  6700. sock->getPeerEndpoint(eps);
  6701. eps.getUrlStr(peerURL);
  6702. PROGLOG("Server accepting from %s", peerURL.str());
  6703. #endif
  6704. runClient(sock.getClear(), false);
  6705. }
  6706. if (securesockavail)
  6707. {
  6708. #ifdef _DEBUG
  6709. sockSSL->getPeerEndpoint(eps);
  6710. eps.getUrlStr(peerURL.clear());
  6711. PROGLOG("Server accepting SECURE from %s", peerURL.str());
  6712. #endif
  6713. runClient(sockSSL.getClear(), false);
  6714. }
  6715. if (rowServiceSockAvail)
  6716. {
  6717. #ifdef _DEBUG
  6718. acceptedRSSock->getPeerEndpoint(eps);
  6719. eps.getUrlStr(peerURL.clear());
  6720. PROGLOG("Server accepting row service socket from %s", peerURL.str());
  6721. #endif
  6722. runClient(acceptedRSSock.getClear(), true);
  6723. }
  6724. }
  6725. else
  6726. checkTimeout();
  6727. }
  6728. if (TF_TRACE_CLIENT_STATS)
  6729. PROGLOG("CRemoteFileServer:run exiting");
  6730. selecthandler->stop(true);
  6731. }
  6732. void processUnauthenticatedCommand(RemoteFileCommandType cmd, ISocket *socket, MemoryBuffer &msg)
  6733. {
  6734. // these are unauthenticated commands
  6735. if (cmd != RFCgetver)
  6736. cmd = RFCinvalid;
  6737. MemoryBuffer reply;
  6738. bool testSocketFlag = processCommand(cmd, msg, initSendBuffer(reply), NULL, NULL);
  6739. sendBuffer(socket, reply, testSocketFlag);
  6740. }
  6741. bool checkAuthentication(ISocket *socket, IAuthenticatedUser *&ret)
  6742. {
  6743. ret = NULL;
  6744. if (!AuthenticationEnabled)
  6745. return true;
  6746. MemoryBuffer reqbuf;
  6747. MemoryBuffer reply;
  6748. MemoryBuffer encbuf; // because aesEncrypt clears input
  6749. initSendBuffer(reply);
  6750. receiveBuffer(socket, reqbuf, 1);
  6751. RemoteFileCommandType typ=0;
  6752. if (reqbuf.remaining()<sizeof(RemoteFileCommandType))
  6753. return false;
  6754. reqbuf.read(typ);
  6755. if (typ!=RFCunlock)
  6756. {
  6757. processUnauthenticatedCommand(typ,socket,reqbuf);
  6758. return false;
  6759. }
  6760. if (reqbuf.remaining()<sizeof(OnceKey))
  6761. return false;
  6762. OnceKey oncekey;
  6763. reqbuf.read(sizeof(oncekey),&oncekey);
  6764. IpAddress ip;
  6765. socket->getPeerAddress(ip);
  6766. byte ipdata[16];
  6767. ip.getNetAddress(sizeof(ipdata),&ipdata);
  6768. mergeOnce(oncekey,sizeof(ipdata),&ipdata); // this is clients key
  6769. OnceKey mykey;
  6770. genOnce(mykey);
  6771. reply.append(RFEnoerror); // errcode
  6772. aesEncrypt(&oncekey,sizeof(oncekey),&mykey,sizeof(oncekey),encbuf);
  6773. reply.append(encbuf.length()).append(encbuf);
  6774. sendBuffer(socket, reply); // send my oncekey
  6775. reqbuf.clear();
  6776. receiveBuffer(socket, reqbuf, 1);
  6777. if (reqbuf.remaining()>sizeof(RemoteFileCommandType)+sizeof(size32_t))
  6778. {
  6779. reqbuf.read(typ);
  6780. if (typ==RFCunlockreply)
  6781. {
  6782. size32_t bs;
  6783. reqbuf.read(bs);
  6784. if (bs<=reqbuf.remaining())
  6785. {
  6786. MemoryBuffer userbuf;
  6787. aesDecrypt(&mykey,sizeof(mykey),reqbuf.readDirect(bs),bs,userbuf);
  6788. byte n;
  6789. userbuf.read(n);
  6790. if (n>=2)
  6791. {
  6792. StringAttr user;
  6793. StringAttr password;
  6794. userbuf.read(user).read(password);
  6795. Owned<IAuthenticatedUser> iau = createAuthenticatedUser();
  6796. if (iau->login(user,password))
  6797. {
  6798. initSendBuffer(reply.clear());
  6799. reply.append(RFEnoerror);
  6800. sendBuffer(socket, reply); // send OK
  6801. ret = iau;
  6802. return true;
  6803. }
  6804. }
  6805. }
  6806. }
  6807. }
  6808. reply.clear();
  6809. appendErr(reply, RFSERR_AuthenticateFailed);
  6810. sendBuffer(socket, reply); // send OK
  6811. return false;
  6812. }
  6813. void runClient(ISocket *sock, bool rowService) // rowService used to distinguish client calls
  6814. {
  6815. cCommandProcessor::cCommandProcessorParams params;
  6816. IAuthenticatedUser *user=NULL;
  6817. bool authenticated = false;
  6818. try
  6819. {
  6820. if (checkAuthentication(sock,user))
  6821. authenticated = true;
  6822. }
  6823. catch (IException *e)
  6824. {
  6825. e->Release();
  6826. }
  6827. if (!authenticated)
  6828. {
  6829. try
  6830. {
  6831. sock->Release();
  6832. }
  6833. catch (IException *e)
  6834. {
  6835. e->Release();
  6836. }
  6837. return;
  6838. }
  6839. params.client = new CRemoteClientHandler(this, sock, user, globallasttick, rowService);
  6840. {
  6841. CriticalBlock block(sect);
  6842. clients.append(*LINK(params.client));
  6843. }
  6844. // NB: This could be blocked, by thread pool limit
  6845. threads->start(&params);
  6846. }
  6847. void stop()
  6848. {
  6849. // stop accept loop
  6850. if (TF_TRACE_CLIENT_STATS)
  6851. PROGLOG("CRemoteFileServer::stop");
  6852. if (acceptsock)
  6853. acceptsock->cancel_accept();
  6854. if (securesock)
  6855. securesock->cancel_accept();
  6856. threads->stopAll();
  6857. threads->joinAll(true,60*1000);
  6858. }
  6859. bool notify(CRemoteClientHandler *_client, MemoryBuffer &msg)
  6860. {
  6861. Linked<CRemoteClientHandler> client;
  6862. client.set(_client);
  6863. if (TF_TRACE_FULL)
  6864. PROGLOG("notify %d", msg.length());
  6865. if (msg.length())
  6866. {
  6867. if (TF_TRACE_FULL)
  6868. PROGLOG("notify CRemoteClientHandler(%p), msg length=%u", _client, msg.length());
  6869. cCommandProcessor::cCommandProcessorParams params;
  6870. params.client = client.getClear();
  6871. params.msg.swapWith(msg);
  6872. /* This can block because the thread pool is full and therefore block the selecthandler
  6873. * This is akin to the main server blocking post accept() for the same reason.
  6874. */
  6875. threads->start(&params);
  6876. }
  6877. else
  6878. onCloseSocket(client,3); // removes owned handles
  6879. return false;
  6880. }
  6881. void addClient(CRemoteClientHandler *client)
  6882. {
  6883. if (client&&client->socket)
  6884. selecthandler->add(client->socket,SELECTMODE_READ,client);
  6885. }
  6886. void checkTimeout()
  6887. {
  6888. if (msTick()-clientcounttick>1000*60*60)
  6889. {
  6890. CriticalBlock block(ClientCountSect);
  6891. if (TF_TRACE_CLIENT_STATS && (ClientCount || MaxClientCount))
  6892. PROGLOG("Client count = %d, max = %d", ClientCount, MaxClientCount);
  6893. clientcounttick = msTick();
  6894. MaxClientCount = ClientCount;
  6895. if (closedclients)
  6896. {
  6897. if (TF_TRACE_CLIENT_STATS)
  6898. PROGLOG("Closed client count = %d",closedclients);
  6899. closedclients = 0;
  6900. }
  6901. }
  6902. CriticalBlock block(sect);
  6903. ForEachItemInRev(i,clients)
  6904. {
  6905. CRemoteClientHandler &client = clients.item(i);
  6906. if (client.timedOut())
  6907. {
  6908. StringBuffer s;
  6909. bool ok = client.getInfo(s); // will spot duff sockets
  6910. if (ok&&(client.openFiles.ordinality()!=0))
  6911. {
  6912. if (TF_TRACE_CLIENT_CONN && client.inactiveTimedOut())
  6913. WARNLOG("Inactive %s",s.str());
  6914. }
  6915. else
  6916. {
  6917. #ifndef _DEBUG
  6918. if (TF_TRACE_CLIENT_CONN)
  6919. #endif
  6920. PROGLOG("Timing out %s",s.str());
  6921. closedclients++;
  6922. onCloseSocket(&client,4); // removes owned handles
  6923. }
  6924. }
  6925. }
  6926. }
  6927. void getInfo(StringBuffer &info, unsigned level=1)
  6928. {
  6929. {
  6930. CriticalBlock block(ClientCountSect);
  6931. info.append(VERSTRING).append('\n');
  6932. info.appendf("Client count = %d\n",ClientCount);
  6933. info.appendf("Max client count = %d",MaxClientCount);
  6934. }
  6935. CriticalBlock block(sect);
  6936. ForEachItemIn(i,clients)
  6937. {
  6938. info.newline().append(i).append(": ");
  6939. clients.item(i).getInfo(info);
  6940. }
  6941. info.newline().appendf("Running threads: %u", threadRunningCount());
  6942. info.newline();
  6943. stdCmdThrottler.getInfo(info);
  6944. info.newline();
  6945. slowCmdThrottler.getInfo(info);
  6946. clientStatsTable.getInfo(info, level);
  6947. }
  6948. unsigned threadRunningCount()
  6949. {
  6950. if (!threads)
  6951. return 0;
  6952. return threads->runningCount();
  6953. }
  6954. unsigned idleTime()
  6955. {
  6956. unsigned t = (unsigned)atomic_read(&globallasttick);
  6957. return msTick()-t;
  6958. }
  6959. void setThrottle(ThrottleClass throttleClass, unsigned limit, unsigned delayMs, unsigned cpuThreshold, unsigned queueLimit)
  6960. {
  6961. switch (throttleClass)
  6962. {
  6963. case ThrottleStd:
  6964. stdCmdThrottler.configure(limit, delayMs, cpuThreshold, queueLimit);
  6965. break;
  6966. case ThrottleSlow:
  6967. slowCmdThrottler.configure(limit, delayMs, cpuThreshold, queueLimit);
  6968. break;
  6969. default:
  6970. {
  6971. StringBuffer availableClasses("{ ");
  6972. for (unsigned c=0; c<ThrottleClassMax; c++)
  6973. {
  6974. availableClasses.append(c).append(" = ").append(getThrottleClassText((ThrottleClass)c));
  6975. if (c+1<ThrottleClassMax)
  6976. availableClasses.append(", ");
  6977. }
  6978. availableClasses.append(" }");
  6979. throw MakeStringException(0, "Unknown throttle class: %u, available classes are: %s", (unsigned)throttleClass, availableClasses.str());
  6980. }
  6981. }
  6982. }
  6983. StringBuffer &getStats(StringBuffer &stats, bool reset)
  6984. {
  6985. CriticalBlock block(sect);
  6986. stdCmdThrottler.getStats(stats, reset).newline();
  6987. slowCmdThrottler.getStats(stats, reset);
  6988. if (reset)
  6989. clientStatsTable.reset();
  6990. return stats;
  6991. }
  6992. };
  6993. IRemoteFileServer * createRemoteFileServer(unsigned maxThreads, unsigned maxThreadsDelayMs, unsigned maxAsyncCopy, IPropertyTree *keyPairInfo)
  6994. {
  6995. #if SIMULATE_PACKETLOSS
  6996. errorSimulationOn = false;
  6997. #endif
  6998. return new CRemoteFileServer(maxThreads, maxThreadsDelayMs, maxAsyncCopy, keyPairInfo);
  6999. }
  7000. #ifdef _USE_CPPUNIT
  7001. #include "unittests.hpp"
  7002. #include "rmtfile.hpp"
  7003. static unsigned serverPort = DAFILESRV_PORT+1; // do not use standard port, which if in a URL will be converted to local parth if IP is local
  7004. static StringBuffer basePath;
  7005. static Owned<CSimpleInterface> serverThread;
  7006. class RemoteFileSlowTest : public CppUnit::TestFixture
  7007. {
  7008. CPPUNIT_TEST_SUITE(RemoteFileSlowTest);
  7009. CPPUNIT_TEST(testRemoteFilename);
  7010. CPPUNIT_TEST(testStartServer);
  7011. CPPUNIT_TEST(testBasicFunctionality);
  7012. CPPUNIT_TEST(testCopy);
  7013. CPPUNIT_TEST(testOther);
  7014. CPPUNIT_TEST(testConfiguration);
  7015. CPPUNIT_TEST(testDirectoryMonitoring);
  7016. CPPUNIT_TEST(testFinish);
  7017. CPPUNIT_TEST_SUITE_END();
  7018. size32_t testLen = 1024;
  7019. protected:
  7020. void testRemoteFilename()
  7021. {
  7022. const char *rfns = "//1.2.3.4/dir1/file1|//1.2.3.4:7100/dir1/file1,"
  7023. "//1.2.3.4:7100/dir1/file1|//1.2.3.4:7100/dir1/file1,"
  7024. "//1.2.3.4/c$/dir1/file1|//1.2.3.4:7100/c$/dir1/file1,"
  7025. "//1.2.3.4:7100/c$/dir1/file1|//1.2.3.4:7100/c$/dir1/file1,"
  7026. "//1.2.3.4:7100/d$/dir1/file1|//1.2.3.4:7100/d$/dir1/file1";
  7027. StringArray tests;
  7028. tests.appendList(rfns, ",");
  7029. ForEachItemIn(i, tests)
  7030. {
  7031. StringArray inOut;
  7032. const char *pair = tests.item(i);
  7033. inOut.appendList(pair, "|");
  7034. const char *rfn = inOut.item(0);
  7035. const char *expected = inOut.item(1);
  7036. Owned<IFile> iFile = createIFile(rfn);
  7037. const char *res = iFile->queryFilename();
  7038. if (!streq(expected, res))
  7039. {
  7040. StringBuffer errMsg("testRemoteFilename MISMATCH");
  7041. errMsg.newline().append("Expected: ").append(expected);
  7042. errMsg.newline().append("Got: ").append(res);
  7043. PROGLOG("%s", errMsg.str());
  7044. CPPUNIT_ASSERT_MESSAGE(errMsg.str(), 0);
  7045. }
  7046. else
  7047. PROGLOG("MATCH: %s", res);
  7048. }
  7049. }
  7050. void testStartServer()
  7051. {
  7052. Owned<ISocket> socket;
  7053. unsigned endPort = MP_END_PORT;
  7054. while (1)
  7055. {
  7056. try
  7057. {
  7058. socket.setown(ISocket::create(serverPort));
  7059. break;
  7060. }
  7061. catch (IJSOCK_Exception *e)
  7062. {
  7063. if (e->errorCode() != JSOCKERR_port_in_use)
  7064. {
  7065. StringBuffer eStr;
  7066. e->errorMessage(eStr);
  7067. e->Release();
  7068. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  7069. }
  7070. else if (serverPort == endPort)
  7071. {
  7072. e->Release();
  7073. CPPUNIT_ASSERT_MESSAGE("Could not find a free port to use for remote file server", 0);
  7074. }
  7075. }
  7076. ++serverPort;
  7077. }
  7078. basePath.append("//");
  7079. SocketEndpoint ep(serverPort);
  7080. ep.getUrlStr(basePath);
  7081. char cpath[_MAX_DIR];
  7082. if (!GetCurrentDirectory(_MAX_DIR, cpath))
  7083. CPPUNIT_ASSERT_MESSAGE("Current directory path too big", 0);
  7084. else
  7085. basePath.append(cpath);
  7086. addPathSepChar(basePath);
  7087. PROGLOG("basePath = %s", basePath.str());
  7088. class CServerThread : public CSimpleInterface, implements IThreaded
  7089. {
  7090. CThreaded threaded;
  7091. Owned<CRemoteFileServer> server;
  7092. Linked<ISocket> socket;
  7093. public:
  7094. CServerThread(CRemoteFileServer *_server, ISocket *_socket) : server(_server), socket(_socket), threaded("CServerThread")
  7095. {
  7096. threaded.init(this);
  7097. }
  7098. ~CServerThread()
  7099. {
  7100. threaded.join();
  7101. }
  7102. // IThreaded
  7103. virtual void threadmain() override
  7104. {
  7105. DAFSConnectCfg sslCfg = SSLNone;
  7106. server->run(sslCfg, socket, nullptr, nullptr);
  7107. }
  7108. };
  7109. enableDafsAuthentication(false);
  7110. Owned<IRemoteFileServer> server = createRemoteFileServer();
  7111. serverThread.setown(new CServerThread(QUERYINTERFACE(server.getClear(), CRemoteFileServer), socket.getClear()));
  7112. }
  7113. void testBasicFunctionality()
  7114. {
  7115. VStringBuffer filePath("%s%s", basePath.str(), "file1");
  7116. // create file
  7117. Owned<IFile> iFile = createIFile(filePath);
  7118. CPPUNIT_ASSERT(iFile);
  7119. Owned<IFileIO> iFileIO = iFile->open(IFOcreate);
  7120. CPPUNIT_ASSERT(iFileIO);
  7121. // write out 1k of random data and crc
  7122. MemoryBuffer mb;
  7123. char *buf = (char *)mb.reserveTruncate(testLen);
  7124. for (unsigned b=0; b<1024; b++)
  7125. buf[b] = getRandom()%256;
  7126. CRC32 crc;
  7127. crc.tally(testLen, buf);
  7128. unsigned writeCrc = crc.get();
  7129. size32_t sz = iFileIO->write(0, testLen, buf);
  7130. CPPUNIT_ASSERT(sz == testLen);
  7131. // close file
  7132. iFileIO.clear();
  7133. // validate remote crc
  7134. CPPUNIT_ASSERT(writeCrc == iFile->getCRC());
  7135. // exists
  7136. CPPUNIT_ASSERT(iFile->exists());
  7137. // validate size
  7138. CPPUNIT_ASSERT(iFile->size() == testLen);
  7139. // read back and validate read data's crc against written
  7140. iFileIO.setown(iFile->open(IFOread));
  7141. CPPUNIT_ASSERT(iFileIO);
  7142. sz = iFileIO->read(0, testLen, buf);
  7143. iFileIO.clear();
  7144. CPPUNIT_ASSERT(sz == testLen);
  7145. crc.reset();
  7146. crc.tally(testLen, buf);
  7147. CPPUNIT_ASSERT(writeCrc == crc.get());
  7148. }
  7149. void testCopy()
  7150. {
  7151. VStringBuffer filePath("%s%s", basePath.str(), "file1");
  7152. Owned<IFile> iFile = createIFile(filePath);
  7153. // test file copy
  7154. VStringBuffer filePathCopy("%s%s", basePath.str(), "file1copy");
  7155. Owned<IFile> iFile1Copy = createIFile(filePathCopy);
  7156. iFile->copyTo(iFile1Copy);
  7157. // read back copy and validate read data's crc against written
  7158. Owned<IFileIO> iFileIO = iFile1Copy->open(IFOreadwrite); // open read/write for appendFile in next step.
  7159. CPPUNIT_ASSERT(iFileIO);
  7160. MemoryBuffer mb;
  7161. char *buf = (char *)mb.reserveTruncate(testLen);
  7162. size32_t sz = iFileIO->read(0, testLen, buf);
  7163. CPPUNIT_ASSERT(sz == testLen);
  7164. CRC32 crc;
  7165. crc.tally(testLen, buf);
  7166. CPPUNIT_ASSERT(iFile->getCRC() == crc.get());
  7167. // check appendFile functionality. NB after this "file1copy" should be 2*testLen
  7168. CPPUNIT_ASSERT(testLen == iFileIO->appendFile(iFile));
  7169. iFileIO.clear();
  7170. // validate new size
  7171. CPPUNIT_ASSERT(iFile1Copy->size() == 2 * testLen);
  7172. // setSize test, truncate copy to original size
  7173. iFileIO.setown(iFile1Copy->open(IFOreadwrite));
  7174. iFileIO->setSize(testLen);
  7175. // validate new size
  7176. CPPUNIT_ASSERT(iFile1Copy->size() == testLen);
  7177. }
  7178. void testOther()
  7179. {
  7180. VStringBuffer filePath("%s%s", basePath.str(), "file1");
  7181. Owned<IFile> iFile = createIFile(filePath);
  7182. // rename
  7183. iFile->rename("file2");
  7184. // create a directory
  7185. VStringBuffer subDirPath("%s%s", basePath.str(), "subdir1");
  7186. Owned<IFile> subDirIFile = createIFile(subDirPath);
  7187. subDirIFile->createDirectory();
  7188. // check isDirectory result
  7189. CPPUNIT_ASSERT(subDirIFile->isDirectory());
  7190. // move previous created and renamed file into new sub-directory
  7191. // ensure not present before move
  7192. VStringBuffer subDirFilePath("%s/%s", subDirPath.str(), "file2");
  7193. Owned<IFile> iFile2 = createIFile(subDirFilePath);
  7194. iFile2->remove();
  7195. iFile->move(subDirFilePath);
  7196. // open sub-directory file2 explicitly
  7197. RemoteFilename rfn;
  7198. rfn.setRemotePath(subDirPath.str());
  7199. Owned<IFile> dir = createIFile(rfn);
  7200. Owned<IDirectoryIterator> diriter = dir->directoryFiles("file2");
  7201. if (!diriter->first())
  7202. {
  7203. CPPUNIT_ASSERT_MESSAGE("Error, file2 diriter->first() is null", 0);
  7204. }
  7205. Linked<IFile> iFile3 = &diriter->query();
  7206. diriter.clear();
  7207. dir.clear();
  7208. OwnedIFileIO iFile3IO = iFile3->openShared(IFOread, IFSHfull);
  7209. if (!iFile3IO)
  7210. {
  7211. CPPUNIT_ASSERT_MESSAGE("Error, file2 openShared() failed", 0);
  7212. }
  7213. iFile3IO->close();
  7214. // count sub-directory files with a wildcard
  7215. unsigned count=0;
  7216. Owned<IDirectoryIterator> iter = subDirIFile->directoryFiles("*2");
  7217. ForEach(*iter)
  7218. ++count;
  7219. CPPUNIT_ASSERT(1 == count);
  7220. // check isFile result
  7221. CPPUNIT_ASSERT(iFile2->isFile());
  7222. // validate isReadOnly before after setting
  7223. CPPUNIT_ASSERT(!iFile2->isReadOnly());
  7224. iFile2->setReadOnly(true);
  7225. CPPUNIT_ASSERT(iFile2->isReadOnly());
  7226. // get/set Time and validate result
  7227. CDateTime createTime, modifiedTime, accessedTime;
  7228. CPPUNIT_ASSERT(subDirIFile->getTime(&createTime, &modifiedTime, &accessedTime));
  7229. CDateTime newModifiedTime = modifiedTime;
  7230. newModifiedTime.adjustTime(-86400); // -1 day
  7231. CPPUNIT_ASSERT(subDirIFile->setTime(&createTime, &newModifiedTime, &accessedTime));
  7232. CPPUNIT_ASSERT(subDirIFile->getTime(&createTime, &modifiedTime, &accessedTime));
  7233. CPPUNIT_ASSERT(modifiedTime == newModifiedTime);
  7234. // test set file permissions
  7235. try
  7236. {
  7237. iFile2->setFilePermissions(0777);
  7238. }
  7239. catch (...)
  7240. {
  7241. CPPUNIT_ASSERT_MESSAGE("iFile2->setFilePermissions() exception", 0);
  7242. }
  7243. }
  7244. void testConfiguration()
  7245. {
  7246. SocketEndpoint ep(serverPort); // test trace open connections
  7247. CPPUNIT_ASSERT(setDafileSvrTraceFlags(ep, 0x08));
  7248. StringBuffer infoStr;
  7249. CPPUNIT_ASSERT(RFEnoerror == getDafileSvrInfo(ep, 10, infoStr));
  7250. CPPUNIT_ASSERT(RFEnoerror == setDafileSvrThrottleLimit(ep, ThrottleStd, DEFAULT_STDCMD_PARALLELREQUESTLIMIT+1, DEFAULT_STDCMD_THROTTLEDELAYMS+1, DEFAULT_STDCMD_THROTTLECPULIMIT+1, DEFAULT_STDCMD_THROTTLEQUEUELIMIT+1));
  7251. }
  7252. void testDirectoryMonitoring()
  7253. {
  7254. VStringBuffer subDirPath("%s%s", basePath.str(), "subdir1");
  7255. Owned<IFile> subDirIFile = createIFile(subDirPath);
  7256. subDirIFile->createDirectory();
  7257. VStringBuffer filePath("%s/%s", subDirPath.str(), "file1");
  7258. class CDelayedFileCreate : implements IThreaded
  7259. {
  7260. CThreaded threaded;
  7261. StringAttr filePath;
  7262. Semaphore doneSem;
  7263. public:
  7264. CDelayedFileCreate(const char *_filePath) : filePath(_filePath), threaded("CDelayedFileCreate")
  7265. {
  7266. threaded.init(this);
  7267. }
  7268. ~CDelayedFileCreate()
  7269. {
  7270. stop();
  7271. }
  7272. void stop()
  7273. {
  7274. doneSem.signal();
  7275. threaded.join();
  7276. }
  7277. // IThreaded impl.
  7278. virtual void threadmain() override
  7279. {
  7280. MilliSleep(1000); // give monitorDirectory a chance to be monitoring
  7281. // create file
  7282. Owned<IFile> iFile = createIFile(filePath);
  7283. CPPUNIT_ASSERT(iFile);
  7284. Owned<IFileIO> iFileIO = iFile->open(IFOcreate);
  7285. CPPUNIT_ASSERT(iFileIO);
  7286. iFileIO.clear();
  7287. doneSem.wait(60 * 1000);
  7288. CPPUNIT_ASSERT(iFile->remove());
  7289. }
  7290. } delayedFileCreate(filePath);
  7291. Owned<IDirectoryDifferenceIterator> iter = subDirIFile->monitorDirectory(nullptr, nullptr, false, false, 2000, 60 * 1000);
  7292. ForEach(*iter)
  7293. {
  7294. StringBuffer fname;
  7295. iter->getName(fname);
  7296. PROGLOG("fname = %s", fname.str());
  7297. }
  7298. delayedFileCreate.stop();
  7299. }
  7300. void testFinish()
  7301. {
  7302. // clearup
  7303. VStringBuffer filePathCopy("%s%s", basePath.str(), "file1copy");
  7304. Owned<IFile> iFile1Copy = createIFile(filePathCopy);
  7305. CPPUNIT_ASSERT(iFile1Copy->remove());
  7306. VStringBuffer subDirPath("%s%s", basePath.str(), "subdir1");
  7307. VStringBuffer subDirFilePath("%s/%s", subDirPath.str(), "file2");
  7308. Owned<IFile> iFile2 = createIFile(subDirFilePath);
  7309. CPPUNIT_ASSERT(iFile2->remove());
  7310. Owned<IFile> subDirIFile = createIFile(subDirPath);
  7311. CPPUNIT_ASSERT(subDirIFile->remove());
  7312. SocketEndpoint ep(serverPort);
  7313. Owned<ISocket> sock = ISocket::connect_timeout(ep, 60 * 1000);
  7314. CPPUNIT_ASSERT(RFEnoerror == stopRemoteServer(sock));
  7315. serverThread.clear();
  7316. }
  7317. };
  7318. CPPUNIT_TEST_SUITE_REGISTRATION( RemoteFileSlowTest );
  7319. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RemoteFileSlowTest, "RemoteFileSlowTests" );
  7320. #endif // _USE_CPPUNIT